feat: owloysius - dynamic init function invocator
[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     mutex_init(&dev->lock);
81     iopoll_init_evt_q(&dev->pollers);
82 }
83
84 struct device*
85 device_alloc(struct device_meta* parent, u32_t type, void* underlay)
86 {
87     struct device* dev = vzalloc(sizeof(struct device));
88
89     if (!dev) {
90         return NULL;
91     }
92
93     device_create(dev, parent, type, underlay);
94
95     return dev;
96 }
97
98 struct device_alias*
99 device_alloc_alias(struct device_meta* parent, struct device_meta* aliased)
100 {
101     struct device_alias* dev = vzalloc(sizeof(struct device_alias));
102
103     if (!dev) {
104         return NULL;
105     }
106
107     device_init_meta(dev_meta(dev), parent, DEV_ALIAS);
108     dev->alias = aliased;
109
110     return dev;
111 }
112
113 struct device_cat*
114 device_alloc_cat(struct device_meta* parent)
115 {
116     struct device_cat* dev = vzalloc(sizeof(struct device_cat));
117
118     if (!dev) {
119         return NULL;
120     }
121
122     device_init_meta(dev_meta(dev), parent, DEV_CAT);
123
124     return dev;
125 }
126
127
128 void
129 device_setname(struct device_meta* dev, char* fmt, ...)
130 {
131     va_list args;
132     va_start(args, fmt);
133
134     device_setname_vargs(dev, fmt, args);
135
136     va_end(args);
137 }
138
139 struct device_cat*
140 device_addcat(struct device_meta* parent, char* name_fmt, ...)
141 {
142     va_list args;
143     va_start(args, name_fmt);
144
145     struct device_cat* dev = device_alloc_cat(parent);
146
147     device_setname_vargs(dev_meta(dev), name_fmt, args);
148     device_register_generic(dev_meta(dev), NULL, NULL);
149
150     va_end(args);
151     return dev;
152 }
153
154 struct device_alias*
155 device_addalias(struct device_meta* parent, struct device_meta* aliased, char* name_fmt, ...)
156 {
157     va_list args;
158     va_start(args, name_fmt);
159
160     struct device_alias* dev = device_alloc_alias(parent, aliased);
161
162     device_setname_vargs(dev_meta(dev), name_fmt, args);
163     device_register_generic(dev_meta(dev), NULL, NULL);
164
165     va_end(args);
166     return dev;
167 }
168
169 struct device_meta*
170 device_getbyid(struct llist_header* devlist, u32_t id)
171 {
172     devlist = devlist ? devlist : &root_list;
173     struct device_meta *pos, *n;
174     llist_for_each(pos, n, devlist, siblings)
175     {
176         if (pos->dev_uid == id) {
177             return pos;
178         }
179     }
180
181     return NULL;
182 }
183
184 struct device_meta*
185 device_getbyhname(struct device_meta* root_dev, struct hstr* name)
186 {
187     struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
188     struct device_meta *pos, *n;
189     llist_for_each(pos, n, devlist, siblings)
190     {
191         if (HSTR_EQ(&pos->name, name)) {
192             return pos;
193         }
194     }
195
196     return NULL;
197 }
198
199 struct device_meta*
200 device_getbyname(struct device_meta* root_dev, const char* name, size_t len)
201 {
202     struct hstr hname = HSTR(name, len);
203     hstr_rehash(&hname, HSTR_FULL_HASH);
204
205     return device_getbyhname(root_dev, &hname);
206 }
207
208 void
209 device_remove(struct device_meta* dev)
210 {
211     llist_delete(&dev->siblings);
212     vfree(dev);
213 }
214
215 struct device_meta*
216 device_getbyoffset(struct device_meta* root_dev, int offset)
217 {
218     struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
219     struct device_meta *pos, *n;
220     int off = 0;
221     llist_for_each(pos, n, devlist, siblings)
222     {
223         if (off++ >= offset) {
224             return pos;
225         }
226     }
227     return NULL;
228 }
229
230 void
231 device_populate_info(struct device* dev, struct dev_info* devinfo)
232 {
233     devinfo->dev_id.group = dev->ident.fn_grp;
234     devinfo->dev_id.unique = dev->ident.unique;
235
236     if (!devinfo->dev_name.buf) {
237         return;
238     }
239
240     struct device_def* def = devdef_byident(&dev->ident);
241     size_t buflen = devinfo->dev_name.buf_len;
242
243     strncpy(devinfo->dev_name.buf, def->name, buflen);
244     devinfo->dev_name.buf[buflen - 1] = 0;
245 }
246
247 struct device_meta*
248 resolve_device_meta(void* maybe_dev) {
249     if (!valid_device_ref(maybe_dev)) {
250         return NULL;
251     }
252
253     struct device_meta* dm = (struct device_meta*)maybe_dev;
254     unsigned int subtype = dm->magic ^ DEV_STRUCT_MAGIC_MASK;
255     
256     switch (subtype)
257     {
258         case DEV_STRUCT:
259         case DEV_CAT:
260             return dm;
261         
262         case DEV_ALIAS: {
263             struct device_meta* aliased_dm = dm;
264             
265             while(valid_device_subtype_ref(aliased_dm, DEV_ALIAS)) {
266                 aliased_dm = to_aliasdev(aliased_dm)->alias;
267             }
268
269             return aliased_dm;
270         }
271         default:
272             return NULL;
273     }
274 }
275
276 struct device*
277 resolve_device(void* maybe_dev) {
278     struct device_meta* dm = resolve_device_meta(maybe_dev);
279     
280     if (!valid_device_subtype_ref(dm, DEV_STRUCT)) {
281         return NULL;
282     }
283
284     return to_dev(dm);
285 }
286
287 void
288 device_alert_poller(struct device* dev, int poll_evt)
289 {
290     dev->poll_evflags = poll_evt;
291     iopoll_wake_pollers(&dev->pollers);
292 }
293
294 __DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, va_list, args)
295 {
296     int errno = -1;
297     struct v_fd* fd_s;
298     if ((errno &= vfs_getfd(fd, &fd_s))) {
299         goto done;
300     }
301
302     struct device* dev = (struct device*)fd_s->file->inode->data;
303     if (valid_device_subtype_ref(dev, DEV_STRUCT)) {
304         errno &= ENODEV;
305         goto done;
306     }
307
308     if (req == DEVIOIDENT) {
309         struct dev_info* devinfo = va_arg(args, struct dev_info*);
310         device_populate_info(dev, devinfo);
311         errno = 0;
312     }
313
314     if (!dev->ops.exec_cmd) {
315         errno &= ENOTSUP;
316         goto done;
317     }
318
319     errno &= dev->ops.exec_cmd(dev, req, args);
320
321 done:
322     return DO_STATUS_OR_RETURN(errno);
323 }