tools/llvm: Do not build with symbols
[minix3.git] / minix / drivers / usb / usbd / hcd / hcd.c
blob018ceea1ff22144bcaeabcd81a9fa190d70e2d1f
1 /*
2 * Implementation of generic HCD
3 */
5 #include <string.h> /* memcpy */
7 #include <minix/drivers.h> /* errno with sign */
9 #include <usbd/hcd_common.h>
10 #include <usbd/hcd_ddekit.h>
11 #include <usbd/hcd_interface.h>
12 #include <usbd/hcd_schedule.h>
13 #include <usbd/usbd_common.h>
16 /*===========================================================================*
17 * Local declarations *
18 *===========================================================================*/
19 /* Thread to handle device logic */
20 static void hcd_device_thread(void *);
22 /* Procedure that locks device thread forever in case of error/completion */
23 static void hcd_device_finish(hcd_device_state *, const char *);
25 /* Procedure that finds device, waiting for given EP interrupt */
26 static hcd_device_state * hcd_get_child_for_ep(hcd_device_state *, hcd_reg1);
28 /* For HCD level, hub handling */
29 static void hcd_add_child(hcd_device_state *, hcd_reg1, hcd_speed);
30 static void hcd_delete_child(hcd_device_state *, hcd_reg1);
31 static void hcd_disconnect_tree(hcd_device_state *);
32 static void hcd_dump_tree(hcd_device_state *, hcd_reg1);
34 /* Typical USD device communication procedures */
35 static int hcd_enumerate(hcd_device_state *);
36 static int hcd_get_device_descriptor(hcd_device_state *);
37 static int hcd_set_address(hcd_device_state *);
38 static int hcd_get_descriptor_tree(hcd_device_state *);
39 static int hcd_set_configuration(hcd_device_state *, hcd_reg1);
40 static void hcd_handle_urb(hcd_device_state *);
41 static void hcd_complete_urb(hcd_device_state *);
42 static int hcd_control_urb(hcd_device_state *, hcd_urb *);
43 static int hcd_non_control_urb(hcd_device_state *, hcd_urb *);
45 /* For internal use by more general methods */
46 static int hcd_setup_packet(hcd_device_state *, hcd_ctrlrequest *, hcd_reg1);
47 static int hcd_finish_setup(hcd_device_state *, void *);
48 static int hcd_data_transfer(hcd_device_state *, hcd_datarequest *);
50 /* TODO: This is not meant to be explicitly visible outside DDEKit library
51 * but there is no other way to set thread priority for now */
52 extern void _ddekit_thread_set_myprio(int);
55 /*===========================================================================*
56 * Local definitions *
57 *===========================================================================*/
58 /* TODO: This was added for compatibility with DDELinux drivers that
59 * allow receiving less data than expected in URB, without error */
60 #define HCD_ANY_LENGTH 0xFFFFFFFFu
62 /* This doesn't seem to be specified in standard but abnormal values
63 * are unlikely so check for this was added below */
64 #define HCD_SANE_DESCRIPTOR_LENGTH 2048
67 /*===========================================================================*
68 * hcd_handle_event *
69 *===========================================================================*/
70 void
71 hcd_handle_event(hcd_device_state * device, hcd_event event, hcd_reg1 val)
73 DEBUG_DUMP;
75 /* Invalid device may be supplied */
76 if (EXIT_SUCCESS != hcd_check_device(device)) {
77 USB_MSG("No device available for event: 0x%02X, value: 0x%02X",
78 event, val);
79 return;
82 #ifdef HCD_DUMP_DEVICE_TREE
83 /* This can be unlocked to dump current USB device tree on event */
85 /* Go to the base of USB device tree and
86 * print the current state of it */
87 hcd_device_state * base;
89 base = device;
91 while (NULL != base->parent)
92 base = base->parent;
94 USB_MSG("Current state of USB device tree:");
95 hcd_dump_tree(base, 0);
97 #endif
99 /* Handle event and forward control to device thread when required */
100 switch (event) {
101 case HCD_EVENT_CONNECTED:
102 USB_ASSERT((HCD_STATE_DISCONNECTED == device->state),
103 "Device not marked as 'disconnected' "
104 "for 'connection' event");
106 /* Try creating new thread for device */
107 if (hcd_connect_device(device, hcd_device_thread))
108 USB_MSG("Device creation failed, nothing more "
109 "will happen until disconnected");
111 break;
113 case HCD_EVENT_DISCONNECTED:
114 USB_ASSERT((HCD_STATE_DISCONNECTED != device->state),
115 "Device is marked as 'disconnected' "
116 "for 'disconnection' event");
118 /* Make this device and all attached children
119 * disconnect recursively */
120 hcd_disconnect_tree(device);
122 break;
124 case HCD_EVENT_PORT_LS_CONNECTED:
125 USB_ASSERT((HCD_STATE_DISCONNECTED != device->state),
126 "Device is marked as 'disconnected' "
127 "for 'hub port LS attach' event");
129 USB_MSG("Low speed device connected at "
130 "hub 0x%08X, port %u", device, val);
132 hcd_add_child(device, val, HCD_SPEED_LOW);
133 break;
135 case HCD_EVENT_PORT_FS_CONNECTED:
136 USB_ASSERT((HCD_STATE_DISCONNECTED != device->state),
137 "Device is marked as 'disconnected' "
138 "for 'hub port FS attach' event");
140 USB_MSG("Full speed device connected at "
141 "hub 0x%08X, port %u", device, val);
143 hcd_add_child(device, val, HCD_SPEED_FULL);
144 break;
146 case HCD_EVENT_PORT_HS_CONNECTED:
147 USB_ASSERT((HCD_STATE_DISCONNECTED != device->state),
148 "Device is marked as 'disconnected' "
149 "for 'hub port HS attach' event");
151 USB_MSG("High speed device connected at "
152 "hub 0x%08X, port %u", device, val);
154 hcd_add_child(device, val, HCD_SPEED_HIGH);
155 break;
157 case HCD_EVENT_PORT_DISCONNECTED:
158 USB_ASSERT((HCD_STATE_DISCONNECTED != device->state),
159 "Device is marked as 'disconnected' "
160 "for 'hub port detach' event");
162 hcd_delete_child(device, val);
164 USB_MSG("Device disconnected from "
165 "hub 0x%08X, port %u", device, val);
167 break;
169 case HCD_EVENT_ENDPOINT:
170 USB_ASSERT((HCD_STATE_DISCONNECTED != device->state),
171 "Parent device is marked as 'disconnected' "
172 "for 'endpoint' event");
174 /* Alters 'device' when endpoint is allocated to
175 * child rather than parent (hub), which allows
176 * proper thread to continue */
177 device = hcd_get_child_for_ep(device, val);
179 /* Check if anything at all, waits for such endpoint */
180 if (device)
181 /* Allow device thread, waiting for endpoint
182 * event, to continue with its logic */
183 hcd_device_continue(device, event, val);
184 else
185 USB_MSG("No device waits for endpoint %u", val);
187 break;
189 case HCD_EVENT_URB:
190 USB_ASSERT((HCD_STATE_DISCONNECTED != device->state),
191 "Device is marked as 'disconnected' "
192 "for 'URB' event");
194 /* Allow device thread to continue with it's logic */
195 hcd_device_continue(device, event, val);
197 break;
199 default:
200 USB_ASSERT(0, "Illegal HCD event");
205 /*===========================================================================*
206 * hcd_update_port *
207 *===========================================================================*/
208 void
209 hcd_update_port(hcd_driver_state * driver, hcd_event event)
211 DEBUG_DUMP;
213 switch (event) {
214 case HCD_EVENT_CONNECTED:
215 /* Check if already assigned */
216 USB_ASSERT(NULL == driver->port_device,
217 "Device was already connected before "
218 "receiving 'connection' event");
220 /* Assign new blank device */
221 driver->port_device = hcd_new_device();
223 /* Associate this device with driver */
224 driver->port_device->driver = driver;
225 break;
227 case HCD_EVENT_DISCONNECTED:
228 /* Check if already released */
229 USB_ASSERT(NULL != driver->port_device,
230 "Device was already disconnected before "
231 "receiving 'disconnection' event");
233 /* Release device */
234 hcd_delete_device(driver->port_device);
236 /* Clear port device pointer */
237 driver->port_device = NULL;
238 break;
240 default:
241 USB_ASSERT(0, "Illegal port update event");
246 /*===========================================================================*
247 * hcd_device_thread *
248 *===========================================================================*/
249 static void
250 hcd_device_thread(void * thread_args)
252 hcd_device_state * this_device;
254 DEBUG_DUMP;
256 /* Set device thread priority higher so it
257 * won't change context unless explicitly locked */
258 _ddekit_thread_set_myprio(2);
260 /* Retrieve structures from generic data */
261 this_device = (hcd_device_state *)thread_args;
263 /* Enumeration sequence */
264 if (EXIT_SUCCESS != hcd_enumerate(this_device))
265 hcd_device_finish(this_device, "USB device enumeration failed");
267 /* Tell everyone that device was connected */
268 hcd_connect_cb(this_device);
270 /* Fully configured */
271 this_device->state = HCD_STATE_CONNECTED;
273 USB_DBG("Waiting for URBs");
275 /* Start handling URB's */
276 for(;;) {
277 /* Block and wait for something like 'submit URB' */
278 hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
279 hcd_handle_urb(this_device);
282 /* Finish device handling to avoid leaving thread */
283 hcd_device_finish(this_device, "USB device handling completed");
287 /*===========================================================================*
288 * hcd_device_finish *
289 *===========================================================================*/
290 static void
291 hcd_device_finish(hcd_device_state * this_device, const char * finish_msg)
293 DEBUG_DUMP;
295 USB_MSG("USB device handling finished with message: '%s'", finish_msg);
297 /* Lock forever */
298 for (;;) {
299 hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
300 USB_MSG("Failed attempt to continue finished thread");
305 /*===========================================================================*
306 * hcd_get_child_for_ep *
307 *===========================================================================*/
308 static hcd_device_state *
309 hcd_get_child_for_ep(hcd_device_state * device, hcd_reg1 ep)
311 hcd_device_state * child_found;
312 hcd_device_state * final_found;
313 hcd_device_state * child;
314 hcd_reg1 child_num;
316 DEBUG_DUMP;
318 /* Nothing yet */
319 final_found = NULL;
321 /* Check if any children (and their children) wait for EP event */
322 /* Every device in tree is checked every time so errors can be found */
323 for (child_num = 0; child_num < HCD_CHILDREN; child_num++) {
324 /* Device, to be checked for EP event recursively... */
325 child = device->child[child_num];
327 /* ...but only if attached */
328 if (NULL != child) {
329 /* Look deeper first */
330 child_found = hcd_get_child_for_ep(child, ep);
332 if (NULL != child_found) {
333 /* Only one device can wait for EP event */
334 USB_ASSERT((NULL == final_found),
335 "More than one device waits for EP");
336 /* Remember what was found */
337 final_found = child_found;
342 /* Check this device last */
343 if ((HCD_EVENT_ENDPOINT == device->wait_event) &&
344 (ep == device->wait_ep)) {
345 /* Only one device can wait for EP event */
346 USB_ASSERT((NULL == final_found),
347 "More than one device waits for EP");
348 /* Remember what was found */
349 final_found = device;
352 return final_found;
356 /*===========================================================================*
357 * hcd_add_child *
358 *===========================================================================*/
359 static void
360 hcd_add_child(hcd_device_state * parent, hcd_reg1 port, hcd_speed speed)
362 DEBUG_DUMP;
364 USB_ASSERT(port < HCD_CHILDREN, "Port number too high");
365 USB_ASSERT(NULL == parent->child[port], "Child device already exists");
367 /* Basic addition */
368 parent->child[port] = hcd_new_device();
369 parent->child[port]->parent = parent;
371 /* Inherit parent's driver */
372 parent->child[port]->driver = parent->driver;
374 /* Remember speed, determined by hub driver */
375 parent->child[port]->speed = speed;
377 /* Try creating new thread for device */
378 if (hcd_connect_device(parent->child[port], hcd_device_thread))
379 USB_MSG("Device creation failed, nothing more "
380 "will happen until disconnected");
384 /*===========================================================================*
385 * hcd_delete_child *
386 *===========================================================================*/
387 static void
388 hcd_delete_child(hcd_device_state * parent, hcd_reg1 port)
390 hcd_device_state * child;
392 DEBUG_DUMP;
394 USB_ASSERT(port < HCD_CHILDREN, "Port number too high");
396 child = parent->child[port]; /* Child to be detached */
398 USB_ASSERT(NULL != child, "Child device does not exist");
400 /* Make this child device and all its attached children
401 * disconnect recursively */
402 hcd_disconnect_tree(child);
404 /* Delete to release device itself */
405 hcd_delete_device(child);
407 /* Mark as released */
408 parent->child[port] = NULL;
412 /*===========================================================================*
413 * hcd_disconnect_tree *
414 *===========================================================================*/
415 static void
416 hcd_disconnect_tree(hcd_device_state * device)
418 hcd_reg1 child_num;
420 DEBUG_DUMP;
422 /* Generate disconnect event for all children */
423 for (child_num = 0; child_num < HCD_CHILDREN; child_num++) {
424 if (NULL != device->child[child_num])
425 hcd_handle_event(device, HCD_EVENT_PORT_DISCONNECTED,
426 child_num);
429 /* If this device was detached during URB handling, some steps must be
430 * taken to ensure that no process/thread is waiting for completion */
431 if (NULL != device->urb) {
432 USB_MSG("Unplugged device had unhandled URB");
433 /* Tell device driver that device was detached */
434 /* TODO: ENODEV selected for that */
435 device->urb->inout_status = ENODEV;
436 hcd_complete_urb(device);
439 /* If connect callback was used before, call
440 * it's equivalent to signal disconnection */
441 if (HCD_STATE_CONNECTED == device->state)
442 hcd_disconnect_cb(device);
444 /* Handle device disconnection (freeing memory etc.) */
445 hcd_disconnect_device(device);
449 /*===========================================================================*
450 * hcd_dump_tree *
451 *===========================================================================*/
452 static void
453 hcd_dump_tree(hcd_device_state * device, hcd_reg1 level)
455 hcd_reg1 child_num;
457 /* DEBUG_DUMP; */ /* Let's keep tree output cleaner */
459 USB_MSG("Device on level %03u: 0x%08X", level, device);
461 /* Traverse device tree recursively */
462 for (child_num = 0; child_num < HCD_CHILDREN; child_num++) {
463 if (NULL != device->child[child_num])
464 hcd_dump_tree(device->child[child_num], level + 1);
469 /*===========================================================================*
470 * hcd_enumerate *
471 *===========================================================================*/
472 static int
473 hcd_enumerate(hcd_device_state * this_device)
475 hcd_driver_state * d;
477 DEBUG_DUMP;
479 d = this_device->driver;
481 /* Having a parent device also means being reseted by it
482 * so only reset devices that have no parents */
483 if (NULL == this_device->parent) {
484 /* First let driver reset device */
485 if (EXIT_SUCCESS != d->reset_device(d->private_data,
486 &(this_device->speed))) {
487 USB_MSG("Failed to reset device");
488 return EXIT_FAILURE;
492 /* Default MaxPacketSize, based on speed */
493 if (HCD_SPEED_HIGH == this_device->speed)
494 this_device->max_packet_size = HCD_HS_MAXPACKETSIZE;
495 else
496 this_device->max_packet_size = HCD_LS_MAXPACKETSIZE;
498 /* Get device descriptor */
499 if (EXIT_SUCCESS != hcd_get_device_descriptor(this_device)) {
500 USB_MSG("Failed to get device descriptor");
501 return EXIT_FAILURE;
504 /* Remember max packet size from device descriptor */
505 this_device->max_packet_size = this_device->device_desc.bMaxPacketSize;
507 /* Dump device descriptor in debug mode */
508 #ifdef DEBUG
510 hcd_device_descriptor * d;
511 d = &(this_device->device_desc);
513 USB_DBG("<<DEVICE>>");
514 USB_DBG("bLength %02X", d->bLength);
515 USB_DBG("bDescriptorType %02X", d->bDescriptorType);
516 USB_DBG("bcdUSB %04X", UGETW(d->bcdUSB));
517 USB_DBG("bDeviceClass %02X", d->bDeviceClass);
518 USB_DBG("bDeviceSubClass %02X", d->bDeviceSubClass);
519 USB_DBG("bDeviceProtocol %02X", d->bDeviceProtocol);
520 USB_DBG("bMaxPacketSize %02X", d->bMaxPacketSize);
521 USB_DBG("idVendor %04X", UGETW(d->idVendor));
522 USB_DBG("idProduct %04X", UGETW(d->idProduct));
523 USB_DBG("bcdDevice %04X", UGETW(d->bcdDevice));
524 USB_DBG("iManufacturer %02X", d->iManufacturer);
525 USB_DBG("iProduct %02X", d->iProduct);
526 USB_DBG("iSerialNumber %02X", d->iSerialNumber);
527 USB_DBG("bNumConfigurations %02X", d->bNumConfigurations);
529 #endif
531 /* Set reserved address */
532 if (EXIT_SUCCESS != hcd_set_address(this_device)) {
533 USB_MSG("Failed to set device address");
534 return EXIT_FAILURE;
537 /* Sleep 5msec to allow addressing */
538 hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(5));
540 /* Remember what was assigned in hardware */
541 this_device->current_address = this_device->reserved_address;
543 /* Get other descriptors */
544 if (EXIT_SUCCESS != hcd_get_descriptor_tree(this_device)) {
545 USB_MSG("Failed to get configuration descriptor tree");
546 return EXIT_FAILURE;
549 /* TODO: Always use first configuration, as there is no support for
550 * multiple configurations in DDEKit/devman and devices rarely have
551 * more than one anyway */
552 /* Set configuration */
553 if (EXIT_SUCCESS != hcd_set_configuration(this_device,
554 HCD_SET_CONFIG_NUM(HCD_DEFAULT_CONFIG))) {
555 USB_MSG("Failed to set configuration");
556 return EXIT_FAILURE;
559 USB_DBG("Enumeration completed");
561 return EXIT_SUCCESS;
565 /*===========================================================================*
566 * hcd_get_device_descriptor *
567 *===========================================================================*/
568 static int
569 hcd_get_device_descriptor(hcd_device_state * this_device)
571 hcd_ctrlrequest setup;
572 hcd_urb urb;
574 DEBUG_DUMP;
576 /* TODO: magic numbers, no header for these */
577 /* Format setup packet */
578 setup.bRequestType = 0x80; /* IN */
579 setup.bRequest = 0x06; /* Get descriptor */
580 setup.wValue = 0x0100; /* Device */
581 setup.wIndex = 0x0000;
582 setup.wLength = sizeof(this_device->device_desc);
584 /* Prepare self-URB */
585 memset(&urb, 0, sizeof(urb));
586 urb.direction = HCD_DIRECTION_IN;
587 urb.endpoint = HCD_DEFAULT_EP;
588 urb.in_setup = &setup;
589 urb.inout_data = (hcd_reg1 *)(&(this_device->device_desc));
590 urb.target_device = this_device;
591 urb.type = HCD_TRANSFER_CONTROL;
593 /* Put it to be scheduled and wait for control to get back */
594 hcd_schedule_internal_urb(&urb);
595 hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
596 hcd_handle_urb(this_device);
598 /* Check if URB submission completed successfully */
599 if (urb.inout_status) {
600 USB_MSG("URB submission failed");
601 return EXIT_FAILURE;
604 /* Check if expected size was received */
605 if (urb.out_size != setup.wLength) {
606 USB_MSG("URB submission returned invalid amount of data");
607 return EXIT_FAILURE;
610 return EXIT_SUCCESS;
614 /*===========================================================================*
615 * hcd_set_address *
616 *===========================================================================*/
617 static int
618 hcd_set_address(hcd_device_state * this_device)
620 hcd_ctrlrequest setup;
621 hcd_urb urb;
623 DEBUG_DUMP;
625 /* Check for legal USB device address (must be non-zero as well) */
626 USB_ASSERT((this_device->reserved_address > HCD_DEFAULT_ADDR) &&
627 (this_device->reserved_address <= HCD_LAST_ADDR),
628 "Illegal device address supplied");
630 /* TODO: magic numbers, no header for these */
631 setup.bRequestType = 0x00; /* OUT */
632 setup.bRequest = 0x05; /* Set address */
633 setup.wValue = this_device->reserved_address;
634 setup.wIndex = 0x0000;
635 setup.wLength = 0x0000;
637 /* Prepare self-URB */
638 memset(&urb, 0, sizeof(urb));
639 urb.direction = HCD_DIRECTION_OUT;
640 urb.endpoint = HCD_DEFAULT_EP;
641 urb.in_setup = &setup;
642 urb.inout_data = NULL;
643 urb.target_device = this_device;
644 urb.type = HCD_TRANSFER_CONTROL;
646 /* Put it to be scheduled and wait for control to get back */
647 hcd_schedule_internal_urb(&urb);
648 hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
649 hcd_handle_urb(this_device);
651 /* Check if URB submission completed successfully */
652 if (urb.inout_status) {
653 USB_MSG("URB submission failed");
654 return EXIT_FAILURE;
657 /* Check if expected size was received */
658 if (urb.out_size != setup.wLength) {
659 USB_MSG("URB submission returned invalid amount of data");
660 return EXIT_FAILURE;
663 return EXIT_SUCCESS;
667 /*===========================================================================*
668 * hcd_get_descriptor_tree *
669 *===========================================================================*/
670 static int
671 hcd_get_descriptor_tree(hcd_device_state * this_device)
673 hcd_config_descriptor temp_config_descriptor;
674 hcd_ctrlrequest setup;
675 hcd_urb urb;
677 /* To receive data */
678 hcd_reg4 expected_length;
679 hcd_reg1 * expected_buffer;
681 int retval;
683 DEBUG_DUMP;
685 /* Initially */
686 retval = EXIT_FAILURE;
687 expected_buffer = NULL;
689 /* First part gets only configuration to find out total length */
691 /* TODO: Default configuration is hard-coded
692 * but others are rarely used anyway */
693 /* TODO: magic numbers, no header for these */
694 setup.bRequestType = 0x80; /* IN */
695 setup.bRequest = 0x06; /* Get descriptor */
696 setup.wValue = 0x0200 | HCD_DEFAULT_CONFIG;
697 setup.wIndex = 0x0000;
698 setup.wLength = sizeof(temp_config_descriptor);
700 /* Prepare self-URB */
701 memset(&urb, 0, sizeof(urb));
702 urb.direction = HCD_DIRECTION_IN;
703 urb.endpoint = HCD_DEFAULT_EP;
704 urb.in_setup = &setup;
705 urb.inout_data = (hcd_reg1 *)(&temp_config_descriptor);
706 urb.target_device = this_device;
707 urb.type = HCD_TRANSFER_CONTROL;
709 /* Put it to be scheduled and wait for control to get back */
710 hcd_schedule_internal_urb(&urb);
711 hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
712 hcd_handle_urb(this_device);
714 /* Check if URB submission completed successfully */
715 if (urb.inout_status) {
716 USB_MSG("URB submission failed");
717 goto FINISH;
720 /* Check if expected size was received */
721 if (urb.out_size != setup.wLength) {
722 USB_MSG("URB submission returned "
723 "invalid amount of data");
724 goto FINISH;
728 /* Get total expected length */
729 expected_length = UGETW(temp_config_descriptor.wTotalLength);
731 /* Check for abnormal value */
732 if (expected_length > HCD_SANE_DESCRIPTOR_LENGTH) {
733 USB_MSG("Total descriptor length declared is too high");
734 goto FINISH;
737 /* Get descriptor buffer to hold everything expected */
738 if (NULL == (expected_buffer = malloc(expected_length))) {
739 USB_MSG("Descriptor allocation failed");
740 goto FINISH;
743 /* Second part gets all available descriptors */
745 /* TODO: Default configuration is hard-coded
746 * but others are rarely used anyway */
747 /* TODO: magic numbers, no header for these */
748 setup.bRequestType = 0x80; /* IN */
749 setup.bRequest = 0x06; /* Get descriptor */
750 setup.wValue = 0x0200 | HCD_DEFAULT_CONFIG;
751 setup.wIndex = 0x0000;
752 setup.wLength = expected_length;
754 /* Prepare self-URB */
755 memset(&urb, 0, sizeof(urb));
756 urb.direction = HCD_DIRECTION_IN;
757 urb.endpoint = HCD_DEFAULT_EP;
758 urb.in_setup = &setup;
759 urb.inout_data = expected_buffer;
760 urb.target_device = this_device;
761 urb.type = HCD_TRANSFER_CONTROL;
763 /* Put it to be scheduled and wait for control to get back */
764 hcd_schedule_internal_urb(&urb);
765 hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
766 hcd_handle_urb(this_device);
768 /* Check if URB submission completed successfully */
769 if (urb.inout_status) {
770 USB_MSG("URB submission failed");
771 goto FINISH;
774 /* Check if expected size was received */
775 if (urb.out_size != setup.wLength) {
776 USB_MSG("URB submission returned "
777 "invalid amount of data");
778 goto FINISH;
782 if (EXIT_SUCCESS != hcd_buffer_to_tree(expected_buffer,
783 (int)expected_length,
784 &(this_device->config_tree))) {
785 USB_MSG("Broken descriptor data");
786 goto FINISH;
789 /* No errors occurred */
790 retval = EXIT_SUCCESS;
792 FINISH:
794 /* Release allocated buffer */
795 if (expected_buffer)
796 free(expected_buffer);
798 return retval;
802 /*===========================================================================*
803 * hcd_set_configuration *
804 *===========================================================================*/
805 static int
806 hcd_set_configuration(hcd_device_state * this_device, hcd_reg1 configuration)
808 hcd_ctrlrequest setup;
809 hcd_urb urb;
811 DEBUG_DUMP;
813 /* TODO: magic numbers, no header for these */
814 setup.bRequestType = 0x00; /* OUT */
815 setup.bRequest = 0x09; /* Set configuration */
816 setup.wValue = configuration;
817 setup.wIndex = 0x0000;
818 setup.wLength = 0x0000;
820 /* Prepare self-URB */
821 memset(&urb, 0, sizeof(urb));
822 urb.direction = HCD_DIRECTION_OUT;
823 urb.endpoint = HCD_DEFAULT_EP;
824 urb.in_setup = &setup;
825 urb.inout_data = NULL;
826 urb.target_device = this_device;
827 urb.type = HCD_TRANSFER_CONTROL;
829 /* Put it to be scheduled and wait for control to get back */
830 hcd_schedule_internal_urb(&urb);
831 hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
832 hcd_handle_urb(this_device);
834 return urb.inout_status;
838 /*===========================================================================*
839 * hcd_handle_urb *
840 *===========================================================================*/
841 static void
842 hcd_handle_urb(hcd_device_state * this_device)
844 hcd_urb * urb;
845 int transfer_status;
847 DEBUG_DUMP;
849 /* Retrieve URB */
850 urb = this_device->urb;
852 USB_ASSERT(NULL != urb, "No URB supplied");
853 USB_ASSERT(this_device == urb->target_device, "Unknown device for URB");
855 /* Only if URB parsing was completed... */
856 if (EXIT_SUCCESS == urb->inout_status) {
858 transfer_status = EXIT_FAILURE;
860 /* ...check for URB to handle */
861 switch (urb->type) {
862 case HCD_TRANSFER_CONTROL:
863 transfer_status = hcd_control_urb(
864 this_device, urb);
865 break;
867 case HCD_TRANSFER_BULK:
868 case HCD_TRANSFER_INTERRUPT:
869 transfer_status = hcd_non_control_urb(
870 this_device, urb);
871 break;
873 default:
874 USB_MSG("Unsupported transfer type 0x%02X",
875 (int)urb->type);
876 break;
879 /* In case of error, only dump message */
880 if (EXIT_SUCCESS != transfer_status)
881 USB_MSG("USB transfer failed");
883 } else
884 USB_MSG("Invalid URB supplied");
886 /* Perform completion routine */
887 hcd_complete_urb(this_device);
891 /*===========================================================================*
892 * hcd_complete_urb *
893 *===========================================================================*/
894 static void
895 hcd_complete_urb(hcd_device_state * this_device)
897 DEBUG_DUMP;
899 /* Signal scheduler that URB was handled */
900 this_device->urb->handled(this_device->urb);
902 /* Use this callback in case it is an external URB */
903 hcd_completion_cb(this_device->urb);
905 /* Make device forget about this URB */
906 this_device->urb = NULL;
910 /*===========================================================================*
911 * hcd_control_urb *
912 *===========================================================================*/
913 static int
914 hcd_control_urb(hcd_device_state * this_device, hcd_urb * urb)
916 DEBUG_DUMP;
918 /* Assume bad values unless something different occurs later */
919 urb->inout_status = EINVAL;
921 /* Must have setup packet for control transfer */
922 if (NULL == urb->in_setup) {
923 USB_MSG("No setup packet in URB, for control transfer");
924 return EXIT_FAILURE;
927 /* TODO: Only EP0 can have control transfer */
928 if (HCD_DEFAULT_EP != urb->endpoint) {
929 USB_MSG("Control transfer for non zero EP");
930 return EXIT_FAILURE;
933 /* Setup and URB directions should match */
934 if (((urb->in_setup->bRequestType >> 7) & 0x01) != urb->direction) {
935 USB_MSG("URB Direction mismatch");
936 return EXIT_FAILURE;
939 /* Send setup packet */
940 if (EXIT_SUCCESS != hcd_setup_packet(this_device, urb->in_setup,
941 urb->endpoint)) {
942 USB_MSG("Sending URB setup packet, failed");
943 urb->inout_status = EPIPE;
944 return EXIT_FAILURE;
947 /* Put what was read back into URB */
948 if (EXIT_SUCCESS != hcd_finish_setup(this_device, urb->inout_data))
949 return EXIT_FAILURE;
951 /* Write transfer output info to URB */
952 urb->out_size = (hcd_reg4)this_device->control_len;
953 urb->inout_status = EXIT_SUCCESS;
955 return EXIT_SUCCESS;
959 /*===========================================================================*
960 * hcd_non_control_urb *
961 *===========================================================================*/
962 static int
963 hcd_non_control_urb(hcd_device_state * this_device, hcd_urb * urb)
965 hcd_endpoint * e;
966 hcd_datarequest request;
968 DEBUG_DUMP;
970 /* Assume bad values unless something different occurs later */
971 urb->inout_status = EINVAL;
973 /* Must have data buffer to send/receive */
974 if (NULL == urb->inout_data) {
975 USB_MSG("No data packet in URB");
976 return EXIT_FAILURE;
979 if (HCD_DEFAULT_EP == urb->endpoint) {
980 USB_MSG("Non-control transfer for EP0");
981 return EXIT_FAILURE;
984 /* Check if EP number is valid within remembered descriptor tree */
985 e = hcd_tree_find_ep(&(this_device->config_tree), urb->endpoint);
987 if (NULL == e) {
988 USB_MSG("Invalid EP number for this device");
989 return EXIT_FAILURE;
992 /* Check if remembered descriptor direction, matches the one in URB */
993 if (((e->descriptor.bEndpointAddress >> 7) & 0x01) != urb->direction) {
994 USB_MSG("EP direction mismatch");
995 return EXIT_FAILURE;
998 /* Check if remembered type matches */
999 if (UE_GET_XFERTYPE(e->descriptor.bmAttributes) != urb->type) {
1000 USB_MSG("EP type mismatch");
1001 return EXIT_FAILURE;
1004 /* Check if remembered interval matches */
1005 if ((hcd_reg1)e->descriptor.bInterval != urb->interval) {
1006 USB_MSG("EP interval mismatch");
1007 return EXIT_FAILURE;
1010 /* Assign URB values to data request structure */
1011 request.type = urb->type;
1012 request.endpoint = urb->endpoint;
1013 request.direction = urb->direction;
1014 request.data_left = (int)urb->in_size;
1015 request.data = urb->inout_data;
1016 /* TODO: This was changed to allow software scheduler to work correctly
1017 * by switching URBs when they NAK, rather than waiting forever if URB
1018 * which requires such waiting, was issued */
1019 #if 0
1020 request.interval = urb->interval;
1021 #else
1022 request.interval = HCD_DEFAULT_NAKLIMIT;
1023 #endif
1025 /* Assign to let know how much data can be transfered at a time */
1026 request.max_packet_size = UGETW(e->descriptor.wMaxPacketSize);
1028 /* Let know how to configure EP for speed */
1029 request.speed = this_device->speed;
1031 /* Start sending data */
1032 if (EXIT_SUCCESS != hcd_data_transfer(this_device, &request)) {
1033 USB_MSG("URB non-control transfer, failed");
1034 urb->inout_status = EPIPE;
1035 return EXIT_FAILURE;
1038 /* Transfer successfully completed update URB */
1039 USB_ASSERT(request.data_left >= 0,
1040 "Negative amount of transfer data remains");
1041 urb->out_size = urb->in_size - (hcd_reg4)request.data_left;
1042 urb->inout_status = EXIT_SUCCESS;
1044 return EXIT_SUCCESS;
1048 /*===========================================================================*
1049 * hcd_setup_packet *
1050 *===========================================================================*/
1051 static int
1052 hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup,
1053 hcd_reg1 ep)
1055 hcd_driver_state * d;
1056 hcd_reg1 * current_byte;
1057 int rx_len;
1059 DEBUG_DUMP;
1061 /* Should have been set at enumeration or with default values */
1062 USB_ASSERT(this_device->max_packet_size >= HCD_LS_MAXPACKETSIZE,
1063 "Illegal MaxPacketSize");
1064 USB_ASSERT(ep <= HCD_LAST_EP, "Invalid EP number");
1065 USB_ASSERT(this_device->current_address <= HCD_LAST_ADDR,
1066 "Invalid device address");
1068 /* Initially... */
1069 d = this_device->driver;
1070 current_byte = this_device->control_data;/* Start reading into this */
1071 this_device->control_len = 0; /* Nothing read yet */
1073 /* Set parameters for further communication */
1074 d->setup_device(d->private_data, ep, this_device->current_address,
1075 NULL, NULL);
1077 /* Send setup packet */
1078 d->setup_stage(d->private_data, setup);
1080 /* Wait for response */
1081 hcd_device_wait(this_device, HCD_EVENT_ENDPOINT, ep);
1083 /* Check response */
1084 if (EXIT_SUCCESS != d->check_error(d->private_data,
1085 HCD_TRANSFER_CONTROL,
1087 HCD_DIRECTION_UNUSED))
1088 return EXIT_FAILURE;
1090 /* For data packets... */
1091 if (setup->wLength > 0) {
1093 /* TODO: magic number */
1094 /* ...IN data packets */
1095 if (setup->bRequestType & 0x80) {
1097 for(;;) {
1099 /* Try getting data */
1100 d->in_data_stage(d->private_data);
1102 /* Wait for response */
1103 hcd_device_wait(this_device,
1104 HCD_EVENT_ENDPOINT, ep);
1106 /* Check response */
1107 if (EXIT_SUCCESS != d->check_error(
1108 d->private_data,
1109 HCD_TRANSFER_CONTROL,
1111 HCD_DIRECTION_UNUSED))
1112 return EXIT_FAILURE;
1114 /* Read data received as response */
1115 rx_len = d->read_data(d->private_data,
1116 current_byte, ep);
1118 /* Increment */
1119 current_byte += rx_len;
1120 this_device->control_len += rx_len;
1122 /* If max sized packet was read (or more)... */
1123 if (rx_len >= (int)this_device->max_packet_size)
1124 /* ...try reading next packet even if
1125 * zero bytes may be received */
1126 continue;
1128 /* If less than max data was read... */
1129 if (rx_len < (int)this_device->max_packet_size)
1130 /* ...it must have been
1131 * the last packet */
1132 break;
1134 /* Unreachable during normal operation */
1135 USB_MSG("rx_len: %d; max_packet_size: %d",
1136 rx_len, this_device->max_packet_size);
1137 USB_ASSERT(0, "Illegal state of data "
1138 "receive operation");
1141 } else {
1142 /* TODO: Unimplemented OUT DATA stage */
1143 d->out_data_stage(d->private_data);
1145 return EXIT_FAILURE;
1149 /* Status stages */
1150 if (setup->bRequestType & 0x80) {
1152 /* Try confirming data receive */
1153 d->out_status_stage(d->private_data);
1155 /* Wait for response */
1156 hcd_device_wait(this_device, HCD_EVENT_ENDPOINT, ep);
1158 /* Check response */
1159 if (EXIT_SUCCESS != d->check_error(d->private_data,
1160 HCD_TRANSFER_CONTROL,
1162 HCD_DIRECTION_UNUSED))
1163 return EXIT_FAILURE;
1165 } else {
1167 /* Try getting status confirmation */
1168 d->in_status_stage(d->private_data);
1170 /* Wait for response */
1171 hcd_device_wait(this_device, HCD_EVENT_ENDPOINT, ep);
1173 /* Check response */
1174 if (EXIT_SUCCESS != d->check_error(d->private_data,
1175 HCD_TRANSFER_CONTROL,
1177 HCD_DIRECTION_UNUSED))
1178 return EXIT_FAILURE;
1180 /* Read zero data from response to clear registers */
1181 if (0 != d->read_data(d->private_data, NULL, ep))
1182 return EXIT_FAILURE;
1185 return EXIT_SUCCESS;
1189 /*===========================================================================*
1190 * hcd_finish_setup *
1191 *===========================================================================*/
1192 static int
1193 hcd_finish_setup(hcd_device_state * this_device, void * output)
1195 DEBUG_DUMP;
1197 /* Validate setup transfer output length */
1198 if (this_device->control_len < 0) {
1199 USB_MSG("Negative control transfer output length");
1200 return EXIT_FAILURE;
1203 /* Length is valid but output not supplied */
1204 if (NULL == output)
1205 return EXIT_SUCCESS;
1207 /* Finally, copy when needed */
1208 memcpy(output, this_device->control_data, this_device->control_len);
1210 return EXIT_SUCCESS;
1214 /*===========================================================================*
1215 * hcd_data_transfer *
1216 *===========================================================================*/
1217 static int
1218 hcd_data_transfer(hcd_device_state * this_device, hcd_datarequest * request)
1220 hcd_driver_state * d;
1221 hcd_datarequest temp_req;
1222 int transfer_len;
1224 DEBUG_DUMP;
1226 USB_ASSERT((request->endpoint <= HCD_LAST_EP) &&
1227 (request->endpoint > HCD_DEFAULT_EP),
1228 "Invalid EP number");
1229 USB_ASSERT((this_device->current_address <= HCD_LAST_ADDR) &&
1230 (this_device->current_address > HCD_DEFAULT_ADDR),
1231 "Invalid device address");
1233 /* Initially... */
1234 d = this_device->driver;
1236 /* Set parameters for further communication */
1237 d->setup_device(d->private_data, request->endpoint,
1238 this_device->current_address,
1239 &(this_device->ep_tx_tog[request->endpoint]),
1240 &(this_device->ep_rx_tog[request->endpoint]));
1242 /* Check transfer direction first */
1243 if (HCD_DIRECTION_IN == request->direction) {
1245 do {
1246 /* Start actual data transfer */
1247 d->rx_stage(d->private_data, request);
1249 /* Wait for response */
1250 hcd_device_wait(this_device, HCD_EVENT_ENDPOINT,
1251 request->endpoint);
1253 /* Check response */
1254 if (EXIT_SUCCESS != d->check_error(d->private_data,
1255 request->type,
1256 request->endpoint,
1257 HCD_DIRECTION_IN))
1258 return EXIT_FAILURE;
1260 /* Read data received as response */
1261 transfer_len = d->read_data(d->private_data,
1262 request->data,
1263 request->endpoint);
1265 request->data_left -= transfer_len;
1266 request->data += transfer_len;
1268 /* Total length shall not become negative */
1269 if (request->data_left < 0) {
1270 USB_MSG("Invalid amount of data received");
1271 return EXIT_FAILURE;
1274 } while (0 != request->data_left);
1276 } else if (HCD_DIRECTION_OUT == request->direction) {
1278 do {
1279 temp_req = *request;
1281 /* Decide temporary transfer size */
1282 if (temp_req.data_left > (int)temp_req.max_packet_size)
1283 temp_req.data_left =
1284 (int)temp_req.max_packet_size;
1286 /* Alter actual transfer size */
1287 request->data += temp_req.data_left;
1288 request->data_left -= temp_req.data_left;
1290 /* Total length shall not become negative */
1291 USB_ASSERT(request->data_left >= 0,
1292 "Invalid amount of transfer data calculated");
1294 /* Start actual data transfer */
1295 d->tx_stage(d->private_data, &temp_req);
1297 /* Wait for response */
1298 hcd_device_wait(this_device, HCD_EVENT_ENDPOINT,
1299 request->endpoint);
1301 /* Check response */
1302 if (EXIT_SUCCESS != d->check_error(d->private_data,
1303 request->type,
1304 request->endpoint,
1305 HCD_DIRECTION_OUT))
1306 return EXIT_FAILURE;
1308 } while (0 != request->data_left);
1310 } else
1311 USB_ASSERT(0, "Invalid transfer direction");
1313 return EXIT_SUCCESS;