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