aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-2.6.29/h3600/03_add_features/0027-USB-add-sa1100_udc-driver.patch
diff options
context:
space:
mode:
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.patch2592
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
-