ChangeSet 1.866, 2002/12/10 14:18:40-08:00, zaitcev@redhat.com [PATCH] Patch for debounce in 2.5 I was getting annoyed that nobody fixed the obviously broken debounce loop, so I had to go ahead and fix that. diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Fri Dec 13 17:19:23 2002 +++ b/drivers/usb/core/hub.c Fri Dec 13 17:19:23 2002 @@ -768,35 +768,49 @@ * Not covered by the spec - but easy to deal with. * * This implementation uses 400ms minimum debounce timeout and checks - * every 100ms for transient disconnects to restart the delay. + * every 25ms for transient disconnects to restart the delay. */ #define HUB_DEBOUNCE_TIMEOUT 400 -#define HUB_DEBOUNCE_STEP 100 +#define HUB_DEBOUNCE_STEP 25 +#define HUB_DEBOUNCE_STABLE 4 /* return: -1 on error, 0 on success, 1 on disconnect. */ static int usb_hub_port_debounce(struct usb_device *hub, int port) { int ret; - unsigned delay_time; + int delay_time, stable_count; u16 portchange, portstatus; + unsigned connection; - for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; /* empty */ ) { - - /* wait debounce step increment */ + connection = 0; + stable_count = 0; + for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) { wait_ms(HUB_DEBOUNCE_STEP); ret = usb_hub_port_status(hub, port, &portstatus, &portchange); if (ret < 0) return -1; + if ((portstatus & USB_PORT_STAT_CONNECTION) == connection) { + if (connection) { + if (++stable_count == HUB_DEBOUNCE_STABLE) + break; + } + } else { + stable_count = 0; + } + connection = portstatus & USB_PORT_STAT_CONNECTION; + if ((portchange & USB_PORT_STAT_C_CONNECTION)) { usb_clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION); - delay_time = 0; } - else - delay_time += HUB_DEBOUNCE_STEP; } + + /* XXX Replace this with dbg() when 2.6 is about to ship. */ + info("debounce: hub %d port %d: delay %dms stable %d status 0x%x\n", + hub->devnum, port, delay_time, stable_count, portstatus); + return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1; }