Skip to content

Commit

Permalink
USB: revert recovery from transient errors
Browse files Browse the repository at this point in the history
This patch (as1135) essentially reverts the major parts of two earlier
patches to usbcore, because they ended up causing a regression.

Trying to recover from transient communication errors can lead to
other problems, because operations that failed during the error period
are not always retried.  The simplest example is the initial
Set-Config request sent after device enumeration; if it gets lost then
it will not be retried and the device will remain unconfigured.

This patch restores the old behavior in which any port disconnect or
port disable causes the entire device structure to be removed, fixing a
reported regression.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Tested-by: Frans Pop <elendil@planet.nl>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Sep 23, 2008
1 parent af747c4 commit 5257d97
Showing 1 changed file with 17 additions and 22 deletions.
39 changes: 17 additions & 22 deletions drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -2683,35 +2683,17 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
USB_PORT_STAT_C_ENABLE);
#endif

/* Try to use the debounce delay for protection against
* port-enable changes caused, for example, by EMI.
*/
if (portchange & (USB_PORT_STAT_C_CONNECTION |
USB_PORT_STAT_C_ENABLE)) {
status = hub_port_debounce(hub, port1);
if (status < 0) {
if (printk_ratelimit())
dev_err (hub_dev, "connect-debounce failed, "
"port %d disabled\n", port1);
portstatus &= ~USB_PORT_STAT_CONNECTION;
} else {
portstatus = status;
}
}

/* Try to resuscitate an existing device */
udev = hdev->children[port1-1];
if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
udev->state != USB_STATE_NOTATTACHED) {

usb_lock_device(udev);
if (portstatus & USB_PORT_STAT_ENABLE) {
status = 0; /* Nothing to do */
} else if (!udev->persist_enabled) {
status = -ENODEV; /* Mustn't resuscitate */

#ifdef CONFIG_USB_SUSPEND
} else if (udev->state == USB_STATE_SUSPENDED) {
} else if (udev->state == USB_STATE_SUSPENDED &&
udev->persist_enabled) {
/* For a suspended device, treat this as a
* remote wakeup event.
*/
Expand All @@ -2726,7 +2708,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
#endif

} else {
status = usb_reset_device(udev);
status = -ENODEV; /* Don't resuscitate */
}
usb_unlock_device(udev);

Expand All @@ -2741,14 +2723,27 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
usb_disconnect(&hdev->children[port1-1]);
clear_bit(port1, hub->change_bits);

if (portchange & (USB_PORT_STAT_C_CONNECTION |
USB_PORT_STAT_C_ENABLE)) {
status = hub_port_debounce(hub, port1);
if (status < 0) {
if (printk_ratelimit())
dev_err(hub_dev, "connect-debounce failed, "
"port %d disabled\n", port1);
portstatus &= ~USB_PORT_STAT_CONNECTION;
} else {
portstatus = status;
}
}

/* Return now if debouncing failed or nothing is connected */
if (!(portstatus & USB_PORT_STAT_CONNECTION)) {

/* maybe switch power back on (e.g. root hub was reset) */
if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
&& !(portstatus & (1 << USB_PORT_FEAT_POWER)))
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);

if (portstatus & USB_PORT_STAT_ENABLE)
goto done;
return;
Expand Down

0 comments on commit 5257d97

Please sign in to comment.