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