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

📄 net2280.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			}		}	} else if (ep->dma) {		int	valid = 1;		if (ep->is_in) {			int	expect;			/* preventing magic zlps is per-engine state, not			 * per-transfer; irq logic must recover hiccups.			 */			expect = likely (req->req.zero				|| (req->req.length % ep->ep.maxpacket) != 0);			if (expect != ep->in_fifo_validate)				valid = 0;		}		queue_dma (ep, req, valid);	} /* else the irq handler advances the queue. */	if (req)		list_add_tail (&req->queue, &ep->queue);done:	spin_unlock_irqrestore (&dev->lock, flags);	/* pci writes may still be posted */	return 0;}static inline voiddma_done (	struct net2280_ep *ep,	struct net2280_request *req,	u32 dmacount,	int status){	req->req.actual = req->req.length - (DMA_BYTE_COUNT_MASK & dmacount);	done (ep, req, status);}static void restart_dma (struct net2280_ep *ep);static void scan_dma_completions (struct net2280_ep *ep){	/* only look at descriptors that were "naturally" retired,	 * so fifo and list head state won't matter	 */	while (!list_empty (&ep->queue)) {		struct net2280_request	*req;		u32			tmp;		req = list_entry (ep->queue.next,				struct net2280_request, queue);		if (!req->valid)			break;		rmb ();		tmp = le32_to_cpup (&req->td->dmacount);		if ((tmp & (1 << VALID_BIT)) != 0)			break;		/* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short"		 * cases where DMA must be aborted; this code handles		 * all non-abort DMA completions.		 */		if (unlikely (req->td->dmadesc == 0)) {			/* paranoia */			tmp = readl (&ep->dma->dmacount);			if (tmp & DMA_BYTE_COUNT_MASK)				break;			/* single transfer mode */			dma_done (ep, req, tmp, 0);			break;		} else if (!ep->is_in				&& (req->req.length % ep->ep.maxpacket) != 0) {			tmp = readl (&ep->regs->ep_stat);			/* AVOID TROUBLE HERE by not issuing short reads from			 * your gadget driver.  That helps avoids errata 0121,			 * 0122, and 0124; not all cases trigger the warning.			 */			if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) {				WARN (ep->dev, "%s lost packet sync!\n",						ep->ep.name);				req->req.status = -EOVERFLOW;			} else if ((tmp = readl (&ep->regs->ep_avail)) != 0) {				/* fifo gets flushed later */				ep->out_overflow = 1;				DEBUG (ep->dev, "%s dma, discard %d len %d\n",						ep->ep.name, tmp,						req->req.length);				req->req.status = -EOVERFLOW;			}		}		dma_done (ep, req, tmp, 0);	}}static void restart_dma (struct net2280_ep *ep){	struct net2280_request	*req;	u32			dmactl = dmactl_default;	if (ep->stopped)		return;	req = list_entry (ep->queue.next, struct net2280_request, queue);	if (!use_dma_chaining) {		start_dma (ep, req);		return;	}	/* the 2280 will be processing the queue unless queue hiccups after	 * the previous transfer:	 *  IN:   wanted automagic zlp, head doesn't (or vice versa)	 *        DMA_FIFO_VALIDATE doesn't init from dma descriptors.	 *  OUT:  was "usb-short", we must restart.	 */	if (ep->is_in && !req->valid) {		struct net2280_request	*entry, *prev = 0;		int			reqmode, done = 0;		DEBUG (ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td);		ep->in_fifo_validate = likely (req->req.zero			|| (req->req.length % ep->ep.maxpacket) != 0);		if (ep->in_fifo_validate)			dmactl |= (1 << DMA_FIFO_VALIDATE);		list_for_each_entry (entry, &ep->queue, queue) {			u32		dmacount;			if (entry == req)				continue;			dmacount = entry->td->dmacount;			if (!done) {				reqmode = likely (entry->req.zero					|| (entry->req.length						% ep->ep.maxpacket) != 0);				if (reqmode == ep->in_fifo_validate) {					entry->valid = 1;					dmacount |= valid_bit;					entry->td->dmacount = dmacount;					prev = entry;					continue;				} else {					/* force a hiccup */					prev->td->dmacount |= dma_done_ie;					done = 1;				}			}			/* walk the rest of the queue so unlinks behave */			entry->valid = 0;			dmacount &= ~valid_bit;			entry->td->dmacount = dmacount;			prev = entry;		}	}	writel (0, &ep->dma->dmactl);	start_queue (ep, dmactl, req->td_dma);}static void abort_dma (struct net2280_ep *ep){	/* abort the current transfer */	if (likely (!list_empty (&ep->queue))) {		/* FIXME work around errata 0121, 0122, 0124 */		writel ((1 << DMA_ABORT), &ep->dma->dmastat);		spin_stop_dma (ep->dma);	} else		stop_dma (ep->dma);	scan_dma_completions (ep);}/* dequeue ALL requests */static void nuke (struct net2280_ep *ep){	struct net2280_request	*req;	/* called with spinlock held */	ep->stopped = 1;	if (ep->dma)		abort_dma (ep);	while (!list_empty (&ep->queue)) {		req = list_entry (ep->queue.next,				struct net2280_request,				queue);		done (ep, req, -ESHUTDOWN);	}}/* dequeue JUST ONE request */static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req){	struct net2280_ep	*ep;	struct net2280_request	*req;	unsigned long		flags;	u32			dmactl;	int			stopped;	ep = container_of (_ep, struct net2280_ep, ep);	if (!_ep || (!ep->desc && ep->num != 0) || !_req)		return -EINVAL;	spin_lock_irqsave (&ep->dev->lock, flags);	stopped = ep->stopped;	/* quiesce dma while we patch the queue */	dmactl = 0;	ep->stopped = 1;	if (ep->dma) {		dmactl = readl (&ep->dma->dmactl);		/* WARNING erratum 0127 may kick in ... */		stop_dma (ep->dma);		scan_dma_completions (ep);	}	/* make sure it's still queued on this endpoint */	list_for_each_entry (req, &ep->queue, queue) {		if (&req->req == _req)			break;	}	if (&req->req != _req) {		spin_unlock_irqrestore (&ep->dev->lock, flags);		return -EINVAL;	}	/* queue head may be partially complete. */	if (ep->queue.next == &req->queue) {		if (ep->dma) {			DEBUG (ep->dev, "unlink (%s) dma\n", _ep->name);			_req->status = -ECONNRESET;			abort_dma (ep);			if (likely (ep->queue.next == &req->queue)) {				// NOTE: misreports single-transfer mode				req->td->dmacount = 0;	/* invalidate */				dma_done (ep, req,					readl (&ep->dma->dmacount),					-ECONNRESET);			}		} else {			DEBUG (ep->dev, "unlink (%s) pio\n", _ep->name);			done (ep, req, -ECONNRESET);		}		req = 0;	/* patch up hardware chaining data */	} else if (ep->dma && use_dma_chaining) {		if (req->queue.prev == ep->queue.next) {			writel (le32_to_cpu (req->td->dmadesc),				&ep->dma->dmadesc);			if (req->td->dmacount & dma_done_ie)				writel (readl (&ep->dma->dmacount)						| dma_done_ie,					&ep->dma->dmacount);		} else {			struct net2280_request	*prev;			prev = list_entry (req->queue.prev,				struct net2280_request, queue);			prev->td->dmadesc = req->td->dmadesc;			if (req->td->dmacount & dma_done_ie)				prev->td->dmacount |= dma_done_ie;		}	}	if (req)		done (ep, req, -ECONNRESET);	ep->stopped = stopped;	if (ep->dma) {		/* turn off dma on inactive queues */		if (list_empty (&ep->queue))			stop_dma (ep->dma);		else if (!ep->stopped) {			/* resume current request, or start new one */			if (req)				writel (dmactl, &ep->dma->dmactl);			else				start_dma (ep, list_entry (ep->queue.next,					struct net2280_request, queue));		}	}	spin_unlock_irqrestore (&ep->dev->lock, flags);	return req ? 0 : -EOPNOTSUPP;}/*-------------------------------------------------------------------------*/static int net2280_fifo_status (struct usb_ep *_ep);static intnet2280_set_halt (struct usb_ep *_ep, int value){	struct net2280_ep	*ep;	unsigned long		flags;	int			retval = 0;	ep = container_of (_ep, struct net2280_ep, ep);	if (!_ep || (!ep->desc && ep->num != 0))		return -EINVAL;	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)		return -ESHUTDOWN;	if (ep->desc /* not ep0 */ && (ep->desc->bmAttributes & 0x03)						== USB_ENDPOINT_XFER_ISOC)		return -EINVAL;	spin_lock_irqsave (&ep->dev->lock, flags);	if (!list_empty (&ep->queue))		retval = -EAGAIN;	else if (ep->is_in && value && net2280_fifo_status (_ep) != 0)		retval = -EAGAIN;	else {		VDEBUG (ep->dev, "%s %s halt\n", _ep->name,				value ? "set" : "clear");		/* set/clear, then synch memory views with the device */		if (value) {			if (ep->num == 0)				ep->dev->protocol_stall = 1;			else				set_halt (ep);		} else			clear_halt (ep);		(void) readl (&ep->regs->ep_rsp);	}	spin_unlock_irqrestore (&ep->dev->lock, flags);	return retval;}static intnet2280_fifo_status (struct usb_ep *_ep){	struct net2280_ep	*ep;	u32			avail;	ep = container_of (_ep, struct net2280_ep, ep);	if (!_ep || (!ep->desc && ep->num != 0))		return -ENODEV;	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)		return -ESHUTDOWN;	avail = readl (&ep->regs->ep_avail) & ((1 << 12) - 1);	if (avail > ep->fifo_size)		return -EOVERFLOW;	if (ep->is_in)		avail = ep->fifo_size - avail;	return avail;}static voidnet2280_fifo_flush (struct usb_ep *_ep){	struct net2280_ep	*ep;	ep = container_of (_ep, struct net2280_ep, ep);	if (!_ep || (!ep->desc && ep->num != 0))		return;	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)		return;	writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat);	(void) readl (&ep->regs->ep_rsp);}static struct usb_ep_ops net2280_ep_ops = {	.enable		= net2280_enable,	.disable	= net2280_disable,	.alloc_request	= net2280_alloc_request,	.free_request	= net2280_free_request,	.alloc_buffer	= net2280_alloc_buffer,	.free_buffer	= net2280_free_buffer,	.queue		= net2280_queue,	.dequeue	= net2280_dequeue,	.set_halt	= net2280_set_halt,	.fifo_status	= net2280_fifo_status,	.fifo_flush	= net2280_fifo_flush,};/*-------------------------------------------------------------------------*/static int net2280_get_frame (struct usb_gadget *_gadget){	struct net2280		*dev;	unsigned long		flags;	u16			retval;	if (!_gadget)		return -ENODEV;	dev = container_of (_gadget, struct net2280, gadget);	spin_lock_irqsave (&dev->lock, flags);	retval = get_idx_reg (dev->regs, REG_FRAME) & 0x03ff;	spin_unlock_irqrestore (&dev->lock, flags);	return retval;}static int net2280_wakeup (struct usb_gadget *_gadget){	struct net2280		*dev;	u32			tmp;	unsigned long		flags;	if (!_gadget)		return 0;	dev = container_of (_gadget, struct net2280, gadget);	spin_lock_irqsave (&dev->lock, flags);	tmp = readl (&dev->usb->usbctl);	if (tmp & (1 << DEVICE_REMOTE_WAKEUP_ENABLE))		writel (1 << GENERATE_RESUME, &dev->usb->usbstat);	spin_unlock_irqrestore (&dev->lock, flags);	/* pci writes may still be posted */	return 0;}static int net2280_set_selfpowered (struct usb_gadget *_gadget, int value){	struct net2280		*dev;	u32			tmp;	unsigned long		flags;	if (!_gadget)		return 0;	dev = container_of (_gadget, struct net2280, gadget);	spin_lock_irqsave (&dev->lock, flags);	tmp = readl (&dev->usb->usbctl);	if (value)		tmp |= (1 << SELF_POWERED_STATUS);	else		tmp &= ~(1 << SELF_POWERED_STATUS);	writel (tmp, &dev->usb->usbctl);	spin_unlock_irqrestore (&dev->lock, flags);	return 0;}static const struct usb_gadget_ops net2280_ops = {	.get_frame	= net2280_get_frame,	.wakeup		= net2280_wakeup,	.set_selfpowered = net2280_set_selfpowered,};/*-------------------------------------------------------------------------*/#ifdef	USE_SYSFS_DEBUG_FILES/* "function" sysfs attribute */static ssize_tshow_function (struct device *_dev, char *buf){	struct net2280	*dev = dev_get_drvdata (_dev);	if (!dev->driver			|| !dev->driver->function			|| strlen (dev->driver->function) > PAGE_SIZE)		return 0;	return snprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);}static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);static ssize_tshow_registers (struct device *_dev, char *buf){	struct net2280		*dev;	char			*next;	unsigned		size, t;	unsigned long		flags;	int			i;	u32			t1, t2;	char			*s;	dev = dev_get_drvdata (_dev);	next = buf;	size = PAGE_SIZE;	spin_lock_irqsave (&dev->lock, flags);	if (dev->driver)		s = dev->driver->driver.name;	else		s = "(none)";	/* Main Control Registers */

⌨️ 快捷键说明

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