aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2010-11-29 19:14:37 -0500
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2011-03-13 21:23:41 -0400
commit4bbb0ace9a3de8392527e3c87926309d541d3b00 (patch)
tree0b71bcd26cd66b4924c2e8997139a965e9b4304f /drivers/usb
parentf6ff0ac878eb420011fa2448851dd48c3a7e7b31 (diff)
xhci: Return a USB 3.0 hub descriptor for USB3 roothub.
Return the correct xHCI roothub descriptor, based on whether the roothub is marked as USB 3.0 or USB 2.0 in usb_hcd->bcdUSB. Fill in DeviceRemovable for the USB 2.0 and USB 3.0 roothub descriptors, using the Device Removable bit in the port status and control registers. xHCI is the first host controller to actually properly set these bits (other hosts say all devices are removable). When userspace asks for a USB 2.0-style hub descriptor for the USB 3.0 roothub, stall the endpoint. This is what real external USB 3.0 hubs do, and we don't want to return a descriptor that userspace didn't ask for. The USB core is already fixed to always ask for USB 3.0-style hub descriptors. Only usbfs (typically lsusb) will ask for the USB 2.0-style hub descriptors. This has already been fixed in usbutils version 0.91, but the kernel needs to deal with older usbutils versions. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/xhci-hub.c134
1 files changed, 114 insertions, 20 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index ee4af076a8fe..191ebc54cc7d 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -28,33 +28,15 @@
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
31static void xhci_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, 31static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
32 struct usb_hub_descriptor *desc) 32 struct usb_hub_descriptor *desc, int ports)
33{ 33{
34 int ports;
35 u16 temp; 34 u16 temp;
36 35
37 if (hcd->speed == HCD_USB3)
38 ports = xhci->num_usb3_ports;
39 else
40 ports = xhci->num_usb2_ports;
41
42 /* FIXME: return a USB 3.0 hub descriptor if this request was for the
43 * USB3 roothub.
44 */
45
46 /* USB 3.0 hubs have a different descriptor, but we fake this for now */
47 desc->bDescriptorType = 0x29;
48 desc->bPwrOn2PwrGood = 10; /* xhci section 5.4.9 says 20ms max */ 36 desc->bPwrOn2PwrGood = 10; /* xhci section 5.4.9 says 20ms max */
49 desc->bHubContrCurrent = 0; 37 desc->bHubContrCurrent = 0;
50 38
51 desc->bNbrPorts = ports; 39 desc->bNbrPorts = ports;
52 temp = 1 + (ports / 8);
53 desc->bDescLength = 7 + 2 * temp;
54
55 memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
56 memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
57
58 /* Ugh, these should be #defines, FIXME */ 40 /* Ugh, these should be #defines, FIXME */
59 /* Using table 11-13 in USB 2.0 spec. */ 41 /* Using table 11-13 in USB 2.0 spec. */
60 temp = 0; 42 temp = 0;
@@ -71,6 +53,102 @@ static void xhci_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
71 desc->wHubCharacteristics = (__force __u16) cpu_to_le16(temp); 53 desc->wHubCharacteristics = (__force __u16) cpu_to_le16(temp);
72} 54}
73 55
56/* Fill in the USB 2.0 roothub descriptor */
57static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
58 struct usb_hub_descriptor *desc)
59{
60 int ports;
61 u16 temp;
62 __u8 port_removable[(USB_MAXCHILDREN + 1 + 7) / 8];
63 u32 portsc;
64 unsigned int i;
65
66 ports = xhci->num_usb2_ports;
67
68 xhci_common_hub_descriptor(xhci, desc, ports);
69 desc->bDescriptorType = 0x29;
70 temp = 1 + (ports / 8);
71 desc->bDescLength = 7 + 2 * temp;
72
73 /* The Device Removable bits are reported on a byte granularity.
74 * If the port doesn't exist within that byte, the bit is set to 0.
75 */
76 memset(port_removable, 0, sizeof(port_removable));
77 for (i = 0; i < ports; i++) {
78 portsc = xhci_readl(xhci, xhci->usb3_ports[i]);
79 /* If a device is removable, PORTSC reports a 0, same as in the
80 * hub descriptor DeviceRemovable bits.
81 */
82 if (portsc & PORT_DEV_REMOVE)
83 /* This math is hairy because bit 0 of DeviceRemovable
84 * is reserved, and bit 1 is for port 1, etc.
85 */
86 port_removable[(i + 1) / 8] |= 1 << ((i + 1) % 8);
87 }
88
89 /* ch11.h defines a hub descriptor that has room for USB_MAXCHILDREN
90 * ports on it. The USB 2.0 specification says that there are two
91 * variable length fields at the end of the hub descriptor:
92 * DeviceRemovable and PortPwrCtrlMask. But since we can have less than
93 * USB_MAXCHILDREN ports, we may need to use the DeviceRemovable array
94 * to set PortPwrCtrlMask bits. PortPwrCtrlMask must always be set to
95 * 0xFF, so we initialize the both arrays (DeviceRemovable and
96 * PortPwrCtrlMask) to 0xFF. Then we set the DeviceRemovable for each
97 * set of ports that actually exist.
98 */
99 memset(desc->u.hs.DeviceRemovable, 0xff,
100 sizeof(desc->u.hs.DeviceRemovable));
101 memset(desc->u.hs.PortPwrCtrlMask, 0xff,
102 sizeof(desc->u.hs.PortPwrCtrlMask));
103
104 for (i = 0; i < (ports + 1 + 7) / 8; i++)
105 memset(&desc->u.hs.DeviceRemovable[i], port_removable[i],
106 sizeof(__u8));
107}
108
109/* Fill in the USB 3.0 roothub descriptor */
110static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
111 struct usb_hub_descriptor *desc)
112{
113 int ports;
114 u16 port_removable;
115 u32 portsc;
116 unsigned int i;
117
118 ports = xhci->num_usb3_ports;
119 xhci_common_hub_descriptor(xhci, desc, ports);
120 desc->bDescriptorType = 0x2a;
121 desc->bDescLength = 12;
122
123 /* header decode latency should be zero for roothubs,
124 * see section 4.23.5.2.
125 */
126 desc->u.ss.bHubHdrDecLat = 0;
127 desc->u.ss.wHubDelay = 0;
128
129 port_removable = 0;
130 /* bit 0 is reserved, bit 1 is for port 1, etc. */
131 for (i = 0; i < ports; i++) {
132 portsc = xhci_readl(xhci, xhci->usb3_ports[i]);
133 if (portsc & PORT_DEV_REMOVE)
134 port_removable |= 1 << (i + 1);
135 }
136 memset(&desc->u.ss.DeviceRemovable,
137 (__force __u16) cpu_to_le16(port_removable),
138 sizeof(__u16));
139}
140
141static void xhci_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
142 struct usb_hub_descriptor *desc)
143{
144
145 if (hcd->speed == HCD_USB3)
146 xhci_usb3_hub_descriptor(hcd, xhci, desc);
147 else
148 xhci_usb2_hub_descriptor(hcd, xhci, desc);
149
150}
151
74static unsigned int xhci_port_speed(unsigned int port_status) 152static unsigned int xhci_port_speed(unsigned int port_status)
75{ 153{
76 if (DEV_LOWSPEED(port_status)) 154 if (DEV_LOWSPEED(port_status))
@@ -320,6 +398,17 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
320 memset(buf, 0, 4); 398 memset(buf, 0, 4);
321 break; 399 break;
322 case GetHubDescriptor: 400 case GetHubDescriptor:
401 /* Check to make sure userspace is asking for the USB 3.0 hub
402 * descriptor for the USB 3.0 roothub. If not, we stall the
403 * endpoint, like external hubs do.
404 */
405 if (hcd->speed == HCD_USB3 &&
406 (wLength < USB_DT_SS_HUB_SIZE ||
407 wValue != (USB_DT_SS_HUB << 8))) {
408 xhci_dbg(xhci, "Wrong hub descriptor type for "
409 "USB 3.0 roothub.\n");
410 goto error;
411 }
323 xhci_hub_descriptor(hcd, xhci, 412 xhci_hub_descriptor(hcd, xhci,
324 (struct usb_hub_descriptor *) buf); 413 (struct usb_hub_descriptor *) buf);
325 break; 414 break;
@@ -331,6 +420,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
331 temp = xhci_readl(xhci, port_array[wIndex]); 420 temp = xhci_readl(xhci, port_array[wIndex]);
332 xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); 421 xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp);
333 422
423 /* FIXME - should we return a port status value like the USB
424 * 3.0 external hubs do?
425 */
334 /* wPortChange bits */ 426 /* wPortChange bits */
335 if (temp & PORT_CSC) 427 if (temp & PORT_CSC)
336 status |= USB_PORT_STAT_C_CONNECTION << 16; 428 status |= USB_PORT_STAT_C_CONNECTION << 16;
@@ -401,6 +493,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
401 wIndex--; 493 wIndex--;
402 temp = xhci_readl(xhci, port_array[wIndex]); 494 temp = xhci_readl(xhci, port_array[wIndex]);
403 temp = xhci_port_state_to_neutral(temp); 495 temp = xhci_port_state_to_neutral(temp);
496 /* FIXME: What new port features do we need to support? */
404 switch (wValue) { 497 switch (wValue) {
405 case USB_PORT_FEAT_SUSPEND: 498 case USB_PORT_FEAT_SUSPEND:
406 temp = xhci_readl(xhci, port_array[wIndex]); 499 temp = xhci_readl(xhci, port_array[wIndex]);
@@ -469,6 +562,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
469 goto error; 562 goto error;
470 wIndex--; 563 wIndex--;
471 temp = xhci_readl(xhci, port_array[wIndex]); 564 temp = xhci_readl(xhci, port_array[wIndex]);
565 /* FIXME: What new port features do we need to support? */
472 temp = xhci_port_state_to_neutral(temp); 566 temp = xhci_port_state_to_neutral(temp);
473 switch (wValue) { 567 switch (wValue) {
474 case USB_PORT_FEAT_SUSPEND: 568 case USB_PORT_FEAT_SUSPEND: