USB: disable reset-resume when USB_QUIRK_RESET is set
authorAlan Stern <stern@rowland.harvard.edu>
Tue, 18 Mar 2014 14:39:05 +0000 (10:39 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Mar 2014 21:00:32 +0000 (14:00 -0700)
The USB_QUIRK_RESET flag indicates that a USB device changes its
identity in some way when it is reset.  It may lose its firmware, its
descriptors may change, or it may switch back to a default mode of
operation.

If a device does this, the kernel needs to avoid resetting it.  Resets
are likely to fail, or worse, succeed while changing the device's
state in a way the system can't detect.

This means we should disable the reset-resume mechanism whenever this
quirk flag is present.  An attempted reset-resume will fail, the
device will be logically disconnected, and later on the hub driver
will rediscover and re-enumerate the device.  This will cause the
appropriate udev events to be generated, so that userspace will have a
chance to switch the device into its normal operating mode, if
necessary.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: Oliver Neukum <oliver@neukum.org>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/core/hub.c

index 2d74dfb9c9895685ee25365ca8e5c043b96ce029..d670aaf13a3d5eb457edf424cf52b7757d2521d3 100644 (file)
@@ -3105,9 +3105,19 @@ static int finish_port_resume(struct usb_device *udev)
         * operation is carried out here, after the port has been
         * resumed.
         */
-       if (udev->reset_resume)
+       if (udev->reset_resume) {
+               /*
+                * If the device morphs or switches modes when it is reset,
+                * we don't want to perform a reset-resume.  We'll fail the
+                * resume, which will cause a logical disconnect, and then
+                * the device will be rediscovered.
+                */
  retry_reset_resume:
-               status = usb_reset_and_verify_device(udev);
+               if (udev->quirks & USB_QUIRK_RESET)
+                       status = -ENODEV;
+               else
+                       status = usb_reset_and_verify_device(udev);
+       }
 
        /* 10.5.4.5 says be sure devices in the tree are still there.
         * For now let's assume the device didn't go crazy on resume,