Example #1
0
u8
uhci_reactivate_urb(struct uhci_host *host, 
		   struct usb_request_block *urb, struct uhci_td_meta *tdm)
{
	struct uhci_td_meta *nexttdm, *comptdm;

	/* update the frame number that indicates issued time */
	URB_UHCI(urb)->frnum_issued = uhci_current_frame_number(host);

	spinlock_lock(&host->lock_hfl);

	/* update tdm chain */
	comptdm = URB_UHCI(urb)->tdm_head;
	URB_UHCI(urb)->tdm_head = tdm;

	/* update qh->element */
	URB_UHCI(urb)->qh->element =(phys32_t)tdm->td_phys;

	/* reactivate the urb */
	urb->status = URB_STATUS_RUN;

	spinlock_unlock(&host->lock_hfl);

	/* clean up completed TDs */
	while (comptdm != tdm) {
		comptdm->td->link = UHCI_TD_LINK_TE;
		free(comptdm->td);
		nexttdm = comptdm->next;
		free(comptdm);
		comptdm = nexttdm;
	}

	return urb->status;
}
Example #2
0
u8
uhci_check_urb_advance(struct usb_host *usbhc,
		       struct usb_request_block *urb)
{
	struct uhci_host *host = (struct uhci_host *)usbhc->private;
	u16 ucfn;

	ucfn = uhci_current_frame_number (host);
	return uhci_check_urb_advance_sub (host, ucfn, usbhc, urb);
}
Example #3
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;
}
Example #4
0
/**
 * @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;
}
Example #5
0
/**
 * @brief activate urb 
 * @param host struct uhci_host *host
 * @param urb struct usb_request_block 
 */
u8
uhci_activate_urb(struct uhci_host *host, struct usb_request_block *urb)
{
	u8 status, type;
	int n;

	type = (urb->endpoint) ? 
		USB_EP_TRANSTYPE(urb->endpoint) : USB_ENDPOINT_TYPE_CONTROL;

	spinlock_lock(&host->lock_hfl);

	switch (type) {
	case USB_ENDPOINT_TYPE_INTERRUPT:
		n = __ffs(urb->endpoint->bInterval | 
			  (1 << (UHCI_NUM_SKELTYPES - 1)));
		/* MEMO: a new interrupt urb must be 
		   inserted just after a skelton anytime. */
		urb->link_prev = host->host_skelton[n];
		if (host->host_skelton[n] ==
		    host->tailurb[URB_TAIL_CONTROL])
			host->tailurb[URB_TAIL_CONTROL] = urb;
		if (host->host_skelton[n] ==
		    host->tailurb[URB_TAIL_BULK])
			host->tailurb[URB_TAIL_BULK] = urb;
		break;
	case USB_ENDPOINT_TYPE_CONTROL:
		urb->link_prev = host->tailurb[URB_TAIL_CONTROL];
		if (host->tailurb[URB_TAIL_CONTROL] == 
		    host->tailurb[URB_TAIL_BULK])
			host->tailurb[URB_TAIL_BULK] = urb;
		host->tailurb[URB_TAIL_CONTROL] = urb;
		break;
	case USB_ENDPOINT_TYPE_BULK:
		urb->link_prev = host->tailurb[URB_TAIL_BULK];
		host->tailurb[URB_TAIL_BULK] = urb;
		break;
	case USB_ENDPOINT_TYPE_ISOCHRONOUS:
	default:
		printf("%s: transfer type(%02x) unsupported.\n",
		       __FUNCTION__, type);
		status = urb->status;
		return status;
	}

	/* initialize qh_element_copy for detecting advance after NAK */
	URB_UHCI(urb)->qh_element_copy = URB_UHCI(urb)->qh->element;

	/* urb link */
	urb->link_next = urb->link_prev->link_next;
	urb->link_prev->link_next = urb;
	if (urb->link_next) {
		/* make a backward pointer */
		urb->link_next->link_prev = urb;
	} else if (type == USB_ENDPOINT_TYPE_BULK) {
		if (host->fsbr) {
			dprintft(2, "%04x: %s: append it to the "
				 "FSBR loopback.\n",
				 host->iobase, __FUNCTION__);
			host->fsbr_loop_tail = urb;
		} else {
			dprintft(2, "%04x: %s: make a FSBR loopback.\n",
				 host->iobase, __FUNCTION__);
			host->fsbr = 1;
			host->fsbr_loop_head = urb;
			host->fsbr_loop_tail = urb;
		}
	}

	/* record the current frame number */
	URB_UHCI(urb)->frnum_issued = uhci_current_frame_number(host);

	/* qh link */
	URB_UHCI(urb)->qh->link = URB_UHCI(urb->link_prev)->qh->link;
	if (host->fsbr_loop_tail)
		URB_UHCI(host->fsbr_loop_tail)->qh->link = (phys32_t)
			URB_UHCI(host->fsbr_loop_head)->qh_phys | 
			UHCI_QH_LINK_QH;
	URB_UHCI(urb->link_prev)->qh->link = 
		URB_UHCI(urb)->qh_phys | UHCI_QH_LINK_QH;

	urb->status = URB_STATUS_RUN;

	dprintft(3, "%s: The urb link is %p <- %p -> %p.\n", 
		__FUNCTION__, urb->link_prev, urb, urb->link_next);

	status = urb->status;
	LIST4_PUSH (host->inproc_urbs, list, urb);
	spinlock_unlock(&host->lock_hfl);

	return status;
}