aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hub.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-04-28 11:06:28 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-07-21 18:15:47 -0400
commit24618b0cd42f936cda461bdf6144670a5c925178 (patch)
treedfcc0d831eb24f7466bbb3ebb2a69b3d93622120 /drivers/usb/core/hub.c
parentb01b03f3ad82b4293f6ca4da9b2692b6a377c609 (diff)
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>
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r--drivers/usb/core/hub.c31
1 files changed, 19 insertions, 12 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index d14da2123eb5..d741b9457427 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2673,9 +2673,10 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
2673 struct usb_device *hdev = hub->hdev; 2673 struct usb_device *hdev = hub->hdev;
2674 struct device *hub_dev = hub->intfdev; 2674 struct device *hub_dev = hub->intfdev;
2675 struct usb_hcd *hcd = bus_to_hcd(hdev->bus); 2675 struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
2676 u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); 2676 unsigned wHubCharacteristics =
2677 le16_to_cpu(hub->descriptor->wHubCharacteristics);
2677 int status, i; 2678 int status, i;
2678 2679
2679 dev_dbg (hub_dev, 2680 dev_dbg (hub_dev,
2680 "port %d, status %04x, change %04x, %s\n", 2681 "port %d, status %04x, change %04x, %s\n",
2681 port1, portstatus, portchange, portspeed (portstatus)); 2682 port1, portstatus, portchange, portspeed (portstatus));
@@ -2684,30 +2685,36 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
2684 set_port_led(hub, port1, HUB_LED_AUTO); 2685 set_port_led(hub, port1, HUB_LED_AUTO);
2685 hub->indicator[port1-1] = INDICATOR_AUTO; 2686 hub->indicator[port1-1] = INDICATOR_AUTO;
2686 } 2687 }
2687
2688 /* Disconnect any existing devices under this port */
2689 if (hdev->children[port1-1])
2690 usb_disconnect(&hdev->children[port1-1]);
2691 clear_bit(port1, hub->change_bits);
2692 2688
2693#ifdef CONFIG_USB_OTG 2689#ifdef CONFIG_USB_OTG
2694 /* during HNP, don't repeat the debounce */ 2690 /* during HNP, don't repeat the debounce */
2695 if (hdev->bus->is_b_host) 2691 if (hdev->bus->is_b_host)
2696 portchange &= ~USB_PORT_STAT_C_CONNECTION; 2692 portchange &= ~(USB_PORT_STAT_C_CONNECTION |
2693 USB_PORT_STAT_C_ENABLE);
2697#endif 2694#endif
2698 2695
2699 if (portchange & USB_PORT_STAT_C_CONNECTION) { 2696 /* Try to use the debounce delay for protection against
2697 * port-enable changes caused, for example, by EMI.
2698 */
2699 if (portchange & (USB_PORT_STAT_C_CONNECTION |
2700 USB_PORT_STAT_C_ENABLE)) {
2700 status = hub_port_debounce(hub, port1); 2701 status = hub_port_debounce(hub, port1);
2701 if (status < 0) { 2702 if (status < 0) {
2702 if (printk_ratelimit()) 2703 if (printk_ratelimit())
2703 dev_err (hub_dev, "connect-debounce failed, " 2704 dev_err (hub_dev, "connect-debounce failed, "
2704 "port %d disabled\n", port1); 2705 "port %d disabled\n", port1);
2705 goto done; 2706 portstatus &= ~USB_PORT_STAT_CONNECTION;
2707 } else {
2708 portstatus = status;
2706 } 2709 }
2707 portstatus = status;
2708 } 2710 }
2709 2711
2710 /* Return now if nothing is connected */ 2712 /* Disconnect any existing devices under this port */
2713 if (hdev->children[port1-1])
2714 usb_disconnect(&hdev->children[port1-1]);
2715 clear_bit(port1, hub->change_bits);
2716
2717 /* Return now if debouncing failed or nothing is connected */
2711 if (!(portstatus & USB_PORT_STAT_CONNECTION)) { 2718 if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
2712 2719
2713 /* maybe switch power back on (e.g. root hub was reset) */ 2720 /* maybe switch power back on (e.g. root hub was reset) */