diff options
Diffstat (limited to 'recipes-kernel/linux/linux-2.6.29/h3600/03_add_features/0027-USB-add-sa1100_udc-driver.patch')
-rw-r--r-- | recipes-kernel/linux/linux-2.6.29/h3600/03_add_features/0027-USB-add-sa1100_udc-driver.patch | 2592 |
1 files changed, 0 insertions, 2592 deletions
diff --git a/recipes-kernel/linux/linux-2.6.29/h3600/03_add_features/0027-USB-add-sa1100_udc-driver.patch b/recipes-kernel/linux/linux-2.6.29/h3600/03_add_features/0027-USB-add-sa1100_udc-driver.patch deleted file mode 100644 index 4b2e4b9..0000000 --- a/recipes-kernel/linux/linux-2.6.29/h3600/03_add_features/0027-USB-add-sa1100_udc-driver.patch +++ /dev/null @@ -1,2592 +0,0 @@ -From c573d808bc27f52066b692e7a2572709cccd0818 Mon Sep 17 00:00:00 2001 -From: Dmitry Artamonow <mad_soft@inbox.ru> -Date: Sat, 21 Mar 2009 18:41:03 +0300 -Subject: [PATCH 27/28] USB: add sa1100_udc driver - -It's original driver by Nick Bane, slightly cleaned -(formatting mostly) and ported to current kernel. -This driver is a mess, but at least it works somehow. - -Signed-off-by: Dmitry Artamonow <mad_soft@inbox.ru> ---- - drivers/usb/gadget/Kconfig | 15 + - drivers/usb/gadget/Makefile | 1 + - drivers/usb/gadget/sa1100_udc.c | 2416 +++++++++++++++++++++++++++++++++++++++ - drivers/usb/gadget/sa1100_udc.h | 104 ++ - 4 files changed, 2536 insertions(+), 0 deletions(-) - create mode 100644 drivers/usb/gadget/sa1100_udc.c - create mode 100644 drivers/usb/gadget/sa1100_udc.h - -diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig -index e55fef5..b71dfbf 100644 ---- a/drivers/usb/gadget/Kconfig -+++ b/drivers/usb/gadget/Kconfig -@@ -464,6 +464,21 @@ config USB_GOKU - # LAST -- dummy/emulated controller - # - -+config USB_GADGET_SA1100 -+ boolean "SA1100 USB Device Port" -+ depends on ARCH_SA1100 -+ select USB_GADGET_SELECTED -+ help -+ -+ Say "y" to link the driver statically, or "m" to build a -+ dynamically linked module called "sa1100_udc" and force all -+ gadget drivers to also be dynamically linked. -+ -+config USB_SA1100 -+ tristate -+ depends on USB_GADGET_SA1100 -+ default USB_GADGET -+ - config USB_GADGET_DUMMY_HCD - boolean "Dummy HCD (DEVELOPMENT)" - depends on USB=y || (USB=m && USB_GADGET=m) -diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile -index 39a51d7..70e56d0 100644 ---- a/drivers/usb/gadget/Makefile -+++ b/drivers/usb/gadget/Makefile -@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_GOKU) += goku_udc.o - obj-$(CONFIG_USB_OMAP) += omap_udc.o - obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o - obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o -+obj-$(CONFIG_USB_SA1100) += sa1100_udc.o - obj-$(CONFIG_USB_AT91) += at91_udc.o - obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o - obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o -diff --git a/drivers/usb/gadget/sa1100_udc.c b/drivers/usb/gadget/sa1100_udc.c -new file mode 100644 -index 0000000..2f5bd85 ---- /dev/null -+++ b/drivers/usb/gadget/sa1100_udc.c -@@ -0,0 +1,2416 @@ -+/* -+ * SA1100 USB Device Controller (UDC) driver. -+ * -+ * Copyright (C) Compaq Computer Corporation, 1998, 1999 -+ * Copyright (C) Extenex Corporation, 2001 -+ * Copyright (C) David Brownell, 2003 -+ * Copyright (C) Nick Bane, 2005, 2006, 2007 -+ * Many fragments from pxa2xx_udc.c and mach-sa1100 driver with various -+ * GPL Copyright authors incl Russel king and Nicolas Pitre -+ * Working port to 2.6.32-1 by N C Bane -+ * -+ * This file provides interrupt routing and overall coordination for the -+ * sa1100 USB endpoints: ep0, ep1out-bulk, ep2in-bulk, as well as device -+ * initialization and some parts of USB "Chapter 9" device behavior. -+ * -+ * It implements the "USB gadget controller" API, abstracting most hardware -+ * details so that drivers running on top of this API are mostly independent -+ * of hardware. A key exception is that ep0 logic needs to understand which -+ * endpoints a given controller has, and their capabilities. Also, hardware -+ * that doesn't fully support USB (like sa1100) may need workarounds in the -+ * protocols implemented by device functions. -+ * -+ * See linux/Documentation/arm/SA1100/SA1100_USB for more info, or the -+ * kerneldoc for the API exposed to gadget drivers. -+ * -+ */ -+#define DEBUG 1 -+#define VERBOSE 1 -+ -+#define SA1100_USB_DEBUG -+#ifdef SA1100_USB_DEBUG -+static int sa1100_usb_debug; -+#endif -+ -+#define NCB_DMA_FIX -+#ifdef NCB_DMA_FIX -+/* This is a clunky fix for dma alignemnt issues -+ * It should probably be done better by someone more -+ * steeped in DMA lore -+ */ -+#include <linux/slab.h> -+#define SEND_BUFFER_SIZE 4096 /* this is probably a bit big */ -+#define RECEIVE_BUFFER_SIZE 256 /* 64 may be all that is necessary */ -+static char *send_buffer; -+static char *receive_buffer; -+#endif -+ -+#include <linux/module.h> -+#include <linux/kernel.h> -+#include <linux/delay.h> -+#include <linux/ioport.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/smp_lock.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/timer.h> -+#include <linux/list.h> -+#include <linux/interrupt.h> -+#include <linux/version.h> -+#include <linux/device.h> -+#include <linux/platform_device.h> -+#include <linux/io.h> -+ -+#include <asm/irq.h> -+#include <mach/dma.h> -+#include <asm/system.h> -+#include <asm/unaligned.h> -+ -+#include <linux/usb.h> -+#include <linux/usb/ch9.h> -+#include <linux/usb/gadget.h> -+ -+#if CONFIG_PROC_FS -+#include <linux/proc_fs.h> -+#endif -+ -+#define DRIVER_VERSION __DATE__ -+ -+#define DMA_ADDR_INVALID (~(dma_addr_t)0) -+ -+ -+static const char driver_name[] = "sa1100_udc"; -+static const char driver_desc[] = "SA-1110 USB Device Controller"; -+ -+static const char ep0name[] = "ep0"; -+ -+#ifdef DEBUG -+static char *type_string(u8 bmAttributes) -+{ -+ switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { -+ case USB_ENDPOINT_XFER_BULK: -+ return "bulk"; -+ /* case USB_ENDPOINT_XFER_ISOC: -+ return "iso"; */ -+ case USB_ENDPOINT_XFER_INT: -+ return "intr"; -+ }; -+ return "control"; -+} -+#endif -+ -+#include <linux/dma-mapping.h> -+struct usb_stats_t { -+ unsigned long ep0_fifo_write_failures; -+ unsigned long ep0_bytes_written; -+ unsigned long ep0_fifo_read_failures; -+ unsigned long ep0_bytes_read; -+}; -+ -+struct usb_info_t { -+ dma_regs_t *dmaregs_tx, *dmaregs_rx; -+ int state; -+ unsigned char address; -+ struct usb_stats_t stats; -+}; -+ -+enum { kError = -1, kEvSuspend = 0, kEvReset = 1, -+ kEvResume = 2, kEvAddress = 3, kEvConfig = 4, kEvDeConfig = 5 }; -+ -+int usbctl_next_state_on_event(int event) -+{ -+ return 0; -+} -+static struct usb_info_t usbd_info; -+ -+/* UDC register utility functions */ -+#define UDC_write(reg, val) { \ -+ int i = 10000; \ -+ do { \ -+ (reg) = (val); \ -+ if (i-- <= 0) { \ -+ pr_err("%s [%d]: write %#x to %p (%#lx) failed\n", \ -+ __func__, __LINE__, (val), &(reg), (reg)); \ -+ break; \ -+ } \ -+ } while ((reg) != (val)); \ -+} -+ -+#define UDC_set(reg, val) { \ -+ int i = 10000; \ -+ do { \ -+ (reg) |= (val); \ -+ if (i-- <= 0) { \ -+ pr_err("%s [%d]: set %#x of %p (%#lx) failed\n", \ -+ __func__, __LINE__, (val), &(reg), (reg)); \ -+ break; \ -+ } \ -+ } while (!((reg) & (val))); \ -+} -+ -+#define UDC_clear(reg, val) { \ -+ int i = 10000; \ -+ do { \ -+ (reg) &= ~(val); \ -+ if (i-- <= 0) { \ -+ pr_err("%s [%d]: clear %#x of %p (%#lx) failed\n", \ -+ __func__, __LINE__, (val), &(reg), (reg)); \ -+ break; \ -+ } \ -+ } while ((reg) & (val)); \ -+} -+ -+#define UDC_flip(reg, val) { \ -+ int i = 10000; \ -+ (reg) = (val); \ -+ do { \ -+ (reg) = (val); \ -+ if (i-- <= 0) { \ -+ pr_err("%s [%d]: flip %#x of %p (%#lx) failed\n", \ -+ __func__, __LINE__, (val), &(reg), (reg)); \ -+ break; \ -+ } \ -+ } while (((reg) & (val))); \ -+} -+ -+#include "sa1100_udc.h" -+ -+static struct sa1100_udc *the_controller; -+static void nuke(struct sa1100_ep *, int status); -+static void done(struct sa1100_ep *ep, struct sa1100_request *req, int status); -+static inline void ep0_idle(struct sa1100_udc *dev) -+{ -+ dev->ep0state = EP0_IDLE; -+} -+ -+/* ep0 handlers */ -+ -+/* 1 == lots of trace noise, 0 = only "important' stuff */ -+#define VERBOSITY 1 -+ -+#if 1 && !defined(ASSERT) -+#define ASSERT(expr) \ -+ if (!(expr)) { \ -+ pr_err("Assertion failed! %s, %s, %s, line = %d\n",\ -+ #expr, __FILE__, __func__, __LINE__); \ -+ } -+#else -+# define ASSERT(expr) -+#endif -+ -+#if VERBOSITY -+#define PRINTKD(fmt, args...) printk(fmt, ## args) -+#else -+#define PRINTKD(fmt, args...) -+#endif -+ -+/* other subroutines */ -+unsigned int (*wrint)(void); -+static void ep0_int_hndlr(void); -+static void ep0_queue(void *buf, unsigned int req, unsigned int act); -+static void write_fifo(void); -+static int read_fifo(struct usb_ctrlrequest *p); -+ -+/* some voodo helpers 01Mar01ww */ -+static void set_cs_bits(__u32 set_bits); -+static void set_de(void); -+static void set_ipr(void); -+static void set_ipr_and_de(void); -+static bool clear_opr(void); -+ -+/*************************************************************************** -+Inline Helpers -+***************************************************************************/ -+ -+/* Data extraction from usb_request_t fields */ -+enum { kTargetDevice = 0, kTargetInterface = 1, kTargetEndpoint = 2 }; -+static inline int request_target(__u8 b) { return (int) (b & 0x0F); } -+ -+static inline int windex_to_ep_num(__u16 w) { return (int) (w & 0x000F); } -+inline int type_code_from_request(__u8 by) { return ((by >> 4) & 3); } -+ -+/* following is hook for self-powered flag in GET_STATUS. Some devices -+ .. might like to override and return real info */ -+static inline bool self_powered_hook(void) { return true; } -+ -+#if VERBOSITY -+/* "pcs" == "print control status" */ -+static inline void pcs(void) -+{ -+ __u32 foo = Ser0UDCCS0; -+ printk("%8.8X: %s %s %s %s\n", -+ foo, -+ foo & UDCCS0_SE ? "SE" : "", -+ foo & UDCCS0_OPR ? "OPR" : "", -+ foo & UDCCS0_IPR ? "IPR" : "", -+ foo & UDCCS0_SST ? "SST" : "" -+ ); -+} -+static inline void preq(struct usb_ctrlrequest *pReq) -+{ -+ static char *tnames[] = { "dev", "intf", "ep", "oth" }; -+ static char *rnames[] = { "std", "class", "vendor", "???" }; -+ char *psz; -+ switch (pReq->bRequest) { -+ case USB_REQ_GET_STATUS: -+ psz = "get stat"; -+ break; -+ case USB_REQ_CLEAR_FEATURE: -+ psz = "clr feat"; -+ break; -+ case USB_REQ_SET_FEATURE: -+ psz = "set feat"; -+ break; -+ case USB_REQ_SET_ADDRESS: -+ psz = "set addr"; -+ break; -+ case USB_REQ_GET_DESCRIPTOR: -+ psz = "get desc"; -+ break; -+ case USB_REQ_SET_DESCRIPTOR: -+ psz = "set desc"; -+ break; -+ case USB_REQ_GET_CONFIGURATION: -+ psz = "get cfg"; -+ break; -+ case USB_REQ_SET_CONFIGURATION: -+ psz = "set cfg"; -+ break; -+ case USB_REQ_GET_INTERFACE: -+ psz = "get intf"; -+ break; -+ case USB_REQ_SET_INTERFACE: -+ psz = "set intf"; -+ break; -+ default: -+ psz = "unknown"; -+ break; -+ } -+ pr_err("- [%s: %s req to %s. dir=%s]\n", psz, -+ rnames[(pReq->bRequestType >> 5) & 3], -+ tnames[pReq->bRequestType & 3], -+ (pReq->bRequestType & 0x80) ? "in" : "out"); -+} -+ -+static inline void usbctl_dump_request(const char *prefix, -+ const struct usb_ctrlrequest *req) -+{ -+ pr_err("%s: bRequestType=0x%02x bRequest=0x%02x " -+ "wValue=0x%04x wIndex=0x%04x wLength=0x%04x\n", -+ prefix, req->bRequestType, req->bRequest, -+ le16_to_cpu(req->wValue), le16_to_cpu(req->wIndex), -+ le16_to_cpu(req->wLength)); -+} -+#else -+static inline void pcs(void) {} -+static inline void preq(void *x) {} -+static inline void usbctl_dump_request(const char *prefix, -+ const struct usb_ctrlrequest *req) {} -+#endif -+ -+/*************************************************************************** -+Globals -+***************************************************************************/ -+static const char pszMe[] = "usbep0: "; -+ -+ -+/* global write struct to keep write -+ ..state around across interrupts */ -+static struct { -+ unsigned char *p; -+ int bytes_left; -+} wr; -+ -+/*************************************************************************** -+Public Interface -+***************************************************************************/ -+ -+/* reset received from HUB (or controller just went nuts and reset by itself!) -+ so udc core has been reset, track this state here */ -+void ep0_reset(void) -+{ -+ /* reset state machine */ -+ wr.p = NULL; -+ wr.bytes_left = 0; -+ usbd_info.address = 0; -+/* needed? */ -+ Ser0UDCAR = 0; -+} -+ -+ -+/* handle interrupt for endpoint zero */ -+ -+inline void ep0_clear_write(void) -+{ -+ wr.p = NULL; -+ wr.bytes_left = 0; -+} -+ -+/* this is a config packet parser based on that from the updated HH 2.6 udc */ -+static void ep0_read_packet(void) -+{ -+ unsigned char status_buf[2]; /* returned in GET_STATUS */ -+ struct usb_ctrlrequest req; -+ int request_type; -+ int n; -+ __u32 address; -+ __u32 in, out; -+ -+ /* reset previous count */ -+ the_controller->ep0_req_len = -1; -+ -+ /* read the setup request */ -+ n = read_fifo(&req); -+ usbctl_dump_request("ep0_read_packet", &req); -+ -+ if (n != sizeof(req)) { -+ pr_err("%ssetup begin: fifo READ ERROR wanted %d bytes" -+ " got %d. Stalling out...\n", -+ pszMe, sizeof(req), n); -+ /* force stall, serviced out */ -+ set_cs_bits(UDCCS0_FST | UDCCS0_SO); -+ goto sh_sb_end; -+ } -+ -+ /* Is it a standard request? (not vendor or class request) */ -+ request_type = type_code_from_request(req.bRequestType); -+ if (request_type != 0) { -+ pr_err("%ssetup begin: unsupported bRequestType: %d ignored\n", -+ pszMe, request_type); -+ set_cs_bits(UDCCS0_DE | UDCCS0_SO); -+ goto sh_sb_end; -+ } -+ -+ /* save requested reply size */ -+ the_controller->ep0_req_len = le16_to_cpu(req.wLength); -+ PRINTKD("%s: request length is %d\n", __func__, -+ the_controller->ep0_req_len); -+ -+#if VERBOSITY -+ { -+ unsigned char *pdb = (unsigned char *) &req; -+ PRINTKD("%2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X ", -+ pdb[0], pdb[1], pdb[2], pdb[3], pdb[4], pdb[5], pdb[6], pdb[7] -+ ); -+ preq(&req); -+ } -+#endif -+ -+ /* Handle it */ -+ switch (req.bRequest) { -+ -+ /* This first bunch have no data phase */ -+ -+ case USB_REQ_SET_ADDRESS: -+ address = (__u32) (req.wValue & 0x7F); -+ /* when SO and DE sent, UDC will enter status phase and ack, -+ ..propagating new address to udc core. Next control transfer -+ ..will be on the new address. You can't see the change in a -+ ..read back of CAR until then. (about 250us later, on my box). -+ ..The original Intel driver sets S0 and DE and code to check -+ ..that address has propagated here. I tried this, but it -+ ..would only work sometimes! The rest of the time it would -+ ..never propagate and we'd spin forever. So now I just set -+ ..it and pray... -+ */ -+ Ser0UDCAR = address; -+ usbd_info.address = address; -+ usbctl_next_state_on_event(kEvAddress); -+ set_cs_bits(UDCCS0_SO | UDCCS0_DE); /* no data phase */ -+ pr_err("%sI have been assigned address: %d\n", pszMe, -+ address); -+ break; -+ -+ -+ case USB_REQ_SET_CONFIGURATION: -+ if (req.wValue == 1) { -+ /* configured */ -+ if (usbctl_next_state_on_event(kEvConfig) != kError) { -+ /* (re)set the out and in max packet sizes */ -+ PRINTKD("%s: calling the_controller." -+ "driver->setup with SET_CONFIGURATION\n", -+ __func__); -+ the_controller->driver->setup(&the_controller->gadget, &req); -+ in = __le16_to_cpu(the_controller->ep[1].ep.maxpacket); -+ out = __le16_to_cpu(the_controller->ep[2].ep.maxpacket); -+ Ser0UDCOMP = (out - 1); -+ Ser0UDCIMP = (in - 1); -+ /* we are configured */ -+ usbd_info.state = USB_STATE_CONFIGURED; -+ /* enable rx and tx interrupts */ -+ Ser0UDCCR &= ~(UDCCR_RIM | UDCCR_TIM); -+ -+ pr_err("%sConfigured (OMP=%8.8X IMP=%8.8X)\n", -+ pszMe, out, in); -+ break; -+ } -+ } else if (req.wValue == 0) { -+ /* de-configured */ -+ if (usbctl_next_state_on_event(kEvDeConfig) != kError) -+ pr_err("%sDe-Configured\n", pszMe); -+ usbd_info.state = 0; -+ Ser0UDCCR |= UDCCR_RIM | UDCCR_TIM; -+ ep1_reset(); -+ ep2_reset(); -+ pr_err("%s: de-configured. Tx and Rx interrupts" -+ "disabled. ep1 and ep2 reset\n", __func__); -+ } else { -+ pr_err("%ssetup phase: Unknown " -+ "\"set configuration\" data %d\n", -+ pszMe, req.wValue); -+ } -+ set_cs_bits(UDCCS0_SO | UDCCS0_DE); /* no data phase */ -+ break; -+ -+ case USB_REQ_CLEAR_FEATURE: -+ /* could check data length, direction...26Jan01ww */ -+ if (req.wValue == 0) { /* clearing ENDPOINT_HALT/STALL */ -+ int ep = windex_to_ep_num(req.wIndex); -+ if (ep == 1) { -+ pr_err("%sclear feature \"endpoint halt\" " -+ " on receiver\n", pszMe); -+ ep1_reset(); -+ } else if (ep == 2) { -+ pr_err("%sclear feature \"endpoint halt\" " -+ "on xmitter\n", pszMe); -+ ep2_reset(); -+ } else { -+ pr_err("%sclear feature \"endpoint halt\" " -+ "on unsupported ep # %d\n", -+ pszMe, ep); -+ } -+ } else { -+ pr_err("%sUnsupported feature selector (%d) " -+ "in clear feature. Ignored.\n" , -+ pszMe, req.wValue); -+ } -+ set_cs_bits(UDCCS0_SO | UDCCS0_DE); /* no data phase */ -+ break; -+ -+ case USB_REQ_SET_FEATURE: -+ if (req.wValue == 0) { /* setting ENDPOINT_HALT/STALL */ -+ int ep = windex_to_ep_num(req.wValue); -+ if (ep == 1) { -+ pr_err("%set feature \"endpoint halt\" " -+ "on receiver\n", pszMe); -+ ep1_stall(); -+ } else if (ep == 2) { -+ pr_err("%sset feature \"endpoint halt\" " -+ " on xmitter\n", pszMe); -+ ep2_stall(); -+ } else { -+ pr_err("%sset feature \"endpoint halt\" " -+ "on unsupported ep # %d\n", -+ pszMe, ep); -+ } -+ } else { -+ pr_err("%sUnsupported feature selector " -+ "(%d) in set feature\n", -+ pszMe, req.wValue); -+ } -+ set_cs_bits(UDCCS0_SO | UDCCS0_DE); /* no data phase */ -+ break; -+ -+ /* The rest have a data phase that writes back to the host */ -+ case USB_REQ_GET_STATUS: -+ /* return status bit flags */ -+ status_buf[0] = status_buf[1] = 0; -+ n = request_target(req.bRequestType); -+ switch (n) { -+ case kTargetDevice: -+ if (self_powered_hook()) -+ status_buf[0] |= 1; -+ break; -+ case kTargetInterface: -+ break; -+ case kTargetEndpoint: -+ /* return stalled bit */ -+ n = windex_to_ep_num(req.wIndex); -+ if (n == 1) -+ status_buf[0] |= (Ser0UDCCS1 & UDCCS1_FST) >> 4; -+ else if (n == 2) -+ status_buf[0] |= (Ser0UDCCS2 & UDCCS2_FST) >> 5; -+ else -+ pr_err("%sUnknown endpoint (%d) " -+ "in GET_STATUS\n", pszMe, n); -+ break; -+ default: -+ pr_err("%sUnknown target (%d) in GET_STATUS\n", -+ pszMe, n); -+ /* fall thru */ -+ break; -+ } -+ PRINTKD("%s: GET_STATUS writing %d\n", __func__, req.wLength); -+ ep0_queue(status_buf, req.wLength, sizeof(status_buf)); -+ break; -+ case USB_REQ_GET_DESCRIPTOR: -+ PRINTKD("%s: calling the_controller.driver->setup" -+ " with GET_DESCRIPTOR\n", __func__); -+ the_controller->driver->setup(&the_controller->gadget, &req); -+ break; -+ case USB_REQ_GET_CONFIGURATION: -+ PRINTKD("%s: calling the_controller.driver->setup" -+ " with GET_CONFIGURATION\n", __func__); -+ the_controller->driver->setup(&the_controller->gadget, &req); -+ break; -+ case USB_REQ_GET_INTERFACE: -+ PRINTKD("%s: calling the_controller->driver->setup" -+ " with GET_INTERFACE\n", __func__); -+ the_controller->driver->setup(&the_controller->gadget, &req); -+ break; -+ case USB_REQ_SET_INTERFACE: -+ PRINTKD("%s: calling the_controller->driver->setup" -+ " with SET_INTERFACE\n", __func__); -+ the_controller->driver->setup(&the_controller->gadget, &req); -+ break; -+ default: -+ pr_err("%sunknown request 0x%x\n", pszMe, req.bRequest); -+ break; -+ } /* switch( bRequest ) */ -+ -+sh_sb_end: -+ return; -+ -+} -+ -+static void ep0_int_hndlr(void) -+{ -+ u32 cs_reg_in; -+ -+ pcs(); -+ -+ cs_reg_in = Ser0UDCCS0; -+ -+ /* -+ * If "setup end" has been set, the usb controller has terminated -+ * a setup transaction before we set DE. This happens during -+ * enumeration with some hosts. For example, the host will ask for -+ * our device descriptor and specify a return of 64 bytes. When we -+ * hand back the first 8, the host will know our max packet size -+ * and turn around and issue a new setup immediately. This causes -+ * the UDC to auto-ack the new setup and set SE. We must then -+ * "unload" (process) the new setup, which is what will happen -+ * after this preamble is finished executing. -+ */ -+ if (cs_reg_in & UDCCS0_SE) { -+ PRINTKD("UDC: early termination of setup\n"); -+ -+ /* -+ * Clear setup end -+ */ -+ set_cs_bits(UDCCS0_SSE); -+ -+ /* -+ * Clear any pending write. -+ */ -+ ep0_clear_write(); -+ } -+ -+ /* -+ * UDC sent a stall due to a protocol violation. -+ */ -+ if (cs_reg_in & UDCCS0_SST) { -+ PRINTKD("UDC: write_preamble: UDC sent stall\n"); -+ -+ /* -+ * Clear sent stall -+ */ -+ set_cs_bits(UDCCS0_SST); -+ -+ /* -+ * Clear any pending write. -+ */ -+ ep0_clear_write(); -+ } -+ -+ switch (cs_reg_in & (UDCCS0_OPR | UDCCS0_IPR)) { -+ case UDCCS0_OPR | UDCCS0_IPR: -+ PRINTKD("UDC: write_preamble: see OPR. Stopping write to " -+ "handle new SETUP\n"); -+ -+ /* -+ * very rarely, you can get OPR and -+ * leftover IPR. Try to clear -+ */ -+ UDC_clear(Ser0UDCCS0, UDCCS0_IPR); -+ -+ /* -+ * Clear any pending write. -+ */ -+ ep0_clear_write(); -+ -+ /*FALLTHROUGH*/ -+ case UDCCS0_OPR: -+ /* -+ * A new setup request is pending. Handle -+ * it. Note that we don't try to read a -+ * packet if SE was set and OPR is clear. -+ */ -+ ep0_read_packet(); -+ break; -+ -+ case 0: -+ /* if data pending ... */ -+ if (wr.p) { -+ unsigned int cs_bits = 0; -+ if (wr.bytes_left != 0) { -+ /* -+ * More data to go -+ */ -+ write_fifo(); -+ /* packet ready */ -+ cs_bits |= UDCCS0_IPR; -+ } -+ -+ if (wr.bytes_left == 0) { -+ /* -+ * All data sent. -+ */ -+ cs_bits |= wrint(); -+ /* a null packet may be following */ -+ if (!wrint) -+ ep0_clear_write(); -+ } -+ set_cs_bits(cs_bits); -+ } else -+ PRINTKD("%s: No data - probably an ACK\n", __func__); -+ break; -+ -+ case UDCCS0_IPR: -+ PRINTKD("UDC: IPR set, not writing\n"); -+ break; -+ } -+ -+ pcs(); -+ PRINTKD("-end-\n"); -+} -+ -+static unsigned int ep0_sh_write_data(void) -+{ -+ /* -+ * If bytes left is zero, we are coming in on the -+ * interrupt after the last packet went out. And -+ * we know we don't have to empty packet this -+ * transfer so just set DE and we are done -+ */ -+ PRINTKD("UDC: normal packet ended\n"); -+ wrint = NULL; -+ return UDCCS0_DE; -+} -+ -+static unsigned int ep0_sh_write_with_empty_packet(void) -+{ -+ /* -+ * If bytes left is zero, we are coming in on the -+ * interrupt after the last packet went out. -+ * We must do short packet suff, so set DE and IPR -+ */ -+ PRINTKD("UDC: short packet sent\n"); -+ wrint = NULL; -+ return UDCCS0_IPR | UDCCS0_DE; -+} -+ -+static unsigned int ep0_sh_write_data_then_empty_packet(void) -+{ -+ PRINTKD("UDC: last packet full. Send empty packet next\n"); -+ wrint = ep0_sh_write_with_empty_packet; -+ return 0; -+} -+ -+static void ep0_queue(void *buf, unsigned int len, unsigned int req_len) -+{ -+ __u32 cs_reg_bits = UDCCS0_IPR; -+ -+ PRINTKD("a=%d r=%d\n", len, req_len); -+ -+ if (len == 0) { -+ /* no output packet to wait for */ -+ PRINTKD("%s: zero byte packet being queued." -+ " Setting DE and OPR end exiting\n", __func__); -+ set_cs_bits(UDCCS0_DE | UDCCS0_SO); -+ return; -+ } -+ -+ /* -+ * thou shalt not enter data phase until -+ * Out Packet Ready is clear -+ */ -+ if (!clear_opr()) { -+ pr_err("UDC: SO did not clear OPR\n"); -+ set_cs_bits(UDCCS0_DE | UDCCS0_SO); -+ return; -+ } -+ -+ /* note data to xmit stored */ -+ wr.p = buf; -+ wr.bytes_left = min(len, req_len); -+ -+ /* write the first block */ -+ write_fifo(); -+ -+ /* done already? */ -+ if (wr.bytes_left == 0) { -+ /* -+ * out in one, so data end -+ */ -+ cs_reg_bits |= UDCCS0_DE; -+ ep0_clear_write(); -+ /* rest is a shorter than expected reply? */ -+ } else if (len < req_len) { -+ /* -+ * we are going to short-change host -+ * so need nul to not stall -+ */ -+ if (len % 8) { -+ PRINTKD("%s: %d more to go ending in a short packet.\n", -+ __func__, wr.bytes_left); -+ wrint = ep0_sh_write_with_empty_packet; -+ } -+ /* unless we are on a packet boundary. -+ * Then send full packet plus null packet. */ -+ else { -+ PRINTKD("%s: %d more to go then add empty packet.\n", -+ __func__, wr.bytes_left); -+ wrint = ep0_sh_write_data_then_empty_packet; -+ } -+ } else { -+ /* -+ * we have as much or more than requested -+ */ -+ PRINTKD("%s: %d more to go.\n", __func__, wr.bytes_left); -+ wrint = ep0_sh_write_data; -+ } -+ -+ /* -+ * note: IPR was set uncondtionally at start of routine -+ */ -+ set_cs_bits(cs_reg_bits); -+} -+ -+/* -+ * write_fifo() -+ * Stick bytes in the 8 bytes endpoint zero FIFO. -+ * This version uses a variety of tricks to make sure the bytes -+ * are written correctly. 1. The count register is checked to -+ * see if the byte went in, and the write is attempted again -+ * if not. 2. An overall counter is used to break out so we -+ * don't hang in those (rare) cases where the UDC reverses -+ * direction of the FIFO underneath us without notification -+ * (in response to host aborting a setup transaction early). -+ * -+ */ -+static void write_fifo(void) -+{ -+ int bytes_this_time = min(wr.bytes_left, 8); -+ int bytes_written = 0; -+ -+ PRINTKD("WF=%d: ", bytes_this_time); -+ -+ while (bytes_this_time--) { -+ unsigned int cwc; -+ int i; -+ PRINTKD("%2.2X ", *wr.p); -+ cwc = Ser0UDCWC & 15; -+ i = 10; -+ do { -+ Ser0UDCD0 = *wr.p; -+ udelay(20); /* voodo 28Feb01ww */ -+ } while ((Ser0UDCWC & 15) == cwc && --i); -+ -+ if (i == 0) { -+ pr_err("%swrite_fifo: write failure\n", pszMe); -+ usbd_info.stats.ep0_fifo_write_failures++; -+ } -+ -+ wr.p++; -+ bytes_written++; -+ } -+ wr.bytes_left -= bytes_written; -+ -+ /* following propagation voodo so maybe caller writing IPR in -+ ..a moment might actually get it to stick 28Feb01ww */ -+ udelay(300); -+ -+ usbd_info.stats.ep0_bytes_written += bytes_written; -+ PRINTKD("L=%d WCR=%8.8lX\n", wr.bytes_left, Ser0UDCWC); -+} -+/* -+ * read_fifo() -+ * Read 1-8 bytes out of FIFO and put in request. -+ * Called to do the initial read of setup requests -+ * from the host. Return number of bytes read. -+ * -+ * Like write fifo above, this driver uses multiple -+ * reads checked agains the count register with an -+ * overall timeout. -+ * -+ */ -+static int -+read_fifo(struct usb_ctrlrequest *request) -+{ -+ int bytes_read = 0; -+ int fifo_count; -+ -+ unsigned char *pOut = (unsigned char *) request; -+ -+ fifo_count = (Ser0UDCWC & 0xFF); -+ -+ ASSERT(fifo_count <= 8); -+ PRINTKD("RF=%d ", fifo_count); -+ -+ while (fifo_count--) { -+ unsigned int cwc; -+ int i; -+ -+ cwc = Ser0UDCWC & 15; -+ -+ i = 10; -+ do { -+ *pOut = (unsigned char) Ser0UDCD0; -+ udelay(20); -+ } while ((Ser0UDCWC & 15) == cwc && --i); -+ -+ if (i == 0) { -+ pr_err("%sread_fifo(): read failure\n", pszMe); -+ usbd_info.stats.ep0_fifo_read_failures++; -+ } -+ pOut++; -+ bytes_read++; -+ } -+ -+ PRINTKD("fc=%d\n", bytes_read); -+ usbd_info.stats.ep0_bytes_read++; -+ return bytes_read; -+} -+ -+/* some voodo I am adding, since the vanilla macros just aren't doing it -+ * 1Mar01ww */ -+ -+#define ABORT_BITS (UDCCS0_SST | UDCCS0_SE) -+#define OK_TO_WRITE (!(Ser0UDCCS0 & ABORT_BITS)) -+#define BOTH_BITS (UDCCS0_IPR | UDCCS0_DE) -+ -+static void set_cs_bits(__u32 bits) -+{ -+ if (bits & (UDCCS0_SO | UDCCS0_SSE | UDCCS0_FST | UDCCS0_SST)) -+ Ser0UDCCS0 = bits; -+ else if ((bits & BOTH_BITS) == BOTH_BITS) -+ set_ipr_and_de(); -+ else if (bits & UDCCS0_IPR) -+ set_ipr(); -+ else if (bits & UDCCS0_DE) -+ set_de(); -+} -+ -+static void set_de(void) -+{ -+ int i = 1; -+ while (1) { -+ if (OK_TO_WRITE) { -+ Ser0UDCCS0 |= UDCCS0_DE; -+ } else { -+ PRINTKD("%sQuitting set DE because SST or SE set\n", -+ pszMe); -+ break; -+ } -+ if (Ser0UDCCS0 & UDCCS0_DE) -+ break; -+ udelay(i); -+ if (++i == 50) { -+ pr_err("%sDangnabbbit! Cannot set DE!" -+ "(DE=%8.8X CCS0=%8.8lX)\n", pszMe, UDCCS0_DE, -+ Ser0UDCCS0); -+ break; -+ } -+ } -+} -+ -+static void set_ipr(void) -+{ -+ int i = 1; -+ while (1) { -+ if (OK_TO_WRITE) { -+ Ser0UDCCS0 |= UDCCS0_IPR; -+ } else { -+ PRINTKD("%sQuitting set IPR because SST or SE set\n", -+ pszMe); -+ break; -+ } -+ if (Ser0UDCCS0 & UDCCS0_IPR) -+ break; -+ udelay(i); -+ if (++i == 50) { -+ pr_err("%sDangnabbbit! Cannot set IPR!" -+ " (IPR=%8.8X CCS0=%8.8lX)\n", pszMe, -+ UDCCS0_IPR, Ser0UDCCS0); -+ break; -+ } -+ } -+} -+ -+static void set_ipr_and_de(void) -+{ -+ int i = 1; -+ while (1) { -+ if (OK_TO_WRITE) { -+ Ser0UDCCS0 |= BOTH_BITS; -+ } else { -+ PRINTKD("%sQuitting set IPR/DE because SST" -+ " or SE set\n", pszMe); -+ break; -+ } -+ if ((Ser0UDCCS0 & BOTH_BITS) == BOTH_BITS) -+ break; -+ udelay(i); -+ if (++i == 50) { -+ pr_err("%sDangnabbbit! Cannot set DE/IPR!" -+ " (DE=%8.8X IPR=%8.8X CCS0=%8.8lX)\n", pszMe, -+ UDCCS0_DE, UDCCS0_IPR, Ser0UDCCS0); -+ break; -+ } -+ } -+} -+ -+static bool clear_opr(void) -+{ -+ int i = 10000; -+ bool is_clear; -+ do { -+ Ser0UDCCS0 = UDCCS0_SO; -+ is_clear = !(Ser0UDCCS0 & UDCCS0_OPR); -+ if (i-- <= 0) { -+ pr_err("%sclear_opr(): failed\n", pszMe); -+ break; -+ } -+ } while (!is_clear); -+ return is_clear; -+} -+ -+ -+ -+/* ep1 handlers */ -+ -+static char *ep1_buf; -+static int ep1_len; -+static void (*ep1_callback)(int flag, int size); -+static char *ep1_curdmabuf; -+static dma_addr_t ep1_curdmapos; -+static int ep1_curdmalen; -+static int ep1_remain; -+static int ep1_used; -+ -+static dma_regs_t *dmaregs_rx; -+static int rx_pktsize; -+ -+static int naking; -+ -+static void -+ep1_start(void) -+{ -+ sa1100_reset_dma(dmaregs_rx); -+ if (!ep1_curdmalen) { -+ ep1_curdmalen = rx_pktsize; -+ if (ep1_curdmalen > ep1_remain) -+ ep1_curdmalen = ep1_remain; -+ ep1_curdmapos = dma_map_single(NULL, ep1_curdmabuf, -+ ep1_curdmalen, DMA_FROM_DEVICE); -+ } -+ -+ UDC_write(Ser0UDCOMP, ep1_curdmalen - 1); -+ -+ sa1100_start_dma(dmaregs_rx, ep1_curdmapos, ep1_curdmalen); -+ -+ if (naking) { -+ /* turn off NAK of OUT packets, if set */ -+ UDC_flip(Ser0UDCCS1, UDCCS1_RPC); -+ naking = 0; -+ } -+} -+ -+static void -+ep1_done(int flag) -+{ -+ int size = ep1_len - ep1_remain; -+ -+ if (!ep1_len) -+ return; -+ if (ep1_curdmalen) -+ dma_unmap_single(NULL, ep1_curdmapos, ep1_curdmalen, -+ DMA_FROM_DEVICE); -+ ep1_len = ep1_curdmalen = 0; -+ if (ep1_callback) -+ ep1_callback(flag, size); -+} -+ -+void -+ep1_state_change_notify(int new_state) -+{ -+ -+} -+ -+void -+ep1_stall(void) -+{ -+ /* SET_FEATURE force stall at UDC */ -+ UDC_set(Ser0UDCCS1, UDCCS1_FST); -+} -+ -+int -+ep1_init(dma_regs_t *dmaregs) -+{ -+ dmaregs_rx = dmaregs; -+ sa1100_reset_dma(dmaregs_rx); -+ ep1_done(-EAGAIN); -+ return 0; -+} -+ -+void -+ep1_reset(void) -+{ -+ if (dmaregs_rx) -+ sa1100_reset_dma(dmaregs_rx); -+ UDC_clear(Ser0UDCCS1, UDCCS1_FST); -+ ep1_done(-EINTR); -+} -+ -+void ep1_int_hndlr(int udcsr) -+{ -+ dma_addr_t dma_addr; -+ unsigned int len; -+ int status = Ser0UDCCS1; -+ -+ if (naking) -+ pr_err("%sEh? in ISR but naking = %d\n", "usbrx: ", naking); -+ -+ if (status & UDCCS1_RPC) { -+ if (!ep1_curdmalen) { -+ pr_err("usb_recv: RPC for non-existent buffer\n"); -+ naking = 1; -+ return; -+ } -+ -+ sa1100_stop_dma(dmaregs_rx); -+ -+ if (status & UDCCS1_SST) { -+ pr_err("usb_recv: stall sent OMP=%ld\n", Ser0UDCOMP); -+ UDC_flip(Ser0UDCCS1, UDCCS1_SST); -+ ep1_done(-EIO); /* UDC aborted current transfer, so we do */ -+ return; -+ } -+ -+ if (status & UDCCS1_RPE) { -+ pr_err("usb_recv: RPError %x\n", status); -+ UDC_flip(Ser0UDCCS1, UDCCS1_RPC); -+ ep1_done(-EIO); -+ return; -+ } -+ -+ dma_addr = sa1100_get_dma_pos(dmaregs_rx); -+ dma_unmap_single(NULL, ep1_curdmapos, ep1_curdmalen, DMA_FROM_DEVICE); -+ len = dma_addr - ep1_curdmapos; -+#ifdef SA1100_USB_DEBUG -+ if (sa1100_usb_debug) { -+ int i; -+ pr_err("usb rx %d :\n ", len); -+ if (sa1100_usb_debug > 1) { -+ for (i = 0; i < len; i++) { -+ if ((i % 32) == 31) -+ pr_err("\n "); -+ pr_err("%2.2x ", ((char *)ep1_curdmapos)[i]); -+ } -+ } -+ pr_err("\n"); -+ } -+#endif -+ if (len < ep1_curdmalen) { -+ char *buf = ep1_curdmabuf + len; -+ while (Ser0UDCCS1 & UDCCS1_RNE) { -+ if (len >= ep1_curdmalen) { -+ pr_err("usb_recv: too much data in fifo\n"); -+ break; -+ } -+ *buf++ = Ser0UDCDR; -+ len++; -+ } -+ } else if (Ser0UDCCS1 & UDCCS1_RNE) { -+ pr_err("usb_recv: fifo screwed, shouldn't contain data\n"); -+ len = 0; -+ } -+ -+#if defined(NCB_DMA_FIX) -+/* if (len && (ep1_buf != ep1_curdmabuf)) -+ memcpy(ep1_buf,ep1_curdmabuf,len); */ -+ if (len) -+ memcpy(&(((unsigned char *)ep1_buf)[ep1_used]), -+ ep1_curdmabuf, len); -+#endif -+ -+ ep1_curdmalen = 0; /* dma unmap already done */ -+ ep1_remain -= len; -+ ep1_used += len; -+/* ep1_curdmabuf += len; // use same buffer again */ -+ naking = 1; -+/* printk("%s: received %d, %d remaining\n",__func__,len,ep1_remain); */ -+ if (len && (len == rx_pktsize)) -+ ep1_start(); -+ else -+ ep1_done((len) ? 0 : -EPIPE); -+ } -+ /* else, you can get here if we are holding NAK */ -+} -+ -+int -+sa1100_usb_recv(struct usb_request *req, void (*callback)(int flag, int size)) -+{ -+ unsigned long flags; -+ char *buf = req->buf; -+ int len = req->length; -+ -+ if (ep1_len) -+ return -EBUSY; -+ -+ local_irq_save(flags); -+ ep1_buf = buf; -+ ep1_len = len; -+ ep1_callback = callback; -+ ep1_remain = len; -+ ep1_used = 0; -+#ifdef NCB_DMA_FIX -+/* if (((size_t)buf)&3) */ -+ if (1) -+ ep1_curdmabuf = receive_buffer; -+ else -+#else -+ ep1_curdmabuf = buf; -+#endif -+ ep1_curdmalen = 0; -+ ep1_start(); -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+/* ep2 handlers */ -+ -+static char *ep2_buf; -+static int ep2_len; -+static void (*ep2_callback)(int status, int size); -+static dma_addr_t ep2_dma; -+static dma_addr_t ep2_curdmapos; -+static int ep2_curdmalen; -+static int ep2_remain; -+static dma_regs_t *dmaregs_tx; -+static int tx_pktsize; -+ -+/* device state is changing, async */ -+void -+ep2_state_change_notify(int new_state) -+{ -+} -+ -+/* set feature stall executing, async */ -+void -+ep2_stall(void) -+{ -+ UDC_set(Ser0UDCCS2, UDCCS2_FST); /* force stall at UDC */ -+} -+ -+static void -+ep2_start(void) -+{ -+ if (!ep2_len) -+ return; -+ -+ ep2_curdmalen = tx_pktsize; -+ if (ep2_curdmalen > ep2_remain) -+ ep2_curdmalen = ep2_remain; -+ -+ /* must do this _before_ queue buffer.. */ -+ UDC_flip(Ser0UDCCS2, UDCCS2_TPC); /* stop NAKing IN tokens */ -+ UDC_write(Ser0UDCIMP, ep2_curdmalen - 1); -+ -+ Ser0UDCAR = usbd_info.address; /* fighting stupid silicon bug */ -+ sa1100_start_dma(dmaregs_tx, ep2_curdmapos, ep2_curdmalen); -+} -+ -+static void -+ep2_done(int flag) -+{ -+ int size = ep2_len - ep2_remain; -+ if (ep2_len) { -+ dma_unmap_single(NULL, ep2_dma, ep2_len, DMA_TO_DEVICE); -+ ep2_len = 0; -+ if (ep2_callback) -+ ep2_callback(flag, size); -+ } -+} -+ -+int ep2_init(dma_regs_t *dmaregs) -+{ -+ dmaregs_tx = dmaregs; -+ sa1100_reset_dma(dmaregs_tx); -+ ep2_done(-EAGAIN); -+ return 0; -+} -+ -+void ep2_reset(void) -+{ -+ UDC_clear(Ser0UDCCS2, UDCCS2_FST); -+ if (dmaregs_tx) -+ sa1100_reset_dma(dmaregs_tx); -+ ep2_done(-EINTR); -+} -+ -+void ep2_int_hndlr(int udcsr) -+{ -+ int status = Ser0UDCCS2; -+ -+ if (Ser0UDCAR != usbd_info.address) /* check for stupid silicon bug. */ -+ Ser0UDCAR = usbd_info.address; -+ -+ if (status & UDCCS2_TPC) { -+ UDC_flip(Ser0UDCCS2, UDCCS2_SST); -+ -+ sa1100_reset_dma(dmaregs_tx); -+ -+ if (status & (UDCCS2_TPE | UDCCS2_TUR)) { -+ pr_err("usb_send: transmit error %x\n", status); -+ ep2_done(-EIO); -+ } else { -+ ep2_curdmapos += ep2_curdmalen; -+ ep2_remain -= ep2_curdmalen; -+ -+ if (ep2_remain != 0) -+ ep2_start(); -+ else -+ ep2_done(0); -+ } -+ } else { -+ pr_err("usb_send: Not TPC: UDCCS2 = %x\n", status); -+ } -+} -+ -+int -+sa1100_usb_send(struct usb_request *req, void (*callback)(int status, int size)) -+{ -+ char *buf = req->buf; -+ int len = req->length; -+ unsigned long flags; -+ -+ if (usbd_info.state != USB_STATE_CONFIGURED) { -+ PRINTKD("%s: return -ENODEV\n", __func__); -+ return -ENODEV; -+ } -+ -+ if (ep2_len) { -+ PRINTKD("%s: return -EBUSY\n", __func__); -+ return -EBUSY; -+ } -+ -+ local_irq_save(flags); -+#ifdef NCB_DMA_FIX -+/* if misaligned, copy to aligned buffer */ -+/* if (((size_t)buf)&3) { */ -+ if (1) { -+ PRINTKD("%s: copying %d bytes to send_buffer\n", __func__, len); -+ memcpy(send_buffer, buf, len); -+ ep2_buf = send_buffer; -+ } else -+#endif -+ ep2_buf = buf; -+ -+ ep2_len = len; -+ ep2_dma = dma_map_single(NULL, ep2_buf, len, DMA_TO_DEVICE); -+ PRINTKD("%s: mapped dma to buffer(%p0\n", __func__, buf); -+ -+ ep2_callback = callback; -+ ep2_remain = len; -+ ep2_curdmapos = ep2_dma; -+ -+ PRINTKD("%s: calling ep2_start\n", __func__); -+ ep2_start(); -+ local_irq_restore(flags); -+ -+ return 0; -+} -+/*-------------------------------------------------------------------------*/ -+ -+static int -+sa1100_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) -+{ -+ struct sa1100_udc *dev; -+ struct sa1100_ep *ep; -+ u32 max; -+ int type; -+ -+ ep = container_of(_ep, struct sa1100_ep, ep); -+ if (!_ep || !desc || ep->desc || _ep->name == ep0name -+ || desc->bDescriptorType != USB_DT_ENDPOINT) { -+ PRINTKD("%s: _ep = %p, desc = %p\n", __func__, _ep, desc); -+ if (_ep && desc) -+ PRINTKD("%s: ep->desc = %p, _ep->name = %s" -+ "desc->bDescriptorType = %s\n", __func__, ep->desc, -+ _ep->name, (desc->bDescriptorType == USB_DT_ENDPOINT) \ -+ ? "USB_DT_ENDPOINT" : "bad!!"); -+ return -EINVAL; -+ } -+ -+ dev = ep->dev; -+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) -+ return -ESHUTDOWN; -+ -+ type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -+ max = le16_to_cpu(desc->wMaxPacketSize); -+ switch (max) { -+ case 64: case 32: -+ /* note: maxpacket > 16 means DMA might overrun/underrun */ -+ case 16: case 8: -+ break; -+ default: -+ if (type == USB_ENDPOINT_XFER_INT && max < 64) -+ break; -+ return -EDOM; -+ } -+ -+ switch (type) { -+ case USB_ENDPOINT_XFER_BULK: -+ case USB_ENDPOINT_XFER_INT: -+ if (ep == &dev->ep[2]) { -+ if (desc->bEndpointAddress != (USB_DIR_IN|2)) { -+ PRINTKD("%s: ep[2] has invalid endpoint\n", -+ __func__); -+ return -EINVAL; -+ } -+ tx_pktsize = max; -+ Ser0UDCOMP = max - 1; -+ PRINTKD("%s: ep2 max packet size is %d\n", __func__, -+ max); -+ break; -+ } else if (ep == &dev->ep[1]) { -+ if (desc->bEndpointAddress != (USB_DIR_OUT|1)) { -+ PRINTKD("%s: ep[1] has invalid endpoint\n", -+ __func__); -+ return -EINVAL; -+ } -+ rx_pktsize = max; -+ Ser0UDCIMP = max - 1; -+ PRINTKD("%s: ep1 max packet size is %d\n", __func__, -+ max); -+ break; -+ } -+ /* FALLTHROUGH */ -+ default: -+ PRINTKD("%s: Invalid endpoint\n", __func__); -+ return -EINVAL; -+ } -+ -+ _ep->maxpacket = max; -+ ep->desc = desc; -+ ep->stopped = 0; -+ -+ DEBUG(dev, "enabled %s %s max %04x\n", _ep->name, -+ type_string(desc->bmAttributes), max); -+ -+ return 0; -+} -+ -+static int sa1100_disable(struct usb_ep *_ep) -+{ -+ struct sa1100_ep *ep; -+ -+ ep = container_of(_ep, struct sa1100_ep, ep); -+ if (!_ep || !ep->desc || _ep->name == ep0name) -+ return -EINVAL; -+ -+ nuke(ep, -ESHUTDOWN); -+ -+ DEBUG(ep->dev, "disabled %s\n", _ep->name); -+ -+ ep->desc = NULL; -+ ep->stopped = 1; -+ return 0; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static struct usb_request * -+sa1100_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -+{ -+ struct sa1100_request *req; -+ -+ if (!_ep) -+ return NULL; -+ -+ req = kzalloc(sizeof *req, gfp_flags); -+ if (!req) -+ return NULL; -+ -+ req->req.dma = DMA_ADDR_INVALID; -+ INIT_LIST_HEAD(&req->queue); -+ return &req->req; -+} -+ -+static void sa1100_free_request(struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct sa1100_request *req; -+ -+ req = container_of(_req, struct sa1100_request, req); -+ WARN_ON(!list_empty(&req->queue)); -+ kfree(req); /* NCB - see pxa2xx_udc */ -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void done(struct sa1100_ep *ep, struct sa1100_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) -+ VDEBUG(ep->dev, "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; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* FIXME move away from the old non-queued api. -+ * - forces extra work on us -+ * - stores request state twice -+ * - doesn't let gadget driver handle dma mapping -+ * - status codes need mapping -+ */ -+ -+static int map_status(int status) -+{ -+ switch (status) { -+ case 0: -+ case -EIO: /* ep[12]_int_handler */ -+ return status; -+ case -EPIPE: /* ep1_int_handler */ -+ return 0; -+ /* case -EAGAIN: *//* ep[12]_init */ -+ /* case -EINTR: *//* ep[12]_reset */ -+ default: -+ return -ESHUTDOWN; -+ } -+} -+ -+static void tx_callback(int status, int size) -+{ -+ struct sa1100_ep *ep = &the_controller->ep[2]; -+ struct sa1100_request *req; -+ -+ if (list_empty(&ep->queue)) { -+ if (status != -EAGAIN) -+ DEBUG(ep->dev, "%s, bogus tx callback %d/%d\n", -+ ep->ep.name, status, size); -+ return; -+ } -+ req = list_entry(ep->queue.next, struct sa1100_request, queue); -+ req->req.actual = size; -+ done(ep, req, map_status(status)); -+ -+ if (ep->stopped || list_empty(&ep->queue)) -+ return; -+ req = list_entry(ep->queue.next, struct sa1100_request, queue); -+ sa1100_usb_send(&req->req, tx_callback); -+} -+ -+static void rx_callback(int status, int size) -+{ -+ struct sa1100_ep *ep = &the_controller->ep[1]; -+ struct sa1100_request *req; -+ -+ if (list_empty(&ep->queue)) { -+ if (status != -EAGAIN) -+ DEBUG(ep->dev, "%s, bogus tx callback %d/%d\n", -+ ep->ep.name, status, size); -+ return; -+ } -+ req = list_entry(ep->queue.next, struct sa1100_request, queue); -+ req->req.actual = size; -+ done(ep, req, map_status(status)); -+ -+ if (ep->stopped || list_empty(&ep->queue)) -+ return; -+ req = list_entry(ep->queue.next, struct sa1100_request, queue); -+ sa1100_usb_recv(&req->req, rx_callback); -+} -+ -+ -+static int -+sa1100_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -+{ -+ struct sa1100_request *req; -+ struct sa1100_ep *ep; -+ struct sa1100_udc *dev; -+ unsigned long flags; -+ -+ req = container_of(_req, struct sa1100_request, req); -+ if (!_req || !_req->complete || !_req->buf -+ || !list_empty(&req->queue)) -+ return -EINVAL; -+ -+ ep = container_of(_ep, struct sa1100_ep, ep); -+ if (unlikely(!_ep || (!ep->desc && _ep->name != ep0name))) -+ return -EINVAL; -+ -+ dev = ep->dev; -+ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) -+ return -ESHUTDOWN; -+ -+ /* handle ep0 */ -+ if (_ep->name == ep0name) { -+ ep0_queue(_req->buf, _req->length, dev->ep0_req_len >= 0 ? \ -+ dev->ep0_req_len : _req->length); -+ return 0; -+ } -+ -+ /* sa1100 udc can't write zlps */ -+ if (ep == &dev->ep[2] && _req->length == 0) -+ return -ERANGE; -+ -+ /* the old sa1100 api doesn't use 'unsigned' for lengths */ -+ if (_req->length > INT_MAX) -+ return -ERANGE; -+ -+ VDEBUG(dev, "%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; -+ -+ if (list_empty(&ep->queue) && !ep->stopped) { -+ /* FIXME this does DMA mapping wrong. caller is allowed -+ * to provide buffers that don't need mapping, but this -+ * doesn't use them. -+ */ -+ if (ep == &ep->dev->ep[2]) { -+ PRINTKD("%s: sa1100_usb_send buf %p length %d\n", -+ __func__, _req->buf, _req->length); -+ sa1100_usb_send(_req, tx_callback); -+ } else if (ep == &ep->dev->ep[1]) { -+ PRINTKD("%s: sa1100_usb_recv buf %p length %d\n", -+ __func__, _req->buf, _req->length); -+ sa1100_usb_recv(_req, rx_callback); -+ } -+ /* ep0 rx/tx is handled separately */ -+ } -+ list_add_tail(&req->queue, &ep->queue); -+ -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+/* dequeue ALL requests */ -+static void nuke(struct sa1100_ep *ep, int status) -+{ -+ struct sa1100_request *req; -+ -+ /* called with irqs blocked */ -+ while (!list_empty(&ep->queue)) { -+ req = list_entry(ep->queue.next, -+ struct sa1100_request, -+ queue); -+ done(ep, req, status); -+ } -+ if (ep == &ep->dev->ep[1]) -+ ep1_reset(); -+ else if (ep == &ep->dev->ep[2]) -+ ep2_reset(); -+} -+ -+/* dequeue JUST ONE request */ -+static int sa1100_dequeue(struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct sa1100_ep *ep; -+ struct sa1100_request *req; -+ unsigned long flags; -+ -+ ep = container_of(_ep, struct sa1100_ep, ep); -+ if (!_ep || (!ep->desc && _ep->name != ep0name) || !_req) -+ 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; -+ } -+ -+ done(ep, req, -ECONNRESET); -+ -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int -+sa1100_set_halt(struct usb_ep *_ep, int value) -+{ -+ struct sa1100_ep *ep; -+ -+ ep = container_of(_ep, struct sa1100_ep, ep); -+ if (unlikely(!_ep -+ || (!ep->desc && _ep->name != ep0name)) -+ || (ep->desc->bmAttributes & 0x03) == USB_ENDPOINT_XFER_ISOC) -+ return -EINVAL; -+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) -+ return -ESHUTDOWN; -+ -+ 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 == &ep->dev->ep[1]) -+ ep1_stall(); -+ else -+ ep2_stall(); -+ } else { -+ if (ep == &ep->dev->ep[1]) -+ ep1_reset(); -+ else -+ ep2_reset(); -+ } -+ -+ return 0; -+} -+ -+static struct usb_ep_ops sa1100_ep_ops = { -+ .enable = sa1100_enable, -+ .disable = sa1100_disable, -+ -+ .alloc_request = sa1100_alloc_request, -+ .free_request = sa1100_free_request, -+ -+ .queue = sa1100_queue, -+ .dequeue = sa1100_dequeue, -+ -+ .set_halt = sa1100_set_halt, -+ /* .fifo_status = sa1100_fifo_status, */ -+ /* .fifo_flush = sa1100_fifo_flush, */ -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int sa1100_get_frame(struct usb_gadget *_gadget) -+{ -+ return -EOPNOTSUPP; -+} -+ -+static int sa1100_wakeup(struct usb_gadget *_gadget) -+{ -+ struct sa1100_udc *dev; -+ -+ if (!_gadget) -+ return 0; -+ dev = container_of(_gadget, struct sa1100_udc, gadget); -+ -+ /* FIXME */ -+ -+ return 0; -+} -+ -+static const struct usb_gadget_ops sa1100_ops = { -+ .get_frame = sa1100_get_frame, -+ .wakeup = sa1100_wakeup, -+ -+ /* .set_selfpowered = sa1100_set_selfpowered, */ -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+static inline void enable_resume_mask_suspend(void) -+{ -+ int i = 0; -+ -+ while (1) { -+ Ser0UDCCR |= UDCCR_SUSIM; /* mask future suspend events */ -+ udelay(i); -+ if ((Ser0UDCCR & UDCCR_SUSIM) || (Ser0UDCSR & UDCSR_RSTIR)) -+ break; -+ if (++i == 50) { -+ WARNING(&the_controller, -+ "%s Could not set SUSIM %8.8lX\n", __func__, -+ Ser0UDCCR); -+ break; -+ } -+ } -+ -+ i = 0; -+ while (1) { -+ Ser0UDCCR &= ~UDCCR_RESIM; -+ udelay(i); -+ if ((Ser0UDCCR & UDCCR_RESIM) == 0 -+ || (Ser0UDCSR & UDCSR_RSTIR)) -+ break; -+ if (++i == 50) { -+ WARNING(&the_controller, -+ "%s Could not clear RESIM %8.8lX\n", -+ __func__, Ser0UDCCR); -+ break; -+ } -+ } -+} -+ -+static inline void enable_suspend_mask_resume(void) -+{ -+ int i = 0; -+ while (1) { -+ Ser0UDCCR |= UDCCR_RESIM; /* mask future resume events */ -+ udelay(i); -+ if (Ser0UDCCR & UDCCR_RESIM || (Ser0UDCSR & UDCSR_RSTIR)) -+ break; -+ if (++i == 50) { -+ WARNING(&the_controller, -+ "%s could not set RESIM %8.8lX\n", -+ __func__, Ser0UDCCR); -+ break; -+ } -+ } -+ i = 0; -+ while (1) { -+ Ser0UDCCR &= ~UDCCR_SUSIM; -+ udelay(i); -+ if ((Ser0UDCCR & UDCCR_SUSIM) == 0 -+ || (Ser0UDCSR & UDCSR_RSTIR)) -+ break; -+ if (++i == 50) { -+ WARNING(&the_controller, -+ "%s Could not clear SUSIM %8.8lX\n", -+ __func__, Ser0UDCCR); -+ break; -+ } -+ } -+} -+ -+/* HACK DEBUG 3Mar01ww -+ * Well, maybe not, it really seems to help! 08Mar01ww -+ */ -+static void core_kicker(void) -+{ -+ u32 car = Ser0UDCAR; -+ u32 imp = Ser0UDCIMP; -+ u32 omp = Ser0UDCOMP; -+ -+ UDC_set(Ser0UDCCR, UDCCR_UDD); -+ udelay(300); -+ UDC_clear(Ser0UDCCR, UDCCR_UDD); -+ -+ Ser0UDCAR = car; -+ Ser0UDCIMP = imp; -+ Ser0UDCOMP = omp; -+} -+ -+static irqreturn_t udc_int_hndlr(int irq, void *_dev) -+{ -+ struct sa1100_udc *dev = _dev; -+ u32 status = Ser0UDCSR; -+ -+ PRINTKD("%s: status = 0x%x and control = 0x%lx\n", __func__, -+ status, Ser0UDCCR); -+ /* ReSeT Interrupt Request - UDC has been reset */ -+ if (status & UDCSR_RSTIR) { -+ PRINTKD("%s: processing UDCSR_RSTIR\n", __func__); -+ if (usbctl_next_state_on_event(kEvReset) != kError) { -+ /* starting 20ms or so reset sequence now... */ -+ INFO(dev, "Resetting\n"); -+ ep0_reset(); /* just set state to idle */ -+ ep1_reset(); /* flush dma, clear false stall */ -+ ep2_reset(); /* flush dma, clear false stall */ -+ } -+ /* mask reset ints, they flood during sequence, enable -+ * suspend and resume */ -+ UDC_set(Ser0UDCCR, UDCCR_REM); /* mask reset */ -+ /*enable suspend and resume */ -+ UDC_clear(Ser0UDCCR, (UDCCR_SUSIM | UDCCR_RESIM)); -+ UDC_flip(Ser0UDCSR, status); /* clear all pending sources */ -+ PRINTKD("%s: setting USB_FULL_SPEED\n", __func__); -+ dev->gadget.speed = USB_SPEED_FULL; -+ return IRQ_HANDLED; /* NCB */ -+ } -+ -+ /* else we have done something other than reset, -+ * so be sure reset enabled */ -+ UDC_clear(Ser0UDCCR, UDCCR_REM); -+ -+ /* RESume Interrupt Request */ -+ if (status & UDCSR_RESIR) { -+ struct usb_gadget_driver *driver = dev->driver; -+ -+ PRINTKD("%s: processing UDCSR_RESIR\n", __func__); -+ if (driver->resume) -+ driver->resume(&dev->gadget); -+ core_kicker(); -+ enable_suspend_mask_resume(); -+ } -+ -+ /* SUSpend Interrupt Request */ -+ if (status & UDCSR_SUSIR) { -+ struct usb_gadget_driver *driver = dev->driver; -+ -+ PRINTKD("%s: processing UDCSR_SUSIR\n", __func__); -+ if (driver->suspend) -+ driver->suspend(&dev->gadget); -+ enable_resume_mask_suspend(); -+ } -+ -+ UDC_flip(Ser0UDCSR, status); /* clear all pending sources */ -+ -+ if (status & UDCSR_EIR) -+ PRINTKD("%s: processing ep0_int_hndlr\n", __func__); -+ ep0_int_hndlr(); -+ -+ if (status & UDCSR_RIR) { -+ PRINTKD("%s: processing ep1_int_hndlr\n", __func__); -+ ep1_int_hndlr(status); -+ } -+ if (status & UDCSR_TIR) { -+ PRINTKD("%s: processing ep2_int_hndlr\n", __func__); -+ ep2_int_hndlr(status); -+ } -+ -+ return IRQ_HANDLED; /* NCB */ -+} -+ -+ -+/* FIXME-MAD - we need to pass soft_connect_hook via platform_data */ -+ -+/* soft_connect_hook () -+ * Some devices have platform-specific circuitry to make USB -+ * not seem to be plugged in, even when it is. This allows -+ * software to control when a device 'appears' on the USB bus -+ * (after Linux has booted and this driver has loaded, for -+ * example). If you have such a circuit, control it here. -+ */ -+#define soft_connect_hook(x) do { } while (0); -+ -+ -+ -+/* "function" sysfs attribute */ -+static ssize_t -+show_function(struct device *_dev, struct device_attribute *attr, char *buf) -+{ -+ struct sa1100_udc *dev = dev_get_drvdata(_dev); -+ -+ if (!dev->driver -+ || !dev->driver->function -+ || strlen(dev->driver->function) > PAGE_SIZE) -+ return 0; -+ return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function); -+} -+static DEVICE_ATTR(function, S_IRUGO, show_function, NULL); -+ -+/* disable the UDC at the source */ -+static void udc_disable(struct sa1100_udc *dev) -+{ -+ soft_connect_hook(0); -+ UDC_set(Ser0UDCCR, UDCCR_UDD); -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+ ep0_idle(dev); -+} -+ -+static void udc_reinit(struct sa1100_udc *dev) -+{ -+ u32 i; -+ -+ /* Initialize the gadget controller data structure */ -+ INIT_LIST_HEAD(&dev->gadget.ep_list); -+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); -+ ep0_idle(dev); -+ for (i = 0 ; i < 3 ; i++) { -+ struct sa1100_ep *ep = &dev->ep[i]; -+ if (i != 0) -+ list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); -+ ep->desc = NULL; -+ ep->stopped = 0; -+ INIT_LIST_HEAD(&ep->queue); -+ } -+} -+ -+/* enable the udc at the source */ -+static void udc_enable(struct sa1100_udc *dev) -+{ -+ UDC_clear(Ser0UDCCR, UDCCR_UDD); -+ ep0_idle(dev); -+} -+ -+static void ep0_start(struct sa1100_udc *dev) -+{ -+ udc_enable(dev); -+ udelay(100); -+ -+ /* clear stall - receiver seems to start stalled? 19Jan01ww */ -+ /* also clear other stuff just to be thurough 22Feb01ww */ -+ UDC_clear(Ser0UDCCS1, UDCCS1_FST | UDCCS1_RPE | UDCCS1_RPC); -+ UDC_clear(Ser0UDCCS2, UDCCS2_FST | UDCCS2_TPE | UDCCS2_TPC); -+ -+ /* mask everything */ -+ Ser0UDCCR = 0xFC; -+ -+ /* flush DMA and fire through some -EAGAINs */ -+ ep1_init(dev->ep[1].dmaregs); -+ ep2_init(dev->ep[2].dmaregs); -+ -+ /* enable any platform specific hardware */ -+ soft_connect_hook(1); -+ -+ /* clear all top-level sources */ -+ Ser0UDCSR = UDCSR_RSTIR | UDCSR_RESIR | UDCSR_EIR | -+ UDCSR_RIR | UDCSR_TIR | UDCSR_SUSIR ; -+ -+ /* EXERIMENT - a short line in the spec says toggling this -+ * bit diddles the internal state machine in the udc to -+ * expect a suspend -+ */ -+ Ser0UDCCR |= UDCCR_RESIM; -+ /* END EXPERIMENT 10Feb01ww */ -+ -+ /* enable any platform specific hardware */ -+ soft_connect_hook(1); -+ -+ /* Enable interrupts. If you are unplugged you will immediately -+ * get a suspend interrupt. If you are plugged and have a soft -+ * connect-circuit, you will get a reset. If you are plugged -+ * without a soft-connect, I think you also get suspend. In short, -+ * start with suspend masked and everything else enabled -+ */ -+ UDC_write(Ser0UDCCR, UDCCR_SUSIM); -+} -+ -+ -+/* when a driver is successfully registered, it will receive -+ * control requests including set_configuration(), which enables -+ * non-control requests. then usb traffic follows until a -+ * disconnect is reported. then a host may connect again, or -+ * the driver might get unbound. -+ */ -+int usb_gadget_register_driver(struct usb_gadget_driver *driver) -+{ -+ struct sa1100_udc *dev = the_controller; -+ int retval; -+ -+ if (!driver || !driver->bind || !driver->setup) -+ return -EINVAL; -+ if (!dev) -+ return -ENODEV; -+ if (dev->driver) -+ return -EBUSY; -+ -+ /* hook up the driver ... */ -+ dev->driver = driver; -+ dev->gadget.dev.driver = &driver->driver; -+ -+ retval = device_add(&dev->gadget.dev); -+ if (retval != 0) { -+ printk(KERN_ERR "Error in device_add() : %d\n", retval); -+ goto register_error; -+ } -+ -+ retval = driver->bind(&dev->gadget); -+ if (retval != 0) { -+ DEBUG(dev, "bind to driver %s --> %d\n", -+ driver->driver.name, retval); -+ device_del(&dev->gadget.dev); -+ goto register_error; -+ } -+ -+ retval = device_create_file(dev->dev, &dev_attr_function); -+ -+ /* ... then enable host detection and ep0; and we're ready -+ * for set_configuration as well as eventual disconnect. -+ */ -+ ep0_start(dev); -+ -+ DEBUG(dev, "%s ready\n", driver->driver.name); -+ -+ return 0; -+ -+register_error: -+ dev->driver = NULL; -+ dev->gadget.dev.driver = NULL; -+ return retval; -+} -+EXPORT_SYMBOL(usb_gadget_register_driver); -+ -+static void -+stop_activity(struct sa1100_udc *dev, struct usb_gadget_driver *driver) -+{ -+ int i; -+ -+ /* don't disconnect if it's not connected */ -+ if (dev->gadget.speed == USB_SPEED_UNKNOWN) -+ driver = NULL; -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+ -+ /* mask everything */ -+ Ser0UDCCR = 0xFC; -+ -+ /* stop hardware; prevent new request submissions; -+ * and kill any outstanding requests. -+ */ -+ for (i = 0; i < 3; i++) { -+ struct sa1100_ep *ep = &dev->ep[i]; -+ ep->stopped = 1; -+ nuke(ep, -ESHUTDOWN); -+ } -+ udc_disable(dev); -+ -+ /* report disconnect; the driver is already quiesced */ -+ if (driver) -+ driver->disconnect(&dev->gadget); -+ -+ /* re-init driver-visible data structures */ -+ udc_reinit(dev); -+} -+ -+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -+{ -+ struct sa1100_udc *dev = the_controller; -+ -+ if (!dev) -+ return -ENODEV; -+ if (!driver || driver != dev->driver) -+ return -EINVAL; -+ -+ local_irq_disable(); -+ stop_activity(dev, driver); -+ local_irq_enable(); -+ if (driver->unbind) -+ driver->unbind(&dev->gadget); -+ dev->driver = 0; -+ -+ device_del(&dev->gadget.dev); -+ device_remove_file(dev->dev, &dev_attr_function); -+ -+ DEBUG(dev, "unregistered driver '%s'\n", driver->driver.name); -+ return 0; -+} -+EXPORT_SYMBOL(usb_gadget_unregister_driver); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/*-------------------------------------------------------------------------*/ -+ -+/* Proc Filesystem Support */ -+ -+#if CONFIG_PROC_FS -+ -+#define SAY(fmt, args...) do { p += sprintf(p, fmt, ## args); } while (0) -+#define SAYV(num) do { p += sprintf(p, num_fmt, "Value", num); } while (0) -+#define SAYC(label, yn) do { p += sprintf(p, yn_fmt, label, yn); } while (0) -+#define SAYS(label, v) do { p += sprintf(p, cnt_fmt, label, v); } while (0) -+ -+static int usbctl_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ const char *num_fmt = "%25.25s: %8.8lX\n"; -+ const char *cnt_fmt = "%25.25s: %lu\n"; -+ const char *yn_fmt = "%25.25s: %s\n"; -+ const char *yes = "YES"; -+ const char *no = "NO"; -+ unsigned long v; -+ char *p = page; -+ int len; -+ -+ SAY("SA1100 USB Controller Core\n"); -+ -+ SAYS("ep0 bytes read", usbd_info.stats.ep0_bytes_read); -+ SAYS("ep0 bytes written", usbd_info.stats.ep0_bytes_written); -+ SAYS("ep0 FIFO read failures", usbd_info.stats.ep0_fifo_read_failures); -+ SAYS("ep0 FIFO write failures", -+ usbd_info.stats.ep0_fifo_write_failures); -+ -+ SAY("\n"); -+ -+ v = Ser0UDCAR; -+ SAY("%25.25s: 0x%8.8lX - %ld\n", "Address Register", v, v); -+ v = Ser0UDCIMP; -+ SAY("%25.25s: %ld (%8.8lX)\n", "IN max packet size", v+1, v); -+ v = Ser0UDCOMP; -+ SAY("%25.25s: %ld (%8.8lX)\n", "OUT max packet size", v+1, v); -+ -+ v = Ser0UDCCR; -+ SAY("\nUDC Mask Register\n"); -+ SAYV(v); -+ SAYC("UDC Active", (v & UDCCR_UDA) ? yes : no); -+ SAYC("Suspend interrupts masked", (v & UDCCR_SUSIM) ? yes : no); -+ SAYC("Resume interrupts masked", (v & UDCCR_RESIM) ? yes : no); -+ SAYC("Reset interrupts masked", (v & UDCCR_REM) ? yes : no); -+ -+ v = Ser0UDCSR; -+ SAY("\nUDC Interrupt Request Register\n"); -+ SAYV(v); -+ SAYC("Reset pending", (v & UDCSR_RSTIR) ? yes : no); -+ SAYC("Suspend pending", (v & UDCSR_SUSIR) ? yes : no); -+ SAYC("Resume pending", (v & UDCSR_RESIR) ? yes : no); -+ SAYC("ep0 pending", (v & UDCSR_EIR) ? yes : no); -+ SAYC("receiver pending", (v & UDCSR_RIR) ? yes : no); -+ SAYC("tramsitter pending", (v & UDCSR_TIR) ? yes : no); -+ -+#if 1 -+ SAY("\nDMA Tx registers\n"); -+ { -+ dma_regs_t *r = the_controller->ep[2].dmaregs; -+ SAY(" DDAR"); -+ SAYV(r->DDAR); -+ SAY(" DCSR"); -+ SAYV(r->RdDCSR); -+ SAY(" DBSA (address buf A) "); -+ SAYV(r->DBSA); -+ SAY(" DBTA (transfer count A) "); -+ SAYV(r->DBTA); -+ SAY(" DBSB (address buf B) "); -+ SAYV(r->DBSB); -+ SAY(" DBTB (transfer count B) "); -+ SAYV(r->DBTB); -+ -+ } -+ SAY("\nDMA Rx registers\n"); -+ { -+ dma_regs_t *r = the_controller->ep[1].dmaregs; -+ SAY(" DDAR"); -+ SAYV(r->DDAR); -+ SAY(" DCSR"); -+ SAYV(r->RdDCSR); -+ SAY(" DBSA (address buf A) "); -+ SAYV(r->DBSA); -+ SAY(" DBTA (transfer count A) "); -+ SAYV(r->DBTA); -+ SAY(" DBSB (address buf B) "); -+ SAYV(r->DBSB); -+ SAY(" DBTB (transfer count B) "); -+ SAYV(r->DBTB); -+ -+ } -+#endif -+#if 1 -+ v = Ser0UDCCS0; -+ SAY("\nUDC Endpoint Zero Status Register\n"); -+ SAYV(v); -+ SAYC("Out Packet Ready", (v & UDCCS0_OPR) ? yes : no); -+ SAYC("In Packet Ready", (v & UDCCS0_IPR) ? yes : no); -+ SAYC("Sent Stall", (v & UDCCS0_SST) ? yes : no); -+ SAYC("Force Stall", (v & UDCCS0_FST) ? yes : no); -+ SAYC("Data End", (v & UDCCS0_DE) ? yes : no); -+ SAYC("Data Setup End", (v & UDCCS0_SE) ? yes : no); -+ SAYC("Serviced (SO)", (v & UDCCS0_SO) ? yes : no); -+ -+ v = Ser0UDCCS1; -+ SAY("\nUDC Receiver Status Register\n"); -+ SAYV(v); -+ SAYC("Receive Packet Complete", (v & UDCCS1_RPC) ? yes : no); -+ SAYC("Sent Stall", (v & UDCCS1_SST) ? yes : no); -+ SAYC("Force Stall", (v & UDCCS1_FST) ? yes : no); -+ SAYC("Receive Packet Error", (v & UDCCS1_RPE) ? yes : no); -+ SAYC("Receive FIFO not empty", (v & UDCCS1_RNE) ? yes : no); -+ -+ v = Ser0UDCCS2; -+ SAY("\nUDC Transmitter Status Register\n"); -+ SAYV(v); -+ SAYC("FIFO has < 8 of 16 chars", (v & UDCCS2_TFS) ? yes : no); -+ SAYC("Transmit Packet Complete", (v & UDCCS2_TPC) ? yes : no); -+ SAYC("Transmit FIFO underrun", (v & UDCCS2_TUR) ? yes : no); -+ SAYC("Transmit Packet Error", (v & UDCCS2_TPE) ? yes : no); -+ SAYC("Sent Stall", (v & UDCCS2_SST) ? yes : no); -+ SAYC("Force Stall", (v & UDCCS2_FST) ? yes : no); -+#endif -+ -+ len = (p - page) - off; -+ if (len < 0) -+ len = 0; -+ *eof = (len <= count) ? 1 : 0; -+ *start = page + off; -+ return len; -+} -+ -+static inline void register_proc_entry(void) -+{ -+ create_proc_read_entry(driver_name, 0, NULL, -+ usbctl_read_proc, NULL); -+} -+ -+static inline void unregister_proc_entry(void) -+{ -+ remove_proc_entry(driver_name, NULL); -+} -+ -+#else -+ -+#define register_proc_entry() do {} while (0) -+#define unregister_proc_entry() do {} while (0) -+ -+#endif /* CONFIG_PROC_FS */ -+ -+/*-------------------------------------------------------------------------*/ -+ -+MODULE_DESCRIPTION("sa1100_udc"); -+MODULE_AUTHOR("Various"); -+MODULE_LICENSE("GPL"); -+ -+static struct sa1100_udc memory = { -+ .gadget = { -+ .ops = &sa1100_ops, -+ .ep0 = &memory.ep[0].ep, -+ .name = driver_name, -+ .dev = { -+ .bus_id = "gadget", -+ }, -+ }, -+ -+ /* control endpoint */ -+ .ep[0] = { -+ .ep = { -+ .name = ep0name, -+ .ops = &sa1100_ep_ops, -+ .maxpacket = EP0_FIFO_SIZE, -+ }, -+ .dev = &memory, -+ }, -+ -+ /* first group of endpoints */ -+ .ep[1] = { -+ .ep = { -+ .name = "ep1out-bulk", -+ .ops = &sa1100_ep_ops, -+ .maxpacket = BULK_FIFO_SIZE, -+ }, -+ .dev = &memory, -+ }, -+ .ep[2] = { -+ .ep = { -+ .name = "ep2in-bulk", -+ .ops = &sa1100_ep_ops, -+ .maxpacket = BULK_FIFO_SIZE, -+ }, -+ .dev = &memory, -+ } -+}; -+ -+static int __init sa1100_udc_probe(struct platform_device *pdev) -+{ -+ struct sa1100_udc *dev = &memory; -+ int retval = 0; -+ -+ /* setup dev */ -+ dev->dev = &pdev->dev; -+/* dev->mach = _dev->platform_data; */ -+ -+ device_initialize(&dev->gadget.dev); -+ dev->gadget.dev.parent = &pdev->dev; -+ dev->gadget.dev.dma_mask = pdev->dev.dma_mask; -+ -+ the_controller = dev; -+ platform_set_drvdata(pdev, dev); -+ -+ /* controller stays disabled until gadget driver is bound */ -+ udc_disable(dev); -+ udc_reinit(dev); -+ -+/* spin_lock_init(&the_udc.lock); */ -+ register_proc_entry(); -+ -+ /* setup dma channels and IRQ */ -+ retval = sa1100_request_dma(DMA_Ser0UDCRd, "USB receive", -+ NULL, NULL, &dev->ep[1].dmaregs); -+ if (retval) { -+ ERROR(dev, "couldn't get rx dma, err %d\n", retval); -+ goto err_rx_dma; -+ } -+ retval = sa1100_request_dma(DMA_Ser0UDCWr, "USB transmit", -+ NULL, NULL, &dev->ep[2].dmaregs); -+ if (retval) { -+ ERROR(dev, "couldn't get tx dma, err %d\n", retval); -+ goto err_tx_dma; -+ } -+ retval = request_irq(IRQ_Ser0UDC, udc_int_hndlr, IRQF_DISABLED, -+ driver_name, dev); -+ if (retval) { -+ ERROR(dev, "couldn't get irq, err %d\n", retval); -+ goto err_irq; -+ } -+ -+ INFO(dev, "initialized, rx %p tx %p irq %d\n", -+ dev->ep[1].dmaregs, dev->ep[2].dmaregs, IRQ_Ser0UDC); -+ return 0; -+ -+err_irq: -+ sa1100_free_dma(dev->ep[2].dmaregs); -+ usbd_info.dmaregs_rx = 0; -+err_tx_dma: -+ sa1100_free_dma(dev->ep[1].dmaregs); -+ usbd_info.dmaregs_tx = 0; -+err_rx_dma: -+ return retval; -+} -+ -+static int __exit sa1100_udc_remove(struct platform_device *pdev) -+{ -+ struct sa1100_udc *dev = platform_get_drvdata(pdev); -+ -+ udc_disable(dev); -+ unregister_proc_entry(); -+ usb_gadget_unregister_driver(dev->driver); -+ sa1100_free_dma(dev->ep[1].dmaregs); -+ sa1100_free_dma(dev->ep[2].dmaregs); -+ free_irq(IRQ_Ser0UDC, dev); -+ platform_set_drvdata(pdev, NULL); -+ the_controller = NULL; -+ return 0; -+} -+ -+static struct platform_driver udc_driver = { -+ .remove = __exit_p(sa1100_udc_remove), -+/* .shutdown = pxa25x_udc_shutdown, */ -+/* .suspend = sa1100_udc_suspend, */ -+/* .resume = sa1100_udc_resume, */ -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "sa11x0-udc", -+ }, -+}; -+ -+static int __init udc_init(void) -+{ -+ printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION); -+#ifdef NCB_DMA_FIX -+ send_buffer = kzalloc(SEND_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); -+ receive_buffer = kzalloc(RECEIVE_BUFFER_SIZE, GFP_KERNEL | -+ GFP_DMA); -+#endif -+ return platform_driver_probe(&udc_driver, sa1100_udc_probe); -+} -+module_init(udc_init); -+ -+static void __exit udc_exit(void) -+{ -+#ifdef NCB_DMA_FIX -+ kfree(send_buffer); -+ kfree(receive_buffer); -+#endif -+ platform_driver_unregister(&udc_driver); -+} -+module_exit(udc_exit); -diff --git a/drivers/usb/gadget/sa1100_udc.h b/drivers/usb/gadget/sa1100_udc.h -new file mode 100644 -index 0000000..fb0bc4a ---- /dev/null -+++ b/drivers/usb/gadget/sa1100_udc.h -@@ -0,0 +1,104 @@ -+/* -+ * internals of "new style" UDC controller -+ * <linux/usb_gadget.h> replaces ARM-specific "sa1100_usb.h". -+ */ -+ -+struct sa1100_ep { -+ struct usb_ep ep; -+ struct sa1100_udc *dev; -+ /* unsigned long irqs; */ -+ -+ const struct usb_endpoint_descriptor *desc; -+ struct list_head queue; -+ dma_regs_t *dmaregs; -+ unsigned stopped:1; -+}; -+ -+struct sa1100_request { -+ struct usb_request req; -+ struct list_head queue; -+/* NCB unsigned mapped : 1; */ -+}; -+ -+enum ep0_state { -+ EP0_IDLE, -+ EP0_IN_DATA_PHASE, -+ EP0_OUT_DATA_PHASE, -+ EP0_END_XFER, -+ EP0_STALL, -+}; -+ -+#define EP0_FIFO_SIZE ((unsigned)8) -+#define BULK_FIFO_SIZE ((unsigned)64) -+/* #define ISO_FIFO_SIZE ((unsigned)256) */ -+/* #define INT_FIFO_SIZE ((unsigned)8) */ -+ -+struct udc_stats { -+ struct ep0stats { -+ unsigned long ops; -+ unsigned long bytes; -+ } read, write; -+ unsigned long irqs; -+}; -+ -+struct sa1100_udc { -+ struct usb_gadget gadget; -+ struct usb_gadget_driver *driver; -+ struct device *dev; -+ enum ep0_state ep0state; -+ struct udc_stats stats; -+/* NCB spinlock_t lock; */ -+/* NCB dma_regs_t *dmaregs_tx, *dmaregs_rx; */ -+ unsigned got_irq:1, -+ vbus:1, -+ pullup:1, -+ has_cfr:1, -+ req_pending:1, -+ req_std:1, -+ req_config:1; -+ struct timer_list timer; -+ u64 dma_mask; -+ unsigned char address; -+ struct sa1100_ep ep[3]; -+ int ep0_req_len; -+}; -+ -+/* receiver */ -+void ep1_reset(void); -+void ep1_stall(void); -+int sa1100_usb_recv(struct usb_request *req, void (*callback) (int, int)); -+ -+/* xmitter */ -+void ep2_reset(void); -+void ep2_stall(void); -+int sa1100_usb_send(struct usb_request *req, void (*callback) (int, int)); -+ -+/*-------------------------------------------------------------------------*/ -+ -+#define xprintk(dev, level, fmt, args...) \ -+ printk(level "%s: " fmt, driver_name, ## args) -+ -+#ifdef DEBUG -+#undef DEBUG -+#define DEBUG(dev, fmt, args...) \ -+ xprintk(dev, KERN_DEBUG, fmt, ## args) -+#else -+#define DEBUG(dev, fmt, args...) \ -+ do { } while (0) -+#endif /* DEBUG */ -+ -+#ifdef VERBOSE -+#define VDEBUG DEBUG -+#else -+#define VDEBUG(dev, fmt, args...) \ -+ do { } while (0) -+#endif /* VERBOSE */ -+ -+#define ERROR(dev, fmt, args...) \ -+ xprintk(dev, KERN_ERR, fmt, ## args) -+#define WARNING(dev, fmt, args...) \ -+ xprintk(dev, KERN_WARNING, fmt, ## args) -+#define INFO(dev, fmt, args...) \ -+ xprintk(dev, KERN_INFO, fmt, ## args) -+ -+/*-------------------------------------------------------------------------*/ --- -1.6.1.3 - |