Prefer passing a USB "pipe" structure over a USB endp encoding.
authorKevin O'Connor <kevin@koconnor.net>
Fri, 26 Feb 2010 13:57:13 +0000 (08:57 -0500)
committerKevin O'Connor <kevin@koconnor.net>
Sun, 28 Feb 2010 22:26:25 +0000 (17:26 -0500)
Instead of passing the "u32 endp" encoding of the usb endpoint,
allocate a "struct usb_pipe" for each end point and pass that.
Allocate a control pipe for every device found.  Support freeing the
pipes after they are done.

Implement pipe allocation and freeing for both UHCI and OHCI
controllers.

Also, don't define every UHCI qh to include a pipe - create a separate
structure "struct uhci_pipe".  Also, be sure to clear the
USBControllers on reset.  Also, convert usb_hub_init to return 0 on
success.  Also, cleanup some of the USB debug messages to make them
more consistent.

13 files changed:
src/ps2port.c
src/usb-hid.c
src/usb-hid.h
src/usb-hub.c
src/usb-hub.h
src/usb-msc.c
src/usb-msc.h
src/usb-ohci.c
src/usb-ohci.h
src/usb-uhci.c
src/usb-uhci.h
src/usb.c
src/usb.h

index 49bf551c58e2fe9f5283485b3673d8547685318d..26c55f28ee8ef6d3ae3221a9deb23680bbbee57d 100644 (file)
@@ -415,7 +415,7 @@ keyboard_init(void *data)
     if (ret)
         return;
 
-    dprintf(1, "keyboard initialized\n");
+    dprintf(1, "PS2 keyboard initialized\n");
 }
 
 void
index ae166860f969caadd0af983bf48b6010c656917f..eae68235191893197cb872774bbc5ada025ec4f9 100644 (file)
@@ -18,7 +18,7 @@ struct usb_pipe *keyboard_pipe VAR16VISIBLE;
  ****************************************************************/
 
 static int
-set_protocol(u32 endp, u16 val)
+set_protocol(struct usb_pipe *pipe, u16 val)
 {
     struct usb_ctrlrequest req;
     req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
@@ -26,11 +26,11 @@ set_protocol(u32 endp, u16 val)
     req.wValue = val;
     req.wIndex = 0;
     req.wLength = 0;
-    return send_default_control(endp, &req, NULL);
+    return send_default_control(pipe, &req, NULL);
 }
 
 static int
-set_idle(u32 endp, int ms)
+set_idle(struct usb_pipe *pipe, int ms)
 {
     struct usb_ctrlrequest req;
     req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
@@ -38,21 +38,22 @@ set_idle(u32 endp, int ms)
     req.wValue = (ms/4)<<8;
     req.wIndex = 0;
     req.wLength = 0;
-    return send_default_control(endp, &req, NULL);
+    return send_default_control(pipe, &req, NULL);
 }
 
 #define KEYREPEATWAITMS 500
 #define KEYREPEATMS 33
 
 int
-usb_keyboard_init(u32 endp, struct usb_interface_descriptor *iface, int imax)
+usb_keyboard_init(struct usb_pipe *pipe
+                  , struct usb_interface_descriptor *iface, int imax)
 {
     if (! CONFIG_USB_KEYBOARD)
         return -1;
     if (keyboard_pipe)
         // XXX - this enables the first found keyboard (could be random)
         return -1;
-    dprintf(2, "usb_keyboard_setup %x\n", endp);
+    dprintf(2, "usb_keyboard_setup %x\n", pipe->endp);
 
     // Find intr in endpoint.
     struct usb_endpoint_descriptor *epdesc = findEndPointDesc(
@@ -61,22 +62,22 @@ usb_keyboard_init(u32 endp, struct usb_interface_descriptor *iface, int imax)
         dprintf(1, "No keyboard intr in?\n");
         return -1;
     }
-    u32 inendp = mkendpFromDesc(endp, epdesc);
 
     // Enable "boot" protocol.
-    int ret = set_protocol(endp, 1);
+    int ret = set_protocol(pipe, 1);
     if (ret)
         return -1;
     // Periodically send reports to enable key repeat.
-    ret = set_idle(endp, KEYREPEATMS);
+    ret = set_idle(pipe, KEYREPEATMS);
     if (ret)
         return -1;
 
-    struct usb_pipe *pipe = alloc_intr_pipe(inendp, epdesc->bInterval);
-    if (!pipe)
+    u32 inendp = mkendpFromDesc(pipe, epdesc);
+    keyboard_pipe = alloc_intr_pipe(inendp, epdesc->bInterval);
+    if (!keyboard_pipe)
         return -1;
-    keyboard_pipe = pipe;
 
+    dprintf(1, "USB keyboard initialized\n");
     return 0;
 }
 
index 6dbb2ada2a0964c27fd7f699a181ea4e0a38f4a1..1c75560109ed39141f191ebaf497d3a5d0e9292f 100644 (file)
@@ -3,8 +3,9 @@
 
 // usb-hid.c
 struct usb_interface_descriptor;
-int usb_keyboard_init(u32 endp, struct usb_interface_descriptor *iface
-                      , int imax);
+struct usb_pipe;
+int usb_keyboard_init(struct usb_pipe *pipe
+                      , struct usb_interface_descriptor *iface, int imax);
 void usb_keyboard_setup(void);
 void usb_check_key(void);
 
index ce9326b2a8e7ef74ef4baf742df86c185fafdd2b..b301f1cec91658260fe9ea3647db5696b3440473 100644 (file)
@@ -10,7 +10,7 @@
 #include "usb.h" // struct usb_s
 
 static int
-get_hub_desc(struct usb_hub_descriptor *desc, u32 endp)
+get_hub_desc(struct usb_pipe *pipe, struct usb_hub_descriptor *desc)
 {
     struct usb_ctrlrequest req;
     req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE;
@@ -18,11 +18,11 @@ get_hub_desc(struct usb_hub_descriptor *desc, u32 endp)
     req.wValue = USB_DT_HUB<<8;
     req.wIndex = 0;
     req.wLength = sizeof(*desc);
-    return send_default_control(endp, &req, desc);
+    return send_default_control(pipe, &req, desc);
 }
 
 static int
-set_port_feature(int port, int feature, u32 endp)
+set_port_feature(struct usb_pipe *pipe, int port, int feature)
 {
     struct usb_ctrlrequest req;
     req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
@@ -30,11 +30,11 @@ set_port_feature(int port, int feature, u32 endp)
     req.wValue = feature;
     req.wIndex = port;
     req.wLength = 0;
-    return send_default_control(endp, &req, NULL);
+    return send_default_control(pipe, &req, NULL);
 }
 
 static int
-clear_port_feature(int port, int feature, u32 endp)
+clear_port_feature(struct usb_pipe *pipe, int port, int feature)
 {
     struct usb_ctrlrequest req;
     req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
@@ -42,11 +42,11 @@ clear_port_feature(int port, int feature, u32 endp)
     req.wValue = feature;
     req.wIndex = port;
     req.wLength = 0;
-    return send_default_control(endp, &req, NULL);
+    return send_default_control(pipe, &req, NULL);
 }
 
 static int
-get_port_status(int port, struct usb_port_status *sts, u32 endp)
+get_port_status(struct usb_pipe *pipe, int port, struct usb_port_status *sts)
 {
     struct usb_ctrlrequest req;
     req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER;
@@ -54,25 +54,25 @@ get_port_status(int port, struct usb_port_status *sts, u32 endp)
     req.wValue = 0;
     req.wIndex = port;
     req.wLength = sizeof(*sts);
-    return send_default_control(endp, &req, sts);
+    return send_default_control(pipe, &req, sts);
 }
 
 // Configure a usb hub and then find devices connected to it.
 int
-usb_hub_init(u32 endp)
+usb_hub_init(struct usb_pipe *pipe)
 {
     if (!CONFIG_USB_HUB)
-        return 0;
+        return -1;
 
     struct usb_hub_descriptor desc;
-    int ret = get_hub_desc(&desc, endp);
+    int ret = get_hub_desc(pipe, &desc);
     if (ret)
         return ret;
 
     // Turn on power to all ports.
     int i;
     for (i=1; i<=desc.bNbrPorts; i++) {
-        ret = set_port_feature(i, USB_PORT_FEAT_POWER, endp);
+        ret = set_port_feature(pipe, i, USB_PORT_FEAT_POWER);
         if (ret)
             goto fail;
     }
@@ -83,11 +83,11 @@ usb_hub_init(u32 endp)
     // possibly wait USB_TIME_ATTDB.
 
     // Detect down stream devices.
-    struct usb_s *cntl = endp2cntl(endp);
+    struct usb_s *cntl = endp2cntl(pipe->endp);
     int totalcount = 0;
     for (i=1; i<=desc.bNbrPorts; i++) {
         struct usb_port_status sts;
-        ret = get_port_status(i, &sts, endp);
+        ret = get_port_status(pipe, i, &sts);
         if (ret)
             goto fail;
         if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION))
@@ -95,14 +95,14 @@ usb_hub_init(u32 endp)
             continue;
 
         // Reset port.
-        ret = set_port_feature(i, USB_PORT_FEAT_RESET, endp);
+        ret = set_port_feature(pipe, i, USB_PORT_FEAT_RESET);
         if (ret)
             goto fail;
 
         // Wait for reset to complete.
         u64 end = calc_future_tsc(USB_TIME_DRST * 2);
         for (;;) {
-            ret = get_port_status(i, &sts, endp);
+            ret = get_port_status(pipe, i, &sts);
             if (ret)
                 goto fail;
             if (!(sts.wPortStatus & USB_PORT_STAT_RESET))
@@ -123,16 +123,19 @@ usb_hub_init(u32 endp)
             cntl, !!(sts.wPortStatus & USB_PORT_STAT_LOW_SPEED));
         if (! count) {
             // Shutdown port
-            ret = clear_port_feature(i, USB_PORT_FEAT_ENABLE, endp);
+            ret = clear_port_feature(pipe, i, USB_PORT_FEAT_ENABLE);
             if (ret)
                 goto fail;
         }
         totalcount += count;
     }
 
-    return totalcount;
+    dprintf(1, "Initialized USB HUB (%d ports used)\n", totalcount);
+    if (totalcount)
+        return 0;
+    return -1;
 
 fail:
     dprintf(1, "Failure on hub setup\n");
-    return 0;
+    return -1;
 }
index 24d8f1f078564614d2d919f0416772af7d74600f..852f771f02836b98ffc83f3f88d3c9451086f0ca 100644 (file)
@@ -2,7 +2,8 @@
 #define __USB_HUB_H
 
 // usb-hub.c
-int usb_hub_init(u32 endp);
+struct usb_pipe;
+int usb_hub_init(struct usb_pipe *pipe);
 
 
 /****************************************************************
index c1fa45ddbc1af1bf1bb6853bd051d9b37106eb8a..cb60c3e22a4ac84a1caf2dacf3a187e7fea3e3a9 100644 (file)
@@ -50,7 +50,7 @@ struct csw_s {
 int
 usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
 {
-    dprintf(1, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n"
+    dprintf(16, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n"
             , op->drive_g, 0, op->count, blocksize, op->buf_fl);
     struct usbdrive_s *udrive_g = container_of(
         op->drive_g, struct usbdrive_s, drive);
@@ -173,7 +173,8 @@ setup_drive_hd(struct disk_op_s *op)
 
 // Configure a usb msc device.
 int
-usb_msc_init(u32 endp, struct usb_interface_descriptor *iface, int imax)
+usb_msc_init(struct usb_pipe *pipe
+             , struct usb_interface_descriptor *iface, int imax)
 {
     if (!CONFIG_USB_MSC)
         return -1;
@@ -193,9 +194,9 @@ usb_msc_init(u32 endp, struct usb_interface_descriptor *iface, int imax)
         iface, imax, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT);
     if (!indesc || !outdesc)
         goto fail;
-    u32 inendp = mkendpFromDesc(endp, indesc);
+    u32 inendp = mkendpFromDesc(pipe, indesc);
     struct usb_pipe *bulkin = alloc_bulk_pipe(inendp);
-    u32 outendp = mkendpFromDesc(endp, outdesc);
+    u32 outendp = mkendpFromDesc(pipe, outdesc);
     struct usb_pipe *bulkout = alloc_bulk_pipe(outendp);
     if (!bulkin || !bulkout)
         goto fail;
index 50c219366996b3f7598c4d31f01a4f6899e10e59..467ccf30046a195269f715d3dfa162dedb71922c 100644 (file)
@@ -5,7 +5,9 @@
 struct disk_op_s;
 int usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
 struct usb_interface_descriptor;
-int usb_msc_init(u32 endp, struct usb_interface_descriptor *iface, int imax);
+struct usb_pipe;
+int usb_msc_init(struct usb_pipe *pipe
+                 , struct usb_interface_descriptor *iface, int imax);
 int process_usb_op(struct disk_op_s *op);
 
 
index 4ce75a696503f68ffe035e318ed7dd97bf8f0803..828507baa4199626f64d2753297f5c18df4e5f14 100644 (file)
 
 #define FIT                     (1 << 31)
 
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
 static int
 start_ohci(struct usb_s *cntl, struct ohci_hcca *hcca)
 {
@@ -41,7 +46,7 @@ start_ohci(struct usb_s *cntl, struct ohci_hcca *hcca)
     }
 
     // Init memory
-    writel(&cntl->ohci.regs->ed_controlhead, (u32)cntl->ohci.control_ed);
+    writel(&cntl->ohci.regs->ed_controlhead, 0);
     writel(&cntl->ohci.regs->ed_bulkhead, 0);
     writel(&cntl->ohci.regs->hcca, (u32)hcca);
 
@@ -162,8 +167,7 @@ ohci_init(void *data)
     // Allocate memory
     struct ohci_hcca *hcca = memalign_high(256, sizeof(*hcca));
     struct ohci_ed *intr_ed = malloc_high(sizeof(*intr_ed));
-    struct ohci_ed *control_ed = malloc_high(sizeof(*control_ed));
-    if (!hcca || !intr_ed || !control_ed) {
+    if (!hcca || !intr_ed) {
         warn_noalloc();
         goto free;
     }
@@ -173,15 +177,13 @@ ohci_init(void *data)
     int i;
     for (i=0; i<ARRAY_SIZE(hcca->int_table); i++)
         hcca->int_table[i] = (u32)intr_ed;
-    memset(control_ed, 0, sizeof(*control_ed));
-    control_ed->hwINFO = ED_SKIP;
-    cntl->ohci.control_ed = control_ed;
 
     int ret = start_ohci(cntl, hcca);
     if (ret)
         goto err;
 
     int count = check_ohci_ports(cntl);
+    free_pipe(cntl->defaultpipe);
     if (! count)
         goto err;
     return;
@@ -191,9 +193,13 @@ err:
 free:
     free(hcca);
     free(intr_ed);
-    free(control_ed);
 }
 
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
 static int
 wait_ed(struct ohci_ed *ed)
 {
@@ -210,13 +216,114 @@ wait_ed(struct ohci_ed *ed)
     }
 }
 
+// Wait for next USB frame to start - for ensuring safe memory release.
+static void
+ohci_waittick(struct usb_s *cntl)
+{
+    barrier();
+    struct ohci_hcca *hcca = (void*)cntl->ohci.regs->hcca;
+    u32 startframe = hcca->frame_no;
+    u64 end = calc_future_tsc(1000 * 5);
+    for (;;) {
+        if (hcca->frame_no != startframe)
+            break;
+        if (check_time(end)) {
+            warn_timeout();
+            return;
+        }
+        yield();
+    }
+}
+
+static void
+signal_freelist(struct usb_s *cntl)
+{
+    u32 v = readl(&cntl->ohci.regs->control);
+    if (v & OHCI_CTRL_CLE) {
+        writel(&cntl->ohci.regs->control, v & ~(OHCI_CTRL_CLE|OHCI_CTRL_BLE));
+        ohci_waittick(cntl);
+        writel(&cntl->ohci.regs->ed_controlcurrent, 0);
+        writel(&cntl->ohci.regs->ed_bulkcurrent, 0);
+        writel(&cntl->ohci.regs->control, v);
+    } else {
+        ohci_waittick(cntl);
+    }
+}
+
+struct ohci_pipe {
+    struct ohci_ed ed;
+    struct usb_pipe pipe;
+    void *data;
+    int count;
+    struct ohci_td *tds;
+};
+
+void
+ohci_free_pipe(struct usb_pipe *p)
+{
+    if (! CONFIG_USB_OHCI)
+        return;
+    struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+    u32 endp = pipe->pipe.endp;
+    dprintf(7, "ohci_free_pipe %x\n", endp);
+    struct usb_s *cntl = endp2cntl(endp);
+
+    u32 *pos = &cntl->ohci.regs->ed_controlhead;
+    for (;;) {
+        struct ohci_ed *next = (void*)*pos;
+        if (!next) {
+            // Not found?!  Exit without freeing.
+            warn_internalerror();
+            return;
+        }
+        if (next == &pipe->ed) {
+            *pos = next->hwNextED;
+            signal_freelist(cntl);
+            free(pipe);
+            return;
+        }
+        pos = &next->hwNextED;
+    }
+}
+
+struct usb_pipe *
+ohci_alloc_control_pipe(u32 endp)
+{
+    if (! CONFIG_USB_OHCI)
+        return NULL;
+    struct usb_s *cntl = endp2cntl(endp);
+    dprintf(7, "ohci_alloc_control_pipe %x\n", endp);
+
+    // Allocate a queue head.
+    struct ohci_pipe *pipe = malloc_tmphigh(sizeof(*pipe));
+    if (!pipe) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    pipe->ed.hwINFO = ED_SKIP;
+    pipe->pipe.endp = endp;
+
+    // Add queue head to controller list.
+    pipe->ed.hwNextED = cntl->ohci.regs->ed_controlhead;
+    barrier();
+    cntl->ohci.regs->ed_controlhead = (u32)&pipe->ed;
+    return &pipe->pipe;
+}
+
 int
-ohci_control(u32 endp, int dir, const void *cmd, int cmdsize
+ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
              , void *data, int datasize)
 {
     if (! CONFIG_USB_OHCI)
         return -1;
-
+    if (datasize > 4096) {
+        // XXX - should support larger sizes.
+        warn_noalloc();
+        return -1;
+    }
+    struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+    u32 endp = pipe->pipe.endp;
     dprintf(5, "ohci_control %x\n", endp);
     struct usb_s *cntl = endp2cntl(endp);
     int maxpacket = endp2maxsize(endp);
@@ -239,31 +346,22 @@ ohci_control(u32 endp, int dir, const void *cmd, int cmdsize
     tds[2].hwBE = 0;
 
     // Transfer data
-    struct ohci_ed *ed = cntl->ohci.control_ed;
-    ed->hwINFO = ED_SKIP;
+    pipe->ed.hwINFO = ED_SKIP;
     barrier();
-    ed->hwHeadP = (u32)&tds[0];
-    ed->hwTailP = (u32)&tds[3];
+    pipe->ed.hwHeadP = (u32)&tds[0];
+    pipe->ed.hwTailP = (u32)&tds[3];
     barrier();
-    ed->hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
+    pipe->ed.hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
     writel(&cntl->ohci.regs->cmdstatus, OHCI_CLF);
 
-    int ret = wait_ed(ed);
-    ed->hwINFO = ED_SKIP;
+    int ret = wait_ed(&pipe->ed);
+    pipe->ed.hwINFO = ED_SKIP;
     if (ret)
-        usleep(1); // XXX - in case controller still accessing tds
+        ohci_waittick(cntl);
     free(tds);
     return ret;
 }
 
-struct ohci_pipe {
-    struct ohci_ed ed;
-    struct usb_pipe pipe;
-    void *data;
-    int count;
-    struct ohci_td *tds;
-};
-
 struct usb_pipe *
 ohci_alloc_intr_pipe(u32 endp, int frameexp)
 {
@@ -328,17 +426,17 @@ err:
 }
 
 int
-ohci_poll_intr(struct usb_pipe *pipe, void *data)
+ohci_poll_intr(struct usb_pipe *p, void *data)
 {
     ASSERT16();
     if (! CONFIG_USB_OHCI)
         return -1;
 
-    struct ohci_pipe *p = container_of(pipe, struct ohci_pipe, pipe);
-    struct ohci_td *tds = GET_FLATPTR(p->tds);
-    struct ohci_td *head = (void*)GET_FLATPTR(p->ed.hwHeadP);
-    struct ohci_td *tail = (void*)GET_FLATPTR(p->ed.hwTailP);
-    int count = GET_FLATPTR(p->count);
+    struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+    struct ohci_td *tds = GET_FLATPTR(pipe->tds);
+    struct ohci_td *head = (void*)GET_FLATPTR(pipe->ed.hwHeadP);
+    struct ohci_td *tail = (void*)GET_FLATPTR(pipe->ed.hwTailP);
+    int count = GET_FLATPTR(pipe->count);
     int pos = (tail - tds + 1) % count;
     struct ohci_td *next = &tds[pos];
     if (head == next)
@@ -347,9 +445,9 @@ ohci_poll_intr(struct usb_pipe *pipe, void *data)
     // XXX - check for errors.
 
     // Copy data.
-    u32 endp = GET_FLATPTR(p->pipe.endp);
+    u32 endp = GET_FLATPTR(pipe->pipe.endp);
     int maxpacket = endp2maxsize(endp);
-    void *pipedata = GET_FLATPTR(p->data);
+    void *pipedata = GET_FLATPTR(pipe->data);
     void *intrdata = pipedata + maxpacket * pos;
     memcpy_far(GET_SEG(SS), data
                , FLATPTR_TO_SEG(intrdata), (void*)FLATPTR_TO_OFFSET(intrdata)
@@ -362,7 +460,7 @@ ohci_poll_intr(struct usb_pipe *pipe, void *data)
     SET_FLATPTR(tail->hwNextTD, (u32)next);
     SET_FLATPTR(tail->hwBE, (u32)intrdata + maxpacket - 1);
 
-    SET_FLATPTR(p->ed.hwTailP, (u32)next);
+    SET_FLATPTR(pipe->ed.hwTailP, (u32)next);
 
     return 0;
 }
index 7ff84f6b22d732bf10d6e226e4d9b28afa092bff..fadd39680cac92e98b75e2a0381f826c7a9212ff 100644 (file)
@@ -4,7 +4,10 @@
 // usb-ohci.c
 struct usb_s;
 void ohci_init(void *data);
-int ohci_control(u32 endp, int dir, const void *cmd, int cmdsize
+struct usb_pipe;
+void ohci_free_pipe(struct usb_pipe *p);
+struct usb_pipe *ohci_alloc_control_pipe(u32 endp);
+int ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
                  , void *data, int datasize);
 struct usb_pipe *ohci_alloc_intr_pipe(u32 endp, int frameexp);
 int ohci_poll_intr(struct usb_pipe *pipe, void *data);
@@ -94,6 +97,7 @@ struct ohci_regs {
 #define OHCI_CTRL_CBSR  (3 << 0)
 #define OHCI_CTRL_PLE   (1 << 2)
 #define OHCI_CTRL_CLE   (1 << 4)
+#define OHCI_CTRL_BLE   (1 << 5)
 #define OHCI_CTRL_HCFS  (3 << 6)
 #       define OHCI_USB_RESET   (0 << 6)
 #       define OHCI_USB_OPER    (2 << 6)
index 881e34562d1981462650f25a46e9b98433ff170e..d4497bd134546d8dd11cd7317f483846e99dd750 100644 (file)
 #include "pci_regs.h" // PCI_BASE_ADDRESS_4
 #include "usb.h" // struct usb_s
 #include "farptr.h" // GET_FLATPTR
+#include "biosvar.h" // GET_GLOBAL
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
 
 static void
 reset_uhci(struct usb_s *cntl)
@@ -37,14 +43,12 @@ configure_uhci(struct usb_s *cntl)
     struct uhci_td *term_td = malloc_high(sizeof(*term_td));
     struct uhci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl));
     struct uhci_qh *intr_qh = malloc_high(sizeof(*intr_qh));
-    struct uhci_qh *data_qh = malloc_high(sizeof(*data_qh));
     struct uhci_qh *term_qh = malloc_high(sizeof(*term_qh));
-    if (!term_td || !fl || !intr_qh || !data_qh || !term_qh) {
+    if (!term_td || !fl || !intr_qh || !term_qh) {
         warn_noalloc();
         free(term_td);
         free(fl);
         free(intr_qh);
-        free(data_qh);
         free(term_qh);
         return;
     }
@@ -58,20 +62,15 @@ configure_uhci(struct usb_s *cntl)
     term_qh->element = (u32)term_td;
     term_qh->link = UHCI_PTR_TERM;
 
-    // Setup primary queue head.
-    memset(data_qh, 0, sizeof(*data_qh));
-    data_qh->element = UHCI_PTR_TERM;
-    data_qh->link = (u32)term_qh | UHCI_PTR_QH;
-    cntl->uhci.qh = data_qh;
-
     // Set schedule to point to primary intr queue head
     memset(intr_qh, 0, sizeof(*intr_qh));
     intr_qh->element = UHCI_PTR_TERM;
-    intr_qh->link = (u32)data_qh | UHCI_PTR_QH;
+    intr_qh->link = (u32)term_qh | UHCI_PTR_QH;
     int i;
     for (i=0; i<ARRAY_SIZE(fl->links); i++)
         fl->links[i] = (u32)intr_qh | UHCI_PTR_QH;
     cntl->uhci.framelist = fl;
+    cntl->uhci.control_qh = cntl->uhci.bulk_qh = intr_qh;
     barrier();
 
     // Set the frame length to the default: 1 ms exactly
@@ -162,11 +161,17 @@ uhci_init(void *data)
     start_uhci(cntl);
 
     int count = check_ports(cntl);
+    free_pipe(cntl->defaultpipe);
     if (! count) {
         // XXX - no devices; free data structures.
     }
 }
 
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
 static int
 wait_qh(struct usb_s *cntl, struct uhci_qh *qh)
 {
@@ -188,19 +193,102 @@ wait_qh(struct usb_s *cntl, struct uhci_qh *qh)
     }
 }
 
+// Wait for next USB frame to start - for ensuring safe memory release.
 static void
-uhci_waittick(void)
+uhci_waittick(struct usb_s *cntl)
+{
+    barrier();
+    u16 iobase = GET_GLOBAL(cntl->uhci.iobase);
+    u16 startframe = inw(iobase + USBFRNUM);
+    u64 end = calc_future_tsc(1000 * 5);
+    for (;;) {
+        if (inw(iobase + USBFRNUM) != startframe)
+            break;
+        if (check_time(end)) {
+            warn_timeout();
+            return;
+        }
+        yield();
+    }
+}
+
+struct uhci_pipe {
+    struct uhci_qh qh;
+    struct uhci_td *next_td;
+    struct usb_pipe pipe;
+};
+
+void
+uhci_free_pipe(struct usb_pipe *p)
+{
+    if (! CONFIG_USB_UHCI)
+        return;
+    struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+    u32 endp = pipe->pipe.endp;
+    dprintf(7, "uhci_free_pipe %x\n", endp);
+    struct usb_s *cntl = endp2cntl(endp);
+
+    struct uhci_framelist *fl = cntl->uhci.framelist;
+    struct uhci_qh *pos = (void*)(fl->links[0] & ~UHCI_PTR_BITS);
+    for (;;) {
+        u32 link = pos->link;
+        if (link == UHCI_PTR_TERM) {
+            // Not found?!  Exit without freeing.
+            warn_internalerror();
+            return;
+        }
+        struct uhci_qh *next = (void*)(link & ~UHCI_PTR_BITS);
+        if (next == &pipe->qh) {
+            pos->link = next->link;
+            if (cntl->uhci.control_qh == next)
+                cntl->uhci.control_qh = pos;
+            if (cntl->uhci.bulk_qh == next)
+                cntl->uhci.bulk_qh = pos;
+            uhci_waittick(cntl);
+            free(pipe);
+            return;
+        }
+        pos = next;
+    }
+}
+
+struct usb_pipe *
+uhci_alloc_control_pipe(u32 endp)
 {
-    // XXX - implement real tick detection.
-    msleep(2);
+    if (! CONFIG_USB_UHCI)
+        return NULL;
+    struct usb_s *cntl = endp2cntl(endp);
+    dprintf(7, "uhci_alloc_control_pipe %x\n", endp);
+
+    // Allocate a queue head.
+    struct uhci_pipe *pipe = malloc_tmphigh(sizeof(*pipe));
+    if (!pipe) {
+        warn_noalloc();
+        return NULL;
+    }
+    pipe->qh.element = UHCI_PTR_TERM;
+    pipe->next_td = 0;
+    pipe->pipe.endp = endp;
+
+    // Add queue head to controller list.
+    struct uhci_qh *control_qh = cntl->uhci.control_qh;
+    pipe->qh.link = control_qh->link;
+    barrier();
+    control_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+    if (cntl->uhci.bulk_qh == control_qh)
+        cntl->uhci.bulk_qh = &pipe->qh;
+    return &pipe->pipe;
 }
 
 int
-uhci_control(u32 endp, int dir, const void *cmd, int cmdsize
+uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
              , void *data, int datasize)
 {
+    ASSERT32FLAT();
     if (! CONFIG_USB_UHCI)
         return -1;
+    struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+    u32 endp = pipe->pipe.endp;
 
     dprintf(5, "uhci_control %x\n", endp);
     struct usb_s *cntl = endp2cntl(endp);
@@ -240,13 +328,12 @@ uhci_control(u32 endp, int dir, const void *cmd, int cmdsize
     tds[i].buffer = 0;
 
     // Transfer data
-    struct uhci_qh *data_qh = cntl->uhci.qh;
     barrier();
-    data_qh->element = (u32)&tds[0];
-    int ret = wait_qh(cntl, data_qh);
+    pipe->qh.element = (u32)&tds[0];
+    int ret = wait_qh(cntl, &pipe->qh);
     if (ret) {
-        data_qh->element = UHCI_PTR_TERM;
-        uhci_waittick();
+        pipe->qh.element = UHCI_PTR_TERM;
+        uhci_waittick(cntl);
     }
     free(tds);
     return ret;
@@ -261,22 +348,22 @@ uhci_alloc_bulk_pipe(u32 endp)
     dprintf(7, "uhci_alloc_bulk_pipe %x\n", endp);
 
     // Allocate a queue head.
-    struct uhci_qh *qh = malloc_low(sizeof(*qh));
-    if (!qh) {
+    struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
+    if (!pipe) {
         warn_noalloc();
         return NULL;
     }
-    qh->element = UHCI_PTR_TERM;
-    qh->next_td = 0;
-    qh->pipe.endp = endp;
+    pipe->qh.element = UHCI_PTR_TERM;
+    pipe->next_td = 0;
+    pipe->pipe.endp = endp;
 
     // Add queue head to controller list.
-    struct uhci_qh *data_qh = cntl->uhci.qh;
-    qh->link = data_qh->link;
+    struct uhci_qh *bulk_qh = cntl->uhci.bulk_qh;
+    pipe->qh.link = bulk_qh->link;
     barrier();
-    data_qh->link = (u32)qh | UHCI_PTR_QH;
+    bulk_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
 
-    return &qh->pipe;
+    return &pipe->pipe;
 }
 
 static int
@@ -305,16 +392,16 @@ wait_td(struct uhci_td *td)
 #define TDALIGN 16
 
 int
-uhci_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize)
+uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
 {
-    struct uhci_qh *qh = container_of(pipe, struct uhci_qh, pipe);
-    u32 endp = GET_FLATPTR(qh->pipe.endp);
+    struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+    u32 endp = GET_FLATPTR(pipe->pipe.endp);
     dprintf(7, "uhci_send_bulk qh=%p endp=%x dir=%d data=%p size=%d\n"
-            , qh, endp, dir, data, datasize);
+            , &pipe->qh, endp, dir, data, datasize);
     int maxpacket = endp2maxsize(endp);
     int lowspeed = endp2speed(endp);
     int devaddr = endp2devaddr(endp) | (endp2ep(endp) << 7);
-    int toggle = (u32)GET_FLATPTR(qh->next_td); // XXX
+    int toggle = (u32)GET_FLATPTR(pipe->next_td); // XXX
 
     // Allocate 4 tds on stack (16byte aligned)
     u8 tdsbuf[sizeof(struct uhci_td) * STACKTDS + TDALIGN - 1];
@@ -322,7 +409,7 @@ uhci_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize)
     memset(tds, 0, sizeof(*tds) * STACKTDS);
 
     // Enable tds
-    SET_FLATPTR(qh->element, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
+    SET_FLATPTR(pipe->qh.element, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
 
     int tdpos = 0;
     while (datasize) {
@@ -357,12 +444,12 @@ uhci_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize)
             goto fail;
     }
 
-    SET_FLATPTR(qh->next_td, (void*)toggle); // XXX
+    SET_FLATPTR(pipe->next_td, (void*)toggle); // XXX
     return 0;
 fail:
     dprintf(1, "uhci_send_bulk failed\n");
-    SET_FLATPTR(qh->element, UHCI_PTR_TERM);
-    uhci_waittick();
+    SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM);
+    uhci_waittick(endp2cntl(endp));
     return -1;
 }
 
@@ -382,15 +469,15 @@ uhci_alloc_intr_pipe(u32 endp, int frameexp)
     // Determine number of entries needed for 2 timer ticks.
     int ms = 1<<frameexp;
     int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * ms);
-    struct uhci_qh *qh = malloc_low(sizeof(*qh));
+    struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
     struct uhci_td *tds = malloc_low(sizeof(*tds) * count);
-    if (!qh || !tds) {
+    if (!pipe || !tds) {
         warn_noalloc();
         goto fail;
     }
     if (maxpacket > sizeof(tds[0].data))
         goto fail;
-    qh->element = (u32)tds;
+    pipe->qh.element = (u32)tds;
     int toggle = 0;
     int i;
     for (i=0; i<count; i++) {
@@ -404,41 +491,45 @@ uhci_alloc_intr_pipe(u32 endp, int frameexp)
         toggle ^= TD_TOKEN_TOGGLE;
     }
 
-    qh->next_td = &tds[0];
-    qh->pipe.endp = endp;
+    pipe->next_td = &tds[0];
+    pipe->pipe.endp = endp;
 
     // Add to interrupt schedule.
     struct uhci_framelist *fl = cntl->uhci.framelist;
     if (frameexp == 0) {
         // Add to existing interrupt entry.
         struct uhci_qh *intr_qh = (void*)(fl->links[0] & ~UHCI_PTR_BITS);
-        qh->link = intr_qh->link;
+        pipe->qh.link = intr_qh->link;
         barrier();
-        intr_qh->link = (u32)qh | UHCI_PTR_QH;
+        intr_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+        if (cntl->uhci.control_qh == intr_qh)
+            cntl->uhci.control_qh = &pipe->qh;
+        if (cntl->uhci.bulk_qh == intr_qh)
+            cntl->uhci.bulk_qh = &pipe->qh;
     } else {
         int startpos = 1<<(frameexp-1);
-        qh->link = fl->links[startpos];
+        pipe->qh.link = fl->links[startpos];
         barrier();
         for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms)
-            fl->links[i] = (u32)qh | UHCI_PTR_QH;
+            fl->links[i] = (u32)&pipe->qh | UHCI_PTR_QH;
     }
 
-    return &qh->pipe;
+    return &pipe->pipe;
 fail:
-    free(qh);
+    free(pipe);
     free(tds);
     return NULL;
 }
 
 int
-uhci_poll_intr(struct usb_pipe *pipe, void *data)
+uhci_poll_intr(struct usb_pipe *p, void *data)
 {
     ASSERT16();
     if (! CONFIG_USB_UHCI)
         return -1;
 
-    struct uhci_qh *qh = container_of(pipe, struct uhci_qh, pipe);
-    struct uhci_td *td = GET_FLATPTR(qh->next_td);
+    struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+    struct uhci_td *td = GET_FLATPTR(pipe->next_td);
     u32 status = GET_FLATPTR(td->status);
     u32 token = GET_FLATPTR(td->token);
     if (status & TD_CTRL_ACTIVE)
@@ -456,7 +547,7 @@ uhci_poll_intr(struct usb_pipe *pipe, void *data)
     barrier();
     SET_FLATPTR(td->status, (uhci_maxerr(0) | (status & TD_CTRL_LS)
                              | TD_CTRL_ACTIVE));
-    SET_FLATPTR(qh->next_td, (void*)(next & ~UHCI_PTR_BITS));
+    SET_FLATPTR(pipe->next_td, (void*)(next & ~UHCI_PTR_BITS));
 
     return 0;
 }
index d7ebb4eca69004415bf4aa3b6518aaded9a5edb5..8dbee9c495a0147271cabd3c2831ac609f96233e 100644 (file)
@@ -1,12 +1,12 @@
 #ifndef __USB_UHCI_H
 #define __USB_UHCI_H
 
-#include "usb.h" // struct usb_pipe
-
 // usb-uhci.c
-struct usb_s;
 void uhci_init(void *data);
-int uhci_control(u32 endp, int dir, const void *cmd, int cmdsize
+struct usb_pipe;
+void uhci_free_pipe(struct usb_pipe *pipe);
+struct usb_pipe *uhci_alloc_control_pipe(u32 endp);
+int uhci_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize
                  , void *data, int datasize);
 struct usb_pipe *uhci_alloc_bulk_pipe(u32 endp);
 int uhci_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize);
@@ -120,10 +120,6 @@ struct uhci_td {
 struct uhci_qh {
     u32 link;
     u32 element;
-
-    // Software fields
-    struct uhci_td *next_td;
-    struct usb_pipe pipe;
 } PACKED;
 
 #define UHCI_PTR_BITS           0x000F
index cc3b2012c0fb62cb6c66598c04409f3c73464f1a..5b3649c3da4d5e5c90de50b6229949d89ce75f8e 100644 (file)
--- a/src/usb.c
+++ b/src/usb.c
@@ -24,18 +24,50 @@ struct usb_s USBControllers[16] VAR16VISIBLE;
  * Controller function wrappers
  ****************************************************************/
 
+// Free an allocated control or bulk pipe.
+void
+free_pipe(struct usb_pipe *pipe)
+{
+    ASSERT32FLAT();
+    if (!pipe)
+        return;
+    struct usb_s *cntl = endp2cntl(pipe->endp);
+    switch (cntl->type) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_free_pipe(pipe);
+    case USB_TYPE_OHCI:
+        return ohci_free_pipe(pipe);
+    }
+}
+
+// Allocate a control pipe (which can only be used by 32bit code)
+static struct usb_pipe *
+alloc_control_pipe(u32 endp)
+{
+    struct usb_s *cntl = endp2cntl(endp);
+    switch (cntl->type) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_alloc_control_pipe(endp);
+    case USB_TYPE_OHCI:
+        return ohci_alloc_control_pipe(endp);
+    }
+}
+
 // Send a message on a control pipe using the default control descriptor.
 static int
-send_control(u32 endp, int dir, const void *cmd, int cmdsize
+send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize
              , void *data, int datasize)
 {
-    struct usb_s *cntl = endp2cntl(endp);
+    ASSERT32FLAT();
+    struct usb_s *cntl = endp2cntl(pipe->endp);
     switch (cntl->type) {
     default:
     case USB_TYPE_UHCI:
-        return uhci_control(endp, dir, cmd, cmdsize, data, datasize);
+        return uhci_control(pipe, dir, cmd, cmdsize, data, datasize);
     case USB_TYPE_OHCI:
-        return ohci_control(endp, dir, cmd, cmdsize, data, datasize);
+        return ohci_control(pipe, dir, cmd, cmdsize, data, datasize);
     }
 }
 
@@ -121,10 +153,18 @@ findEndPointDesc(struct usb_interface_descriptor *iface, int imax
     }
 }
 
+// Change endpoint characteristics of the default control pipe.
+static void
+usb_alter_control(struct usb_pipe *pipe, u32 endp)
+{
+    pipe->endp = endp;
+}
+
 // Build an encoded "endp" from an endpoint descriptor.
 u32
-mkendpFromDesc(u32 endp, struct usb_endpoint_descriptor *epdesc)
+mkendpFromDesc(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
 {
+    u32 endp = pipe->endp;
     return mkendp(endp2cntl(endp), endp2devaddr(endp)
                   , epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK
                   , endp2speed(endp), epdesc->wMaxPacketSize);
@@ -132,15 +172,16 @@ mkendpFromDesc(u32 endp, struct usb_endpoint_descriptor *epdesc)
 
 // Send a message to the default control pipe of a device.
 int
-send_default_control(u32 endp, const struct usb_ctrlrequest *req, void *data)
+send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
+                     , void *data)
 {
-    return send_control(endp, req->bRequestType & USB_DIR_IN
+    return send_control(pipe, req->bRequestType & USB_DIR_IN
                         , req, sizeof(*req), data, req->wLength);
 }
 
 // Get the first 8 bytes of the device descriptor.
 static int
-get_device_info8(struct usb_device_descriptor *dinfo, u32 endp)
+get_device_info8(struct usb_pipe *pipe, struct usb_device_descriptor *dinfo)
 {
     struct usb_ctrlrequest req;
     req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
@@ -148,11 +189,11 @@ get_device_info8(struct usb_device_descriptor *dinfo, u32 endp)
     req.wValue = USB_DT_DEVICE<<8;
     req.wIndex = 0;
     req.wLength = 8;
-    return send_default_control(endp, &req, dinfo);
+    return send_default_control(pipe, &req, dinfo);
 }
 
 static struct usb_config_descriptor *
-get_device_config(u32 endp)
+get_device_config(struct usb_pipe *pipe)
 {
     struct usb_config_descriptor cfg;
 
@@ -162,7 +203,7 @@ get_device_config(u32 endp)
     req.wValue = USB_DT_CONFIG<<8;
     req.wIndex = 0;
     req.wLength = sizeof(cfg);
-    int ret = send_default_control(endp, &req, &cfg);
+    int ret = send_default_control(pipe, &req, &cfg);
     if (ret)
         return NULL;
 
@@ -170,18 +211,19 @@ get_device_config(u32 endp)
     if (!config)
         return NULL;
     req.wLength = cfg.wTotalLength;
-    ret = send_default_control(endp, &req, config);
+    ret = send_default_control(pipe, &req, config);
     if (ret)
         return NULL;
     //hexdump(config, cfg.wTotalLength);
     return config;
 }
 
-static u32
-set_address(u32 endp)
+static struct usb_pipe *
+set_address(struct usb_pipe *pipe)
 {
-    dprintf(3, "set_address %x\n", endp);
-    struct usb_s *cntl = endp2cntl(endp);
+    ASSERT32FLAT();
+    dprintf(3, "set_address %x\n", pipe->endp);
+    struct usb_s *cntl = endp2cntl(pipe->endp);
     if (cntl->maxaddr >= USB_MAXADDR)
         return 0;
 
@@ -191,17 +233,19 @@ set_address(u32 endp)
     req.wValue = cntl->maxaddr + 1;
     req.wIndex = 0;
     req.wLength = 0;
-    int ret = send_default_control(endp, &req, NULL);
+    int ret = send_default_control(pipe, &req, NULL);
     if (ret)
         return 0;
     msleep(USB_TIME_SETADDR_RECOVERY);
 
     cntl->maxaddr++;
-    return mkendp(cntl, cntl->maxaddr, 0, endp2speed(endp), endp2maxsize(endp));
+    u32 endp = mkendp(cntl, cntl->maxaddr, 0
+                      , endp2speed(pipe->endp), endp2maxsize(pipe->endp));
+    return alloc_control_pipe(endp);
 }
 
 static int
-set_configuration(u32 endp, u16 val)
+set_configuration(struct usb_pipe *pipe, u16 val)
 {
     struct usb_ctrlrequest req;
     req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
@@ -209,7 +253,7 @@ set_configuration(u32 endp, u16 val)
     req.wValue = val;
     req.wIndex = 0;
     req.wLength = 0;
-    return send_default_control(endp, &req, NULL);
+    return send_default_control(pipe, &req, NULL);
 }
 
 
@@ -222,12 +266,20 @@ set_configuration(u32 endp, u16 val)
 int
 configure_usb_device(struct usb_s *cntl, int lowspeed)
 {
+    ASSERT32FLAT();
     dprintf(3, "config_usb: %p %d\n", cntl, lowspeed);
 
     // Get device info
+    struct usb_pipe *defpipe = cntl->defaultpipe;
     u32 endp = mkendp(cntl, 0, 0, lowspeed, 8);
+    if (!defpipe) {
+        cntl->defaultpipe = defpipe = alloc_control_pipe(endp);
+        if (!defpipe)
+            return 0;
+    }
+    usb_alter_control(defpipe, endp);
     struct usb_device_descriptor dinfo;
-    int ret = get_device_info8(&dinfo, endp);
+    int ret = get_device_info8(defpipe, &dinfo);
     if (ret)
         return 0;
     dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%02x\n"
@@ -236,9 +288,11 @@ configure_usb_device(struct usb_s *cntl, int lowspeed)
     if (dinfo.bMaxPacketSize0 < 8 || dinfo.bMaxPacketSize0 > 64)
         return 0;
     endp = mkendp(cntl, 0, 0, lowspeed, dinfo.bMaxPacketSize0);
+    usb_alter_control(defpipe, endp);
 
     // Get configuration
-    struct usb_config_descriptor *config = get_device_config(endp);
+    struct usb_pipe *pipe = NULL;
+    struct usb_config_descriptor *config = get_device_config(defpipe);
     if (!config)
         return 0;
 
@@ -254,26 +308,25 @@ configure_usb_device(struct usb_s *cntl, int lowspeed)
         goto fail;
 
     // Set the address and configure device.
-    endp = set_address(endp);
-    if (!endp)
+    pipe = set_address(defpipe);
+    if (!pipe)
         goto fail;
-    ret = set_configuration(endp, config->bConfigurationValue);
+    ret = set_configuration(pipe, config->bConfigurationValue);
     if (ret)
         goto fail;
 
     // Configure driver.
-    if (iface->bInterfaceClass == USB_CLASS_HUB) {
-        free(config);
-        return usb_hub_init(endp);
-    }
     int imax = (void*)config + config->wTotalLength - (void*)iface;
-    if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE)
-        ret = usb_msc_init(endp, iface, imax);
+    if (iface->bInterfaceClass == USB_CLASS_HUB)
+        ret = usb_hub_init(pipe);
+    else if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE)
+        ret = usb_msc_init(pipe, iface, imax);
     else
-        ret = usb_keyboard_init(endp, iface, imax);
+        ret = usb_keyboard_init(pipe, iface, imax);
     if (ret)
         goto fail;
 
+    free_pipe(pipe);
     free(config);
     return 1;
 fail:
@@ -290,6 +343,7 @@ usb_setup(void)
 
     dprintf(3, "init usb\n");
 
+    memset(&USBControllers, 0, sizeof(USBControllers));
     usb_keyboard_setup();
 
     // Look for USB controllers
index d94789156dc7d5f72992ca56bb43915bf1771862..0f65e39328af34938de6cb010c07f22f436e0eff 100644 (file)
--- a/src/usb.h
+++ b/src/usb.h
@@ -2,20 +2,24 @@
 #ifndef __USB_H
 #define __USB_H
 
+struct usb_pipe {
+    u32 endp;
+};
+
 // Local information for a usb controller.
 struct usb_s {
     u8 type;
     u8 maxaddr;
     u16 bdf;
+    struct usb_pipe *defaultpipe;
 
     union {
         struct {
             u16 iobase;
-            void *qh, *framelist;
+            void *control_qh, *bulk_qh, *framelist;
         } uhci;
         struct {
             struct ohci_regs *regs;
-            void *control_ed;
         } ohci;
     };
 };
@@ -25,26 +29,24 @@ struct usb_s {
 
 extern struct usb_s USBControllers[];
 
-struct usb_pipe {
-    u32 endp;
-};
-
 #define USB_MAXADDR 127
 
 // usb.c
 void usb_setup(void);
 int configure_usb_device(struct usb_s *cntl, int lowspeed);
 struct usb_ctrlrequest;
-int send_default_control(u32 endp, const struct usb_ctrlrequest *req
+int send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
                          , void *data);
 int usb_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize);
+void free_pipe(struct usb_pipe *pipe);
 struct usb_pipe *alloc_bulk_pipe(u32 endp);
 struct usb_pipe *alloc_intr_pipe(u32 endp, int period);
 int usb_poll_intr(struct usb_pipe *pipe, void *data);
 struct usb_interface_descriptor;
 struct usb_endpoint_descriptor *findEndPointDesc(
     struct usb_interface_descriptor *iface, int imax, int type, int dir);
-u32 mkendpFromDesc(u32 endp, struct usb_endpoint_descriptor *epdesc);
+u32 mkendpFromDesc(struct usb_pipe *pipe
+                   , struct usb_endpoint_descriptor *epdesc);
 
 
 /****************************************************************