aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/usb/persist.txt7
-rw-r--r--drivers/usb/core/hub.c20
2 files changed, 22 insertions, 5 deletions
diff --git a/Documentation/usb/persist.txt b/Documentation/usb/persist.txt
index d56cb1a11550..074b159b77c2 100644
--- a/Documentation/usb/persist.txt
+++ b/Documentation/usb/persist.txt
@@ -81,8 +81,11 @@ re-enumeration shows that the device now attached to that port has the
81same descriptors as before, including the Vendor and Product IDs, then 81same descriptors as before, including the Vendor and Product IDs, then
82the kernel continues to use the same device structure. In effect, the 82the kernel continues to use the same device structure. In effect, the
83kernel treats the device as though it had merely been reset instead of 83kernel treats the device as though it had merely been reset instead of
84unplugged. The same thing happens if the host controller is in the 84unplugged.
85expected state but a USB device was unplugged and then replugged. 85
86The same thing happens if the host controller is in the expected state
87but a USB device was unplugged and then replugged, or if a USB device
88fails to carry out a normal resume.
86 89
87If no device is now attached to the port, or if the descriptors are 90If no device is now attached to the port, or if the descriptors are
88different from what the kernel remembers, then the treatment is what 91different from what the kernel remembers, then the treatment is what
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index f1efabbc1ca2..107e1d25ddec 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1822,9 +1822,15 @@ static int check_port_resume_type(struct usb_device *udev,
1822 status = -ENODEV; 1822 status = -ENODEV;
1823 } 1823 }
1824 1824
1825 /* Can't do a normal resume if the port isn't enabled */ 1825 /* Can't do a normal resume if the port isn't enabled,
1826 else if (!(portstatus & USB_PORT_STAT_ENABLE) && !udev->reset_resume) 1826 * so try a reset-resume instead.
1827 status = -ENODEV; 1827 */
1828 else if (!(portstatus & USB_PORT_STAT_ENABLE) && !udev->reset_resume) {
1829 if (udev->persist_enabled)
1830 udev->reset_resume = 1;
1831 else
1832 status = -ENODEV;
1833 }
1828 1834
1829 if (status) { 1835 if (status) {
1830 dev_dbg(hub->intfdev, 1836 dev_dbg(hub->intfdev,
@@ -1973,6 +1979,7 @@ static int finish_port_resume(struct usb_device *udev)
1973 * resumed. 1979 * resumed.
1974 */ 1980 */
1975 if (udev->reset_resume) 1981 if (udev->reset_resume)
1982 retry_reset_resume:
1976 status = usb_reset_and_verify_device(udev); 1983 status = usb_reset_and_verify_device(udev);
1977 1984
1978 /* 10.5.4.5 says be sure devices in the tree are still there. 1985 /* 10.5.4.5 says be sure devices in the tree are still there.
@@ -1984,6 +1991,13 @@ static int finish_port_resume(struct usb_device *udev)
1984 status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); 1991 status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
1985 if (status >= 0) 1992 if (status >= 0)
1986 status = (status > 0 ? 0 : -ENODEV); 1993 status = (status > 0 ? 0 : -ENODEV);
1994
1995 /* If a normal resume failed, try doing a reset-resume */
1996 if (status && !udev->reset_resume && udev->persist_enabled) {
1997 dev_dbg(&udev->dev, "retry with reset-resume\n");
1998 udev->reset_resume = 1;
1999 goto retry_reset_resume;
2000 }
1987 } 2001 }
1988 2002
1989 if (status) { 2003 if (status) {