USB: debounce before unregistering
This patch (as1080) makes a significant change to the way khubd handles port connect-change and enable-change events. Both types of event are now debounced, and the debouncing is carried out _before_ an existing usb_device is unregistered, instead of afterward. This means that drivers will have to deal with longer runs of errors when a device is unplugged, but they are supposed to be prepared for that in any case. The advantage is that when an enable-change occurs (caused for example by electromagnetic interference), the debouncing period will provide time for the cause of the problem to die away. A simple port reset (added in a forthcoming patch) will then allow us to recover from the fault. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
b01b03f3ad
commit
24618b0cd4
|
@ -2673,9 +2673,10 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||||
struct usb_device *hdev = hub->hdev;
|
struct usb_device *hdev = hub->hdev;
|
||||||
struct device *hub_dev = hub->intfdev;
|
struct device *hub_dev = hub->intfdev;
|
||||||
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
|
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
|
||||||
u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
|
unsigned wHubCharacteristics =
|
||||||
|
le16_to_cpu(hub->descriptor->wHubCharacteristics);
|
||||||
int status, i;
|
int status, i;
|
||||||
|
|
||||||
dev_dbg (hub_dev,
|
dev_dbg (hub_dev,
|
||||||
"port %d, status %04x, change %04x, %s\n",
|
"port %d, status %04x, change %04x, %s\n",
|
||||||
port1, portstatus, portchange, portspeed (portstatus));
|
port1, portstatus, portchange, portspeed (portstatus));
|
||||||
|
@ -2684,30 +2685,36 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||||
set_port_led(hub, port1, HUB_LED_AUTO);
|
set_port_led(hub, port1, HUB_LED_AUTO);
|
||||||
hub->indicator[port1-1] = INDICATOR_AUTO;
|
hub->indicator[port1-1] = INDICATOR_AUTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disconnect any existing devices under this port */
|
|
||||||
if (hdev->children[port1-1])
|
|
||||||
usb_disconnect(&hdev->children[port1-1]);
|
|
||||||
clear_bit(port1, hub->change_bits);
|
|
||||||
|
|
||||||
#ifdef CONFIG_USB_OTG
|
#ifdef CONFIG_USB_OTG
|
||||||
/* during HNP, don't repeat the debounce */
|
/* during HNP, don't repeat the debounce */
|
||||||
if (hdev->bus->is_b_host)
|
if (hdev->bus->is_b_host)
|
||||||
portchange &= ~USB_PORT_STAT_C_CONNECTION;
|
portchange &= ~(USB_PORT_STAT_C_CONNECTION |
|
||||||
|
USB_PORT_STAT_C_ENABLE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (portchange & USB_PORT_STAT_C_CONNECTION) {
|
/* 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);
|
status = hub_port_debounce(hub, port1);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
if (printk_ratelimit())
|
if (printk_ratelimit())
|
||||||
dev_err (hub_dev, "connect-debounce failed, "
|
dev_err (hub_dev, "connect-debounce failed, "
|
||||||
"port %d disabled\n", port1);
|
"port %d disabled\n", port1);
|
||||||
goto done;
|
portstatus &= ~USB_PORT_STAT_CONNECTION;
|
||||||
|
} else {
|
||||||
|
portstatus = status;
|
||||||
}
|
}
|
||||||
portstatus = status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return now if nothing is connected */
|
/* Disconnect any existing devices under this port */
|
||||||
|
if (hdev->children[port1-1])
|
||||||
|
usb_disconnect(&hdev->children[port1-1]);
|
||||||
|
clear_bit(port1, hub->change_bits);
|
||||||
|
|
||||||
|
/* Return now if debouncing failed or nothing is connected */
|
||||||
if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
|
if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
|
||||||
|
|
||||||
/* maybe switch power back on (e.g. root hub was reset) */
|
/* maybe switch power back on (e.g. root hub was reset) */
|
||||||
|
|
Loading…
Reference in New Issue