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

📄 ehci-sched.c

📁 linux2.4.20下的针对三星公司的s3c2410的usb模块驱动代码
💻 C
📖 第 1 页 / 共 3 页
字号:
			itd->uframe = uframe;			itd->hw_transaction [uframe & 0x07] = itd->transaction;			itd_link (ehci, (uframe >> 3) % ehci->periodic_size,				itd);			wmb ();			usecs += itd->usecs;			itd = list_entry (itd->itd_list.next,				struct ehci_itd, itd_list);		}		/* update bandwidth utilization records (for usbfs)		 *		 * FIXME This claims each URB queued to an endpoint, as if		 * transfers were concurrent, not sequential.  So bandwidth		 * typically gets double-billed ... comes from tying it to		 * URBs rather than endpoints in the schedule.  Luckily we		 * don't use this usbfs data for serious decision making.		 */		usecs /= urb->number_of_packets;		usecs /= urb->interval;		usecs >>= 3;		if (usecs < 1)			usecs = 1;		usb_claim_bandwidth (urb->dev, urb, usecs, 1);		/* maybe enable periodic schedule processing */		if (!ehci->periodic_urbs++)			enable_periodic (ehci);		return 0;	} while ((start = ++start % mod) != max);	/* no room in the schedule */	dbg ("urb %p, CAN'T SCHEDULE", urb);	return -ENOSPC;}/*-------------------------------------------------------------------------*/#define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)static unsigned longitd_complete (	struct ehci_hcd	*ehci,	struct ehci_itd	*itd,	unsigned	uframe,	unsigned long	flags) {	struct urb				*urb = itd->urb;	struct iso_packet_descriptor		*desc;	u32					t;	/* update status for this uframe's transfers */	desc = &urb->iso_frame_desc [itd->index];	t = itd->hw_transaction [uframe];	itd->hw_transaction [uframe] = 0;	if (t & EHCI_ISOC_ACTIVE)		desc->status = -EXDEV;	else if (t & ISO_ERRS) {		urb->error_count++;		if (t & EHCI_ISOC_BUF_ERR)			desc->status = usb_pipein (urb->pipe)				? -ENOSR  /* couldn't read */				: -ECOMM; /* couldn't write */		else if (t & EHCI_ISOC_BABBLE)			desc->status = -EOVERFLOW;		else /* (t & EHCI_ISOC_XACTERR) */			desc->status = -EPROTO;		/* HC need not update length with this error */		if (!(t & EHCI_ISOC_BABBLE))			desc->actual_length += EHCI_ITD_LENGTH (t);	} else {		desc->status = 0;		desc->actual_length += EHCI_ITD_LENGTH (t);	}	vdbg ("itd %p urb %p packet %d/%d trans %x status %d len %d",		itd, urb, itd->index + 1, urb->number_of_packets,		t, desc->status, desc->actual_length);	/* handle completion now? */	if ((itd->index + 1) != urb->number_of_packets)		return flags;	/*	 * Always give the urb back to the driver ... expect it to submit	 * a new urb (or resubmit this), and to have another already queued	 * when un-interrupted transfers are needed.	 *	 * NOTE that for now we don't accelerate ISO unlinks; they just	 * happen according to the current schedule.  Means a delay of	 * up to about a second (max).	 */	itd_free_list (ehci, urb);	if (urb->status == -EINPROGRESS)		urb->status = 0;	spin_unlock_irqrestore (&ehci->lock, flags);	usb_hcd_giveback_urb (&ehci->hcd, urb);	spin_lock_irqsave (&ehci->lock, flags);	/* defer stopping schedule; completion can submit */	ehci->periodic_urbs--;	if (!ehci->periodic_urbs)		disable_periodic (ehci);	return flags;}/*-------------------------------------------------------------------------*/static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags){	int		status;	unsigned long	flags;	dbg ("itd_submit urb %p", urb);	/* NOTE DMA mapping assumes this ... */	if (urb->iso_frame_desc [0].offset != 0)		return -EINVAL;		/* allocate ITDs w/o locking anything */	status = itd_urb_transaction (ehci, urb, mem_flags);	if (status < 0)		return status;	/* schedule ... need to lock */	spin_lock_irqsave (&ehci->lock, flags);	status = itd_schedule (ehci, urb);	spin_unlock_irqrestore (&ehci->lock, flags);	if (status < 0)		itd_free_list (ehci, urb);	return status;}#ifdef have_split_iso/*-------------------------------------------------------------------------*//* * "Split ISO TDs" ... used for USB 1.1 devices going through * the TTs in USB 2.0 hubs. */static voidsitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd){	pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma);}static struct ehci_sitd *sitd_make (	struct ehci_hcd	*ehci,	struct urb	*urb,	unsigned	index,		// urb->iso_frame_desc [index]	unsigned	uframe,		// scheduled start	dma_addr_t	dma,		// mapped transfer buffer	int		mem_flags) {	struct ehci_sitd	*sitd;	unsigned		length;	sitd = pci_pool_alloc (ehci->sitd_pool, mem_flags, &dma);	if (!sitd)		return sitd;	sitd->urb = urb;	length = urb->iso_frame_desc [index].length;	dma += urb->iso_frame_desc [index].offset;#if 0	// FIXME:  do the rest!#else	sitd_free (ehci, sitd);	return 0;#endif}static voidsitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd){	u32		ptr;	ptr = cpu_to_le32 (sitd->sitd_dma | 2);	// type 2 == sitd	if (ehci->pshadow [frame].ptr) {		if (!sitd->sitd_next.ptr) {			sitd->sitd_next = ehci->pshadow [frame];			sitd->hw_next = ehci->periodic [frame];		} else if (sitd->sitd_next.ptr != ehci->pshadow [frame].ptr) {			dbg ("frame %d sitd link goof", frame);			BUG ();		}	}	ehci->pshadow [frame].sitd = sitd;	ehci->periodic [frame] = ptr;}static unsigned longsitd_complete (	struct ehci_hcd *ehci,	struct ehci_sitd	*sitd,	unsigned long		flags) {	// FIXME -- implement!	dbg ("NYI -- sitd_complete");	return flags;}/*-------------------------------------------------------------------------*/static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags){	// struct ehci_sitd	*first_sitd = 0;	unsigned		frame_index;	dma_addr_t		dma;	dbg ("NYI -- sitd_submit");	// FIXME -- implement!	// FIXME:  setup one big dma mapping	dma = 0;	for (frame_index = 0;			frame_index < urb->number_of_packets;			frame_index++) {		struct ehci_sitd	*sitd;		unsigned		uframe;		// FIXME:  use real arguments, schedule this!		uframe = -1;		sitd = sitd_make (ehci, urb, frame_index,				uframe, dma, mem_flags);		if (sitd) {    /*			if (first_sitd)				list_add_tail (&sitd->sitd_list,						&first_sitd->sitd_list);			else				first_sitd = sitd;    */		} else {			// FIXME:  clean everything up		}	}	// if we have a first sitd, then		// store them all into the periodic schedule!		// urb->hcpriv = first sitd in sitd_list	return -ENOSYS;}#endif /* have_split_iso *//*-------------------------------------------------------------------------*/static void scan_periodic (struct ehci_hcd *ehci){	unsigned	frame, clock, now_uframe, mod;	unsigned long	flags;	mod = ehci->periodic_size << 3;	spin_lock_irqsave (&ehci->lock, flags);	/*	 * When running, scan from last scan point up to "now"	 * else clean up by scanning everything that's left.	 * Touches as few pages as possible:  cache-friendly.	 * Don't scan ISO entries more than once, though.	 */	frame = ehci->next_uframe >> 3;	if (HCD_IS_RUNNING (ehci->hcd.state))		now_uframe = readl (&ehci->regs->frame_index);	else		now_uframe = (frame << 3) - 1;	now_uframe %= mod;	clock = now_uframe >> 3;	for (;;) {		union ehci_shadow	q, *q_p;		u32			type, *hw_p;		unsigned		uframes;restart:		/* scan schedule to _before_ current frame index */		if (frame == clock)			uframes = now_uframe & 0x07;		else			uframes = 8;		q_p = &ehci->pshadow [frame];		hw_p = &ehci->periodic [frame];		q.ptr = q_p->ptr;		type = Q_NEXT_TYPE (*hw_p);		/* scan each element in frame's queue for completions */		while (q.ptr != 0) {			int			last;			unsigned		uf;			union ehci_shadow	temp;			switch (type) {			case Q_TYPE_QH:				last = (q.qh->hw_next == EHCI_LIST_END);				temp = q.qh->qh_next;				type = Q_NEXT_TYPE (q.qh->hw_next);				flags = intr_complete (ehci, frame,						qh_get (q.qh), flags);				qh_put (ehci, q.qh);				q = temp;				break;			case Q_TYPE_FSTN:				last = (q.fstn->hw_next == EHCI_LIST_END);				/* for "save place" FSTNs, look at QH entries				 * in the previous frame for completions.				 */				if (q.fstn->hw_prev != EHCI_LIST_END) {					dbg ("ignoring completions from FSTNs");				}				type = Q_NEXT_TYPE (q.fstn->hw_next);				q = q.fstn->fstn_next;				break;			case Q_TYPE_ITD:				last = (q.itd->hw_next == EHCI_LIST_END);				/* Unlink each (S)ITD we see, since the ISO				 * URB model forces constant rescheduling.				 * That complicates sharing uframes in ITDs,				 * and means we need to skip uframes the HC				 * hasn't yet processed.				 */				for (uf = 0; uf < uframes; uf++) {					if (q.itd->hw_transaction [uf] != 0) {						temp = q;						*q_p = q.itd->itd_next;						*hw_p = q.itd->hw_next;						type = Q_NEXT_TYPE (*hw_p);						/* might free q.itd ... */						flags = itd_complete (ehci,							temp.itd, uf, flags);						break;					}				}				/* we might skip this ITD's uframe ... */				if (uf == uframes) {					q_p = &q.itd->itd_next;					hw_p = &q.itd->hw_next;					type = Q_NEXT_TYPE (q.itd->hw_next);				}				q = *q_p;				break;#ifdef have_split_iso			case Q_TYPE_SITD:				last = (q.sitd->hw_next == EHCI_LIST_END);				flags = sitd_complete (ehci, q.sitd, flags);				type = Q_NEXT_TYPE (q.sitd->hw_next);				// FIXME unlink SITD after split completes				q = q.sitd->sitd_next;				break;#endif /* have_split_iso */			default:				dbg ("corrupt type %d frame %d shadow %p",					type, frame, q.ptr);				// BUG ();				last = 1;				q.ptr = 0;			}			/* did completion remove an interior q entry? */			if (unlikely (q.ptr == 0 && !last))				goto restart;		}		/* stop when we catch up to the HC */		// FIXME:  this assumes we won't get lapped when		// latencies climb; that should be rare, but...		// detect it, and just go all the way around.		// FLR might help detect this case, so long as latencies		// don't exceed periodic_size msec (default 1.024 sec).		// FIXME:  likewise assumes HC doesn't halt mid-scan		if (frame == clock) {			unsigned	now;			if (!HCD_IS_RUNNING (ehci->hcd.state))				break;			ehci->next_uframe = now_uframe;			now = readl (&ehci->regs->frame_index) % mod;			if (now_uframe == now)				break;			/* rescan the rest of this frame, then ... */			now_uframe = now;			clock = now_uframe >> 3;		} else			frame = (frame + 1) % ehci->periodic_size;	} 	spin_unlock_irqrestore (&ehci->lock, flags);}

⌨️ 快捷键说明

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