static void ehci_free_pipes(struct usb_ehci_s *cntl) { dprintf(7, "ehci_free_pipes %p\n", cntl); struct ehci_qh *start = cntl->async_qh; struct ehci_qh *pos = start; for (;;) { struct ehci_qh *next = (void*)(pos->next & ~EHCI_PTR_BITS); if (next == start) break; struct ehci_pipe *pipe = container_of(next, struct ehci_pipe, qh); if (pipe->pipe.cntl != &cntl->usb) pos->next = next->next; else pos = next; } ehci_waittick(cntl); for (;;) { struct usb_pipe *usbpipe = cntl->usb.freelist; if (!usbpipe) break; cntl->usb.freelist = usbpipe->freenext; struct ehci_pipe *pipe = container_of(usbpipe, struct ehci_pipe, pipe); free(pipe); } }
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_LOWFLAT(pipe->qh.current); u32 tok = GET_LOWFLAT(pipe->qh.token); u32 next = GET_LOWFLAT(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_LOWFLAT(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; }
void ehci_free_pipe(struct usb_pipe *p) { if (! CONFIG_USB_EHCI) return; dprintf(7, "ehci_free_pipe %p\n", p); struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe); struct usb_ehci_s *cntl = container_of( pipe->pipe.cntl, struct usb_ehci_s, usb); struct ehci_qh *start = cntl->async_qh; struct ehci_qh *pos = start; for (;;) { struct ehci_qh *next = (void*)(pos->next & ~EHCI_PTR_BITS); if (next == start) { // Not found?! Exit without freeing. warn_internalerror(); return; } if (next == &pipe->qh) { pos->next = next->next; ehci_waittick(cntl); free(pipe); return; } pos = next; } }