mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-18 11:17:07 +00:00
USB: Reset USB 3.0 devices on (re)discovery
If the device isn't reset, the XHCI HCD sends SET ADDRESS to address 0 while the device is already in Addressed state, and the request is dropped on the floor as it is addressed to the default address. This sequence of events, which this patch fixes looks like this: usb_reset_and_verify_device() hub_port_init() hub_set_address() SET_ADDRESS to 0 with 1 usb_get_device_descriptor(udev, 8) usb_get_device_descriptor(udev, 18) descriptors_changed() --> goto re_enumerate: hub_port_logical_disconnect() kick_khubd() And then: hub_events() hub_port_connect_change() usb_disconnect() usb_disable_device() new device struct sets device state to Powered choose_address() hub_port_init() <-- no reset, but SET ADDRESS to 0 with 1, timeout! The solution is to always reset the device in hub_port_init() to put it in a known state. Signed-off-by: Luben Tuikov <ltuikov@yahoo.com> Cc: Sarah Sharp <sarah.a.sharp@linux.intel.com> Cc: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
72a012ce0a
commit
637d11bfb8
@ -2681,17 +2681,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
|||||||
|
|
||||||
mutex_lock(&usb_address0_mutex);
|
mutex_lock(&usb_address0_mutex);
|
||||||
|
|
||||||
if (!udev->config && oldspeed == USB_SPEED_SUPER) {
|
/* Reset the device; full speed may morph to high speed */
|
||||||
/* Don't reset USB 3.0 devices during an initial setup */
|
/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
|
||||||
usb_set_device_state(udev, USB_STATE_DEFAULT);
|
retval = hub_port_reset(hub, port1, udev, delay);
|
||||||
} else {
|
if (retval < 0) /* error or disconnect */
|
||||||
/* Reset the device; full speed may morph to high speed */
|
goto fail;
|
||||||
/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
|
/* success, speed is known */
|
||||||
retval = hub_port_reset(hub, port1, udev, delay);
|
|
||||||
if (retval < 0) /* error or disconnect */
|
|
||||||
goto fail;
|
|
||||||
/* success, speed is known */
|
|
||||||
}
|
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
|
|
||||||
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
|
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user