diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2009-02-26 10:21:02 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-03-24 19:20:38 -0400 |
commit | 4fe0387afa893b44c5a21b9bfbb0888354ef4656 (patch) | |
tree | b86045c34fab6ff5146dd3ca6be70d54514a1359 /drivers/usb | |
parent | 77aa2b5878f48d6ab6e0c412cc9214c845483475 (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')
-rw-r--r-- | drivers/usb/core/hub.c | 23 |
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", |