feat: (devfs) a new filesystem for device exposure.
[lunaix-os.git] / lunaix-os / kernel / device / device.c
1 #include <klibc/stdio.h>
2 #include <lunaix/device.h>
3 #include <lunaix/fs/twifs.h>
4 #include <lunaix/mm/valloc.h>
5 #include <lunaix/spike.h>
6
7 static DEFINE_LLIST(root_list);
8
9 static volatile dev_t devid = 0;
10
11 struct device*
12 __device_add(struct device* parent,
13              void* underlay,
14              char* name_fmt,
15              uint32_t type,
16              va_list args)
17 {
18     struct device* dev = vzalloc(sizeof(struct device));
19
20     if (parent) {
21         assert((parent->dev_type & DEV_MSKIF) == DEV_IFCAT);
22     }
23
24     size_t strlen =
25       __sprintf_internal(dev->name_val, name_fmt, DEVICE_NAME_SIZE, args);
26
27     dev->dev_id = devid++;
28     dev->name = HSTR(dev->name_val, strlen);
29     dev->parent = parent;
30     dev->underlay = underlay;
31     dev->dev_type = type;
32
33     hstr_rehash(&dev->name, HSTR_FULL_HASH);
34     llist_append(&root_list, &dev->siblings);
35
36     return dev;
37 }
38
39 struct device*
40 device_addseq(struct device* parent, void* underlay, char* name_fmt, ...)
41 {
42     va_list args;
43     va_start(args, name_fmt);
44
45     struct device* dev =
46       __device_add(parent, underlay, name_fmt, DEV_IFSEQ, args);
47
48     va_end(args);
49     return dev;
50 }
51
52 struct device*
53 device_addvol(struct device* parent, void* underlay, char* name_fmt, ...)
54 {
55     va_list args;
56     va_start(args, name_fmt);
57
58     struct device* dev =
59       __device_add(parent, underlay, name_fmt, DEV_IFVOL, args);
60
61     va_end(args);
62     return dev;
63 }
64
65 struct device*
66 device_addcat(struct device* parent, char* name_fmt, ...)
67 {
68     va_list args;
69     va_start(args, name_fmt);
70
71     struct device* dev = __device_add(parent, NULL, name_fmt, DEV_IFCAT, args);
72
73     va_end(args);
74     return dev;
75 }
76
77 struct device*
78 device_getbyid(struct llist_header* devlist, dev_t id)
79 {
80     devlist = devlist ? devlist : &root_list;
81     struct device *pos, *n;
82     llist_for_each(pos, n, devlist, siblings)
83     {
84         if (pos->dev_id == id) {
85             return pos;
86         }
87     }
88
89     return NULL;
90 }
91
92 struct device*
93 device_getbyname(struct llist_header* devlist, struct hstr* name)
94 {
95     devlist = devlist ? devlist : &root_list;
96     struct device *pos, *n;
97     llist_for_each(pos, n, devlist, siblings)
98     {
99         if (HSTR_EQ(&pos->name, name)) {
100             return pos;
101         }
102     }
103
104     return NULL;
105 }
106
107 void
108 device_remove(struct device* dev)
109 {
110     llist_delete(&dev->siblings);
111     vfree(dev);
112 }
113
114 struct device*
115 device_getbyoffset(struct llist_header* devlist, int offset)
116 {
117     devlist = devlist ? devlist : &root_list;
118     struct device *pos, *n;
119     int off = 0;
120     llist_for_each(pos, n, devlist, siblings)
121     {
122         if (off++ >= offset) {
123             return pos;
124         }
125     }
126     return NULL;
127 }