Further parallelize USB init by launching a thread per usb port.
[seabios.git] / src / usb-uhci.c
index d4497bd134546d8dd11cd7317f483846e99dd750..86eeceabd6cef11029085010b7e772f12d34c079 100644 (file)
 #include "usb.h" // struct usb_s
 #include "farptr.h" // GET_FLATPTR
 #include "biosvar.h" // GET_GLOBAL
+#include "usb-hub.h" // struct usbhub_s
+
+
+/****************************************************************
+ * Root hub
+ ****************************************************************/
+
+static void
+init_uhci_port(void *data)
+{
+    struct usbhub_s *hub = data;
+    u32 port = hub->port; // XXX - find better way to pass port
+    u16 ioport = hub->cntl->uhci.iobase + USBPORTSC1 + port * 2;
+
+    u16 status = inw(ioport);
+    if (!(status & USBPORTSC_CCS))
+        // No device
+        goto done;
+
+    // XXX - if just powered up, need to wait for USB_TIME_ATTDB?
+
+    // Reset port
+    outw(USBPORTSC_PR, ioport);
+    msleep(USB_TIME_DRSTR);
+    mutex_lock(&hub->cntl->resetlock);
+    outw(0, ioport);
+    udelay(6); // 64 high-speed bit times
+    status = inw(ioport);
+    if (!(status & USBPORTSC_CCS))
+        // No longer connected
+        goto resetfail;
+    outw(USBPORTSC_PE, ioport);
+    struct usb_pipe *pipe = usb_set_address(
+        hub->cntl, !!(status & USBPORTSC_LSDA));
+    if (!pipe)
+        goto resetfail;
+    mutex_unlock(&hub->cntl->resetlock);
+
+    // Configure port
+    int count = configure_usb_device(pipe);
+    free_pipe(pipe);
+    if (! count)
+        // Disable port
+        outw(0, ioport);
+    hub->devcount += count;
+done:
+    hub->threads--;
+    return;
+
+resetfail:
+    outw(0, ioport);
+    mutex_unlock(&hub->cntl->resetlock);
+    goto done;
+}
+
+// Find any devices connected to the root hub.
+static int
+check_ports(struct usb_s *cntl)
+{
+    ASSERT32FLAT();
+    struct usbhub_s hub;
+    memset(&hub, 0, sizeof(hub));
+    hub.cntl = cntl;
+    hub.threads = 2;
+
+    // Launch a thread for every port.
+    run_thread(init_uhci_port, &hub);
+    hub.port = 1;
+    run_thread(init_uhci_port, &hub);
+
+    // Wait for threads to complete.
+    while (hub.threads)
+        yield();
+
+    return hub.devcount;
+}
 
 
 /****************************************************************
@@ -90,54 +166,6 @@ start_uhci(struct usb_s *cntl)
     outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, cntl->uhci.iobase + USBCMD);
 }
 
-// Find any devices connected to the root hub.
-static int
-check_ports(struct usb_s *cntl)
-{
-    // XXX - if just powered up, need to wait for USB_TIME_SIGATT?
-    u16 port1 = inw(cntl->uhci.iobase + USBPORTSC1);
-    u16 port2 = inw(cntl->uhci.iobase + USBPORTSC2);
-
-    if (!((port1 & USBPORTSC_CCS) || (port2 & USBPORTSC_CCS)))
-        // No devices
-        return 0;
-
-    // XXX - if just powered up, need to wait for USB_TIME_ATTDB?
-
-    // reset ports
-    if (port1 & USBPORTSC_CCS)
-        outw(USBPORTSC_PR, cntl->uhci.iobase + USBPORTSC1);
-    if (port2 & USBPORTSC_CCS)
-        outw(USBPORTSC_PR, cntl->uhci.iobase + USBPORTSC2);
-    msleep(USB_TIME_DRSTR);
-
-    // Configure ports
-    int totalcount = 0;
-    outw(0, cntl->uhci.iobase + USBPORTSC1);
-    udelay(6); // 64 high-speed bit times
-    port1 = inw(cntl->uhci.iobase + USBPORTSC1);
-    if (port1 & USBPORTSC_CCS) {
-        outw(USBPORTSC_PE, cntl->uhci.iobase + USBPORTSC1);
-        msleep(USB_TIME_RSTRCY);
-        int count = configure_usb_device(cntl, !!(port1 & USBPORTSC_LSDA));
-        if (! count)
-            outw(0, cntl->uhci.iobase + USBPORTSC1);
-        totalcount += count;
-    }
-    outw(0, cntl->uhci.iobase + USBPORTSC2);
-    udelay(6);
-    port2 = inw(cntl->uhci.iobase + USBPORTSC2);
-    if (port2 & USBPORTSC_CCS) {
-        outw(USBPORTSC_PE, cntl->uhci.iobase + USBPORTSC2);
-        msleep(USB_TIME_RSTRCY);
-        int count = configure_usb_device(cntl, !!(port2 & USBPORTSC_LSDA));
-        if (! count)
-            outw(0, cntl->uhci.iobase + USBPORTSC2);
-        totalcount += count;
-    }
-    return totalcount;
-}
-
 void
 uhci_init(void *data)
 {