devfs.c 7.6 KB
Newer Older
Y
yiyue.fang 已提交
1
/*
2
 * Copyright (c) 2006-2018, RT-Thread Development Team
Y
yiyue.fang 已提交
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
Y
yiyue.fang 已提交
5 6 7
 *
 * Change Logs:
 * Date           Author       Notes
B
BernardXiong 已提交
8
 * 2018-02-11     Bernard      Ignore O_CREAT flag in open.
Y
yiyue.fang 已提交
9 10
 */

11
#include <rtthread.h>
B
bernard 已提交
12 13
#include <rtdevice.h>

14 15
#include <dfs.h>
#include <dfs_fs.h>
B
bernard 已提交
16
#include <dfs_file.h>
17 18 19 20 21

#include "devfs.h"

struct device_dirent
{
Y
yiyue.fang 已提交
22 23 24
    rt_device_t *devices;
    rt_uint16_t read_index;
    rt_uint16_t device_count;
25 26
};

27
int dfs_device_fs_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *data)
28
{
B
bernard 已提交
29
    return RT_EOK;
30 31
}

32
int dfs_device_fs_ioctl(struct dfs_fd *file, int cmd, void *args)
33
{
Y
yiyue.fang 已提交
34 35
    rt_err_t result;
    rt_device_t dev_id;
36

Y
yiyue.fang 已提交
37
    RT_ASSERT(file != RT_NULL);
38

Y
yiyue.fang 已提交
39 40 41
    /* get device handler */
    dev_id = (rt_device_t)file->data;
    RT_ASSERT(dev_id != RT_NULL);
42

Y
yiyue.fang 已提交
43 44 45
    /* close device handler */
    result = rt_device_control(dev_id, cmd, args);
    if (result == RT_EOK)
B
bernard 已提交
46
        return RT_EOK;
47

B
bernard 已提交
48
    return result;
49 50
}

B
bernard 已提交
51
int dfs_device_fs_read(struct dfs_fd *file, void *buf, size_t count)
52
{
Y
yiyue.fang 已提交
53 54
    int result;
    rt_device_t dev_id;
55

Y
yiyue.fang 已提交
56
    RT_ASSERT(file != RT_NULL);
57

Y
yiyue.fang 已提交
58 59 60
    /* get device handler */
    dev_id = (rt_device_t)file->data;
    RT_ASSERT(dev_id != RT_NULL);
61

Y
yiyue.fang 已提交
62 63 64
    /* read device data */
    result = rt_device_read(dev_id, file->pos, buf, count);
    file->pos += result;
65

Y
yiyue.fang 已提交
66
    return result;
67 68
}

B
bernard 已提交
69
int dfs_device_fs_write(struct dfs_fd *file, const void *buf, size_t count)
70
{
Y
yiyue.fang 已提交
71 72
    int result;
    rt_device_t dev_id;
73

Y
yiyue.fang 已提交
74
    RT_ASSERT(file != RT_NULL);
75

Y
yiyue.fang 已提交
76 77 78
    /* get device handler */
    dev_id = (rt_device_t)file->data;
    RT_ASSERT(dev_id != RT_NULL);
79

Y
yiyue.fang 已提交
80 81 82
    /* read device data */
    result = rt_device_write(dev_id, file->pos, buf, count);
    file->pos += result;
83

Y
yiyue.fang 已提交
84
    return result;
85 86
}

87
int dfs_device_fs_close(struct dfs_fd *file)
88
{
Y
yiyue.fang 已提交
89 90
    rt_err_t result;
    rt_device_t dev_id;
91

Y
yiyue.fang 已提交
92
    RT_ASSERT(file != RT_NULL);
93

Y
yiyue.fang 已提交
94 95 96
    if (file->type == FT_DIRECTORY)
    {
        struct device_dirent *root_dirent;
97

Y
yiyue.fang 已提交
98 99
        root_dirent = (struct device_dirent *)file->data;
        RT_ASSERT(root_dirent != RT_NULL);
100

Y
yiyue.fang 已提交
101 102
        /* release dirent */
        rt_free(root_dirent);
B
bernard 已提交
103
        return RT_EOK;
Y
yiyue.fang 已提交
104
    }
105

Y
yiyue.fang 已提交
106 107 108
    /* get device handler */
    dev_id = (rt_device_t)file->data;
    RT_ASSERT(dev_id != RT_NULL);
109

Y
yiyue.fang 已提交
110 111 112 113 114
    /* close device handler */
    result = rt_device_close(dev_id);
    if (result == RT_EOK)
    {
        file->data = RT_NULL;
115

B
bernard 已提交
116
        return RT_EOK;
Y
yiyue.fang 已提交
117
    }
118

B
bernard 已提交
119
    return -EIO;
120 121
}

122
int dfs_device_fs_open(struct dfs_fd *file)
123
{
124
    rt_err_t result;
Y
yiyue.fang 已提交
125 126 127 128
    rt_device_t device;

    /* open root directory */
    if ((file->path[0] == '/') && (file->path[1] == '\0') &&
B
bernard 已提交
129
        (file->flags & O_DIRECTORY))
Y
yiyue.fang 已提交
130 131 132 133 134 135
    {
        struct rt_object *object;
        struct rt_list_node *node;
        struct rt_object_information *information;
        struct device_dirent *root_dirent;
        rt_uint32_t count = 0;
136

Y
yiyue.fang 已提交
137 138 139 140
        /* lock scheduler */
        rt_enter_critical();

        /* traverse device object */
141 142
        information = rt_object_get_information(RT_Object_Class_Device);
        RT_ASSERT(information != RT_NULL);
Y
yiyue.fang 已提交
143 144 145 146 147
        for (node = information->object_list.next; node != &(information->object_list); node = node->next)
        {
            count ++;
        }

148 149
        root_dirent = (struct device_dirent *)rt_malloc(sizeof(struct device_dirent) +
                      count * sizeof(rt_device_t));
Y
yiyue.fang 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
        if (root_dirent != RT_NULL)
        {
            root_dirent->devices = (rt_device_t *)(root_dirent + 1);
            root_dirent->read_index = 0;
            root_dirent->device_count = count;
            count = 0;
            /* get all device node */
            for (node = information->object_list.next; node != &(information->object_list); node = node->next)
            {
                object = rt_list_entry(node, struct rt_object, list);
                root_dirent->devices[count] = (rt_device_t)object;
                count ++;
            }
        }
        rt_exit_critical();

        /* set data */
        file->data = root_dirent;
168

B
bernard 已提交
169
        return RT_EOK;
Y
yiyue.fang 已提交
170 171 172 173
    }

    device = rt_device_find(&file->path[1]);
    if (device == RT_NULL)
B
bernard 已提交
174
        return -ENODEV;
Y
yiyue.fang 已提交
175

B
bernard 已提交
176
#ifdef RT_USING_POSIX
B
bernard 已提交
177
    if (device->fops)
178
    {
B
bernard 已提交
179 180
        /* use device fops */
        file->fops = device->fops;
181
        file->data = (void *)device;
B
bernard 已提交
182 183 184 185 186 187 188 189 190 191 192 193

        /* use fops */
        if (file->fops->open)
        {
            result = file->fops->open(file);
            if (result == RT_EOK || result == -RT_ENOSYS)
            {
                return 0;
            }
        }
    }
    else
B
bernard 已提交
194
#endif
B
bernard 已提交
195 196 197 198 199 200 201
    {
        result = rt_device_open(device, RT_DEVICE_OFLAG_RDWR);
        if (result == RT_EOK || result == -RT_ENOSYS)
        {
            file->data = device;
            return RT_EOK;
        }
202 203
    }

B
bernard 已提交
204
    file->data = RT_NULL;
205
    /* open device failed. */
B
bernard 已提交
206
    return -EIO;
207 208
}

209
int dfs_device_fs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
210
{
Y
yiyue.fang 已提交
211 212 213 214 215
    /* stat root directory */
    if ((path[0] == '/') && (path[1] == '\0'))
    {
        st->st_dev = 0;

B
bernard 已提交
216
        st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
217
                      S_IWUSR | S_IWGRP | S_IWOTH;
B
bernard 已提交
218 219
        st->st_mode &= ~S_IFREG;
        st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
Y
yiyue.fang 已提交
220 221 222

        st->st_size  = 0;
        st->st_mtime = 0;
223

B
bernard 已提交
224
        return RT_EOK;
Y
yiyue.fang 已提交
225 226 227 228 229 230 231 232 233 234
    }
    else
    {
        rt_device_t dev_id;

        dev_id = rt_device_find(&path[1]);
        if (dev_id != RT_NULL)
        {
            st->st_dev = 0;

B
bernard 已提交
235
            st->st_mode = S_IRUSR | S_IRGRP | S_IROTH |
236
                          S_IWUSR | S_IWGRP | S_IWOTH;
Y
yiyue.fang 已提交
237 238

            if (dev_id->type == RT_Device_Class_Char)
B
bernard 已提交
239
                st->st_mode |= S_IFCHR;
Y
yiyue.fang 已提交
240
            else if (dev_id->type == RT_Device_Class_Block)
B
bernard 已提交
241 242 243
                st->st_mode |= S_IFBLK;
            else if (dev_id->type == RT_Device_Class_Pipe)
                st->st_mode |= S_IFIFO;
Y
yiyue.fang 已提交
244
            else
B
bernard 已提交
245
                st->st_mode |= S_IFREG;
Y
yiyue.fang 已提交
246 247 248

            st->st_size  = 0;
            st->st_mtime = 0;
249

B
bernard 已提交
250
            return RT_EOK;
Y
yiyue.fang 已提交
251 252 253
        }
    }

B
bernard 已提交
254
    return -ENOENT;
255 256
}

B
bernard 已提交
257
int dfs_device_fs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t count)
258
{
Y
yiyue.fang 已提交
259 260 261 262 263 264 265 266 267 268 269
    rt_uint32_t index;
    rt_object_t object;
    struct dirent *d;
    struct device_dirent *root_dirent;

    root_dirent = (struct device_dirent *)file->data;
    RT_ASSERT(root_dirent != RT_NULL);

    /* make integer count */
    count = (count / sizeof(struct dirent));
    if (count == 0)
B
bernard 已提交
270
        return -EINVAL;
Y
yiyue.fang 已提交
271 272 273 274 275 276 277

    for (index = 0; index < count && index + root_dirent->read_index < root_dirent->device_count; 
        index ++)
    {
        object = (rt_object_t)root_dirent->devices[root_dirent->read_index + index];

        d = dirp + index;
B
bernard 已提交
278
        d->d_type = DT_REG;
Y
yiyue.fang 已提交
279 280 281 282 283 284 285 286
        d->d_namlen = RT_NAME_MAX;
        d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
        rt_strncpy(d->d_name, object->name, RT_NAME_MAX);
    }

    root_dirent->read_index += index;

    return index * sizeof(struct dirent);
287 288
}

B
bernard 已提交
289
static int dfs_device_fs_poll(struct dfs_fd *fd, struct rt_pollreq *req)
290
{
B
bernard 已提交
291 292 293 294
    int mask = 0;

    return mask;
}
Y
yiyue.fang 已提交
295

296
static const struct dfs_file_ops _device_fops =
B
bernard 已提交
297
{
Y
yiyue.fang 已提交
298 299 300 301 302
    dfs_device_fs_open,
    dfs_device_fs_close,
    dfs_device_fs_ioctl,
    dfs_device_fs_read,
    dfs_device_fs_write,
B
bernard 已提交
303 304 305 306 307 308
    RT_NULL,                    /* flush */
    RT_NULL,                    /* lseek */
    dfs_device_fs_getdents,
    dfs_device_fs_poll,
};

309
static const struct dfs_filesystem_ops _device_fs =
B
bernard 已提交
310 311 312 313 314 315
{
    "devfs",
    DFS_FS_FLAG_DEFAULT,
    &_device_fops,

    dfs_device_fs_mount,
Y
yiyue.fang 已提交
316 317
    RT_NULL,
    RT_NULL,
B
bernard 已提交
318 319
    RT_NULL,

Y
yiyue.fang 已提交
320 321 322
    RT_NULL,
    dfs_device_fs_stat,
    RT_NULL,
323 324 325 326
};

int devfs_init(void)
{
Y
yiyue.fang 已提交
327 328
    /* register rom file system */
    dfs_register(&_device_fs);
329

Y
yiyue.fang 已提交
330
    return 0;
331
}