aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-02-26 10:21:02 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-03-24 19:20:38 -0400
commit4fe0387afa893b44c5a21b9bfbb0888354ef4656 (patch)
treeb86045c34fab6ff5146dd3ca6be70d54514a1359 /drivers/usb/core
parent77aa2b5878f48d6ab6e0c412cc9214c845483475 (diff)
USB: don't send Set-Interface after reset
This patch (as1221) changes the way usbcore reinitializes a device following a reset or a reset-resume. Currently we call usb_set_interface() for every interface in the active configuration; this is to put the interface into the same altsetting as before the reset and to make sure that the host's endpoint state matches the device's endpoint state. However, sending a Set-Interface request is a waste of time if an interface was already in altsetting 0 before the reset, since it is certainly in altsetting 0 afterward. In addition, many devices can't handle Set-Interface requests -- they crash when they receive them. So instead, the patch adds code to check each interface. If the interface wasn't in altsetting 0 before the reset, we go head with the Set-Interface request as before. But if it was then we skip sending the Set-Interface request, and we clear out the host-side endpoint state by calling usb_disable_interface() followed by usb_enable_interface(). The patch also adds a couple of new comments to explain what's going on. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/hub.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index f17d9ebc44af..81eb3e6b6592 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3393,10 +3393,10 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
3393 udev->descriptor = descriptor; /* for disconnect() calls */ 3393 udev->descriptor = descriptor; /* for disconnect() calls */
3394 goto re_enumerate; 3394 goto re_enumerate;
3395 } 3395 }
3396 3396
3397 /* Restore the device's previous configuration */
3397 if (!udev->actconfig) 3398 if (!udev->actconfig)
3398 goto done; 3399 goto done;
3399
3400 ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 3400 ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
3401 USB_REQ_SET_CONFIGURATION, 0, 3401 USB_REQ_SET_CONFIGURATION, 0,
3402 udev->actconfig->desc.bConfigurationValue, 0, 3402 udev->actconfig->desc.bConfigurationValue, 0,
@@ -3409,16 +3409,25 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
3409 } 3409 }
3410 usb_set_device_state(udev, USB_STATE_CONFIGURED); 3410 usb_set_device_state(udev, USB_STATE_CONFIGURED);
3411 3411
3412 /* Put interfaces back into the same altsettings as before.
3413 * Don't bother to send the Set-Interface request for interfaces
3414 * that were already in altsetting 0; besides being unnecessary,
3415 * many devices can't handle it. Instead just reset the host-side
3416 * endpoint state.
3417 */
3412 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { 3418 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
3413 struct usb_interface *intf = udev->actconfig->interface[i]; 3419 struct usb_interface *intf = udev->actconfig->interface[i];
3414 struct usb_interface_descriptor *desc; 3420 struct usb_interface_descriptor *desc;
3415 3421
3416 /* set_interface resets host side toggle even
3417 * for altsetting zero. the interface may have no driver.
3418 */
3419 desc = &intf->cur_altsetting->desc; 3422 desc = &intf->cur_altsetting->desc;
3420 ret = usb_set_interface(udev, desc->bInterfaceNumber, 3423 if (desc->bAlternateSetting == 0) {
3421 desc->bAlternateSetting); 3424 usb_disable_interface(udev, intf, true);
3425 usb_enable_interface(udev, intf, true);
3426 ret = 0;
3427 } else {
3428 ret = usb_set_interface(udev, desc->bInterfaceNumber,
3429 desc->bAlternateSetting);
3430 }
3422 if (ret < 0) { 3431 if (ret < 0) {
3423 dev_err(&udev->dev, "failed to restore interface %d " 3432 dev_err(&udev->dev, "failed to restore interface %d "
3424 "altsetting %d (error=%d)\n", 3433 "altsetting %d (error=%d)\n",