1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2018-02-11 Bernard Ignore O_CREAT flag in open.
9 */
10 #include <rthw.h>
11 #include <rtdbg.h>
12 #include <rtdevice.h>
13
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <sys/unistd.h>
17
18 #include <dfs.h>
19 #include <dfs_fs.h>
20 #include <dfs_file.h>
21 #include <dfs_dentry.h>
22 #include <dfs_mnt.h>
23
dfs_devfs_open(struct dfs_file * file)24 static int dfs_devfs_open(struct dfs_file *file)
25 {
26 int ret = RT_EOK;
27
28 RT_ASSERT(file != RT_NULL);
29 RT_ASSERT(file->vnode->ref_count > 0);
30
31 if (file->vnode->ref_count > 1)
32 {
33 if (file->vnode->type == FT_DIRECTORY
34 && !(file->flags & O_DIRECTORY))
35 {
36 return -ENOENT;
37 }
38 file->fpos = 0;
39 }
40
41 if (!S_ISDIR(file->vnode->mode))
42 {
43 rt_device_t device = RT_NULL;
44 struct dfs_dentry *de = file->dentry;
45 char *device_name = rt_malloc(DFS_PATH_MAX);
46
47 if (!device_name)
48 {
49 return -ENOMEM;
50 }
51
52 /* skip `/dev` */
53 rt_snprintf(device_name, DFS_PATH_MAX, "%s%s", de->mnt->fullpath + sizeof("/dev") - 1, de->pathname);
54
55 device = rt_device_find(device_name + 1);
56 if (device)
57 {
58 file->vnode->data = device;
59 #ifdef RT_USING_POSIX_DEVIO
60 if (device->fops && device->fops->open)
61 {
62 ret = device->fops->open(file);
63 if (ret == RT_EOK || ret == -RT_ENOSYS)
64 {
65 ret = RT_EOK;
66 }
67 }
68 else if (device->ops && file->vnode->ref_count == 1)
69 #else
70 if (device->ops && file->vnode->ref_count == 1)
71 #endif /* RT_USING_POSIX_DEVIO */
72 {
73 ret = rt_device_open(device, RT_DEVICE_OFLAG_RDWR);
74 if (ret == RT_EOK || ret == -RT_ENOSYS)
75 {
76 ret = RT_EOK;
77 }
78 }
79 }
80 rt_free(device_name);
81 }
82
83 return ret;
84 }
85
dfs_devfs_close(struct dfs_file * file)86 static int dfs_devfs_close(struct dfs_file *file)
87 {
88 int ret = RT_EOK;
89 rt_device_t device;
90
91 RT_ASSERT(file != RT_NULL);
92 RT_ASSERT(file->vnode->ref_count > 0);
93
94 if (file->vnode && file->vnode->data)
95 {
96 /* get device handler */
97 device = (rt_device_t)file->vnode->data;
98
99 #ifdef RT_USING_POSIX_DEVIO
100 if (device->fops && device->fops->close)
101 {
102 ret = device->fops->close(file);
103 }
104 else if (file->vnode->ref_count == 1)
105 #else
106 if (device->ops && file->vnode->ref_count == 1)
107 #endif /* RT_USING_POSIX_DEVIO */
108 {
109 /* close device handler */
110 ret = rt_device_close(device);
111 }
112 }
113
114 return ret;
115 }
116
_get_unit_shift(rt_device_t device)117 static rt_ubase_t _get_unit_shift(rt_device_t device)
118 {
119 rt_ubase_t shift = 0;
120
121 /**
122 * transfer unit size from POSIX RW(in bytes) to rt_device_R/W
123 * (block size for blk device, otherwise in bytes).
124 */
125 if (device->type == RT_Device_Class_Block)
126 {
127 struct rt_device_blk_geometry geometry = {0};
128
129 /* default to 512 */
130 shift = 9;
131 if (!rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry))
132 {
133 shift = __rt_ffs(geometry.block_size) - 1;
134 }
135 }
136
137 return shift;
138 }
139
dfs_devfs_read(struct dfs_file * file,void * buf,size_t count,off_t * pos)140 static ssize_t dfs_devfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
141 {
142 ssize_t ret = -RT_EIO;
143 rt_device_t device;
144
145 RT_ASSERT(file != RT_NULL);
146
147 if (file->vnode && file->vnode->data)
148 {
149 /* get device handler */
150 device = (rt_device_t)file->vnode->data;
151
152 #ifdef RT_USING_POSIX_DEVIO
153 if (device->fops && device->fops->read)
154 {
155 ret = device->fops->read(file, buf, count, pos);
156 }
157 else
158 #else
159 if (device->ops)
160 #endif /* RT_USING_POSIX_DEVIO */
161 {
162 rt_ubase_t shift = _get_unit_shift(device);
163
164 ret = rt_device_read(device, *pos, buf, count >> shift);
165 if (ret > 0)
166 {
167 ret <<= shift;
168 *pos += ret;
169 }
170 }
171 }
172
173 return ret;
174 }
175
dfs_devfs_write(struct dfs_file * file,const void * buf,size_t count,off_t * pos)176 static ssize_t dfs_devfs_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
177 {
178 ssize_t ret = -RT_EIO;
179 rt_device_t device;
180
181 RT_ASSERT(file != RT_NULL);
182
183 if(file->vnode->data)
184 {
185 /* get device handler */
186 device = (rt_device_t)file->vnode->data;
187
188 if ((file->dentry->pathname[0] == '/') && (file->dentry->pathname[1] == '\0'))
189 return -RT_ENOSYS;
190
191 #ifdef RT_USING_POSIX_DEVIO
192 if (device->fops && device->fops->write)
193 {
194 ret = device->fops->write(file, buf, count, pos);
195 }
196 else
197 #else
198 if (device->ops)
199 #endif /* RT_USING_POSIX_DEVIO */
200 {
201 rt_ubase_t shift = _get_unit_shift(device);
202
203 /* read device data */
204 ret = rt_device_write(device, *pos, buf, count >> shift);
205 if (ret > 0)
206 {
207 ret <<= shift;
208 *pos += ret;
209 }
210 }
211 }
212
213 return ret;
214 }
215
dfs_devfs_ioctl(struct dfs_file * file,int cmd,void * args)216 static int dfs_devfs_ioctl(struct dfs_file *file, int cmd, void *args)
217 {
218 int ret = RT_EOK;
219 rt_device_t device;
220
221 RT_ASSERT(file != RT_NULL);
222
223 if (file->vnode && file->vnode->data)
224 {
225 /* get device handler */
226 device = (rt_device_t)file->vnode->data;
227
228 if ((file->dentry->pathname[0] == '/') && (file->dentry->pathname[1] == '\0'))
229 return -RT_ENOSYS;
230
231 #ifdef RT_USING_POSIX_DEVIO
232 if (device->fops && device->fops->ioctl)
233 {
234 ret = device->fops->ioctl(file, cmd, args);
235 }
236 else
237 #endif /* RT_USING_POSIX_DEVIO */
238 {
239 ret = rt_device_control(device, cmd, args);
240 }
241 }
242
243 return ret;
244 }
245
dfs_devfs_getdents(struct dfs_file * file,struct dirent * dirp,uint32_t count)246 static int dfs_devfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
247 {
248 int ret = -RT_ENOSYS;
249
250 RT_ASSERT(file != RT_NULL);
251
252 return ret;
253 }
254
dfs_devfs_poll(struct dfs_file * file,struct rt_pollreq * req)255 static int dfs_devfs_poll(struct dfs_file *file, struct rt_pollreq *req)
256 {
257 int mask = 0;
258 rt_device_t device;
259
260 RT_ASSERT(file != RT_NULL);
261
262 if (file->vnode && file->vnode->data)
263 {
264 /* get device handler */
265 device = (rt_device_t)file->vnode->data;
266
267 #ifdef RT_USING_POSIX_DEVIO
268 if (device->fops && device->fops->poll)
269 {
270 mask = device->fops->poll(file, req);
271 }
272 #endif /* RT_USING_POSIX_DEVIO */
273 }
274
275 return mask;
276 }
277
dfs_devfs_flush(struct dfs_file * file)278 static int dfs_devfs_flush(struct dfs_file *file)
279 {
280 int ret = RT_EOK;
281 rt_device_t device;
282
283 RT_ASSERT(file != RT_NULL);
284
285 if (file->vnode && file->vnode->data)
286 {
287 /* get device handler */
288 device = (rt_device_t)file->vnode->data;
289
290 #ifdef RT_USING_POSIX_DEVIO
291 if (device->fops && device->fops->flush)
292 {
293 ret = device->fops->flush(file);
294 }
295 #endif /* RT_USING_POSIX_DEVIO */
296 }
297
298 return ret;
299 }
300
dfs_devfs_lseek(struct dfs_file * file,off_t offset,int wherece)301 static off_t dfs_devfs_lseek(struct dfs_file *file, off_t offset, int wherece)
302 {
303 off_t ret = -EPERM;
304 rt_device_t device;
305
306 RT_ASSERT(file != RT_NULL);
307
308 if (file->vnode && file->vnode->data)
309 {
310 /* get device handler */
311 device = (rt_device_t)file->vnode->data;
312
313 #ifdef RT_USING_POSIX_DEVIO
314 if (device->fops && device->fops->lseek)
315 {
316 ret = device->fops->lseek(file, offset, wherece);
317 }
318 #endif /* RT_USING_POSIX_DEVIO */
319 }
320
321 return ret;
322 }
323
dfs_devfs_truncate(struct dfs_file * file,off_t offset)324 static int dfs_devfs_truncate(struct dfs_file *file, off_t offset)
325 {
326 int ret = RT_EOK;
327 rt_device_t device;
328
329 RT_ASSERT(file != RT_NULL);
330
331 if (file->vnode && file->vnode->data)
332 {
333 /* get device handler */
334 device = (rt_device_t)file->vnode->data;
335
336 #ifdef RT_USING_POSIX_DEVIO
337 if (device->fops && device->fops->truncate)
338 {
339 ret = device->fops->truncate(file, offset);
340 }
341 #endif /* RT_USING_POSIX_DEVIO */
342 }
343
344 return ret;
345 }
346
dfs_devfs_mmap(struct dfs_file * file,struct lwp_avl_struct * mmap)347 static int dfs_devfs_mmap(struct dfs_file *file, struct lwp_avl_struct *mmap)
348 {
349 int ret = RT_EOK;
350 rt_device_t device;
351
352 RT_ASSERT(file != RT_NULL);
353
354 if (file->vnode && file->vnode->data)
355 {
356 /* get device handler */
357 device = (rt_device_t)file->vnode->data;
358
359 #ifdef RT_USING_POSIX_DEVIO
360 if (device->fops && device->fops->mmap)
361 {
362 ret = device->fops->mmap(file, mmap);
363 }
364 #endif /* RT_USING_POSIX_DEVIO */
365 }
366
367 return ret;
368 }
369
dfs_devfs_lock(struct dfs_file * file,struct file_lock * flock)370 static int dfs_devfs_lock(struct dfs_file *file, struct file_lock *flock)
371 {
372 int ret = RT_EOK;
373 rt_device_t device;
374
375 RT_ASSERT(file != RT_NULL);
376
377 if (file->vnode && file->vnode->data)
378 {
379 /* get device handler */
380 device = (rt_device_t)file->vnode->data;
381
382 #ifdef RT_USING_POSIX_DEVIO
383 if (device->fops && device->fops->lock)
384 {
385 ret = device->fops->lock(file, flock);
386 }
387 #endif /* RT_USING_POSIX_DEVIO */
388 }
389
390 return ret;
391 }
392
dfs_devfs_flock(struct dfs_file * file,int operation,struct file_lock * flock)393 static int dfs_devfs_flock(struct dfs_file *file, int operation, struct file_lock *flock)
394 {
395 int ret = RT_EOK;
396 rt_device_t device;
397
398 RT_ASSERT(file != RT_NULL);
399
400 if (file->vnode && file->vnode->data)
401 {
402 /* get device handler */
403 device = (rt_device_t)file->vnode->data;
404
405 #ifdef RT_USING_POSIX_DEVIO
406 if (device->fops && device->fops->flock)
407 {
408 ret = device->fops->flock(file, operation, flock);
409 }
410 #endif /* RT_USING_POSIX_DEVIO */
411 }
412
413 return ret;
414 }
415
416 static const struct dfs_file_ops _dev_fops =
417 {
418 .open = dfs_devfs_open,
419 .close = dfs_devfs_close,
420 .read = dfs_devfs_read,
421 .write = dfs_devfs_write,
422 .ioctl = dfs_devfs_ioctl,
423 .getdents = dfs_devfs_getdents,
424 .poll = dfs_devfs_poll,
425
426 .flush = dfs_devfs_flush,
427 .lseek = dfs_devfs_lseek,
428 .truncate = dfs_devfs_truncate,
429 .mmap = dfs_devfs_mmap,
430 .lock = dfs_devfs_lock,
431 .flock = dfs_devfs_flock,
432 };
433
dfs_devfs_fops(void)434 const struct dfs_file_ops *dfs_devfs_fops(void)
435 {
436 return &_dev_fops;
437 }
438
dfs_devfs_device_to_mode(struct rt_device * device)439 mode_t dfs_devfs_device_to_mode(struct rt_device *device)
440 {
441 mode_t mode = 0;
442
443 switch (device->type)
444 {
445 case RT_Device_Class_Char:
446 mode = S_IFCHR | 0666;
447 break;
448 case RT_Device_Class_Block:
449 mode = S_IFBLK | 0666;
450 break;
451 case RT_Device_Class_Pipe:
452 mode = S_IFIFO | 0666;
453 break;
454 default:
455 mode = S_IFCHR | 0666;
456 break;
457 }
458
459 return mode;
460 }
461
dfs_devfs_mkdir(const char * fullpath,mode_t mode)462 static void dfs_devfs_mkdir(const char *fullpath, mode_t mode)
463 {
464 int len = rt_strlen(fullpath);
465 char *path = (char *)rt_malloc(len + 1);
466
467 if (path)
468 {
469 int index = len - 1;
470
471 rt_strcpy(path, fullpath);
472
473 if (path[index] == '/')
474 {
475 path[index] = '\0';
476 index --;
477 }
478
479 while (path[index] != '/' && index >= 0)
480 {
481 index --;
482 }
483
484 path[index] = '\0';
485
486 if (index > 0 && access(path, 0) != 0)
487 {
488 int i = 0;
489
490 if (path[i] == '/')
491 {
492 i ++;
493 }
494
495 while (index > i)
496 {
497 if (path[i] == '/')
498 {
499 path[i] = '\0';
500 mkdir(path, mode);
501 path[i] = '/';
502 }
503
504 i ++;
505 }
506
507 mkdir(path, mode);
508 }
509 }
510 }
511
dfs_devfs_device_add(rt_device_t device)512 void dfs_devfs_device_add(rt_device_t device)
513 {
514 int fd;
515 char path[512];
516
517 if (device)
518 {
519 rt_snprintf(path, 512, "/dev/%s", device->parent.name);
520
521 if (access(path, 0) != 0)
522 {
523 mode_t mode = dfs_devfs_device_to_mode(device);
524
525 dfs_devfs_mkdir(path, mode);
526
527 fd = open(path, O_RDWR | O_CREAT, mode);
528 if (fd >= 0)
529 {
530 close(fd);
531 }
532 }
533 }
534 }
535
dfs_devfs_update(void)536 int dfs_devfs_update(void)
537 {
538 int count = rt_object_get_length(RT_Object_Class_Device);
539 if (count > 0)
540 {
541 rt_device_t *devices = rt_malloc(count * sizeof(rt_device_t));
542 if (devices)
543 {
544 rt_object_get_pointers(RT_Object_Class_Device, (rt_object_t *)devices, count);
545
546 for (int index = 0; index < count; index ++)
547 {
548 dfs_devfs_device_add(devices[index]);
549 }
550 rt_free(devices);
551 }
552 }
553
554 return count;
555 }
556