[SeaBIOS] [PATCH 7/7] usb: Perform device detect polling on all usb controllers.

Kevin O'Connor kevin at koconnor.net
Wed Sep 10 20:46:06 CEST 2014


Move the 100ms (USB_TIME_SIGATT) device detect polling from the
ohci/uhci/usb-hub code to the generic usb_hub_port_setup() code.  This
extends the 100ms polling to ehci and xhci controllers.  The code in
usb_hub_port_setup() now compares USB_TIME_SIGATT to the start of
usb_enumerate(), which may make boots faster when threads are
disabled.

This patch also changes the meaning of the return code for
hub->op->detect() calls.  Now 1 indicates device found, 0 indicates
device not found, and -1 indicates permanent failure.

Also, the xhci controller generic delay of 100ms is replaced with a
20ms root hub power stabilize time.  This in combination with the
100ms for USB_TIME_SIGATT should be closer to the USB2 spec (the USB3
spec does not seem to declare an equivalent of USB_TIME_SIGATT).

Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
 src/hw/usb-ehci.c |  4 ++--
 src/hw/usb-hub.c  | 26 +++++---------------------
 src/hw/usb-ohci.c | 17 ++---------------
 src/hw/usb-uhci.c | 18 +++++-------------
 src/hw/usb-xhci.c |  8 +++++---
 src/hw/usb.c      | 21 +++++++++++++++------
 src/hw/usb.h      |  1 +
 7 files changed, 35 insertions(+), 60 deletions(-)

diff --git a/src/hw/usb-ehci.c b/src/hw/usb-ehci.c
index 86496ce..20e387b 100644
--- a/src/hw/usb-ehci.c
+++ b/src/hw/usb-ehci.c
@@ -52,7 +52,7 @@ ehci_hub_detect(struct usbhub_s *hub, u32 port)
 
     if (!(portsc & PORT_CONNECT))
         // No device present
-        return -1;
+        return 0;
 
     if ((portsc & PORT_LINESTATUS_MASK) == PORT_LINESTATUS_KSTATE) {
         // low speed device
@@ -66,7 +66,7 @@ ehci_hub_detect(struct usbhub_s *hub, u32 port)
     portsc = (portsc & ~PORT_PE) | PORT_RESET;
     writel(portreg, portsc);
     msleep(USB_TIME_DRSTR);
-    return 0;
+    return 1;
 }
 
 // Reset device on port
diff --git a/src/hw/usb-hub.c b/src/hw/usb-hub.c
index 2a34e57..4731a91 100644
--- a/src/hw/usb-hub.c
+++ b/src/hw/usb-hub.c
@@ -72,29 +72,13 @@ get_port_status(struct usbhub_s *hub, int port, struct usb_port_status *sts)
 static int
 usb_hub_detect(struct usbhub_s *hub, u32 port)
 {
-    // Check periodically for a device connect.
     struct usb_port_status sts;
-    u32 end = timer_calc(USB_TIME_SIGATT);
-    for (;;) {
-        int ret = get_port_status(hub, port, &sts);
-        if (ret)
-            goto fail;
-        if (sts.wPortStatus & USB_PORT_STAT_CONNECTION)
-            // Device connected.
-            break;
-        if (timer_check(end))
-            // No device found.
-            return -1;
-        msleep(5);
+    int ret = get_port_status(hub, port, &sts);
+    if (ret) {
+        dprintf(1, "Failure on hub port %d detect\n", port);
+        return -1;
     }
-
-    // XXX - wait USB_TIME_ATTDB time?
-
-    return 0;
-
-fail:
-    dprintf(1, "Failure on hub port %d detect\n", port);
-    return -1;
+    return (sts.wPortStatus & USB_PORT_STAT_CONNECTION) ? 1 : 0;
 }
 
 // Disable port
diff --git a/src/hw/usb-ohci.c b/src/hw/usb-ohci.c
index 8089e13..7a22057 100644
--- a/src/hw/usb-ohci.c
+++ b/src/hw/usb-ohci.c
@@ -42,21 +42,8 @@ static int
 ohci_hub_detect(struct usbhub_s *hub, u32 port)
 {
     struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
-    u32 end = timer_calc(USB_TIME_SIGATT);
-    for (;;) {
-        u32 sts = readl(&cntl->regs->roothub_portstatus[port]);
-        if (sts & RH_PS_CCS)
-            // Device connected.
-            break;
-        if (timer_check(end))
-            // No device found.
-            return -1;
-        msleep(5);
-    }
-
-    // XXX - need to wait for USB_TIME_ATTDB if just powered up?
-
-    return 0;
+    u32 sts = readl(&cntl->regs->roothub_portstatus[port]);
+    return (sts & RH_PS_CCS) ? 1 : 0;
 }
 
 // Disable port
diff --git a/src/hw/usb-uhci.c b/src/hw/usb-uhci.c
index 406af90..a34f6db 100644
--- a/src/hw/usb-uhci.c
+++ b/src/hw/usb-uhci.c
@@ -43,25 +43,17 @@ uhci_hub_detect(struct usbhub_s *hub, u32 port)
 {
     struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
     u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
-
-    u32 end = timer_calc(USB_TIME_SIGATT);
-    for (;;) {
-        u16 status = inw(ioport);
-        if (status & USBPORTSC_CCS)
-            // Device connected.
-            break;
-        if (timer_check(end))
-            // No device found.
-            return -1;
-        msleep(5);
-    }
+    u16 status = inw(ioport);
+    if (!(status & USBPORTSC_CCS))
+        // No device found.
+        return 0;
 
     // XXX - if just powered up, need to wait for USB_TIME_ATTDB?
 
     // Begin reset on port
     outw(USBPORTSC_PR, ioport);
     msleep(USB_TIME_DRSTR);
-    return 0;
+    return 1;
 }
 
 // Reset device on port
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c
index 5f91d89..eafa4cb 100644
--- a/src/hw/usb-xhci.c
+++ b/src/hw/usb-xhci.c
@@ -320,6 +320,8 @@ static int wait_bit(u32 *reg, u32 mask, int value, u32 timeout)
  * Root hub
  ****************************************************************/
 
+#define XHCI_TIME_POSTPOWER 20
+
 // Check if device attached to port
 static void
 xhci_print_port_state(int loglevel, const char *prefix, u32 port, u32 portsc)
@@ -339,7 +341,7 @@ xhci_hub_detect(struct usbhub_s *hub, u32 port)
 {
     struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb);
     u32 portsc = readl(&xhci->pr[port].portsc);
-    return (portsc & XHCI_PORTSC_CCS) ? 0 : -1;
+    return (portsc & XHCI_PORTSC_CCS) ? 1 : 0;
 }
 
 // Reset device on port
@@ -388,8 +390,8 @@ static struct usbhub_op_s xhci_hub_ops = {
 static int
 xhci_check_ports(struct usb_xhci_s *xhci)
 {
-    // FIXME: try find a more elegant way than a fixed delay
-    msleep(100);
+    // Wait for port power to stabilize.
+    msleep(XHCI_TIME_POSTPOWER);
 
     struct usbhub_s hub;
     memset(&hub, 0, sizeof(hub));
diff --git a/src/hw/usb.c b/src/hw/usb.c
index 930b5d9..153e153 100644
--- a/src/hw/usb.c
+++ b/src/hw/usb.c
@@ -404,15 +404,23 @@ usb_hub_port_setup(void *data)
     struct usbhub_s *hub = usbdev->hub;
     u32 port = usbdev->port;
 
-    // Detect if device present (and possibly start reset)
-    int ret = hub->op->detect(hub, port);
-    if (ret)
-        // No device present
-        goto done;
+    for (;;) {
+        // Detect if device present (and possibly start reset)
+        int ret = hub->op->detect(hub, port);
+        if (ret > 0)
+            // Device connected.
+            break;
+        if (ret < 0 || timer_check(hub->detectend))
+            // No device found.
+            goto done;
+        msleep(5);
+    }
+
+    // XXX - wait USB_TIME_ATTDB time?
 
     // Reset port and determine device speed
     mutex_lock(&hub->cntl->resetlock);
-    ret = hub->op->reset(hub, port);
+    int ret = hub->op->reset(hub, port);
     if (ret < 0)
         // Reset failed
         goto resetfail;
@@ -447,6 +455,7 @@ usb_enumerate(struct usbhub_s *hub)
 {
     u32 portcount = hub->portcount;
     hub->threads = portcount;
+    hub->detectend = timer_calc(USB_TIME_SIGATT);
 
     // Launch a thread for every port.
     int i;
diff --git a/src/hw/usb.h b/src/hw/usb.h
index 223e4d6..fe80ea6 100644
--- a/src/hw/usb.h
+++ b/src/hw/usb.h
@@ -46,6 +46,7 @@ struct usbhub_s {
     struct usbdevice_s *usbdev;
     struct usb_s *cntl;
     struct mutex_s lock;
+    u32 detectend;
     u32 port;
     u32 threads;
     u32 portcount;
-- 
1.9.3




More information about the SeaBIOS mailing list