feat: input device subsystem to resolve race condition on polling input
[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 = device_getbyhname(this->data, &dnode->name);
78     if (!dev) {
79         return ENOENT;
80     }
81     return devfs_mknod(dnode, dev);
82 }
83
84 int
85 devfs_readdir(struct v_file* file, struct dir_context* dctx)
86 {
87     struct device* dev = device_getbyoffset(file->inode->data, dctx->index);
88     if (!dev) {
89         return 0;
90     }
91     dctx->read_complete_callback(
92       dctx, dev->name.value, dev->name.len, devfs_get_itype(dev));
93     return 1;
94 }
95
96 void
97 devfs_init_inode(struct v_superblock* vsb, struct v_inode* inode)
98 {
99     inode->ops = &devfs_inode_ops;
100     inode->default_fops = &devfs_file_ops;
101 }
102
103 int
104 devfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
105 {
106     vsb->ops.init_inode = devfs_init_inode;
107
108     struct v_inode* rootnod = vfs_i_alloc(vsb);
109
110     if (!rootnod) {
111         return ENOMEM;
112     }
113
114     rootnod->id = -1;
115     rootnod->itype = VFS_IFDIR;
116
117     vfs_i_addhash(rootnod);
118     vfs_assign_inode(mount_point, rootnod);
119
120     return 0;
121 }
122
123 int
124 devfs_unmount(struct v_superblock* vsb)
125 {
126     return 0;
127 }
128
129 void
130 devfs_init()
131 {
132     struct filesystem* fs = fsm_new_fs("devfs", 5);
133     fsm_register(fs);
134     fs->mount = devfs_mount;
135     fs->unmount = devfs_unmount;
136 }
137
138 struct v_inode_ops devfs_inode_ops = { .dir_lookup = devfs_dirlookup,
139                                        .open = default_inode_open,
140                                        .mkdir = default_inode_mkdir,
141                                        .rmdir = default_inode_rmdir };
142
143 struct v_file_ops devfs_file_ops = { .close = default_file_close,
144                                      .read = devfs_read,
145                                      .write = devfs_write,
146                                      .seek = default_file_seek,
147                                      .readdir = devfs_readdir };