From: John Youn <johnyoun@xxxxxxxxxxxx> Make the following changes to work with SuperSpeed hubs: - Add new constants in header - Add check for superspeed hubs - Skip some things not needed for superspeed hub - Set the hub depth after enumeration to address downstream ports - Modify the port status and port changed bits from the hub Signed-off-by: John Youn <johnyoun@xxxxxxxxxxxx> Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx> --- v2 - Rediffed against Greg's usb-next branch Hi Sarah, Can we finally get John's hub patches queued for .39? There are SuperSpeed hubs in the market now (e.g. http://www.amazon.com/SuperSpeed-USB-3-0-7-Port-Hub/dp/B003NE5I9I) so I think we should have the support in the kernel. It also makes it easier for us not needing to patch the kernel every time a new version is released. I seem to recall some objections to a couple of things in the patch, but I don't remember what those were now. The diffs are against Greg's usb-next branch. -Paul drivers/usb/core/hub.c | 60 ++++++++++++++++++++++++++++++++++++++++++-- include/linux/usb/ch11.h | 62 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 103 insertions(+), 19 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c168121..5dd9dd1 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 @@ -176,10 +180,17 @@ static int get_hub_descriptor(struct usb_device *hdev, void *data, int size) { int i, ret; + unsigned dtype = USB_DT_HUB; + + if (hub_is_superspeed(hdev)) { + dtype = USB_DT_SS_HUB; + size = 12; + } + 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 +376,17 @@ 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 & USB3_PORT_STAT_MASK; + if (*status & USB3_PORT_STAT_POWER) + tmp |= USB_PORT_STAT_POWER; + if ((*status & USB3_PORT_STAT_SPEED) == USB3_PORT_STAT_SPEED_SUPER) + tmp |= USB_PORT_STAT_SUPER_SPEED; + *status = tmp; + } + ret = 0; } mutex_unlock(&hub->status_mutex); @@ -607,7 +629,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(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 +817,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,6 +991,18 @@ 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. @@ -991,7 +1030,8 @@ 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]; @@ -3423,6 +3463,20 @@ static void hub_events(void) clear_port_feature(hdev, i, USB_PORT_FEAT_C_RESET); } + if (portchange & USB_PORT_STAT_C_LINK_STATE) { + dev_dbg (hub_dev, + "link state change on port %d\n", + i); + clear_port_feature(hub->hdev, i, + USB_PORT_FEAT_C_PORT_LINK_STATE); + } + if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { + dev_dbg (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/include/linux/usb/ch11.h b/include/linux/usb/ch11.h index 38c42b0..a87153e 100644 --- a/include/linux/usb/ch11.h +++ b/include/linux/usb/ch11.h @@ -26,6 +26,7 @@ #define HUB_RESET_TT 9 #define HUB_GET_TT_STATE 10 #define HUB_STOP_TT 11 +#define HUB_SET_DEPTH 12 /* * Hub class additional requests defined by USB 3.0 spec @@ -45,22 +46,28 @@ * Port feature numbers * See USB 2.0 spec Table 11-17 */ -#define USB_PORT_FEAT_CONNECTION 0 -#define USB_PORT_FEAT_ENABLE 1 -#define USB_PORT_FEAT_SUSPEND 2 /* L2 suspend */ -#define USB_PORT_FEAT_OVER_CURRENT 3 -#define USB_PORT_FEAT_RESET 4 -#define USB_PORT_FEAT_L1 5 /* L1 suspend */ -#define USB_PORT_FEAT_POWER 8 -#define USB_PORT_FEAT_LOWSPEED 9 /* Should never be used */ -#define USB_PORT_FEAT_C_CONNECTION 16 -#define USB_PORT_FEAT_C_ENABLE 17 -#define USB_PORT_FEAT_C_SUSPEND 18 -#define USB_PORT_FEAT_C_OVER_CURRENT 19 -#define USB_PORT_FEAT_C_RESET 20 -#define USB_PORT_FEAT_TEST 21 -#define USB_PORT_FEAT_INDICATOR 22 -#define USB_PORT_FEAT_C_PORT_L1 23 +#define USB_PORT_FEAT_CONNECTION 0 +#define USB_PORT_FEAT_ENABLE 1 +#define USB_PORT_FEAT_SUSPEND 2 /* L2 suspend */ +#define USB_PORT_FEAT_OVER_CURRENT 3 +#define USB_PORT_FEAT_RESET 4 +#define USB_PORT_FEAT_L1 5 /* L1 suspend */ +#define USB_PORT_FEAT_POWER 8 +#define USB_PORT_FEAT_LOWSPEED 9 /* Should never be used */ +#define USB_PORT_FEAT_C_CONNECTION 16 +#define USB_PORT_FEAT_C_ENABLE 17 +#define USB_PORT_FEAT_C_SUSPEND 18 +#define USB_PORT_FEAT_C_OVER_CURRENT 19 +#define USB_PORT_FEAT_C_RESET 20 +#define USB_PORT_FEAT_TEST 21 +#define USB_PORT_FEAT_INDICATOR 22 +#define USB_PORT_FEAT_C_PORT_L1 23 +#define USB_PORT_FEAT_C_PORT_LINK_STATE 25 +#define USB_PORT_FEAT_C_PORT_CONFIG_ERROR 26 +#define USB_PORT_FEAT_PORT_REMOTE_WAKE_MASK 27 +#define USB_PORT_FEAT_BH_PORT_RESET 28 +#define USB_PORT_FEAT_C_BH_PORT_RESET 29 +#define USB_PORT_FEAT_FORCE_LINKPM_ACCEPT 30 /* * Port feature selectors added by USB 3.0 spec. @@ -131,6 +138,21 @@ struct usb_port_status { #define USB_SS_PORT_LS_LOOPBACK 0x0160 /* + * USB 3.0 wPortStatus bit fields + * See USB 3.0 spec Table 10-10 + */ +/* Bits that are the same from USB 2.0 */ +#define USB3_PORT_STAT_MASK (USB_PORT_STAT_CONNECTION | \ + USB_PORT_STAT_ENABLE | \ + USB_PORT_STAT_OVERCURRENT | \ + USB_PORT_STAT_RESET) +/* 3.0 specific bits */ +#define USB3_PORT_STAT_LINK_STATE 0x01e0 +#define USB3_PORT_STAT_POWER 0x0200 +#define USB3_PORT_STAT_SPEED 0x1c00 +#define USB3_PORT_STAT_SPEED_SUPER 0x0 + +/* * wPortChange bit field * See USB 2.0 spec Table 11-22 and USB 2.0 LPM ECN Table-4.10 * Bits 0 to 5 shown, bits 6 to 15 are reserved @@ -141,6 +163,13 @@ struct usb_port_status { #define USB_PORT_STAT_C_OVERCURRENT 0x0008 #define USB_PORT_STAT_C_RESET 0x0010 #define USB_PORT_STAT_C_L1 0x0020 +/* + * USB 3.0 wPortChange bit fields + * See USB 3.0 spec Table 10-11 + */ +#define USB_PORT_STAT_C_BH_RESET 0x0020 +#define USB_PORT_STAT_C_LINK_STATE 0x0040 +#define USB_PORT_STAT_C_CONFIG_ERROR 0x0080 /* * wHubCharacteristics (masks) @@ -175,6 +204,7 @@ struct usb_hub_status { */ #define USB_DT_HUB (USB_TYPE_CLASS | 0x09) +#define USB_DT_SS_HUB (USB_TYPE_CLASS | 0x0a) #define USB_DT_HUB_NONVAR_SIZE 7 struct usb_hub_descriptor { -- 1.6.5.1.69.g36942 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html