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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
ac90e36592
commit
86c57edf60
@@ -81,8 +81,11 @@ re-enumeration shows that the device now attached to that port has the
|
|||||||
same descriptors as before, including the Vendor and Product IDs, then
|
same descriptors as before, including the Vendor and Product IDs, then
|
||||||
the kernel continues to use the same device structure. In effect, the
|
the kernel continues to use the same device structure. In effect, the
|
||||||
kernel treats the device as though it had merely been reset instead of
|
kernel treats the device as though it had merely been reset instead of
|
||||||
unplugged. The same thing happens if the host controller is in the
|
unplugged.
|
||||||
expected state but a USB device was unplugged and then replugged.
|
|
||||||
|
The same thing happens if the host controller is in the expected state
|
||||||
|
but a USB device was unplugged and then replugged, or if a USB device
|
||||||
|
fails to carry out a normal resume.
|
||||||
|
|
||||||
If no device is now attached to the port, or if the descriptors are
|
If no device is now attached to the port, or if the descriptors are
|
||||||
different from what the kernel remembers, then the treatment is what
|
different from what the kernel remembers, then the treatment is what
|
||||||
|
@@ -1822,9 +1822,15 @@ static int check_port_resume_type(struct usb_device *udev,
|
|||||||
status = -ENODEV;
|
status = -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Can't do a normal resume if the port isn't enabled */
|
/* Can't do a normal resume if the port isn't enabled,
|
||||||
else if (!(portstatus & USB_PORT_STAT_ENABLE) && !udev->reset_resume)
|
* so try a reset-resume instead.
|
||||||
status = -ENODEV;
|
*/
|
||||||
|
else if (!(portstatus & USB_PORT_STAT_ENABLE) && !udev->reset_resume) {
|
||||||
|
if (udev->persist_enabled)
|
||||||
|
udev->reset_resume = 1;
|
||||||
|
else
|
||||||
|
status = -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
dev_dbg(hub->intfdev,
|
dev_dbg(hub->intfdev,
|
||||||
@@ -1973,6 +1979,7 @@ static int finish_port_resume(struct usb_device *udev)
|
|||||||
* resumed.
|
* resumed.
|
||||||
*/
|
*/
|
||||||
if (udev->reset_resume)
|
if (udev->reset_resume)
|
||||||
|
retry_reset_resume:
|
||||||
status = usb_reset_and_verify_device(udev);
|
status = usb_reset_and_verify_device(udev);
|
||||||
|
|
||||||
/* 10.5.4.5 says be sure devices in the tree are still there.
|
/* 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)
|
|||||||
status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
|
status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
|
||||||
if (status >= 0)
|
if (status >= 0)
|
||||||
status = (status > 0 ? 0 : -ENODEV);
|
status = (status > 0 ? 0 : -ENODEV);
|
||||||
|
|
||||||
|
/* If a normal resume failed, try doing a reset-resume */
|
||||||
|
if (status && !udev->reset_resume && udev->persist_enabled) {
|
||||||
|
dev_dbg(&udev->dev, "retry with reset-resume\n");
|
||||||
|
udev->reset_resume = 1;
|
||||||
|
goto retry_reset_resume;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
|
Reference in New Issue
Block a user