feat: device subsystem rework
[lunaix-os.git] / lunaix-os / kernel / device / device.c
1 #include <klibc/stdio.h>
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 static DEFINE_LLIST(root_list);
12
13 static volatile dev_t devid = 0;
14
15 void
16 device_prepare(struct device* dev)
17 {
18     dev->magic = DEV_STRUCT_MAGIC;
19     dev->dev_id = devid++;
20
21     llist_init_head(&dev->children);
22 }
23
24 static void
25 device_setname_vargs(struct device* dev, char* fmt, va_list args)
26 {
27     size_t strlen =
28       __ksprintf_internal(dev->name_val, fmt, DEVICE_NAME_SIZE, args);
29
30     dev->name = HSTR(dev->name_val, strlen);
31
32     hstr_rehash(&dev->name, HSTR_FULL_HASH);
33 }
34
35 void
36 device_setname(struct device* dev, char* fmt, ...)
37 {
38     va_list args;
39     va_start(args, fmt);
40
41     device_setname_vargs(dev, fmt, args);
42
43     va_end(args);
44 }
45
46 struct device*
47 device_add_vargs(struct device* parent,
48                  void* underlay,
49                  char* name_fmt,
50                  u32_t type,
51                  va_list args)
52 {
53     struct device* dev = vzalloc(sizeof(struct device));
54
55     device_prepare(dev);
56
57     if (parent) {
58         assert((parent->dev_type & DEV_MSKIF) == DEV_IFCAT);
59         llist_append(&parent->children, &dev->siblings);
60     } else {
61         llist_append(&root_list, &dev->siblings);
62     }
63
64     if (name_fmt) {
65         device_setname_vargs(dev, name_fmt, args);
66     }
67
68     dev->parent = parent;
69     dev->underlay = underlay;
70     dev->dev_type = type;
71
72     return dev;
73 }
74
75 struct device*
76 device_add(struct device* parent,
77            void* underlay,
78            u32_t type,
79            char* name_fmt,
80            ...)
81 {
82     va_list args;
83     va_start(args, name_fmt);
84
85     struct device* dev =
86       device_add_vargs(parent, underlay, name_fmt, type, args);
87
88     va_end(args);
89     return dev;
90 }
91
92 struct device*
93 device_addsys(struct device* parent, void* underlay, char* name_fmt, ...)
94 {
95     va_list args;
96     va_start(args, name_fmt);
97
98     struct device* dev =
99       device_add_vargs(parent, underlay, name_fmt, DEV_IFSEQ, args);
100
101     va_end(args);
102     return dev;
103 }
104
105 struct device*
106 device_addseq(struct device* parent, void* underlay, char* name_fmt, ...)
107 {
108     va_list args;
109     va_start(args, name_fmt);
110
111     struct device* dev =
112       device_add_vargs(parent, underlay, name_fmt, DEV_IFSEQ, args);
113
114     va_end(args);
115     return dev;
116 }
117
118 struct device*
119 device_addvol(struct device* parent, void* underlay, char* name_fmt, ...)
120 {
121     va_list args;
122     va_start(args, name_fmt);
123
124     struct device* dev =
125       device_add_vargs(parent, underlay, name_fmt, DEV_IFVOL, args);
126
127     va_end(args);
128     return dev;
129 }
130
131 struct device*
132 device_addcat(struct device* parent, char* name_fmt, ...)
133 {
134     va_list args;
135     va_start(args, name_fmt);
136
137     struct device* dev =
138       device_add_vargs(parent, NULL, name_fmt, DEV_IFCAT, args);
139
140     va_end(args);
141     return dev;
142 }
143
144 struct device*
145 device_getbyid(struct llist_header* devlist, dev_t id)
146 {
147     devlist = devlist ? devlist : &root_list;
148     struct device *pos, *n;
149     llist_for_each(pos, n, devlist, siblings)
150     {
151         if (pos->dev_id == id) {
152             return pos;
153         }
154     }
155
156     return NULL;
157 }
158
159 struct device*
160 device_getbyhname(struct device* root_dev, struct hstr* name)
161 {
162     struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
163     struct device *pos, *n;
164     llist_for_each(pos, n, devlist, siblings)
165     {
166         if (HSTR_EQ(&pos->name, name)) {
167             return pos;
168         }
169     }
170
171     return NULL;
172 }
173
174 struct device*
175 device_getbyname(struct device* root_dev, const char* name, size_t len)
176 {
177     struct hstr hname = HSTR(name, len);
178     hstr_rehash(&hname, HSTR_FULL_HASH);
179
180     return device_getbyhname(root_dev, &hname);
181 }
182
183 void
184 device_remove(struct device* dev)
185 {
186     llist_delete(&dev->siblings);
187     vfree(dev);
188 }
189
190 struct device*
191 device_getbyoffset(struct device* root_dev, int offset)
192 {
193     struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
194     struct device *pos, *n;
195     int off = 0;
196     llist_for_each(pos, n, devlist, siblings)
197     {
198         if (off++ >= offset) {
199             return pos;
200         }
201     }
202     return NULL;
203 }
204
205 __DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, va_list, args)
206 {
207     int errno;
208     struct v_fd* fd_s;
209     if ((errno = vfs_getfd(fd, &fd_s))) {
210         goto done;
211     }
212
213     struct device* dev = (struct device*)fd_s->file->inode->data;
214     if (dev->magic != DEV_STRUCT_MAGIC) {
215         errno = ENODEV;
216         goto done;
217     }
218
219     if (!dev->ops.exec_cmd) {
220         errno = ENOTSUP;
221         goto done;
222     }
223
224     errno = dev->ops.exec_cmd(dev, req, args);
225
226 done:
227     return DO_STATUS_OR_RETURN(errno);
228 }