diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
| -rw-r--r-- | drivers/usb/core/hub.c | 73 | 
1 files changed, 73 insertions, 0 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index bbab424b0d55..9eca403af2a8 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -44,6 +44,9 @@  #define USB_PRODUCT_USB5534B			0x5534  #define USB_VENDOR_CYPRESS			0x04b4  #define USB_PRODUCT_CY7C65632			0x6570 +#define USB_VENDOR_TEXAS_INSTRUMENTS		0x0451 +#define USB_PRODUCT_TUSB8041_USB3		0x8140 +#define USB_PRODUCT_TUSB8041_USB2		0x8142  #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND	0x01  #define HUB_QUIRK_DISABLE_AUTOSUSPEND		0x02 @@ -3081,6 +3084,48 @@ done:  	return status;  } +/* + * hub_port_stop_enumerate - stop USB enumeration or ignore port events + * @hub: target hub + * @port1: port num of the port + * @retries: port retries number of hub_port_init() + * + * Return: + *    true: ignore port actions/events or give up connection attempts. + *    false: keep original behavior. + * + * This function will be based on retries to check whether the port which is + * marked with early_stop attribute would stop enumeration or ignore events. + * + * Note: + * This function didn't change anything if early_stop is not set, and it will + * prevent all connection attempts when early_stop is set and the attempts of + * the port are more than 1. + */ +static bool hub_port_stop_enumerate(struct usb_hub *hub, int port1, int retries) +{ +	struct usb_port *port_dev = hub->ports[port1 - 1]; + +	if (port_dev->early_stop) { +		if (port_dev->ignore_event) +			return true; + +		/* +		 * We want unsuccessful attempts to fail quickly. +		 * Since some devices may need one failure during +		 * port initialization, we allow two tries but no +		 * more. +		 */ +		if (retries < 2) +			return false; + +		port_dev->ignore_event = 1; +	} else +		port_dev->ignore_event = 0; + +	return port_dev->ignore_event; +} +  /* Check if a port is power on */  int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus)  { @@ -4796,6 +4841,11 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,  	do_new_scheme = use_new_scheme(udev, retry_counter, port_dev);  	for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) { +		if (hub_port_stop_enumerate(hub, port1, retries)) { +			retval = -ENODEV; +			break; +		} +  		if (do_new_scheme) {  			struct usb_device_descriptor *buf;  			int r = 0; @@ -5246,6 +5296,11 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,  	status = 0;  	for (i = 0; i < PORT_INIT_TRIES; i++) { +		if (hub_port_stop_enumerate(hub, port1, i)) { +			status = -ENODEV; +			break; +		} +  		usb_lock_port(port_dev);  		mutex_lock(hcd->address0_mutex);  		retry_locked = true; @@ -5614,6 +5669,10 @@ static void port_event(struct usb_hub *hub, int port1)  	if (!pm_runtime_active(&port_dev->dev))  		return; +	/* skip port actions if ignore_event and early_stop are true */ +	if (port_dev->ignore_event && port_dev->early_stop) +		return; +  	if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange))  		connect_change = 1; @@ -5798,6 +5857,16 @@ static const struct usb_device_id hub_id_table[] = {        .idVendor = USB_VENDOR_GENESYS_LOGIC,        .bInterfaceClass = USB_CLASS_HUB,        .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND}, +    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR +			| USB_DEVICE_ID_MATCH_PRODUCT, +      .idVendor = USB_VENDOR_TEXAS_INSTRUMENTS, +      .idProduct = USB_PRODUCT_TUSB8041_USB2, +      .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND}, +    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR +			| USB_DEVICE_ID_MATCH_PRODUCT, +      .idVendor = USB_VENDOR_TEXAS_INSTRUMENTS, +      .idProduct = USB_PRODUCT_TUSB8041_USB3, +      .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},      { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,        .bDeviceClass = USB_CLASS_HUB},      { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, @@ -5927,6 +5996,10 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  	mutex_lock(hcd->address0_mutex);  	for (i = 0; i < PORT_INIT_TRIES; ++i) { +		if (hub_port_stop_enumerate(parent_hub, port1, i)) { +			ret = -ENODEV; +			break; +		}  		/* ep0 maxpacket size may change; let the HCD know about it.  		 * Other endpoints will be handled by re-enumeration. */  | 
