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