This series refactors parts of the internal USB driver code interface. It merges the ?hci_send_bulk() and ?hci_send_control() functions into one function ?hci_send_pipe(). The control and bulk transmission functions were similar, but often had slightly different implementations and quirks. Unifying them reduces the overall code size. It also makes it easier to issue control commands at run-time, which should make it easier for future enhancements (such as keyboard led control).
I tested this on qemu and with a bunch of devices on my c720 and e350m1. However, I don't have a uhci board readily available. I'll have to dust off my via board and see if it still works. If others can run some tests that would be appreciated.
In the process of testing this series, I found that USB3 hubs aren't working that great - I sometimes get timeout messages on my e350m1 (though all functionality still works), and usb3 hubs aren't working on my c720. This does not look to be a regression though. (It does seem that USB3 hubs still need more work though).
This series is also available at: https://github.com/KevinOConnor/seabios/tree/testing
-Kevin
Kevin O'Connor (9): ehci: No need to support td array wrapping ehci: Merge ehci_send_control with ehci_send_bulk ohci: Merge ohci_send_control with ohci_send_bulk uhci: Merge uhci_send_control with uhci_send_bulk xhci: Merge xhci_send_control with xhci_send_bulk usb: Use usb_send_pipe() now that all drivers have x_send_pipe() xhci: Move xhci_xfer_x() functions together xhci: Merge some xhci_xfer_x() functions into xhci_send_pipe() usb: Control transfers always have an 8 byte command size
src/hw/usb-ehci.c | 123 +++++++++++++++--------------------------- src/hw/usb-ehci.h | 5 +- src/hw/usb-ohci.c | 87 ++++++++++-------------------- src/hw/usb-ohci.h | 5 +- src/hw/usb-uhci.c | 96 ++++++++++++--------------------- src/hw/usb-uhci.h | 5 +- src/hw/usb-xhci.c | 156 +++++++++++++++++------------------------------------- src/hw/usb-xhci.h | 5 +- src/hw/usb.c | 40 ++++++-------- src/hw/usb.h | 2 + 10 files changed, 180 insertions(+), 344 deletions(-)
The maximum bulk transfer is 64K and 4 QTDs can always transfer 64K. So, there is no need to support a transfer with more than 4 QTDs. Build the entire transaction and then submit it in one operation to simplify the code.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-ehci.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/src/hw/usb-ehci.c b/src/hw/usb-ehci.c index 8938915..feef4a1 100644 --- a/src/hw/usb-ehci.c +++ b/src/hw/usb-ehci.c @@ -626,37 +626,35 @@ ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) , &pipe->qh, dir, data, datasize);
// Allocate 4 tds on stack (with required alignment) - u32 end = timer_calc(usb_xfer_time(p, datasize)); u8 tdsbuf[sizeof(struct ehci_qtd) * STACKQTDS + EHCI_QTD_ALIGN - 1]; - struct ehci_qtd *tds = (void*)ALIGN((u32)tdsbuf, EHCI_QTD_ALIGN); + struct ehci_qtd *tds = (void*)ALIGN((u32)tdsbuf, EHCI_QTD_ALIGN), *td = tds; memset(tds, 0, sizeof(*tds) * STACKQTDS); - barrier(); - SET_LOWFLAT(pipe->qh.qtd_next, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
+ // Setup transfer descriptors u16 maxpacket = GET_LOWFLAT(pipe->pipe.maxpacket); - int tdpos = 0; while (datasize) { - struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS]; - int ret = ehci_wait_td(pipe, td, end); - if (ret) + if (td >= &tds[STACKQTDS]) { + warn_noalloc(); return -1; - - struct ehci_qtd *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS) - , &tds[tdpos % STACKQTDS]); - + } int transfer = fillTDbuffer(td, maxpacket, data, datasize); - td->qtd_next = (transfer==datasize ? EHCI_PTR_TERM : (u32)nexttd_fl); + td->qtd_next = (u32)MAKE_FLATPTR(GET_SEG(SS), td+1); td->alt_next = EHCI_PTR_TERM; - barrier(); td->token = (ehci_explen(transfer) | QTD_STS_ACTIVE | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3)); + td++;
data += transfer; datasize -= transfer; } + + // Transfer data + (td-1)->qtd_next = EHCI_PTR_TERM; + barrier(); + SET_LOWFLAT(pipe->qh.qtd_next, (u32)MAKE_FLATPTR(GET_SEG(SS), tds)); + u32 end = timer_calc(usb_xfer_time(p, datasize)); int i; - for (i=0; i<STACKQTDS; i++) { - struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS]; + for (i=0, td=tds; i<STACKQTDS; i++, td++) { int ret = ehci_wait_td(pipe, td, end); if (ret) return -1;
Merge both the control and bulk pipe sending functions into one new function: ehci_send_pipe(). The two existing functions were similar, and by merging them the resulting code supports more flexible control transfers.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-ehci.c | 93 +++++++++++++++++-------------------------------------- src/hw/usb-ehci.h | 5 ++- src/hw/usb.c | 4 +-- 3 files changed, 32 insertions(+), 70 deletions(-)
diff --git a/src/hw/usb-ehci.c b/src/hw/usb-ehci.c index feef4a1..aef3945 100644 --- a/src/hw/usb-ehci.c +++ b/src/hw/usb-ehci.c @@ -552,77 +552,16 @@ fillTDbuffer(struct ehci_qtd *td, u16 maxpacket, const void *buf, int bytes) return dest - (u32)buf; }
-int -ehci_send_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize - , void *data, int datasize) -{ - ASSERT32FLAT(); - if (! CONFIG_USB_EHCI) - return -1; - dprintf(5, "ehci_control %p (dir=%d cmd=%d data=%d)\n" - , p, dir, cmdsize, datasize); - if (datasize > 4*4096 || cmdsize > 4*4096) { - // XXX - should support larger sizes. - warn_noalloc(); - return -1; - } - struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe); - - // Setup transfer descriptors - struct ehci_qtd *tds = memalign_tmphigh(EHCI_QTD_ALIGN, sizeof(*tds) * 3); - if (!tds) { - warn_noalloc(); - return -1; - } - memset(tds, 0, sizeof(*tds) * 3); - struct ehci_qtd *td = tds; - - td->qtd_next = (u32)&td[1]; - td->alt_next = EHCI_PTR_TERM; - td->token = (ehci_explen(cmdsize) | QTD_STS_ACTIVE - | QTD_PID_SETUP | ehci_maxerr(3)); - u16 maxpacket = pipe->pipe.maxpacket; - fillTDbuffer(td, maxpacket, cmd, cmdsize); - td++; - - if (datasize) { - td->qtd_next = (u32)&td[1]; - td->alt_next = EHCI_PTR_TERM; - td->token = (QTD_TOGGLE | ehci_explen(datasize) | QTD_STS_ACTIVE - | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3)); - fillTDbuffer(td, maxpacket, data, datasize); - td++; - } - - td->qtd_next = EHCI_PTR_TERM; - td->alt_next = EHCI_PTR_TERM; - td->token = (QTD_TOGGLE | QTD_STS_ACTIVE - | (dir ? QTD_PID_OUT : QTD_PID_IN) | ehci_maxerr(3)); - - // Transfer data - u32 end = timer_calc(usb_xfer_time(p, datasize)); - barrier(); - pipe->qh.qtd_next = (u32)tds; - int i, ret=0; - for (i=0; i<3; i++) { - struct ehci_qtd *td = &tds[i]; - ret = ehci_wait_td(pipe, td, end); - if (ret) - break; - } - free(tds); - return ret; -} - #define STACKQTDS 4
int -ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) +ehci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize) { if (! CONFIG_USB_EHCI) return -1; struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe); - dprintf(7, "ehci_send_bulk qh=%p dir=%d data=%p size=%d\n" + dprintf(7, "ehci_send_pipe qh=%p dir=%d data=%p size=%d\n" , &pipe->qh, dir, data, datasize);
// Allocate 4 tds on stack (with required alignment) @@ -632,7 +571,19 @@ ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
// Setup transfer descriptors u16 maxpacket = GET_LOWFLAT(pipe->pipe.maxpacket); + u32 toggle = 0; + if (cmd) { + // Send setup pid on control transfers + int transfer = fillTDbuffer(td, maxpacket, cmd, cmdsize); + td->qtd_next = (u32)MAKE_FLATPTR(GET_SEG(SS), td+1); + td->alt_next = EHCI_PTR_TERM; + td->token = (ehci_explen(transfer) | QTD_STS_ACTIVE + | QTD_PID_SETUP | ehci_maxerr(3)); + td++; + toggle = QTD_TOGGLE; + } while (datasize) { + // Send data pids if (td >= &tds[STACKQTDS]) { warn_noalloc(); return -1; @@ -640,13 +591,25 @@ ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) int transfer = fillTDbuffer(td, maxpacket, data, datasize); td->qtd_next = (u32)MAKE_FLATPTR(GET_SEG(SS), td+1); td->alt_next = EHCI_PTR_TERM; - td->token = (ehci_explen(transfer) | QTD_STS_ACTIVE + td->token = (ehci_explen(transfer) | toggle | QTD_STS_ACTIVE | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3)); td++;
data += transfer; datasize -= transfer; } + if (cmd) { + // Send status pid on control transfers + if (td >= &tds[STACKQTDS]) { + warn_noalloc(); + return -1; + } + td->qtd_next = EHCI_PTR_TERM; + td->alt_next = EHCI_PTR_TERM; + td->token = (QTD_TOGGLE | QTD_STS_ACTIVE + | (dir ? QTD_PID_OUT : QTD_PID_IN) | ehci_maxerr(3)); + td++; + }
// Transfer data (td-1)->qtd_next = EHCI_PTR_TERM; diff --git a/src/hw/usb-ehci.h b/src/hw/usb-ehci.h index da74438..08ae046 100644 --- a/src/hw/usb-ehci.h +++ b/src/hw/usb-ehci.h @@ -9,9 +9,8 @@ struct usb_pipe; struct usb_pipe *ehci_realloc_pipe(struct usbdevice_s *usbdev , struct usb_pipe *upipe , struct usb_endpoint_descriptor *epdesc); -int ehci_send_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize - , void *data, int datasize); -int ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize); +int ehci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize); int ehci_poll_intr(struct usb_pipe *p, void *data);
diff --git a/src/hw/usb.c b/src/hw/usb.c index 75412f9..ed2db8a 100644 --- a/src/hw/usb.c +++ b/src/hw/usb.c @@ -57,7 +57,7 @@ usb_send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize case USB_TYPE_OHCI: return ohci_send_control(pipe, dir, cmd, cmdsize, data, datasize); case USB_TYPE_EHCI: - return ehci_send_control(pipe, dir, cmd, cmdsize, data, datasize); + return ehci_send_pipe(pipe, dir, cmd, cmdsize, data, datasize); case USB_TYPE_XHCI: return xhci_send_control(pipe, dir, cmd, cmdsize, data, datasize); } @@ -75,7 +75,7 @@ usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize) return -1; return ohci_send_bulk(pipe_fl, dir, data, datasize); case USB_TYPE_EHCI: - return ehci_send_bulk(pipe_fl, dir, data, datasize); + return ehci_send_pipe(pipe_fl, dir, NULL, 0, data, datasize); case USB_TYPE_XHCI: if (MODESEGMENT) return -1;
Merge both the control and bulk pipe sending functions into one new function: ohci_send_pipe(). The two existing functions were similar, and by merging them the resulting code supports more flexible control transfers.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-ohci.c | 87 +++++++++++++++++++------------------------------------ src/hw/usb-ohci.h | 5 ++-- src/hw/usb.c | 4 +-- 3 files changed, 33 insertions(+), 63 deletions(-)
diff --git a/src/hw/usb-ohci.c b/src/hw/usb-ohci.c index c32c492..fed5989 100644 --- a/src/hw/usb-ohci.c +++ b/src/hw/usb-ohci.c @@ -455,70 +455,17 @@ wait_ed(struct ohci_ed *ed, int timeout) } }
-int -ohci_send_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize - , void *data, int datasize) -{ - if (! CONFIG_USB_OHCI) - return -1; - dprintf(5, "ohci_control %p\n", p); - if (datasize > 4096) { - // XXX - should support larger sizes. - warn_noalloc(); - return -1; - } - struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe); - - // Setup transfer descriptors - struct ohci_td *tds = malloc_tmphigh(sizeof(*tds) * 3); - if (!tds) { - warn_noalloc(); - return -1; - } - struct ohci_td *td = tds; - td->hwINFO = TD_DP_SETUP | TD_T_DATA0 | TD_CC; - td->hwCBP = (u32)cmd; - td->hwNextTD = (u32)&td[1]; - td->hwBE = (u32)cmd + cmdsize - 1; - td++; - if (datasize) { - td->hwINFO = (dir ? TD_DP_IN : TD_DP_OUT) | TD_T_DATA1 | TD_CC; - td->hwCBP = (u32)data; - td->hwNextTD = (u32)&td[1]; - td->hwBE = (u32)data + datasize - 1; - td++; - } - td->hwINFO = (dir ? TD_DP_OUT : TD_DP_IN) | TD_T_DATA1 | TD_CC; - td->hwCBP = 0; - td->hwNextTD = (u32)&td[1]; - td->hwBE = 0; - td++; - - // Transfer data - pipe->ed.hwHeadP = (u32)tds; - pipe->ed.hwTailP = (u32)td; - barrier(); - pipe->ed.hwINFO &= ~ED_SKIP; - writel(&pipe->regs->cmdstatus, OHCI_CLF); - - int ret = wait_ed(&pipe->ed, usb_xfer_time(p, datasize)); - pipe->ed.hwINFO |= ED_SKIP; - if (ret) - ohci_waittick(pipe->regs); - free(tds); - return ret; -} - #define STACKOTDS 16 #define OHCI_TD_ALIGN 16
int -ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) +ohci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize) { ASSERT32FLAT(); if (! CONFIG_USB_OHCI) return -1; - dprintf(7, "ohci_send_bulk %p\n", p); + dprintf(7, "ohci_send_pipe %p\n", p); struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
// Allocate 16 tds on stack (with required alignment) @@ -528,8 +475,20 @@ ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
// Setup transfer descriptors u16 maxpacket = pipe->pipe.maxpacket; + u32 toggle = 0, statuscmd = OHCI_BLF; + if (cmd) { + // Send setup pid on control transfers + td->hwINFO = TD_DP_SETUP | TD_T_DATA0 | TD_CC; + td->hwCBP = (u32)cmd; + td->hwNextTD = (u32)&td[1]; + td->hwBE = (u32)cmd + cmdsize - 1; + td++; + toggle = TD_T_DATA1; + statuscmd = OHCI_CLF; + } u32 dest = (u32)data, end = dest + datasize; while (dest < end) { + // Send data pids if (td >= &tds[STACKOTDS]) { warn_noalloc(); return -1; @@ -538,20 +497,32 @@ ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) if ((tend / PAGE_SIZE) - (dest / PAGE_SIZE) > 1) // Transfer must not span two pages in single td tend = dest+2*PAGE_SIZE - ALIGN(dest & (PAGE_SIZE-1), maxpacket) - 1; - td->hwINFO = (dir ? TD_DP_IN : TD_DP_OUT) | TD_CC; + td->hwINFO = (dir ? TD_DP_IN : TD_DP_OUT) | toggle | TD_CC; td->hwCBP = dest; td->hwNextTD = (u32)&td[1]; td->hwBE = tend; td++; dest = tend+1; } + if (cmd) { + // Send status pid on control transfers + if (td >= &tds[STACKOTDS]) { + warn_noalloc(); + return -1; + } + td->hwINFO = (dir ? TD_DP_OUT : TD_DP_IN) | TD_T_DATA1 | TD_CC; + td->hwCBP = 0; + td->hwNextTD = (u32)&td[1]; + td->hwBE = 0; + td++; + }
// Transfer data pipe->ed.hwHeadP = (u32)tds | (pipe->ed.hwHeadP & ED_C); pipe->ed.hwTailP = (u32)td; barrier(); pipe->ed.hwINFO &= ~ED_SKIP; - writel(&pipe->regs->cmdstatus, OHCI_BLF); + writel(&pipe->regs->cmdstatus, statuscmd);
int ret = wait_ed(&pipe->ed, usb_xfer_time(p, datasize)); pipe->ed.hwINFO |= ED_SKIP; diff --git a/src/hw/usb-ohci.h b/src/hw/usb-ohci.h index db935ca..3dbc0e0 100644 --- a/src/hw/usb-ohci.h +++ b/src/hw/usb-ohci.h @@ -9,9 +9,8 @@ struct usb_pipe; struct usb_pipe *ohci_realloc_pipe(struct usbdevice_s *usbdev , struct usb_pipe *upipe , struct usb_endpoint_descriptor *epdesc); -int ohci_send_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize - , void *data, int datasize); -int ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize); +int ohci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize); int ohci_poll_intr(struct usb_pipe *p, void *data);
diff --git a/src/hw/usb.c b/src/hw/usb.c index ed2db8a..9e6cfc8 100644 --- a/src/hw/usb.c +++ b/src/hw/usb.c @@ -55,7 +55,7 @@ usb_send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize case USB_TYPE_UHCI: return uhci_send_control(pipe, dir, cmd, cmdsize, data, datasize); case USB_TYPE_OHCI: - return ohci_send_control(pipe, dir, cmd, cmdsize, data, datasize); + return ohci_send_pipe(pipe, dir, cmd, cmdsize, data, datasize); case USB_TYPE_EHCI: return ehci_send_pipe(pipe, dir, cmd, cmdsize, data, datasize); case USB_TYPE_XHCI: @@ -73,7 +73,7 @@ usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize) case USB_TYPE_OHCI: if (MODESEGMENT) return -1; - return ohci_send_bulk(pipe_fl, dir, data, datasize); + return ohci_send_pipe(pipe_fl, dir, NULL, 0, data, datasize); case USB_TYPE_EHCI: return ehci_send_pipe(pipe_fl, dir, NULL, 0, data, datasize); case USB_TYPE_XHCI:
Merge both the control and bulk pipe sending functions into one new function: uhci_send_pipe(). The two existing functions were similar, and by merging them the resulting code supports more flexible control transfers.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-uhci.c | 96 ++++++++++++++++++++----------------------------------- src/hw/usb-uhci.h | 5 ++- src/hw/usb.c | 4 +-- 3 files changed, 39 insertions(+), 66 deletions(-)
diff --git a/src/hw/usb-uhci.c b/src/hw/usb-uhci.c index 06a1d4e..890b7d6 100644 --- a/src/hw/usb-uhci.c +++ b/src/hw/usb-uhci.c @@ -443,73 +443,17 @@ wait_td(struct uhci_td *td, u32 end) return 0; }
-int -uhci_send_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize - , void *data, int datasize) -{ - ASSERT32FLAT(); - if (! CONFIG_USB_UHCI) - return -1; - dprintf(5, "uhci_control %p\n", p); - struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe); - - int maxpacket = pipe->pipe.maxpacket; - int lowspeed = pipe->pipe.speed; - int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7); - - // Setup transfer descriptors - int count = 2 + DIV_ROUND_UP(datasize, maxpacket); - struct uhci_td *tds = malloc_tmphigh(sizeof(*tds) * count); - if (!tds) { - warn_noalloc(); - return -1; - } - - tds[0].link = (u32)&tds[1] | UHCI_PTR_DEPTH; - tds[0].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0) - | TD_CTRL_ACTIVE); - tds[0].token = (uhci_explen(cmdsize) | (devaddr << TD_TOKEN_DEVADDR_SHIFT) - | USB_PID_SETUP); - tds[0].buffer = (void*)cmd; - int toggle = TD_TOKEN_TOGGLE; - int i; - for (i=1; i<count-1; i++) { - tds[i].link = (u32)&tds[i+1] | UHCI_PTR_DEPTH; - tds[i].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0) - | TD_CTRL_ACTIVE); - int len = (i == count-2 ? (datasize - (i-1)*maxpacket) : maxpacket); - tds[i].token = (uhci_explen(len) | toggle - | (devaddr << TD_TOKEN_DEVADDR_SHIFT) - | (dir ? USB_PID_IN : USB_PID_OUT)); - tds[i].buffer = data + (i-1) * maxpacket; - toggle ^= TD_TOKEN_TOGGLE; - } - tds[i].link = UHCI_PTR_TERM; - tds[i].status = (uhci_maxerr(0) | (lowspeed ? TD_CTRL_LS : 0) - | TD_CTRL_ACTIVE); - tds[i].token = (uhci_explen(0) | TD_TOKEN_TOGGLE - | (devaddr << TD_TOKEN_DEVADDR_SHIFT) - | (dir ? USB_PID_OUT : USB_PID_IN)); - tds[i].buffer = 0; - - // Transfer data - barrier(); - pipe->qh.element = (u32)&tds[0]; - int ret = wait_pipe(pipe, timer_calc(usb_xfer_time(p, datasize))); - free(tds); - return ret; -} - #define STACKTDS 16 #define TDALIGN 16
int -uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) +uhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize) { if (! CONFIG_USB_UHCI) return -1; struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe); - dprintf(7, "uhci_send_bulk qh=%p dir=%d data=%p size=%d\n" + dprintf(7, "uhci_send_pipe qh=%p dir=%d data=%p size=%d\n" , &pipe->qh, dir, data, datasize); int maxpacket = GET_LOWFLAT(pipe->pipe.maxpacket); int lowspeed = GET_LOWFLAT(pipe->pipe.speed); @@ -521,14 +465,29 @@ uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) u8 tdsbuf[sizeof(struct uhci_td) * STACKTDS + TDALIGN - 1]; struct uhci_td *tds = (void*)ALIGN((u32)tdsbuf, TDALIGN); memset(tds, 0, sizeof(*tds) * STACKTDS); + int tdpos = 0;
// Enable tds u32 end = timer_calc(usb_xfer_time(p, datasize)); barrier(); SET_LOWFLAT(pipe->qh.element, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
- int tdpos = 0; + // Setup transfer descriptors + if (cmd) { + // Send setup pid on control transfers + struct uhci_td *td = &tds[tdpos++ % STACKTDS]; + u32 nexttd = (u32)MAKE_FLATPTR(GET_SEG(SS), &tds[tdpos % STACKTDS]); + td->link = nexttd | UHCI_PTR_DEPTH; + td->token = (uhci_explen(cmdsize) | (devaddr << TD_TOKEN_DEVADDR_SHIFT) + | USB_PID_SETUP); + td->buffer = (void*)cmd; + barrier(); + td->status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0) + | TD_CTRL_ACTIVE); + toggle = TD_TOKEN_TOGGLE; + } while (datasize) { + // Send data pids struct uhci_td *td = &tds[tdpos++ % STACKTDS]; int ret = wait_td(td, end); if (ret) @@ -538,7 +497,7 @@ uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) if (transfer > maxpacket) transfer = maxpacket; u32 nexttd = (u32)MAKE_FLATPTR(GET_SEG(SS), &tds[tdpos % STACKTDS]); - td->link = (transfer==datasize + td->link = ((transfer==datasize && !cmd) ? UHCI_PTR_TERM : (nexttd | UHCI_PTR_DEPTH)); td->token = (uhci_explen(transfer) | toggle | (devaddr << TD_TOKEN_DEVADDR_SHIFT) @@ -552,6 +511,21 @@ uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) data += transfer; datasize -= transfer; } + if (cmd) { + // Send status pid on control transfers + struct uhci_td *td = &tds[tdpos++ % STACKTDS]; + int ret = wait_td(td, end); + if (ret) + goto fail; + td->link = UHCI_PTR_TERM; + td->token = (uhci_explen(0) | TD_TOKEN_TOGGLE + | (devaddr << TD_TOKEN_DEVADDR_SHIFT) + | (dir ? USB_PID_OUT : USB_PID_IN)); + td->buffer = 0; + barrier(); + td->status = (uhci_maxerr(0) | (lowspeed ? TD_CTRL_LS : 0) + | TD_CTRL_ACTIVE); + } SET_LOWFLAT(pipe->toggle, !!toggle); return wait_pipe(pipe, end); fail: diff --git a/src/hw/usb-uhci.h b/src/hw/usb-uhci.h index 541954a..c5ba43d 100644 --- a/src/hw/usb-uhci.h +++ b/src/hw/usb-uhci.h @@ -9,9 +9,8 @@ struct usb_pipe; struct usb_pipe *uhci_realloc_pipe(struct usbdevice_s *usbdev , struct usb_pipe *upipe , struct usb_endpoint_descriptor *epdesc); -int uhci_send_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize - , void *data, int datasize); -int uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize); +int uhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize); int uhci_poll_intr(struct usb_pipe *p, void *data);
diff --git a/src/hw/usb.c b/src/hw/usb.c index 9e6cfc8..053440c 100644 --- a/src/hw/usb.c +++ b/src/hw/usb.c @@ -53,7 +53,7 @@ usb_send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize switch (pipe->type) { default: case USB_TYPE_UHCI: - return uhci_send_control(pipe, dir, cmd, cmdsize, data, datasize); + return uhci_send_pipe(pipe, dir, cmd, cmdsize, data, datasize); case USB_TYPE_OHCI: return ohci_send_pipe(pipe, dir, cmd, cmdsize, data, datasize); case USB_TYPE_EHCI: @@ -69,7 +69,7 @@ usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize) switch (GET_LOWFLAT(pipe_fl->type)) { default: case USB_TYPE_UHCI: - return uhci_send_bulk(pipe_fl, dir, data, datasize); + return uhci_send_pipe(pipe_fl, dir, NULL, 0, data, datasize); case USB_TYPE_OHCI: if (MODESEGMENT) return -1;
Merge both the control and bulk pipe sending functions into one new function: xhci_send_pipe(). This makes the xhci interface similar to the other usb drivers.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-xhci.c | 45 +++++++++++++++------------------------------ src/hw/usb-xhci.h | 5 ++--- src/hw/usb.c | 4 ++-- 3 files changed, 19 insertions(+), 35 deletions(-)
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index d6caa77..6c7fc13 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -1117,50 +1117,35 @@ xhci_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe }
int -xhci_send_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize - , void *data, int datalen) +xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datalen) { if (!CONFIG_USB_XHCI) return -1; - const struct usb_ctrlrequest *req = cmd; struct xhci_pipe *pipe = container_of(p, struct xhci_pipe, pipe); struct usb_xhci_s *xhci = container_of( pipe->pipe.cntl, struct usb_xhci_s, usb);
- if (req->bRequest == USB_REQ_SET_ADDRESS) - // Set address command sent during xhci_alloc_pipe. - return 0; - - xhci_xfer_setup(pipe, req, dir, datalen); - if (datalen) - xhci_xfer_data(pipe, dir, data, datalen); - xhci_xfer_status(pipe, dir, datalen); + if (cmd) { + const struct usb_ctrlrequest *req = cmd; + if (req->bRequest == USB_REQ_SET_ADDRESS) + // Set address command sent during xhci_alloc_pipe. + return 0;
- int cc = xhci_event_wait(xhci, &pipe->reqs, usb_xfer_time(p, datalen)); - if (cc != CC_SUCCESS) { - dprintf(1, "%s: control xfer failed (cc %d)\n", __func__, cc); - return -1; + xhci_xfer_setup(pipe, req, dir, datalen); + if (datalen) + xhci_xfer_data(pipe, dir, data, datalen); + xhci_xfer_status(pipe, dir, datalen); + } else { + xhci_xfer_normal(pipe, data, datalen); }
- return 0; -} - -int -xhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datalen) -{ - if (!CONFIG_USB_XHCI) - return -1; - - struct xhci_pipe *pipe = container_of(p, struct xhci_pipe, pipe); - struct usb_xhci_s *xhci = container_of( - pipe->pipe.cntl, struct usb_xhci_s, usb); - - xhci_xfer_normal(pipe, data, datalen); int cc = xhci_event_wait(xhci, &pipe->reqs, usb_xfer_time(p, datalen)); if (cc != CC_SUCCESS) { - dprintf(1, "%s: bulk xfer failed (cc %d)\n", __func__, cc); + dprintf(1, "%s: xfer failed (cc %d)\n", __func__, cc); return -1; } + return 0; }
diff --git a/src/hw/usb-xhci.h b/src/hw/usb-xhci.h index 807d597..fc1bf7f 100644 --- a/src/hw/usb-xhci.h +++ b/src/hw/usb-xhci.h @@ -12,9 +12,8 @@ void xhci_setup(void); struct usb_pipe *xhci_realloc_pipe(struct usbdevice_s *usbdev , struct usb_pipe *upipe , struct usb_endpoint_descriptor *epdesc); -int xhci_send_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize - , void *data, int datasize); -int xhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize); +int xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize + , void *data, int datasize); int xhci_poll_intr(struct usb_pipe *p, void *data);
// -------------------------------------------------------------- diff --git a/src/hw/usb.c b/src/hw/usb.c index 053440c..a262a98 100644 --- a/src/hw/usb.c +++ b/src/hw/usb.c @@ -59,7 +59,7 @@ usb_send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize case USB_TYPE_EHCI: return ehci_send_pipe(pipe, dir, cmd, cmdsize, data, datasize); case USB_TYPE_XHCI: - return xhci_send_control(pipe, dir, cmd, cmdsize, data, datasize); + return xhci_send_pipe(pipe, dir, cmd, cmdsize, data, datasize); } }
@@ -79,7 +79,7 @@ usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize) case USB_TYPE_XHCI: if (MODESEGMENT) return -1; - return xhci_send_bulk(pipe_fl, dir, data, datasize); + return xhci_send_pipe(pipe_fl, dir, NULL, 0, data, datasize); } }
Now that all drivers have unified control and bulk transmit functions, unify the driver calling code in usb.c as well.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb.c | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-)
diff --git a/src/hw/usb.c b/src/hw/usb.c index a262a98..773057e 100644 --- a/src/hw/usb.c +++ b/src/hw/usb.c @@ -46,40 +46,23 @@ usb_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *pipe
// Send a message on a control pipe using the default control descriptor. static int -usb_send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize - , void *data, int datasize) -{ - ASSERT32FLAT(); - switch (pipe->type) { - default: - case USB_TYPE_UHCI: - return uhci_send_pipe(pipe, dir, cmd, cmdsize, data, datasize); - case USB_TYPE_OHCI: - return ohci_send_pipe(pipe, dir, cmd, cmdsize, data, datasize); - case USB_TYPE_EHCI: - return ehci_send_pipe(pipe, dir, cmd, cmdsize, data, datasize); - case USB_TYPE_XHCI: - return xhci_send_pipe(pipe, dir, cmd, cmdsize, data, datasize); - } -} - -int -usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize) +usb_send_pipe(struct usb_pipe *pipe_fl, int dir, const void *cmd, int cmdsize + , void *data, int datasize) { switch (GET_LOWFLAT(pipe_fl->type)) { default: case USB_TYPE_UHCI: - return uhci_send_pipe(pipe_fl, dir, NULL, 0, data, datasize); + return uhci_send_pipe(pipe_fl, dir, cmd, cmdsize, data, datasize); case USB_TYPE_OHCI: if (MODESEGMENT) return -1; - return ohci_send_pipe(pipe_fl, dir, NULL, 0, data, datasize); + return ohci_send_pipe(pipe_fl, dir, cmd, cmdsize, data, datasize); case USB_TYPE_EHCI: - return ehci_send_pipe(pipe_fl, dir, NULL, 0, data, datasize); + return ehci_send_pipe(pipe_fl, dir, cmd, cmdsize, data, datasize); case USB_TYPE_XHCI: if (MODESEGMENT) return -1; - return xhci_send_pipe(pipe_fl, dir, NULL, 0, data, datasize); + return xhci_send_pipe(pipe_fl, dir, cmd, cmdsize, data, datasize); } }
@@ -135,8 +118,15 @@ int usb_send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req , void *data) { - return usb_send_control(pipe, req->bRequestType & USB_DIR_IN - , req, sizeof(*req), data, req->wLength); + return usb_send_pipe(pipe, req->bRequestType & USB_DIR_IN + , req, sizeof(*req), data, req->wLength); +} + +// Send a message to a bulk endpoint +int +usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize) +{ + return usb_send_pipe(pipe_fl, dir, NULL, 0, data, datasize); }
// Check if a pipe for a given controller is on the freelist
This is purely code movement - no code changes.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-xhci.c | 162 +++++++++++++++++++++++++++--------------------------- 1 file changed, 81 insertions(+), 81 deletions(-)
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index 6c7fc13..1cfb025 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -736,39 +736,6 @@ static void xhci_trb_queue(struct xhci_ring *ring, trb->status & 0xffff); }
-static void xhci_xfer_queue(struct xhci_pipe *pipe, - struct xhci_trb *trb) -{ - xhci_trb_queue(&pipe->reqs, trb); -} - -static void xhci_xfer_kick(struct xhci_pipe *pipe) -{ - struct usb_xhci_s *xhci = container_of( - pipe->pipe.cntl, struct usb_xhci_s, usb); - u32 slotid = pipe->slotid; - u32 epid = pipe->epid; - - dprintf(5, "%s: ring %p, slotid %d, epid %d\n", - __func__, &pipe->reqs, slotid, epid); - xhci_doorbell(xhci, slotid, epid); -} - -static void xhci_xfer_normal(struct xhci_pipe *pipe, - void *data, int datalen) -{ - struct xhci_trb trb; - - memset(&trb, 0, sizeof(trb)); - trb.ptr_low = (u32)data; - trb.status = datalen; - trb.control |= (TR_NORMAL << 10); // trb type - trb.control |= TRB_TR_IOC; - - xhci_xfer_queue(pipe, &trb); - xhci_xfer_kick(pipe); -} - static int xhci_cmd_submit(struct usb_xhci_s *xhci, struct xhci_trb *cmd) { @@ -852,54 +819,6 @@ static int xhci_cmd_evaluate_context(struct usb_xhci_s *xhci, u32 slotid return xhci_cmd_submit(xhci, &cmd); }
-static void xhci_xfer_setup(struct xhci_pipe *pipe, - const struct usb_ctrlrequest *req, - int dir, int datalen) -{ - struct xhci_trb trb; - - memset(&trb, 0, sizeof(trb)); - trb.ptr_low |= req->bRequestType; - trb.ptr_low |= (req->bRequest) << 8; - trb.ptr_low |= (req->wValue) << 16; - trb.ptr_high |= req->wIndex; - trb.ptr_high |= (req->wLength) << 16; - trb.status |= 8; // length - trb.control |= (TR_SETUP << 10); // trb type - trb.control |= TRB_TR_IDT; - if (datalen) - trb.control |= (dir ? 3 : 2) << 16; // transfer type - xhci_xfer_queue(pipe, &trb); -} - -static void xhci_xfer_data(struct xhci_pipe *pipe, - int dir, void *data, int datalen) -{ - struct xhci_trb trb; - - memset(&trb, 0, sizeof(trb)); - trb.ptr_low = (u32)data; - trb.status = datalen; - trb.control |= (TR_DATA << 10); // trb type - if (dir) - trb.control |= (1 << 16); - xhci_xfer_queue(pipe, &trb); -} - -static void xhci_xfer_status(struct xhci_pipe *pipe, int dir, int datalen) -{ - struct xhci_trb trb; - - memset(&trb, 0, sizeof(trb)); - trb.control |= (TR_STATUS << 10); // trb type - trb.control |= TRB_TR_IOC; - if (!datalen || !dir) - trb.control |= (1 << 16); - - xhci_xfer_queue(pipe, &trb); - xhci_xfer_kick(pipe); -} - static struct xhci_inctx * xhci_alloc_inctx(struct usbdevice_s *usbdev, int maxepid) { @@ -1116,6 +1035,87 @@ xhci_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe return upipe; }
+static void xhci_xfer_queue(struct xhci_pipe *pipe, + struct xhci_trb *trb) +{ + xhci_trb_queue(&pipe->reqs, trb); +} + +static void xhci_xfer_kick(struct xhci_pipe *pipe) +{ + struct usb_xhci_s *xhci = container_of( + pipe->pipe.cntl, struct usb_xhci_s, usb); + u32 slotid = pipe->slotid; + u32 epid = pipe->epid; + + dprintf(5, "%s: ring %p, slotid %d, epid %d\n", + __func__, &pipe->reqs, slotid, epid); + xhci_doorbell(xhci, slotid, epid); +} + +static void xhci_xfer_normal(struct xhci_pipe *pipe, + void *data, int datalen) +{ + struct xhci_trb trb; + + memset(&trb, 0, sizeof(trb)); + trb.ptr_low = (u32)data; + trb.status = datalen; + trb.control |= (TR_NORMAL << 10); // trb type + trb.control |= TRB_TR_IOC; + + xhci_xfer_queue(pipe, &trb); + xhci_xfer_kick(pipe); +} + +static void xhci_xfer_setup(struct xhci_pipe *pipe, + const struct usb_ctrlrequest *req, + int dir, int datalen) +{ + struct xhci_trb trb; + + memset(&trb, 0, sizeof(trb)); + trb.ptr_low |= req->bRequestType; + trb.ptr_low |= (req->bRequest) << 8; + trb.ptr_low |= (req->wValue) << 16; + trb.ptr_high |= req->wIndex; + trb.ptr_high |= (req->wLength) << 16; + trb.status |= 8; // length + trb.control |= (TR_SETUP << 10); // trb type + trb.control |= TRB_TR_IDT; + if (datalen) + trb.control |= (dir ? 3 : 2) << 16; // transfer type + xhci_xfer_queue(pipe, &trb); +} + +static void xhci_xfer_data(struct xhci_pipe *pipe, + int dir, void *data, int datalen) +{ + struct xhci_trb trb; + + memset(&trb, 0, sizeof(trb)); + trb.ptr_low = (u32)data; + trb.status = datalen; + trb.control |= (TR_DATA << 10); // trb type + if (dir) + trb.control |= (1 << 16); + xhci_xfer_queue(pipe, &trb); +} + +static void xhci_xfer_status(struct xhci_pipe *pipe, int dir, int datalen) +{ + struct xhci_trb trb; + + memset(&trb, 0, sizeof(trb)); + trb.control |= (TR_STATUS << 10); // trb type + trb.control |= TRB_TR_IOC; + if (!datalen || !dir) + trb.control |= (1 << 16); + + xhci_xfer_queue(pipe, &trb); + xhci_xfer_kick(pipe); +} + int xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize , void *data, int datalen)
The xhci_xfer_setup, xhci_xfer_data, xhci_xfer_status, and xhci_xfer_normal functions are very similar - enhance xhci_xfer_queue to reduce the boiler plate in the above functions. Merge the resulting setup, data, and status code into the only function that uses them - xhci_send_pipe().
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-xhci.c | 80 +++++++++++++------------------------------------------ 1 file changed, 18 insertions(+), 62 deletions(-)
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index 1cfb025..bacae11 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -1036,9 +1036,17 @@ xhci_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe }
static void xhci_xfer_queue(struct xhci_pipe *pipe, - struct xhci_trb *trb) + void *data, int datalen, u32 flags) { - xhci_trb_queue(&pipe->reqs, trb); + struct xhci_trb trb; + memset(&trb, 0, sizeof(trb)); + if (flags & TRB_TR_IDT) + memcpy(&trb.ptr_low, data, datalen); + else + trb.ptr_low = (u32)data; + trb.status = datalen; + trb.control = flags; + xhci_trb_queue(&pipe->reqs, &trb); }
static void xhci_xfer_kick(struct xhci_pipe *pipe) @@ -1056,63 +1064,7 @@ static void xhci_xfer_kick(struct xhci_pipe *pipe) static void xhci_xfer_normal(struct xhci_pipe *pipe, void *data, int datalen) { - struct xhci_trb trb; - - memset(&trb, 0, sizeof(trb)); - trb.ptr_low = (u32)data; - trb.status = datalen; - trb.control |= (TR_NORMAL << 10); // trb type - trb.control |= TRB_TR_IOC; - - xhci_xfer_queue(pipe, &trb); - xhci_xfer_kick(pipe); -} - -static void xhci_xfer_setup(struct xhci_pipe *pipe, - const struct usb_ctrlrequest *req, - int dir, int datalen) -{ - struct xhci_trb trb; - - memset(&trb, 0, sizeof(trb)); - trb.ptr_low |= req->bRequestType; - trb.ptr_low |= (req->bRequest) << 8; - trb.ptr_low |= (req->wValue) << 16; - trb.ptr_high |= req->wIndex; - trb.ptr_high |= (req->wLength) << 16; - trb.status |= 8; // length - trb.control |= (TR_SETUP << 10); // trb type - trb.control |= TRB_TR_IDT; - if (datalen) - trb.control |= (dir ? 3 : 2) << 16; // transfer type - xhci_xfer_queue(pipe, &trb); -} - -static void xhci_xfer_data(struct xhci_pipe *pipe, - int dir, void *data, int datalen) -{ - struct xhci_trb trb; - - memset(&trb, 0, sizeof(trb)); - trb.ptr_low = (u32)data; - trb.status = datalen; - trb.control |= (TR_DATA << 10); // trb type - if (dir) - trb.control |= (1 << 16); - xhci_xfer_queue(pipe, &trb); -} - -static void xhci_xfer_status(struct xhci_pipe *pipe, int dir, int datalen) -{ - struct xhci_trb trb; - - memset(&trb, 0, sizeof(trb)); - trb.control |= (TR_STATUS << 10); // trb type - trb.control |= TRB_TR_IOC; - if (!datalen || !dir) - trb.control |= (1 << 16); - - xhci_xfer_queue(pipe, &trb); + xhci_xfer_queue(pipe, data, datalen, (TR_NORMAL << 10) | TRB_TR_IOC); xhci_xfer_kick(pipe); }
@@ -1132,10 +1084,14 @@ xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize // Set address command sent during xhci_alloc_pipe. return 0;
- xhci_xfer_setup(pipe, req, dir, datalen); + xhci_xfer_queue(pipe, (void*)req, 8, (TR_SETUP << 10) | TRB_TR_IDT + | ((datalen ? (dir ? 3 : 2) : 0) << 16)); if (datalen) - xhci_xfer_data(pipe, dir, data, datalen); - xhci_xfer_status(pipe, dir, datalen); + xhci_xfer_queue(pipe, data, datalen, (TR_DATA << 10) + | ((dir ? 1 : 0) << 16)); + xhci_xfer_queue(pipe, NULL, 0, (TR_STATUS << 10) | TRB_TR_IOC + | ((dir ? 0 : 1) << 16)); + xhci_xfer_kick(pipe); } else { xhci_xfer_normal(pipe, data, datalen); }
There is no need to pass 'cmdsize' to the usb drivers as the cmdsize is always 8 bytes.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-ehci.c | 4 ++-- src/hw/usb-ehci.h | 2 +- src/hw/usb-ohci.c | 4 ++-- src/hw/usb-ohci.h | 2 +- src/hw/usb-uhci.c | 6 +++--- src/hw/usb-uhci.h | 2 +- src/hw/usb-xhci.c | 5 +++-- src/hw/usb-xhci.h | 2 +- src/hw/usb.c | 16 ++++++++-------- src/hw/usb.h | 2 ++ 10 files changed, 24 insertions(+), 21 deletions(-)
diff --git a/src/hw/usb-ehci.c b/src/hw/usb-ehci.c index aef3945..291639e 100644 --- a/src/hw/usb-ehci.c +++ b/src/hw/usb-ehci.c @@ -555,7 +555,7 @@ fillTDbuffer(struct ehci_qtd *td, u16 maxpacket, const void *buf, int bytes) #define STACKQTDS 4
int -ehci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize +ehci_send_pipe(struct usb_pipe *p, int dir, const void *cmd , void *data, int datasize) { if (! CONFIG_USB_EHCI) @@ -574,7 +574,7 @@ ehci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize u32 toggle = 0; if (cmd) { // Send setup pid on control transfers - int transfer = fillTDbuffer(td, maxpacket, cmd, cmdsize); + int transfer = fillTDbuffer(td, maxpacket, cmd, USB_CONTROL_SETUP_SIZE); td->qtd_next = (u32)MAKE_FLATPTR(GET_SEG(SS), td+1); td->alt_next = EHCI_PTR_TERM; td->token = (ehci_explen(transfer) | QTD_STS_ACTIVE diff --git a/src/hw/usb-ehci.h b/src/hw/usb-ehci.h index 08ae046..88f7b6a 100644 --- a/src/hw/usb-ehci.h +++ b/src/hw/usb-ehci.h @@ -9,7 +9,7 @@ struct usb_pipe; struct usb_pipe *ehci_realloc_pipe(struct usbdevice_s *usbdev , struct usb_pipe *upipe , struct usb_endpoint_descriptor *epdesc); -int ehci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize +int ehci_send_pipe(struct usb_pipe *p, int dir, const void *cmd , void *data, int datasize); int ehci_poll_intr(struct usb_pipe *p, void *data);
diff --git a/src/hw/usb-ohci.c b/src/hw/usb-ohci.c index fed5989..659e454 100644 --- a/src/hw/usb-ohci.c +++ b/src/hw/usb-ohci.c @@ -459,7 +459,7 @@ wait_ed(struct ohci_ed *ed, int timeout) #define OHCI_TD_ALIGN 16
int -ohci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize +ohci_send_pipe(struct usb_pipe *p, int dir, const void *cmd , void *data, int datasize) { ASSERT32FLAT(); @@ -481,7 +481,7 @@ ohci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize td->hwINFO = TD_DP_SETUP | TD_T_DATA0 | TD_CC; td->hwCBP = (u32)cmd; td->hwNextTD = (u32)&td[1]; - td->hwBE = (u32)cmd + cmdsize - 1; + td->hwBE = (u32)cmd + USB_CONTROL_SETUP_SIZE - 1; td++; toggle = TD_T_DATA1; statuscmd = OHCI_CLF; diff --git a/src/hw/usb-ohci.h b/src/hw/usb-ohci.h index 3dbc0e0..5a275a3 100644 --- a/src/hw/usb-ohci.h +++ b/src/hw/usb-ohci.h @@ -9,7 +9,7 @@ struct usb_pipe; struct usb_pipe *ohci_realloc_pipe(struct usbdevice_s *usbdev , struct usb_pipe *upipe , struct usb_endpoint_descriptor *epdesc); -int ohci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize +int ohci_send_pipe(struct usb_pipe *p, int dir, const void *cmd , void *data, int datasize); int ohci_poll_intr(struct usb_pipe *p, void *data);
diff --git a/src/hw/usb-uhci.c b/src/hw/usb-uhci.c index 890b7d6..69c33ee 100644 --- a/src/hw/usb-uhci.c +++ b/src/hw/usb-uhci.c @@ -447,7 +447,7 @@ wait_td(struct uhci_td *td, u32 end) #define TDALIGN 16
int -uhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize +uhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd , void *data, int datasize) { if (! CONFIG_USB_UHCI) @@ -478,8 +478,8 @@ uhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize struct uhci_td *td = &tds[tdpos++ % STACKTDS]; u32 nexttd = (u32)MAKE_FLATPTR(GET_SEG(SS), &tds[tdpos % STACKTDS]); td->link = nexttd | UHCI_PTR_DEPTH; - td->token = (uhci_explen(cmdsize) | (devaddr << TD_TOKEN_DEVADDR_SHIFT) - | USB_PID_SETUP); + td->token = (uhci_explen(USB_CONTROL_SETUP_SIZE) + | (devaddr << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_SETUP); td->buffer = (void*)cmd; barrier(); td->status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0) diff --git a/src/hw/usb-uhci.h b/src/hw/usb-uhci.h index c5ba43d..bff70c6 100644 --- a/src/hw/usb-uhci.h +++ b/src/hw/usb-uhci.h @@ -9,7 +9,7 @@ struct usb_pipe; struct usb_pipe *uhci_realloc_pipe(struct usbdevice_s *usbdev , struct usb_pipe *upipe , struct usb_endpoint_descriptor *epdesc); -int uhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize +int uhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd , void *data, int datasize); int uhci_poll_intr(struct usb_pipe *p, void *data);
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index bacae11..fd58334 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -1069,7 +1069,7 @@ static void xhci_xfer_normal(struct xhci_pipe *pipe, }
int -xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize +xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd , void *data, int datalen) { if (!CONFIG_USB_XHCI) @@ -1084,7 +1084,8 @@ xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize // Set address command sent during xhci_alloc_pipe. return 0;
- xhci_xfer_queue(pipe, (void*)req, 8, (TR_SETUP << 10) | TRB_TR_IDT + xhci_xfer_queue(pipe, (void*)req, USB_CONTROL_SETUP_SIZE + , (TR_SETUP << 10) | TRB_TR_IDT | ((datalen ? (dir ? 3 : 2) : 0) << 16)); if (datalen) xhci_xfer_queue(pipe, data, datalen, (TR_DATA << 10) diff --git a/src/hw/usb-xhci.h b/src/hw/usb-xhci.h index fc1bf7f..c768c5b 100644 --- a/src/hw/usb-xhci.h +++ b/src/hw/usb-xhci.h @@ -12,7 +12,7 @@ void xhci_setup(void); struct usb_pipe *xhci_realloc_pipe(struct usbdevice_s *usbdev , struct usb_pipe *upipe , struct usb_endpoint_descriptor *epdesc); -int xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd, int cmdsize +int xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd , void *data, int datasize); int xhci_poll_intr(struct usb_pipe *p, void *data);
diff --git a/src/hw/usb.c b/src/hw/usb.c index 773057e..46e17df 100644 --- a/src/hw/usb.c +++ b/src/hw/usb.c @@ -46,23 +46,23 @@ usb_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *pipe
// Send a message on a control pipe using the default control descriptor. static int -usb_send_pipe(struct usb_pipe *pipe_fl, int dir, const void *cmd, int cmdsize +usb_send_pipe(struct usb_pipe *pipe_fl, int dir, const void *cmd , void *data, int datasize) { switch (GET_LOWFLAT(pipe_fl->type)) { default: case USB_TYPE_UHCI: - return uhci_send_pipe(pipe_fl, dir, cmd, cmdsize, data, datasize); + return uhci_send_pipe(pipe_fl, dir, cmd, data, datasize); case USB_TYPE_OHCI: if (MODESEGMENT) return -1; - return ohci_send_pipe(pipe_fl, dir, cmd, cmdsize, data, datasize); + return ohci_send_pipe(pipe_fl, dir, cmd, data, datasize); case USB_TYPE_EHCI: - return ehci_send_pipe(pipe_fl, dir, cmd, cmdsize, data, datasize); + return ehci_send_pipe(pipe_fl, dir, cmd, data, datasize); case USB_TYPE_XHCI: if (MODESEGMENT) return -1; - return xhci_send_pipe(pipe_fl, dir, cmd, cmdsize, data, datasize); + return xhci_send_pipe(pipe_fl, dir, cmd, data, datasize); } }
@@ -118,15 +118,15 @@ int usb_send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req , void *data) { - return usb_send_pipe(pipe, req->bRequestType & USB_DIR_IN - , req, sizeof(*req), data, req->wLength); + return usb_send_pipe(pipe, req->bRequestType & USB_DIR_IN, req + , data, req->wLength); }
// Send a message to a bulk endpoint int usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize) { - return usb_send_pipe(pipe_fl, dir, NULL, 0, data, datasize); + return usb_send_pipe(pipe_fl, dir, NULL, data, datasize); }
// Check if a pipe for a given controller is on the freelist diff --git a/src/hw/usb.h b/src/hw/usb.h index 208d08f..efb5e6f 100644 --- a/src/hw/usb.h +++ b/src/hw/usb.h @@ -211,6 +211,8 @@ struct usb_endpoint_descriptor { #define USB_ENDPOINT_XFER_INT 3 #define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
+#define USB_CONTROL_SETUP_SIZE 8 +
/**************************************************************** * usb mass storage flags
On Wed, Dec 31, 2014 at 07:57:21PM -0500, Kevin O'Connor wrote:
This series refactors parts of the internal USB driver code interface. It merges the ?hci_send_bulk() and ?hci_send_control() functions into one function ?hci_send_pipe(). The control and bulk transmission functions were similar, but often had slightly different implementations and quirks. Unifying them reduces the overall code size. It also makes it easier to issue control commands at run-time, which should make it easier for future enhancements (such as keyboard led control).
I tested this on qemu and with a bunch of devices on my c720 and e350m1. However, I don't have a uhci board readily available. I'll have to dust off my via board and see if it still works. If others can run some tests that would be appreciated.
In the process of testing this series, I found that USB3 hubs aren't working that great - I sometimes get timeout messages on my e350m1 (though all functionality still works), and usb3 hubs aren't working on my c720. This does not look to be a regression though. (It does seem that USB3 hubs still need more work though).
This series is also available at: https://github.com/KevinOConnor/seabios/tree/testing
FYI, I pushed this series (with a few changes to it) to the main repo.
-Kevin