diff options
author | John Youn <John.Youn@synopsys.com> | 2001-09-17 00:00:00 -0700 |
---|---|---|
committer | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2011-03-13 18:07:11 -0700 |
commit | dbe79bbe9dcb22cb3651c46f18943477141ca452 (patch) | |
tree | 86e2dd608fd6ae7902b4abfdfbcf1969980386e3 /drivers/usb | |
parent | ad73dff32e04cad1ff2af89512bf489224b503cc (diff) | |
download | linux-dbe79bbe9dcb22cb3651c46f18943477141ca452.tar.bz2 |
USB 3.0 Hub Changes
Update the USB core to deal with USB 3.0 hubs. These hubs have a slightly
different hub descriptor than USB 2.0 hubs, with a fixed (rather than
variable length) size. Change the USB core's hub descriptor to have a
union for the last fields that differ. Change the host controller drivers
that access those last fields (DeviceRemovable and PortPowerCtrlMask) to
use the union.
Translate the new version of the hub port status field into the old
version that khubd understands. (Note: we need to fix it to translate the
roothub's port status once we stop converting it to USB 2.0 hub status
internally.)
Add new code to handle link state change status. Send out new control
messages that are needed for USB 3.0 hubs, like Set Hub Depth.
This patch is a modified version of the original patch submitted by John
Youn. It's updated to reflect the removal of the "bitmap" #define, and
change the hub descriptor accesses of a couple new host controller
drivers.
Signed-off-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
Cc: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
Cc: Tony Olech <tony.olech@elandigitalsystems.com>
Cc: "Robert P. J. Day" <rpjday@crashcourse.ca>
Cc: Max Vozeler <mvz@vozeler.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Cc: Rodolfo Giometti <giometti@linux.it>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Anton Vorontsov <avorontsov@mvista.com>
Cc: Sebastian Siewior <bigeasy@linutronix.de>
Cc: Lothar Wassmann <LW@KARO-electronics.de>
Cc: Olav Kongas <ok@artecdesign.ee>
Cc: Martin Fuzzey <mfuzzey@gmail.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/core/hub.c | 73 | ||||
-rw-r--r-- | drivers/usb/gadget/dummy_hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/imx21-hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/isp116x-hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/isp1362-hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/isp1760-hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hub.c | 11 | ||||
-rw-r--r-- | drivers/usb/host/oxu210hp-hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/r8a66597-hcd.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/sl811-hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/u132-hcd.c | 11 | ||||
-rw-r--r-- | drivers/usb/host/xhci-hub.c | 4 | ||||
-rw-r--r-- | drivers/usb/musb/musb_virthub.c | 4 | ||||
-rw-r--r-- | drivers/usb/wusbcore/rh.c | 4 |
15 files changed, 102 insertions, 42 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b574f9131b43..feb6e596c7c9 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -82,6 +82,10 @@ struct usb_hub { void **port_owners; }; +static inline int hub_is_superspeed(struct usb_device *hdev) +{ + return (hdev->descriptor.bDeviceProtocol == 3); +} /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can @@ -172,14 +176,23 @@ static struct usb_hub *hdev_to_hub(struct usb_device *hdev) } /* USB 2.0 spec Section 11.24.4.5 */ -static int get_hub_descriptor(struct usb_device *hdev, void *data, int size) +static int get_hub_descriptor(struct usb_device *hdev, void *data) { - int i, ret; + int i, ret, size; + unsigned dtype; + + if (hub_is_superspeed(hdev)) { + dtype = USB_DT_SS_HUB; + size = USB_DT_SS_HUB_SIZE; + } else { + dtype = USB_DT_HUB; + size = sizeof(struct usb_hub_descriptor); + } for (i = 0; i < 3; i++) { ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, - USB_DT_HUB << 8, 0, data, size, + dtype << 8, 0, data, size, USB_CTRL_GET_TIMEOUT); if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2)) return ret; @@ -365,6 +378,19 @@ static int hub_port_status(struct usb_hub *hub, int port1, } else { *status = le16_to_cpu(hub->status->port.wPortStatus); *change = le16_to_cpu(hub->status->port.wPortChange); + + if ((hub->hdev->parent != NULL) && + hub_is_superspeed(hub->hdev)) { + /* Translate the USB 3 port status */ + u16 tmp = *status & USB_SS_PORT_STAT_MASK; + if (*status & USB_SS_PORT_STAT_POWER) + tmp |= USB_PORT_STAT_POWER; + if ((*status & USB_SS_PORT_STAT_SPEED) == + USB_PORT_STAT_SPEED_5GBPS) + tmp |= USB_PORT_STAT_SUPER_SPEED; + *status = tmp; + } + ret = 0; } mutex_unlock(&hub->status_mutex); @@ -607,7 +633,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) if (hdev->children[port1-1] && set_state) usb_set_device_state(hdev->children[port1-1], USB_STATE_NOTATTACHED); - if (!hub->error) + if (!hub->error && !hub_is_superspeed(hub->hdev)) ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); if (ret) dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", @@ -795,6 +821,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_ENABLE); } + if (portchange & USB_PORT_STAT_C_LINK_STATE) { + need_debounce_delay = true; + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_PORT_LINK_STATE); + } /* We can forget about a "removed" device when there's a * physical disconnect or the connect status changes. @@ -964,12 +995,23 @@ static int hub_configure(struct usb_hub *hub, goto fail; } + if (hub_is_superspeed(hdev) && (hdev->parent != NULL)) { + ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + HUB_SET_DEPTH, USB_RT_HUB, + hdev->level - 1, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + + if (ret < 0) { + message = "can't set hub depth"; + goto fail; + } + } + /* Request the entire hub descriptor. * hub->descriptor can handle USB_MAXCHILDREN ports, * but the hub can/will return fewer bytes here. */ - ret = get_hub_descriptor(hdev, hub->descriptor, - sizeof(*hub->descriptor)); + ret = get_hub_descriptor(hdev, hub->descriptor); if (ret < 0) { message = "can't read hub descriptor"; goto fail; @@ -991,12 +1033,14 @@ static int hub_configure(struct usb_hub *hub, wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); - if (wHubCharacteristics & HUB_CHAR_COMPOUND) { + /* FIXME for USB 3.0, skip for now */ + if ((wHubCharacteristics & HUB_CHAR_COMPOUND) && + !(hub_is_superspeed(hdev))) { int i; char portstr [USB_MAXCHILDREN + 1]; for (i = 0; i < hdev->maxchild; i++) - portstr[i] = hub->descriptor->DeviceRemovable + portstr[i] = hub->descriptor->u.hs.DeviceRemovable [((i + 1) / 8)] & (1 << ((i + 1) % 8)) ? 'F' : 'R'; portstr[hdev->maxchild] = 0; @@ -2029,6 +2073,8 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, udev->speed = USB_SPEED_HIGH; else if (portstatus & USB_PORT_STAT_LOW_SPEED) udev->speed = USB_SPEED_LOW; + else if (portstatus & USB_PORT_STAT_SUPER_SPEED) + udev->speed = USB_SPEED_SUPER; else udev->speed = USB_SPEED_FULL; return 0; @@ -3430,6 +3476,17 @@ static void hub_events(void) clear_port_feature(hdev, i, USB_PORT_FEAT_C_RESET); } + if (portchange & USB_PORT_STAT_C_LINK_STATE) { + clear_port_feature(hub->hdev, i, + USB_PORT_FEAT_C_PORT_LINK_STATE); + } + if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { + dev_warn(hub_dev, + "config error on port %d\n", + i); + clear_port_feature(hub->hdev, i, + USB_PORT_FEAT_C_PORT_CONFIG_ERROR); + } if (connect_change) hub_port_connect_change(hub, i, diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index f2040e8af8b1..3214ca375d64 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1593,8 +1593,8 @@ hub_descriptor (struct usb_hub_descriptor *desc) desc->bDescLength = 9; desc->wHubCharacteristics = cpu_to_le16(0x0001); desc->bNbrPorts = 1; - desc->DeviceRemovable[0] = 0xff; - desc->DeviceRemovable[1] = 0xff; + desc->u.hs.DeviceRemovable[0] = 0xff; + desc->u.hs.DeviceRemovable[1] = 0xff; } static int dummy_hub_control ( diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index dfa1e1d371c8..d05ea03cfb4d 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -717,8 +717,8 @@ ehci_hub_descriptor ( desc->bDescLength = 7 + 2 * temp; /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ - memset(&desc->DeviceRemovable[0], 0, temp); - memset(&desc->DeviceRemovable[temp], 0xff, temp); + memset(&desc->u.hs.DeviceRemovable[0], 0, temp); + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); temp = 0x0008; /* per-port overcurrent reporting */ if (HCS_PPC (ehci->hcs_params)) diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index 2f180dfe5371..2562e92e3178 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -1472,8 +1472,8 @@ static int get_hub_descriptor(struct usb_hcd *hcd, 0x0010 | /* No over current protection */ 0); - desc->DeviceRemovable[0] = 1 << 1; - desc->DeviceRemovable[1] = ~0; + desc->u.hs.DeviceRemovable[0] = 1 << 1; + desc->u.hs.DeviceRemovable[1] = ~0; return 0; } diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 2a60a50bc420..c0e22f26da19 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -952,8 +952,8 @@ static void isp116x_hub_descriptor(struct isp116x *isp116x, desc->wHubCharacteristics = cpu_to_le16((u16) ((reg >> 8) & 0x1f)); desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff); /* ports removable, and legacy PortPwrCtrlMask */ - desc->DeviceRemovable[0] = 0; - desc->DeviceRemovable[1] = ~0; + desc->u.hs.DeviceRemovable[0] = 0; + desc->u.hs.DeviceRemovable[1] = ~0; } /* Perform reset of a given port. diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 6dd94b997d97..662cd002adfc 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -1553,8 +1553,8 @@ static void isp1362_hub_descriptor(struct isp1362_hcd *isp1362_hcd, DBG(0, "%s: hubcharacteristics = %02x\n", __func__, cpu_to_le16((reg >> 8) & 0x1f)); desc->bPwrOn2PwrGood = (reg >> 24) & 0xff; /* ports removable, and legacy PortPwrCtrlMask */ - desc->DeviceRemovable[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1; - desc->DeviceRemovable[1] = ~0; + desc->u.hs.DeviceRemovable[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1; + desc->u.hs.DeviceRemovable[1] = ~0; DBG(3, "%s: exit\n", __func__); } diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 1c8de7666d6a..f50e84ac570a 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1752,8 +1752,8 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv, desc->bDescLength = 7 + 2 * temp; /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */ - memset(&desc->DeviceRemovable[0], 0, temp); - memset(&desc->DeviceRemovable[temp], 0xff, temp); + memset(&desc->u.hs.DeviceRemovable[0], 0, temp); + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); /* per-port overcurrent reporting */ temp = 0x0008; diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index cd4b74f27d06..9154615292db 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -582,13 +582,14 @@ ohci_hub_descriptor ( /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */ rh = roothub_b (ohci); - memset(desc->DeviceRemovable, 0xff, sizeof(desc->DeviceRemovable)); - desc->DeviceRemovable[0] = rh & RH_B_DR; + memset(desc->u.hs.DeviceRemovable, 0xff, + sizeof(desc->u.hs.DeviceRemovable)); + desc->u.hs.DeviceRemovable[0] = rh & RH_B_DR; if (ohci->num_ports > 7) { - desc->DeviceRemovable[1] = (rh & RH_B_DR) >> 8; - desc->DeviceRemovable[2] = 0xff; + desc->u.hs.DeviceRemovable[1] = (rh & RH_B_DR) >> 8; + desc->u.hs.DeviceRemovable[2] = 0xff; } else - desc->DeviceRemovable[1] = 0xff; + desc->u.hs.DeviceRemovable[1] = 0xff; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index ad54a4144756..38193f4e980e 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -452,8 +452,8 @@ static void ehci_hub_descriptor(struct oxu_hcd *oxu, desc->bDescLength = 7 + 2 * temp; /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */ - memset(&desc->DeviceRemovable[0], 0, temp); - memset(&desc->DeviceRemovable[temp], 0xff, temp); + memset(&desc->u.hs.DeviceRemovable[0], 0, temp); + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); temp = 0x0008; /* per-port overcurrent reporting */ if (HCS_PPC(oxu->hcs_params)) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 98afe75500cc..db6f8b9c19b6 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2150,8 +2150,9 @@ static void r8a66597_hub_descriptor(struct r8a66597 *r8a66597, desc->bDescLength = 9; desc->bPwrOn2PwrGood = 0; desc->wHubCharacteristics = cpu_to_le16(0x0011); - desc->DeviceRemovable[0] = ((1 << r8a66597->max_root_hub) - 1) << 1; - desc->DeviceRemovable[1] = ~0; + desc->u.hs.DeviceRemovable[0] = + ((1 << r8a66597->max_root_hub) - 1) << 1; + desc->u.hs.DeviceRemovable[1] = ~0; } static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index f3899b334c73..18b7099a8125 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1112,8 +1112,8 @@ sl811h_hub_descriptor ( desc->wHubCharacteristics = cpu_to_le16(temp); /* ports removable, and legacy PortPwrCtrlMask */ - desc->DeviceRemovable[0] = 0 << 1; - desc->DeviceRemovable[1] = ~0; + desc->u.hs.DeviceRemovable[0] = 0 << 1; + desc->u.hs.DeviceRemovable[1] = ~0; } static void diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index a659e1590bca..b4785934e091 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -2604,13 +2604,14 @@ static int u132_roothub_descriptor(struct u132 *u132, retval = u132_read_pcimem(u132, roothub.b, &rh_b); if (retval) return retval; - memset(desc->DeviceRemovable, 0xff, sizeof(desc->DeviceRemovable)); - desc->DeviceRemovable[0] = rh_b & RH_B_DR; + memset(desc->u.hs.DeviceRemovable, 0xff, + sizeof(desc->u.hs.DeviceRemovable)); + desc->u.hs.DeviceRemovable[0] = rh_b & RH_B_DR; if (u132->num_ports > 7) { - desc->DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8; - desc->DeviceRemovable[2] = 0xff; + desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8; + desc->u.hs.DeviceRemovable[2] = 0xff; } else - desc->DeviceRemovable[1] = 0xff; + desc->u.hs.DeviceRemovable[1] = 0xff; return 0; } diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 43e0a099d634..847b071b6fc9 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -45,8 +45,8 @@ static void xhci_hub_descriptor(struct xhci_hcd *xhci, temp = 1 + (ports / 8); desc->bDescLength = 7 + 2 * temp; - memset(&desc->DeviceRemovable[0], 0, temp); - memset(&desc->DeviceRemovable[temp], 0xff, temp); + memset(&desc->u.hs.DeviceRemovable[0], 0, temp); + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); /* Ugh, these should be #defines, FIXME */ /* Using table 11-13 in USB 2.0 spec. */ diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index b46d1877e28e..489104a5ae14 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -305,8 +305,8 @@ int musb_hub_control( desc->bHubContrCurrent = 0; /* workaround bogus struct definition */ - desc->DeviceRemovable[0] = 0x02; /* port 1 */ - desc->DeviceRemovable[1] = 0xff; + desc->u.hs.DeviceRemovable[0] = 0x02; /* port 1 */ + desc->u.hs.DeviceRemovable[1] = 0xff; } break; case GetHubStatus: diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c index cff246b7cb26..c175b7300c73 100644 --- a/drivers/usb/wusbcore/rh.c +++ b/drivers/usb/wusbcore/rh.c @@ -184,8 +184,8 @@ static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue, descr->bPwrOn2PwrGood = 0; descr->bHubContrCurrent = 0; /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ - memset(&descr->DeviceRemovable[0], 0, temp); - memset(&descr->DeviceRemovable[temp], 0xff, temp); + memset(&descr->u.hs.DeviceRemovable[0], 0, temp); + memset(&descr->u.hs.DeviceRemovable[temp], 0xff, temp); return 0; } |