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 -#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 */