refactor: improve on scrolling experience in lunaix console
[lunaix-os.git] / lunaix-os / kernel / device / devfs.c
1 #include <lunaix/device.h>
2 #include <lunaix/fs.h>
3 #include <lunaix/fs/devfs.h>
4 #include <lunaix/spike.h>
5
6 extern struct v_inode_ops devfs_inode_ops;
7 extern struct v_file_ops devfs_file_ops;
8
9 int
10 devfs_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
11 {
12     assert(inode->data);
13
14     struct device* dev = (struct device*)inode->data;
15
16     if (!dev->read) {
17         return ENOTSUP;
18     }
19
20     return dev->read(dev, buffer, fpos, len);
21 }
22
23 int
24 devfs_write(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
25 {
26     assert(inode->data);
27
28     struct device* dev = (struct device*)inode->data;
29
30     if (!dev->write) {
31         return ENOTSUP;
32     }
33
34     return dev->write(dev, buffer, fpos, len);
35 }
36
37 int
38 devfs_get_itype(struct device* dev)
39 {
40     int itype = VFS_IFFILE;
41     int dev_if = dev->dev_type & DEV_MSKIF;
42     if (dev_if == DEV_IFCAT) {
43         itype = VFS_IFDIR;
44     } else if (dev_if == DEV_IFVOL) {
45         itype |= VFS_IFVOLDEV;
46     } else {
47         itype |= VFS_IFSEQDEV;
48     }
49     return itype;
50 }
51
52 int
53 devfs_mknod(struct v_dnode* dnode, struct device* dev)
54 {
55     assert(dev);
56
57     struct v_inode* devnod = vfs_i_find(dnode->super_block, dev->dev_id);
58     if (!devnod) {
59         if ((devnod = vfs_i_alloc(dnode->super_block))) {
60             devnod->id = dev->dev_id;
61             devnod->data = dev;
62             devnod->itype = devfs_get_itype(dev);
63
64             vfs_i_addhash(devnod);
65         } else {
66             return ENOMEM;
67         }
68     }
69
70     vfs_assign_inode(dnode, devnod);
71     return 0;
72 }
73
74 int
75 devfs_dirlookup(struct v_inode* this, struct v_dnode* dnode)
76 {
77     struct device* dev =
78       device_getbyhname((struct device*)this->data, &dnode->name);
79     if (!dev) {
80         return ENOENT;
81     }
82     return devfs_mknod(dnode, dev);
83 }
84
85 int
86 devfs_readdir(struct v_file* file, struct dir_context* dctx)
87 {
88     struct device* dev =
89       device_getbyoffset((struct device*)(file->inode->data), dctx->index);
90     if (!dev) {
91         return 0;
92     }
93     dctx->read_complete_callback(
94       dctx, dev->name.value, dev->name.len, devfs_get_itype(dev));
95     return 1;
96 }
97
98 void
99 devfs_init_inode(struct v_superblock* vsb, struct v_inode* inode)
100 {
101     inode->ops = &devfs_inode_ops;
102     inode->default_fops = &devfs_file_ops;
103 }
104
105 int
106 devfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
107 {
108     vsb->ops.init_inode = devfs_init_inode;
109
110     struct v_inode* rootnod = vfs_i_alloc(vsb);
111
112     if (!rootnod) {
113         return ENOMEM;
114     }
115
116     rootnod->id = -1;
117     rootnod->itype = VFS_IFDIR;
118
119     vfs_i_addhash(rootnod);
120     vfs_assign_inode(mount_point, rootnod);
121
122     return 0;
123 }
124
125 int
126 devfs_unmount(struct v_superblock* vsb)
127 {
128     return 0;
129 }
130
131 void
132 devfs_init()
133 {
134     struct filesystem* fs = fsm_new_fs("devfs", 5);
135     fsm_register(fs);
136     fs->mount = devfs_mount;
137     fs->unmount = devfs_unmount;
138 }
139
140 struct v_inode_ops devfs_inode_ops = { .dir_lookup = devfs_dirlookup,
141                                        .open = default_inode_open,
142                                        .mkdir = default_inode_mkdir,
143                                        .rmdir = default_inode_rmdir };
144
145 struct v_file_ops devfs_file_ops = { .close = default_file_close,
146                                      .read = devfs_read,
147                                      .write = devfs_write,
148                                      .seek = default_file_seek,
149                                      .readdir = devfs_readdir };