979b461b86184a8c1bcdfa18f3ce0f0505f094a1
[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 struct device*
16 device_add(struct device* parent,
17            void* underlay,
18            char* name_fmt,
19            u32_t type,
20            va_list args)
21 {
22     struct device* dev = vzalloc(sizeof(struct device));
23
24     if (parent) {
25         assert((parent->dev_type & DEV_MSKIF) == DEV_IFCAT);
26         llist_append(&parent->children, &dev->siblings);
27     } else {
28         llist_append(&root_list, &dev->siblings);
29     }
30
31     size_t strlen =
32       __ksprintf_internal(dev->name_val, name_fmt, DEVICE_NAME_SIZE, args);
33
34     dev->magic = DEV_STRUCT_MAGIC;
35     dev->dev_id = devid++;
36     dev->name = HSTR(dev->name_val, strlen);
37     dev->parent = parent;
38     dev->underlay = underlay;
39     dev->dev_type = type;
40
41     hstr_rehash(&dev->name, HSTR_FULL_HASH);
42     llist_init_head(&dev->children);
43
44     return dev;
45 }
46
47 struct device*
48 device_addsys(struct device* parent, void* underlay, char* name_fmt, ...)
49 {
50     va_list args;
51     va_start(args, name_fmt);
52
53     struct device* dev =
54       device_add(parent, underlay, name_fmt, DEV_IFSEQ, args);
55
56     va_end(args);
57     return dev;
58 }
59
60 struct device*
61 device_addseq(struct device* parent, void* underlay, char* name_fmt, ...)
62 {
63     va_list args;
64     va_start(args, name_fmt);
65
66     struct device* dev =
67       device_add(parent, underlay, name_fmt, DEV_IFSEQ, args);
68
69     va_end(args);
70     return dev;
71 }
72
73 struct device*
74 device_addvol(struct device* parent, void* underlay, char* name_fmt, ...)
75 {
76     va_list args;
77     va_start(args, name_fmt);
78
79     struct device* dev =
80       device_add(parent, underlay, name_fmt, DEV_IFVOL, args);
81
82     va_end(args);
83     return dev;
84 }
85
86 struct device*
87 device_addcat(struct device* parent, char* name_fmt, ...)
88 {
89     va_list args;
90     va_start(args, name_fmt);
91
92     struct device* dev = device_add(parent, NULL, name_fmt, DEV_IFCAT, args);
93
94     va_end(args);
95     return dev;
96 }
97
98 struct device*
99 device_getbyid(struct llist_header* devlist, dev_t id)
100 {
101     devlist = devlist ? devlist : &root_list;
102     struct device *pos, *n;
103     llist_for_each(pos, n, devlist, siblings)
104     {
105         if (pos->dev_id == id) {
106             return pos;
107         }
108     }
109
110     return NULL;
111 }
112
113 struct device*
114 device_getbyhname(struct device* root_dev, struct hstr* name)
115 {
116     struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
117     struct device *pos, *n;
118     llist_for_each(pos, n, devlist, siblings)
119     {
120         if (HSTR_EQ(&pos->name, name)) {
121             return pos;
122         }
123     }
124
125     return NULL;
126 }
127
128 struct device*
129 device_getbyname(struct device* root_dev, const char* name, size_t len)
130 {
131     struct hstr hname = HSTR(name, len);
132     hstr_rehash(&hname, HSTR_FULL_HASH);
133
134     return device_getbyhname(root_dev, &hname);
135 }
136
137 void
138 device_remove(struct device* dev)
139 {
140     llist_delete(&dev->siblings);
141     vfree(dev);
142 }
143
144 struct device*
145 device_getbyoffset(struct device* root_dev, int offset)
146 {
147     struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
148     struct device *pos, *n;
149     int off = 0;
150     llist_for_each(pos, n, devlist, siblings)
151     {
152         if (off++ >= offset) {
153             return pos;
154         }
155     }
156     return NULL;
157 }
158
159 __DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, va_list, args)
160 {
161     int errno;
162     struct v_fd* fd_s;
163     if ((errno = vfs_getfd(fd, &fd_s))) {
164         goto done;
165     }
166
167     struct device* dev = (struct device*)fd_s->file->inode->data;
168     if (dev->magic != DEV_STRUCT_MAGIC) {
169         errno = ENODEV;
170         goto done;
171     }
172
173     if (!dev->ops.exec_cmd) {
174         errno = ENOTSUP;
175         goto done;
176     }
177
178     errno = dev->ops.exec_cmd(dev, req, args);
179
180 done:
181     return DO_STATUS_OR_RETURN(errno);
182 }