summaryrefslogtreecommitdiffstats
path: root/src/drivers/usb
diff options
context:
space:
mode:
authorMichael Brown2015-12-07 01:54:01 +0100
committerMichael Brown2015-12-07 14:16:47 +0100
commit53ba5936b5c70b030d81e8f2349d75a7264581ae (patch)
tree10c75d777eacc264aedbe6f5a0136ea637c8b44c /src/drivers/usb
parent[usb] Allow USB device IDs to include arbitrary driver-specific data (diff)
downloadipxe-53ba5936b5c70b030d81e8f2349d75a7264581ae.tar.gz
ipxe-53ba5936b5c70b030d81e8f2349d75a7264581ae.tar.xz
ipxe-53ba5936b5c70b030d81e8f2349d75a7264581ae.zip
[usb] Allow additional settling time for out-of-spec hubs
Some hubs (e.g. the Avocent Corp. Virtual Hub on a Lenovo x3550 Integrated Management Module) have been observed to require more than the standard 200ms for ports to stabilise, with the result that devices appear to disconnect and immediately reconnect during the initial bus enumeration. Work around this problem by allowing specific hubs an extra 500ms of settling time. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/usb')
-rw-r--r--src/drivers/usb/usbhub.c11
-rw-r--r--src/drivers/usb/usbhub.h8
2 files changed, 19 insertions, 0 deletions
diff --git a/src/drivers/usb/usbhub.c b/src/drivers/usb/usbhub.c
index a3e7bc00..7095fc31 100644
--- a/src/drivers/usb/usbhub.c
+++ b/src/drivers/usb/usbhub.c
@@ -155,6 +155,10 @@ static int hub_open ( struct usb_hub *hub ) {
/* Refill interrupt ring */
hub_refill ( hubdev );
+ /* Delay to allow ports to stabilise on out-of-spec hubs */
+ if ( hubdev->flags & USB_HUB_SLOW_START )
+ mdelay ( USB_HUB_SLOW_START_DELAY_MS );
+
return 0;
usb_endpoint_close ( &hubdev->intr );
@@ -410,6 +414,7 @@ static int hub_probe ( struct usb_function *func,
hubdev->usb = usb;
hubdev->features =
( enhanced ? USB_HUB_FEATURES_ENHANCED : USB_HUB_FEATURES );
+ hubdev->flags = func->id->driver_data;
usb_endpoint_init ( &hubdev->intr, usb, &usb_hub_intr_operations );
usb_refill_init ( &hubdev->intr, 0, USB_HUB_INTR_FILL );
process_init_stopped ( &hubdev->refill, &hub_refill_desc, NULL );
@@ -518,6 +523,12 @@ static void hub_remove ( struct usb_function *func ) {
/** USB hub device IDs */
static struct usb_device_id hub_ids[] = {
{
+ .name = "avocent-hub",
+ .vendor = 0x0624,
+ .product = 0x0248,
+ .driver_data = USB_HUB_SLOW_START,
+ },
+ {
.name = "hub",
.vendor = USB_ANY_ID,
.product = USB_ANY_ID,
diff --git a/src/drivers/usb/usbhub.h b/src/drivers/usb/usbhub.h
index d7d8f961..a5f123ac 100644
--- a/src/drivers/usb/usbhub.h
+++ b/src/drivers/usb/usbhub.h
@@ -257,6 +257,8 @@ struct usb_hub_device {
struct usb_hub *hub;
/** Features */
unsigned int features;
+ /** Flags */
+ unsigned int flags;
/** Interrupt endpoint */
struct usb_endpoint intr;
@@ -264,6 +266,12 @@ struct usb_hub_device {
struct process refill;
};
+/** Hub requires additional settling delay */
+#define USB_HUB_SLOW_START 0x0001
+
+/** Additional setting delay for out-of-spec hubs */
+#define USB_HUB_SLOW_START_DELAY_MS 500
+
/** Interrupt ring fill level
*
* This is a policy decision.