From 827c7224a0aa44530aa8dfe11ec12c0e58bcb054 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sun, 28 Apr 2013 03:19:20 +0200 Subject: [PATCH] Implement debounce sequence according to USB 2.0 specs. This replaces waiting a fixed time of 300ms for the device power to stabilize. In the ideal case this reduces the boot time by 200ms per connected device (including internal hubs). This is very similar to what Linux implements and we use the same time values. An interval of 25ms is used to check for connection state changes, the stable time is at least 100ms as per the USB specs and the whole process times out after 1.5 seconds. --- src/add-ons/kernel/bus_managers/usb/Hub.cpp | 44 ++++++++++++++++++- .../kernel/bus_managers/usb/usb_private.h | 2 + .../kernel/bus_managers/usb/usbspec_private.h | 5 ++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index 271efaffe4..38f01a9878 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -221,8 +221,13 @@ Hub::Explore(change_item **changeList) int32 retry = 2; while (retry--) { - // wait some time for the device to power up - snooze(USB_DELAY_DEVICE_POWER_UP); + // wait for stable device power + result = _DebouncePort(i); + if (result != B_OK) { + TRACE_ERROR("debouncing port %" B_PRId32 + " failed: %s\n", i, strerror(result)); + break; + } // reset the port, this will also enable it result = ResetPort(i); @@ -433,3 +438,38 @@ Hub::BuildDeviceName(char *string, uint32 *index, size_t bufferSize, return B_OK; } + + +status_t +Hub::_DebouncePort(uint8 index) +{ + uint32 timeout = 0; + uint32 stableTime = 0; + while (timeout < USB_DEBOUNCE_TIMEOUT) { + snooze(USB_DEBOUNCE_CHECK_INTERVAL); + timeout += USB_DEBOUNCE_CHECK_INTERVAL; + + status_t result = UpdatePortStatus(index); + if (result != B_OK) + return result; + + if ((fPortStatus[index].change & PORT_STATUS_CONNECTION) == 0) { + stableTime += USB_DEBOUNCE_CHECK_INTERVAL; + if (stableTime >= USB_DEBOUNCE_STABLE_TIME) + return B_OK; + continue; + } + + // clear the connection change and reset stable time + result = DefaultPipe()->SendRequest(USB_REQTYPE_CLASS + | USB_REQTYPE_OTHER_OUT, USB_REQUEST_CLEAR_FEATURE, + C_PORT_CONNECTION, index + 1, 0, NULL, 0, NULL); + if (result != B_OK) + return result; + + TRACE("got connection change during debounce, resetting stable time\n"); + stableTime = 0; + } + + return B_TIMED_OUT; +} diff --git a/src/add-ons/kernel/bus_managers/usb/usb_private.h b/src/add-ons/kernel/bus_managers/usb/usb_private.h index be8b3215ea..4f0ffc6936 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb_private.h +++ b/src/add-ons/kernel/bus_managers/usb/usb_private.h @@ -610,6 +610,8 @@ virtual status_t BuildDeviceName(char *string, Device *device); private: + status_t _DebouncePort(uint8 index); + InterruptPipe * fInterruptPipe; usb_hub_descriptor fHubDescriptor; diff --git a/src/add-ons/kernel/bus_managers/usb/usbspec_private.h b/src/add-ons/kernel/bus_managers/usb/usbspec_private.h index 2103994f74..bd8fbc6b0a 100644 --- a/src/add-ons/kernel/bus_managers/usb/usbspec_private.h +++ b/src/add-ons/kernel/bus_managers/usb/usbspec_private.h @@ -19,7 +19,6 @@ #define USB_MAX_PORT_COUNT 16 #define USB_DELAY_BUS_RESET 100000 -#define USB_DELAY_DEVICE_POWER_UP 300000 #define USB_DELAY_HUB_POWER_UP 200000 #define USB_DELAY_PORT_RESET 50000 #define USB_DELAY_PORT_RESET_RECOVERY 250000 @@ -28,6 +27,10 @@ #define USB_DELAY_SET_CONFIGURATION 50000 #define USB_DELAY_HUB_EXPLORE 1000000 +#define USB_DEBOUNCE_TIMEOUT 1500000 +#define USB_DEBOUNCE_CHECK_INTERVAL 25000 +#define USB_DEBOUNCE_STABLE_TIME 100000 + // For bandwidth calculation #define USB_BW_HOST_DELAY 1000 #define USB_BW_SETUP_LOW_SPEED_PORT_DELAY 333