renamed and cleaned up export header files to match linux convention
[lunaix-os.git] / lunaix-os / kernel / device / devfs.c
1 #include <lunaix/device.h>
2 #include <lunaix/fs/api.h>
3 #include <lunaix/fs/devfs.h>
4 #include <lunaix/spike.h>
5
6 #include <usr/lunaix/dirent.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(morph_t* obj)
69 {
70     int itype = VFS_IFDEV;
71
72     if (morph_type_of(obj, devcat_morpher)) {
73         return VFS_IFDIR;
74     }
75
76     struct device* dev = resolve_device(obj);
77
78     if (!dev) {
79         return itype;
80     }
81     
82     int dev_if = dev->dev_type & DEV_MSKIF;
83     if (dev_if == DEV_IFVOL) {
84         itype |= VFS_IFVOLDEV;
85     }
86
87     // otherwise, the mapping is considered to be generic seq dev.
88     return itype;
89 }
90
91 static inline int
92 devfs_get_dtype(morph_t* dev_morph)
93 {
94     if (morph_type_of(dev_morph, devcat_morpher)) {
95         return DT_DIR;
96     }
97     return DT_FILE;
98 }
99
100 static inline morph_t*
101 __try_resolve(struct v_inode* inode)
102 {
103     if (!inode->data) {
104         return dev_object_root;
105     }
106
107     return resolve_device_morph(inode->data);
108 }
109
110 int
111 devfs_mknod(struct v_dnode* dnode, morph_t* obj)
112 {
113     struct v_inode* devnod;
114     
115     assert(obj);
116
117     devnod = vfs_i_find(dnode->super_block, morpher_uid(obj));
118     if (!devnod) {
119         if ((devnod = vfs_i_alloc(dnode->super_block))) {
120             devnod->id = morpher_uid(obj);
121             devnod->data = changeling_ref(obj);
122             devnod->itype = devfs_get_itype(obj);
123
124             vfs_i_addhash(devnod);
125         } else {
126             return ENOMEM;
127         }
128     }
129
130     vfs_assign_inode(dnode, devnod);
131     return 0;
132 }
133
134 int
135 devfs_dirlookup(struct v_inode* this, struct v_dnode* dnode)
136 {
137     morph_t *mobj, *root;
138
139     root = __try_resolve(this);
140     if (!root) {
141         return ENOTDIR;
142     }
143
144     mobj = changeling_find(root, &dnode->name);
145     if (!mobj) {
146         return ENOENT;
147     }
148
149     return devfs_mknod(dnode, mobj);
150 }
151
152 int
153 devfs_readdir(struct v_file* file, struct dir_context* dctx)
154 {
155     morph_t *mobj, *root;
156
157     root = __try_resolve(file->inode);
158     if (!root) {
159         return ENOTDIR;
160     }
161
162     if (fsapi_handle_pseudo_dirent(file, dctx)) {
163         return 1;
164     }
165
166     mobj = changeling_get_at(root, file->f_pos - 2);
167     if (!mobj) {
168         return 0;
169     }
170
171     dctx->read_complete_callback(dctx, 
172                                  mobj->name.value, mobj->name.len, 
173                                  devfs_get_dtype(mobj));
174     return 1;
175 }
176
177 void
178 devfs_init_inode(struct v_superblock* vsb, struct v_inode* inode)
179 {
180     inode->ops = &devfs_inode_ops;
181     inode->default_fops = &devfs_file_ops;
182
183     // we set default access right to be 0775.
184     // TODO need a way to allow this to be changed
185     
186     fsapi_inode_setaccess(inode, FSACL_DEFAULT);
187     fsapi_inode_setowner(inode, 0, 0);
188 }
189
190 int
191 devfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
192 {
193     vsb->ops.init_inode = devfs_init_inode;
194
195     struct v_inode* rootnod = vfs_i_alloc(vsb);
196
197     if (!rootnod) {
198         return ENOMEM;
199     }
200
201     rootnod->id = -1;
202     rootnod->itype = VFS_IFDIR;
203
204     vfs_i_addhash(rootnod);
205     vfs_assign_inode(mount_point, rootnod);
206
207     return 0;
208 }
209
210 int
211 devfs_unmount(struct v_superblock* vsb)
212 {
213     return 0;
214 }
215
216 void
217 devfs_init()
218 {
219     struct filesystem* fs;
220     fs = fsapi_fs_declare("devfs", FSTYPE_PSEUDO);
221     
222     fsapi_fs_set_mntops(fs, devfs_mount, devfs_unmount);
223     fsapi_fs_finalise(fs);
224 }
225 EXPORT_FILE_SYSTEM(devfs, devfs_init);
226
227 struct v_inode_ops devfs_inode_ops = { .dir_lookup = devfs_dirlookup,
228                                        .open = default_inode_open,
229                                        .mkdir = default_inode_mkdir,
230                                        .rmdir = default_inode_rmdir };
231
232 struct v_file_ops devfs_file_ops = { .close = default_file_close,
233                                      .read = devfs_read,
234                                      .read_page = devfs_read_page,
235                                      .write = devfs_write,
236                                      .write_page = devfs_write_page,
237                                      .seek = default_file_seek,
238                                      .readdir = devfs_readdir };