Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24618b0c authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent b01b03f3
Loading
Loading
Loading
Loading
+19 −12
Original line number Diff line number Diff line
@@ -2673,7 +2673,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
	struct usb_device *hdev = hub->hdev;
	struct device *hub_dev = hub->intfdev;
	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;

	dev_dbg (hub_dev,
@@ -2685,29 +2686,35 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
		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
	/* during HNP, don't repeat the debounce */
	if (hdev->bus->is_b_host)
		portchange &= ~USB_PORT_STAT_C_CONNECTION;
		portchange &= ~(USB_PORT_STAT_C_CONNECTION |
				USB_PORT_STAT_C_ENABLE);
#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);
		if (status < 0) {
			if (printk_ratelimit())
				dev_err (hub_dev, "connect-debounce failed, "
						"port %d disabled\n", port1);
			goto done;
		}
			portstatus &= ~USB_PORT_STAT_CONNECTION;
		} else {
			portstatus = status;
		}
	}

	/* 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 nothing is connected */
	/* 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) */