diff options
Diffstat (limited to 'packages/linux/linux-2.6.21/270-usb-gadget-udc.patch')
| -rw-r--r-- | packages/linux/linux-2.6.21/270-usb-gadget-udc.patch | 2739 |
1 files changed, 0 insertions, 2739 deletions
diff --git a/packages/linux/linux-2.6.21/270-usb-gadget-udc.patch b/packages/linux/linux-2.6.21/270-usb-gadget-udc.patch deleted file mode 100644 index 630d188ea0..0000000000 --- a/packages/linux/linux-2.6.21/270-usb-gadget-udc.patch +++ /dev/null @@ -1,2739 +0,0 @@ -Index: linux-2.6.21gum/drivers/usb/gadget/Kconfig -=================================================================== ---- linux-2.6.21gum.orig/drivers/usb/gadget/Kconfig -+++ linux-2.6.21gum/drivers/usb/gadget/Kconfig -@@ -129,6 +129,28 @@ config USB_PXA2XX_SMALL - default y if USB_ETH - default y if USB_G_SERIAL - -+config USB_GADGET_PXA27X -+ boolean "PXA 27x" -+ depends on ARCH_PXA && PXA27x -+ help -+ Intel's PXA 27x series XScale ARM-5TE processors include -+ an integrated full speed USB 1.1 device controller. -+ -+ Say "y" to link the driver statically, or "m" to build a -+ dynamically linked module called "pxa27x_udc" and force all -+ gadget drivers to also be dynamically linked. -+ -+config USB_PXA27X -+ tristate -+ depends on USB_GADGET_PXA27X -+ default USB_GADGET -+ select USB_GADGET_SELECTED -+ -+config USB_PXA27X_DMA -+ bool # "Use DMA support" -+ depends on USB_GADGET_PXA27X -+ default n -+ - config USB_GADGET_GOKU - boolean "Toshiba TC86C001 'Goku-S'" - depends on PCI -Index: linux-2.6.21gum/drivers/usb/gadget/Makefile -=================================================================== ---- linux-2.6.21gum.orig/drivers/usb/gadget/Makefile -+++ linux-2.6.21gum/drivers/usb/gadget/Makefile -@@ -7,6 +7,7 @@ obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o - obj-$(CONFIG_USB_GOKU) += goku_udc.o - obj-$(CONFIG_USB_OMAP) += omap_udc.o - obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o -+obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o - obj-$(CONFIG_USB_AT91) += at91_udc.o - obj-$(CONFIG_USB_GADGET_GUMSTIX) += gumstix_gadget.o - -Index: linux-2.6.21gum/drivers/usb/gadget/pxa27x_udc.c -=================================================================== ---- /dev/null -+++ linux-2.6.21gum/drivers/usb/gadget/pxa27x_udc.c -@@ -0,0 +1,2352 @@ -+/* -+ * linux/drivers/usb/gadget/pxa27x_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 -+ * Copyright (C) 2004 Intel Corporation -+ * Copyright (C) 2005 SDG Systems, LLC (Aric Blumer) -+ * -+ * 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 DEBUG 1 -+ //#define VERBOSE DBG_VERBOSE -+ -+#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/platform_device.h> -+#include <linux/dma-mapping.h> -+#include <linux/irq.h> -+ -+#include <asm/byteorder.h> -+#include <asm/dma.h> -+#include <asm/io.h> -+#include <asm/system.h> -+#include <asm/mach-types.h> -+#include <asm/unaligned.h> -+#include <asm/hardware.h> -+#include <asm/mach/irq.h> -+#include <asm/arch/pxa-regs.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 27777777x -+ * series processors. -+ * 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 "21-Jul-2005" -+#define DRIVER_DESC "PXA 27x USB Device Controller driver" -+ -+ -+static const char driver_name [] = "pxa27x_udc"; -+ -+static const char ep0name [] = "ep0"; -+ -+ -+#define USE_DMA -+//#define DISABLE_TEST_MODE -+ -+#ifdef CONFIG_PROC_FS -+#define UDC_PROC_FILE -+#endif -+ -+#include "pxa27x_udc.h" -+ -+#if 0 -+#ifdef CONFIG_EMBEDDED -+/* few strings, and little code to use them */ -+#undef DEBUG -+#undef UDC_PROC_FILE -+#endif -+#endif -+ -+#ifdef USE_DMA -+static int use_dma = 1; -+module_param(use_dma, bool, 0); -+MODULE_PARM_DESC (use_dma, "true to use dma"); -+ -+static void dma_nodesc_handler (int dmach, void *_ep); -+static void kick_dma(struct pxa27x_ep *ep, struct pxa27x_request *req); -+ -+#define DMASTR " (dma support)" -+ -+#else /* !USE_DMA */ -+#define DMASTR " (pio only)" -+#endif -+ -+#ifdef CONFIG_USB_PXA27X_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_param(fifo_mode, ushort, 0); -+MODULE_PARM_DESC (fifo_mode, "pxa27x udc fifo mode"); -+#endif -+ -+#define UDCISR0_IR0 0x3 -+#define UDCISR_INT_MASK (UDC_INT_FIFOERROR | UDC_INT_PACKETCMP) -+#define UDCICR_INT_MASK UDCISR_INT_MASK -+ -+#define UDCCSR_MASK (UDCCSR_FST | UDCCSR_DME) -+/* --------------------------------------------------------------------------- -+ * endpoint related parts of the api to the usb controller hardware, -+ * used by gadget driver; and the inner talker-to-hardware core. -+ * --------------------------------------------------------------------------- -+ */ -+ -+static void pxa27x_ep_fifo_flush (struct usb_ep *ep); -+static void nuke (struct pxa27x_ep *, int status); -+ -+static void pio_irq_enable(int ep_num) -+{ -+ if (ep_num < 16) -+ UDCICR0 |= 3 << (ep_num * 2); -+ else { -+ ep_num -= 16; -+ UDCICR1 |= 3 << (ep_num * 2); -+ } -+} -+ -+static void pio_irq_disable(int ep_num) -+{ -+ ep_num &= 0xf; -+ if (ep_num < 16) -+ UDCICR0 &= ~(3 << (ep_num * 2)); -+ else { -+ ep_num -= 16; -+ UDCICR1 &= ~(3 << (ep_num * 2)); -+ } -+} -+ -+/* 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_OEN | 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 pxa27x -+ * endpoint configurations are fixed, and are pretty much always enabled, -+ * there's not a lot to manage here. -+ * -+ * because pxa27x 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 pxa27x_ep_enable (struct usb_ep *_ep, -+ const struct usb_endpoint_descriptor *desc) -+{ -+ struct pxa27x_ep *ep; -+ struct pxa27x_udc *dev; -+ -+ ep = container_of (_ep, struct pxa27x_ep, ep); -+ if (!_ep || !desc || _ep->name == ep0name -+ || desc->bDescriptorType != USB_DT_ENDPOINT -+ || 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->ep_type != 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) */ -+ pxa27x_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. -+ */ -+ DMSG("%s: called attributes=%d\n", __FUNCTION__, ep->ep_type); -+ switch (ep->ep_type) { -+ 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); -+ } -+ default: -+ break; -+ } -+#endif -+ DBG(DBG_VERBOSE, "enabled %s\n", _ep->name); -+ return 0; -+} -+ -+static int pxa27x_ep_disable (struct usb_ep *_ep) -+{ -+ struct pxa27x_ep *ep; -+ -+ ep = container_of (_ep, struct pxa27x_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) */ -+ pxa27x_ep_fifo_flush (_ep); -+ -+ ep->desc = 0; -+ ep->stopped = 1; -+ -+ DBG(DBG_VERBOSE, "%s disabled\n", _ep->name); -+ return 0; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* for the pxa27x, 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). -+ */ -+ -+/* -+ * pxa27x_ep_alloc_request - allocate a request data structure -+ */ -+static struct usb_request * -+pxa27x_ep_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) -+{ -+ struct pxa27x_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; -+} -+ -+ -+/* -+ * pxa27x_ep_free_request - deallocate a request data structure -+ */ -+static void -+pxa27x_ep_free_request (struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct pxa27x_request *req; -+ -+ req = container_of(_req, struct pxa27x_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 * -+pxa27x_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes, -+ dma_addr_t *dma, unsigned gfp_flags) -+{ -+ char *retval; -+ -+ retval = kmalloc (bytes, gfp_flags & ~(__GFP_DMA|__GFP_HIGHMEM)); -+ if (retval) -+ *dma = virt_to_bus (retval); -+ return retval; -+} -+ -+static void -+pxa27x_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 pxa27x_ep *ep, struct pxa27x_request *req, int status) -+{ -+ 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 */ -+ req->req.complete(&ep->ep, &req->req); -+} -+ -+ -+static inline void ep0_idle (struct pxa27x_udc *dev) -+{ -+ dev->ep0state = EP0_IDLE; -+ LED_EP0_OFF; -+} -+ -+static int -+write_packet(volatile u32 *uddr, struct pxa27x_request *req, unsigned max) -+{ -+ u32 *buf; -+ int length, count, remain; -+ -+ buf = (u32*)(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; -+ -+ remain = length & 0x3; -+ count = length & ~(0x3); -+ -+ while (likely(count)) { -+ *uddr = *buf++; -+ count -= 4; -+ } -+ -+ if (remain) { -+ volatile u8* reg=(u8*)uddr; -+ char *rd =(u8*)buf; -+ -+ while (remain--) { -+ *reg=*rd++; -+ } -+ } -+ -+ 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 int -+write_fifo (struct pxa27x_ep *ep, struct pxa27x_request *req) -+{ -+ unsigned max; -+ -+ max = le16_to_cpu(ep->desc->wMaxPacketSize); -+ do { -+ int count; -+ int is_last, is_short; -+ -+ count = write_packet(ep->reg_udcdr, 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); -+ } -+ -+ DMSG("wrote %s count:%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->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_udccsr = UDCCSR_PC; -+ if (is_short) -+ *ep->reg_udccsr = UDCCSR_SP; -+ -+ /* 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->ep_num); -+#ifdef USE_DMA -+ /* unaligned data and zlps couldn't use dma */ -+ if (unlikely(!list_empty(&ep->queue))) { -+ req = list_entry(ep->queue.next, -+ struct pxa27x_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_udccsr & UDCCSR_FS); -+ return 0; -+} -+ -+/* caller asserts req->pending (ep0 irq status nyet cleared); starts -+ * ep0 data stage. these chips want very simple state transitions. -+ */ -+static inline -+void ep0start(struct pxa27x_udc *dev, u32 flags, const char *tag) -+{ -+ UDCCSR0 = flags|UDCCSR0_SA|UDCCSR0_OPC; -+ UDCISR0 = UDCICR_INT(0, UDC_INT_FIFOERROR | UDC_INT_PACKETCMP); -+ dev->req_pending = 0; -+ DBG(DBG_VERY_NOISY, "%s %s, %02x/%02x\n", -+ __FUNCTION__, tag, UDCCSR0, flags); -+} -+ -+static int -+write_ep0_fifo (struct pxa27x_ep *ep, struct pxa27x_request *req) -+{ -+ unsigned count; -+ int is_short; -+ -+ count = write_packet(&UDCDR0, req, EP0_FIFO_SIZE); -+ ep->dev->stats.write.bytes += count; -+ -+ /* last packet "must be" short (or a zlp) */ -+ is_short = (count != EP0_FIFO_SIZE); -+ -+ DBG(DBG_VERY_NOISY, "ep0in %d bytes %d left %p\n", count, -+ req->req.length - req->req.actual, &req->req); -+ -+ if (unlikely (is_short)) { -+ if (ep->dev->req_pending) -+ ep0start(ep->dev, UDCCSR0_IPR, "short IN"); -+ else -+ UDCCSR0 = UDCCSR0_IPR; -+ -+ count = req->req.length; -+ done (ep, req, 0); -+ ep0_idle(ep->dev); -+#if 0 -+ /* This seems to get rid of lost status irqs in some cases: -+ * host responds quickly, or next request involves config -+ * change automagic, or should have been hidden, or ... -+ * -+ * FIXME get rid of all udelays possible... -+ */ -+ if (count >= EP0_FIFO_SIZE) { -+ count = 100; -+ do { -+ if ((UDCCSR0 & UDCCSR0_OPC) != 0) { -+ /* clear OPC, generate ack */ -+ UDCCSR0 = UDCCSR0_OPC; -+ break; -+ } -+ count--; -+ udelay(1); -+ } while (count); -+ } -+#endif -+ } else if (ep->dev->req_pending) -+ ep0start(ep->dev, 0, "IN"); -+ return is_short; -+} -+ -+ -+/* -+ * read_fifo - unload packet(s) from the fifo we use for usb OUT -+ * transfers and put them into the request. caller should have made -+ * sure there's at least one packet ready. -+ * -+ * returns true if the request completed because of short packet or the -+ * request buffer having filled (and maybe overran till end-of-packet). -+ */ -+static int -+read_fifo (struct pxa27x_ep *ep, struct pxa27x_request *req) -+{ -+ for (;;) { -+ u32 *buf; -+ int bufferspace, count, is_short; -+ -+ /* make sure there's a packet in the FIFO.*/ -+ if (unlikely ((*ep->reg_udccsr & UDCCSR_PC) == 0)) -+ break; -+ buf =(u32*) (req->req.buf + req->req.actual); -+ prefetchw(buf); -+ bufferspace = req->req.length - req->req.actual; -+ -+ /* read all bytes from this packet */ -+ if (likely (*ep->reg_udccsr & UDCCSR_BNE)) { -+ count = 0x3ff & *ep->reg_udcbcr; -+ req->req.actual += min (count, bufferspace); -+ } else /* zlp */ -+ count = 0; -+ -+ is_short = (count < ep->ep.maxpacket); -+ DMSG("read %s udccsr:%02x, count:%d bytes%s req %p %d/%d\n", -+ ep->ep.name, *ep->reg_udccsr, count, -+ is_short ? "/S" : "", -+ &req->req, req->req.actual, req->req.length); -+ -+// dump_regs(ep->ep_num ); -+ count = min(count, bufferspace); -+ while (likely (count > 0)) { -+ *buf++ = *ep->reg_udcdr; -+ count -= 4; -+ } -+ DMSG("Buf:0x%p\n", req->req.buf); -+ -+ *ep->reg_udccsr = UDCCSR_PC; -+ /* RPC/RSP/RNE could now reflect the other packet buffer */ -+ -+ /* completion */ -+ if (is_short || req->req.actual == req->req.length) { -+ done (ep, req, 0); -+ if (list_empty(&ep->queue)) -+ pio_irq_disable (ep->ep_num); -+ return 1; -+ } -+ -+ /* finished that packet. the next one may be waiting... */ -+ } -+ return 0; -+} -+ -+/* -+ * special ep0 version of the above. no UBCR0 or double buffering; status -+ * handshaking is magic. most device protocols don't need control-OUT. -+ * CDC vendor commands (and RNDIS), mass storage CB/CBI, and some other -+ * protocols do use them. -+ */ -+static int -+read_ep0_fifo (struct pxa27x_ep *ep, struct pxa27x_request *req) -+{ -+ u32 *buf, word; -+ unsigned bufferspace; -+ -+ buf = (u32*) (req->req.buf + req->req.actual); -+ bufferspace = req->req.length - req->req.actual; -+ -+ while (UDCCSR0 & UDCCSR0_RNE) { -+ word = UDCDR0; -+ -+ if (unlikely (bufferspace == 0)) { -+ /* this happens when the driver's buffer -+ * is smaller than what the host sent. -+ * discard the extra data. -+ */ -+ if (req->req.status != -EOVERFLOW) -+ DMSG("%s overflow\n", ep->ep.name); -+ req->req.status = -EOVERFLOW; -+ } else { -+ *buf++ = word; -+ req->req.actual += 4; -+ bufferspace -= 4; -+ } -+ } -+ -+ UDCCSR0 = UDCCSR0_OPC ; -+ -+ /* completion */ -+ if (req->req.actual >= req->req.length) -+ return 1; -+ -+ /* finished that packet. the next one may be waiting... */ -+ return 0; -+} -+ -+#ifdef USE_DMA -+ -+#define MAX_IN_DMA ((DCMD_LENGTH + 1) - BULK_FIFO_SIZE) -+static void kick_dma(struct pxa27x_ep *ep, struct pxa27x_request *req) -+{ -+ u32 dcmd = 0; -+ u32 len = req->req.length; -+ u32 buf = req->req.dma; -+ u32 fifo = io_v2p ((u32)ep->reg_udcdr); -+ -+ buf += req->req.actual; -+ len -= req->req.actual; -+ ep->dma_con = 0; -+ -+ DMSG("%s: req:0x%p length:%d, actual:%d dma:%d\n", -+ __FUNCTION__, &req->req, req->req.length, -+ req->req.actual,ep->dma); -+ -+ /* no-descriptor mode can be simple for bulk-in, iso-in, iso-out */ -+ DCSR(ep->dma) = DCSR_NODESC; -+ if (buf & 0x3) -+ DALGN |= 1 << ep->dma; -+ else -+ DALGN &= ~(1 << ep->dma); -+ -+ if (ep->dir_in) { -+ DSADR(ep->dma) = buf; -+ DTADR(ep->dma) = fifo; -+ if (len > MAX_IN_DMA) { -+ len= MAX_IN_DMA; -+ ep->dma_con =1 ; -+ } else if (len >= ep->ep.maxpacket) { -+ if ((ep->dma_con = (len % ep->ep.maxpacket) != 0)) -+ len = ep->ep.maxpacket; -+ } -+ dcmd = len | DCMD_BURST32 | DCMD_WIDTH4 | DCMD_ENDIRQEN -+ | DCMD_FLOWTRG | DCMD_INCSRCADDR; -+ } else { -+ DSADR(ep->dma) = fifo; -+ DTADR(ep->dma) = buf; -+ dcmd = len | DCMD_BURST32 | DCMD_WIDTH4 | DCMD_ENDIRQEN -+ | DCMD_FLOWSRC | DCMD_INCTRGADDR; -+ } -+ *ep->reg_udccsr = UDCCSR_DME; -+ DCMD(ep->dma) = dcmd; -+ DCSR(ep->dma) = DCSR_NODESC | DCSR_EORIRQEN \ -+ | ((ep->dir_in) ? DCSR_STOPIRQEN : 0); -+ *ep->reg_drcmr = ep->dma | DRCMR_MAPVLD; -+ DCSR(ep->dma) |= DCSR_RUN; -+} -+ -+static void cancel_dma(struct pxa27x_ep *ep) -+{ -+ struct pxa27x_request *req; -+ u32 tmp; -+ -+ if (DCSR(ep->dma) == 0 || list_empty(&ep->queue)) -+ return; -+ -+ DMSG("hehe dma:%d,dcsr:0x%x\n", ep->dma, DCSR(ep->dma)); -+ DCSR(ep->dma) = 0; -+ while ((DCSR(ep->dma) & DCSR_STOPSTATE) == 0) -+ cpu_relax(); -+ -+ req = list_entry(ep->queue.next, struct pxa27x_request, queue); -+ tmp = DCMD(ep->dma) & DCMD_LENGTH; -+ req->req.actual = req->req.length - tmp; -+ -+ /* the last tx packet may be incomplete, so flush the fifo. -+ * FIXME correct req.actual if we can -+ */ -+ *ep->reg_udccsr = UDCCSR_FEF; -+} -+ -+static void dma_nodesc_handler(int dmach, void *_ep) -+{ -+ struct pxa27x_ep *ep = _ep; -+ struct pxa27x_request *req, *req_next; -+ u32 dcsr, tmp, completed; -+ -+ local_irq_disable(); -+ -+ req = list_entry(ep->queue.next, struct pxa27x_request, queue); -+ -+ DMSG("%s, buf:0x%p\n",__FUNCTION__, req->req.buf); -+ -+ ep->dma_irqs++; -+ ep->dev->stats.irqs++; -+ HEX_DISPLAY(ep->dev->stats.irqs); -+ -+ completed = 0; -+ -+ dcsr = DCSR(dmach); -+ DCSR(ep->dma) &= ~DCSR_RUN; -+ -+ if (dcsr & DCSR_BUSERR) { -+ DCSR(dmach) = DCSR_BUSERR; -+ printk(KERN_ERR " Buss Error\n"); -+ req->req.status = -EIO; -+ completed = 1; -+ } else if (dcsr & DCSR_ENDINTR) { -+ DCSR(dmach) = DCSR_ENDINTR; -+ if (ep->dir_in) { -+ tmp = req->req.length - req->req.actual; -+ /* Last packet is a short one*/ -+ if ( tmp < ep->ep.maxpacket) { -+ int count = 0; -+ -+ *ep->reg_udccsr = UDCCSR_SP | \ -+ (*ep->reg_udccsr & UDCCSR_MASK); -+ /*Wait for packet out */ -+ while( (count++ < 10000) && \ -+ !(*ep->reg_udccsr & UDCCSR_FS)); -+ if (count >= 10000) -+ DMSG("Failed to send packet\n"); -+ else -+ DMSG("%s: short packet sent len:%d," -+ "length:%d,actual:%d\n", __FUNCTION__, -+ tmp, req->req.length, req->req.actual); -+ req->req.actual = req->req.length; -+ completed = 1; -+ /* There are still packets to transfer */ -+ } else if ( ep->dma_con) { -+ DMSG("%s: more packets,length:%d,actual:%d\n", -+ __FUNCTION__,req->req.length, -+ req->req.actual); -+ req->req.actual += ep->ep.maxpacket; -+ completed = 0; -+ } else { -+ DMSG("%s: no more packets,length:%d," -+ "actual:%d\n", __FUNCTION__, -+ req->req.length, req->req.actual); -+ req->req.actual = req->req.length; -+ completed = 1; -+ } -+ } else { -+ req->req.actual = req->req.length; -+ completed = 1; -+ } -+ } else if (dcsr & DCSR_EORINTR) { //Only happened in OUT DMA -+ int remain,udccsr ; -+ -+ DCSR(dmach) = DCSR_EORINTR; -+ remain = DCMD(dmach) & DCMD_LENGTH; -+ req->req.actual = req->req.length - remain; -+ -+ udccsr = *ep->reg_udccsr; -+ if (udccsr & UDCCSR_SP) { -+ *ep->reg_udccsr = UDCCSR_PC | (udccsr & UDCCSR_MASK); -+ completed = 1; -+ } -+ DMSG("%s: length:%d actual:%d\n", -+ __FUNCTION__, req->req.length, req->req.actual); -+ } else -+ DMSG("%s: Others dma:%d DCSR:0x%x DCMD:0x%x\n", -+ __FUNCTION__, dmach, DCSR(dmach), DCMD(dmach)); -+ -+ if (likely(completed)) { -+ if (req->queue.next != &ep->queue) { -+ req_next = list_entry(req->queue.next, -+ struct pxa27x_request, queue); -+ kick_dma(ep, req_next); -+ } -+ done(ep, req, 0); -+ } else { -+ kick_dma(ep, req); -+ } -+ -+ local_irq_enable(); -+} -+ -+#endif -+/*-------------------------------------------------------------------------*/ -+ -+static int -+pxa27x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) -+{ -+ struct pxa27x_ep *ep; -+ struct pxa27x_request *req; -+ struct pxa27x_udc *dev; -+ unsigned long flags; -+ -+ req = container_of(_req, struct pxa27x_request, req); -+ if (unlikely (!_req || !_req->complete || !_req->buf|| -+ !list_empty(&req->queue))) { -+ DMSG("%s, bad params\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ ep = container_of(_ep, struct pxa27x_ep, ep); -+ if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { -+ DMSG("%s, bad ep\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ DMSG("%s, ep point %d is queue\n", __FUNCTION__, ep->ep_num); -+ -+ dev = ep->dev; -+ if (unlikely (!dev->driver -+ || dev->gadget.speed == USB_SPEED_UNKNOWN)) { -+ DMSG("%s, bogus device state\n", __FUNCTION__); -+ return -ESHUTDOWN; -+ } -+ -+ /* iso is always one packet per request, that's the only way -+ * we can report per-packet status. that also helps with dma. -+ */ -+ if (unlikely (ep->ep_type == USB_ENDPOINT_XFER_ISOC -+ && 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, _req->buf, _req->length, -+ (ep->dir_in) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); -+ } -+#endif -+ -+ DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n", -+ _ep->name, _req, _req->length, _req->buf); -+ -+ local_irq_save(flags); -+ -+ _req->status = -EINPROGRESS; -+ _req->actual = 0; -+ -+ /* kickstart this i/o queue? */ -+ if (list_empty(&ep->queue) && !ep->stopped) { -+ if (ep->desc == 0 /* ep0 */) { -+ unsigned length = _req->length; -+ -+ switch (dev->ep0state) { -+ case EP0_IN_DATA_PHASE: -+ dev->stats.write.ops++; -+ if (write_ep0_fifo(ep, req)) -+ req = 0; -+ break; -+ -+ case EP0_OUT_DATA_PHASE: -+ dev->stats.read.ops++; -+ if (dev->req_pending) -+ ep0start(dev, UDCCSR0_IPR, "OUT"); -+ if (length == 0 || ((UDCCSR0 & UDCCSR0_RNE) != 0 -+ && read_ep0_fifo(ep, req))) { -+ ep0_idle(dev); -+ done(ep, req, 0); -+ req = 0; -+ } -+ break; -+ case EP0_NO_ACTION: -+ ep0_idle(dev); -+ req=0; -+ break; -+ default: -+ DMSG("ep0 i/o, odd state %d\n", dev->ep0state); -+ local_irq_restore (flags); -+ return -EL2HLT; -+ } -+#ifdef USE_DMA -+ /* either start dma or prime pio pump */ -+ } else if (ep->dma >= 0) { -+ kick_dma(ep, req); -+#endif -+ /* can the FIFO can satisfy the request immediately? */ -+ } else if (ep->dir_in -+ && (*ep->reg_udccsr & UDCCSR_FS) != 0 -+ && write_fifo(ep, req)) { -+ req = 0; -+ } else if ((*ep->reg_udccsr & UDCCSR_FS) != 0 -+ && read_fifo(ep, req)) { -+ req = 0; -+ } -+ DMSG("req:%p,ep->desc:%p,ep->dma:%d\n", req, ep->desc, ep->dma); -+ if (likely (req && ep->desc) && ep->dma < 0) -+ pio_irq_enable(ep->ep_num); -+ } -+ -+ /* pio or dma irq handler advances the queue. */ -+ if (likely (req != 0)) -+ list_add_tail(&req->queue, &ep->queue); -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+ -+/* -+ * nuke - dequeue ALL requests -+ */ -+static void nuke(struct pxa27x_ep *ep, int status) -+{ -+ struct pxa27x_request *req; -+ -+ /* called with irqs blocked */ -+#ifdef USE_DMA -+ if (ep->dma >= 0 && !ep->stopped) -+ cancel_dma(ep); -+#endif -+ while (!list_empty(&ep->queue)) { -+ req = list_entry(ep->queue.next, struct pxa27x_request, queue); -+ done(ep, req, status); -+ } -+ if (ep->desc) -+ pio_irq_disable (ep->ep_num); -+} -+ -+ -+/* dequeue JUST ONE request */ -+static int pxa27x_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct pxa27x_ep *ep; -+ struct pxa27x_request *req; -+ unsigned long flags; -+ -+ ep = container_of(_ep, struct pxa27x_ep, ep); -+ 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); -+ done(ep, req, -ECONNRESET); -+ /* restart i/o */ -+ if (!list_empty(&ep->queue)) { -+ req = list_entry(ep->queue.next, -+ struct pxa27x_request, queue); -+ kick_dma(ep, req); -+ } -+ } else -+#endif -+ done(ep, req, -ECONNRESET); -+ -+ local_irq_restore(flags); -+ return 0; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int pxa27x_ep_set_halt(struct usb_ep *_ep, int value) -+{ -+ struct pxa27x_ep *ep; -+ unsigned long flags; -+ -+ DMSG("%s is called\n", __FUNCTION__); -+ ep = container_of(_ep, struct pxa27x_ep, ep); -+ if (unlikely (!_ep -+ || (!ep->desc && ep->ep.name != ep0name)) -+ || ep->ep_type == USB_ENDPOINT_XFER_ISOC) { -+ DMSG("%s, bad ep\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ if (value == 0) { -+ /* this path (reset toggle+halt) is needed to implement -+ * SET_INTERFACE on normal hardware. but it can't be -+ * done from software on the PXA UDC, and the hardware -+ * forgets to do it as part of SET_INTERFACE automagic. -+ */ -+ DMSG("only host can clear %s halt\n", _ep->name); -+ return -EROFS; -+ } -+ -+ local_irq_save(flags); -+ -+ if (ep->dir_in && ((*ep->reg_udccsr & UDCCSR_FS) == 0 -+ || !list_empty(&ep->queue))) { -+ local_irq_restore(flags); -+ return -EAGAIN; -+ } -+ -+ /* FST bit is the same for control, bulk in, bulk out, interrupt in */ -+ *ep->reg_udccsr = UDCCSR_FST|UDCCSR_FEF; -+ -+ /* ep0 needs special care */ -+ if (!ep->desc) { -+ start_watchdog(ep->dev); -+ ep->dev->req_pending = 0; -+ ep->dev->ep0state = EP0_STALL; -+ LED_EP0_OFF; -+ -+ /* and bulk/intr endpoints like dropping stalls too */ -+ } else { -+ unsigned i; -+ for (i = 0; i < 1000; i += 20) { -+ if (*ep->reg_udccsr & UDCCSR_SST) -+ break; -+ udelay(20); -+ } -+ } -+ local_irq_restore(flags); -+ -+ DBG(DBG_VERBOSE, "%s halt\n", _ep->name); -+ return 0; -+} -+ -+static int pxa27x_ep_fifo_status(struct usb_ep *_ep) -+{ -+ struct pxa27x_ep *ep; -+ -+ ep = container_of(_ep, struct pxa27x_ep, ep); -+ if (!_ep) { -+ DMSG("%s, bad ep\n", __FUNCTION__); -+ return -ENODEV; |
