aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2011-10-06 14:54:23 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-10-18 16:42:06 -0400
commit48e8236114c12c5366e032fc517e1bd376369a56 (patch)
tree40e410e90671bbbb7f25f5563d6cbe000797c263 /drivers/usb
parentfa3ae0c158c70e6cf227b3a194659ee7fed8c588 (diff)
xHCI/USB: Make xHCI driver have a BOS descriptor.
To add USB 3.0 link power management (LPM), we need to know what the U1 and U2 exit latencies are for the xHCI host controller. External USB 3.0 hubs report these values through the SuperSpeed Capabilities descriptor in the BOS descriptor. Make the USB 3.0 roothub for the xHCI host behave like an external hub and return the BOS descriptors. The U1 and U2 exit latencies will vary across each host controller, so we need to dynamically fill those values in by reading the exit latencies out of the xHC registers. Make the roothub code in the USB core handle hub_control() returning the length of the data copied. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/hcd.c18
-rw-r--r--drivers/usb/host/xhci-hub.c34
2 files changed, 50 insertions, 2 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 100d4b002642..b3b7d062906d 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -442,7 +442,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
442 struct usb_ctrlrequest *cmd; 442 struct usb_ctrlrequest *cmd;
443 u16 typeReq, wValue, wIndex, wLength; 443 u16 typeReq, wValue, wIndex, wLength;
444 u8 *ubuf = urb->transfer_buffer; 444 u8 *ubuf = urb->transfer_buffer;
445 u8 tbuf [sizeof (struct usb_hub_descriptor)] 445 /*
446 * tbuf should be as big as the BOS descriptor and
447 * the USB hub descriptor.
448 */
449 u8 tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE]
446 __attribute__((aligned(4))); 450 __attribute__((aligned(4)));
447 const u8 *bufp = tbuf; 451 const u8 *bufp = tbuf;
448 unsigned len = 0; 452 unsigned len = 0;
@@ -562,6 +566,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
562 else /* unsupported IDs --> "protocol stall" */ 566 else /* unsupported IDs --> "protocol stall" */
563 goto error; 567 goto error;
564 break; 568 break;
569 case USB_DT_BOS << 8:
570 goto nongeneric;
565 default: 571 default:
566 goto error; 572 goto error;
567 } 573 }
@@ -596,6 +602,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
596 /* CLASS REQUESTS (and errors) */ 602 /* CLASS REQUESTS (and errors) */
597 603
598 default: 604 default:
605nongeneric:
599 /* non-generic request */ 606 /* non-generic request */
600 switch (typeReq) { 607 switch (typeReq) {
601 case GetHubStatus: 608 case GetHubStatus:
@@ -605,6 +612,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
605 case GetHubDescriptor: 612 case GetHubDescriptor:
606 len = sizeof (struct usb_hub_descriptor); 613 len = sizeof (struct usb_hub_descriptor);
607 break; 614 break;
615 case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
616 /* len is returned by hub_control */
617 break;
608 } 618 }
609 status = hcd->driver->hub_control (hcd, 619 status = hcd->driver->hub_control (hcd,
610 typeReq, wValue, wIndex, 620 typeReq, wValue, wIndex,
@@ -615,7 +625,7 @@ error:
615 status = -EPIPE; 625 status = -EPIPE;
616 } 626 }
617 627
618 if (status) { 628 if (status < 0) {
619 len = 0; 629 len = 0;
620 if (status != -EPIPE) { 630 if (status != -EPIPE) {
621 dev_dbg (hcd->self.controller, 631 dev_dbg (hcd->self.controller,
@@ -624,6 +634,10 @@ error:
624 typeReq, wValue, wIndex, 634 typeReq, wValue, wIndex,
625 wLength, status); 635 wLength, status);
626 } 636 }
637 } else if (status > 0) {
638 /* hub_control may return the length of data copied. */
639 len = status;
640 status = 0;
627 } 641 }
628 if (len) { 642 if (len) {
629 if (urb->transfer_buffer_length < len) 643 if (urb->transfer_buffer_length < len)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 9f844d45c667..2f74eddbe3c1 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -28,6 +28,25 @@
28#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \ 28#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
29 PORT_RC | PORT_PLC | PORT_PE) 29 PORT_RC | PORT_PLC | PORT_PE)
30 30
31/* usb 1.1 root hub device descriptor */
32static u8 usb_bos_descriptor [] = {
33 USB_DT_BOS_SIZE, /* __u8 bLength, 5 bytes */
34 USB_DT_BOS, /* __u8 bDescriptorType */
35 0x0F, 0x00, /* __le16 wTotalLength, 15 bytes */
36 0x1, /* __u8 bNumDeviceCaps */
37 /* First device capability */
38 USB_DT_USB_SS_CAP_SIZE, /* __u8 bLength, 10 bytes */
39 USB_DT_DEVICE_CAPABILITY, /* Device Capability */
40 USB_SS_CAP_TYPE, /* bDevCapabilityType, SUPERSPEED_USB */
41 0x00, /* bmAttributes, LTM off by default */
42 USB_5GBPS_OPERATION, 0x00, /* wSpeedsSupported, 5Gbps only */
43 0x03, /* bFunctionalitySupport,
44 USB 3.0 speed only */
45 0x00, /* bU1DevExitLat, set later. */
46 0x00, 0x00 /* __le16 bU2DevExitLat, set later. */
47};
48
49
31static void xhci_common_hub_descriptor(struct xhci_hcd *xhci, 50static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
32 struct usb_hub_descriptor *desc, int ports) 51 struct usb_hub_descriptor *desc, int ports)
33{ 52{
@@ -455,6 +474,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
455 xhci_hub_descriptor(hcd, xhci, 474 xhci_hub_descriptor(hcd, xhci,
456 (struct usb_hub_descriptor *) buf); 475 (struct usb_hub_descriptor *) buf);
457 break; 476 break;
477 case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
478 if ((wValue & 0xff00) != (USB_DT_BOS << 8))
479 goto error;
480
481 if (hcd->speed != HCD_USB3)
482 goto error;
483
484 memcpy(buf, &usb_bos_descriptor,
485 USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE);
486 temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
487 buf[12] = HCS_U1_LATENCY(temp);
488 put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);
489
490 spin_unlock_irqrestore(&xhci->lock, flags);
491 return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE;
458 case GetPortStatus: 492 case GetPortStatus:
459 if (!wIndex || wIndex > max_ports) 493 if (!wIndex || wIndex > max_ports)
460 goto error; 494 goto error;