1433d6423SLionel Sambuc #include <errno.h>
2433d6423SLionel Sambuc #include <stdlib.h>
3433d6423SLionel Sambuc #include <string.h>
4433d6423SLionel Sambuc #include <sys/queue.h>
5433d6423SLionel Sambuc #include <minix/com.h>
6433d6423SLionel Sambuc #include <minix/ipc.h>
7433d6423SLionel Sambuc #include <minix/const.h>
8433d6423SLionel Sambuc #include <minix/devman.h>
9433d6423SLionel Sambuc #include <minix/safecopies.h>
10433d6423SLionel Sambuc #include <minix/sysutil.h>
11433d6423SLionel Sambuc #include <minix/ds.h>
12433d6423SLionel Sambuc
13433d6423SLionel Sambuc #include "local.h"
14433d6423SLionel Sambuc
15433d6423SLionel Sambuc static endpoint_t devman_ep;
16433d6423SLionel Sambuc
17433d6423SLionel Sambuc static int save_string(char *buffer, char *src, size_t *offset);
18433d6423SLionel Sambuc
19433d6423SLionel Sambuc static TAILQ_HEAD(devlist_head, devman_dev) dev_list;
20433d6423SLionel Sambuc
21433d6423SLionel Sambuc /****************************************************************************
22433d6423SLionel Sambuc * save_string *
23433d6423SLionel Sambuc ***************************************************************************/
save_string(char * buffer,char * src,size_t * offset)24433d6423SLionel Sambuc static int save_string(char *buffer, char *src, size_t *offset)
25433d6423SLionel Sambuc {
26433d6423SLionel Sambuc unsigned old_offset = *offset;
27433d6423SLionel Sambuc size_t len = strlen(src) + 1;
28433d6423SLionel Sambuc memcpy(buffer + *offset, src, len);
29433d6423SLionel Sambuc *offset += len;
30433d6423SLionel Sambuc return old_offset;
31433d6423SLionel Sambuc }
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc /****************************************************************************
34433d6423SLionel Sambuc * serialize_dev *
35433d6423SLionel Sambuc ***************************************************************************/
serialize_dev(struct devman_dev * dev,size_t * overall_size)3665f76edbSDavid van Moolenbroek static void *serialize_dev(struct devman_dev *dev, size_t *overall_size)
37433d6423SLionel Sambuc {
38433d6423SLionel Sambuc /* determine size of serialized version of dev */
39433d6423SLionel Sambuc char *buffer;
40433d6423SLionel Sambuc char *string_buffer;
41433d6423SLionel Sambuc size_t string_buffer_offset;
42433d6423SLionel Sambuc size_t count = 0;
43433d6423SLionel Sambuc size_t size = sizeof(struct devman_device_info);
44433d6423SLionel Sambuc size_t strings_size = strlen(dev->name) + 1;
45433d6423SLionel Sambuc struct devman_device_info * serialized_dev;
46433d6423SLionel Sambuc struct devman_device_info_entry *entry;
47433d6423SLionel Sambuc struct devman_static_attribute *attribute;
48433d6423SLionel Sambuc
49433d6423SLionel Sambuc TAILQ_FOREACH(attribute, &dev->attrs, list) {
50433d6423SLionel Sambuc strings_size += strlen(attribute->name) + 1;
51433d6423SLionel Sambuc strings_size += strlen(attribute->data) + 1;
52433d6423SLionel Sambuc size += sizeof(struct devman_device_info_entry);
53433d6423SLionel Sambuc count++;
54433d6423SLionel Sambuc }
55433d6423SLionel Sambuc
56433d6423SLionel Sambuc buffer = malloc(size + strings_size);
57433d6423SLionel Sambuc
58433d6423SLionel Sambuc if (buffer == NULL) {
59433d6423SLionel Sambuc return NULL;
60433d6423SLionel Sambuc }
61433d6423SLionel Sambuc
62433d6423SLionel Sambuc string_buffer = buffer;
63433d6423SLionel Sambuc string_buffer_offset = size; /* strings start after
64433d6423SLionel Sambuc devman_device_info and
65433d6423SLionel Sambuc devman_device_info_entries */
66433d6423SLionel Sambuc
67433d6423SLionel Sambuc /* serialize device */
68433d6423SLionel Sambuc serialized_dev = (struct devman_device_info *) buffer;
69433d6423SLionel Sambuc
70433d6423SLionel Sambuc serialized_dev->count = count;
71433d6423SLionel Sambuc serialized_dev->parent_dev_id = dev->parent_dev_id;
72433d6423SLionel Sambuc serialized_dev->name_offset =
73433d6423SLionel Sambuc save_string(string_buffer, dev->name, &string_buffer_offset);
74433d6423SLionel Sambuc #if 0
75433d6423SLionel Sambuc serialized_dev->bus =
76433d6423SLionel Sambuc save_string(string_buffer, dev->bus, &string_buffer_offset);
77433d6423SLionel Sambuc #endif
78433d6423SLionel Sambuc
79433d6423SLionel Sambuc /* serialize entries */
80433d6423SLionel Sambuc entry =
81433d6423SLionel Sambuc (struct devman_device_info_entry *)
82433d6423SLionel Sambuc (buffer + sizeof(struct devman_device_info));
83433d6423SLionel Sambuc
84433d6423SLionel Sambuc TAILQ_FOREACH(attribute, &dev->attrs, list) {
85433d6423SLionel Sambuc entry->type = 0; /* TODO: use macro */
86433d6423SLionel Sambuc entry->name_offset =
87433d6423SLionel Sambuc save_string(string_buffer, attribute->name, &string_buffer_offset);
88433d6423SLionel Sambuc entry->data_offset =
89433d6423SLionel Sambuc save_string(string_buffer, attribute->data, &string_buffer_offset);
90433d6423SLionel Sambuc entry++;
91433d6423SLionel Sambuc }
92433d6423SLionel Sambuc
93433d6423SLionel Sambuc *overall_size = size + strings_size;
94433d6423SLionel Sambuc
95433d6423SLionel Sambuc return buffer;
96433d6423SLionel Sambuc
97433d6423SLionel Sambuc }
98433d6423SLionel Sambuc
99433d6423SLionel Sambuc /****************************************************************************
100433d6423SLionel Sambuc * devman_add_device *
101433d6423SLionel Sambuc ***************************************************************************/
devman_add_device(struct devman_dev * dev)102433d6423SLionel Sambuc int devman_add_device(struct devman_dev *dev)
103433d6423SLionel Sambuc {
104433d6423SLionel Sambuc message msg;
105433d6423SLionel Sambuc int res;
106*e1cdaee1SLionel Sambuc size_t grant_size = 0;
107433d6423SLionel Sambuc void *buf = serialize_dev(dev, &grant_size);
108433d6423SLionel Sambuc
1097c48de6cSDavid van Moolenbroek if (buf == NULL)
1107c48de6cSDavid van Moolenbroek panic("out of memory");
1117c48de6cSDavid van Moolenbroek
112433d6423SLionel Sambuc cp_grant_id_t gid =
113433d6423SLionel Sambuc cpf_grant_direct(devman_ep,(vir_bytes) buf,
114433d6423SLionel Sambuc grant_size, CPF_READ);
115433d6423SLionel Sambuc
116433d6423SLionel Sambuc /* prepare message */
117433d6423SLionel Sambuc msg.m_type = DEVMAN_ADD_DEV;
118433d6423SLionel Sambuc msg.DEVMAN_GRANT_ID = gid;
119433d6423SLionel Sambuc msg.DEVMAN_GRANT_SIZE = grant_size;
120433d6423SLionel Sambuc
121433d6423SLionel Sambuc /* send message */
122433d6423SLionel Sambuc res = ipc_sendrec(devman_ep, &msg);
123433d6423SLionel Sambuc
124433d6423SLionel Sambuc if (res != 0) {
125433d6423SLionel Sambuc panic("devman_add_device: could not talk to devman: %d", res);
126433d6423SLionel Sambuc }
127433d6423SLionel Sambuc
128433d6423SLionel Sambuc if (msg.m_type != DEVMAN_REPLY) {
129433d6423SLionel Sambuc panic("devman_add_device: got illegal response from devman: %d",
130433d6423SLionel Sambuc msg.m_type);
131433d6423SLionel Sambuc }
132433d6423SLionel Sambuc
133433d6423SLionel Sambuc if (msg.DEVMAN_RESULT != 0) {
134433d6423SLionel Sambuc panic("devman_add_device: could add device: %ld",
135433d6423SLionel Sambuc msg.DEVMAN_RESULT);
136433d6423SLionel Sambuc }
137433d6423SLionel Sambuc
138433d6423SLionel Sambuc /* store given dev_id to dev */
139433d6423SLionel Sambuc dev->dev_id = msg.DEVMAN_DEVICE_ID;
140433d6423SLionel Sambuc
141433d6423SLionel Sambuc cpf_revoke(gid);
142433d6423SLionel Sambuc
143433d6423SLionel Sambuc free(buf);
144433d6423SLionel Sambuc
145433d6423SLionel Sambuc /* put device in list */
146433d6423SLionel Sambuc TAILQ_INSERT_HEAD(&dev_list, dev, dev_list);
147433d6423SLionel Sambuc
148433d6423SLionel Sambuc return 0;
149433d6423SLionel Sambuc }
150433d6423SLionel Sambuc
151433d6423SLionel Sambuc /****************************************************************************
152433d6423SLionel Sambuc * devman_del_device *
153433d6423SLionel Sambuc ***************************************************************************/
devman_del_device(struct devman_dev * dev)154433d6423SLionel Sambuc int devman_del_device(struct devman_dev *dev)
155433d6423SLionel Sambuc {
156433d6423SLionel Sambuc message msg;
157433d6423SLionel Sambuc int res;
158433d6423SLionel Sambuc
159433d6423SLionel Sambuc msg.m_type = DEVMAN_DEL_DEV;
160433d6423SLionel Sambuc msg.DEVMAN_DEVICE_ID = dev->dev_id;
161433d6423SLionel Sambuc
162433d6423SLionel Sambuc res = ipc_sendrec(devman_ep, &msg);
163433d6423SLionel Sambuc
164433d6423SLionel Sambuc if (res != 0) {
165433d6423SLionel Sambuc panic("devman_del_device: could not talk to devman: %d", res);
166433d6423SLionel Sambuc }
167433d6423SLionel Sambuc
168433d6423SLionel Sambuc if (msg.m_type != DEVMAN_REPLY) {
169433d6423SLionel Sambuc panic("devman_del_device: got illegal response from devman: %d",
170433d6423SLionel Sambuc msg.m_type);
171433d6423SLionel Sambuc }
172433d6423SLionel Sambuc
173433d6423SLionel Sambuc if (msg.DEVMAN_RESULT != 0) {
174433d6423SLionel Sambuc panic("devman_del_device: could delete device: %ld",
175433d6423SLionel Sambuc msg.DEVMAN_RESULT);
176433d6423SLionel Sambuc }
177433d6423SLionel Sambuc
178433d6423SLionel Sambuc /* remove the device from list */
179433d6423SLionel Sambuc TAILQ_REMOVE(&dev_list, dev, dev_list);
180433d6423SLionel Sambuc
181433d6423SLionel Sambuc return 0;
182433d6423SLionel Sambuc
183433d6423SLionel Sambuc }
184433d6423SLionel Sambuc
185433d6423SLionel Sambuc /****************************************************************************
186433d6423SLionel Sambuc * devman_init *
187433d6423SLionel Sambuc ***************************************************************************/
devman_init(void)188433d6423SLionel Sambuc int devman_init(void)
189433d6423SLionel Sambuc {
190433d6423SLionel Sambuc int res;
191433d6423SLionel Sambuc
192433d6423SLionel Sambuc /* get the endpoint of the HCD */
193433d6423SLionel Sambuc res = ds_retrieve_label_endpt("devman", &devman_ep);
194433d6423SLionel Sambuc
195433d6423SLionel Sambuc if (res != 0) {
196433d6423SLionel Sambuc panic("usb_init: ds_retrieve_label_endpt failed for 'devman': %d", res);
197433d6423SLionel Sambuc }
198433d6423SLionel Sambuc
199433d6423SLionel Sambuc TAILQ_INIT(&dev_list);
200433d6423SLionel Sambuc
201433d6423SLionel Sambuc return res;
202433d6423SLionel Sambuc }
203433d6423SLionel Sambuc
204433d6423SLionel Sambuc /****************************************************************************
205433d6423SLionel Sambuc * do_bind *
206433d6423SLionel Sambuc ***************************************************************************/
do_bind(message * m)207433d6423SLionel Sambuc static void do_bind(message *m)
208433d6423SLionel Sambuc {
209433d6423SLionel Sambuc struct devman_dev *dev;
210433d6423SLionel Sambuc int res;
211433d6423SLionel Sambuc
212433d6423SLionel Sambuc /* find device */
213433d6423SLionel Sambuc TAILQ_FOREACH(dev, &dev_list, dev_list) {
214433d6423SLionel Sambuc if (dev->dev_id == m->DEVMAN_DEVICE_ID) {
215433d6423SLionel Sambuc if (dev->bind_cb) {
216433d6423SLionel Sambuc res = dev->bind_cb(dev->data, m->DEVMAN_ENDPOINT);
217433d6423SLionel Sambuc m->m_type = DEVMAN_REPLY;
218433d6423SLionel Sambuc m->DEVMAN_RESULT = res;
219433d6423SLionel Sambuc ipc_send(devman_ep, m);
220433d6423SLionel Sambuc return;
221433d6423SLionel Sambuc }
222433d6423SLionel Sambuc }
223433d6423SLionel Sambuc }
224433d6423SLionel Sambuc m->m_type = DEVMAN_REPLY;
225433d6423SLionel Sambuc m->DEVMAN_RESULT = ENODEV;
226433d6423SLionel Sambuc ipc_send(devman_ep, m);
227433d6423SLionel Sambuc return;
228433d6423SLionel Sambuc }
229433d6423SLionel Sambuc
230433d6423SLionel Sambuc /****************************************************************************
231433d6423SLionel Sambuc * do_unbind *
232433d6423SLionel Sambuc ***************************************************************************/
do_unbind(message * m)233433d6423SLionel Sambuc static void do_unbind(message *m)
234433d6423SLionel Sambuc {
235433d6423SLionel Sambuc struct devman_dev *dev;
236433d6423SLionel Sambuc int res;
237433d6423SLionel Sambuc
238433d6423SLionel Sambuc /* find device */
239433d6423SLionel Sambuc TAILQ_FOREACH(dev, &dev_list, dev_list) {
240433d6423SLionel Sambuc if (dev->dev_id == m->DEVMAN_DEVICE_ID) {
241433d6423SLionel Sambuc if (dev->unbind_cb) {
242433d6423SLionel Sambuc res = dev->unbind_cb(dev->data, m->DEVMAN_ENDPOINT);
243433d6423SLionel Sambuc m->m_type = DEVMAN_REPLY;
244433d6423SLionel Sambuc m->DEVMAN_RESULT = res;
245433d6423SLionel Sambuc ipc_send(devman_ep, m);
246433d6423SLionel Sambuc return;
247433d6423SLionel Sambuc }
248433d6423SLionel Sambuc }
249433d6423SLionel Sambuc }
250433d6423SLionel Sambuc m->m_type = DEVMAN_REPLY;
251433d6423SLionel Sambuc m->DEVMAN_RESULT = ENODEV;
252433d6423SLionel Sambuc ipc_send(devman_ep, m);
253433d6423SLionel Sambuc }
254433d6423SLionel Sambuc
255433d6423SLionel Sambuc /****************************************************************************
256433d6423SLionel Sambuc * devman_handle_msg *
257433d6423SLionel Sambuc ***************************************************************************/
devman_handle_msg(message * m)258433d6423SLionel Sambuc int devman_handle_msg(message *m)
259433d6423SLionel Sambuc {
260433d6423SLionel Sambuc /* make sure msg comes from devman server */
261433d6423SLionel Sambuc if (m->m_source != devman_ep) {
262433d6423SLionel Sambuc /* we don't honor requests from others by answering them */
263433d6423SLionel Sambuc return 0;
264433d6423SLionel Sambuc }
265433d6423SLionel Sambuc switch (m->m_type) {
266433d6423SLionel Sambuc case DEVMAN_BIND:
267433d6423SLionel Sambuc do_bind(m);
268433d6423SLionel Sambuc return 1;
269433d6423SLionel Sambuc case DEVMAN_UNBIND:
270433d6423SLionel Sambuc do_unbind(m);
271433d6423SLionel Sambuc return 1;
272433d6423SLionel Sambuc default:
273433d6423SLionel Sambuc return 0;
274433d6423SLionel Sambuc }
275433d6423SLionel Sambuc }
276