Exemple #1
0
static void
usbhub_remove(struct usb_device *dev)
{
	dprintft(1, "HUB(%02x): HUB device disconnect.\n", dev->devnum);

	if (!dev || !dev->handle) {
		dprintft(1, "HUB(%02x): No device entry.\n", dev->devnum);
		return;
	}

	free(dev->handle);
	dev->handle = NULL;

	usbhub_clean_list (dev);
	return;
}
Exemple #2
0
/**
 * @brief distroy urb 
 * @param host struct uhci_host
 * @param urb struct usb_request_block
 */
void
uhci_destroy_urb(struct uhci_host *host, struct usb_request_block *urb)
{
	struct uhci_td_meta *tdm, *nexttdm;
	struct usb_buffer_list *b;

	if (urb->status != URB_STATUS_UNLINKED) {
		dprintft(2, "%s: the target urb(%p) is still linked(%02x)?\n",
			__FUNCTION__, urb, urb->status);
		return;
	}

	if (URB_UHCI(urb)->qh) {
		URB_UHCI(urb)->qh->link = 
			URB_UHCI(urb)->qh->element = UHCI_QH_LINK_TE;
		free(URB_UHCI(urb)->qh);
	}
	tdm = URB_UHCI(urb)->tdm_head;
	while (tdm) {
		if (tdm->td) {
			tdm->td->link = UHCI_TD_LINK_TE;
			tdm->td->buffer = 0U;
			free(tdm->td);
		}
		nexttdm = tdm->next;
		free(tdm);
		tdm = nexttdm;
	}

	while (urb->buffers) {
		b = urb->buffers;
		if (b->vadr)
			free((void *)b->vadr);
		urb->buffers = b->next;
		free(b);
	}

	dprintft(3, "%04x: %s: urb(%p) destroyed.\n",
		 host->iobase, __FUNCTION__, urb);

	free(urb->hcpriv);
	free(urb);

	return;
}
Exemple #3
0
static int
usbhub_set_portno(struct usb_host *usbhc, u8 devadr, u64 port)
{
	usbhc->last_changed_port = port;
	dprintft(3, "HUB(%02x): HUB PORT(%d) status connect.\n",
		 devadr, port & USB_PORT_MASK);

	return USB_HOOK_PASS;
}
Exemple #4
0
static int
usbhub_device_disconnect(struct usb_host *usbhc, u8 devadr, u64 port)
{
	struct usb_device *dev;

	dprintft(3, "HUB(%02x): HUB PORT(%d) status disconnect.\n",
				 devadr, (int)(port & USB_PORT_MASK));
	dev = get_device_by_port (usbhc, port);
	if (dev)
		free_device (usbhc, dev);
	return USB_HOOK_PASS;
}
Exemple #5
0
/**
 * @brief submit bulk urb 
 * @param host struct uhci_host
 * @param device struct usb_device
 * @param endpoint u8  
 * @param data void * 
 * @param size u16 
 * @param callback int * 
 * @param arg void * 
 * @param ioc int 
 */
struct usb_request_block *
uhci_submit_bulk(struct uhci_host *host, struct usb_device *device,
		 u8 endpoint, void *data, u16 size,
		 int (*callback)(struct usb_host *,
				 struct usb_request_block *, void *), 
		 void *arg, int ioc)
{
	struct usb_endpoint_descriptor *epdesc;

	epdesc = usb_epdesc(device, endpoint);
	if (!epdesc || (USB_EP_TRANSTYPE(epdesc) != USB_ENDPOINT_TYPE_BULK)) {
		if (!epdesc)
			dprintft(2, "%04x: %s: no endpoint(%02x) found.\n",
				 host->iobase, __FUNCTION__, endpoint);
		else 
			dprintft(2, "%04x: %s: wrong endpoint(%02x).\n",
				 host->iobase, __FUNCTION__, 
				 USB_EP_TRANSTYPE(epdesc));
		return (struct usb_request_block *)NULL;
	}

	return uhci_submit_async(host, device, epdesc, 
				  data, size, callback, arg, ioc);
}
Exemple #6
0
/**
 * @brief submit bulk urb 
 * @param host struct uhci_host
 * @param device struct usb_device
 * @param endpoint u8  
 * @param data void * 
 * @param size u16 
 * @param callback int * 
 * @param arg void * 
 * @param ioc int 
 */
struct usb_request_block *
uhci_submit_bulk(struct usb_host *usbhc, struct usb_device *device,
		 struct usb_endpoint_descriptor *epdesc,
		 void *data, u16 size,
		 int (*callback)(struct usb_host *,
				 struct usb_request_block *, void *), 
		 void *arg, int ioc)
{
	struct uhci_host *host = (struct uhci_host *)usbhc->private;

	if (USB_EP_TRANSTYPE(epdesc) != USB_ENDPOINT_TYPE_BULK) {
		dprintft(2, "%04x: %s: wrong endpoint(%02x).\n",
			 host->iobase, __FUNCTION__, 
			 USB_EP_TRANSTYPE(epdesc));
		return (struct usb_request_block *)NULL;
	}

	return uhci_submit_async(host, device, epdesc, 
				  data, size, callback, arg, ioc);
}
Exemple #7
0
static void
usbhub_clean_list (struct usb_device *hubdev)
{
	struct usb_device *dev;
	struct usb_host *usbhc;

	usbhc = hubdev->host;
	if (!usbhc) {
		dprintft (1, "hubdev->host NULL.\n");
		return;
	}
again:
	for (dev = usbhc->device; dev; dev = dev->next) {
		if (dev->parent == hubdev) {
			/* if dev is hub, dev->next may be freed
			 * during free_device() */
			free_device (usbhc, dev);
			goto again;
		}
	}
}
Exemple #8
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;
}
Exemple #9
0
/**
 * @brief submit the control messagie
 * @param host struct uhci_host
 * @param device struct usb_device 
 * @param endpoint u8
 * @param csetup struct usb_device 
 * @param callback int * 
 * @param arg void* 
 * @param ioc int  
 */	
struct usb_request_block *
uhci_submit_control(struct usb_host *usbhc, struct usb_device *device, 
		    u8 endpoint, u16 pktsz, struct usb_ctrl_setup *csetup,
		    int (*callback)(struct usb_host *,
				    struct usb_request_block *, void *), 
		    void *arg, int ioc)
{
	struct uhci_host *host = (struct uhci_host *)usbhc->private;
	struct usb_request_block *urb;
	struct usb_endpoint_descriptor *epdesc;
	struct uhci_td_meta *tdm;
	struct usb_buffer_list *b;
	u32 lospeed = 0;

	epdesc = get_edesc_by_address(device, endpoint);
	if (!epdesc) {
		if (endpoint != 0) {
			dprintft(2, "%04x: %s: no endpoint(%d) found.\n",
				 host->iobase, __FUNCTION__, endpoint);

			return (struct usb_request_block *)NULL;
		}
		
		/* use the default endpoint */
		epdesc = &default_ep0;
	}

	/* determine if we are dealing with a low speed device or not */
	if (device) {
		if (device->speed == UD_SPEED_UNDEF) {
			u16 portsc;
			ASSERT (device->portno <= UHCI_NUM_PORTS_HC);
			portsc = host->portsc[(device->portno-1)];
			device->speed = (portsc & UHCI_PORTSC_LOSPEED) ? 
				UD_SPEED_LOW : UD_SPEED_FULL;
		}
		lospeed = (device->speed == UD_SPEED_LOW) ? UHCI_TD_STAT_LS : 0;
	}

	dprintft(5, "%s: epdesc->wMaxPacketSize = %d\n", 
		__FUNCTION__, epdesc->wMaxPacketSize);

	urb = uhci_create_urb(host);
	if (!urb)
		return (struct usb_request_block *)NULL;
	if (device) {
		spinlock_lock(&device->lock_dev);
		init_urb(urb, device->devnum, epdesc, callback, arg);
		spinlock_unlock(&device->lock_dev);
	}
	/* create a QH */
	URB_UHCI(urb)->qh = uhci_alloc_qh(host, &URB_UHCI(urb)->qh_phys);
	if (!URB_UHCI(urb)->qh)
		goto fail_submit_control;

	URB_UHCI(urb)->qh->link = UHCI_QH_LINK_TE;

	if (pktsz == 0)
		pktsz = epdesc->wMaxPacketSize;

	/* SETUP TD */
	URB_UHCI(urb)->tdm_head = tdm = uhci_new_td_meta(host, NULL);
	if (!tdm)
		goto fail_submit_control;
	URB_UHCI(urb)->qh->element = 
		URB_UHCI(urb)->qh_element_copy = tdm->td_phys;
	b = zalloc_usb_buffer_list();
	b->pid = USB_PID_SETUP;
	b->len = sizeof(*csetup);
	b->vadr = (virt_t)alloc2_aligned(b->len, &b->padr);
		
	if (!b->vadr) {
		free(b);
		goto fail_submit_control;
	}
	urb->buffers = b;
	memcpy((void *)b->vadr, (void *)csetup, b->len);

	tdm->td->status = tdm->status_copy =
		UHCI_TD_STAT_AC | lospeed | uhci_td_maxerr(3);
	if (device) {
		spinlock_lock(&device->lock_dev);
		tdm->td->token = tdm->token_copy =
			uhci_td_explen(sizeof(*csetup)) |
			UHCI_TD_TOKEN_ENDPOINT(epdesc->bEndpointAddress) | 
			UHCI_TD_TOKEN_DEVADDRESS(device->devnum) |
			UHCI_TD_TOKEN_PID_SETUP;
		spinlock_unlock(&device->lock_dev);
	}
	tdm->td->buffer = (phys32_t)b->padr;

	if (csetup->wLength > 0) {
		b = zalloc_usb_buffer_list();
		b->pid = USB_PID_IN;
		b->len = csetup->wLength;
		b->vadr = (virt_t)alloc2_aligned(b->len, &b->padr);

		if (!b->vadr) {
			free(b);
			goto fail_submit_control;
		}

		b->next = urb->buffers;
		urb->buffers = b;
		if (device) {
			spinlock_lock(&device->lock_dev);
			tdm = prepare_buffer_tds(host, (phys32_t)b->padr, 
						 b->len,
						 device->devnum, epdesc, 
						 (size_t)pktsz,
						 UHCI_TD_STAT_AC | 
						 UHCI_TD_STAT_SP | 
						 lospeed |
						 uhci_td_maxerr(3));
			spinlock_unlock(&device->lock_dev);
		}
		if (!tdm)
			goto fail_submit_control;
		dprintft(5, "%s: tdm->td_phys = %llx\n", 
			__FUNCTION__, tdm->td_phys);
		URB_UHCI(urb)->tdm_head->next = tdm;
		URB_UHCI(urb)->tdm_head->td->link = tdm->td_phys;

	}

	/* The 1st toggle for SETUP must be 0. */
	uhci_fixup_toggles(URB_UHCI(urb)->tdm_head, epdesc->toggle);

	/* append one more TD for the status stage */
	for (tdm = URB_UHCI(urb)->tdm_head; tdm->next; tdm = tdm->next);
	tdm->next = uhci_new_td_meta(host, NULL);
	if (!tdm->next)
		goto fail_submit_control;
	
        tdm->next->td->link = UHCI_TD_LINK_TE;
        tdm->next->td->status = UHCI_TD_STAT_AC | lospeed | uhci_td_maxerr(3);
	if (ioc) 
		tdm->next->td->status |= UHCI_TD_STAT_IC;
	if (device) {
		spinlock_lock(&device->lock_dev);
		tdm->next->td->token = uhci_td_explen(0) |
			UHCI_TD_TOKEN_ENDPOINT(epdesc->bEndpointAddress) | 
			UHCI_TD_TOKEN_DEVADDRESS(device->devnum) |
			UHCI_TD_TOKEN_DT1_TOGGLE;
		spinlock_unlock(&device->lock_dev);
	}
	tdm->next->td->token |= (csetup->wLength > 0) ? 
		UHCI_TD_TOKEN_PID_OUT : UHCI_TD_TOKEN_PID_IN;
        tdm->next->td->buffer = 0U;
	tdm->td->link = (phys32_t)tdm->next->td_phys;

	/* link the QH into the frame list */
	if (uhci_activate_urb(host, urb) != URB_STATUS_RUN)
		goto fail_submit_control;

	URB_UHCI(urb)->tdm_acttail = NULL;

	return urb;
fail_submit_control:
	uhci_destroy_urb(host, urb);
	return (struct usb_request_block *)NULL;
}
Exemple #10
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;
}
Exemple #11
0
/** 
 * @brief deactivates the urb 
 * @param host struct uhci_host
 * @param urb struct usb_request_block
 */
u8
uhci_deactivate_urb(struct usb_host *usbhc, struct usb_request_block *urb)
{
	struct uhci_host *host = (struct uhci_host *)usbhc->private;
	u8 status, type;

	/* nothing to do if already unlinked */
	if (urb->status == URB_STATUS_UNLINKED)
		return urb->status;

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

	spinlock_lock(&host->lock_hfl);

	if (urb->prevent_del) {
		urb->deferred_del = true;
		spinlock_unlock(&host->lock_hfl);
		return 0U;
	}

	/* urb link */
	if ((urb == host->fsbr_loop_head) && 
	    (urb == host->fsbr_loop_tail)) {
		dprintft(2, "%04x: %s: FSBR unlooped \n",
			 host->iobase, __FUNCTION__);
		host->fsbr = 0;
		host->fsbr_loop_head = host->fsbr_loop_tail = 
			(struct usb_request_block *)NULL;
		/* qh */
		URB_UHCI(urb->link_prev)->qh->link = UHCI_QH_LINK_TE;
	} else if (urb == host->fsbr_loop_tail) {
		/* tail of a FSBR loopback */
		dprintft(2, "%04x: %s: the tail of a FSBR loopback\n",
			 host->iobase, __FUNCTION__);
		host->fsbr_loop_tail = urb->link_prev;
		/* qh */
		URB_UHCI(host->fsbr_loop_tail)->qh->link = 
			(phys32_t)URB_UHCI(host->fsbr_loop_head)->qh_phys |
			UHCI_QH_LINK_QH;
	} else if (host->fsbr_loop_head == urb) {
		/* head of a FSBR loopback */
		dprintft(2, "%04x: %s: the head of a FSBR loopback\n",
			 host->iobase, __FUNCTION__);
		host->fsbr_loop_head = urb->link_next;
		/* qh */
		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->link;
	} else {
		/* qh */
		URB_UHCI(urb->link_prev)->qh->link = URB_UHCI(urb)->qh->link;
	}
	URB_UHCI(urb)->qh->link = UHCI_QH_LINK_TE;

	/* MEMO: There must exist urb->link_prev 
	   because of the skelton. */
	urb->link_prev->link_next = urb->link_next;
	if (urb->link_next)
		urb->link_next->link_prev = urb->link_prev;

	urb->status = URB_STATUS_UNLINKED;

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

	switch (type) {
	case USB_ENDPOINT_TYPE_INTERRUPT:
		/* through */
	case USB_ENDPOINT_TYPE_CONTROL:
		if (host->tailurb[URB_TAIL_CONTROL] == urb)
			host->tailurb[URB_TAIL_CONTROL] = urb->link_prev;
		/* through */
	case USB_ENDPOINT_TYPE_BULK:
		if (host->tailurb[URB_TAIL_BULK] == urb)
			host->tailurb[URB_TAIL_BULK] = urb->link_prev;
		break;
	case USB_ENDPOINT_TYPE_ISOCHRONOUS:
	default:
		printf("%s: transfer type(%02x) unsupported.\n",
		       __FUNCTION__, type);
	}

	status = urb->status;
	LIST4_DEL (host->inproc_urbs, list, urb);
	LIST4_ADD (host->unlinked_urbs[host->unlinked_urbs_index], list, urb);
	spinlock_unlock(&host->lock_hfl);

	return status;
}
Exemple #12
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;
}
Exemple #13
0
/**
 * @brief submit the control messagie
 * @param host struct uhci_host
 * @param device struct usb_device 
 * @param endpoint u8
 * @param csetup struct usb_device 
 * @param callback int * 
 * @param arg void* 
 * @param ioc int  
 */	
struct usb_request_block *
uhci_submit_control(struct uhci_host *host, struct usb_device *device, 
		    u8 endpoint, struct usb_ctrl_setup *csetup,
		    int (*callback)(struct usb_host *,
				    struct usb_request_block *, void *), 
		    void *arg, int ioc)
{
	struct usb_request_block *urb;
	struct usb_endpoint_descriptor *epdesc;
	struct uhci_td_meta *tdm;
	struct usb_buffer_list *b;
	size_t pktsize;

	epdesc = usb_epdesc(device, endpoint);
	if (!epdesc) {
		dprintft(2, "%04x: %s: no endpoint(%d) found.\n",
			 host->iobase, __FUNCTION__, endpoint);

		return (struct usb_request_block *)NULL;
	}

	dprintft(5, "%s: epdesc->wMaxPacketSize = %d\n", 
		__FUNCTION__, epdesc->wMaxPacketSize);

	urb = create_urb(host);
	if (!urb)
		return (struct usb_request_block *)NULL;
	if (device){
		spinlock_lock(&device->lock_dev);
		init_urb(urb, device->devnum, epdesc, callback, arg);
		spinlock_unlock(&device->lock_dev);
	}
	/* create a QH */
	URB_UHCI(urb)->qh = uhci_alloc_qh(host, &URB_UHCI(urb)->qh_phys);
	if (!URB_UHCI(urb)->qh)
		goto fail_submit_control;

	URB_UHCI(urb)->qh->link = UHCI_QH_LINK_TE;

	pktsize = epdesc->wMaxPacketSize;

	/* SETUP TD */
	URB_UHCI(urb)->tdm_head = tdm = uhci_new_td_meta(host, NULL);
	if (!tdm)
		goto fail_submit_control;
	URB_UHCI(urb)->qh->element = 
		URB_UHCI(urb)->qh_element_copy = tdm->td_phys;
	b = zalloc_usb_buffer_list();
	b->len = sizeof(*csetup);
	b->vadr = malloc_from_pool(host->pool, b->len, &b->padr);
		
	if (!b->vadr) {
		free(b);
		goto fail_submit_control;
	}
	urb->buffers = b;
	memcpy((void *)b->vadr, (void *)csetup, b->len);

	tdm->td->status = tdm->status_copy =
		UHCI_TD_STAT_AC | uhci_td_maxerr(3);
	if (device){
		spinlock_lock(&device->lock_dev);
		tdm->td->token = tdm->token_copy =
			uhci_td_explen(sizeof(*csetup)) |
			UHCI_TD_TOKEN_ENDPOINT(epdesc->bEndpointAddress) | 
			UHCI_TD_TOKEN_DEVADDRESS(device->devnum) |
			UHCI_TD_TOKEN_PID_SETUP;
		spinlock_unlock(&device->lock_dev);
	}
	tdm->td->buffer = (phys32_t)b->padr;

	if (csetup->wLength > 0) {
		b = zalloc_usb_buffer_list();
		b->len = csetup->wLength;
		b->vadr = malloc_from_pool(host->pool, b->len, &b->padr);

		if (!b->vadr) {
			free(b);
			goto fail_submit_control;
		}

		b->next = urb->buffers;
		urb->buffers = b;
		if(device){
			spinlock_lock(&device->lock_dev);
			tdm = prepare_buffer_tds(host, (phys32_t)b->padr, 
						 b->len,
						 device->devnum, epdesc, 
						 UHCI_TD_STAT_AC | 
						 UHCI_TD_STAT_SP | 
						 uhci_td_maxerr(3));
			spinlock_unlock(&device->lock_dev);
		}
		if (!tdm)
			goto fail_submit_control;
		dprintft(5, "%s: tdm->td_phys = %llx\n", 
			__FUNCTION__, tdm->td_phys);
		URB_UHCI(urb)->tdm_head->next = tdm;
		URB_UHCI(urb)->tdm_head->td->link = tdm->td_phys;

	}

	/* The 1st toggle for SETUP must be 0. */
	uhci_fixup_toggles(URB_UHCI(urb)->tdm_head, epdesc->toggle); 

	/* append one more TD for the status stage */
	for (tdm = URB_UHCI(urb)->tdm_head; tdm->next; tdm = tdm->next);
	tdm->next = uhci_new_td_meta(host, NULL);
	if (!tdm->next)
		goto fail_submit_control;
	
        tdm->next->td->link = UHCI_TD_LINK_TE;
        tdm->next->td->status = UHCI_TD_STAT_AC | uhci_td_maxerr(3);
	if (ioc) 
		tdm->next->td->status |= UHCI_TD_STAT_IC;
	if (device){
		spinlock_lock(&device->lock_dev);
		tdm->next->td->token = uhci_td_explen(0) |
			UHCI_TD_TOKEN_ENDPOINT(epdesc->bEndpointAddress) | 
			UHCI_TD_TOKEN_DEVADDRESS(device->devnum) |
			UHCI_TD_TOKEN_DT1_TOGGLE;
		spinlock_unlock(&device->lock_dev);
	}
	tdm->next->td->token |= (csetup->wLength > 0) ? 
		UHCI_TD_TOKEN_PID_OUT : UHCI_TD_TOKEN_PID_IN;
        tdm->next->td->buffer = 0U;
	tdm->td->link = (phys32_t)tdm->next->td_phys;

	/* link the QH into the frame list */
	if (uhci_activate_urb(host, urb) != URB_STATUS_RUN)
		goto fail_submit_control;

	link_urb(&host->inproc_urbs, urb);

	return urb;
fail_submit_control:
	destroy_urb(host, urb);
	return (struct usb_request_block *)NULL;
}
Exemple #14
0
static int 
init_hub_device(struct usb_host *usbhc, 
		struct usb_request_block *urb, void *arg)
{
	u8 devadr, cls;
	struct usb_device *dev;
	struct usb_device_handle *handler;
	static const struct usb_hook_pattern pat_clrpf = {
		.pid = USB_PID_SETUP,
		.mask = 0x000000000000ffffULL,
		.pattern = 0x000000000000000123ULL,
		.offset = 0,
		.next = NULL
	};

	devadr = urb->address;
	dev = urb->dev;

	/* an interface descriptor must exists */
	if (!dev || !dev->config || !dev->config->interface || 
	    !dev->config->interface->altsetting) {
		dprintft(1, "HUB(%02x): interface descriptor not found.\n",
			 devadr);
		return USB_HOOK_PASS;
	}

	/* only Hub devices interests */
	cls = dev->config->interface->altsetting->bInterfaceClass;
	if (cls != 0x09)
		return USB_HOOK_PASS;
	
	dprintft(1, "HUB(%02x): A Hub Class device found\n", devadr);

	if (dev->handle) {
		dprintft(1, "HUB(%02x): maybe reset.\n",  devadr);
		return USB_HOOK_PASS;
	}

	handler = usb_new_dev_handle (usbhc, dev);
	handler->remove = usbhub_remove;
	dev->handle = handler;

	/* notify whenever ClearPortFeature() issued. */
	spinlock_lock(&usbhc->lock_hk);
	usb_hook_register (usbhc, USB_HOOK_REPLY, USB_HOOK_MATCH_DEV |
			   USB_HOOK_MATCH_ENDP | USB_HOOK_MATCH_DATA,
			   devadr, 0, &pat_clrpf, usbhub_connect_changed,
			   NULL, dev);
	spinlock_unlock(&usbhc->lock_hk);

	return USB_HOOK_PASS;
}

void 
usbhub_init_handle(struct usb_host *host)
{
	static const struct usb_hook_pattern pat_setconf = {
		.pid = USB_PID_SETUP,
		.mask = 0x000000000000ffffULL,
		.pattern = 0x0000000000000900ULL,
		.offset = 0,
		.next = NULL
	};

	/* check a device class whenever SetConfigration() issued. */
	spinlock_lock(&host->lock_hk);
	usb_hook_register(host, USB_HOOK_REPLY, 
			  USB_HOOK_MATCH_ENDP | USB_HOOK_MATCH_DATA,
			  0, 0, &pat_setconf, init_hub_device,
			  NULL, NULL);
	spinlock_unlock(&host->lock_hk);

	printf("USB HUB Class handler registered.\n");

	return;
}

void 
hub_portdevice_register(struct usb_host *host, 
			u64 hub_port, struct usb_device *dev)
{
	struct usb_device *hubdev;

	for (hubdev = host->device; hubdev; hubdev = hubdev->next)
		if (hub_port == hubdev->portno) {
			dev->parent = hubdev;
			dprintft(3, "HUB(%02x): HUB PORT(%d) device "
				 "checked and registered.\n",
				 hubdev->devnum,
				(int)dev->portno & USB_PORT_MASK);
			break;
		}
	if (!hubdev)
		dprintft(1, "HUB(%02x): HUB device not found!?!?\n",
						 dev->devnum);

	return;
}