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