static int ehci_wait_td(struct ehci_pipe *pipe, struct ehci_qtd *td, int timeout) { u64 end = calc_future_tsc(timeout); u32 status; for (;;) { status = td->token; if (!(status & QTD_STS_ACTIVE)) break; if (check_tsc(end)) { u32 cur = GET_FLATPTR(pipe->qh.current); u32 tok = GET_FLATPTR(pipe->qh.token); u32 next = GET_FLATPTR(pipe->qh.qtd_next); warn_timeout(); dprintf(1, "ehci pipe=%p cur=%08x tok=%08x next=%x td=%p status=%x\n" , pipe, cur, tok, next, td, status); ehci_reset_pipe(pipe); struct usb_ehci_s *cntl = container_of( GET_FLATPTR(pipe->pipe.cntl), struct usb_ehci_s, usb); ehci_waittick(cntl); return -1; } yield(); } if (status & QTD_STS_HALT) { dprintf(1, "ehci_wait_td error - status=%x\n", status); ehci_reset_pipe(pipe); return -2; } return 0; }
static void ehci_reset_pipe(struct ehci_pipe *pipe) { SET_FLATPTR(pipe->qh.qtd_next, EHCI_PTR_TERM); SET_FLATPTR(pipe->qh.alt_next, EHCI_PTR_TERM); barrier(); SET_FLATPTR(pipe->qh.token, GET_FLATPTR(pipe->qh.token) & QTD_TOGGLE); }
int ehci_poll_intr(struct usb_pipe *p, void *data) { ASSERT16(); if (! CONFIG_USB_EHCI) return -1; struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe); struct ehci_qtd *td = GET_FLATPTR(pipe->next_td); u32 token = GET_FLATPTR(td->token); if (token & QTD_STS_ACTIVE) // No intrs found. return -1; // XXX - check for errors. // Copy data. int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket); int pos = td - GET_FLATPTR(pipe->tds); void *tddata = GET_FLATPTR(pipe->data) + maxpacket * pos; memcpy_far(GET_SEG(SS), data , FLATPTR_TO_SEG(tddata), (void*)FLATPTR_TO_OFFSET(tddata) , maxpacket); // Reenable this td. struct ehci_qtd *next = (void*)(GET_FLATPTR(td->qtd_next) & ~EHCI_PTR_BITS); SET_FLATPTR(pipe->next_td, next); SET_FLATPTR(td->buf[0], (u32)tddata); barrier(); SET_FLATPTR(td->token, (ehci_explen(maxpacket) | QTD_STS_ACTIVE | QTD_PID_IN | ehci_maxerr(3))); return 0; }
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 ohci_poll_intr(struct usb_pipe *pipe, void *data) { ASSERT16(); if (! CONFIG_USB_OHCI) return -1; struct ohci_pipe *p = container_of(pipe, struct ohci_pipe, pipe); struct ohci_td *tds = GET_FLATPTR(p->tds); struct ohci_td *head = (void*)GET_FLATPTR(p->ed.hwHeadP); struct ohci_td *tail = (void*)GET_FLATPTR(p->ed.hwTailP); int count = GET_FLATPTR(p->count); int pos = (tail - tds + 1) % count; struct ohci_td *next = &tds[pos]; if (head == next) // No intrs found. return -1; // XXX - check for errors. // Copy data. u32 endp = GET_FLATPTR(p->pipe.endp); int maxpacket = endp2maxsize(endp); void *pipedata = GET_FLATPTR(p->data); void *intrdata = pipedata + maxpacket * pos; memcpy_far(GET_SEG(SS), data , FLATPTR_TO_SEG(intrdata), (void*)FLATPTR_TO_OFFSET(intrdata) , maxpacket); // Reenable this td. SET_FLATPTR(tail->hwINFO, TD_DP_IN | TD_T_TOGGLE | TD_CC); intrdata = pipedata + maxpacket * (tail-tds); SET_FLATPTR(tail->hwCBP, (u32)intrdata); SET_FLATPTR(tail->hwNextTD, (u32)next); SET_FLATPTR(tail->hwBE, (u32)intrdata + maxpacket - 1); SET_FLATPTR(p->ed.hwTailP, (u32)next); return 0; }