Re: [PATCH] USB: Add support for SuperSpeed hubs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Paul,

There's a lot more work that needs to be done than just this patch.
I've been working on getting that done on the 'hubs-v3' branch in my
repository.  I've built on top of John's patch and modified it based on
community feedback.  It's on my todo list for this weekend to get the
final feedback integrated and try to push out a new RFC next week.

Greg, NAK on this patch for now.

Sarah Sharp

On Fri, Feb 25, 2011 at 01:39:20PM -0800, Paul Zimmerman wrote:
> 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>
> ---
> 
> 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 for-linus branch.
> 
> -Paul
> 
> 
>  drivers/usb/core/hub.c   |   60 +++++++++++++++++++++++++++++++++++++++++++--
>  include/linux/usb/ch11.h |   30 +++++++++++++++++++++++
>  2 files changed, 87 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index 0f299b7..fb8e96b 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 10ec069..3edf7bc 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
> @@ -61,6 +62,12 @@
>  #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
>   * Bits 0 to 4 shown, bits 5 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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux