ChangeSet 1.1500.8.24, 2004/02/05 16:33:43-08:00, david-b@pacbell.net

[PATCH] USB Gadget: pxa2xx_udc updates

[USB] pxa2xx_udc updates, mostly for non-Lubbock hardware

  - IXP 42x UDC support (Greg Weeks)

  - remove Lubbock-specific build assumption (Guennadi Liakhovetski)

  - handle D+ pullup right on iPaqs, e7xx, etc (HH.org)

  - don't unbind() with irqs blocked; matches other controller drivers,
    and network layer expectations

  - handle some deferred ep0 responses better

  - support iso transfers (needs fifo size tracking)


 drivers/usb/gadget/pxa2xx_udc.c |  142 +++++++++++++++++++++++++++-------------
 drivers/usb/gadget/pxa2xx_udc.h |   18 +++--
 2 files changed, 109 insertions(+), 51 deletions(-)


diff -Nru a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
--- a/drivers/usb/gadget/pxa2xx_udc.c	Mon Feb  9 14:38:13 2004
+++ b/drivers/usb/gadget/pxa2xx_udc.c	Mon Feb  9 14:38:13 2004
@@ -1,6 +1,6 @@
 /*
  * linux/drivers/usb/gadget/pxa2xx_udc.c
- * Intel PXA2xx on-chip full speed USB device controllers
+ * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers
  *
  * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
  * Copyright (C) 2003 Robert Schwebel, Pengutronix
@@ -59,27 +59,26 @@
 
 #include <asm/arch/udc.h>
 
-#include "pxa2xx_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	"7-Nov-2003"
-#define DRIVER_DESC	"PXA 2xx USB Device Controller driver"
+#define	DRIVER_VERSION	"14-Dec-2003"
+#define	DRIVER_DESC	"PXA 2xx USB Device Controller driver"
 
 
 static const char driver_name [] = "pxa2xx_udc";
@@ -95,6 +94,19 @@
 #define	UDC_PROC_FILE
 #endif
 
+#ifdef CONFIG_ARCH_IXP425
+#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
@@ -215,7 +227,8 @@
 	if (!_ep || !desc || ep->desc || _ep->name == ep0name
 			|| desc->bDescriptorType != USB_DT_ENDPOINT
 			|| ep->bEndpointAddress != desc->bEndpointAddress
-			|| ep->ep.maxpacket < desc->wMaxPacketSize) {
+			|| ep->fifo_size < le16_to_cpu
+						(desc->wMaxPacketSize)) {
 		DMSG("%s, bad ep or descriptor\n", __FUNCTION__);
 		return -EINVAL;
 	}
@@ -230,7 +243,8 @@
 
 	/* hardware _could_ do smaller, but driver doesn't */
 	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
-				&& desc->wMaxPacketSize != BULK_FIFO_SIZE)
+				&& le16_to_cpu (desc->wMaxPacketSize)
+						!= BULK_FIFO_SIZE)
 			|| !desc->wMaxPacketSize) {
 		DMSG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
 		return -ERANGE;
@@ -246,6 +260,7 @@
 	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);
@@ -254,18 +269,18 @@
 
 #ifdef	USE_DMA
 	/* for (some) bulk and ISO endpoints, try to get a DMA channel and
-	 * bind it to the endpoint.  otherwise use PIO.
+	 * bind it to the endpoint.  otherwise use PIO. 
 	 */
 	switch (ep->bmAttributes) {
 	case USB_ENDPOINT_XFER_ISOC:
-		if (desc->wMaxPacketSize % 32)
+		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,
-				(desc->wMaxPacketSize > 64)
+ 				(le16_to_cpu (desc->wMaxPacketSize) > 64)
 					? DMA_PRIO_MEDIUM /* some iso */
 					: DMA_PRIO_LOW,
 				dma_nodesc_handler, ep);
@@ -437,7 +452,7 @@
 {
 	unsigned		max;
 
-	max = ep->desc->wMaxPacketSize;
+	max = le16_to_cpu(ep->desc->wMaxPacketSize);
 	do {
 		unsigned	count;
 		int		is_last, is_short;
@@ -454,13 +469,7 @@
 			else
 				is_last = 1;
 			/* interrupt/iso maxpacket may not fill the fifo */
-			is_short = unlikely (max < ep->ep.maxpacket);
-
-			/* FIXME ep.maxpacket should be the current size,
-			 * modified (for periodic endpoints) when the
-			 * ep is enabled.  do that, re-init as needed,
-			 * and change maxpacket refs accordingly.
-			 */
+			is_short = unlikely (max < ep->fifo_size);
 		}
 
 		DBG(DBG_VERY_NOISY, "wrote %s %d bytes%s%s %d left %p\n",
@@ -598,7 +607,7 @@
 			req->req.actual += min (count, bufferspace);
 		} else /* zlp */
 			count = 0;
-		is_short = (count < ep->desc->wMaxPacketSize);
+		is_short = (count < ep->ep.maxpacket);
 		DBG(DBG_VERY_NOISY, "read %s %02x, %d bytes%s req %p %d/%d\n",
 			ep->ep.name, udccs, count,
 			is_short ? "/S" : "",
@@ -897,13 +906,14 @@
 	 * we can report per-packet status.  that also helps with dma.
 	 */
 	if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
-			&& req->req.length > ep->desc->wMaxPacketSize))
+			&& req->req.length > le16_to_cpu
+						(ep->desc->wMaxPacketSize)))
 		return -EMSGSIZE;
 
 #ifdef	USE_DMA
 	// FIXME caller may already have done the dma mapping
 	if (ep->dma >= 0) {
-		_req->dma = dma_map_single(&dev->dev.dev,
+		_req->dma = dma_map_single(dev->dev,
 			_req->buf, _req->length,
 			((ep->bEndpointAddress & USB_DIR_IN) != 0)
 				? DMA_TO_DEVICE
@@ -1017,11 +1027,21 @@
 	unsigned long		flags;
 
 	ep = container_of(_ep, struct pxa2xx_ep, ep);
-	req = container_of(_req, struct pxa2xx_request, req);
-	if (!_ep || !_req || ep->ep.name == ep0name)
+	if (!_ep || ep->ep.name == ep0name)
 		return -EINVAL;
 
 	local_irq_save(flags);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry (req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		local_irq_restore(flags);
+		return -EINVAL;
+	}
+
 #ifdef	USE_DMA
 	if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) {
 		cancel_dma(ep);
@@ -1034,13 +1054,10 @@
 		}
 	} else
 #endif
-	if (!list_empty(&req->queue))
 		done(ep, req, -ECONNRESET);
-	else
-		req = 0;
-	local_irq_restore(flags);
 
-	return req ? 0 : -EOPNOTSUPP;
+	local_irq_restore(flags);
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1386,8 +1403,10 @@
 
 	udc_clear_mask_UDCCR(UDCCR_UDE);
 
+#ifdef	CONFIG_ARCH_PXA
         /* Disable clock for USB device */
         CKEN &= ~CKEN11_USB;
+#endif
 
 	ep0_idle (dev);
 	dev->gadget.speed = USB_SPEED_UNKNOWN;
@@ -1430,8 +1449,10 @@
 {
 	udc_clear_mask_UDCCR(UDCCR_UDE);
 
+#ifdef	CONFIG_ARCH_PXA
         /* Enable clock for USB device */
         CKEN |= CKEN11_USB;
+#endif
 
 	/* try to clear these bits before we enable the udc */
 	udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR);
@@ -1590,9 +1611,10 @@
 	local_irq_disable();
 	udc_disable(dev);
 	stop_activity(dev, driver);
+	local_irq_enable();
+
 	driver->unbind(&dev->gadget);
 	dev->driver = 0;
-	local_irq_enable();
 
 	device_del (&dev->gadget.dev);
 	device_remove_file(dev->dev, &dev_attr_function);
@@ -1776,7 +1798,6 @@
 					 * else use AREN (later) not SA|OPR
 					 * USIR0_IR0 acts edge sensitive
 					 */
-					dev->req_pending = 0;
 				}
 				break;
 			/* ... and here, even more ... */
@@ -1853,6 +1874,7 @@
 			/* pxa210/250 erratum 131 for B0/B1 says RNE lies.
 			 * still observed on a pxa255 a0.
 			 */
+			DBG(DBG_VERBOSE, "e131\n");
 			nuke(ep, -EPROTO);
 
 			/* read SETUP data, but don't trust it too much */
@@ -2043,7 +2065,7 @@
 				stop_activity (dev, dev->driver);
 
 			} else {
-				dev_info(&dev->gadget.dev, "USB reset\n");
+				INFO("USB reset\n");
 				dev->gadget.speed = USB_SPEED_FULL;
 				LED_CONNECTED_ON;
 				memset(&dev->stats, 0, sizeof dev->stats);
@@ -2133,11 +2155,12 @@
 			.maxpacket	= BULK_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= BULK_FIFO_SIZE,
 		.bEndpointAddress = USB_DIR_IN | 1,
 		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
 		.reg_udccs	= &UDCCS1,
 		.reg_uddr	= &UDDR1,
-		.reg_drcmr	= &DRCMR25,
+		drcmr (25)
 	},
 	.ep[2] = {
 		.ep = {
@@ -2146,12 +2169,13 @@
 			.maxpacket	= BULK_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= BULK_FIFO_SIZE,
 		.bEndpointAddress = 2,
 		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
 		.reg_udccs	= &UDCCS2,
 		.reg_ubcr	= &UBCR2,
 		.reg_uddr	= &UDDR2,
-		.reg_drcmr	= &DRCMR26,
+		drcmr (26)
 	},
 #ifndef CONFIG_USB_PXA2XX_SMALL
 	.ep[3] = {
@@ -2161,11 +2185,12 @@
 			.maxpacket	= ISO_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= ISO_FIFO_SIZE,
 		.bEndpointAddress = USB_DIR_IN | 3,
 		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
 		.reg_udccs	= &UDCCS3,
 		.reg_uddr	= &UDDR3,
-		.reg_drcmr	= &DRCMR27,
+		drcmr (27)
 	},
 	.ep[4] = {
 		.ep = {
@@ -2174,12 +2199,13 @@
 			.maxpacket	= ISO_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= ISO_FIFO_SIZE,
 		.bEndpointAddress = 4,
 		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
 		.reg_udccs	= &UDCCS4,
 		.reg_ubcr	= &UBCR4,
 		.reg_uddr	= &UDDR4,
-		.reg_drcmr	= &DRCMR28,
+		drcmr (28)
 	},
 	.ep[5] = {
 		.ep = {
@@ -2188,6 +2214,7 @@
 			.maxpacket	= INT_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= INT_FIFO_SIZE,
 		.bEndpointAddress = USB_DIR_IN | 5,
 		.bmAttributes	= USB_ENDPOINT_XFER_INT,
 		.reg_udccs	= &UDCCS5,
@@ -2202,11 +2229,12 @@
 			.maxpacket	= BULK_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= BULK_FIFO_SIZE,
 		.bEndpointAddress = USB_DIR_IN | 6,
 		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
 		.reg_udccs	= &UDCCS6,
 		.reg_uddr	= &UDDR6,
-		.reg_drcmr	= &DRCMR30,
+		drcmr (30)
 	},
 	.ep[7] = {
 		.ep = {
@@ -2215,12 +2243,13 @@
 			.maxpacket	= BULK_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= BULK_FIFO_SIZE,
 		.bEndpointAddress = 7,
 		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
 		.reg_udccs	= &UDCCS7,
 		.reg_ubcr	= &UBCR7,
 		.reg_uddr	= &UDDR7,
-		.reg_drcmr	= &DRCMR31,
+		drcmr (31)
 	},
 	.ep[8] = {
 		.ep = {
@@ -2229,11 +2258,12 @@
 			.maxpacket	= ISO_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= ISO_FIFO_SIZE,
 		.bEndpointAddress = USB_DIR_IN | 8,
 		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
 		.reg_udccs	= &UDCCS8,
 		.reg_uddr	= &UDDR8,
-		.reg_drcmr	= &DRCMR32,
+		drcmr (32)
 	},
 	.ep[9] = {
 		.ep = {
@@ -2242,12 +2272,13 @@
 			.maxpacket	= ISO_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= ISO_FIFO_SIZE,
 		.bEndpointAddress = 9,
 		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
 		.reg_udccs	= &UDCCS9,
 		.reg_ubcr	= &UBCR9,
 		.reg_uddr	= &UDDR9,
-		.reg_drcmr	= &DRCMR33,
+		drcmr (33)
 	},
 	.ep[10] = {
 		.ep = {
@@ -2256,6 +2287,7 @@
 			.maxpacket	= INT_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= INT_FIFO_SIZE,
 		.bEndpointAddress = USB_DIR_IN | 10,
 		.bmAttributes	= USB_ENDPOINT_XFER_INT,
 		.reg_udccs	= &UDCCS10,
@@ -2270,11 +2302,12 @@
 			.maxpacket	= BULK_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= BULK_FIFO_SIZE,
 		.bEndpointAddress = USB_DIR_IN | 11,
 		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
 		.reg_udccs	= &UDCCS11,
 		.reg_uddr	= &UDDR11,
-		.reg_drcmr	= &DRCMR35,
+		drcmr (35)
 	},
 	.ep[12] = {
 		.ep = {
@@ -2283,12 +2316,13 @@
 			.maxpacket	= BULK_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= BULK_FIFO_SIZE,
 		.bEndpointAddress = 12,
 		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
 		.reg_udccs	= &UDCCS12,
 		.reg_ubcr	= &UBCR12,
 		.reg_uddr	= &UDDR12,
-		.reg_drcmr	= &DRCMR36,
+		drcmr (36)
 	},
 	.ep[13] = {
 		.ep = {
@@ -2297,11 +2331,12 @@
 			.maxpacket	= ISO_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= ISO_FIFO_SIZE,
 		.bEndpointAddress = USB_DIR_IN | 13,
 		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
 		.reg_udccs	= &UDCCS13,
 		.reg_uddr	= &UDDR13,
-		.reg_drcmr	= &DRCMR37,
+		drcmr (37)
 	},
 	.ep[14] = {
 		.ep = {
@@ -2310,12 +2345,13 @@
 			.maxpacket	= ISO_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= ISO_FIFO_SIZE,
 		.bEndpointAddress = 14,
 		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
 		.reg_udccs	= &UDCCS14,
 		.reg_ubcr	= &UBCR14,
 		.reg_uddr	= &UDDR14,
-		.reg_drcmr	= &DRCMR38,
+		drcmr (38)
 	},
 	.ep[15] = {
 		.ep = {
@@ -2324,6 +2360,7 @@
 			.maxpacket	= INT_FIFO_SIZE,
 		},
 		.dev		= &memory,
+		.fifo_size	= INT_FIFO_SIZE,
 		.bEndpointAddress = USB_DIR_IN | 15,
 		.bmAttributes	= USB_ENDPOINT_XFER_INT,
 		.reg_udccs	= &UDCCS15,
@@ -2333,8 +2370,15 @@
 };
 
 #define CP15R0_VENDOR_MASK	0xffffe000
+
+#if	defined(CONFIG_ARCH_PXA)
 #define CP15R0_XSCALE_VALUE	0x69052000	/* intel/arm/xscale */
 
+#elif	defined(CONFIG_ARCH_IXP425)
+#define CP15R0_XSCALE_VALUE	0x69054000	/* intel/arm/ixp425 */
+
+#endif
+
 #define CP15R0_PROD_MASK	0x000003f0
 #define PXA25x			0x00000100	/* and PXA26x */
 #define PXA210			0x00000120
@@ -2355,6 +2399,7 @@
 #define PXA210_B2		0x00000124
 #define PXA210_B1		0x00000123
 #define PXA210_B0		0x00000122
+#define IXP425_A0		0x000001c1
 
 /*
  * 	probe - binds to the platform device
@@ -2374,6 +2419,7 @@
 
 	/* trigger chiprev-specific logic */
 	switch (chiprev & CP15R0_PRODREV_MASK) {
+#if	defined(CONFIG_ARCH_PXA)
 	case PXA255_A0:
 		dev->has_cfr = 1;
 		break;
@@ -2388,6 +2434,11 @@
 		/* fall through */
 	case PXA250_C0: case PXA210_C0:
 		break;
+#elif	defined(CONFIG_ARCH_IXP425)
+	case IXP425_A0:
+		out_dma = 0;
+		break;
+#endif
 	default:
 		out_dma = 0;
 		printk(KERN_ERR "%s: unrecognized processor: %08x\n",
@@ -2443,6 +2494,7 @@
 	}
 	dev->got_irq = 1;
 
+#ifdef CONFIG_ARCH_LUBBOCK
 	if (machine_is_lubbock()) {
 		disable_irq(LUBBOCK_USB_DISC_IRQ);
 		retval = request_irq(LUBBOCK_USB_DISC_IRQ,
@@ -2457,7 +2509,7 @@
 		}
 		dev->got_disc = 1;
 	}
-
+#endif
 	create_proc_files();
 
 	return 0;
diff -Nru a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
--- a/drivers/usb/gadget/pxa2xx_udc.h	Mon Feb  9 14:38:13 2004
+++ b/drivers/usb/gadget/pxa2xx_udc.h	Mon Feb  9 14:38:13 2004
@@ -52,14 +52,15 @@
 	struct list_head			queue;
 	unsigned long				pio_irqs;
 	unsigned long				dma_irqs;
-	int					dma;
+	short					dma; 
 
+	unsigned short				fifo_size;
 	u8					bEndpointAddress;
 	u8					bmAttributes;
 
 	unsigned				stopped : 1;
 	unsigned				dma_fixup : 1;
-
+							 
 	/* UDCCS = UDC Control/Status for this EP
 	 * UBCR = UDC Byte Count Remaining (contents of OUT fifo)
 	 * UDDR = UDC Endpoint Data Register (the fifo)
@@ -68,7 +69,12 @@
 	volatile u32				*reg_udccs;
 	volatile u32				*reg_ubcr;
 	volatile u32				*reg_uddr;
+#ifdef USE_DMA
 	volatile u32				*reg_drcmr;
+#define	drcmr(n)  .reg_drcmr = & DRCMR ## n ,
+#else
+#define	drcmr(n)  
+#endif
 };
 
 struct pxa2xx_request {
@@ -76,7 +82,7 @@
 	struct list_head			queue;
 };
 
-enum ep0_state {
+enum ep0_state { 
 	EP0_IDLE,
 	EP0_IN_DATA_PHASE,
 	EP0_OUT_DATA_PHASE,
@@ -181,14 +187,14 @@
 {
 	if (!the_controller->mach->udc_command)
 		return;
-	the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+	the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
 }
 
 static inline void let_usb_appear(void)
 {
 	if (!the_controller->mach->udc_command)
 		return;
-	the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+	the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -305,7 +311,7 @@
 #define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0)
 
 #define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
-
+#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
 
 
 #endif /* __LINUX_USB_GADGET_PXA2XX_H */
