xref: /minix/minix/lib/libdevman/generic.c (revision 433d6423)
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  ***************************************************************************/
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  ***************************************************************************/
36 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  ***************************************************************************/
102 int devman_add_device(struct devman_dev *dev)
103 {
104 	message msg;
105 	int res;
106 	size_t grant_size;
107 	void *buf = serialize_dev(dev, &grant_size);
108 
109 	cp_grant_id_t gid =
110 	    cpf_grant_direct(devman_ep,(vir_bytes) buf,
111 		    grant_size, CPF_READ);
112 
113 	/* prepare message */
114 	msg.m_type            = DEVMAN_ADD_DEV;
115 	msg.DEVMAN_GRANT_ID   = gid;
116 	msg.DEVMAN_GRANT_SIZE = grant_size;
117 
118 	/* send message */
119 	res = ipc_sendrec(devman_ep, &msg);
120 
121 	if (res != 0) {
122 		panic("devman_add_device: could not talk to devman: %d", res);
123 	}
124 
125 	if (msg.m_type != DEVMAN_REPLY) {
126 		panic("devman_add_device: got illegal response from devman: %d",
127 		    msg.m_type);
128 	}
129 
130 	if (msg.DEVMAN_RESULT != 0) {
131 		panic("devman_add_device: could add device: %ld",
132 		    msg.DEVMAN_RESULT);
133 	}
134 
135 	/* store given dev_id to dev */
136 	dev->dev_id = msg.DEVMAN_DEVICE_ID;
137 
138 	cpf_revoke(gid);
139 
140 	free(buf);
141 
142 	/* put device in list */
143 	TAILQ_INSERT_HEAD(&dev_list, dev, dev_list);
144 
145 	return 0;
146 }
147 
148 /****************************************************************************
149  *     devman_del_device                                                    *
150  ***************************************************************************/
151 int devman_del_device(struct devman_dev *dev)
152 {
153 	message msg;
154 	int res;
155 
156 	msg.m_type            = DEVMAN_DEL_DEV;
157 	msg.DEVMAN_DEVICE_ID   = dev->dev_id;
158 
159 	res = ipc_sendrec(devman_ep, &msg);
160 
161 	if (res != 0) {
162 		panic("devman_del_device: could not talk to devman: %d", res);
163 	}
164 
165 	if (msg.m_type != DEVMAN_REPLY) {
166 		panic("devman_del_device: got illegal response from devman: %d",
167 		    msg.m_type);
168 	}
169 
170 	if (msg.DEVMAN_RESULT != 0) {
171 		panic("devman_del_device: could delete device: %ld",
172 		    msg.DEVMAN_RESULT);
173 	}
174 
175 	/* remove the device from list */
176 	TAILQ_REMOVE(&dev_list, dev, dev_list);
177 
178 	return 0;
179 
180 }
181 
182 /****************************************************************************
183  *     devman_get_ep                                                        *
184  ***************************************************************************/
185 endpoint_t devman_get_ep(void)
186 {
187 	return devman_ep;
188 }
189 
190 /****************************************************************************
191  *     devman_init                                                          *
192  ***************************************************************************/
193 int devman_init(void)
194 {
195 	int res;
196 
197 	/* get the endpoint of the HCD */
198 	res = ds_retrieve_label_endpt("devman", &devman_ep);
199 
200 	if (res != 0) {
201 		panic("usb_init: ds_retrieve_label_endpt failed for 'devman': %d", res);
202 	}
203 
204 	TAILQ_INIT(&dev_list);
205 
206 	return res;
207 }
208 
209 /****************************************************************************
210  *     do_bind                                                              *
211  ***************************************************************************/
212 static void do_bind(message *m)
213 {
214 	struct devman_dev *dev;
215 	int res;
216 
217 	/* find device */
218 	TAILQ_FOREACH(dev, &dev_list, dev_list) {
219 		if (dev->dev_id == m->DEVMAN_DEVICE_ID) {
220 			if (dev->bind_cb) {
221 				res = dev->bind_cb(dev->data, m->DEVMAN_ENDPOINT);
222 				m->m_type = DEVMAN_REPLY;
223 				m->DEVMAN_RESULT = res;
224 				ipc_send(devman_ep, m);
225 				return;
226 			}
227 		}
228 	}
229 	m->m_type = DEVMAN_REPLY;
230 	m->DEVMAN_RESULT = ENODEV;
231 	ipc_send(devman_ep, m);
232 	return;
233 }
234 
235 /****************************************************************************
236  *     do_unbind                                                            *
237  ***************************************************************************/
238 static void do_unbind(message *m)
239 {
240 	struct devman_dev *dev;
241 	int res;
242 
243 	/* find device */
244 	TAILQ_FOREACH(dev, &dev_list, dev_list) {
245 		if (dev->dev_id == m->DEVMAN_DEVICE_ID) {
246 			if (dev->unbind_cb) {
247 				res = dev->unbind_cb(dev->data, m->DEVMAN_ENDPOINT);
248 				m->m_type = DEVMAN_REPLY;
249 				m->DEVMAN_RESULT = res;
250 				ipc_send(devman_ep, m);
251 				return;
252 			}
253 		}
254 	}
255 	m->m_type = DEVMAN_REPLY;
256 	m->DEVMAN_RESULT = ENODEV;
257 	ipc_send(devman_ep, m);
258 }
259 
260 /****************************************************************************
261  *     devman_handle_msg                                                    *
262  ***************************************************************************/
263 int devman_handle_msg(message *m)
264 {
265 	/* make sure msg comes from devman server */
266 	if (m->m_source != devman_ep) {
267 		/* we don't honor requests from others by answering them */
268 		return 0;
269 	}
270 	switch (m->m_type) {
271 		case DEVMAN_BIND:
272 			do_bind(m);
273 			return 1;
274 		case DEVMAN_UNBIND:
275 			do_unbind(m);
276 			return 1;
277 		default:
278 			return 0;
279 	}
280 }
281