Main work is in last patch - first three patches are just cleanups. This patch series improves the boot time on my epia-cn machine, and it also sets up for further ehancements that will follow.
-Kevin
Kevin O'Connor (4): Prefer passing a USB "pipe" structure over a USB endp encoding. Only compile usb-hub.c and paravirt.c with 32bit code. Introduce simple "mutex" locking code. Further parallelize USB init by launching a thread per usb port.
Makefile | 4 +- src/ps2port.c | 2 +- src/stacks.c | 20 ++++ src/usb-hid.c | 25 +++-- src/usb-hid.h | 5 +- src/usb-hub.c | 190 +++++++++++++++++++++------------ src/usb-hub.h | 13 ++- src/usb-msc.c | 9 +- src/usb-msc.h | 4 +- src/usb-ohci.c | 325 +++++++++++++++++++++++++++++++++++++++---------------- src/usb-ohci.h | 6 +- src/usb-uhci.c | 319 ++++++++++++++++++++++++++++++++++++++----------------- src/usb-uhci.h | 12 +-- src/usb.c | 167 +++++++++++++++++++---------- src/usb.h | 24 +++-- src/util.h | 3 + 16 files changed, 767 insertions(+), 361 deletions(-)
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. --- src/ps2port.c | 2 +- src/usb-hid.c | 25 ++++---- src/usb-hid.h | 5 +- src/usb-hub.c | 41 ++++++------ src/usb-hub.h | 3 +- src/usb-msc.c | 9 ++- src/usb-msc.h | 4 +- src/usb-ohci.c | 166 ++++++++++++++++++++++++++++++++++++++---------- src/usb-ohci.h | 6 ++- src/usb-uhci.c | 195 +++++++++++++++++++++++++++++++++++++++++--------------- src/usb-uhci.h | 12 +-- src/usb.c | 118 +++++++++++++++++++++++++--------- src/usb.h | 18 +++-- 13 files changed, 429 insertions(+), 175 deletions(-)
diff --git a/src/ps2port.c b/src/ps2port.c index 49bf551..26c55f2 100644 --- a/src/ps2port.c +++ b/src/ps2port.c @@ -415,7 +415,7 @@ keyboard_init(void *data) if (ret) return;
- dprintf(1, "keyboard initialized\n"); + dprintf(1, "PS2 keyboard initialized\n"); }
void diff --git a/src/usb-hid.c b/src/usb-hid.c index ae16686..eae6823 100644 --- a/src/usb-hid.c +++ b/src/usb-hid.c @@ -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; }
diff --git a/src/usb-hid.h b/src/usb-hid.h index 6dbb2ad..1c75560 100644 --- a/src/usb-hid.h +++ b/src/usb-hid.h @@ -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);
diff --git a/src/usb-hub.c b/src/usb-hub.c index ce9326b..b301f1c 100644 --- a/src/usb-hub.c +++ b/src/usb-hub.c @@ -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; } diff --git a/src/usb-hub.h b/src/usb-hub.h index 24d8f1f..852f771 100644 --- a/src/usb-hub.h +++ b/src/usb-hub.h @@ -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);
/**************************************************************** diff --git a/src/usb-msc.c b/src/usb-msc.c index c1fa45d..cb60c3e 100644 --- a/src/usb-msc.c +++ b/src/usb-msc.c @@ -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; diff --git a/src/usb-msc.h b/src/usb-msc.h index 50c2193..467ccf3 100644 --- a/src/usb-msc.h +++ b/src/usb-msc.h @@ -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);
diff --git a/src/usb-ohci.c b/src/usb-ohci.c index 4ce75a6..828507b 100644 --- a/src/usb-ohci.c +++ b/src/usb-ohci.c @@ -14,6 +14,11 @@
#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; } diff --git a/src/usb-ohci.h b/src/usb-ohci.h index 7ff84f6..fadd396 100644 --- a/src/usb-ohci.h +++ b/src/usb-ohci.h @@ -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) diff --git a/src/usb-uhci.c b/src/usb-uhci.c index 881e345..d4497bd 100644 --- a/src/usb-uhci.c +++ b/src/usb-uhci.c @@ -12,6 +12,12 @@ #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; } diff --git a/src/usb-uhci.h b/src/usb-uhci.h index d7ebb4e..8dbee9c 100644 --- a/src/usb-uhci.h +++ b/src/usb-uhci.h @@ -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 diff --git a/src/usb.c b/src/usb.c index cc3b201..5b3649c 100644 --- 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 diff --git a/src/usb.h b/src/usb.h index d947891..0f65e39 100644 --- 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);
/****************************************************************
Those files are only used by 32bit code, so don't bother including them with the 16bit code. --- Makefile | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile index b896b54..82651d8 100644 --- a/Makefile +++ b/Makefile @@ -14,11 +14,11 @@ OUT=out/ SRCBOTH=misc.c pmm.c stacks.c output.c util.c block.c floppy.c ata.c mouse.c \ kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \ pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \ - usb.c usb-uhci.c usb-ohci.c usb-hid.c usb-hub.c usb-msc.c paravirt.c + usb.c usb-uhci.c usb-ohci.c usb-hid.c usb-msc.c SRC16=$(SRCBOTH) system.c disk.c apm.c font.c SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ - lzmadecode.c + lzmadecode.c usb-hub.c paravirt.c SRC32SEG=util.c output.c pci.c pcibios.c apm.c
cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
Locks are not normally necessary because SeaBIOS uses a cooperative multitasking system. However, occasionally it is necessary to be able to lock a resource across yield calls. This patch introduces a simple mechanism for doing that. --- src/stacks.c | 20 ++++++++++++++++++++ src/util.h | 3 +++ 2 files changed, 23 insertions(+), 0 deletions(-)
diff --git a/src/stacks.c b/src/stacks.c index a35ca3d..c783967 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -248,6 +248,26 @@ wait_threads(void) yield(); }
+void +mutex_lock(struct mutex_s *mutex) +{ + ASSERT32FLAT(); + if (! CONFIG_THREADS) + return; + while (mutex->isLocked) + yield(); + mutex->isLocked = 1; +} + +void +mutex_unlock(struct mutex_s *mutex) +{ + ASSERT32FLAT(); + if (! CONFIG_THREADS) + return; + mutex->isLocked = 0; +} +
/**************************************************************** * Thread preemption diff --git a/src/util.h b/src/util.h index 9f71d65..9b4fd3a 100644 --- a/src/util.h +++ b/src/util.h @@ -208,6 +208,9 @@ struct thread_info *getCurThread(void); void yield(void); void run_thread(void (*func)(void*), void *data); void wait_threads(void); +struct mutex_s { u32 isLocked; }; +void mutex_lock(struct mutex_s *mutex); +void mutex_unlock(struct mutex_s *mutex); void start_preempt(void); void finish_preempt(void); void check_preempt(void);
Run a thread per usb port in addition to the existing thread per usb controller. This can reduce total boot time by allowing multiple USB devices on the same controller to initialize in parallel. It also makes startup time for critical devices (eg, the keyboard) less dependent on which port they are plugged into. --- src/usb-hub.c | 185 +++++++++++++++++++++++++++++++++++--------------------- src/usb-hub.h | 10 +++ src/usb-ohci.c | 159 +++++++++++++++++++++++++++++------------------ src/usb-uhci.c | 124 +++++++++++++++++++++++--------------- src/usb.c | 87 +++++++++++++------------- src/usb.h | 6 ++- 6 files changed, 350 insertions(+), 221 deletions(-)
diff --git a/src/usb-hub.c b/src/usb-hub.c index b301f1c..da7d9f8 100644 --- a/src/usb-hub.c +++ b/src/usb-hub.c @@ -22,7 +22,7 @@ get_hub_desc(struct usb_pipe *pipe, struct usb_hub_descriptor *desc) }
static int -set_port_feature(struct usb_pipe *pipe, int port, int feature) +set_port_feature(struct usbhub_s *hub, int port, int feature) { struct usb_ctrlrequest req; req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER; @@ -30,11 +30,14 @@ set_port_feature(struct usb_pipe *pipe, int port, int feature) req.wValue = feature; req.wIndex = port; req.wLength = 0; - return send_default_control(pipe, &req, NULL); + mutex_lock(&hub->lock); + int ret = send_default_control(hub->pipe, &req, NULL); + mutex_unlock(&hub->lock); + return ret; }
static int -clear_port_feature(struct usb_pipe *pipe, int port, int feature) +clear_port_feature(struct usbhub_s *hub, int port, int feature) { struct usb_ctrlrequest req; req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER; @@ -42,11 +45,14 @@ clear_port_feature(struct usb_pipe *pipe, int port, int feature) req.wValue = feature; req.wIndex = port; req.wLength = 0; - return send_default_control(pipe, &req, NULL); + mutex_lock(&hub->lock); + int ret = send_default_control(hub->pipe, &req, NULL); + mutex_unlock(&hub->lock); + return ret; }
static int -get_port_status(struct usb_pipe *pipe, int port, struct usb_port_status *sts) +get_port_status(struct usbhub_s *hub, int port, struct usb_port_status *sts) { struct usb_ctrlrequest req; req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER; @@ -54,13 +60,103 @@ get_port_status(struct usb_pipe *pipe, int port, struct usb_port_status *sts) req.wValue = 0; req.wIndex = port; req.wLength = sizeof(*sts); - return send_default_control(pipe, &req, sts); + mutex_lock(&hub->lock); + int ret = send_default_control(hub->pipe, &req, sts); + mutex_unlock(&hub->lock); + return ret; +} + +static void +init_hub_port(void *data) +{ + struct usbhub_s *hub = data; + u32 port = hub->port; // XXX - find better way to pass port + + // Turn on power to port. + int ret = set_port_feature(hub, port, USB_PORT_FEAT_POWER); + if (ret) + goto fail; + + // Wait for port power to stabilize. + msleep(hub->powerwait); + + // Check periodically for a device connect. + struct usb_port_status sts; + u64 end = calc_future_tsc(USB_TIME_SIGATT); + for (;;) { + ret = get_port_status(hub, port, &sts); + if (ret) + goto fail; + if (sts.wPortStatus & USB_PORT_STAT_CONNECTION) + // Device connected. + break; + if (check_time(end)) + // No device found. + goto done; + msleep(5); + } + + // XXX - wait USB_TIME_ATTDB time? + + // Reset port. + mutex_lock(&hub->cntl->resetlock); + ret = set_port_feature(hub, port, USB_PORT_FEAT_RESET); + if (ret) + goto resetfail; + + // Wait for reset to complete. + end = calc_future_tsc(USB_TIME_DRST * 2); + for (;;) { + ret = get_port_status(hub, port, &sts); + if (ret) + goto resetfail; + if (!(sts.wPortStatus & USB_PORT_STAT_RESET)) + break; + if (check_time(end)) { + warn_timeout(); + goto resetfail; + } + msleep(5); + } + + // Reset complete. + if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION)) + // Device no longer present + goto resetfail; + + // Set address of port + struct usb_pipe *pipe = usb_set_address( + hub->cntl, !!(sts.wPortStatus & USB_PORT_STAT_LOW_SPEED)); + if (!pipe) + goto resetfail; + mutex_unlock(&hub->cntl->resetlock); + + // Configure the device + int count = configure_usb_device(pipe); + free_pipe(pipe); + if (!count) { + ret = clear_port_feature(hub, port, USB_PORT_FEAT_ENABLE); + if (ret) + goto fail; + } + hub->devcount += count; +done: + hub->threads--; + return; + +resetfail: + clear_port_feature(hub, port, USB_PORT_FEAT_ENABLE); + mutex_unlock(&hub->cntl->resetlock); +fail: + dprintf(1, "Failure on hub port %d setup\n", port); + goto done; }
// Configure a usb hub and then find devices connected to it. int usb_hub_init(struct usb_pipe *pipe) { + ASSERT32FLAT(); if (!CONFIG_USB_HUB) return -1;
@@ -69,73 +165,26 @@ usb_hub_init(struct usb_pipe *pipe) if (ret) return ret;
- // Turn on power to all ports. + struct usbhub_s hub; + memset(&hub, 0, sizeof(hub)); + hub.pipe = pipe; + hub.cntl = endp2cntl(pipe->endp); + hub.powerwait = desc.bPwrOn2PwrGood * 2; + + // Launch a thread for every port. int i; for (i=1; i<=desc.bNbrPorts; i++) { - ret = set_port_feature(pipe, i, USB_PORT_FEAT_POWER); - if (ret) - goto fail; + hub.port = i; + hub.threads++; + run_thread(init_hub_port, &hub); }
- // Wait for port detection. - msleep(desc.bPwrOn2PwrGood * 2 + USB_TIME_SIGATT); - // XXX - should poll for ports becoming active sooner and then - // possibly wait USB_TIME_ATTDB. - - // Detect down stream devices. - 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(pipe, i, &sts); - if (ret) - goto fail; - if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION)) - // XXX - power down port? - continue; + // Wait for threads to complete. + while (hub.threads) + yield();
- // Reset port. - 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(pipe, i, &sts); - if (ret) - goto fail; - if (!(sts.wPortStatus & USB_PORT_STAT_RESET)) - break; - if (check_time(end)) { - // Timeout. - warn_timeout(); - goto fail; - } - yield(); - } - if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION)) - // Device no longer present. XXX - power down port? - continue; - - // XXX - should try to parallelize configuration. - int count = configure_usb_device( - cntl, !!(sts.wPortStatus & USB_PORT_STAT_LOW_SPEED)); - if (! count) { - // Shutdown port - ret = clear_port_feature(pipe, i, USB_PORT_FEAT_ENABLE); - if (ret) - goto fail; - } - totalcount += count; - } - - dprintf(1, "Initialized USB HUB (%d ports used)\n", totalcount); - if (totalcount) + dprintf(1, "Initialized USB HUB (%d ports used)\n", hub.devcount); + if (hub.devcount) return 0; return -1; - -fail: - dprintf(1, "Failure on hub setup\n"); - return -1; } diff --git a/src/usb-hub.h b/src/usb-hub.h index 852f771..399df57 100644 --- a/src/usb-hub.h +++ b/src/usb-hub.h @@ -1,6 +1,16 @@ #ifndef __USB_HUB_H #define __USB_HUB_H
+struct usbhub_s { + struct usb_pipe *pipe; + struct usb_s *cntl; + struct mutex_s lock; + u32 powerwait; + u32 port; + u32 threads; + u32 devcount; +}; + // usb-hub.c struct usb_pipe; int usb_hub_init(struct usb_pipe *pipe); diff --git a/src/usb-ohci.c b/src/usb-ohci.c index 828507b..3e94de6 100644 --- a/src/usb-ohci.c +++ b/src/usb-ohci.c @@ -11,11 +11,109 @@ #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
#define FIT (1 << 31)
/**************************************************************** + * Root hub + ****************************************************************/ + +static void +init_ohci_port(void *data) +{ + struct usbhub_s *hub = data; + u32 port = hub->port; // XXX - find better way to pass port + + u32 sts = readl(&hub->cntl->ohci.regs->roothub_portstatus[port]); + if (!(sts & RH_PS_CCS)) + // No device. + goto done; + + // XXX - need to wait for USB_TIME_ATTDB if just powered up? + + // Signal reset + mutex_lock(&hub->cntl->resetlock); + writel(&hub->cntl->ohci.regs->roothub_portstatus[port], RH_PS_PRS); + u64 end = calc_future_tsc(USB_TIME_DRSTR * 2); + for (;;) { + sts = readl(&hub->cntl->ohci.regs->roothub_portstatus[port]); + if (!(sts & RH_PS_PRS)) + // XXX - need to ensure USB_TIME_DRSTR time in reset? + break; + if (check_time(end)) { + // Timeout. + warn_timeout(); + goto resetfail; + } + yield(); + } + + if ((sts & (RH_PS_CCS|RH_PS_PES)) != (RH_PS_CCS|RH_PS_PES)) + // Device no longer present + goto resetfail; + + // Set address of port + struct usb_pipe *pipe = usb_set_address(hub->cntl, !!(sts & RH_PS_LSDA)); + if (!pipe) + goto resetfail; + mutex_unlock(&hub->cntl->resetlock); + + // Configure the device + int count = configure_usb_device(pipe); + free_pipe(pipe); + if (! count) + // Shutdown port + writel(&hub->cntl->ohci.regs->roothub_portstatus[port] + , RH_PS_CCS|RH_PS_LSDA); + hub->devcount += count; +done: + hub->threads--; + return; + +resetfail: + // Shutdown port + writel(&hub->cntl->ohci.regs->roothub_portstatus[port] + , RH_PS_CCS|RH_PS_LSDA); + mutex_unlock(&hub->cntl->resetlock); + goto done; +} + +// Find any devices connected to the root hub. +static int +check_ohci_ports(struct usb_s *cntl) +{ + ASSERT32FLAT(); + // Turn on power for all devices on roothub. + u32 rha = readl(&cntl->ohci.regs->roothub_a); + rha &= ~(RH_A_PSM | RH_A_OCPM); + writel(&cntl->ohci.regs->roothub_status, RH_HS_LPSC); + writel(&cntl->ohci.regs->roothub_b, RH_B_PPCM); + msleep((rha >> 24) * 2); + // XXX - need to sleep for USB_TIME_SIGATT if just powered up? + + // Lanuch a thread per port. + struct usbhub_s hub; + memset(&hub, 0, sizeof(hub)); + hub.cntl = cntl; + int ports = rha & RH_A_NDP; + hub.threads = ports; + int i; + for (i=0; i<ports; i++) { + hub.port = i; + run_thread(init_ohci_port, &hub); + } + + // Wait for threads to complete. + while (hub.threads) + yield(); + + return hub.devcount; +} + + +/**************************************************************** * Setup ****************************************************************/
@@ -77,67 +175,6 @@ stop_ohci(struct usb_s *cntl) readl(&cntl->ohci.regs->control); // flush writes }
-// Find any devices connected to the root hub. -static int -check_ohci_ports(struct usb_s *cntl) -{ - // Turn on power for all devices on roothub. - u32 rha = readl(&cntl->ohci.regs->roothub_a); - rha &= ~(RH_A_PSM | RH_A_OCPM); - writel(&cntl->ohci.regs->roothub_status, RH_HS_LPSC); - writel(&cntl->ohci.regs->roothub_b, RH_B_PPCM); - msleep((rha >> 24) * 2); - // XXX - need to sleep for USB_TIME_SIGATT if just powered up? - - // Count and reset connected devices - int ports = rha & RH_A_NDP; - int totalcount = 0; - int i; - for (i=0; i<ports; i++) { - u32 sts = readl(&cntl->ohci.regs->roothub_portstatus[i]); - if (!(sts & RH_PS_CCS)) - continue; - // XXX - need to wait for USB_TIME_ATTDB if just powered up? - writel(&cntl->ohci.regs->roothub_portstatus[i], RH_PS_PRS); - u64 end = calc_future_tsc(USB_TIME_DRSTR * 2); - for (;;) { - sts = readl(&cntl->ohci.regs->roothub_portstatus[i]); - if (!(sts & RH_PS_PRS)) - // XXX - need to ensure USB_TIME_DRSTR time in reset? - break; - if (check_time(end)) { - // Timeout. - warn_timeout(); - goto shutdown; - } - yield(); - } - - if ((sts & (RH_PS_CCS|RH_PS_PES)) != (RH_PS_CCS|RH_PS_PES)) - // Device no longer present - continue; - - msleep(USB_TIME_RSTRCY); - - // XXX - should try to parallelize configuration. - int count = configure_usb_device(cntl, !!(sts & RH_PS_LSDA)); - if (! count) - // Shutdown port - writel(&cntl->ohci.regs->roothub_portstatus[i] - , RH_PS_CCS|RH_PS_LSDA); - totalcount += count; - } - if (!totalcount) - // No devices connected - goto shutdown; - return totalcount; - -shutdown: - // Turn off power to all ports - writel(&cntl->ohci.regs->roothub_status, RH_HS_LPS); - return 0; -} - void ohci_init(void *data) { diff --git a/src/usb-uhci.c b/src/usb-uhci.c index d4497bd..86eecea 100644 --- a/src/usb-uhci.c +++ b/src/usb-uhci.c @@ -13,6 +13,82 @@ #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) { diff --git a/src/usb.c b/src/usb.c index 5b3649c..ba70181 100644 --- a/src/usb.c +++ b/src/usb.c @@ -218,32 +218,6 @@ get_device_config(struct usb_pipe *pipe) return config; }
-static struct usb_pipe * -set_address(struct usb_pipe *pipe) -{ - ASSERT32FLAT(); - dprintf(3, "set_address %x\n", pipe->endp); - struct usb_s *cntl = endp2cntl(pipe->endp); - if (cntl->maxaddr >= USB_MAXADDR) - return 0; - - struct usb_ctrlrequest req; - req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; - req.bRequest = USB_REQ_SET_ADDRESS; - req.wValue = cntl->maxaddr + 1; - req.wIndex = 0; - req.wLength = 0; - int ret = send_default_control(pipe, &req, NULL); - if (ret) - return 0; - msleep(USB_TIME_SETADDR_RECOVERY); - - cntl->maxaddr++; - u32 endp = mkendp(cntl, cntl->maxaddr, 0 - , endp2speed(pipe->endp), endp2maxsize(pipe->endp)); - return alloc_control_pipe(endp); -} - static int set_configuration(struct usb_pipe *pipe, u16 val) { @@ -261,25 +235,56 @@ set_configuration(struct usb_pipe *pipe, u16 val) * Initialization and enumeration ****************************************************************/
-// Called for every found device - see if a driver is available for -// this device and do setup if so. -int -configure_usb_device(struct usb_s *cntl, int lowspeed) +// Assign an address to a device in the default state on the given +// controller. +struct usb_pipe * +usb_set_address(struct usb_s *cntl, int lowspeed) { ASSERT32FLAT(); - dprintf(3, "config_usb: %p %d\n", cntl, lowspeed); + dprintf(3, "set_address %p\n", cntl); + if (cntl->maxaddr >= USB_MAXADDR) + return NULL;
- // 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; + return NULL; } usb_alter_control(defpipe, endp); + + msleep(USB_TIME_RSTRCY); + + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; + req.bRequest = USB_REQ_SET_ADDRESS; + req.wValue = cntl->maxaddr + 1; + req.wIndex = 0; + req.wLength = 0; + int ret = send_default_control(defpipe, &req, NULL); + if (ret) + return NULL; + + msleep(USB_TIME_SETADDR_RECOVERY); + + cntl->maxaddr++; + endp = mkendp(cntl, cntl->maxaddr, 0, lowspeed, 8); + return alloc_control_pipe(endp); +} + +// Called for every found device - see if a driver is available for +// this device and do setup if so. +int +configure_usb_device(struct usb_pipe *pipe) +{ + ASSERT32FLAT(); + struct usb_s *cntl = endp2cntl(pipe->endp); + dprintf(3, "config_usb: %p\n", cntl); + + // Set the max packet size for endpoint 0 of this device. struct usb_device_descriptor dinfo; - int ret = get_device_info8(defpipe, &dinfo); + int ret = get_device_info8(pipe, &dinfo); if (ret) return 0; dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%02x\n" @@ -287,12 +292,12 @@ configure_usb_device(struct usb_s *cntl, int lowspeed) , dinfo.bDeviceProtocol, dinfo.bMaxPacketSize0); if (dinfo.bMaxPacketSize0 < 8 || dinfo.bMaxPacketSize0 > 64) return 0; - endp = mkendp(cntl, 0, 0, lowspeed, dinfo.bMaxPacketSize0); - usb_alter_control(defpipe, endp); + u32 endp = mkendp(cntl, endp2devaddr(pipe->endp), 0 + , endp2speed(pipe->endp), dinfo.bMaxPacketSize0); + usb_alter_control(pipe, endp);
// Get configuration - struct usb_pipe *pipe = NULL; - struct usb_config_descriptor *config = get_device_config(defpipe); + struct usb_config_descriptor *config = get_device_config(pipe); if (!config) return 0;
@@ -307,10 +312,7 @@ configure_usb_device(struct usb_s *cntl, int lowspeed) // Not a supported device. goto fail;
- // Set the address and configure device. - pipe = set_address(defpipe); - if (!pipe) - goto fail; + // Set the configuration. ret = set_configuration(pipe, config->bConfigurationValue); if (ret) goto fail; @@ -326,7 +328,6 @@ configure_usb_device(struct usb_s *cntl, int lowspeed) if (ret) goto fail;
- free_pipe(pipe); free(config); return 1; fail: diff --git a/src/usb.h b/src/usb.h index 0f65e39..5a6fc0f 100644 --- a/src/usb.h +++ b/src/usb.h @@ -2,6 +2,8 @@ #ifndef __USB_H #define __USB_H
+#include "util.h" // struct mutex_s + struct usb_pipe { u32 endp; }; @@ -12,6 +14,7 @@ struct usb_s { u8 maxaddr; u16 bdf; struct usb_pipe *defaultpipe; + struct mutex_s resetlock;
union { struct { @@ -33,7 +36,8 @@ extern struct usb_s USBControllers[];
// usb.c void usb_setup(void); -int configure_usb_device(struct usb_s *cntl, int lowspeed); +struct usb_pipe *usb_set_address(struct usb_s *cntl, int lowspeed); +int configure_usb_device(struct usb_pipe *pipe); struct usb_ctrlrequest; int send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req , void *data);