1 #include <errno.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/queue.h>
5 #include <minix/com.h>
6 #include <minix/ipc.h>
7 #include <minix/const.h>
8 #include <minix/devman.h>
9 #include <minix/safecopies.h>
10 #include <minix/sysutil.h>
11 #include <minix/ds.h>
12
13 #include "local.h"
14
15 static endpoint_t devman_ep;
16
17 static int save_string(char *buffer, char *src, size_t *offset);
18
19 static TAILQ_HEAD(devlist_head, devman_dev) dev_list;
20
21 /****************************************************************************
22 * save_string *
23 ***************************************************************************/
save_string(char * buffer,char * src,size_t * offset)24 static int save_string(char *buffer, char *src, size_t *offset)
25 {
26 unsigned old_offset = *offset;
27 size_t len = strlen(src) + 1;
28 memcpy(buffer + *offset, src, len);
29 *offset += len;
30 return old_offset;
31 }
32
33 /****************************************************************************
34 * serialize_dev *
35 ***************************************************************************/
serialize_dev(struct devman_dev * dev,size_t * overall_size)36 static void *serialize_dev(struct devman_dev *dev, size_t *overall_size)
37 {
38 /* determine size of serialized version of dev */
39 char *buffer;
40 char *string_buffer;
41 size_t string_buffer_offset;
42 size_t count = 0;
43 size_t size = sizeof(struct devman_device_info);
44 size_t strings_size = strlen(dev->name) + 1;
45 struct devman_device_info * serialized_dev;
46 struct devman_device_info_entry *entry;
47 struct devman_static_attribute *attribute;
48
49 TAILQ_FOREACH(attribute, &dev->attrs, list) {
50 strings_size += strlen(attribute->name) + 1;
51 strings_size += strlen(attribute->data) + 1;
52 size += sizeof(struct devman_device_info_entry);
53 count++;
54 }
55
56 buffer = malloc(size + strings_size);
57
58 if (buffer == NULL) {
59 return NULL;
60 }
61
62 string_buffer = buffer;
63 string_buffer_offset = size; /* strings start after
64 devman_device_info and
65 devman_device_info_entries */
66
67 /* serialize device */
68 serialized_dev = (struct devman_device_info *) buffer;
69
70 serialized_dev->count = count;
71 serialized_dev->parent_dev_id = dev->parent_dev_id;
72 serialized_dev->name_offset =
73 save_string(string_buffer, dev->name, &string_buffer_offset);
74 #if 0
75 serialized_dev->bus =
76 save_string(string_buffer, dev->bus, &string_buffer_offset);
77 #endif
78
79 /* serialize entries */
80 entry =
81 (struct devman_device_info_entry *)
82 (buffer + sizeof(struct devman_device_info));
83
84 TAILQ_FOREACH(attribute, &dev->attrs, list) {
85 entry->type = 0; /* TODO: use macro */
86 entry->name_offset =
87 save_string(string_buffer, attribute->name, &string_buffer_offset);
88 entry->data_offset =
89 save_string(string_buffer, attribute->data, &string_buffer_offset);
90 entry++;
91 }
92
93 *overall_size = size + strings_size;
94
95 return buffer;
96
97 }
98
99 /****************************************************************************
100 * devman_add_device *
101 ***************************************************************************/
devman_add_device(struct devman_dev * dev)102 int devman_add_device(struct devman_dev *dev)
103 {
104 message msg;
105 int res;
106 size_t grant_size = 0;
107 void *buf = serialize_dev(dev, &grant_size);
108
109 if (buf == NULL)
110 panic("out of memory");
111
112 cp_grant_id_t gid =
113 cpf_grant_direct(devman_ep,(vir_bytes) buf,
114 grant_size, CPF_READ);
115
116 /* prepare message */
117 msg.m_type = DEVMAN_ADD_DEV;
118 msg.DEVMAN_GRANT_ID = gid;
119 msg.DEVMAN_GRANT_SIZE = grant_size;
120
121 /* send message */
122 res = ipc_sendrec(devman_ep, &msg);
123
124 if (res != 0) {
125 panic("devman_add_device: could not talk to devman: %d", res);
126 }
127
128 if (msg.m_type != DEVMAN_REPLY) {
129 panic("devman_add_device: got illegal response from devman: %d",
130 msg.m_type);
131 }
132
133 if (msg.DEVMAN_RESULT != 0) {
134 panic("devman_add_device: could add device: %ld",
135 msg.DEVMAN_RESULT);
136 }
137
138 /* store given dev_id to dev */
139 dev->dev_id = msg.DEVMAN_DEVICE_ID;
140
141 cpf_revoke(gid);
142
143 free(buf);
144
145 /* put device in list */
146 TAILQ_INSERT_HEAD(&dev_list, dev, dev_list);
147
148 return 0;
149 }
150
151 /****************************************************************************
152 * devman_del_device *
153 ***************************************************************************/
devman_del_device(struct devman_dev * dev)154 int devman_del_device(struct devman_dev *dev)
155 {
156 message msg;
157 int res;
158
159 msg.m_type = DEVMAN_DEL_DEV;
160 msg.DEVMAN_DEVICE_ID = dev->dev_id;
161
162 res = ipc_sendrec(devman_ep, &msg);
163
164 if (res != 0) {
165 panic("devman_del_device: could not talk to devman: %d", res);
166 }
167
168 if (msg.m_type != DEVMAN_REPLY) {
169 panic("devman_del_device: got illegal response from devman: %d",
170 msg.m_type);
171 }
172
173 if (msg.DEVMAN_RESULT != 0) {
174 panic("devman_del_device: could delete device: %ld",
175 msg.DEVMAN_RESULT);
176 }
177
178 /* remove the device from list */
179 TAILQ_REMOVE(&dev_list, dev, dev_list);
180
181 return 0;
182
183 }
184
185 /****************************************************************************
186 * devman_init *
187 ***************************************************************************/
devman_init(void)188 int devman_init(void)
189 {
190 int res;
191
192 /* get the endpoint of the HCD */
193 res = ds_retrieve_label_endpt("devman", &devman_ep);
194
195 if (res != 0) {
196 panic("usb_init: ds_retrieve_label_endpt failed for 'devman': %d", res);
197 }
198
199 TAILQ_INIT(&dev_list);
200
201 return res;
202 }
203
204 /****************************************************************************
205 * do_bind *
206 ***************************************************************************/
do_bind(message * m)207 static void do_bind(message *m)
208 {
209 struct devman_dev *dev;
210 int res;
211
212 /* find device */
213 TAILQ_FOREACH(dev, &dev_list, dev_list) {
214 if (dev->dev_id == m->DEVMAN_DEVICE_ID) {
215 if (dev->bind_cb) {
216 res = dev->bind_cb(dev->data, m->DEVMAN_ENDPOINT);
217 m->m_type = DEVMAN_REPLY;
218 m->DEVMAN_RESULT = res;
219 ipc_send(devman_ep, m);
220 return;
221 }
222 }
223 }
224 m->m_type = DEVMAN_REPLY;
225 m->DEVMAN_RESULT = ENODEV;
226 ipc_send(devman_ep, m);
227 return;
228 }
229
230 /****************************************************************************
231 * do_unbind *
232 ***************************************************************************/
do_unbind(message * m)233 static void do_unbind(message *m)
234 {
235 struct devman_dev *dev;
236 int res;
237
238 /* find device */
239 TAILQ_FOREACH(dev, &dev_list, dev_list) {
240 if (dev->dev_id == m->DEVMAN_DEVICE_ID) {
241 if (dev->unbind_cb) {
242 res = dev->unbind_cb(dev->data, m->DEVMAN_ENDPOINT);
243 m->m_type = DEVMAN_REPLY;
244 m->DEVMAN_RESULT = res;
245 ipc_send(devman_ep, m);
246 return;
247 }
248 }
249 }
250 m->m_type = DEVMAN_REPLY;
251 m->DEVMAN_RESULT = ENODEV;
252 ipc_send(devman_ep, m);
253 }
254
255 /****************************************************************************
256 * devman_handle_msg *
257 ***************************************************************************/
devman_handle_msg(message * m)258 int devman_handle_msg(message *m)
259 {
260 /* make sure msg comes from devman server */
261 if (m->m_source != devman_ep) {
262 /* we don't honor requests from others by answering them */
263 return 0;
264 }
265 switch (m->m_type) {
266 case DEVMAN_BIND:
267 do_bind(m);
268 return 1;
269 case DEVMAN_UNBIND:
270 do_unbind(m);
271 return 1;
272 default:
273 return 0;
274 }
275 }
276