⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ehci-q.c

📁 host usb 主设备程序 支持sd卡 mouse keyboard 的最单单的驱动程序 gcc编译
💻 C
📖 第 1 页 / 共 3 页
字号:
			/* token in overlay may be most current */			if (state == QH_STATE_IDLE					&& cpu_to_le32 (qtd->qtd_dma)						== qh->hw_current)				token = le32_to_cpu (qh->hw_token);			/* force halt for unlinked or blocked qh, so we'll			 * patch the qh later and so that completions can't			 * activate it while we "know" it's stopped.			 */			if ((HALT_BIT & qh->hw_token) == 0) {halt:				qh->hw_token |= HALT_BIT;				wmb ();			}		}		/* remove it from the queue */		spin_lock (&urb->lock);		qtd_copy_status (ehci, urb, qtd->length, token);		do_status = (urb->status == -EREMOTEIO)				&& usb_pipecontrol (urb->pipe);		spin_unlock (&urb->lock);		if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {			last = list_entry (qtd->qtd_list.prev,					struct ehci_qtd, qtd_list);			last->hw_next = qtd->hw_next;		}		list_del (&qtd->qtd_list);		last = qtd;	}	/* last urb's completion might still need calling */	if (likely (last != NULL)) {		ehci_urb_done (ehci, last->urb);		count++;		ehci_qtd_free (ehci, last);	}	/* restore original state; caller must unlink or relink */	qh->qh_state = state;	/* be sure the hardware's done with the qh before refreshing	 * it after fault cleanup, or recovering from silicon wrongly	 * overlaying the dummy qtd (which reduces DMA chatter).	 */	if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END) {		switch (state) {		case QH_STATE_IDLE:			qh_refresh(ehci, qh);			break;		case QH_STATE_LINKED:			/* should be rare for periodic transfers,			 * except maybe high bandwidth ...			 */			if ((__constant_cpu_to_le32 (QH_SMASK)					& qh->hw_info2) != 0) {				intr_deschedule (ehci, qh);				(void) qh_schedule (ehci, qh);			} else				unlink_async (ehci, qh);			break;		/* otherwise, unlink already started */		}	}	return count;}/*-------------------------------------------------------------------------*/// high bandwidth multiplier, as encoded in highspeed endpoint descriptors#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))// ... and packet size, for any kind of endpoint descriptor#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)/* * reverse of qh_urb_transaction:  free a list of TDs. * used for cleanup after errors, before HC sees an URB's TDs. */static void qtd_list_free (	struct ehci_hcd		*ehci,	struct urb		*urb,	struct list_head	*qtd_list) {	struct list_head	*entry, *temp;	list_for_each_safe (entry, temp, qtd_list) {		struct ehci_qtd	*qtd;		qtd = list_entry (entry, struct ehci_qtd, qtd_list);		list_del (&qtd->qtd_list);		ehci_qtd_free (ehci, qtd);	}}/* * create a list of filled qtds for this URB; won't link into qh. */static struct list_head *qh_urb_transaction (	struct ehci_hcd		*ehci,	struct urb		*urb,	struct list_head	*head,	gfp_t			flags) {	struct ehci_qtd		*qtd, *qtd_prev;	dma_addr_t		buf;	int			len, maxpacket;	int			is_input;	u32			token;	/*	 * URBs map to sequences of QTDs:  one logical transaction	 */	qtd = ehci_qtd_alloc (ehci, flags);	if (unlikely (!qtd))		return NULL;	list_add_tail (&qtd->qtd_list, head);	qtd->urb = urb;	token = QTD_STS_ACTIVE;	token |= (EHCI_TUNE_CERR << 10);	/* for split transactions, SplitXState initialized to zero */	len = urb->transfer_buffer_length;	is_input = usb_pipein (urb->pipe);	if (usb_pipecontrol (urb->pipe)) {		/* SETUP pid */		qtd_fill (qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest),			token | (2 /* "setup" */ << 8), 8);		/* ... and always at least one more pid */		token ^= QTD_TOGGLE;		qtd_prev = qtd;		qtd = ehci_qtd_alloc (ehci, flags);		if (unlikely (!qtd))			goto cleanup;		qtd->urb = urb;		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);		list_add_tail (&qtd->qtd_list, head);		/* for zero length DATA stages, STATUS is always IN */		if (len == 0)			token |= (1 /* "in" */ << 8);	}	/*	 * data transfer stage:  buffer setup	 */	buf = urb->transfer_dma;	if (is_input)		token |= (1 /* "in" */ << 8);	/* else it's already initted to "out" pid (0 << 8) */	maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));	/*	 * buffer gets wrapped in one or more qtds;	 * last one may be "short" (including zero len)	 * and may serve as a control status ack	 */	for (;;) {		int this_qtd_len;		this_qtd_len = qtd_fill (qtd, buf, len, token, maxpacket);		len -= this_qtd_len;		buf += this_qtd_len;		if (is_input)			qtd->hw_alt_next = ehci->async->hw_alt_next;		/* qh makes control packets use qtd toggle; maybe switch it */		if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)			token ^= QTD_TOGGLE;		if (likely (len <= 0))			break;		qtd_prev = qtd;		qtd = ehci_qtd_alloc (ehci, flags);		if (unlikely (!qtd))			goto cleanup;		qtd->urb = urb;		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);		list_add_tail (&qtd->qtd_list, head);	}	/* unless the bulk/interrupt caller wants a chance to clean	 * up after short reads, hc should advance qh past this urb	 */	if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0				|| usb_pipecontrol (urb->pipe)))		qtd->hw_alt_next = EHCI_LIST_END;	/*	 * control requests may need a terminating data "status" ack;	 * bulk ones may need a terminating short packet (zero length).	 */	if (likely (urb->transfer_buffer_length != 0)) {		int	one_more = 0;		if (usb_pipecontrol (urb->pipe)) {			one_more = 1;			token ^= 0x0100;	/* "in" <--> "out"  */			token |= QTD_TOGGLE;	/* force DATA1 */		} else if (usb_pipebulk (urb->pipe)				&& (urb->transfer_flags & URB_ZERO_PACKET)				&& !(urb->transfer_buffer_length % maxpacket)) {			one_more = 1;		}		if (one_more) {			qtd_prev = qtd;			qtd = ehci_qtd_alloc (ehci, flags);			if (unlikely (!qtd))				goto cleanup;			qtd->urb = urb;			qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);			list_add_tail (&qtd->qtd_list, head);			/* never any data in such packets */			qtd_fill (qtd, 0, 0, token, 0);		}	}	/* by default, enable interrupt on urb completion */	if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))		qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);	return head;cleanup:	qtd_list_free (ehci, urb, head);	return NULL;}/*-------------------------------------------------------------------------*/// Would be best to create all qh's from config descriptors,// when each interface/altsetting is established.  Unlink// any previous qh and cancel its urbs first; endpoints are// implicitly reset then (data toggle too).// That'd mean updating how usbcore talks to HCDs. (2.7?)/* * Each QH holds a qtd list; a QH is used for everything except iso. * * For interrupt urbs, the scheduler must set the microframe scheduling * mask(s) each time the QH gets scheduled.  For highspeed, that's * just one microframe in the s-mask.  For split interrupt transactions * there are additional complications: c-mask, maybe FSTNs. */static struct ehci_qh *qh_make (	struct ehci_hcd		*ehci,	struct urb		*urb,	gfp_t			flags) {	struct ehci_qh		*qh = ehci_qh_alloc (ehci, flags);	u32			info1 = 0, info2 = 0;	int			is_input, type;	int			maxp = 0;	if (!qh)		return qh;	/*	 * init endpoint/device data for this QH	 */	info1 |= usb_pipeendpoint (urb->pipe) << 8;	info1 |= usb_pipedevice (urb->pipe) << 0;	is_input = usb_pipein (urb->pipe);	type = usb_pipetype (urb->pipe);	maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input);	/* Compute interrupt scheduling parameters just once, and save.	 * - allowing for high bandwidth, how many nsec/uframe are used?	 * - split transactions need a second CSPLIT uframe; same question	 * - splits also need a schedule gap (for full/low speed I/O)	 * - qh has a polling interval	 *	 * For control/bulk requests, the HC or TT handles these.	 */	if (type == PIPE_INTERRUPT) {		qh->usecs = NS_TO_US (usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,				hb_mult (maxp) * max_packet (maxp)));		qh->start = NO_FRAME;		if (urb->dev->speed == USB_SPEED_HIGH) {			qh->c_usecs = 0;			qh->gap_uf = 0;			qh->period = urb->interval >> 3;			if (qh->period == 0 && urb->interval != 1) {				/* NOTE interval 2 or 4 uframes could work.				 * But interval 1 scheduling is simpler, and				 * includes high bandwidth.				 */				dbg ("intr period %d uframes, NYET!",						urb->interval);				goto done;			}		} else {			struct usb_tt	*tt = urb->dev->tt;			int		think_time;			/* gap is f(FS/LS transfer times) */			qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed,					is_input, 0, maxp) / (125 * 1000);			/* FIXME this just approximates SPLIT/CSPLIT times */			if (is_input) {		// SPLIT, gap, CSPLIT+DATA				qh->c_usecs = qh->usecs + HS_USECS (0);				qh->usecs = HS_USECS (1);			} else {		// SPLIT+DATA, gap, CSPLIT				qh->usecs += HS_USECS (1);				qh->c_usecs = HS_USECS (0);			}			think_time = tt ? tt->think_time : 0;			qh->tt_usecs = NS_TO_US (think_time +					usb_calc_bus_time (urb->dev->speed,					is_input, 0, max_packet (maxp)));			qh->period = urb->interval;		}	}	/* support for tt scheduling, and access to toggles */	qh->dev = urb->dev;	/* using TT? */	switch (urb->dev->speed) {	case USB_SPEED_LOW:		info1 |= (1 << 12);	/* EPS "low" */		/* FALL THROUGH */	case USB_SPEED_FULL:		/* EPS 0 means "full" */		if (type != PIPE_INTERRUPT)			info1 |= (EHCI_TUNE_RL_TT << 28);		if (type == PIPE_CONTROL) {			info1 |= (1 << 27);	/* for TT */			info1 |= 1 << 14;	/* toggle from qtd */		}		info1 |= maxp << 16;		info2 |= (EHCI_TUNE_MULT_TT << 30);		/* Some Freescale processors have an erratum in which the		 * port number in the queue head was 0..N-1 instead of 1..N.		 */		if (ehci_has_fsl_portno_bug(ehci))			info2 |= (urb->dev->ttport-1) << 23;		else			info2 |= urb->dev->ttport << 23;		/* set the address of the TT; for TDI's integrated		 * root hub tt, leave it zeroed.		 */		if (!ehci_is_TDI(ehci)				|| urb->dev->tt->hub !=					ehci_to_hcd(ehci)->self.root_hub)			info2 |= urb->dev->tt->hub->devnum << 16;		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */		break;	case USB_SPEED_HIGH:		/* no TT involved */		info1 |= (2 << 12);	/* EPS "high" */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -