Second Extended Filesystem (ext2) and other improvements (#33)
[lunaix-os.git] / lunaix-os / kernel / device / device.c
1
2 #include <lunaix/device.h>
3 #include <lunaix/fs.h>
4 #include <lunaix/fs/twifs.h>
5 #include <lunaix/ioctl.h>
6 #include <lunaix/mm/valloc.h>
7 #include <lunaix/spike.h>
8 #include <lunaix/syscall.h>
9 #include <lunaix/syscall_utils.h>
10
11 #include <klibc/strfmt.h>
12 #include <klibc/string.h>
13
14 static DEFINE_LLIST(root_list);
15
16 static volatile u32_t devid = 0;
17
18 struct devclass default_devclass = {};
19
20 void
21 device_setname_vargs(struct device_meta* dev, char* fmt, va_list args)
22 {
23     size_t strlen = ksnprintfv(dev->name_val, fmt, DEVICE_NAME_SIZE, args);
24
25     dev->name = HSTR(dev->name_val, strlen);
26
27     hstr_rehash(&dev->name, HSTR_FULL_HASH);
28 }
29
30 void
31 device_register_generic(struct device_meta* devm, struct devclass* class, char* fmt, ...)
32 {
33     va_list args;
34     va_start(args, fmt);
35
36     if (fmt) {
37         device_setname_vargs(devm, fmt, args);
38     }
39
40     if (class && valid_device_subtype_ref(devm, DEV_STRUCT)) {
41         struct device* dev = to_dev(devm);
42         dev->ident = (struct devident){ .fn_grp = class->fn_grp,
43                                         .unique = DEV_UNIQUE(class->device,
44                                                              class->variant) };
45     }
46
47     devm->dev_uid = devid++;
48
49     struct device_meta* parent = devm->parent;
50     if (parent) {
51         assert(valid_device_subtype_ref(parent, DEV_CAT));
52         llist_append(&parent->children, &devm->siblings);
53     } else {
54         llist_append(&root_list, &devm->siblings);
55     }
56
57     va_end(args);
58 }
59
60 static void
61 device_init_meta(struct device_meta* dmeta, struct device_meta* parent, unsigned int subtype) 
62 {
63     dmeta->magic = DEV_STRUCT_MAGIC_MASK | subtype;
64     dmeta->parent = parent;
65
66     llist_init_head(&dmeta->children);
67 }
68
69 void
70 device_create(struct device* dev,
71               struct device_meta* parent,
72               u32_t type,
73               void* underlay)
74 {
75     dev->magic = DEV_STRUCT_MAGIC;
76     dev->underlay = underlay;
77     dev->dev_type = type;
78
79     device_init_meta(dev_meta(dev), parent, DEV_STRUCT);
80     llist_init_head(&dev->capabilities);
81     mutex_init(&dev->lock);
82     iopoll_init_evt_q(&dev->pollers);
83 }
84
85 struct device*
86 device_alloc(struct device_meta* parent, u32_t type, void* underlay)
87 {
88     struct device* dev = vzalloc(sizeof(struct device));
89
90     if (!dev) {
91         return NULL;
92     }
93
94     device_create(dev, parent, type, underlay);
95
96     return dev;
97 }
98
99 struct device_alias*
100 device_alloc_alias(struct device_meta* parent, struct device_meta* aliased)
101 {
102     struct device_alias* dev = vzalloc(sizeof(struct device_alias));
103
104     if (!dev) {
105         return NULL;
106     }
107
108     device_init_meta(dev_meta(dev), parent, DEV_ALIAS);
109     dev->alias = aliased;
110
111     return dev;
112 }
113
114 struct device_cat*
115 device_alloc_cat(struct device_meta* parent)
116 {
117     struct device_cat* dev = vzalloc(sizeof(struct device_cat));
118
119     if (!dev) {
120         return NULL;
121     }
122
123     device_init_meta(dev_meta(dev), parent, DEV_CAT);
124
125     return dev;
126 }
127
128
129 void
130 device_setname(struct device_meta* dev, char* fmt, ...)
131 {
132     va_list args;
133     va_start(args, fmt);
134
135     device_setname_vargs(dev, fmt, args);
136
137     va_end(args);
138 }
139
140 struct device_cat*
141 device_addcat(struct device_meta* parent, char* name_fmt, ...)
142 {
143     va_list args;
144     va_start(args, name_fmt);
145
146     struct device_cat* dev = device_alloc_cat(parent);
147
148     device_setname_vargs(dev_meta(dev), name_fmt, args);
149     device_register_generic(dev_meta(dev), NULL, NULL);
150
151     va_end(args);
152     return dev;
153 }
154
155 struct device_alias*
156 device_addalias(struct device_meta* parent, struct device_meta* aliased, char* name_fmt, ...)
157 {
158     va_list args;
159     va_start(args, name_fmt);
160
161     struct device_alias* dev = device_alloc_alias(parent, aliased);
162
163     device_setname_vargs(dev_meta(dev), name_fmt, args);
164     device_register_generic(dev_meta(dev), NULL, NULL);
165
166     va_end(args);
167     return dev;
168 }
169
170 struct device_meta*
171 device_getbyid(struct llist_header* devlist, u32_t id)
172 {
173     devlist = devlist ? devlist : &root_list;
174     struct device_meta *pos, *n;
175     llist_for_each(pos, n, devlist, siblings)
176     {
177         if (pos->dev_uid == id) {
178             return pos;
179         }
180     }
181
182     return NULL;
183 }
184
185 struct device_meta*
186 device_getbyhname(struct device_meta* root_dev, struct hstr* name)
187 {
188     struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
189     struct device_meta *pos, *n;
190     llist_for_each(pos, n, devlist, siblings)
191     {
192         if (HSTR_EQ(&pos->name, name)) {
193             return pos;
194         }
195     }
196
197     return NULL;
198 }
199
200 struct device_meta*
201 device_getbyname(struct device_meta* root_dev, const char* name, size_t len)
202 {
203     struct hstr hname = HSTR(name, len);
204     hstr_rehash(&hname, HSTR_FULL_HASH);
205
206     return device_getbyhname(root_dev, &hname);
207 }
208
209 void
210 device_remove(struct device_meta* dev)
211 {
212     llist_delete(&dev->siblings);
213     vfree(dev);
214 }
215
216 struct device_meta*
217 device_getbyoffset(struct device_meta* root_dev, int offset)
218 {
219     struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
220     struct device_meta *pos, *n;
221     int off = 0;
222     llist_for_each(pos, n, devlist, siblings)
223     {
224         if (off++ >= offset) {
225             return pos;
226         }
227     }
228     return NULL;
229 }
230
231 void
232 device_populate_info(struct device* dev, struct dev_info* devinfo)
233 {
234     devinfo->dev_id.group = dev->ident.fn_grp;
235     devinfo->dev_id.unique = dev->ident.unique;
236
237     if (!devinfo->dev_name.buf) {
238         return;
239     }
240
241     struct device_def* def = devdef_byident(&dev->ident);
242     size_t buflen = devinfo->dev_name.buf_len;
243
244     strncpy(devinfo->dev_name.buf, def->name, buflen);
245     devinfo->dev_name.buf[buflen - 1] = 0;
246 }
247
248 struct device_meta*
249 resolve_device_meta(void* maybe_dev) {
250     if (!valid_device_ref(maybe_dev)) {
251         return NULL;
252     }
253
254     struct device_meta* dm = (struct device_meta*)maybe_dev;
255     unsigned int subtype = dm->magic ^ DEV_STRUCT_MAGIC_MASK;
256     
257     switch (subtype)
258     {
259         case DEV_STRUCT:
260         case DEV_CAT:
261             return dm;
262         
263         case DEV_ALIAS: {
264             struct device_meta* aliased_dm = dm;
265             
266             while(valid_device_subtype_ref(aliased_dm, DEV_ALIAS)) {
267                 aliased_dm = to_aliasdev(aliased_dm)->alias;
268             }
269
270             return aliased_dm;
271         }
272         default:
273             return NULL;
274     }
275 }
276
277 struct device*
278 resolve_device(void* maybe_dev) {
279     struct device_meta* dm = resolve_device_meta(maybe_dev);
280     
281     if (!valid_device_subtype_ref(dm, DEV_STRUCT)) {
282         return NULL;
283     }
284
285     return to_dev(dm);
286 }
287
288 void
289 device_alert_poller(struct device* dev, int poll_evt)
290 {
291     dev->poll_evflags = poll_evt;
292     iopoll_wake_pollers(&dev->pollers);
293 }
294
295 __DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, sc_va_list, _args)
296 {
297     int errno = -1;
298     struct v_fd* fd_s;
299     va_list args;
300
301     convert_valist(&args, _args);
302
303     if ((errno &= vfs_getfd(fd, &fd_s))) {
304         goto done;
305     }
306
307     struct device* dev = resolve_device(fd_s->file->inode->data);
308     if (!valid_device_subtype_ref(dev, DEV_STRUCT)) {
309         errno = ENODEV;
310         goto done;
311     }
312
313     if (req == DEVIOIDENT) {
314         struct dev_info* devinfo = va_arg(args, struct dev_info*);
315         device_populate_info(dev, devinfo);
316         errno = 0;
317     }
318
319     if (!dev->ops.exec_cmd) {
320         errno = ENOTSUP;
321         goto done;
322     }
323
324     errno = dev->ops.exec_cmd(dev, req, args);
325
326 done:
327     return DO_STATUS_OR_RETURN(errno);
328 }