xref: /minix/minix/drivers/usb/usbd/hcd/hcd_common.c (revision 433d6423)
1 /*
2  * Implementation of commonly used procedures for HCD handling/initialization
3  * If possible, everything OS specific should be here
4  */
5 
6 #include <string.h>			/* memset... */
7 #include <time.h>			/* nanosleep */
8 
9 #include <sys/mman.h>			/* Physical to virtual memory mapping */
10 
11 #include <ddekit/interrupt.h>		/* DDEKit based interrupt handling */
12 
13 #include <minix/clkconf.h>		/* clkconf_* */
14 #include <minix/syslib.h>		/* sys_privctl */
15 
16 #include <usb/hcd_common.h>
17 #include <usb/hcd_interface.h>
18 #include <usb/usb_common.h>
19 
20 
21 /*===========================================================================*
22  *    Local prototypes                                                       *
23  *===========================================================================*/
24 static int hcd_fill_configuration(hcd_reg1 *, int, hcd_configuration *, int);
25 static int hcd_fill_interface(hcd_reg1 *, int, hcd_interface *, int);
26 static int hcd_fill_endpoint(hcd_reg1 *, int, hcd_endpoint *);
27 
28 
29 /*===========================================================================*
30  *    hcd_os_interrupt_attach                                                *
31  *===========================================================================*/
32 int
33 hcd_os_interrupt_attach(int irq, void (*init)(void *),
34 			void (*isr)(void *), void *priv)
35 {
36 	DEBUG_DUMP;
37 
38 	if (NULL == ddekit_interrupt_attach(irq, 0, init, isr, priv)) {
39 		USB_MSG("Attaching interrupt %d failed", irq);
40 		return EXIT_FAILURE;
41 	}
42 
43 	return EXIT_SUCCESS;
44 }
45 
46 
47 /*===========================================================================*
48  *    hcd_os_interrupt_detach                                                *
49  *===========================================================================*/
50 void
51 hcd_os_interrupt_detach(int irq)
52 {
53 	DEBUG_DUMP;
54 	ddekit_interrupt_detach(irq);
55 }
56 
57 
58 /*===========================================================================*
59  *    hcd_os_interrupt_enable                                                *
60  *===========================================================================*/
61 void
62 hcd_os_interrupt_enable(int irq)
63 {
64 	DEBUG_DUMP;
65 	ddekit_interrupt_enable(irq);
66 }
67 
68 
69 /*===========================================================================*
70  *    hcd_os_interrupt_disable                                               *
71  *===========================================================================*/
72 void
73 hcd_os_interrupt_disable(int irq)
74 {
75 	DEBUG_DUMP;
76 	ddekit_interrupt_disable(irq);
77 }
78 
79 
80 /*===========================================================================*
81  *    hcd_os_regs_init                                                       *
82  *===========================================================================*/
83 void *
84 hcd_os_regs_init(hcd_addr phys_addr, unsigned long addr_len)
85 {
86 	/* Memory range where we need privileged access */
87 	struct minix_mem_range mr;
88 
89 	/* NULL unless initialization was fully completed */
90 	void * virt_reg_base;
91 
92 	DEBUG_DUMP;
93 
94 	virt_reg_base = NULL;
95 
96 	/* Must have been set before */
97 	USB_ASSERT(0 != phys_addr, "Invalid base address!");
98 	USB_ASSERT(0 != addr_len, "Invalid base length!");
99 
100 	/* Set memory range for peripheral */
101 	mr.mr_base = phys_addr;
102 	mr.mr_limit = phys_addr + addr_len;
103 
104 	/* Try getting access to memory range */
105 	if (EXIT_SUCCESS == sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr)) {
106 
107 		/* And map it where we want it */
108 		virt_reg_base = vm_map_phys(SELF, (void *)phys_addr, addr_len);
109 
110 		/* Check for mapping errors to allow us returning NULL */
111 		if (MAP_FAILED == virt_reg_base) {
112 			USB_MSG("Mapping memory with vm_map_phys() failed");
113 			virt_reg_base = NULL;
114 		}
115 
116 	} else
117 		USB_MSG("Acquiring memory with sys_privctl() failed");
118 
119 	return virt_reg_base;
120 }
121 
122 
123 /*===========================================================================*
124  *    hcd_os_regs_deinit                                                     *
125  *===========================================================================*/
126 int
127 hcd_os_regs_deinit(hcd_addr virt_addr, unsigned long addr_len)
128 {
129 	DEBUG_DUMP;
130 
131 	/* To keep USBD return value convention */
132 	return (0 == vm_unmap_phys(SELF, (void*)virt_addr, addr_len)) ?
133 		EXIT_SUCCESS : EXIT_FAILURE;
134 }
135 
136 
137 /*===========================================================================*
138  *    hcd_os_clkconf                                                         *
139  *===========================================================================*/
140 int
141 hcd_os_clkconf(unsigned long clk, unsigned long mask, unsigned long value)
142 {
143 	DEBUG_DUMP;
144 
145 	/* Apparently clkconf_init may be called more than once anyway */
146 	if ((0 == clkconf_init()) && (0 == clkconf_set(clk, mask, value)))
147 		return EXIT_SUCCESS;
148 	else
149 		return EXIT_FAILURE;
150 }
151 
152 
153 /*===========================================================================*
154  *    hcd_os_clkconf_release                                                 *
155  *===========================================================================*/
156 int
157 hcd_os_clkconf_release(void)
158 {
159 	DEBUG_DUMP;
160 	return clkconf_release();
161 }
162 
163 
164 /*===========================================================================*
165  *    hcd_os_nanosleep                                                       *
166  *===========================================================================*/
167 void
168 hcd_os_nanosleep(int nanosec)
169 {
170 	struct timespec nanotm;
171 
172 	DEBUG_DUMP;
173 
174 	if (nanosec >= HCD_NANO) {
175 		nanotm.tv_sec = nanosec / HCD_NANO;
176 		nanotm.tv_nsec = nanosec % HCD_NANO;
177 	} else {
178 		nanotm.tv_sec = 0;
179 		nanotm.tv_nsec = nanosec;
180 	}
181 
182 	/* TODO: Since it is not likely to be ever interrupted, we do not try
183 	 * to sleep for a remaining time in case of signal handling */
184 	/* Signal handling will most likely end up with termination anyway */
185 	USB_ASSERT(EXIT_SUCCESS == nanosleep(&nanotm, NULL),
186 		"Calling nanosleep() failed");
187 }
188 
189 
190 /*===========================================================================*
191  *    hcd_init_device                                                        *
192  *===========================================================================*/
193 int
194 hcd_connect_device(hcd_device_state * this_device, hcd_thread_function funct)
195 {
196 	DEBUG_DUMP;
197 
198 	if ((NULL != this_device->lock) || (NULL != this_device->thread)) {
199 		USB_MSG("Device data already allocated");
200 		return EXIT_FAILURE;
201 	}
202 
203 	if (NULL == (this_device->lock = ddekit_sem_init(0)))
204 		return EXIT_FAILURE;
205 
206 	if (NULL == (this_device->thread = ddekit_thread_create(funct,
207 								this_device,
208 								"Device"))) {
209 		ddekit_sem_deinit(this_device->lock);
210 		return EXIT_FAILURE;
211 	}
212 
213 	/* Allow device thread to work */
214 	ddekit_yield();
215 
216 	return EXIT_SUCCESS;
217 }
218 
219 /*===========================================================================*
220  *    hcd_deinit_device                                                      *
221  *===========================================================================*/
222 void
223 hcd_disconnect_device(hcd_device_state * this_device)
224 {
225 	DEBUG_DUMP;
226 
227 	hcd_tree_cleanup(&(this_device->config_tree));
228 
229 	ddekit_thread_terminate(this_device->thread);
230 	ddekit_sem_deinit(this_device->lock);
231 
232 	this_device->thread = NULL;
233 	this_device->lock = NULL;
234 }
235 
236 
237 /*===========================================================================*
238  *    hcd_device_wait                                                        *
239  *===========================================================================*/
240 void
241 hcd_device_wait(hcd_device_state * this_device, hcd_event event, hcd_reg1 ep)
242 {
243 	hcd_driver_state * drv;
244 
245 	DEBUG_DUMP;
246 
247 	drv = (hcd_driver_state *)this_device->driver;
248 
249 	drv->expected_event = event;
250 	drv->expected_endpoint = ep;
251 
252 	USB_DBG("Waiting for: ev=0x%X, ep=0x%X", (int)event, ep);
253 
254 	ddekit_sem_down(this_device->lock);
255 }
256 
257 
258 /*===========================================================================*
259  *    hcd_device_continue                                                    *
260  *===========================================================================*/
261 void
262 hcd_device_continue(hcd_device_state * this_device)
263 {
264 	hcd_driver_state * drv;
265 
266 	DEBUG_DUMP;
267 
268 	drv = (hcd_driver_state *)this_device->driver;
269 
270 	/* We need to get what was expected... */
271 	USB_ASSERT(drv->current_event == drv->expected_event,
272 		"Unexpected event occurred");
273 
274 	/* ...including endpoint interrupts */
275 	if (HCD_EVENT_ENDPOINT == drv->current_event) {
276 		USB_ASSERT(drv->current_endpoint == drv->expected_endpoint,
277 			"Unexpected endpoint interrupt");
278 	}
279 
280 	ddekit_sem_up(this_device->lock);
281 }
282 
283 
284 /*===========================================================================*
285  *    hcd_buffer_to_tree                                                     *
286  *===========================================================================*/
287 int
288 hcd_buffer_to_tree(hcd_reg1 * buf, int len, hcd_configuration * c)
289 {
290 	hcd_interface * i;
291 	hcd_endpoint * e;
292 	hcd_descriptor * desc;
293 	int cfg_num;
294 	int if_num;
295 	int ep_num;
296 
297 	DEBUG_DUMP;
298 
299 	cfg_num = 0;
300 	if_num = 0;
301 	ep_num = 0;
302 
303 	i = NULL;
304 	e = NULL;
305 
306 	/* Cleanup initially to NULL pointers before any allocation */
307 	memset(c, 0, sizeof(*c));
308 
309 	while (len > (int)sizeof(*desc)) {
310 		/* Check descriptor type */
311 		desc = (hcd_descriptor *)buf;
312 
313 		if (0 == desc->bLength) {
314 			USB_MSG("Zero length descriptor");
315 			goto PARSE_ERROR;
316 		}
317 
318 		if (UDESC_CONFIG == desc->bDescriptorType) {
319 			if (EXIT_SUCCESS != hcd_fill_configuration(buf, len,
320 								c, cfg_num++))
321 				goto PARSE_ERROR;
322 
323 			if_num = 0;
324 		}
325 		else if (UDESC_INTERFACE == desc->bDescriptorType) {
326 			if (NULL == c->interface)
327 				goto PARSE_ERROR;
328 
329 			i = &(c->interface[if_num]);
330 
331 			if (EXIT_SUCCESS != hcd_fill_interface(buf, len,
332 								i, if_num++))
333 				goto PARSE_ERROR;
334 
335 			ep_num = 0;
336 		}
337 		else if (UDESC_ENDPOINT == desc->bDescriptorType) {
338 			if (NULL == c->interface)
339 				goto PARSE_ERROR;
340 
341 			if (NULL == i)
342 				goto PARSE_ERROR;
343 
344 			e = &(i->endpoint[ep_num++]);
345 
346 			if (EXIT_SUCCESS != hcd_fill_endpoint(buf, len, e))
347 				goto PARSE_ERROR;
348 		} else
349 			USB_DBG("Unhandled descriptor type 0x%02X",
350 				desc->bDescriptorType);
351 
352 		len -= desc->bLength;
353 		buf += desc->bLength;
354 	}
355 
356 	if (0 != len) {
357 		USB_MSG("After parsing, some descriptor data remains");
358 		goto PARSE_ERROR;
359 	}
360 
361 	return EXIT_SUCCESS;
362 
363 	PARSE_ERROR:
364 	hcd_tree_cleanup(c);
365 	return EXIT_FAILURE;
366 }
367 
368 
369 /*===========================================================================*
370  *    hcd_tree_cleanup                                                       *
371  *===========================================================================*/
372 void
373 hcd_tree_cleanup(hcd_configuration * c)
374 {
375 	int if_idx;
376 
377 	DEBUG_DUMP;
378 
379 	/* Free if anything was allocated */
380 	if (NULL != c->interface) {
381 
382 		USB_ASSERT(c->num_interfaces > 0, "Interface number error");
383 
384 		for (if_idx = 0; if_idx < c->num_interfaces; if_idx++) {
385 			if (NULL != c->interface[if_idx].endpoint) {
386 				USB_DBG("Freeing ep for interface #%d", if_idx);
387 				free(c->interface[if_idx].endpoint);
388 			}
389 		}
390 
391 		USB_DBG("Freeing interfaces");
392 		free(c->interface);
393 		c->interface = NULL;
394 	}
395 }
396 
397 
398 /*===========================================================================*
399  *    hcd_tree_find_ep                                                       *
400  *===========================================================================*/
401 hcd_endpoint *
402 hcd_tree_find_ep(hcd_configuration * c, hcd_reg1 ep)
403 {
404 	hcd_interface * i;
405 	hcd_endpoint * e;
406 	int if_idx;
407 	int ep_idx;
408 
409 	DEBUG_DUMP;
410 
411 	/* Free if anything was allocated */
412 	USB_ASSERT(NULL != c->interface, "No interfaces available");
413 	USB_ASSERT(c->num_interfaces > 0, "Interface number error");
414 
415 	for (if_idx = 0; if_idx < c->num_interfaces; if_idx++) {
416 		i = &(c->interface[if_idx]);
417 		for (ep_idx = 0; ep_idx < i->num_endpoints; ep_idx++) {
418 			e = &(i->endpoint[ep_idx]);
419 			if (UE_GET_ADDR(e->descriptor.bEndpointAddress) == ep)
420 				return e;
421 		}
422 	}
423 
424 	return NULL;
425 }
426 
427 
428 /*===========================================================================*
429  *    hcd_fill_configuration                                                 *
430  *===========================================================================*/
431 static int
432 hcd_fill_configuration(hcd_reg1 * buf, int len, hcd_configuration * c, int num)
433 {
434 	hcd_config_descriptor * desc;
435 	int interfaces_size;
436 
437 	DEBUG_DUMP;
438 
439 	desc = (hcd_config_descriptor *)buf;
440 
441 	USB_DBG("Configuration #%d", num);
442 
443 	if (num > 0) {
444 		USB_DBG("Only one configuration possible");
445 		return EXIT_SUCCESS;
446 	}
447 
448 	if (UDESC_CONFIG != desc->bDescriptorType)
449 		return EXIT_FAILURE;
450 
451 	if (desc->bLength > len)
452 		return EXIT_FAILURE;
453 
454 	if (sizeof(*desc) != desc->bLength)
455 		return EXIT_FAILURE;
456 
457 	memcpy(&(c->descriptor), buf, sizeof(c->descriptor));
458 
459 	c->num_interfaces = c->descriptor.bNumInterface;
460 
461 	interfaces_size = c->num_interfaces * sizeof(*(c->interface));
462 
463 	USB_DBG("Allocating interfaces, %dB", interfaces_size);
464 	c->interface = malloc(interfaces_size);
465 
466 	memset(c->interface, 0, interfaces_size);
467 
468 	/* Dump configuration in debug mode */
469 	USB_DBG("<<CONFIGURATION>>");
470 	USB_DBG("bLength %02X",			desc->bLength);
471 	USB_DBG("bDescriptorType %02X",		desc->bDescriptorType);
472 	USB_DBG("wTotalLength %04X",		UGETW(desc->wTotalLength));
473 	USB_DBG("bNumInterface %02X",		desc->bNumInterface);
474 	USB_DBG("bConfigurationValue %02X",	desc->bConfigurationValue);
475 	USB_DBG("iConfiguration %02X",		desc->iConfiguration);
476 	USB_DBG("bmAttributes %02X",		desc->bmAttributes);
477 	USB_DBG("bMaxPower %02X",		desc->bMaxPower);
478 
479 	return EXIT_SUCCESS;
480 }
481 
482 
483 /*===========================================================================*
484  *    hcd_fill_interface                                                     *
485  *===========================================================================*/
486 static int
487 hcd_fill_interface(hcd_reg1 * buf, int len, hcd_interface * i, int num)
488 {
489 	hcd_interface_descriptor * desc;
490 	int endpoints_size;
491 
492 	DEBUG_DUMP;
493 
494 	desc = (hcd_interface_descriptor *)buf;
495 
496 	USB_DBG("Interface #%d", num);
497 
498 	if (UDESC_INTERFACE != desc->bDescriptorType)
499 		return EXIT_FAILURE;
500 
501 	if (desc->bLength > len)
502 		return EXIT_FAILURE;
503 
504 	if (sizeof(*desc) != desc->bLength)
505 		return EXIT_FAILURE;
506 
507 	/* It is mandatory to supply interfaces in correct order */
508 	if (desc->bInterfaceNumber != num)
509 		return EXIT_FAILURE;
510 
511 	memcpy(&(i->descriptor), buf, sizeof(i->descriptor));
512 
513 	i->num_endpoints = i->descriptor.bNumEndpoints;
514 
515 	endpoints_size = i->num_endpoints * sizeof(*(i->endpoint));
516 
517 	USB_DBG("Allocating endpoints, %dB", endpoints_size);
518 	i->endpoint = malloc(endpoints_size);
519 
520 	memset(i->endpoint, 0, endpoints_size);
521 
522 	/* Dump interface in debug mode */
523 	USB_DBG("<<INTERFACE>>");
524 	USB_DBG("bLength %02X",			desc->bLength);
525 	USB_DBG("bDescriptorType %02X",		desc->bDescriptorType);
526 	USB_DBG("bInterfaceNumber %02X",	desc->bInterfaceNumber);
527 	USB_DBG("bAlternateSetting %02X",	desc->bAlternateSetting);
528 	USB_DBG("bNumEndpoints %02X",		desc->bNumEndpoints);
529 	USB_DBG("bInterfaceClass %02X",		desc->bInterfaceClass);
530 	USB_DBG("bInterfaceSubClass %02X",	desc->bInterfaceSubClass);
531 	USB_DBG("bInterfaceProtocol %02X",	desc->bInterfaceProtocol);
532 	USB_DBG("iInterface %02X",		desc->iInterface);
533 
534 	return EXIT_SUCCESS;
535 }
536 
537 
538 /*===========================================================================*
539  *    hcd_fill_endpoint                                                      *
540  *===========================================================================*/
541 static int
542 hcd_fill_endpoint(hcd_reg1 * buf, int len, hcd_endpoint * e)
543 {
544 	hcd_endpoint_descriptor * desc;
545 
546 	DEBUG_DUMP;
547 
548 	desc = (hcd_endpoint_descriptor *)buf;
549 
550 	USB_DBG("Endpoint #%d", UE_GET_ADDR(desc->bEndpointAddress));
551 
552 	if (UDESC_ENDPOINT != desc->bDescriptorType)
553 		return EXIT_FAILURE;
554 
555 	if (desc->bLength > len)
556 		return EXIT_FAILURE;
557 
558 	if (sizeof(*desc) != desc->bLength)
559 		return EXIT_FAILURE;
560 
561 	memcpy(&(e->descriptor), buf, sizeof(e->descriptor));
562 
563 	/* Dump endpoint in debug mode */
564 	USB_DBG("<<ENDPOINT>>");
565 	USB_DBG("bLength %02X",			desc->bLength);
566 	USB_DBG("bDescriptorType %02X",		desc->bDescriptorType);
567 	USB_DBG("bEndpointAddress %02X",	desc->bEndpointAddress);
568 	USB_DBG("bmAttributes %02X",		desc->bmAttributes);
569 	USB_DBG("wMaxPacketSize %04X",		UGETW(desc->wMaxPacketSize));
570 	USB_DBG("bInterval %02X",		desc->bInterval);
571 
572 	return EXIT_SUCCESS;
573 }
574