/** * @brief chek_advance * @param host struct uhci_host */ int uhci_check_advance(struct usb_host *usbhc) { struct uhci_host *host = (struct uhci_host *)usbhc->private; struct usb_request_block *urb, *nexturb; int advance = 0; int ucfn = -1; if (cmpxchgl(&host->incheck, 0U, 1U)) return 0; #if 0 in16(host->iobase + UHCI_REG_USBSTS, &usbsts); if (usbsts) dprintft(2, "%04x: %s: usbsts = %04x\n", host->iobase, __FUNCTION__, usbsts); #endif /* 0 */ spinlock_lock(&host->lock_hfl); recheck: for (urb = LIST4_HEAD (host->inproc_urbs, list); urb; urb = nexturb) { urb->prevent_del = true; spinlock_unlock(&host->lock_hfl); /* update urb->status */ if (urb->status == URB_STATUS_RUN) { if (ucfn < 0) ucfn = uhci_current_frame_number (host); uhci_check_urb_advance_sub (host, ucfn, host->hc, urb); } switch (urb->status) { default: /* errors */ dprintft(2, "%04x: %s: got some errors(%s) " "for urb(%p).\n", host->iobase, __FUNCTION__, uhci_error_status_string(urb->status), urb); /* through */ case URB_STATUS_ADVANCED: if (urb->callback) (urb->callback) (host->hc, urb, urb->cb_arg); advance++; break; case URB_STATUS_NAK: dprintft(2, "%04x: %s: got an NAK for urb(%p).\n", host->iobase, __FUNCTION__, urb); urb->status = URB_STATUS_RUN; case URB_STATUS_RUN: case URB_STATUS_FINALIZED: case URB_STATUS_UNLINKED: break; } spinlock_lock(&host->lock_hfl); nexturb = LIST4_NEXT (urb, list); urb->prevent_del = false; if (urb->deferred_del) { urb->deferred_del = false; spinlock_unlock(&host->lock_hfl); uhci_deactivate_urb(host->hc, urb); spinlock_lock(&host->lock_hfl); goto recheck; } } spinlock_unlock(&host->lock_hfl); #if 0 if (advance) { dprintft(3, "%s: USBSTS register cleared.\n", __FUNCTION__); out16(host->iobase + UHCI_REG_USBSTS, usbsts); } #endif host->incheck = 0U; return advance; }
/** * @brief chek_advance * @param host struct uhci_host */ int check_advance(struct uhci_host *host) { struct usb_request_block *urb, *nexturb; int advance = 0, ret = 0; u16 usbsts = 0U; if (cmpxchgl(&host->incheck, 0U, 1U)) return 0; #if 0 in16(host->iobase + UHCI_REG_USBSTS, &usbsts); if (usbsts) dprintft(2, "%04x: %s: usbsts = %04x\n", host->iobase, __FUNCTION__, usbsts); #endif /* 0 */ urb = host->inproc_urbs; while (urb) { /* update urb->status */ if (urb->status == URB_STATUS_RUN) check_urb_advance(host, urb, usbsts); switch (urb->status) { case URB_STATUS_UNLINKED: spinlock_lock(&host->lock_hfl); nexturb = urb->next; remove_urb(&host->inproc_urbs, urb); destroy_urb(host, urb); dprintft(3, "%04x: %s: urb(%p) destroyed.\n", host->iobase, __FUNCTION__, urb); urb = nexturb; spinlock_unlock(&host->lock_hfl); continue; default: /* errors */ dprintft(2, "%04x: %s: got some errors(%s) " "for urb(%p).\n", host->iobase, __FUNCTION__, uhci_error_status_string(urb->status), urb); uhci_dump_all(3, host, urb); /* through */ case URB_STATUS_ADVANCED: if (urb->callback) ret = (urb->callback)(host->hc, urb, urb->cb_arg); advance++; break; case URB_STATUS_NAK: dprintft(2, "%04x: %s: got an NAK for urb(%p).\n", host->iobase, __FUNCTION__, urb); if (urb->shadow) uhci_force_copyback(host, urb); urb->status = URB_STATUS_RUN; case URB_STATUS_RUN: case URB_STATUS_FINALIZED: break; } urb = urb->next; } #if 0 if (advance) { dprintft(3, "%s: USBSTS register cleared.\n", __FUNCTION__); out16(host->iobase + UHCI_REG_USBSTS, usbsts); } #endif host->incheck = 0U; return advance; }