350bbd65e447ab64ed5b50de1757490ef75a27a4
[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 #include <usr/lunaix/dirent_defs.h>
7
8 extern struct v_inode_ops devfs_inode_ops;
9 extern struct v_file_ops devfs_file_ops;
10
11 int
12 devfs_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
13 {
14     assert(inode->data);
15
16     struct device* dev = resolve_device(inode->data);
17
18     if (!dev || !dev->ops.read) {
19         return ENOTSUP;
20     }
21
22     return dev->ops.read(dev, buffer, fpos, len);
23 }
24
25 int
26 devfs_write(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
27 {
28     assert(inode->data);
29
30     struct device* dev = resolve_device(inode->data);
31
32     if (!dev || !dev->ops.write) {
33         return ENOTSUP;
34     }
35
36     return dev->ops.write(dev, buffer, fpos, len);
37 }
38
39 int
40 devfs_read_page(struct v_inode* inode, void* buffer, size_t fpos)
41 {
42     assert(inode->data);
43
44     struct device* dev = resolve_device(inode->data);
45
46     if (!dev || !dev->ops.read_page) {
47         return ENOTSUP;
48     }
49
50     return dev->ops.read_page(dev, buffer, fpos);
51 }
52
53 int
54 devfs_write_page(struct v_inode* inode, void* buffer, size_t fpos)
55 {
56     assert(inode->data);
57
58     struct device* dev = resolve_device(inode->data);
59
60     if (!dev || !dev->ops.read_page) {
61         return ENOTSUP;
62     }
63
64     return dev->ops.read_page(dev, buffer, fpos);
65 }
66
67 int
68 devfs_get_itype(struct device_meta* dm)
69 {
70     int itype = VFS_IFFILE;
71
72     if (valid_device_subtype_ref(dm, DEV_CAT)) {
73         return VFS_IFDIR;
74     }
75
76     struct device* dev = resolve_device(dm);
77     int dev_if = dev->dev_type & DEV_MSKIF;
78     
79     if (dev_if == DEV_IFVOL) {
80         itype |= VFS_IFVOLDEV;
81     } else if (dev_if == DEV_IFSEQ) {
82         itype |= VFS_IFSEQDEV;
83     } else {
84         itype |= VFS_IFDEV;
85     }
86     return itype;
87 }
88
89 int
90 devfs_get_dtype(struct device_meta* dev)
91 {
92     if (valid_device_subtype_ref(dev, DEV_CAT)) {
93         return DT_DIR;
94     }
95     return DT_FILE;
96 }
97
98 int
99 devfs_mknod(struct v_dnode* dnode, struct device_meta* dev)
100 {
101     assert(dev);
102
103     struct v_inode* devnod = vfs_i_find(dnode->super_block, dev->dev_uid);
104     if (!devnod) {
105         if ((devnod = vfs_i_alloc(dnode->super_block))) {
106             devnod->id = dev->dev_uid;
107             devnod->data = dev;
108             devnod->itype = devfs_get_itype(dev);
109
110             vfs_i_addhash(devnod);
111         } else {
112             return ENOMEM;
113         }
114     }
115
116     vfs_assign_inode(dnode, devnod);
117     return 0;
118 }
119
120 int
121 devfs_dirlookup(struct v_inode* this, struct v_dnode* dnode)
122 {
123     void* data = this->data;
124     struct device_meta* rootdev = resolve_device_meta(data);
125
126     if (data && !rootdev) {
127         return ENOTDIR;
128     }
129
130     struct device_meta* dev =
131       device_getbyhname(rootdev, &dnode->name);
132     
133     if (!dev) {
134         return ENOENT;
135     }
136
137     return devfs_mknod(dnode, dev);
138 }
139
140 int
141 devfs_readdir(struct v_file* file, struct dir_context* dctx)
142 {
143     void* data = file->inode->data;
144     struct device_meta* rootdev = resolve_device_meta(data);
145
146     if (data && !rootdev) {
147         return ENOTDIR;
148     }
149
150     struct device_meta* dev =
151       device_getbyoffset(rootdev, dctx->index);
152     
153     if (!dev) {
154         return 0;
155     }
156
157     dctx->read_complete_callback(
158       dctx, dev->name.value, dev->name.len, devfs_get_dtype(dev));
159     return 1;
160 }
161
162 void
163 devfs_init_inode(struct v_superblock* vsb, struct v_inode* inode)
164 {
165     inode->ops = &devfs_inode_ops;
166     inode->default_fops = &devfs_file_ops;
167 }
168
169 int
170 devfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
171 {
172     vsb->ops.init_inode = devfs_init_inode;
173
174     struct v_inode* rootnod = vfs_i_alloc(vsb);
175
176     if (!rootnod) {
177         return ENOMEM;
178     }
179
180     rootnod->id = -1;
181     rootnod->itype = VFS_IFDIR;
182
183     vfs_i_addhash(rootnod);
184     vfs_assign_inode(mount_point, rootnod);
185
186     return 0;
187 }
188
189 int
190 devfs_unmount(struct v_superblock* vsb)
191 {
192     return 0;
193 }
194
195 void
196 devfs_init()
197 {
198     struct filesystem* fs = fsm_new_fs("devfs", 5);
199     fsm_register(fs);
200     fs->mount = devfs_mount;
201     fs->unmount = devfs_unmount;
202 }
203 EXPORT_FILE_SYSTEM(devfs, devfs_init);
204
205 struct v_inode_ops devfs_inode_ops = { .dir_lookup = devfs_dirlookup,
206                                        .open = default_inode_open,
207                                        .mkdir = default_inode_mkdir,
208                                        .rmdir = default_inode_rmdir };
209
210 struct v_file_ops devfs_file_ops = { .close = default_file_close,
211                                      .read = devfs_read,
212                                      .read_page = devfs_read_page,
213                                      .write = devfs_write,
214                                      .write_page = devfs_write_page,
215                                      .seek = default_file_seek,
216                                      .readdir = devfs_readdir };