[SeaBIOS] [PATCH RFC] Quite hacky patch to get USB ehci working on bare metal.

Christian Gmeiner christian.gmeiner at gmail.com
Mon Jan 14 16:55:33 CET 2013


Some results can be found here:
http://dpaste.com/876523/

Before this patch I got a timeout at Inquiry.

Signed-off-by: Christian Gmeiner <christian.gmeiner at gmail.com>
---
 src/usb-ehci.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 75 insertions(+), 2 deletions(-)

diff --git a/src/usb-ehci.c b/src/usb-ehci.c
index 2676615..0b71935 100644
--- a/src/usb-ehci.c
+++ b/src/usb-ehci.c
@@ -173,6 +173,34 @@ check_ehci_ports(struct usb_ehci_s *cntl)
     return hub.devcount;
 }
 
+static int ehci_set_async_schedule(struct usb_ehci_s *ehcic, int enable)
+{
+    dprintf(7, "%s: enable %d\n", __func__, enable);
+
+    // Set async schedule status.
+    u32 cmd = readl(&ehcic->regs->usbcmd);
+    if (enable)
+        cmd |= CMD_ASE;
+    else
+        cmd &= ~CMD_ASE;
+
+    writel(&ehcic->regs->usbcmd, cmd);
+
+   /* Wait for the controller to accept async schedule status.
+     * This shouldn't take too long, but we should timeout nevertheless.
+     */
+    enable = enable ? STS_ASS : 0;
+    int timeout = 100; /* time out after 100ms */
+    while (((readl(&ehcic->regs->usbsts) & STS_ASS) != enable)
+            && timeout--)
+        mdelay(1);
+    if (timeout < 0) {
+        dprintf(7, "ehci async schedule status change timed out.\n");
+        return 1;
+    }
+    return 0;
+}
+
 
 /****************************************************************
  * Setup
@@ -410,6 +438,8 @@ ehci_desc2pipe(struct ehci_pipe *pipe, struct usbdevice_s *usbdev
                            | QH_TOGGLECONTROL);
     else if (eptype == USB_ENDPOINT_XFER_INT)
         pipe->qh.info2 |= (0x01 << QH_SMASK_SHIFT) | (0x1c << QH_CMASK_SHIFT);
+    else if (eptype == USB_ENDPOINT_XFER_BULK)
+        pipe->qh.info1 |= QH_TOGGLECONTROL;
 }
 
 static struct usb_pipe *
@@ -561,6 +591,9 @@ ehci_wait_td(struct ehci_pipe *pipe, struct ehci_qtd *td, int timeout)
 static int
 fillTDbuffer(struct ehci_qtd *td, u16 maxpacket, const void *buf, int bytes)
 {
+    dprintf(1, "%s\t", __func__);
+    hexdump(buf, bytes);
+
     u32 dest = (u32)buf;
     u32 *pos = td->buf;
     while (bytes) {
@@ -649,9 +682,19 @@ ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
     if (! CONFIG_USB_EHCI)
         return -1;
     struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
-    dprintf(7, "ehci_send_bulk qh=%p dir=%d data=%p size=%d\n"
+    dprintf(1, "ehci_send_bulk qh=%p dir=%d data=%p size=%d\n"
             , &pipe->qh, dir, data, datasize);
 
+    dprintf(1, "data:");
+    hexdump(data, datasize);
+
+
+    struct usb_ehci_s *ehcic = container_of(
+        GET_LOWFLAT(pipe->pipe.cntl), struct usb_ehci_s, usb);
+
+    // stop async schedule
+    ehci_set_async_schedule(ehcic, 0);
+
     // Allocate 4 tds on stack (with required alignment)
     u8 tdsbuf[sizeof(struct ehci_qtd) * STACKQTDS + EHCI_QTD_ALIGN - 1];
     struct ehci_qtd *tds = (void*)ALIGN((u32)tdsbuf, EHCI_QTD_ALIGN);
@@ -661,12 +704,17 @@ ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
 
     u16 maxpacket = GET_LOWFLAT(pipe->pipe.maxpacket);
     int tdpos = 0;
+    struct ehci_qtd *last = &tds[0];
+    int num = 0;
+    int chgm;
+
     while (datasize) {
         struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS];
+/*
         int ret = ehci_wait_td(pipe, td, 5000);
         if (ret)
             return -1;
-
+*/
         struct ehci_qtd *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS)
                                                  , &tds[tdpos % STACKQTDS]);
 
@@ -677,9 +725,29 @@ ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
         td->token = (ehci_explen(transfer) | QTD_STS_ACTIVE
                      | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3));
 
+        /* dump td buf */
+        dprintf(1, "td #%d buf\t", num);
+        for (chgm = 0; chgm < ARRAY_SIZE(td->buf); chgm++) {
+            dprintf(1, "\tpointer %d: 0x%08x\n", chgm, td->buf[chgm]);
+
+            if (td->buf[chgm] != 0) {
+                hexdump((const void *)td->buf[chgm], transfer);
+            }
+        }
+
         data += transfer;
         datasize -= transfer;
+        num++;
     }
+
+    dprintf(1, "ehci_send_bulk needs %d td's\n", num);
+
+    /* update based on endpoint toggle */
+    tds[0].token  |= (pipe->pipe.toogle?QTD_TOGGLE:0);
+    pipe->qh.token|= (pipe->pipe.toogle?QTD_TOGGLE:0);
+
+    ehci_set_async_schedule(ehcic, 1);
+
     int i;
     for (i=0; i<STACKQTDS; i++) {
         struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS];
@@ -688,6 +756,11 @@ ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
             return -1;
     }
 
+    ehci_set_async_schedule(ehcic, 0);
+
+    /* update endpoint toggle based on device */
+    pipe->pipe.toogle = (last->token & QTD_TOGGLE) >> 31;
+
     return 0;
 }
 
-- 
1.7.12.2.421.g261b511




More information about the SeaBIOS mailing list