int ehci_send_bulk(struct usb_pipe *p, int dir, 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" , &pipe->qh, dir, data, datasize); // Allocate 4 tds on stack (16byte aligned) u8 tdsbuf[sizeof(struct ehci_qtd) * STACKQTDS + EHCI_QTD_ALIGN - 1]; struct ehci_qtd *tds = (void*)ALIGN((u32)tdsbuf, EHCI_QTD_ALIGN); memset(tds, 0, sizeof(*tds) * STACKQTDS); // Setup fields in qh u16 maxpacket = GET_FLATPTR(pipe->pipe.maxpacket); SET_FLATPTR(pipe->qh.info1 , ((1 << QH_MULT_SHIFT) | (maxpacket << QH_MAXPACKET_SHIFT) | (GET_FLATPTR(pipe->pipe.speed) << QH_SPEED_SHIFT) | (GET_FLATPTR(pipe->pipe.ep) << QH_EP_SHIFT) | (GET_FLATPTR(pipe->pipe.devaddr) << QH_DEVADDR_SHIFT))); SET_FLATPTR(pipe->qh.info2 , ((1 << QH_MULT_SHIFT) | (GET_FLATPTR(pipe->pipe.tt_port) << QH_HUBPORT_SHIFT) | (GET_FLATPTR(pipe->pipe.tt_devaddr) << QH_HUBADDR_SHIFT))); barrier(); SET_FLATPTR(pipe->qh.qtd_next, (u32)MAKE_FLATPTR(GET_SEG(SS), tds)); int tdpos = 0; while (datasize) { struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS]; int ret = ehci_wait_td(pipe, td, 5000); if (ret) 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->alt_next = EHCI_PTR_TERM; barrier(); td->token = (ehci_explen(transfer) | QTD_STS_ACTIVE | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3)); data += transfer; datasize -= transfer; } int i; for (i=0; i<STACKQTDS; i++) { struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS]; int ret = ehci_wait_td(pipe, td, 5000); if (ret) return -1; } return 0; }
int ehci_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 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, 500); if (ret) break; } free(tds); return ret; }
int ehci_send_bulk(struct usb_pipe *p, int dir, 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" , &pipe->qh, dir, data, datasize); // Allocate 4 tds on stack (with required alignment) u8 tdsbuf[sizeof(struct ehci_qtd) * STACKQTDS + EHCI_QTD_ALIGN - 1]; struct ehci_qtd *tds = (void*)ALIGN((u32)tdsbuf, EHCI_QTD_ALIGN); memset(tds, 0, sizeof(*tds) * STACKQTDS); barrier(); SET_LOWFLAT(pipe->qh.qtd_next, (u32)MAKE_FLATPTR(GET_SEG(SS), tds)); 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, 5000); if (ret) 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->alt_next = EHCI_PTR_TERM; barrier(); td->token = (ehci_explen(transfer) | QTD_STS_ACTIVE | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3)); data += transfer; datasize -= transfer; } int i; for (i=0; i<STACKQTDS; i++) { struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS]; int ret = ehci_wait_td(pipe, td, 5000); if (ret) return -1; } return 0; }