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 <rtthread.h>
12 #include <rtdevice.h>
13
14 #include <dfs.h>
15 #include <dfs_fs.h>
16 #include <dfs_file.h>
17
18 #include "devfs.h"
19
20 struct device_dirent
21 {
22 rt_device_t *devices;
23 rt_uint16_t read_index;
24 rt_uint16_t device_count;
25 };
26
dfs_device_fs_mount(struct dfs_filesystem * fs,unsigned long rwflag,const void * data)27 int dfs_device_fs_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *data)
28 {
29 return RT_EOK;
30 }
31
dfs_device_fs_statfs(struct dfs_filesystem * fs,struct statfs * buf)32 int dfs_device_fs_statfs(struct dfs_filesystem *fs, struct statfs *buf)
33 {
34 buf->f_bsize = 512;
35 buf->f_blocks = 2048 * 64; // 64M
36 buf->f_bfree = buf->f_blocks;
37 buf->f_bavail = buf->f_bfree;
38
39 return RT_EOK;
40 }
41
dfs_device_fs_ioctl(struct dfs_file * file,int cmd,void * args)42 int dfs_device_fs_ioctl(struct dfs_file *file, int cmd, void *args)
43 {
44 rt_err_t result;
45 rt_device_t dev_id;
46
47 RT_ASSERT(file != RT_NULL);
48
49 /* get device handler */
50 dev_id = (rt_device_t)file->vnode->data;
51 RT_ASSERT(dev_id != RT_NULL);
52
53 if ((file->vnode->path[0] == '/') && (file->vnode->path[1] == '\0'))
54 return -RT_ENOSYS;
55
56 /* close device handler */
57 result = rt_device_control(dev_id, cmd, args);
58 if (result == RT_EOK)
59 return RT_EOK;
60
61 return result;
62 }
63
dfs_device_fs_read(struct dfs_file * file,void * buf,size_t count)64 ssize_t dfs_device_fs_read(struct dfs_file *file, void *buf, size_t count)
65 {
66 int result;
67 rt_device_t dev_id;
68
69 RT_ASSERT(file != RT_NULL);
70
71 /* get device handler */
72 dev_id = (rt_device_t)file->vnode->data;
73 RT_ASSERT(dev_id != RT_NULL);
74
75 if ((file->vnode->path[0] == '/') && (file->vnode->path[1] == '\0'))
76 return -RT_ENOSYS;
77
78 /* read device data */
79 result = rt_device_read(dev_id, file->pos, buf, count);
80 file->pos += result;
81
82 return result;
83 }
84
dfs_device_fs_write(struct dfs_file * file,const void * buf,size_t count)85 ssize_t dfs_device_fs_write(struct dfs_file *file, const void *buf, size_t count)
86 {
87 int result;
88 rt_device_t dev_id;
89
90 RT_ASSERT(file != RT_NULL);
91
92 /* get device handler */
93 dev_id = (rt_device_t)file->vnode->data;
94 RT_ASSERT(dev_id != RT_NULL);
95
96 if ((file->vnode->path[0] == '/') && (file->vnode->path[1] == '\0'))
97 return -RT_ENOSYS;
98
99 /* read device data */
100 result = rt_device_write(dev_id, file->pos, buf, count);
101 file->pos += result;
102
103 return result;
104 }
105
dfs_device_fs_close(struct dfs_file * file)106 int dfs_device_fs_close(struct dfs_file *file)
107 {
108 rt_err_t result;
109 rt_device_t dev_id;
110
111 RT_ASSERT(file != RT_NULL);
112 RT_ASSERT(file->vnode->ref_count > 0);
113
114 if (file->vnode->ref_count > 1)
115 {
116 return 0;
117 }
118
119 if (file->vnode->type == FT_DIRECTORY && (file->vnode->path[0] == '/') && (file->vnode->path[1] == '\0'))
120 {
121 struct device_dirent *root_dirent;
122
123 root_dirent = (struct device_dirent *)file->vnode->data;
124 RT_ASSERT(root_dirent != RT_NULL);
125
126 /* release dirent */
127 rt_free(root_dirent);
128 return RT_EOK;
129 }
130
131 /* get device handler */
132 dev_id = (rt_device_t)file->vnode->data;
133 RT_ASSERT(dev_id != RT_NULL);
134
135 /* close device handler */
136 result = rt_device_close(dev_id);
137 if (result == RT_EOK)
138 {
139 file->vnode->data = RT_NULL;
140
141 return RT_EOK;
142 }
143
144 return -EIO;
145 }
146
dfs_device_fs_open(struct dfs_file * file)147 int dfs_device_fs_open(struct dfs_file *file)
148 {
149 rt_err_t result;
150 rt_device_t device;
151
152 RT_ASSERT(file->vnode->ref_count > 0);
153 if (file->vnode->ref_count > 1)
154 {
155 file->pos = 0;
156 return 0;
157 }
158 /* open root directory */
159 if ((file->vnode->path[0] == '/') && (file->vnode->path[1] == '\0') &&
160 (file->flags & O_DIRECTORY))
161 {
162 struct rt_object *object;
163 struct rt_list_node *node;
164 struct rt_object_information *information;
165 struct device_dirent *root_dirent;
166 rt_uint32_t count = 0;
167
168 /* lock scheduler */
169 rt_enter_critical();
170
171 /* traverse device object */
172 information = rt_object_get_information(RT_Object_Class_Device);
173 RT_ASSERT(information != RT_NULL);
174 for (node = information->object_list.next; node != &(information->object_list); node = node->next)
175 {
176 count ++;
177 }
178 rt_exit_critical();
179
180 root_dirent = (struct device_dirent *)rt_malloc(sizeof(struct device_dirent) +
181 count * sizeof(rt_device_t));
182 if (root_dirent != RT_NULL)
183 {
184 /* lock scheduler */
185 rt_enter_critical();
186
187 root_dirent->devices = (rt_device_t *)(root_dirent + 1);
188 root_dirent->read_index = 0;
189 root_dirent->device_count = count;
190 count = 0;
191 /* get all device node */
192 for (node = information->object_list.next; node != &(information->object_list); node = node->next)
193 {
194 /* avoid memory write through */
195 if (count == root_dirent->device_count)
196 {
197 rt_kprintf("warning: There are newly added devices that are not displayed!");
198 break;
199 }
200 object = rt_list_entry(node, struct rt_object, list);
201 root_dirent->devices[count] = (rt_device_t)object;
202 count ++;
203 }
204 rt_exit_critical();
205 }
206
207 /* set data */
208 file->vnode->data = root_dirent;
209
210 return RT_EOK;
211 }
212 #ifdef RT_USING_DEV_BUS
213 else if (file->flags & O_CREAT)
214 {
215 if (!(file->flags & O_DIRECTORY))
216 {
217 return -ENOSYS;
218 }
219 /* regester bus device */
220 if (rt_device_bus_create(&file->vnode->path[1], 0) == RT_NULL)
221 {
222 return -EEXIST;
223 }
224 }
225 #endif
226
227 device = rt_device_find(&file->vnode->path[1]);
228 if (device == RT_NULL)
229 {
230 return -ENODEV;
231 }
232
233 #ifdef RT_USING_POSIX_DEVIO
234 if (device->fops)
235 {
236 /* use device fops */
237 file->vnode->fops = device->fops;
238 file->vnode->data = (void *)device;
239
240 /* use fops */
241 if (file->vnode->fops->open)
242 {
243 result = file->vnode->fops->open(file);
244 if (result == RT_EOK || result == -RT_ENOSYS)
245 {
246 file->vnode->type = FT_DEVICE;
247 return 0;
248 }
249 }
250 }
251 else
252 #endif /* RT_USING_POSIX_DEVIO */
253 {
254 result = rt_device_open(device, RT_DEVICE_OFLAG_RDWR);
255 if (result == RT_EOK || result == -RT_ENOSYS)
256 {
257 file->vnode->data = device;
258 file->vnode->type = FT_DEVICE;
259 return RT_EOK;
260 }
261 }
262
263 file->vnode->data = RT_NULL;
264 /* open device failed. */
265 return -EIO;
266 }
267
dfs_device_fs_unlink(struct dfs_filesystem * fs,const char * path)268 int dfs_device_fs_unlink(struct dfs_filesystem *fs, const char *path)
269 {
270 #ifdef RT_USING_DEV_BUS
271 rt_device_t dev_id;
272
273 dev_id = rt_device_find(&path[1]);
274 if (dev_id == RT_NULL)
275 {
276 return -1;
277 }
278 if (dev_id->type != RT_Device_Class_Bus)
279 {
280 return -1;
281 }
282 rt_device_bus_destroy(dev_id);
283 #endif
284 return RT_EOK;
285 }
286
dfs_device_fs_stat(struct dfs_filesystem * fs,const char * path,struct stat * st)287 int dfs_device_fs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
288 {
289 st->st_dev = (dev_t)((size_t)dfs_filesystem_lookup(fs->path));
290 /* stat root directory */
291 if ((path[0] == '/') && (path[1] == '\0'))
292 {
293 st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
294 S_IWUSR | S_IWGRP | S_IWOTH;
295 st->st_mode &= ~S_IFREG;
296 st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
297
298 st->st_size = 0;
299 st->st_mtime = 0;
300
301 return RT_EOK;
302 }
303 else
304 {
305 rt_device_t dev_id;
306
307 dev_id = rt_device_find(&path[1]);
308 if (dev_id != RT_NULL)
309 {
310 st->st_mode = S_IRUSR | S_IRGRP | S_IROTH |
311 S_IWUSR | S_IWGRP | S_IWOTH;
312
313 if (dev_id->type == RT_Device_Class_Char)
314 st->st_mode |= S_IFCHR;
315 else if (dev_id->type == RT_Device_Class_Block)
316 st->st_mode |= S_IFBLK;
317 else if (dev_id->type == RT_Device_Class_Pipe)
318 st->st_mode |= S_IFIFO;
319 else if (dev_id->type == RT_Device_Class_Bus)
320 st->st_mode |= S_IFDIR;
321 else
322 st->st_mode |= S_IFREG;
323
324 st->st_size = 0;
325 st->st_mtime = 0;
326
327 return RT_EOK;
328 }
329 }
330
331 return -ENOENT;
332 }
333
dfs_device_fs_getdents(struct dfs_file * file,struct dirent * dirp,uint32_t count)334 int dfs_device_fs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
335 {
336 rt_uint32_t index;
337 rt_object_t object;
338 struct dirent *d;
339 struct device_dirent *root_dirent;
340
341 root_dirent = (struct device_dirent *)file->vnode->data;
342 RT_ASSERT(root_dirent != RT_NULL);
343
344 /* make integer count */
345 count = (count / sizeof(struct dirent));
346 if (count == 0)
347 return -EINVAL;
348
349 for (index = 0; index < count && index + root_dirent->read_index < root_dirent->device_count;
350 index ++)
351 {
352 object = (rt_object_t)root_dirent->devices[root_dirent->read_index + index];
353
354 d = dirp + index;
355 if ((((rt_device_t)object)->type) == RT_Device_Class_Bus)
356 {
357 d->d_type = DT_DIR;
358 }
359 else
360 {
361 d->d_type = DT_REG;
362 }
363 d->d_namlen = RT_NAME_MAX;
364 d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
365 rt_strncpy(d->d_name, object->name, RT_NAME_MAX);
366 }
367
368 root_dirent->read_index += index;
369
370 return index * sizeof(struct dirent);
371 }
372
dfs_device_fs_poll(struct dfs_file * fd,struct rt_pollreq * req)373 static int dfs_device_fs_poll(struct dfs_file *fd, struct rt_pollreq *req)
374 {
375 int mask = 0;
376
377 return mask;
378 }
379
380 static const struct dfs_file_ops _device_fops =
381 {
382 dfs_device_fs_open,
383 dfs_device_fs_close,
384 dfs_device_fs_ioctl,
385 dfs_device_fs_read,
386 dfs_device_fs_write,
387 RT_NULL, /* flush */
388 RT_NULL, /* lseek */
389 dfs_device_fs_getdents,
390 dfs_device_fs_poll,
391 };
392
393 static const struct dfs_filesystem_ops _device_fs =
394 {
395 "devfs",
396 DFS_FS_FLAG_DEFAULT,
397 &_device_fops,
398 dfs_device_fs_mount,
399 RT_NULL, /*unmount*/
400 RT_NULL, /*mkfs*/
401 dfs_device_fs_statfs,
402 dfs_device_fs_unlink,
403 dfs_device_fs_stat,
404 RT_NULL, /*rename*/
405 };
406
devfs_init(void)407 int devfs_init(void)
408 {
409 /* register device file system */
410 dfs_register(&_device_fs);
411
412 return 0;
413 }
414