diff options
-rw-r--r-- | drivers/usb/core/hcd.c | 18 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 15 | ||||
-rw-r--r-- | include/linux/usb.h | 1 |
3 files changed, 24 insertions, 10 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 0495fa651225..80995ef0868c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -1684,6 +1684,24 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev, | |||
1684 | } | 1684 | } |
1685 | } | 1685 | } |
1686 | if (cur_alt && new_alt) { | 1686 | if (cur_alt && new_alt) { |
1687 | struct usb_interface *iface = usb_ifnum_to_if(udev, | ||
1688 | cur_alt->desc.bInterfaceNumber); | ||
1689 | |||
1690 | if (iface->resetting_device) { | ||
1691 | /* | ||
1692 | * The USB core just reset the device, so the xHCI host | ||
1693 | * and the device will think alt setting 0 is installed. | ||
1694 | * However, the USB core will pass in the alternate | ||
1695 | * setting installed before the reset as cur_alt. Dig | ||
1696 | * out the alternate setting 0 structure, or the first | ||
1697 | * alternate setting if a broken device doesn't have alt | ||
1698 | * setting 0. | ||
1699 | */ | ||
1700 | cur_alt = usb_altnum_to_altsetting(iface, 0); | ||
1701 | if (!cur_alt) | ||
1702 | cur_alt = &iface->altsetting[0]; | ||
1703 | } | ||
1704 | |||
1687 | /* Drop all the endpoints in the current alt setting */ | 1705 | /* Drop all the endpoints in the current alt setting */ |
1688 | for (i = 0; i < cur_alt->desc.bNumEndpoints; i++) { | 1706 | for (i = 0; i < cur_alt->desc.bNumEndpoints; i++) { |
1689 | ret = hcd->driver->drop_endpoint(hcd, udev, | 1707 | ret = hcd->driver->drop_endpoint(hcd, udev, |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b9f5fcd713e2..35cc8b9ba1f5 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -3695,19 +3695,14 @@ static int usb_reset_and_verify_device(struct usb_device *udev) | |||
3695 | usb_enable_interface(udev, intf, true); | 3695 | usb_enable_interface(udev, intf, true); |
3696 | ret = 0; | 3696 | ret = 0; |
3697 | } else { | 3697 | } else { |
3698 | /* We've just reset the device, so it will think alt | 3698 | /* Let the bandwidth allocation function know that this |
3699 | * setting 0 is installed. For usb_set_interface() to | 3699 | * device has been reset, and it will have to use |
3700 | * work properly, we need to set the current alternate | 3700 | * alternate setting 0 as the current alternate setting. |
3701 | * interface setting to 0 (or the first alt setting, if | ||
3702 | * the device doesn't have alt setting 0). | ||
3703 | */ | 3701 | */ |
3704 | intf->cur_altsetting = | 3702 | intf->resetting_device = 1; |
3705 | usb_find_alt_setting(config, i, 0); | ||
3706 | if (!intf->cur_altsetting) | ||
3707 | intf->cur_altsetting = | ||
3708 | &config->intf_cache[i]->altsetting[0]; | ||
3709 | ret = usb_set_interface(udev, desc->bInterfaceNumber, | 3703 | ret = usb_set_interface(udev, desc->bInterfaceNumber, |
3710 | desc->bAlternateSetting); | 3704 | desc->bAlternateSetting); |
3705 | intf->resetting_device = 0; | ||
3711 | } | 3706 | } |
3712 | if (ret < 0) { | 3707 | if (ret < 0) { |
3713 | dev_err(&udev->dev, "failed to restore interface %d " | 3708 | dev_err(&udev->dev, "failed to restore interface %d " |
diff --git a/include/linux/usb.h b/include/linux/usb.h index e101a2d04d75..d7ace1b80f09 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
@@ -192,6 +192,7 @@ struct usb_interface { | |||
192 | unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */ | 192 | unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */ |
193 | unsigned needs_binding:1; /* needs delayed unbind/rebind */ | 193 | unsigned needs_binding:1; /* needs delayed unbind/rebind */ |
194 | unsigned reset_running:1; | 194 | unsigned reset_running:1; |
195 | unsigned resetting_device:1; /* true: bandwidth alloc after reset */ | ||
195 | 196 | ||
196 | struct device dev; /* interface specific device info */ | 197 | struct device dev; /* interface specific device info */ |
197 | struct device *usb_dev; | 198 | struct device *usb_dev; |