diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8ea095e59099baabaae7e6b1cef6fd1d0b3c215c..bc80168957b8b629dba042c0bb4c1361bf1303df 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -130,6 +130,10 @@ MODULE_PARM_DESC(use_both_schemes, DECLARE_RWSEM(ehci_cf_port_reset_rwsem); EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); +#define HUB_DEBOUNCE_TIMEOUT 1500 +#define HUB_DEBOUNCE_STEP 25 +#define HUB_DEBOUNCE_STABLE 100 + static inline char *portspeed(int portstatus) { @@ -643,6 +647,7 @@ static void hub_restart(struct usb_hub *hub, enum hub_activation_type type) { struct usb_device *hdev = hub->hdev; int port1; + bool need_debounce_delay = false; /* Check each port and set hub->change_bits to let khubd know * which ports need attention. @@ -673,6 +678,18 @@ static void hub_restart(struct usb_hub *hub, enum hub_activation_type type) portstatus &= ~USB_PORT_STAT_ENABLE; } + /* Clear status-change flags; we'll debounce later */ + if (portchange & USB_PORT_STAT_C_CONNECTION) { + need_debounce_delay = true; + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_CONNECTION); + } + if (portchange & USB_PORT_STAT_C_ENABLE) { + need_debounce_delay = true; + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_ENABLE); + } + if (!udev || udev->state == USB_STATE_NOTATTACHED) { /* Tell khubd to disconnect the device or * check for a new connection @@ -702,6 +719,16 @@ static void hub_restart(struct usb_hub *hub, enum hub_activation_type type) } } + /* If no port-status-change flags were set, we don't need any + * debouncing. If flags were set we can try to debounce the + * ports all at once right now, instead of letting khubd do them + * one at a time later on. + * + * If any port-status changes do occur during this delay, khubd + * will see them later and handle them normally. + */ + if (need_debounce_delay) + msleep(HUB_DEBOUNCE_STABLE); hub_activate(hub); } @@ -2211,11 +2238,6 @@ static inline int remote_wakeup(struct usb_device *udev) * every 25ms for transient disconnects. When the port status has been * unchanged for 100ms it returns the port status. */ - -#define HUB_DEBOUNCE_TIMEOUT 1500 -#define HUB_DEBOUNCE_STEP 25 -#define HUB_DEBOUNCE_STABLE 100 - static int hub_port_debounce(struct usb_hub *hub, int port1) { int ret;