grml...
[seabios.git] / src / usb-uhci.c
index 65498089d6ca0845fd7b80e1c1928ef09ebdb271..a78dbcaf63e679ac55d1c8f3fc11fd93454ec6b0 100644 (file)
@@ -179,13 +179,19 @@ fail:
 }
 
 void
-uhci_init(u16 bdf, int busid)
+uhci_init(struct pci_device *pci, int busid)
 {
     if (! CONFIG_USB_UHCI)
         return;
+    u16 bdf = pci->bdf;
     struct usb_uhci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+    if (!cntl) {
+        warn_noalloc();
+        return;
+    }
     memset(cntl, 0, sizeof(*cntl));
     cntl->usb.busid = busid;
+    cntl->usb.pci = pci;
     cntl->usb.type = USB_TYPE_UHCI;
     cntl->iobase = (pci_config_readl(bdf, PCI_BASE_ADDRESS_4)
                     & PCI_BASE_ADDRESS_IO_MASK);
@@ -206,26 +212,13 @@ uhci_init(u16 bdf, int busid)
  * End point communication
  ****************************************************************/
 
-static int
-wait_qh(struct usb_uhci_s *cntl, struct uhci_qh *qh)
-{
-    // XXX - 500ms just a guess
-    u64 end = calc_future_tsc(500);
-    for (;;) {
-        if (qh->element & UHCI_PTR_TERM)
-            return 0;
-        if (check_tsc(end)) {
-            warn_timeout();
-            struct uhci_td *td = (void*)(qh->element & ~UHCI_PTR_BITS);
-            dprintf(1, "Timeout on wait_qh %p (td=%p s=%x c=%x/%x)\n"
-                    , qh, td, td->status
-                    , inw(cntl->iobase + USBCMD)
-                    , inw(cntl->iobase + USBSTS));
-            return -1;
-        }
-        yield();
-    }
-}
+struct uhci_pipe {
+    struct uhci_qh qh;
+    struct uhci_td *next_td;
+    struct usb_pipe pipe;
+    u16 iobase;
+    u8 toggle;
+};
 
 // Wait for next USB frame to start - for ensuring safe memory release.
 static void
@@ -245,13 +238,29 @@ uhci_waittick(u16 iobase)
     }
 }
 
-struct uhci_pipe {
-    struct uhci_qh qh;
-    struct uhci_td *next_td;
-    struct usb_pipe pipe;
-    u16 iobase;
-    u8 toggle;
-};
+static int
+wait_pipe(struct uhci_pipe *pipe, int timeout)
+{
+    u64 end = calc_future_tsc(timeout);
+    for (;;) {
+        u32 el_link = GET_FLATPTR(pipe->qh.element);
+        if (el_link & UHCI_PTR_TERM)
+            return 0;
+        if (check_tsc(end)) {
+            warn_timeout();
+            u16 iobase = GET_FLATPTR(pipe->iobase);
+            struct uhci_td *td = (void*)(el_link & ~UHCI_PTR_BITS);
+            dprintf(1, "Timeout on wait_pipe %p (td=%p s=%x c=%x/%x)\n"
+                    , pipe, (void*)el_link, GET_FLATPTR(td->status)
+                    , inw(iobase + USBCMD)
+                    , inw(iobase + USBSTS));
+            SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM);
+            uhci_waittick(iobase);
+            return -1;
+        }
+        yield();
+    }
+}
 
 void
 uhci_free_pipe(struct usb_pipe *p)
@@ -325,8 +334,6 @@ uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
         return -1;
     dprintf(5, "uhci_control %p\n", p);
     struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
-    struct usb_uhci_s *cntl = container_of(
-        pipe->pipe.cntl, struct usb_uhci_s, usb);
 
     int maxpacket = pipe->pipe.maxpacket;
     int lowspeed = pipe->pipe.speed;
@@ -370,11 +377,7 @@ uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
     // Transfer data
     barrier();
     pipe->qh.element = (u32)&tds[0];
-    int ret = wait_qh(cntl, &pipe->qh);
-    if (ret) {
-        pipe->qh.element = UHCI_PTR_TERM;
-        uhci_waittick(pipe->iobase);
-    }
+    int ret = wait_pipe(pipe, 500);
     free(tds);
     return ret;
 }
@@ -481,16 +484,8 @@ uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
         data += transfer;
         datasize -= transfer;
     }
-    int i;
-    for (i=0; i<STACKTDS; i++) {
-        struct uhci_td *td = &tds[tdpos++ % STACKTDS];
-        int ret = wait_td(td);
-        if (ret)
-            goto fail;
-    }
-
     SET_FLATPTR(pipe->toggle, !!toggle);
-    return 0;
+    return wait_pipe(pipe, 5000);
 fail:
     dprintf(1, "uhci_send_bulk failed\n");
     SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM);