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: