aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2014-12-31 01:56:53 -0500
committerKevin O'Connor <kevin@koconnor.net>2015-01-07 10:13:46 -0500
commiteb9f3ae5e652d24ff36f45dda80b013417f81f23 (patch)
treeea1127db8b2ed7470c84e11f59353dc91033da38
parent5372a3f7c8ceec09f7ebeb2545bfff7f38840084 (diff)
downloadseabios-eb9f3ae5e652d24ff36f45dda80b013417f81f23.zip
seabios-eb9f3ae5e652d24ff36f45dda80b013417f81f23.tar.gz
seabios-eb9f3ae5e652d24ff36f45dda80b013417f81f23.tar.bz2
uhci: Merge uhci_send_control with uhci_send_bulk
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>
-rw-r--r--src/hw/usb-uhci.c96
-rw-r--r--src/hw/usb-uhci.h5
-rw-r--r--src/hw/usb.c4
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;