Exemple #1
0
/**
 * @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;
}
Exemple #2
0
/**
 * @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;
}