aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r--drivers/usb/core/hub.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b38fd6730e2..e4b0e28f745 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3599,6 +3599,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
{
struct usb_device *parent_hdev = udev->parent;
struct usb_hub *parent_hub;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
struct usb_device_descriptor descriptor = udev->descriptor;
int i, ret = 0;
int port1 = udev->portnum;
@@ -3642,6 +3643,16 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
/* Restore the device's previous configuration */
if (!udev->actconfig)
goto done;
+
+ mutex_lock(&hcd->bandwidth_mutex);
+ ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL);
+ if (ret < 0) {
+ dev_warn(&udev->dev,
+ "Busted HC? Not enough HCD resources for "
+ "old configuration.\n");
+ mutex_unlock(&hcd->bandwidth_mutex);
+ goto re_enumerate;
+ }
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_CONFIGURATION, 0,
udev->actconfig->desc.bConfigurationValue, 0,
@@ -3650,8 +3661,10 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
dev_err(&udev->dev,
"can't restore configuration #%d (error=%d)\n",
udev->actconfig->desc.bConfigurationValue, ret);
+ mutex_unlock(&hcd->bandwidth_mutex);
goto re_enumerate;
}
+ mutex_unlock(&hcd->bandwidth_mutex);
usb_set_device_state(udev, USB_STATE_CONFIGURED);
/* Put interfaces back into the same altsettings as before.
@@ -3661,7 +3674,8 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
* endpoint state.
*/
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
- struct usb_interface *intf = udev->actconfig->interface[i];
+ struct usb_host_config *config = udev->actconfig;
+ struct usb_interface *intf = config->interface[i];
struct usb_interface_descriptor *desc;
desc = &intf->cur_altsetting->desc;
@@ -3670,6 +3684,17 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
usb_enable_interface(udev, intf, true);
ret = 0;
} else {
+ /* We've just reset the device, so it will think alt
+ * setting 0 is installed. For usb_set_interface() to
+ * work properly, we need to set the current alternate
+ * interface setting to 0 (or the first alt setting, if
+ * the device doesn't have alt setting 0).
+ */
+ intf->cur_altsetting =
+ usb_find_alt_setting(config, i, 0);
+ if (!intf->cur_altsetting)
+ intf->cur_altsetting =
+ &config->intf_cache[i]->altsetting[0];
ret = usb_set_interface(udev, desc->bInterfaceNumber,
desc->bAlternateSetting);
}