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