diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2014-12-31 01:56:53 -0500 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2015-01-07 10:13:46 -0500 |
commit | eb9f3ae5e652d24ff36f45dda80b013417f81f23 (patch) | |
tree | ea1127db8b2ed7470c84e11f59353dc91033da38 /src | |
parent | 5372a3f7c8ceec09f7ebeb2545bfff7f38840084 (diff) | |
download | seabios-hppa-eb9f3ae5e652d24ff36f45dda80b013417f81f23.zip seabios-hppa-eb9f3ae5e652d24ff36f45dda80b013417f81f23.tar.gz seabios-hppa-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>
Diffstat (limited to 'src')
-rw-r--r-- | src/hw/usb-uhci.c | 96 | ||||
-rw-r--r-- | src/hw/usb-uhci.h | 5 | ||||
-rw-r--r-- | 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; |