/** * @brief check urb advance * @param host struct uhci_host * @param urb struct usb_request_block * @param usbsts u16 */ static u8 check_urb_advance(struct uhci_host *host, struct usb_request_block *urb, u16 usbsts) { struct uhci_td_meta *tdm; phys32_t qh_element; int elapse, len; elapse = (uhci_current_frame_number(host) + UHCI_NUM_FRAMES - URB_UHCI(urb)->frnum_issued) & (UHCI_NUM_FRAMES - 1); if (!elapse) return urb->status; spinlock_lock(&host->lock_hfl); recheck: urb->actlen = 0; qh_element = URB_UHCI(urb)->qh->element; /* atomic */ /* count up actual length of input/output data */ for (tdm = URB_UHCI(urb)->tdm_head; tdm; tdm = tdm->next) { if (!is_active_td(tdm->td)) { len = UHCI_TD_STAT_ACTLEN(tdm->td); if (!is_setup_td(tdm->td)) urb->actlen += len; } if ((phys32_t)tdm->td_phys == qh_element) { urb->status = UHCI_TD_STAT_STATUS(tdm->td); break; } } if (is_terminate(qh_element)) { urb->status = URB_STATUS_ADVANCED; } else { /* double check */ if (qh_element != URB_UHCI(urb)->qh->element) goto recheck; if (!(urb->status & URB_STATUS_RUN) && !(urb->status & URB_STATUS_ERRORS) && (uhci_td_actlen(tdm->td) == uhci_td_maxlen(tdm->td)) && tdm->next && is_active(tdm->next->status_copy)) urb->status = URB_STATUS_RUN; } URB_UHCI(urb)->qh_element_copy = qh_element; spinlock_unlock(&host->lock_hfl); return urb->status; }
/** * @brief check urb advance * @param host struct uhci_host * @param urb struct usb_request_block * @param usbsts u16 */ static u8 uhci_check_urb_advance_sub (struct uhci_host *host, u16 ucfn, struct usb_host *usbhc, struct usb_request_block *urb) { struct uhci_td_meta *tdm; phys32_t qh_element, td_stat; int elapse; u8 new_status; size_t len, actlen; elapse = (ucfn + UHCI_NUM_FRAMES - URB_UHCI(urb)->frnum_issued) & (UHCI_NUM_FRAMES - 1); if (!elapse) return urb->status; actlen = 0; qh_element = URB_UHCI(urb)->qh->element; /* atomic */ /* check status and count up actual length of input/output * data */ new_status = URB_STATUS_ADVANCED; for (tdm = URB_UHCI(urb)->tdm_head; tdm; tdm = tdm->next) { td_stat = tdm->td->status; new_status = UHCI_TD_STATUS(td_stat); if (is_active(td_stat)) break; len = uhci_td_actlen(tdm->td); if (!is_setup_td(tdm->td)) actlen += len; if (is_error(td_stat)) break; if (tdm == URB_UHCI(urb)->tdm_acttail) break; if (len < uhci_td_maxlen(tdm->td)) /* short packet */ break; } urb->actlen = actlen; urb->status = new_status; URB_UHCI(urb)->qh_element_copy = qh_element; return new_status; }