xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/devfs/devfs.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * Copyright (c) 2006-2018, 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 
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_ioctl(struct dfs_fd * file,int cmd,void * args)32 int dfs_device_fs_ioctl(struct dfs_fd *file, int cmd, void *args)
33 {
34     rt_err_t result;
35     rt_device_t dev_id;
36 
37     RT_ASSERT(file != RT_NULL);
38 
39     /* get device handler */
40     dev_id = (rt_device_t)file->data;
41     RT_ASSERT(dev_id != RT_NULL);
42 
43     /* close device handler */
44     result = rt_device_control(dev_id, cmd, args);
45     if (result == RT_EOK)
46         return RT_EOK;
47 
48     return result;
49 }
50 
dfs_device_fs_read(struct dfs_fd * file,void * buf,size_t count)51 int dfs_device_fs_read(struct dfs_fd *file, void *buf, size_t count)
52 {
53     int result;
54     rt_device_t dev_id;
55 
56     RT_ASSERT(file != RT_NULL);
57 
58     /* get device handler */
59     dev_id = (rt_device_t)file->data;
60     RT_ASSERT(dev_id != RT_NULL);
61 
62     /* read device data */
63     result = rt_device_read(dev_id, file->pos, buf, count);
64     file->pos += result;
65 
66     return result;
67 }
68 
dfs_device_fs_write(struct dfs_fd * file,const void * buf,size_t count)69 int dfs_device_fs_write(struct dfs_fd *file, const void *buf, size_t count)
70 {
71     int result;
72     rt_device_t dev_id;
73 
74     RT_ASSERT(file != RT_NULL);
75 
76     /* get device handler */
77     dev_id = (rt_device_t)file->data;
78     RT_ASSERT(dev_id != RT_NULL);
79 
80     /* read device data */
81     result = rt_device_write(dev_id, file->pos, buf, count);
82     file->pos += result;
83 
84     return result;
85 }
86 
dfs_device_fs_close(struct dfs_fd * file)87 int dfs_device_fs_close(struct dfs_fd *file)
88 {
89     rt_err_t result;
90     rt_device_t dev_id;
91 
92     RT_ASSERT(file != RT_NULL);
93 
94     if (file->type == FT_DIRECTORY)
95     {
96         struct device_dirent *root_dirent;
97 
98         root_dirent = (struct device_dirent *)file->data;
99         RT_ASSERT(root_dirent != RT_NULL);
100 
101         /* release dirent */
102         rt_free(root_dirent);
103         return RT_EOK;
104     }
105 
106     /* get device handler */
107     dev_id = (rt_device_t)file->data;
108     RT_ASSERT(dev_id != RT_NULL);
109 
110     /* close device handler */
111     result = rt_device_close(dev_id);
112     if (result == RT_EOK)
113     {
114         file->data = RT_NULL;
115 
116         return RT_EOK;
117     }
118 
119     return -EIO;
120 }
121 
dfs_device_fs_open(struct dfs_fd * file)122 int dfs_device_fs_open(struct dfs_fd *file)
123 {
124     rt_err_t result;
125     rt_device_t device;
126 
127     /* open root directory */
128     if ((file->path[0] == '/') && (file->path[1] == '\0') &&
129         (file->flags & O_DIRECTORY))
130     {
131         struct rt_object *object;
132         struct rt_list_node *node;
133         struct rt_object_information *information;
134         struct device_dirent *root_dirent;
135         rt_uint32_t count = 0;
136 
137         /* lock scheduler */
138         rt_enter_critical();
139 
140         /* traverse device object */
141         information = rt_object_get_information(RT_Object_Class_Device);
142         RT_ASSERT(information != RT_NULL);
143         for (node = information->object_list.next; node != &(information->object_list); node = node->next)
144         {
145             count ++;
146         }
147 
148         root_dirent = (struct device_dirent *)rt_malloc(sizeof(struct device_dirent) +
149             count * sizeof(rt_device_t));
150         if (root_dirent != RT_NULL)
151         {
152             root_dirent->devices = (rt_device_t *)(root_dirent + 1);
153             root_dirent->read_index = 0;
154             root_dirent->device_count = count;
155             count = 0;
156             /* get all device node */
157             for (node = information->object_list.next; node != &(information->object_list); node = node->next)
158             {
159                 object = rt_list_entry(node, struct rt_object, list);
160                 root_dirent->devices[count] = (rt_device_t)object;
161                 count ++;
162             }
163         }
164         rt_exit_critical();
165 
166         /* set data */
167         file->data = root_dirent;
168 
169         return RT_EOK;
170     }
171 
172     device = rt_device_find(&file->path[1]);
173     if (device == RT_NULL)
174         return -ENODEV;
175 
176 #ifdef RT_USING_POSIX
177     if (device->fops)
178     {
179         /* use device fops */
180         file->fops = device->fops;
181         file->data = (void*)device;
182 
183         /* use fops */
184         if (file->fops->open)
185         {
186             result = file->fops->open(file);
187             if (result == RT_EOK || result == -RT_ENOSYS)
188             {
189                 return 0;
190             }
191         }
192     }
193     else
194 #endif
195     {
196         result = rt_device_open(device, RT_DEVICE_OFLAG_RDWR);
197         if (result == RT_EOK || result == -RT_ENOSYS)
198         {
199             file->data = device;
200             return RT_EOK;
201         }
202     }
203 
204     file->data = RT_NULL;
205     /* open device failed. */
206     return -EIO;
207 }
208 
dfs_device_fs_stat(struct dfs_filesystem * fs,const char * path,struct stat * st)209 int dfs_device_fs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
210 {
211     /* stat root directory */
212     if ((path[0] == '/') && (path[1] == '\0'))
213     {
214         st->st_dev = 0;
215 
216         st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
217             S_IWUSR | S_IWGRP | S_IWOTH;
218         st->st_mode &= ~S_IFREG;
219         st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
220 
221         st->st_size  = 0;
222         st->st_mtime = 0;
223 
224         return RT_EOK;
225     }
226     else
227     {
228         rt_device_t dev_id;
229 
230         dev_id = rt_device_find(&path[1]);
231         if (dev_id != RT_NULL)
232         {
233             st->st_dev = 0;
234 
235             st->st_mode = S_IRUSR | S_IRGRP | S_IROTH |
236                 S_IWUSR | S_IWGRP | S_IWOTH;
237 
238             if (dev_id->type == RT_Device_Class_Char)
239                 st->st_mode |= S_IFCHR;
240             else if (dev_id->type == RT_Device_Class_Block)
241                 st->st_mode |= S_IFBLK;
242             else if (dev_id->type == RT_Device_Class_Pipe)
243                 st->st_mode |= S_IFIFO;
244             else
245                 st->st_mode |= S_IFREG;
246 
247             st->st_size  = 0;
248             st->st_mtime = 0;
249 
250             return RT_EOK;
251         }
252     }
253 
254     return -ENOENT;
255 }
256 
dfs_device_fs_getdents(struct dfs_fd * file,struct dirent * dirp,uint32_t count)257 int dfs_device_fs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t count)
258 {
259     rt_uint32_t index;
260     rt_object_t object;
261     struct dirent *d;
262     struct device_dirent *root_dirent;
263 
264     root_dirent = (struct device_dirent *)file->data;
265     RT_ASSERT(root_dirent != RT_NULL);
266 
267     /* make integer count */
268     count = (count / sizeof(struct dirent));
269     if (count == 0)
270         return -EINVAL;
271 
272     for (index = 0; index < count && index + root_dirent->read_index < root_dirent->device_count;
273         index ++)
274     {
275         object = (rt_object_t)root_dirent->devices[root_dirent->read_index + index];
276 
277         d = dirp + index;
278         d->d_type = DT_REG;
279         d->d_namlen = RT_NAME_MAX;
280         d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
281         rt_strncpy(d->d_name, object->name, RT_NAME_MAX);
282     }
283 
284     root_dirent->read_index += index;
285 
286     return index * sizeof(struct dirent);
287 }
288 
dfs_device_fs_poll(struct dfs_fd * fd,struct rt_pollreq * req)289 static int dfs_device_fs_poll(struct dfs_fd *fd, struct rt_pollreq *req)
290 {
291     int mask = 0;
292 
293     return mask;
294 }
295 
296 static const struct dfs_file_ops _device_fops =
297 {
298     dfs_device_fs_open,
299     dfs_device_fs_close,
300     dfs_device_fs_ioctl,
301     dfs_device_fs_read,
302     dfs_device_fs_write,
303     RT_NULL,                    /* flush */
304     RT_NULL,                    /* lseek */
305     dfs_device_fs_getdents,
306     dfs_device_fs_poll,
307 };
308 
309 static const struct dfs_filesystem_ops _device_fs =
310 {
311     "devfs",
312     DFS_FS_FLAG_DEFAULT,
313     &_device_fops,
314 
315     dfs_device_fs_mount,
316     RT_NULL,
317     RT_NULL,
318     RT_NULL,
319 
320     RT_NULL,
321     dfs_device_fs_stat,
322     RT_NULL,
323 };
324 
devfs_init(void)325 int devfs_init(void)
326 {
327     /* register rom file system */
328     dfs_register(&_device_fs);
329 
330     return 0;
331 }
332