2 * Implementation of generic HCD
5 #include <string.h> /* memcpy */
7 #include <minix/drivers.h> /* errno with sign */
8 #include <minix/usb.h> /* USB_TRANSFER_CTL... */
10 #include <usb/hcd_common.h>
11 #include <usb/hcd_ddekit.h>
12 #include <usb/hcd_interface.h>
13 #include <usb/usb_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 /* Typical USD device communication procedures */
26 static int hcd_enumerate(hcd_device_state
*);
27 static int hcd_get_device_descriptor(hcd_device_state
*);
28 static int hcd_set_address(hcd_device_state
*, int);
29 static int hcd_get_descriptor_tree(hcd_device_state
*);
30 static int hcd_set_configuration(hcd_device_state
*, int);
31 static int hcd_handle_urb(hcd_device_state
*);
32 static int hcd_control_urb(hcd_device_state
*);
33 static int hcd_non_control_urb(hcd_device_state
*, int);
35 /* For internal use by more general methods */
36 static int hcd_setup_packet(hcd_device_state
*, hcd_ctrlrequest
*);
37 static int hcd_data_transfer(hcd_device_state
*, hcd_datarequest
*);
40 /*===========================================================================*
42 *===========================================================================*/
43 /* TODO: Only one device at a time
44 * If ever HUB functionality is added, one must remember that disconnecting
45 * HUB, means disconnecting every device attached to it, so data structure may
46 * have to be altered to allow that */
47 static hcd_device_state hcd_device
[1];
50 /*===========================================================================*
52 *===========================================================================*/
54 hcd_handle_event(hcd_driver_state
* driver
)
56 hcd_device_state
* this_device
;
60 /* TODO: Finding which hcd_device is in use should be performed here */
61 this_device
= &(hcd_device
[0]);
63 /* Sometimes interrupts occur in a weird order (EP after disconnect)
64 * This helps finding ordering errors in DEBUG */
65 USB_DBG("Event: 0x%02X, state: 0x%02X",
66 driver
->current_event
, this_device
->state
);
68 /* Set what was received for device thread to use */
69 this_device
->driver
= driver
;
71 /* Handle event and forward control to device thread when required */
72 switch (driver
->current_event
) {
73 case HCD_EVENT_CONNECTED
:
74 if (HCD_STATE_DISCONNECTED
== this_device
->state
) {
75 if (EXIT_SUCCESS
!= hcd_connect_device(
78 USB_MSG("Device creation failed");
80 USB_MSG("Device not marked as 'disconnected' "
81 "for 'connection' event");
85 case HCD_EVENT_DISCONNECTED
:
86 if (HCD_STATE_DISCONNECTED
!= this_device
->state
) {
87 /* If connect callback was used before, call
88 * it's equivalent to signal disconnection */
89 if (HCD_STATE_CONNECTED
== this_device
->state
)
90 hcd_disconnect_cb(this_device
);
91 hcd_disconnect_device(this_device
);
92 this_device
->state
= HCD_STATE_DISCONNECTED
;
94 USB_MSG("Device is marked as 'disconnected' "
95 "for 'disconnection' event");
99 case HCD_EVENT_ENDPOINT
:
101 /* Allow device thread to continue with it's logic */
102 if (HCD_STATE_DISCONNECTED
!= this_device
->state
)
103 hcd_device_continue(this_device
);
105 USB_MSG("Device is marked as 'disconnected' "
111 USB_ASSERT(0, "Illegal HCD event");
117 /*===========================================================================*
118 * hcd_device_thread *
119 *===========================================================================*/
121 hcd_device_thread(void * thread_args
)
123 hcd_device_state
* this_device
;
127 /* Retrieve structures from generic data */
128 this_device
= (hcd_device_state
*)thread_args
;
131 this_device
->state
= HCD_STATE_CONNECTION_PENDING
;
133 /* Enumeration sequence */
134 if (EXIT_SUCCESS
!= hcd_enumerate(this_device
))
135 hcd_device_finish(this_device
, "USB device enumeration failed");
137 /* Tell everyone that device was connected */
138 hcd_connect_cb(this_device
);
140 /* Fully configured */
141 this_device
->state
= HCD_STATE_CONNECTED
;
143 USB_DBG("Waiting for URBs");
145 /* Start handling URB's */
148 this_device
->urb
= NULL
;
150 /* Block and wait for something like 'submit URB' */
151 hcd_device_wait(this_device
, HCD_EVENT_URB
, HCD_NO_ENDPOINT
);
153 if (EXIT_SUCCESS
!= hcd_handle_urb(this_device
))
154 hcd_device_finish(this_device
, "URB handling failed");
157 /* Finish device handling to avoid leaving thread */
158 hcd_device_finish(this_device
, "USB device handling completed");
162 /*===========================================================================*
163 * hcd_device_finish *
164 *===========================================================================*/
166 hcd_device_finish(hcd_device_state
* this_device
, const char * finish_msg
)
170 USB_MSG("USB device handling finished with message: '%s'", finish_msg
);
174 hcd_device_wait(this_device
, HCD_EVENT_URB
, HCD_NO_ENDPOINT
);
175 USB_MSG("Failed attempt to continue finished thread");
180 /*===========================================================================*
182 *===========================================================================*/
184 hcd_enumerate(hcd_device_state
* this_device
)
186 hcd_driver_state
* d
;
190 d
= this_device
->driver
;
192 /* First let driver reset device */
193 if (EXIT_SUCCESS
!= d
->reset_device(d
->private_data
,
194 &(this_device
->speed
))) {
195 USB_MSG("Failed to reset device");
199 /* Get device descriptor */
200 if (EXIT_SUCCESS
!= hcd_get_device_descriptor(this_device
)) {
201 USB_MSG("Failed to get device descriptor");
205 /* TODO: dynamic device address when more devices are available */
208 if (EXIT_SUCCESS
!= hcd_set_address(this_device
, HCD_ATTACHED_ADDR
)) {
209 USB_MSG("Failed to set device address");
213 /* Set parameters for further communication */
214 d
->setup_device(d
->private_data
, HCD_DEFAULT_EP
, this_device
->address
);
216 /* Get other descriptors */
217 if (EXIT_SUCCESS
!= hcd_get_descriptor_tree(this_device
)) {
218 USB_MSG("Failed to get configuration descriptor tree");
222 /* TODO: always first configuration */
223 /* Set configuration */
224 if (EXIT_SUCCESS
!= hcd_set_configuration(this_device
, 0x01)) {
225 USB_MSG("Failed to set configuration");
229 USB_DBG("Enumeration completed");
235 /*===========================================================================*
236 * hcd_get_device_descriptor *
237 *===========================================================================*/
239 hcd_get_device_descriptor(hcd_device_state
* this_device
)
241 hcd_ctrlrequest setup
;
245 /* TODO: magic numbers, no header for these */
247 /* Format setup packet */
248 setup
.bRequestType
= 0x80; /* IN */
249 setup
.bRequest
= 0x06; /* Get descriptor */
250 setup
.wValue
= 0x0100; /* Device */
251 setup
.wIndex
= 0x0000;
252 setup
.wLength
= sizeof(this_device
->device_desc
);
254 /* Handle formatted setup packet */
255 if (EXIT_SUCCESS
!= hcd_setup_packet(this_device
, &setup
)) {
256 USB_MSG("Handling setup packet failed");
260 /* Put what was read in device descriptor */
261 memcpy(&(this_device
->device_desc
), this_device
->buffer
,
262 sizeof(this_device
->device_desc
));
264 /* Remember max packet size from device descriptor */
265 this_device
->max_packet_size
= this_device
->device_desc
.bMaxPacketSize
;
267 /* Dump device descriptor in debug mode */
270 hcd_device_descriptor
* d
;
271 d
= &(this_device
->device_desc
);
273 USB_DBG("<<DEVICE>>");
274 USB_DBG("bLength %02X", d
->bLength
);
275 USB_DBG("bDescriptorType %02X", d
->bDescriptorType
);
276 USB_DBG("bcdUSB %04X", UGETW(d
->bcdUSB
));
277 USB_DBG("bDeviceClass %02X", d
->bDeviceClass
);
278 USB_DBG("bDeviceSubClass %02X", d
->bDeviceSubClass
);
279 USB_DBG("bDeviceProtocol %02X", d
->bDeviceProtocol
);
280 USB_DBG("bMaxPacketSize %02X", d
->bMaxPacketSize
);
281 USB_DBG("idVendor %04X", UGETW(d
->idVendor
));
282 USB_DBG("idProduct %04X", UGETW(d
->idProduct
));
283 USB_DBG("bcdDevice %04X", UGETW(d
->bcdDevice
));
284 USB_DBG("iManufacturer %02X", d
->iManufacturer
);
285 USB_DBG("iProduct %02X", d
->iProduct
);
286 USB_DBG("iSerialNumber %02X", d
->iSerialNumber
);
287 USB_DBG("bNumConfigurations %02X", d
->bNumConfigurations
);
295 /*===========================================================================*
297 *===========================================================================*/
299 hcd_set_address(hcd_device_state
* this_device
, int address
)
301 hcd_ctrlrequest setup
;
305 USB_ASSERT((address
> 0) && (address
< 128), "Illegal address");
307 /* TODO: magic numbers, no header for these */
308 setup
.bRequestType
= 0x00; /* OUT */
309 setup
.bRequest
= 0x05; /* Set address */
310 setup
.wValue
= address
;
311 setup
.wIndex
= 0x0000;
312 setup
.wLength
= 0x0000;
314 /* Handle formatted setup packet */
315 if (EXIT_SUCCESS
!= hcd_setup_packet(this_device
, &setup
)) {
316 USB_MSG("Handling setup packet failed");
320 /* Sleep 5msec to allow addressing */
321 hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(5));
323 /* Remember what was assigned in hardware */
324 this_device
->address
= address
;
330 /*===========================================================================*
331 * hcd_get_descriptor_tree *
332 *===========================================================================*/
334 hcd_get_descriptor_tree(hcd_device_state
* this_device
)
336 hcd_config_descriptor config_descriptor
;
337 hcd_ctrlrequest setup
;
344 /* First, ask only for configuration itself to get length info */
345 buffer_length
= sizeof(config_descriptor
);
349 /* TODO: configuration 0 is hard-coded
350 * but others are rarely used anyway */
351 /* TODO: magic numbers, no header for these */
352 setup
.bRequestType
= 0x80; /* IN */
353 setup
.bRequest
= 0x06; /* Get descriptor */
354 setup
.wValue
= 0x0200; /* Configuration 0 */
355 setup
.wIndex
= 0x0000;
356 setup
.wLength
= buffer_length
;
358 /* Handle formatted setup packet */
359 if (EXIT_SUCCESS
!= hcd_setup_packet(this_device
, &setup
)) {
360 USB_MSG("Handling setup packet failed");
364 /* If we only asked for configuration itself
365 * then ask again for other descriptors */
366 if (sizeof(config_descriptor
) == buffer_length
) {
368 /* Put what was read in configuration descriptor */
369 memcpy(&config_descriptor
, this_device
->buffer
,
370 sizeof(config_descriptor
));
372 /* Continue only if there is more data */
373 total_length
= config_descriptor
.wTotalLength
[0] +
374 (config_descriptor
.wTotalLength
[1] << 8);
376 if (total_length
< (int)sizeof(config_descriptor
)) {
377 /* This should never happen for a fine device */
378 USB_MSG("Illegal wTotalLength value");
381 else if (sizeof(config_descriptor
) == total_length
) {
382 /* Nothing more was in descriptor anyway */
386 /* Read whatever is needed */
387 buffer_length
= total_length
;
391 /* All data for given configuration was read */
397 /* Create tree based on received buffer */
398 if (EXIT_SUCCESS
!= hcd_buffer_to_tree(this_device
->buffer
,
399 this_device
->data_len
,
400 &(this_device
->config_tree
))) {
401 /* This should never happen for a fine device */
402 USB_MSG("Illegal descriptor values");
410 /*===========================================================================*
411 * hcd_set_configuration *
412 *===========================================================================*/
414 hcd_set_configuration(hcd_device_state
* this_device
, int configuration
)
416 hcd_ctrlrequest setup
;
420 /* TODO: magic numbers, no header for these */
421 setup
.bRequestType
= 0x00; /* OUT */
422 setup
.bRequest
= 0x09; /* Set configuration */
423 setup
.wValue
= configuration
;
424 setup
.wIndex
= 0x0000;
425 setup
.wLength
= 0x0000;
427 /* Handle formatted setup packet */
428 if (EXIT_SUCCESS
!= hcd_setup_packet(this_device
, &setup
)) {
429 USB_MSG("Handling setup packet failed");
437 /*===========================================================================*
439 *===========================================================================*/
441 hcd_handle_urb(hcd_device_state
* this_device
)
448 transfer_status
= EXIT_FAILURE
;
449 urb
= this_device
->urb
;
451 USB_ASSERT(NULL
!= urb
, "NULL URB given");
452 /* TODO: One device only */
453 USB_ASSERT((void *)this_device
!= (void *)urb
->dev
,
454 "Unknown device for URB");
458 case USB_TRANSFER_CTL
:
459 transfer_status
= hcd_control_urb(this_device
);
462 case USB_TRANSFER_BLK
:
463 case USB_TRANSFER_INT
:
464 transfer_status
= hcd_non_control_urb(this_device
,
468 case USB_TRANSFER_ISO
:
469 /* TODO: ISO transfer */
470 USB_MSG("ISO transfer not supported");
474 USB_MSG("Invalid transfer type 0x%X", urb
->type
);
478 if (EXIT_SUCCESS
!= transfer_status
)
479 USB_MSG("USB transfer failed");
481 /* Call completion regardless of status */
482 hcd_completion_cb(urb
->priv
);
484 /* TODO: Only critical failures should ever yield EXIT_FAILURE, so
485 * return is not bound to transfer_status for now, to let device
486 * driver act accordingly */
491 /*===========================================================================*
493 *===========================================================================*/
495 hcd_control_urb(hcd_device_state
* this_device
)
498 hcd_ctrlrequest setup
;
502 urb
= this_device
->urb
;
504 /* Assume bad values unless something different occurs later */
505 urb
->status
= EINVAL
;
507 /* Must have setup packet */
508 if (NULL
== urb
->setup_packet
) {
509 USB_MSG("No setup packet in URB, for control transfer");
513 /* TODO: Only EP0 can have control transfer */
514 if (0 != urb
->endpoint
) {
515 USB_MSG("Control transfer for non zero EP");
519 /* Hold setup packet and analyze it */
520 memcpy(&setup
, urb
->setup_packet
, sizeof(setup
));
522 /* TODO: broken constants for urb->direction (USB_OUT...) */
523 if (((setup
.bRequestType
>> 7) & 0x01) != urb
->direction
) {
524 USB_MSG("URB Direction mismatch");
528 /* Send setup packet */
529 if (EXIT_SUCCESS
!= hcd_setup_packet(this_device
, &setup
)) {
530 USB_MSG("Sending URB setup packet, failed");
535 urb
->status
= EXIT_SUCCESS
;
540 /*===========================================================================*
541 * hcd_non_control_urb *
542 *===========================================================================*/
544 hcd_non_control_urb(hcd_device_state
* this_device
, int type
)
547 hcd_datarequest request
;
552 urb
= this_device
->urb
;
554 /* Assume bad values unless something different occurs later */
555 urb
->status
= EINVAL
;
557 if (NULL
== urb
->data
) {
558 USB_MSG("No data packet in URB");
562 if ((UE_GET_ADDR(urb
->endpoint
) >= 16) ||
563 (UE_GET_ADDR(urb
->endpoint
) <= 0)) {
564 USB_MSG("Illegal EP number");
568 /* TODO: broken USB_IN... constants */
569 if ((1 != urb
->direction
) && (0 != urb
->direction
)) {
570 USB_MSG("Illegal EP direction");
574 /* TODO: usb.h constants to type mapping */
576 case USB_TRANSFER_BLK
:
577 request
.type
= HCD_TRANSFER_BULK
;
579 case USB_TRANSFER_INT
:
580 request
.type
= HCD_TRANSFER_INTERRUPT
;
583 /* TODO: ISO transfer */
584 USB_MSG("Invalid transfer type");
588 /* TODO: Any additional checks? (sane size?) */
590 /* Assign to data request structure */
591 request
.endpoint
= urb
->endpoint
;
592 request
.direction
= urb
->direction
;
593 request
.size
= (int)urb
->size
;
594 request
.data
= urb
->data
;
595 request
.interval
= urb
->interval
;
597 /* Check if EP number is valid */
598 e
= hcd_tree_find_ep(&(this_device
->config_tree
), request
.endpoint
);
601 USB_MSG("Invalid EP value");
605 /* TODO: broken constants for urb->direction (USB_OUT...) */
606 /* Check if remembered direction matches */
607 if (((e
->descriptor
.bEndpointAddress
>> 7) & 0x01) != urb
->direction
) {
608 USB_MSG("EP direction mismatch");
612 /* Check if remembered type matches */
613 if (UE_GET_XFERTYPE(e
->descriptor
.bmAttributes
) != (int)request
.type
) {
614 USB_MSG("EP type mismatch");
618 /* Assign to let know how much data can be transfered at a time */
619 request
.max_packet_size
= UGETW(e
->descriptor
.wMaxPacketSize
);
621 /* Let know how to configure EP for speed */
622 request
.speed
= this_device
->speed
;
624 /* Start sending data */
625 if (EXIT_SUCCESS
!= hcd_data_transfer(this_device
, &request
)) {
626 USB_MSG("URB non-control transfer, failed");
631 /* Transfer successfully completed */
632 urb
->status
= EXIT_SUCCESS
;
637 /*===========================================================================*
639 *===========================================================================*/
641 hcd_setup_packet(hcd_device_state
* this_device
, hcd_ctrlrequest
* setup
)
643 hcd_driver_state
* d
;
644 hcd_reg1
* current_byte
;
651 d
= this_device
->driver
;
652 expected_len
= (int)setup
->wLength
;
653 current_byte
= this_device
->buffer
;
655 /* Send setup packet */
656 d
->setup_stage(d
->private_data
, setup
);
658 /* Wait for response */
659 hcd_device_wait(this_device
, HCD_EVENT_ENDPOINT
, HCD_ENDPOINT_0
);
662 if (EXIT_SUCCESS
!= d
->check_error(d
->private_data
,
663 HCD_TRANSFER_CONTROL
,
664 HCD_DIRECTION_UNUSED
))
667 /* For data packets... */
668 if (expected_len
> 0) {
670 /* TODO: magic number */
671 /* ...IN data packets */
672 if (setup
->bRequestType
& 0x80) {
674 /* What was received until now */
675 this_device
->data_len
= 0;
678 /* Try getting data */
679 d
->in_data_stage(d
->private_data
);
681 /* Wait for response */
682 hcd_device_wait(this_device
,
687 if (EXIT_SUCCESS
!= d
->check_error(
689 HCD_TRANSFER_CONTROL
,
690 HCD_DIRECTION_UNUSED
))
693 /* Read data received as response */
694 received_len
= d
->read_data(d
->private_data
,
697 /* Data reading should always yield positive
698 * results for proper setup packet */
699 if (received_len
> 0) {
700 /* Try next packet */
701 this_device
->data_len
+= received_len
;
702 current_byte
+= received_len
;
706 } while (expected_len
> this_device
->data_len
);
708 /* Should be exactly what we requested, no more */
709 if (this_device
->data_len
!= expected_len
) {
710 USB_MSG("Received more data than expected");
715 /* TODO: unimplemented */
716 USB_MSG("Illegal non-zero length OUT setup packet");
722 if (setup
->bRequestType
& 0x80) {
724 /* Try confirming data receive */
725 d
->out_status_stage(d
->private_data
);
727 /* Wait for response */
728 hcd_device_wait(this_device
, HCD_EVENT_ENDPOINT
,
732 if (EXIT_SUCCESS
!= d
->check_error(d
->private_data
,
733 HCD_TRANSFER_CONTROL
,
734 HCD_DIRECTION_UNUSED
))
739 /* Try getting status confirmation */
740 d
->in_status_stage(d
->private_data
);
742 /* Wait for response */
743 hcd_device_wait(this_device
, HCD_EVENT_ENDPOINT
,
747 if (EXIT_SUCCESS
!= d
->check_error(d
->private_data
,
748 HCD_TRANSFER_CONTROL
,
749 HCD_DIRECTION_UNUSED
))
752 /* Read zero data from response to clear registers */
753 if (0 != d
->read_data(d
->private_data
, NULL
, 0))
761 /*===========================================================================*
762 * hcd_data_transfer *
763 *===========================================================================*/
765 hcd_data_transfer(hcd_device_state
* this_device
, hcd_datarequest
* request
)
767 hcd_driver_state
* d
;
768 hcd_datarequest temp_req
;
774 d
= this_device
->driver
;
776 /* Set parameters for further communication */
777 d
->setup_device(d
->private_data
,
779 this_device
->address
);
781 /* TODO: broken USB_IN... constants */
782 if (1 == request
->direction
) {
785 /* Start actual data transfer */
786 d
->rx_stage(d
->private_data
, request
);
788 /* Wait for response */
789 hcd_device_wait(this_device
, HCD_EVENT_ENDPOINT
,
793 if (EXIT_SUCCESS
!= d
->check_error(d
->private_data
,
798 /* Read data received as response */
799 transfer_len
= d
->read_data(d
->private_data
,
800 (hcd_reg1
*)request
->data
,
803 request
->size
-= transfer_len
;
804 request
->data
+= transfer_len
;
806 /* Total length shall not become negative */
807 if (request
->size
< 0) {
808 USB_MSG("Invalid amount of data received");
813 /* TODO: REMOVEME (dumping of data transfer) */
816 USB_MSG("RECEIVED: %d", transfer_len
);
817 for (i
= 0; i
< transfer_len
; i
++)
818 USB_MSG("0x%02X: %c",
819 (request
->data
-transfer_len
)[i
],
820 (request
->data
-transfer_len
)[i
]);
824 } while (0 != request
->size
);
826 } else if (0 == request
->direction
) {
831 /* Decide transfer size */
832 if (temp_req
.size
> (int)temp_req
.max_packet_size
) {
833 temp_req
.size
= temp_req
.max_packet_size
;
836 request
->data
+= temp_req
.size
;
837 request
->size
-= temp_req
.size
;
839 /* Total length shall not become negative */
840 USB_ASSERT(request
->size
>= 0,
841 "Invalid amount of transfer data calculated");
843 /* Start actual data transfer */
844 d
->tx_stage(d
->private_data
, &temp_req
);
846 /* Wait for response */
847 hcd_device_wait(this_device
, HCD_EVENT_ENDPOINT
,
851 if (EXIT_SUCCESS
!= d
->check_error(d
->private_data
,
856 } while (0 != request
->size
);
859 USB_ASSERT(0, "Invalid transfer direction");