summaryrefslogtreecommitdiffstats
path: root/src/drivers/usb/ehci.c
diff options
context:
space:
mode:
authorMichael Brown2015-03-23 14:34:16 +0100
committerMichael Brown2015-03-23 17:23:08 +0100
commitb418af26d961dd465ce0667575ffc6d82a1a8987 (patch)
tree2a1bb351244ede637bbc74e1a64f255ae09f76a6 /src/drivers/usb/ehci.c
parent[usb] Clear transaction translator buffers when applicable (diff)
downloadipxe-b418af26d961dd465ce0667575ffc6d82a1a8987.tar.gz
ipxe-b418af26d961dd465ce0667575ffc6d82a1a8987.tar.xz
ipxe-b418af26d961dd465ce0667575ffc6d82a1a8987.zip
[ehci] Support USB1 devices attached via transaction translators
Support low-speed and full-speed devices attached to a USB2 hub. Such devices use a transaction translator (TT) within the USB2 hub, which asynchronously initiates transactions on the lower-speed bus and returns the result via a split completion on the high-speed bus. We make the simplifying assumption that there will never be more than sixteen active interrupt endpoints behind a single transaction translator; this assumption allows us to schedule all periodic start splits in microframe 0 and all periodic split completions in microframes 2 and 3. (We do not handle isochronous endpoints.) Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/usb/ehci.c')
-rw-r--r--src/drivers/usb/ehci.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/src/drivers/usb/ehci.c b/src/drivers/usb/ehci.c
index 83635f45..f912de35 100644
--- a/src/drivers/usb/ehci.c
+++ b/src/drivers/usb/ehci.c
@@ -545,7 +545,7 @@ static int ehci_enqueue ( struct ehci_device *ehci, struct ehci_ring *ring,
assert ( xfer->len <= EHCI_LEN_MASK );
assert ( EHCI_FL_TOGGLE == EHCI_LEN_TOGGLE );
desc->len = cpu_to_le16 ( xfer->len | toggle );
- desc->flags = xfer->flags;
+ desc->flags = ( xfer->flags | EHCI_FL_CERR_MAX );
/* Copy data to immediate data buffer (if requested) */
data = xfer->data;
@@ -902,19 +902,16 @@ static uint32_t ehci_endpoint_characteristics ( struct usb_endpoint *ep ) {
chr |= EHCI_CHR_TOGGLE;
/* Determine endpoint speed */
- switch ( usb->port->speed ) {
- case USB_SPEED_HIGH :
+ if ( usb->port->speed == USB_SPEED_HIGH ) {
chr |= EHCI_CHR_EPS_HIGH;
- break;
- case USB_SPEED_FULL :
- chr |= EHCI_CHR_EPS_FULL;
- break;
- default:
- assert ( usb->port->speed == USB_SPEED_LOW );
- chr |= EHCI_CHR_EPS_LOW;
+ } else {
+ if ( usb->port->speed == USB_SPEED_FULL ) {
+ chr |= EHCI_CHR_EPS_FULL;
+ } else {
+ chr |= EHCI_CHR_EPS_LOW;
+ }
if ( attr == USB_ENDPOINT_ATTR_CONTROL )
chr |= EHCI_CHR_CONTROL;
- break;
}
return chr;
@@ -927,6 +924,8 @@ static uint32_t ehci_endpoint_characteristics ( struct usb_endpoint *ep ) {
* @ret cap Endpoint capabilities
*/
static uint32_t ehci_endpoint_capabilities ( struct usb_endpoint *ep ) {
+ struct usb_device *usb = ep->usb;
+ struct usb_port *tt = usb_transaction_translator ( usb );
unsigned int attr = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
uint32_t cap;
unsigned int i;
@@ -943,6 +942,15 @@ static uint32_t ehci_endpoint_capabilities ( struct usb_endpoint *ep ) {
}
}
+ /* Set transaction translator hub address and port, if applicable */
+ if ( tt ) {
+ assert ( tt->hub->usb );
+ cap |= ( EHCI_CAP_TT_HUB ( tt->hub->usb->address ) |
+ EHCI_CAP_TT_PORT ( tt->address ) );
+ if ( attr == USB_ENDPOINT_ATTR_INTERRUPT )
+ cap |= EHCI_CAP_SPLIT_SCHED_DEFAULT;
+ }
+
return cap;
}