Skip to content

Commit

Permalink
USB: optimize port debouncing during hub activation
Browse files Browse the repository at this point in the history
This patch (as1082) makes a small optimization to the way the hub
driver carries out port debouncing immediately after a hub is
activated (i.e., initialized, reset, or resumed).  If any port-change
statuses are observed, the code will delay for a minimal debounce
period -- thereby making a good start at debouncing all the ports at
once.

If this wasn't sufficient then khubd will debounce any port that still
requires attention.  But in most cases it should suffice; it's rare
for a device to need more than a minimal debounce delay.  (In the
cases of hub initialization or reset even that is most likely not
needed, since any devices plugged in at such times have probably been
attached for a while.)

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Jul 21, 2008
1 parent 8808f00 commit 948fea3
Showing 1 changed file with 27 additions and 5 deletions.
32 changes: 27 additions & 5 deletions drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 948fea3

Please sign in to comment.