diff options
| author | Alan Stern <stern@rowland.harvard.edu> | 2008-06-30 11:14:43 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-07-21 18:16:48 -0400 |
| commit | 86c57edf60f5c98adb496880f56cd0e5a3423153 (patch) | |
| tree | e95742e71c85f85549d3be390803d1fa5328853f | |
| parent | ac90e36592ea5171c4e70f58b39a782d871a7d9f (diff) | |
USB: use reset_resume when normal resume fails
This patch (as1109b) makes USB-Persist more resilient to errors. With
the current code, if a normal resume fails, it's an unrecoverable
error. With the patch, if a normal resume fails (and if the device is
enabled for USB-Persist) then a reset-resume is tried.
This fixes the problem reported in Bugzilla #10977.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | Documentation/usb/persist.txt | 7 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 20 |
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 | |||
| 81 | same descriptors as before, including the Vendor and Product IDs, then | 81 | same descriptors as before, including the Vendor and Product IDs, then |
| 82 | the kernel continues to use the same device structure. In effect, the | 82 | the kernel continues to use the same device structure. In effect, the |
| 83 | kernel treats the device as though it had merely been reset instead of | 83 | kernel treats the device as though it had merely been reset instead of |
| 84 | unplugged. The same thing happens if the host controller is in the | 84 | unplugged. |
| 85 | expected state but a USB device was unplugged and then replugged. | 85 | |
| 86 | The same thing happens if the host controller is in the expected state | ||
| 87 | but a USB device was unplugged and then replugged, or if a USB device | ||
| 88 | fails to carry out a normal resume. | ||
| 86 | 89 | ||
| 87 | If no device is now attached to the port, or if the descriptors are | 90 | If no device is now attached to the port, or if the descriptors are |
| 88 | different from what the kernel remembers, then the treatment is what | 91 | different 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) { |
