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

📄 pxa2xx_udc.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * linux/drivers/usb/gadget/pxa2xx_udc.c * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers * * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) * Copyright (C) 2003 Robert Schwebel, Pengutronix * Copyright (C) 2003 Benedikt Spranger, Pengutronix * Copyright (C) 2003 David Brownell * Copyright (C) 2003 Joshua Wise * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * */#undef	DEBUG// #define	VERBOSE	DBG_VERBOSE#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/ioport.h>#include <linux/types.h>#include <linux/version.h>#include <linux/errno.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/proc_fs.h>#include <linux/mm.h>#include <linux/device.h>#include <linux/dma-mapping.h>#include <asm/byteorder.h>#include <asm/dma.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/mach-types.h>#include <asm/unaligned.h>#include <asm/hardware.h>#include <linux/usb_ch9.h>#include <linux/usb_gadget.h>#include <asm/arch/udc.h>/* * This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx * series processors.  The UDC for the IXP 4xx series is very similar. * There are fifteen endpoints, in addition to ep0. * * Such controller drivers work with a gadget driver.  The gadget driver * returns descriptors, implements configuration and data protocols used * by the host to interact with this device, and allocates endpoints to * the different protocol interfaces.  The controller driver virtualizes * usb hardware so that the gadget drivers will be more portable. *  * This UDC hardware wants to implement a bit too much USB protocol, so * it constrains the sorts of USB configuration change events that work. * The errata for these chips are misleading; some "fixed" bugs from * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. */#define	DRIVER_VERSION	"14-Dec-2003"#define	DRIVER_DESC	"PXA 2xx USB Device Controller driver"static const char driver_name [] = "pxa2xx-udc";static const char ep0name [] = "ep0";// #define	USE_DMA// #define	USE_OUT_DMA// #define	DISABLE_TEST_MODE#ifdef CONFIG_PROC_FS#define	UDC_PROC_FILE#endif#ifdef CONFIG_ARCH_IXP4XX#undef USE_DMA/* cpu-specific register addresses are compiled in to this code */#ifdef CONFIG_ARCH_PXA#error "Can't configure both IXP and PXA"#endif#endif#include "pxa2xx_udc.h"#ifdef CONFIG_EMBEDDED/* few strings, and little code to use them */#undef	DEBUG#undef	UDC_PROC_FILE#endif#ifdef	USE_DMAstatic int use_dma = 1;MODULE_PARM (use_dma, "i");MODULE_PARM_DESC (use_dma, "true to use dma");static void dma_nodesc_handler (int dmach, void *_ep, struct pt_regs *r);static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req);#ifdef USE_OUT_DMA#define	DMASTR " (dma support)"#else#define	DMASTR " (dma in)"#endif#else	/* !USE_DMA */#define	DMASTR " (pio only)"#undef	USE_OUT_DMA#endif#ifdef	CONFIG_USB_PXA2XX_SMALL#define SIZE_STR	" (small)"#else#define SIZE_STR	""#endif#ifdef DISABLE_TEST_MODE/* (mode == 0) == no undocumented chip tweaks * (mode & 1)  == double buffer bulk IN * (mode & 2)  == double buffer bulk OUT * ... so mode = 3 (or 7, 15, etc) does it for both */static ushort fifo_mode = 0;MODULE_PARM (fifo_mode, "h");MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode");#endif/* --------------------------------------------------------------------------- * 	endpoint related parts of the api to the usb controller hardware, *	used by gadget driver; and the inner talker-to-hardware core. * --------------------------------------------------------------------------- */static void pxa2xx_ep_fifo_flush (struct usb_ep *ep);static void nuke (struct pxa2xx_ep *, int status);static void pio_irq_enable(int bEndpointAddress){        bEndpointAddress &= 0xf;        if (bEndpointAddress < 8)                UICR0 &= ~(1 << bEndpointAddress);        else {                bEndpointAddress -= 8;                UICR1 &= ~(1 << bEndpointAddress);	}}static void pio_irq_disable(int bEndpointAddress){        bEndpointAddress &= 0xf;        if (bEndpointAddress < 8)                UICR0 |= 1 << bEndpointAddress;        else {                bEndpointAddress -= 8;                UICR1 |= 1 << bEndpointAddress;        }}/* The UDCCR reg contains mask and interrupt status bits, * so using '|=' isn't safe as it may ack an interrupt. */#define UDCCR_MASK_BITS         (UDCCR_REM | UDCCR_SRM | UDCCR_UDE)static inline void udc_set_mask_UDCCR(int mask){	UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS);}static inline void udc_clear_mask_UDCCR(int mask){	UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS);}static inline void udc_ack_int_UDCCR(int mask){	/* udccr contains the bits we dont want to change */	__u32 udccr = UDCCR & UDCCR_MASK_BITS;	UDCCR = udccr | (mask & ~UDCCR_MASK_BITS);}/* * endpoint enable/disable * * we need to verify the descriptors used to enable endpoints.  since pxa2xx * endpoint configurations are fixed, and are pretty much always enabled, * there's not a lot to manage here. * * because pxa2xx can't selectively initialize bulk (or interrupt) endpoints, * (resetting endpoint halt and toggle), SET_INTERFACE is unusable except * for a single interface (with only the default altsetting) and for gadget * drivers that don't halt endpoints (not reset by set_interface).  that also * means that if you use ISO, you must violate the USB spec rule that all * iso endpoints must be in non-default altsettings. */static int pxa2xx_ep_enable (struct usb_ep *_ep,		const struct usb_endpoint_descriptor *desc){	struct pxa2xx_ep        *ep;	struct pxa2xx_udc       *dev;	ep = container_of (_ep, struct pxa2xx_ep, ep);	if (!_ep || !desc || ep->desc || _ep->name == ep0name			|| desc->bDescriptorType != USB_DT_ENDPOINT			|| ep->bEndpointAddress != desc->bEndpointAddress			|| ep->fifo_size < le16_to_cpu						(desc->wMaxPacketSize)) {		DMSG("%s, bad ep or descriptor\n", __FUNCTION__);		return -EINVAL;	}	/* xfer types must match, except that interrupt ~= bulk */	if (ep->bmAttributes != desc->bmAttributes			&& ep->bmAttributes != USB_ENDPOINT_XFER_BULK			&& desc->bmAttributes != USB_ENDPOINT_XFER_INT) {		DMSG("%s, %s type mismatch\n", __FUNCTION__, _ep->name);		return -EINVAL;	}	/* hardware _could_ do smaller, but driver doesn't */	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK				&& le16_to_cpu (desc->wMaxPacketSize)						!= BULK_FIFO_SIZE)			|| !desc->wMaxPacketSize) {		DMSG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);		return -ERANGE;	}	dev = ep->dev;	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {		DMSG("%s, bogus device state\n", __FUNCTION__);		return -ESHUTDOWN;	}	ep->desc = desc;	ep->dma = -1;	ep->stopped = 0;	ep->pio_irqs = ep->dma_irqs = 0;	ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);	/* flush fifo (mostly for OUT buffers) */	pxa2xx_ep_fifo_flush (_ep);	/* ... reset halt state too, if we could ... */#ifdef	USE_DMA	/* for (some) bulk and ISO endpoints, try to get a DMA channel and	 * bind it to the endpoint.  otherwise use PIO. 	 */	switch (ep->bmAttributes) {	case USB_ENDPOINT_XFER_ISOC:		if (le16_to_cpu(desc->wMaxPacketSize) % 32)			break;		// fall through	case USB_ENDPOINT_XFER_BULK:		if (!use_dma || !ep->reg_drcmr)			break;		ep->dma = pxa_request_dma ((char *)_ep->name, 				(le16_to_cpu (desc->wMaxPacketSize) > 64)					? DMA_PRIO_MEDIUM /* some iso */					: DMA_PRIO_LOW,				dma_nodesc_handler, ep);		if (ep->dma >= 0) {			*ep->reg_drcmr = DRCMR_MAPVLD | ep->dma;			DMSG("%s using dma%d\n", _ep->name, ep->dma);		}	}#endif	DBG(DBG_VERBOSE, "enabled %s\n", _ep->name);	return 0;}static int pxa2xx_ep_disable (struct usb_ep *_ep){	struct pxa2xx_ep	*ep;	ep = container_of (_ep, struct pxa2xx_ep, ep);	if (!_ep || !ep->desc) {		DMSG("%s, %s not enabled\n", __FUNCTION__,			_ep ? ep->ep.name : NULL);		return -EINVAL;	}	nuke (ep, -ESHUTDOWN);#ifdef	USE_DMA	if (ep->dma >= 0) {		*ep->reg_drcmr = 0;		pxa_free_dma (ep->dma);		ep->dma = -1;	}#endif	/* flush fifo (mostly for IN buffers) */	pxa2xx_ep_fifo_flush (_ep);	ep->desc = 0;	ep->stopped = 1;	DBG(DBG_VERBOSE, "%s disabled\n", _ep->name);	return 0;}/*-------------------------------------------------------------------------*//* for the pxa2xx, these can just wrap kmalloc/kfree.  gadget drivers * must still pass correctly initialized endpoints, since other controller * drivers may care about how it's currently set up (dma issues etc). *//* * 	pxa2xx_ep_alloc_request - allocate a request data structure */static struct usb_request *pxa2xx_ep_alloc_request (struct usb_ep *_ep, int gfp_flags){	struct pxa2xx_request *req;	req = kmalloc (sizeof *req, gfp_flags);	if (!req)		return 0;	memset (req, 0, sizeof *req);	INIT_LIST_HEAD (&req->queue);	return &req->req;}/* * 	pxa2xx_ep_free_request - deallocate a request data structure */static voidpxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req){	struct pxa2xx_request	*req;	req = container_of (_req, struct pxa2xx_request, req);	WARN_ON (!list_empty (&req->queue));	kfree(req);}/* PXA cache needs flushing with DMA I/O (it's dma-incoherent), but there's * no device-affinity and the heap works perfectly well for i/o buffers. * It wastes much less memory than dma_alloc_coherent() would, and even * prevents cacheline (32 bytes wide) sharing problems. */static void *pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes,	dma_addr_t *dma, int gfp_flags){	char			*retval;	retval = kmalloc (bytes, gfp_flags & ~(__GFP_DMA|__GFP_HIGHMEM));	if (retval)		*dma = virt_to_bus (retval);	return retval;}static voidpxa2xx_ep_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma,		unsigned bytes){	kfree (buf);}/*-------------------------------------------------------------------------*//* *	done - retire a request; caller blocked irqs */static void done(struct pxa2xx_ep *ep, struct pxa2xx_request *req, int status){	unsigned		stopped = ep->stopped;	list_del_init(&req->queue);	if (likely (req->req.status == -EINPROGRESS))		req->req.status = status;	else		status = req->req.status;	if (status && status != -ESHUTDOWN)		DBG(DBG_VERBOSE, "complete %s req %p stat %d len %u/%u\n",			ep->ep.name, &req->req, status,			req->req.actual, req->req.length);	/* don't modify queue heads during completion callback */	ep->stopped = 1;	req->req.complete(&ep->ep, &req->req);	ep->stopped = stopped;}static inline void ep0_idle (struct pxa2xx_udc *dev){	dev->ep0state = EP0_IDLE;	LED_EP0_OFF;}static intwrite_packet(volatile u32 *uddr, struct pxa2xx_request *req, unsigned max){	u8		*buf;	unsigned	length, count;	buf = req->req.buf + req->req.actual;	prefetch(buf);	/* how big will this packet be? */	length = min(req->req.length - req->req.actual, max);	req->req.actual += length;	count = length;	while (likely(count--))		*uddr = *buf++;	return length;}/* * write to an IN endpoint fifo, as many packets as possible. * irqs will use this to write the rest later. * caller guarantees at least one packet buffer is ready (or a zlp). */static intwrite_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req){	unsigned		max;	max = le16_to_cpu(ep->desc->wMaxPacketSize);	do {		unsigned	count;		int		is_last, is_short;		count = write_packet(ep->reg_uddr, req, max);		/* last packet is usually short (or a zlp) */		if (unlikely (count != max))			is_last = is_short = 1;		else {			if (likely(req->req.length != req->req.actual)					|| req->req.zero)				is_last = 0;			else				is_last = 1;			/* interrupt/iso maxpacket may not fill the fifo */			is_short = unlikely (max < ep->fifo_size);		}		DBG(DBG_VERY_NOISY, "wrote %s %d bytes%s%s %d left %p\n",			ep->ep.name, count,			is_last ? "/L" : "", is_short ? "/S" : "",			req->req.length - req->req.actual, req);		/* let loose that packet. maybe try writing another one,		 * double buffering might work.  TSP, TPC, and TFS		 * bit values are the same for all normal IN endpoints.		 */		*ep->reg_udccs = UDCCS_BI_TPC;		if (is_short)			*ep->reg_udccs = UDCCS_BI_TSP;		/* requests complete when all IN data is in the FIFO */		if (is_last) {			done (ep, req, 0);			if (list_empty(&ep->queue) || unlikely(ep->dma >= 0)) {				pio_irq_disable (ep->bEndpointAddress);#ifdef USE_DMA				/* unaligned data and zlps couldn't use dma */				if (unlikely(!list_empty(&ep->queue))) {					req = list_entry(ep->queue.next,						struct pxa2xx_request, queue);					kick_dma(ep,req);					return 0;				}#endif			}			return 1;		}		// TODO experiment: how robust can fifo mode tweaking be?		// double buffering is off in the default fifo mode, which		// prevents TFS from being set here.	} while (*ep->reg_udccs & UDCCS_BI_TFS);	return 0;}/* caller asserts req->pending (ep0 irq status nyet cleared); starts * ep0 data stage.  these chips want very simple state transitions.

⌨️ 快捷键说明

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