aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2014-12-31 01:55:48 -0500
committerKevin O'Connor <kevin@koconnor.net>2015-01-07 10:13:46 -0500
commit5372a3f7c8ceec09f7ebeb2545bfff7f38840084 (patch)
tree6fbfb9fe13dd2dddef44698279a569d1f8ba7190
parentabd674200825ef0df1cb8560b774e24db01cb9f2 (diff)
downloadseabios-5372a3f7c8ceec09f7ebeb2545bfff7f38840084.zip
seabios-5372a3f7c8ceec09f7ebeb2545bfff7f38840084.tar.gz
seabios-5372a3f7c8ceec09f7ebeb2545bfff7f38840084.tar.bz2
ohci: Merge ohci_send_control with ohci_send_bulk
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>
-rw-r--r--src/hw/usb-ohci.c90
-rw-r--r--src/hw/usb-ohci.h5
-rw-r--r--src/hw/usb.c4
3 files changed, 34 insertions, 65 deletions
diff --git a/src/hw/usb-ohci.c b/src/hw/usb-ohci.c
index ee31b83..11fe9fa 100644
--- a/src/hw/usb-ohci.c
+++ b/src/hw/usb-ohci.c
@@ -455,79 +455,37 @@ 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 STACKOTDS 18
#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)
+ // Allocate tds on stack (with required alignment)
u8 tdsbuf[sizeof(struct ohci_td) * STACKOTDS + OHCI_TD_ALIGN - 1];
struct ohci_td *tds = (void*)ALIGN((u32)tdsbuf, OHCI_TD_ALIGN), *td = tds;
memset(tds, 0, sizeof(*tds) * STACKOTDS);
// 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, dataend = dest + datasize;
while (dest < dataend) {
// Send data pids
@@ -539,20 +497,32 @@ ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
int transfer = dataend - dest;
if (transfer > maxtransfer)
transfer = ALIGN_DOWN(maxtransfer, maxpacket);
- 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 = dest + transfer - 1;
td++;
dest += transfer;
}
+ 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: