From 17aceb34da3bad166cab8579a3616806fff8e05b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 9 Feb 2015 23:50:35 +0000 Subject: [PATCH] [usb] Parse endpoint descriptor bInterval field Signed-off-by: Michael Brown --- src/drivers/bus/usb.c | 27 +++++++++++++++++++++++---- src/drivers/usb/xhci.c | 10 ++++++++++ src/drivers/usb/xhci.h | 5 +++++ src/include/ipxe/usb.h | 9 ++++++++- 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c index 97c2e3fcf..5a338a5e0 100644 --- a/src/drivers/bus/usb.c +++ b/src/drivers/bus/usb.c @@ -227,10 +227,13 @@ int usb_endpoint_described ( struct usb_endpoint *ep, struct usb_configuration_descriptor *config, struct usb_interface_descriptor *interface, unsigned int type, unsigned int index ) { + struct usb_device *usb = ep->usb; + struct usb_port *port = usb->port; struct usb_endpoint_descriptor *desc; struct usb_endpoint_companion_descriptor *descx; unsigned int sizes; unsigned int burst; + unsigned int interval; size_t mtu; /* Locate endpoint descriptor */ @@ -246,9 +249,23 @@ int usb_endpoint_described ( struct usb_endpoint *ep, mtu = USB_ENDPOINT_MTU ( sizes ); burst = ( descx ? descx->burst : USB_ENDPOINT_BURST ( sizes ) ); + /* Calculate interval */ + if ( type == USB_INTERRUPT ) { + if ( port->speed >= USB_SPEED_HIGH ) { + /* 2^(desc->interval-1) is a microframe count */ + interval = ( 1 << ( desc->interval - 1 ) ); + } else { + /* desc->interval is a (whole) frame count */ + interval = ( desc->interval << 3 ); + } + } else { + /* desc->interval is a microframe count */ + interval = desc->interval; + } + /* Describe endpoint */ usb_endpoint_describe ( ep, desc->endpoint, desc->attributes, - mtu, burst ); + mtu, burst, interval ); return 0; } @@ -286,8 +303,9 @@ int usb_endpoint_open ( struct usb_endpoint *ep ) { } ep->open = 1; - DBGC2 ( usb, "USB %s %s opened with MTU %zd (burst %d)\n", usb->name, - usb_endpoint_name ( ep->address ), ep->mtu, ep->burst ); + DBGC2 ( usb, "USB %s %s opened with MTU %zd, burst %d, interval %d\n", + usb->name, usb_endpoint_name ( ep->address ), ep->mtu, + ep->burst, ep->interval ); return 0; ep->open = 0; @@ -1147,7 +1165,8 @@ static int register_usb ( struct usb_device *usb ) { /* Describe control endpoint */ mtu = USB_EP0_DEFAULT_MTU ( port->speed ); usb_endpoint_describe ( &usb->control, USB_EP0_ADDRESS, - USB_EP0_ATTRIBUTES, mtu, USB_EP0_BURST ); + USB_EP0_ATTRIBUTES, mtu, USB_EP0_BURST, + USB_EP0_INTERVAL ); /* Open control endpoint */ if ( ( rc = usb_endpoint_open ( &usb->control ) ) != 0 ) diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index cdebc47da..49901275d 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -1986,6 +1986,7 @@ static void xhci_configure_endpoint_input ( struct xhci_device *xhci, /* Populate endpoint context */ ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) ); + ep_ctx->interval = endpoint->interval; ep_ctx->type = endpoint->type; ep_ctx->burst = endpoint->ep->burst; ep_ctx->mtu = cpu_to_le16 ( endpoint->ep->mtu ); @@ -2252,6 +2253,7 @@ static int xhci_endpoint_open ( struct usb_endpoint *ep ) { struct xhci_endpoint *endpoint; unsigned int ctx; unsigned int type; + unsigned int interval; int rc; /* Calculate context index */ @@ -2265,6 +2267,13 @@ static int xhci_endpoint_open ( struct usb_endpoint *ep ) { if ( ep->address & USB_DIR_IN ) type |= XHCI_EP_TYPE_IN; + /* Calculate interval */ + if ( type & XHCI_EP_TYPE_PERIODIC ) { + interval = ( fls ( ep->interval ) - 1 ); + } else { + interval = ep->interval; + } + /* Allocate and initialise structure */ endpoint = zalloc ( sizeof ( *endpoint ) ); if ( ! endpoint ) { @@ -2278,6 +2287,7 @@ static int xhci_endpoint_open ( struct usb_endpoint *ep ) { endpoint->ep = ep; endpoint->ctx = ctx; endpoint->type = type; + endpoint->interval = interval; endpoint->context = ( ( ( void * ) slot->context ) + xhci_device_context_offset ( xhci, ctx ) ); diff --git a/src/drivers/usb/xhci.h b/src/drivers/usb/xhci.h index 7f768aa0a..186ff27d0 100644 --- a/src/drivers/usb/xhci.h +++ b/src/drivers/usb/xhci.h @@ -806,6 +806,9 @@ enum xhci_endpoint_state { /** Input endpoint type */ #define XHCI_EP_TYPE_IN XHCI_EP_TYPE ( 4 ) +/** Periodic endpoint type */ +#define XHCI_EP_TYPE_PERIODIC XHCI_EP_TYPE ( 1 ) + /** Endpoint dequeue cycle state */ #define XHCI_EP_DCS 0x00000001UL @@ -1078,6 +1081,8 @@ struct xhci_endpoint { unsigned int ctx; /** Endpoint type */ unsigned int type; + /** Endpoint interval */ + unsigned int interval; /** Endpoint context */ struct xhci_endpoint_context *context; /** Transfer ring */ diff --git a/src/include/ipxe/usb.h b/src/include/ipxe/usb.h index acc8391f7..e21ca1c43 100644 --- a/src/include/ipxe/usb.h +++ b/src/include/ipxe/usb.h @@ -372,6 +372,8 @@ struct usb_endpoint { size_t mtu; /** Maximum burst size */ unsigned int burst; + /** Interval (in microframes) */ + unsigned int interval; /** Endpoint is open */ int open; @@ -462,6 +464,9 @@ struct usb_endpoint_driver_operations { /** Control endpoint maximum burst size */ #define USB_EP0_BURST 0 +/** Control endpoint interval */ +#define USB_EP0_INTERVAL 0 + /** Maximum endpoint number */ #define USB_ENDPOINT_MAX 0x0f @@ -496,16 +501,18 @@ usb_endpoint_init ( struct usb_endpoint *ep, struct usb_device *usb, * @v attributes Attributes * @v mtu Maximum packet size * @v burst Maximum burst size + * @v interval Interval (in microframes) */ static inline __attribute__ (( always_inline )) void usb_endpoint_describe ( struct usb_endpoint *ep, unsigned int address, unsigned int attributes, size_t mtu, - unsigned int burst ) { + unsigned int burst, unsigned int interval ) { ep->address = address; ep->attributes = attributes; ep->mtu = mtu; ep->burst = burst; + ep->interval = interval; } /**