Support non-local build directory - allow "make OUT=abc/" to work.
[seabios.git] / src / usb-ehci.c
index 8e3219f923844615c478fe7c35f6c32115b5b934..f11924afcf91725bb3c46b7d62d87aeb022c6c91 100644 (file)
@@ -13,7 +13,6 @@
 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
 #include "usb.h" // struct usb_s
 #include "farptr.h" // GET_FLATPTR
-#include "usb-hub.h" // struct usbhub_s
 #include "usb-uhci.h" // init_uhci
 #include "usb-ohci.h" // init_ohci
 
@@ -40,13 +39,17 @@ struct usb_ehci_s {
 #define EHCI_TIME_POSTPOWER 20
 #define EHCI_TIME_POSTRESET 2
 
-// Start processing of companion controllers for full/low speed devices
+// Check if need companion controllers for full/low speed devices
 static void
-ehci_startcompanion(struct usb_ehci_s *cntl)
+ehci_note_port(struct usb_ehci_s *cntl)
 {
+    if (--cntl->checkports)
+        // Ports still being detected.
+        return;
     if (! cntl->legacycount)
         // No full/low speed devices found.
         return;
+    // Start companion controllers.
     int i;
     for (i=0; i<ARRAY_SIZE(cntl->companion); i++) {
         u16 type = cntl->companion[i].type;
@@ -59,13 +62,11 @@ ehci_startcompanion(struct usb_ehci_s *cntl)
     }
 }
 
-static void
-init_ehci_port(void *data)
+// Check if device attached to port
+static int
+ehci_hub_detect(struct usbhub_s *hub, u32 port)
 {
-    struct usbhub_s *hub = data;
-    u32 port = hub->port; // XXX - find better way to pass port
     struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb);
-
     u32 *portreg = &cntl->regs->portsc[port];
     u32 portsc = readl(portreg);
 
@@ -92,15 +93,31 @@ init_ehci_port(void *data)
 
     // XXX - if just powered up, need to wait for USB_TIME_ATTDB?
 
-    // Reset port
+    // Begin reset on port
     portsc = (portsc & ~PORT_PE) | PORT_RESET;
     writel(portreg, portsc);
     msleep(USB_TIME_DRSTR);
-    mutex_lock(&cntl->usb.resetlock);
+    return 0;
+
+doneearly:
+    ehci_note_port(cntl);
+    return -1;
+}
+
+// Reset device on port
+static int
+ehci_hub_reset(struct usbhub_s *hub, u32 port)
+{
+    struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb);
+    u32 *portreg = &cntl->regs->portsc[port];
+    u32 portsc = readl(portreg);
+
+    // Finish reset on port
     portsc &= ~PORT_RESET;
     writel(portreg, portsc);
     msleep(EHCI_TIME_POSTRESET);
 
+    int rv = -1;
     portsc = readl(portreg);
     if (!(portsc & PORT_CONNECT))
         // No longer connected
@@ -112,58 +129,39 @@ init_ehci_port(void *data)
         goto resetfail;
     }
 
-    if (! --cntl->checkports)
-        ehci_startcompanion(cntl);
-
-    struct usb_pipe *pipe = usb_set_address(hub, port, USB_HIGHSPEED);
-    if (!pipe) {
-        writel(portreg, portsc & ~PORT_PE);
-        mutex_unlock(&cntl->usb.resetlock);
-        goto done;
-    }
-    mutex_unlock(&cntl->usb.resetlock);
-
-    // Configure port
-    int count = configure_usb_device(pipe);
-    free_pipe(pipe);
-    if (! count)
-        // Disable port
-        writel(portreg, portsc & ~PORT_PE);
-    hub->devcount += count;
-done:
-    hub->threads--;
-    return;
-
+    rv = USB_HIGHSPEED;
 resetfail:
-    mutex_unlock(&cntl->usb.resetlock);
-doneearly:
-    if (! --cntl->checkports)
-        ehci_startcompanion(cntl);
-    goto done;
+    ehci_note_port(cntl);
+    return rv;
+}
+
+// Disable port
+static void
+ehci_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+    struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb);
+    u32 *portreg = &cntl->regs->portsc[port];
+    u32 portsc = readl(portreg);
+    writel(portreg, portsc & ~PORT_PE);
 }
 
+static struct usbhub_op_s ehci_HubOp = {
+    .detect = ehci_hub_detect,
+    .reset = ehci_hub_reset,
+    .disconnect = ehci_hub_disconnect,
+};
+
 // Find any devices connected to the root hub.
 static int
 check_ehci_ports(struct usb_ehci_s *cntl)
 {
     ASSERT32FLAT();
-
-    // Launch a thread for every port.
     struct usbhub_s hub;
     memset(&hub, 0, sizeof(hub));
     hub.cntl = &cntl->usb;
-    int ports = cntl->checkports;
-    hub.threads = ports;
-    int i;
-    for (i=0; i<ports; i++) {
-        hub.port = i;
-        run_thread(init_ehci_port, &hub);
-    }
-
-    // Wait for threads to complete.
-    while (hub.threads)
-        yield();
-
+    hub.portcount = cntl->checkports;
+    hub.op = &ehci_HubOp;
+    usb_enumerate(&hub);
     return hub.devcount;
 }
 
@@ -196,10 +194,11 @@ configure_ehci(void *data)
         cmd = readl(&cntl->regs->usbcmd);
         if (!(cmd & CMD_HCRESET))
             break;
-        if (check_time(end)) {
+        if (check_tsc(end)) {
             warn_timeout();
             goto fail;
         }
+        yield();
     }
 
     // Disable interrupts (just to be safe).
@@ -266,6 +265,7 @@ ehci_init(u16 bdf, int busid, int compbdf)
     struct usb_ehci_s *cntl = malloc_tmphigh(sizeof(*cntl));
     memset(cntl, 0, sizeof(*cntl));
     cntl->usb.busid = busid;
+    cntl->usb.bdf = bdf;
     cntl->usb.type = USB_TYPE_EHCI;
     cntl->caps = caps;
     cntl->regs = (void*)caps + readb(&caps->caplength);
@@ -315,7 +315,7 @@ ehci_wait_qh(struct usb_ehci_s *cntl, struct ehci_qh *qh)
         if (qh->qtd_next & EHCI_PTR_TERM)
             // XXX - confirm
             return 0;
-        if (check_time(end)) {
+        if (check_tsc(end)) {
             warn_timeout();
             return -1;
         }
@@ -342,7 +342,7 @@ ehci_waittick(struct usb_ehci_s *cntl)
             if (!(cmd & CMD_IAAD))
                 break;
         }
-        if (check_time(end)) {
+        if (check_tsc(end)) {
             warn_timeout();
             return;
         }
@@ -355,7 +355,7 @@ ehci_waittick(struct usb_ehci_s *cntl)
         sts = readl(&cntl->regs->usbsts);
         if (sts & STS_IAA)
             break;
-        if (check_time(end)) {
+        if (check_tsc(end)) {
             warn_timeout();
             return;
         }
@@ -567,7 +567,7 @@ ehci_wait_td(struct ehci_qtd *td)
         status = td->token;
         if (!(status & QTD_STS_ACTIVE))
             break;
-        if (check_time(end)) {
+        if (check_tsc(end)) {
             warn_timeout();
             return -1;
         }