diff options
Diffstat (limited to 'recipes/linux/linux-2.6.28/collie/0009-add-sa1100-usb-gadget-driver-hack.patch')
-rw-r--r-- | recipes/linux/linux-2.6.28/collie/0009-add-sa1100-usb-gadget-driver-hack.patch | 2629 |
1 files changed, 0 insertions, 2629 deletions
diff --git a/recipes/linux/linux-2.6.28/collie/0009-add-sa1100-usb-gadget-driver-hack.patch b/recipes/linux/linux-2.6.28/collie/0009-add-sa1100-usb-gadget-driver-hack.patch deleted file mode 100644 index bb8dd5cd63..0000000000 --- a/recipes/linux/linux-2.6.28/collie/0009-add-sa1100-usb-gadget-driver-hack.patch +++ /dev/null @@ -1,2629 +0,0 @@ -From 923ac0a48c2a064e4639b0fa53dbd0a18d87043e Mon Sep 17 00:00:00 2001 -From: Thomas Kunze <thommycheck@gmx.de> -Date: Tue, 10 Feb 2009 18:09:03 +0100 -Subject: [PATCH 09/23] add sa1100 usb gadget driver hack - -Conflicts: - - drivers/usb/gadget/Makefile ---- - arch/arm/mach-sa1100/include/mach/collie.h | 5 +- - drivers/usb/gadget/Kconfig | 14 + - drivers/usb/gadget/Makefile | 1 + - drivers/usb/gadget/sa1100_udc.c | 2447 ++++++++++++++++++++++++++++ - drivers/usb/gadget/sa1100_udc.h | 94 ++ - 5 files changed, 2558 insertions(+), 3 deletions(-) - create mode 100644 drivers/usb/gadget/sa1100_udc.c - create mode 100644 drivers/usb/gadget/sa1100_udc.h - -diff --git a/arch/arm/mach-sa1100/include/mach/collie.h b/arch/arm/mach-sa1100/include/mach/collie.h -index 9bc5349..799c930 100644 ---- a/arch/arm/mach-sa1100/include/mach/collie.h -+++ b/arch/arm/mach-sa1100/include/mach/collie.h -@@ -23,11 +23,10 @@ - #define COLLIE_SCP_5VON SCOOP_GPCR_PA16 - #define COLLIE_SCP_AMP_ON SCOOP_GPCR_PA17 - #define COLLIE_GPIO_VPEN (COLLIE_SCOOP_GPIO_BASE + 7) --#define COLLIE_SCP_LB_VOL_CHG SCOOP_GPCR_PA19 -+#define COLLIE_GPIO_LB_VOL_CHG (COLLIE_SCOOP_GPIO_BASE + 8) - - #define COLLIE_SCOOP_IO_DIR ( COLLIE_SCP_CHARGE_ON | COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \ -- COLLIE_SCP_5VON | COLLIE_SCP_AMP_ON | \ -- COLLIE_SCP_LB_VOL_CHG ) -+ COLLIE_SCP_5VON | COLLIE_SCP_AMP_ON ) - #define COLLIE_SCOOP_IO_OUT ( COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \ - COLLIE_SCP_CHARGE_ON ) - -diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig -index dd4cd5a..efb65ac 100644 ---- a/drivers/usb/gadget/Kconfig -+++ b/drivers/usb/gadget/Kconfig -@@ -419,6 +419,20 @@ config USB_GOKU - default USB_GADGET - select USB_GADGET_SELECTED - -+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 - - # - # LAST -- dummy/emulated controller -diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile -index bd4041b..5cdd0ce 100644 ---- a/drivers/usb/gadget/Makefile -+++ b/drivers/usb/gadget/Makefile -@@ -19,6 +19,7 @@ obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o - obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o - obj-$(CONFIG_USB_M66592) += m66592-udc.o - obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o -+obj-$(CONFIG_USB_SA1100) += sa1100_udc.o - - # - # USB gadget drivers -diff --git a/drivers/usb/gadget/sa1100_udc.c b/drivers/usb/gadget/sa1100_udc.c -new file mode 100644 -index 0000000..5e26a6d ---- /dev/null -+++ b/drivers/usb/gadget/sa1100_udc.c -@@ -0,0 +1,2447 @@ -+/* -+ * 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=0; -+#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=NULL; -+static char *receive_buffer=NULL; -+#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 <asm/byteorder.h> -+#include <asm/io.h> -+#include <asm/irq.h> -+#include <mach/dma.h> -+#include <asm/system.h> -+#include <asm/mach-types.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 -+ -+#if defined(CONFIG_SA1100_BALLOON) -+#include <asm/arch/balloon2.h> -+#endif -+ -+#if defined(CONFIG_SA1100_COLLIE) -+#include <linux/gpio.h> -+#include <mach/collie.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; -+ -+/* 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)); -+ -+/* UDC register utility functions */ -+#define UDC_write(reg, val) { \ -+ int i = 10000; \ -+ do { \ -+ (reg) = (val); \ -+ if (i-- <= 0) { \ -+ printk( "%s [%d]: write %#x to %p (%#lx) failed\n", \ -+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \ -+ break; \ -+ } \ -+ } while((reg) != (val)); \ -+} -+ -+#define UDC_set(reg, val) { \ -+ int i = 10000; \ -+ do { \ -+ (reg) |= (val); \ -+ if (i-- <= 0) { \ -+ printk( "%s [%d]: set %#x of %p (%#lx) failed\n", \ -+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \ -+ break; \ -+ } \ -+ } while(!((reg) & (val))); \ -+} -+ -+#define UDC_clear(reg, val) { \ -+ int i = 10000; \ -+ do { \ -+ (reg) &= ~(val); \ -+ if (i-- <= 0) { \ -+ printk( "%s [%d]: clear %#x of %p (%#lx) failed\n", \ -+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \ -+ break; \ -+ } \ -+ } while((reg) & (val)); \ -+} -+ -+#define UDC_flip(reg, val) { \ -+ int i = 10000; \ -+ (reg) = (val); \ -+ do { \ -+ (reg) = (val); \ -+ if (i-- <= 0) { \ -+ printk( "%s [%d]: flip %#x of %p (%#lx) failed\n", \ -+ __FUNCTION__, __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 0 -+ -+#if 1 && !defined( ASSERT ) -+# define ASSERT(expr) \ -+ if(!(expr)) { \ -+ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ -+ #expr,__FILE__,__FUNCTION__,__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); -+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; -+ } -+ printk( "- [%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) -+{ -+ printk("%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 ){} -+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 ) ) { -+ printk( "%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 ) { -+ printk( "%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",__FUNCTION__,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 */ -+ printk( "%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", __FUNCTION__ ); -+ 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); -+ -+ printk( "%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 ) -+ printk( "%sDe-Configured\n", pszMe ); -+ usbd_info.state = 0; -+ Ser0UDCCR |= UDCCR_RIM | UDCCR_TIM; -+ ep1_reset (); -+ ep2_reset (); -+ printk("%s: de-configured. Tx and Rx interrupts disabled. ep1 and ep2 reset\n",__FUNCTION__); -+ } else { -+ printk( "%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 ) { -+ printk( "%sclear feature \"endpoint halt\" " -+ " on receiver\n", pszMe ); -+ ep1_reset(); -+ } -+ else if ( ep == 2 ) { -+ printk( "%sclear feature \"endpoint halt\" " -+ "on xmitter\n", pszMe ); -+ ep2_reset(); -+ } else { -+ printk( "%sclear feature \"endpoint halt\" " -+ "on unsupported ep # %d\n", -+ pszMe, ep ); -+ } -+ } else { -+ printk( "%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 ) { -+ printk( "%set feature \"endpoint halt\" " -+ "on receiver\n", pszMe ); -+ ep1_stall(); -+ } -+ else if ( ep == 2 ) { -+ printk( "%sset feature \"endpoint halt\" " -+ " on xmitter\n", pszMe ); -+ ep2_stall(); -+ } else { -+ printk( "%sset feature \"endpoint halt\" " -+ "on unsupported ep # %d\n", -+ pszMe, ep ); -+ } -+ } -+ else { -+ printk( "%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 { -+ printk( "%sUnknown endpoint (%d) " -+ "in GET_STATUS\n", pszMe, n ); -+ } -+ break; -+ default: -+ printk( "%sUnknown target (%d) in GET_STATUS\n", -+ pszMe, n ); -+ /* fall thru */ -+ break; -+ } -+ PRINTKD("%s: GET_STATUS writing %d\n",__FUNCTION__,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", __FUNCTION__ ); -+ 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", __FUNCTION__ ); -+ 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", __FUNCTION__ ); -+ 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", __FUNCTION__ ); -+ the_controller->driver->setup(&the_controller->gadget, &req); -+ break; -+ default : -+ printk("%sunknown request 0x%x\n", pszMe, req.bRequest); -+ break; -+ } /* switch( bRequest ) */ -+ -+sh_sb_end: -+ return; -+ -+} -+ -+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",__FUNCTION__); -+ 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",__FUNCTION__); -+ set_cs_bits(UDCCS0_DE | UDCCS0_SO); -+ return; -+ } -+ -+ /* -+ * thou shalt not enter data phase until -+ * Out Packet Ready is clear -+ */ -+ if (!clear_opr()) { -+ printk("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",__FUNCTION__,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",__FUNCTION__,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",__FUNCTION__,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 ) { -+ printk( "%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 ) { -+ printk( "%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 ) { -+ printk( "%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 ) { -+ printk( "%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 ) { -+ printk( "%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 ) { -+ printk( "%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 = NULL; -+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 ) printk( "%sEh? in ISR but naking = %d\n", "usbrx: ", naking ); -+ -+ if (status & UDCCS1_RPC) { -+ -+ if (!ep1_curdmalen) { -+ printk("usb_recv: RPC for non-existent buffer\n"); -+ naking=1; -+ return; -+ } -+ -+ sa1100_stop_dma(dmaregs_rx); -+ -+ if (status & UDCCS1_SST) { -+ printk("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) { -+ printk("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; -+ printk("usb rx %d :\n ",len); -+ if (sa1100_usb_debug>1) { -+ for (i=0; i<len; i++) { -+ if ((i % 32)==31) -+ printk("\n "); -+ printk("%2.2x ",((char *)ep1_curdmapos)[i]); -+ } -+ } -+ printk("\n"); -+ } -+#endif -+ if (len < ep1_curdmalen) { -+ char *buf = ep1_curdmabuf + len; -+ while (Ser0UDCCS1 & UDCCS1_RNE) { -+ if (len >= ep1_curdmalen) { -+ printk("usb_recv: too much data in fifo\n"); -+ break; -+ } -+ *buf++ = Ser0UDCDR; -+ len++; -+ } -+ } else if (Ser0UDCCS1 & UDCCS1_RNE) { -+ printk("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",__FUNCTION__,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 = NULL; -+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)) { -+ printk("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 { -+ printk("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",__FUNCTION__); -+ return -ENODEV; -+ } -+ -+ if (ep2_len) { -+ PRINTKD("%s: return -EBUSY\n",__FUNCTION__); -+ 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",__FUNCTION__,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",__FUNCTION__,buf); -+ -+ ep2_callback = callback; -+ ep2_remain = len; -+ ep2_curdmapos = ep2_dma; -+ -+ PRINTKD("%s: calling ep2_start\n",__FUNCTION__); -+ 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",__FUNCTION__,_ep,desc); -+ if (_ep && desc) -+ PRINTKD("%s: ep->desc = %p, _ep->name = %s desc->bDescriptorType = %s\n",__FUNCTION__,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",__FUNCTION__); -+ return -EINVAL; -+ } -+ tx_pktsize = max; -+ Ser0UDCOMP = max - 1; -+ PRINTKD("%s: ep2 max packet size is %d\n",__FUNCTION__,max); -+ break; -+ } else if (ep == &dev->ep[1]) { -+ if (desc->bEndpointAddress != (USB_DIR_OUT|1)) { -+ PRINTKD("%s: ep[1] has invalid endpoint\n",__FUNCTION__); -+ return -EINVAL; -+ } -+ rx_pktsize = max; -+ Ser0UDCIMP = max - 1; -+ PRINTKD("%s: ep1 max packet size is %d\n",__FUNCTION__,max); -+ break; -+ } -+ // FALLTHROUGH -+ default: -+ PRINTKD("%s: Invalid endpoint\n",__FUNCTION__); -+ 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 0; -+ -+ req = kzalloc(sizeof *req, gfp_flags); -+ if (!req) -+ return 0; -+ -+ memset (req, 0, sizeof *req); -+ 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",__FUNCTION__,_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",__FUNCTION__,_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) { -+ WARN_ (&the_controller, "%s Could not set SUSIM %8.8lX\n", -+ __FUNCTION__, Ser0UDCCR); -+ break; -+ } -+ } -+ -+ i = 0; -+ while (1) { -+ Ser0UDCCR &= ~UDCCR_RESIM; -+ udelay (i); -+ if ( (Ser0UDCCR & UDCCR_RESIM) == 0 -+ || (Ser0UDCSR & UDCSR_RSTIR)) -+ break; -+ if (++i == 50) { -+ WARN_ (&the_controller, "%s Could not clear RESIM %8.8lX\n", -+ __FUNCTION__, 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) { -+ WARN_ (&the_controller, "%s could not set RESIM %8.8lX\n", -+ __FUNCTION__, Ser0UDCCR); -+ break; -+ } -+ } -+ i = 0; -+ while (1) { -+ Ser0UDCCR &= ~UDCCR_SUSIM; -+ udelay (i); -+ if ( (Ser0UDCCR & UDCCR_SUSIM) == 0 -+ || (Ser0UDCSR & UDCSR_RSTIR)) -+ break; -+ if (++i == 50) { -+ WARN_ (&the_controller, "%s Could not clear SUSIM %8.8lX\n", -+ __FUNCTION__, 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", __FUNCTION__, -+ status, Ser0UDCCR); -+ /* ReSeT Interrupt Request - UDC has been reset */ -+ if (status & UDCSR_RSTIR) { -+ PRINTKD("%s: processing UDCSR_RSTIR\n", __FUNCTION__); -+ 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 -+ UDC_clear(Ser0UDCCR, (UDCCR_SUSIM | UDCCR_RESIM)); // enable suspend and resume -+ UDC_flip(Ser0UDCSR, status); // clear all pending sources -+ PRINTKD("%s: setting USB_FULL_SPEED\n",__FUNCTION__); -+ 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",__FUNCTION__); -+ 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",__FUNCTION__); -+ 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",__FUNCTION__); -+ ep0_int_hndlr(); -+ -+ if (status & UDCSR_RIR) { -+ PRINTKD("%s: processing ep1_int_hndlr\n",__FUNCTION__); -+ ep1_int_hndlr(status); -+ } -+ if (status & UDCSR_TIR) { -+ PRINTKD("%s: processing ep2_int_hndlr\n",__FUNCTION__); -+ ep2_int_hndlr(status); -+ } -+ -+ return IRQ_HANDLED; // NCB -+} -+ -+/* 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. -+ */ -+#ifdef CONFIG_SA1100_EXTENEX1 -+static void soft_connect_hook(int enable) -+{ -+ if (machine_is_extenex1 ()) { -+ if (enable) { -+ PPDR |= PPC_USB_SOFT_CON; -+ PPSR |= PPC_USB_SOFT_CON; -+ } else { -+ PPSR &= ~PPC_USB_SOFT_CON; -+ PPDR &= ~PPC_USB_SOFT_CON; -+ } -+ } -+} -+#elif defined(CONFIG_SA1100_BALLOON) -+static void soft_connect_hook(int enable) -+{ -+ if (machine_is_balloon()) { -+ if (enable) -+ balloon_cpld_control(BALLOON_UDC_DISCONNECT, 0); -+ else -+ balloon_cpld_control(BALLOON_UDC_DISCONNECT, 1); -+ } -+} -+#elif defined(CONFIG_SA1100_COLLIE) -+static int collie_usb_init(void) -+{ -+ int rc; -+ rc = gpio_request(COLLIE_GPIO_LB_VOL_CHG, "usb enable"); -+ if (rc) -+ return rc; -+ -+ rc = gpio_direction_output(COLLIE_GPIO_LB_VOL_CHG, 1); -+ if (rc) -+ gpio_free(COLLIE_GPIO_LB_VOL_CHG); -+ -+ return rc; -+} -+ -+static void collie_set_usb(int enable) -+{ -+ gpio_set_value(COLLIE_GPIO_LB_VOL_CHG, enable); -+} -+ -+static void collie_usb_exit(void) -+{ -+ gpio_free(COLLIE_GPIO_LB_VOL_CHG); -+} -+ -+static void soft_connect_hook(int enable) -+{ -+ collie_set_usb(enable); -+} -+#else -+#define soft_connect_hook(x) do { } while (0); -+#endif -+ -+/* "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...) p += sprintf (p, fmt, ## args) -+#define SAYV(num) p += sprintf (p, num_fmt, "Value", num) -+#define SAYC(label,yn) p += sprintf (p, yn_fmt, label, yn) -+#define SAYS(label,v) p += sprintf (p, cnt_fmt, label, v) -+ -+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); -+ -+#ifdef CONFIG_SA1100_EXTENEX1 -+ SAYC ("\nSoft connect", (PPSR & PPC_USB_SOFT_CON) ? "Visible" : "Hidden"); -+#endif -+ -+#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 device *_dev) -+{ -+ struct sa1100_udc *dev = &memory; -+ int retval = 0; -+ -+ /* setup dev */ -+ dev->dev = _dev; -+// dev->mach = _dev->platform_data; -+ -+ device_initialize(&dev->gadget.dev); -+ dev->gadget.dev.parent = _dev; -+ dev->gadget.dev.dma_mask = _dev->dma_mask; -+ -+ the_controller = dev; -+ dev_set_drvdata(_dev, dev); -+ -+ /* controller stays disabled until gadget driver is bound */ -+ udc_disable(dev); -+ udc_reinit(dev); -+ -+// spin_lock_init(&the_udc.lock); -+ register_proc_entry(); -+ -+#if defined(CONFIG_SA1100_COLLIE) -+ collie_usb_init(); -+#endif -+ -+ /* 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 device *_dev) -+{ -+ struct sa1100_udc *dev = dev_get_drvdata(_dev); -+ -+ 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); -+ dev_set_drvdata(_dev,NULL); -+ the_controller = NULL; -+#if defined(CONFIG_SA1100_COLLIE) -+ collie_usb_exit(); -+#endif -+ return 0; -+} -+ -+static struct device_driver udc_driver = { -+ .name = "sa11x0-udc", -+ .bus = &platform_bus_type, -+ .probe = sa1100_udc_probe, -+ .remove = __exit_p(sa1100_udc_remove), -+// .suspend = sa1100_udc_suspend, -+// .resume = sa1100_udc_resume, -+ .owner = THIS_MODULE, -+}; -+ -+static int __init udc_init(void) -+{ -+ printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION); -+#ifdef NCB_DMA_FIX -+ send_buffer = (char*) kzalloc(SEND_BUFFER_SIZE, GFP_KERNEL | GFP_DMA ); -+ receive_buffer = (char*) kzalloc(RECEIVE_BUFFER_SIZE, GFP_KERNEL | GFP_DMA ); -+#endif -+ return driver_register(&udc_driver); -+} -+module_init(udc_init); -+ -+static void __exit udc_exit(void) -+{ -+#ifdef NCB_DMA_FIX -+ if (send_buffer) { -+ kfree(send_buffer); -+ send_buffer = NULL; -+ } -+ if (receive_buffer) { -+ kfree(receive_buffer); -+ receive_buffer = NULL; -+ } -+#endif -+ 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..86fa28d ---- /dev/null -+++ b/drivers/usb/gadget/sa1100_udc.h -@@ -0,0 +1,94 @@ -+/* -+ * 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; -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+#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 WARN_(dev,fmt,args...) \ -+ xprintk(dev , KERN_WARNING , fmt , ## args) -+#define INFO(dev,fmt,args...) \ -+ xprintk(dev , KERN_INFO , fmt , ## args)
-+ -+/*-------------------------------------------------------------------------*/ --- -1.5.6.5 - |