001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019 #include <sos/assert.h>
020 #include <sos/types.h>
021 #include <sos/fs.h>
022 #include <sos/list.h>
023 #include <sos/kmalloc.h>
024
025 #include "chardev.h"
026
027 struct sos_chardev_class
028 {
029 sos_ui32_t device_class;
030 struct sos_chardev_ops *ops;
031
032
033
034 void *custom_data;
035
036 sos_count_t ref_cnt;
037
038
039 struct sos_chardev_class *next, *prev;
040 };
041
042
043 struct sos_chardev_opened_file
044 {
045
046
047 struct sos_fs_opened_file super;
048
049
050
051 struct sos_chardev_class *class;
052 };
053
054
055
056
057 static struct sos_chardev_class *registered_chardev_classes;
058
059
060
061 static struct sos_fs_ops_opened_file chardev_ops_opened_file;
062 static struct sos_fs_ops_opened_chardev chardev_ops_opened_chardev;
063
064 static sos_ret_t
065 chardev_helper_sync(struct sos_fs_node * this);
066 static sos_ret_t
067 chardev_helper_new_opened_file(struct sos_fs_node * this,
068 const struct sos_process * owner,
069 sos_ui32_t open_flags,
070 struct sos_fs_opened_file ** result_of);
071 static sos_ret_t
072 chardev_helper_close_opened_file(struct sos_fs_node * this,
073 struct sos_fs_opened_file * of);
074 static sos_ret_t
075 duplicate_opened_chardev(struct sos_fs_opened_file *this,
076 const struct sos_process * for_owner,
077 struct sos_fs_opened_file **result);
078
079
080
081
082
083
084 static struct sos_chardev_class * lookup_chardev_class(sos_ui32_t device_class)
085 {
086 struct sos_chardev_class *chardev;
087 int nb;
088
089 list_foreach (registered_chardev_classes, chardev, nb)
090 {
091 if (chardev->device_class == device_class)
092 return chardev;
093 }
094
095 return NULL;
096 }
097
098
099 sos_ret_t sos_chardev_register_class (sos_ui32_t device_class,
100 struct sos_chardev_ops *ops,
101 void * chardev_class_custom_data)
102 {
103 struct sos_chardev_class *chardev;
104
105
106 chardev = lookup_chardev_class(device_class);
107 if (NULL != chardev)
108 return -SOS_EBUSY;
109
110
111 chardev = (struct sos_chardev_class *)
112 sos_kmalloc(sizeof(struct sos_chardev_class), 0);
113 if (chardev == NULL)
114 return -SOS_ENOMEM;
115
116 chardev->device_class = device_class;
117 chardev->custom_data = chardev_class_custom_data;
118 chardev->ops = ops;
119 chardev->ref_cnt = 1;
120
121
122 list_add_tail (registered_chardev_classes, chardev);
123
124 return SOS_OK;
125 }
126
127
128 sos_ret_t sos_chardev_unregister_class (sos_ui32_t device_class)
129 {
130 struct sos_chardev_class *chardev;
131
132
133 chardev = lookup_chardev_class(device_class);
134 if (NULL == chardev)
135 return -SOS_ENODEV;
136
137
138 if (chardev->ref_cnt != 1)
139 return -SOS_EBUSY;
140
141
142 list_delete (registered_chardev_classes, chardev);
143 return sos_kfree((sos_vaddr_t)chardev);
144 }
145
146
147
148 sos_ret_t sos_chardev_helper_ref_new_fsnode(struct sos_fs_node * this)
149 {
150 this->sync = chardev_helper_sync;
151 this->new_opened_file = chardev_helper_new_opened_file;
152 this->close_opened_file = chardev_helper_close_opened_file;
153
154 return SOS_OK;
155 }
156
157
158 sos_ret_t sos_chardev_helper_release_fsnode(struct sos_fs_node * this)
159 {
160 return SOS_OK;
161 }
162
163
164
165 static sos_ret_t
166 chardev_helper_sync(struct sos_fs_node * this)
167 {
168 return SOS_OK;
169 }
170
171
172
173
174
175 static sos_ret_t
176 chardev_helper_new_opened_file(struct sos_fs_node * this,
177 const struct sos_process * owner,
178 sos_ui32_t open_flags,
179 struct sos_fs_opened_file ** result_of)
180 {
181 sos_ret_t retval;
182 struct sos_chardev_opened_file *chardev_of;
183
184
185 struct sos_chardev_class * chardev
186 = lookup_chardev_class(this->dev_id.device_class);
187 if (NULL == chardev)
188 return -SOS_ENODEV;
189
190
191 chardev_of = (struct sos_chardev_opened_file*)
192 sos_kmalloc(sizeof(struct sos_chardev_opened_file), 0);
193 if (NULL == chardev_of)
194 return -SOS_ENOMEM;
195
196 memset(chardev_of, 0x0, sizeof(struct sos_chardev_opened_file));
197 chardev_of->class = chardev;
198 *result_of = & chardev_of->super;
199
200
201 SOS_ASSERT_FATAL(chardev->ref_cnt >= 1);
202 chardev->ref_cnt ++;
203
204
205 (*result_of)->owner = owner;
206 (*result_of)->open_flags = open_flags;
207 (*result_of)->ops_file = & chardev_ops_opened_file;
208 (*result_of)->ops_chardev = & chardev_ops_opened_chardev;
209
210
211 retval = chardev->ops->open(this, & chardev_of->super, chardev->custom_data);
212 if (SOS_OK != retval)
213 {
214 sos_kfree((sos_vaddr_t) chardev_of);
215 chardev->ref_cnt --;
216 *result_of = NULL;
217 return retval;
218 }
219
220
221 (*result_of)->duplicate = duplicate_opened_chardev;
222
223 return retval;
224 }
225
226
227
228
229 static sos_ret_t
230 chardev_helper_close_opened_file(struct sos_fs_node * this,
231 struct sos_fs_opened_file * of)
232 {
233 sos_ret_t retval;
234 struct sos_chardev_opened_file *chardev_of
235 = ((struct sos_chardev_opened_file*)of);
236
237 struct sos_chardev_class * chardev = chardev_of->class;
238 SOS_ASSERT_FATAL(NULL != chardev);
239
240
241 if (NULL != chardev->ops->close)
242 retval = chardev->ops->close(& chardev_of->super, chardev->custom_data);
243 else
244 retval = SOS_OK;
245 if (SOS_OK != retval)
246 return retval;
247
248
249 SOS_ASSERT_FATAL(chardev->ref_cnt > 1);
250 chardev->ref_cnt --;
251
252 sos_kfree((sos_vaddr_t) chardev_of);
253 return retval;
254 }
255
256
257
258
259
260
261
262
263 static sos_ret_t
264 duplicate_opened_chardev(struct sos_fs_opened_file *this,
265 const struct sos_process * for_owner,
266 struct sos_fs_opened_file **result)
267 {
268 sos_ret_t retval;
269 struct sos_chardev_opened_file *chardev_of
270 = ((struct sos_chardev_opened_file*)this);
271 struct sos_chardev_opened_file *new_chardev_of;
272 struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(this->direntry);
273
274 *result = NULL;
275
276
277 struct sos_chardev_class * chardev = chardev_of->class;
278 SOS_ASSERT_FATAL(NULL != chardev);
279
280
281 new_chardev_of = (struct sos_chardev_opened_file*)
282 sos_kmalloc(sizeof(struct sos_chardev_opened_file), 0);
283 if (NULL == new_chardev_of)
284 return -SOS_ENOMEM;
285
286 memcpy(new_chardev_of, chardev_of, sizeof(*new_chardev_of));
287 new_chardev_of->super.owner = for_owner;
288 new_chardev_of->super.direntry = NULL;
289
290 SOS_ASSERT_FATAL(chardev->ref_cnt > 1);
291 chardev->ref_cnt ++;
292
293 retval = chardev->ops->open(fsnode,
294 & new_chardev_of->super, chardev->custom_data);
295 if (SOS_OK != retval)
296 {
297 sos_kfree((sos_vaddr_t) new_chardev_of);
298 chardev->ref_cnt --;
299 return retval;
300 }
301
302
303 SOS_ASSERT_FATAL(NULL != new_chardev_of->super.ops_file);
304 SOS_ASSERT_FATAL(NULL != new_chardev_of->super.ops_file->seek);
305 SOS_ASSERT_FATAL(NULL != new_chardev_of->super.ops_file->read);
306
307 *result = & new_chardev_of->super;
308 return retval;
309 }
310
311
312
313
314
315
316
317
318
319
320 static sos_ret_t chardev_wrap_seek(struct sos_fs_opened_file *this,
321 sos_lsoffset_t offset,
322 sos_seek_whence_t whence,
323 sos_lsoffset_t * result_position)
324 {
325 sos_ret_t retval = -SOS_ENOSYS;
326 struct sos_chardev_opened_file *chardev_of
327 = ((struct sos_chardev_opened_file*)this);
328
329 struct sos_chardev_class * chardev = chardev_of->class;
330 SOS_ASSERT_FATAL(NULL != chardev);
331 SOS_ASSERT_FATAL(NULL != chardev->ops);
332
333 if (NULL != chardev->ops->seek)
334 retval = chardev->ops->seek(this, offset, whence, result_position);
335
336 return retval;
337 }
338
339
340
341
342
343
344 static sos_ret_t chardev_wrap_read(struct sos_fs_opened_file *this,
345 sos_uaddr_t dest_buf,
346 sos_size_t * len)
347 {
348 sos_ret_t retval = -SOS_ENOSYS;
349 struct sos_chardev_opened_file *chardev_of
350 = ((struct sos_chardev_opened_file*)this);
351
352 struct sos_chardev_class * chardev = chardev_of->class;
353 SOS_ASSERT_FATAL(NULL != chardev);
354 SOS_ASSERT_FATAL(NULL != chardev->ops);
355
356 if (NULL != chardev->ops->read)
357 retval = chardev->ops->read(this, dest_buf, len);
358
359 return retval;
360 }
361
362
363
364
365
366
367 static sos_ret_t chardev_wrap_write(struct sos_fs_opened_file *this,
368 sos_uaddr_t src_buf,
369 sos_size_t * len)
370 {
371 sos_ret_t retval = -SOS_ENOSYS;
372 struct sos_chardev_opened_file *chardev_of
373 = ((struct sos_chardev_opened_file*)this);
374
375 struct sos_chardev_class * chardev = chardev_of->class;
376 SOS_ASSERT_FATAL(NULL != chardev);
377 SOS_ASSERT_FATAL(NULL != chardev->ops);
378
379 if (NULL != chardev->ops->write)
380 retval = chardev->ops->write(this, src_buf, len);
381
382 return retval;
383 }
384
385
386
387
388
389
390 static sos_ret_t chardev_wrap_mmap(struct sos_fs_opened_file *this,
391 sos_uaddr_t *uaddr, sos_size_t size,
392 sos_ui32_t access_rights,
393 sos_ui32_t flags,
394 sos_luoffset_t offset)
395 {
396 sos_ret_t retval = -SOS_ENOSYS;
397 struct sos_chardev_opened_file *chardev_of
398 = ((struct sos_chardev_opened_file*)this);
399
400 struct sos_chardev_class * chardev = chardev_of->class;
401 SOS_ASSERT_FATAL(NULL != chardev);
402 SOS_ASSERT_FATAL(NULL != chardev->ops);
403
404 if (NULL != chardev->ops->mmap)
405 retval = chardev->ops->mmap(this, uaddr, size,
406 access_rights, flags, offset);
407
408 return retval;
409 }
410
411
412
413
414
415
416 static sos_ret_t chardev_wrap_fcntl(struct sos_fs_opened_file *this,
417 int req_id,
418 sos_ui32_t req_arg)
419 {
420 sos_ret_t retval = -SOS_ENOSYS;
421 struct sos_chardev_opened_file *chardev_of
422 = ((struct sos_chardev_opened_file*)this);
423
424 struct sos_chardev_class * chardev = chardev_of->class;
425 SOS_ASSERT_FATAL(NULL != chardev);
426 SOS_ASSERT_FATAL(NULL != chardev->ops);
427
428 if (NULL != chardev->ops->fcntl)
429 retval = chardev->ops->fcntl(this, req_id, req_arg);
430
431 return retval;
432 }
433
434
435
436
437
438
439 static sos_ret_t chardev_wrap_ioctl(struct sos_fs_opened_file *this,
440 int req_id,
441 sos_ui32_t req_arg)
442 {
443 sos_ret_t retval = -SOS_ENOSYS;
444 struct sos_chardev_opened_file *chardev_of
445 = ((struct sos_chardev_opened_file*)this);
446
447 struct sos_chardev_class * chardev = chardev_of->class;
448 SOS_ASSERT_FATAL(NULL != chardev);
449 SOS_ASSERT_FATAL(NULL != chardev->ops);
450
451 if (NULL != chardev->ops->ioctl)
452 retval = chardev->ops->ioctl(this, req_id, req_arg);
453
454 return retval;
455 }
456
457
458
459
460
461 static struct sos_fs_ops_opened_file chardev_ops_opened_file
462 = (struct sos_fs_ops_opened_file) {
463 .seek = chardev_wrap_seek,
464 .read = chardev_wrap_read,
465 .write = chardev_wrap_write,
466 .mmap = chardev_wrap_mmap,
467 .fcntl = chardev_wrap_fcntl
468 };
469
470
471 static struct sos_fs_ops_opened_chardev chardev_ops_opened_chardev
472 = (struct sos_fs_ops_opened_chardev) {
473 .ioctl = chardev_wrap_ioctl
474 };