--- linux/Makefile-otgorig	2006-09-20 16:02:57.347146612 +0200
+++ linux/Makefile	2006-09-20 16:03:35.280797278 +0200
@@ -181,6 +181,7 @@
 DRIVERS-$(CONFIG_HAMRADIO) += drivers/net/hamradio/hamradio.o
 DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a
 DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
+DRIVERS-$(CONFIG_OTG) += drivers/otg/otg_drv.o
 DRIVERS-$(CONFIG_USB_GADGET) += drivers/usb/gadget/built-in.o
 DRIVERS-y +=drivers/media/media.o
 DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
--- linux/arch/mips/config-shared.in-otgorig	2006-09-20 16:09:20.671834564 +0200
+++ linux/arch/mips/config-shared.in	2006-09-20 16:09:28.068156725 +0200
@@ -1009,6 +1009,7 @@
 endmenu
 
 source drivers/usb/Config.in
+source drivers/otg/Config.in
 
 source net/bluetooth/Config.in
 
--- linux/drivers/Makefile-otgorig	2006-09-20 16:09:47.100985766 +0200
+++ linux/drivers/Makefile	2006-09-20 16:10:25.730668535 +0200
@@ -6,7 +6,7 @@
 #
 
 
-mod-subdirs :=	dio hil mtd sbus video macintosh usb input telephony ide \
+mod-subdirs :=	dio hil mtd sbus video macintosh usb otg input telephony ide \
 		message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
 		fc4 net/hamradio i2c acpi bluetooth usb/gadget sensors
 
@@ -28,6 +28,7 @@
 subdir-$(CONFIG_MAC)		+= macintosh
 subdir-$(CONFIG_PPC32)		+= macintosh
 subdir-$(CONFIG_USB)		+= usb
+subdir-$(CONFIG_OTG)		+= otg
 subdir-$(CONFIG_USB_GADGET)	+= usb/gadget
 subdir-$(CONFIG_INPUT)		+= input
 subdir-$(CONFIG_PHONE)		+= telephony
diff -uNr linux/drivers/no-otg/Config.in linux/drivers/otg/Config.in
--- linux/drivers/no-otg/Config.in	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/Config.in	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,103 @@
+#
+# USBOTG - Top level configuration of a USB Peripheral or USB On-The-Go Peripheral Device
+#
+# Copyright (c) 2004 Belcarra
+#
+#
+
+mainmenu_option next_comment
+
+    #
+    # Enable/Disable OTG Support
+    #
+    comment 'On-The-Go and USB Peripheral Support'
+    tristate 'Support for On-The-Go and USB Peripherals ' CONFIG_OTG
+
+    if [ "$CONFIG_OTG" != "n" ]; then
+        #
+        # Select appropriate hardware platform, each config file
+        # will only offer options if the kernel is configured for
+        # that specific architecture or platform. They should define
+        # the following to enable the further configuration in this
+        # file:
+        #       CONFIG_OTG_PLATFORM_OTG     offer OTG configuration
+        #
+        #       CONFIG_OTG_PLATFORM_USBD    offer USBD configuration and
+        #                               function selection
+        #       CONFIG_OTG_PLATFORM_HOST    offer HOST configuration
+        #
+        mainmenu_option next_comment
+            comment 'Select Hardware'
+        
+            # platform oriented configurations
+#            source drivers/otg/config/Config.in-mainstone
+#            source drivers/otg/config/Config.in-pcs-b780
+#            source drivers/otg/config/Config.in-pcs-p1
+#            source drivers/otg/config/Config.in-mx2ads
+#            source drivers/otg/config/Config.in-omap-h2
+            source drivers/otg/config/Config.in-db1550
+#            source drivers/otg/config/Config.in-mordor
+            
+            # architecture specific configurations
+            source drivers/otg/config/Config.in-au1x00
+#            source drivers/otg/config/Config.in-dbmx1
+#            source drivers/otg/config/Config.in-lh7a400
+#            source drivers/otg/config/Config.in-lubbock
+#            source drivers/otg/config/Config.in-smdk2500
+#            source drivers/otg/config/Config.in-strongarm
+#            source drivers/otg/config/Config.in-superh
+
+            # generic drivers
+            source drivers/otg/config/Config.in-isp1301
+	    source drivers/otg/config/Config.in-max3353e
+        endmenu
+
+        if [ "$CONFIG_OTG_PLATFORM_OTG" = "y" -o "$CONFIG_OTG_PLATFORM_USBD" = "y" ]; then
+
+            #
+            # Generic Options
+            #
+            mainmenu_option next_comment
+                comment      'General Support Options'
+                bool         'Enable High Speed Descriptors' CONFIG_OTG_HIGH_SPEED
+    #           bool         'Enable Root HUB Function' CONFIG_OTG_ROOT_HUB
+                bool         'OTG Fast Tracing' CONFIG_OTG_TRACE
+                tristate 'USB FUNCTION FS Module' CONFIG_OTG_PROCFSM 
+                bool         'Disable C99 initializers' CONFIG_OTG_NOC99
+            endmenu
+        
+            #
+            # Select USB Peripheral Function Drivers
+            #
+            mainmenu_option next_comment
+                comment      'Targeted Peripherals (USB Peripheral Function Drivers)'
+                source drivers/otg/functions/acm/Config.in
+                source drivers/otg/functions/mouse/Config.in
+                source drivers/otg/functions/network/Config.in
+                source drivers/otg/functions/msc/Config.in
+#                source drivers/otg/functions/test/Config.in
+            endmenu
+
+            mainmenu_option next_comment
+                comment      'Traditional Device Options'
+                bool         'Built-in Minimal USB Device' CONFIG_OTG_FW_MN
+                dep_bool         'Enable Auto-Start' CONFIG_OTG_TR_AUTO $CONFIG_OTG_MN
+            endmenu
+        fi
+        #dep_tristate 'Build OTG minihost core' CONFIG_OTG_HOSTCORE $CONFIG_OTG
+        if [ "$CONFIG_OTG_PLATFORM_HOST" != "n" ]; then
+            #
+            # Host configuration
+            #
+            mainmenu_option next_comment
+                comment      'Host configuration (OTG minihost core and HCD)'
+#                source drivers/otg/core/Config.in
+                source drivers/otg/ocd/Config.in
+#                source drivers/otg/classes/usblan/Config.in
+            endmenu
+        fi
+
+    fi
+
+endmenu
+
diff -uNr linux/drivers/no-otg/Config.in-orig linux/drivers/otg/Config.in-orig
--- linux/drivers/no-otg/Config.in-orig	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/Config.in-orig	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,73 @@
+#
+# OTG - configuration of a USB On-The-Go Device
+#
+# Copyright (c) 2004 Belcarra
+#
+# The otg_export script will delete all comments marked "(Testing)"
+#
+
+mainmenu_option next_comment
+
+comment 'OTG devices'
+
+tristate 'Support for USB On-The-Go Devices ' CONFIG_OTG
+
+if [ "$CONFIG_OTG" = "y" -o "$CONFIG_OTG" = "m" ]; then
+   comment ''
+   bool   '   Enable High Speed Descriptors' CONFIG_OTG_HIGH_SPEED
+   bool   '   Enable Root HUB Function' CONFIG_OTG_ROOT_HUB
+   comment ''
+
+   bool   '   Disable PCD' CONFIG_OTG_DISABLE_PCD
+   bool   '   Disable HCD' CONFIG_OTG_DISABLE_HCD
+
+   comment ''
+
+   bool   '  OTG Proc FS' CONFIG_OTG_PROCFS
+   tristate   '  OTG Proc FS Module' CONFIG_OTG_PROCFSM $CONFIG_OTG
+
+   comment 'On-The-Go Functions'
+
+   source drivers/otg/functions/network/Config.in
+   source drivers/otg/functions/acm/Config.in
+   source drivers/otg/functions/msc/Config.in
+
+   source drivers/otg/functions/isotest/Config.in
+   source drivers/otg/functions/mouse/Config.in
+
+   comment ''
+   comment 'On-The-Go Transceiver Controller Drivers (TCD)'
+
+   source drivers/otg/tcd/isp1301/Config.in
+
+   comment ''
+   comment 'On-The-Go Peripheral Controller Drivers (PCD)'
+
+   source drivers/otg/pcd/au1x00/Config.in
+   source drivers/otg/pcd/mx1/Config.in
+   source drivers/otg/pcd/mx2/Config.in
+   source drivers/otg/pcd/pxa/Config.in
+   source drivers/otg/pcd/sa1100/Config.in
+   source drivers/otg/pcd/lh7a400/Config.in
+   source drivers/otg/pcd/omap/Config.in
+   source drivers/otg/pcd/smdk2500/Config.in
+   source drivers/otg/pcd/superh/Config.in
+   source drivers/otg/pcd/sx2/Config.in
+   source drivers/otg/pcd/wmmx/Config.in
+
+   comment ''
+   comment 'On-The-Go Host Controller Drivers (HCD)'
+
+   source drivers/otg/hcd/omap/Config.in
+
+   comment ''
+   tristate '  OTG Fast Tracing' CONFIG_OTG_TRACE
+   comment ''
+
+   comment 'Non Current Bus Drivers (Testing)'
+   source drivers/otg/functions/pst/Config.in
+   source drivers/otg/functions/datalog/Config.in
+
+fi
+
+endmenu
diff -uNr linux/drivers/no-otg/FIX-MAKEFILES linux/drivers/otg/FIX-MAKEFILES
--- linux/drivers/no-otg/FIX-MAKEFILES	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/FIX-MAKEFILES	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+ARG=$1
+shift
+
+[ -z "${ARG}" ] && echo Bad args && exit 1
+
+#find . -name Makefile-${ARG} | while read i
+#do
+#        m=`expr $i : "\(.*\)-${ARG}"`
+#        ln -sfv $i $m
+#done
+
+find . -type d | while read d
+do
+        pushd $d > /dev/null
+        if [ -s Makefile-${ARG} ] ; then
+                echo -n `pwd` ": "
+                ln -sfv Makefile-${ARG} Makefile
+        fi
+        popd >/dev/null
+done
+
diff -uNr linux/drivers/no-otg/Kconfig linux/drivers/otg/Kconfig
--- linux/drivers/no-otg/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/Kconfig	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,115 @@
+menu "On-The-Go and USB Peripheral Support"
+
+    config OTG
+        tristate "Support for On-The-Go and USB Peripheral Support"
+        ---help---
+            Configure all or part of the Belcarra OTG Stack
+
+
+    menu "On-The-Go Support"
+        depends on OTG 
+
+        source "drivers/otg/config/Kconfig-scma11-evb"
+        #source "drivers/otg/config/Kconfig-omap-h2"
+
+    endmenu
+
+    menu "On-The-Go Support Configuration"
+        depends on OTG_PLATFORM_OTG
+
+        choice
+            depends on OTG && OTG_PLATFORM_OTG
+            prompt "On-The-Go Device Configuration"
+            config OTG_CFG_TR
+                bool "Traditional USB Peripheral"
+                ---help---
+                Compile as a Traditional USB Peripheral. 
+                On-The-Go support is enabled.
+            config OTG_CFG_HO
+                bool "Host Only"
+                ---help---
+                Compile the USB Host support without the USB Peripheral
+                support. This is generally only useful for testing the
+                USB Host support and Host Controller drivers.
+            config OTG_CFG_PO
+                bool "Peripheral Only"
+                ---help---
+                Compile as a On-The-Go Peripheral-Only device. This
+                is similiar to a Traditional USB Peripheral but enables
+                On-The-Go features such as SRP.
+            config OTG_CFG_DR
+                bool "Dual Role"
+                ---help---
+                Compile as an On-The-Go Dual-Role device.
+
+        endchoice
+    endmenu
+
+    menu "Targeted Peripheral List (USB Host Class Drivers)"
+        depends on OTG_PLATFORM_OTG
+        # souce "drivers/otg/xxxx"
+        #
+        #---help---
+        #A list of USB peripherals that this device
+        #can support when it is acting as a host.
+    endmenu
+
+    menu "General Support Options"
+
+        depends on OTG_PLATFORM_OTG|| OTG_PLATFORM_USBD
+
+        # This needs to be a specific defined variable that comes
+        # from Kconfig-platform file
+        #
+        #config usb
+        #    tristate 'OTG host core support (separate from native Linux host support)'
+            
+        config OTG_HIGH_SPEED
+            bool 'Enable high speed descriptors'
+            depends on OTG!=n
+
+        config OTG_TRACE
+            bool 'OTG Fast Tracing'
+            depends on OTG!=n
+            ---help---
+            This option implements register trace to support 
+            driver debugging.
+        
+        #config OTG_ROOT_HUB
+        #    bool 'Enable Root HUB Function'
+        #    depends on OTG!=n
+        
+        config OTG_PROCFS
+            bool 'OTG Proc FS'
+            depends on OTG!=n
+            ---help---
+            This option enables /proc/ support in various modules
+            Note: Some information previously exposed via the /proc
+            interface is now exposed via a different mechanism
+        
+        config OTG_PROCFSM
+            tristate 'OTG Proc FS Module'
+            depends on OTG != n
+            ---help---
+            Build in extra support to perform various operations
+            through the /proc filesystem.  Note: this module is
+            held over from the Device stack and its functions are
+            gradually being transferred to the OTG Admin API.
+        
+    endmenu
+
+
+    menu "Targeted Peripherals List (USB Peripheral Function Drivers)"
+        depends on OTG_PLATFORM_OTG || OTG_PLATFORM_USBD
+        #---help---
+        #A list of USB peripheral types that this device
+        #can emulate when it is acting as a peripheral.
+        source "drivers/otg/functions/acm/Kconfig"
+        source "drivers/otg/functions/mouse/Kconfig"
+        source "drivers/otg/functions/msc/Kconfig"
+        source "drivers/otg/functions/network/Kconfig"
+    endmenu
+
+
+endmenu
+
diff -uNr linux/drivers/no-otg/Makefile linux/drivers/otg/Makefile
--- linux/drivers/no-otg/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/Makefile	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,132 @@
+#
+# Belcarra OTG - On-The-Go 
+#
+# Copyright (c) 2004 Belcarra Technologies Corp
+
+TOPDIR ?= ../../..
+
+# order here may be important (determines linking order, thus module init order)
+subdir-y 	:= otgcore functions ocd 
+subdir-m 	:= otgcore functions ocd 
+subdir-n 	:=
+subdir- 	:=
+# The target object and module list name.
+
+O_TARGET	:= otg_drv.o
+
+# Objects that export symbols.
+
+#export-objs	:= usbd.o usbd-bops.o usbd-fops.o usbd-pcd.o ep0.o hub.o
+
+# Multipart objects. (core layer)
+
+
+# Optional parts of multipart objects.
+
+# Object file lists.
+
+obj-y		:=
+obj-m		:=
+obj-n		:=
+obj-		:=
+
+# Each configuration option enables a list of files.
+
+ifeq ($(CONFIG_OTG),y)
+obj-y	+= otgcore/otgcore.o 
+endif
+
+
+# Object files in subdirectories (There has to be a better way to do this)
+
+#=== Function drivers
+f-obj-y		:=
+f-obj-m		:=
+f-obj-n		:=
+f-obj-		:=
+
+f-obj-$(CONFIG_OTG_ACM)		+= functions/function_target.o
+f-obj-$(CONFIG_OTG_ISOTEST)	+= functions/function_target.o
+f-obj-$(CONFIG_OTG_MSC)		+= functions/function_target.o
+f-obj-$(CONFIG_OTG_MOUSE)	+= functions/function_target.o
+f-obj-$(CONFIG_OTG_NETWORK)	+= functions/function_target.o
+f-obj-$(CONFIG_OTG_PST)		+= functions/function_target.o
+
+# Remove any duplicate entries in the list by sorting (since that drops dups)
+obj-y		+= $(sort $(f-obj-y))
+#obj-m		+= $(sort $(f-obj-m))
+obj-n		+= $(sort $(f-obj-n))
+obj-		+= $(sort $(f-obj-))
+
+#=== Peripheral controller drivers
+p-obj-y		:=
+p-obj-m		:=
+p-obj-n		:=
+p-obj-		:=
+
+p-obj-$(CONFIG_OTG_AU1X00)	+= ocd/ocd_target.o
+p-obj-$(CONFIG_OTG_AU1550_DB1550_TR) += ocd/ocd_target.o
+
+# Remove any duplicate entries in the list by sorting (since that drops dups)
+obj-y		+= $(sort $(p-obj-y))
+#obj-m		+= $(sort $(p-obj-m))
+obj-n		+= $(sort $(p-obj-n))
+obj-		+= $(sort $(p-obj-))
+
+#=== Host controller drivers
+h-obj-y		:=
+h-obj-m		:=
+h-obj-n		:=
+h-obj-		:=
+
+
+# Remove any duplicate entries in the list by sorting (since that drops dups)
+obj-y		+= $(sort $(h-obj-y))
+#obj-m		+= $(sort $(h-obj-m))
+obj-n		+= $(sort $(h-obj-n))
+obj-		+= $(sort $(h-obj-))
+
+
+#=== Class drivers
+class-obj-y		:=
+class-obj-m		:=
+class-obj-n		:=
+class-obj-		:=
+
+#class-obj-$(CONFIG_OTG_CLASS_USBLAN)		+= classes/class_target.o
+
+# Remove any duplicate entries in the list by sorting (since that drops dups)
+obj-y		+= $(sort $(class-obj-y))
+#obj-m		+= $(sort $(f-obj-m))
+#obj-n		+= $(sort $(f-obj-n))
+#obj-		+= $(sort $(f-obj-))
+
+
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+int-m		:= $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
+OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
+EXTRA_CFLAGS += -Wno-format -Wall
+
diff -uNr linux/drivers/no-otg/Makefile-l26 linux/drivers/otg/Makefile-l26
--- linux/drivers/no-otg/Makefile-l26	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/Makefile-l26	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,7 @@
+#
+# Belcarra OTG - On-The-Go 
+#
+# Copyright (c) 2004 Belcarra Technologies Corp
+
+obj-y 		+= 
+obj-m	        += functions/ ocd/ otgcore/ core/
diff -uNr linux/drivers/no-otg/OWNER linux/drivers/otg/OWNER
--- linux/drivers/no-otg/OWNER	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/OWNER	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,20 @@
+OWNER: Belcarra Technologies Corp
+LICENSEE: Freescale
+
+THIS SOURCE CODE KIT IS SUPPLIED UNDER LICENSE
+
+Unless expressly modified elsewhere, the author of 
+each source file included herein retains ownership
+of the identified file notwithstanding release of
+a specific version under a Public License such as 
+the GNU General Public License.
+
+The line OWNER(entity) in a comment line at or near
+the top of a source file expressly asserts ownership
+of the file by that entity or person.
+
+In addition the presence of an OWNER.TXT or OWNER
+file in a directory asserts ownership of the contents
+of that directory and of the compilation thereof into
+the present and derivative kits.
+
diff -uNr linux/drivers/no-otg/README linux/drivers/otg/README
--- linux/drivers/no-otg/README	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/README	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,11 @@
+otg/README
+
+This is the top level of the OTG toolkit source tree.
+
+        classes         Host Class drivers
+        functions       Peripheral Function drivers
+        ocd             OTG Controller drivers
+        otgcore         OTG State Machine and USB Device stack
+        otghw           Hardware related include files
+        otg             Include files
+
diff -uNr linux/drivers/no-otg/config/Config.in-au1x00 linux/drivers/otg/config/Config.in-au1x00
--- linux/drivers/no-otg/config/Config.in-au1x00	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/config/Config.in-au1x00	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,29 @@
+#
+# Copyright (c) 2004 Belcarra
+#
+
+# Au1x00 on DB1100, PB1100 and PB1500
+
+if [ "$CONFIG_SOC_AU1X00" = "y" -o \
+    "$CONFIG_MIPS_AU1X00" = "y" -o \
+    "$CONFIG_CPU_AU1X00" = "y"  -o \
+    "$CONFIG_MIPS_AU1500" = "y" -o \
+    "$CONFIG_MIPS_AU1100" = "y" -o \
+    "$CONFIG_MIPS_AU1000" = "y" ]
+then	
+    mainmenu_option next_comment
+    comment 'AMD AU1X00 Bus Interface'
+    
+    dep_tristate 'DB1100/PB1100/PB1500 Development Boards Support' CONFIG_OTG_AU1X00 $CONFIG_OTG
+    
+    if [ "$CONFIG_OTG_AU1X00" != "n" ]; then
+        int 'AU1X00  System Clock' CONFIG_OTG_AU1X00_SCLOCK 400 
+        define_bool CONFIG_AU1000_USB_DEVICE n
+        define_bool CONFIG_AU1X00_USB_DEVICE y
+        define_bool CONFIG_OTG_PLATFORM_USBD y
+    #else
+    #    define_bool CONFIG_OTG_PLATFORM_USBD n
+    fi
+    endmenu
+fi
+
diff -uNr linux/drivers/no-otg/config/Config.in-db1550 linux/drivers/otg/config/Config.in-db1550
--- linux/drivers/no-otg/config/Config.in-db1550	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/config/Config.in-db1550	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2004 Belcarra
+#
+
+if [ "$CONFIG_MIPS_DB1550" = "y" -o "$CONFIG_MIPS_MTX2" ]
+then	
+    mainmenu_option next_comment
+    comment 'DB1550 Development Board'
+    
+    dep_tristate 'DB1550 Development Boards Support' CONFIG_OTG_DB1550 $CONFIG_OTG
+
+    #define_tristate CONFIG_OTG_AU1550
+ 
+    if [ "$CONFIG_OTG_DB1550" != "n" ]; then
+        int 'AU1X00  System Clock' CONFIG_OTG_AU1X00_SCLOCK 400 
+        define_bool CONFIG_AU1000_USB_DEVICE n
+        define_bool CONFIG_AU1X00_USB_DEVICE n
+        define_bool CONFIG_OTG_PLATFORM_USBD y
+        define_tristate CONFIG_OTG_AU1550 $CONFIG_OTG_DB1550
+
+        choice 'Select DB1550 Standard B or Mini A-B Port' \
+              "Mini-B-J14 CONFIG_OTG_DB1550_J14 \
+               Mini-A-B-J15 CONFIG_OTG_DB1550_J15"  Mini-B-J14
+
+        if [ "$CONFIG_OTG_DB1550_J14" = "y" ]; then
+            define_bool CONFIG_OTG_PLATFORM_OTG n
+            define_bool CONFIG_OTG_PLATFORM_USBD y
+            define_bool CONFIG_OTG_MAX3353E n
+            define_tristate CONFIG_OTG_AU1550_DB1550_TR $CONFIG_OTG_DB1550
+
+        else 
+            if [ "$CONFIG_OTG_DB1550_J15" = "y" ]; then
+                define_bool CONFIG_OTG_PLATFORM_OTG y
+                define_bool CONFIG_OTG_PLATFORM_USBD n
+                define_bool CONFIG_OTG_MAX3353E y
+                define_tristate CONFIG_OTG_MAX3353E_DB1550 $CONFIG_OTG_DB1550
+                define_tristate CONFIG_OTG_AU1550_DB1550_DR $CONFIG_OTG_DB1550
+
+                # J15 is external OTG Transceiver Client
+                define_bool CONFIG_OTG_DB1550_HXOE n
+                define_bool CONFIG_OTG_DB1550_HXS y
+                define_int CONFIG_OTG_DB1550_SEOS 4
+            fi
+        fi
+    fi
+    endmenu
+fi
+
diff -uNr linux/drivers/no-otg/config/Config.in-dbmx1 linux/drivers/otg/config/Config.in-dbmx1
--- linux/drivers/no-otg/config/Config.in-dbmx1	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/config/Config.in-dbmx1	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2004 Belcarra
+#
+
+# MX1ADS - Motorola MX1                                                            	
+
+if [ "$CONFIG_ARCH_MX1ADS" = "y" ]; then						
+
+    mainmenu_option next_comment
+    comment 'Motorola MX1 Bus Interface'
+    dep_tristate 'DBMX1 Developement Board Support' CONFIG_OTG_DBMX1 $CONFIG_OTG	
+
+    if [ "$CONFIG_OTG_DBMX1" != "n" ]; then
+        define_bool CONFIG_OTG_PLATFORM_USBD y
+    else
+        define_bool CONFIG_OTG_PLATFORM_USBD n
+    fi
+    endmenu
+fi											
diff -uNr linux/drivers/no-otg/config/Config.in-isp1301 linux/drivers/otg/config/Config.in-isp1301
--- linux/drivers/no-otg/config/Config.in-isp1301	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/config/Config.in-isp1301	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,25 @@
+
+#
+# Copyright (c) 2004 Belcarra
+#
+# ISP 1301 TCD
+
+#if [ "$CONFIG_OTG_ISP1301" = "y" ]; then
+#    mainmenu_option next_comment
+#    comment 'ISP 1301'
+#   
+#    #bool 'Proc FS debug' CONFIG_OTG_ISP1301_PROCFSX 
+#    #bool         'Enable High Speed Descriptors' CONFIG_OTG_HIGH_SPEEDX
+#    define_bool CONFIG_OTG_TEST y
+#
+#    endmenu
+#fi
+if [ "$CONFIG_OTG_ISP1301" = "y" ]; then
+
+    mainmenu_option next_comment
+    comment 'ISP 1301'
+    bool 'Proc FS debug' CONFIG_OTG_ISP1301_PROCFS
+
+    endmenu
+fi                                                                  
+
diff -uNr linux/drivers/no-otg/config/Config.in-max3353e linux/drivers/otg/config/Config.in-max3353e
--- linux/drivers/no-otg/config/Config.in-max3353e	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/config/Config.in-max3353e	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,25 @@
+
+#
+# Copyright (c) 2004 Belcarra
+#
+# MAX 3353E TCD
+
+#if [ "$CONFIG_OTG_MAX3353E" = "y" ]; then
+#    mainmenu_option next_comment
+#    comment 'MAX 3353E'
+#   
+#    #bool 'Proc FS debug' CONFIG_OTG_MAX3353E_PROCFSX 
+#    #bool         'Enable High Speed Descriptors' CONFIG_OTG_HIGH_SPEEDX
+#    define_bool CONFIG_OTG_TEST y
+#
+#    endmenu
+#fi
+if [ "$CONFIG_OTG_MAX3353E" = "y" ]; then
+
+    mainmenu_option next_comment
+    comment 'MAX 3353E'
+    bool 'Proc FS debug' CONFIG_OTG_MAX3353E_PROCFS
+
+    endmenu
+fi                                                                  
+
diff -uNr linux/drivers/no-otg/config/Config.in-mordor linux/drivers/otg/config/Config.in-mordor
--- linux/drivers/no-otg/config/Config.in-mordor	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/config/Config.in-mordor	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,28 @@
+#
+# Copyright (c) 2004 Belcarra
+#
+
+# Au1x00 on DB1100, PB1100 and PB1500
+
+if [ "$CONFIG_AMX_MORDOR" = "y"  ]
+then	
+    mainmenu_option next_comment
+    comment 'AMX Mordor Board'
+    
+    dep_tristate 'AMX Mordor Board Support' CONFIG_OTG_AU1550 $CONFIG_OTG
+    define_tristate CONFIG_OTG_BVD $CONFIG_OTG_AU1550  
+ 
+    if [ "$CONFIG_OTG_AU1550" != "n" ]; then
+        int 'AU1X00  System Clock' CONFIG_OTG_AU1X00_SCLOCK 400 
+        define_bool CONFIG_AU1000_USB_DEVICE n
+        define_bool CONFIG_AU1X00_USB_DEVICE n
+        define_bool CONFIG_OTG_PLATFORM_USBD y
+
+        define_bool CONFIG_OTG_PLATFORM_OTG n
+        define_bool CONFIG_OTG_PLATFORM_USBD y
+
+    else
+        define_bool CONFIG_OTG_PLATFORM_USBD n
+    fi
+    endmenu
+fi
diff -uNr linux/drivers/no-otg/config/Kconfig-omap-h2 linux/drivers/otg/config/Kconfig-omap-h2
--- linux/drivers/no-otg/config/Kconfig-omap-h2	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/config/Kconfig-omap-h2	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,87 @@
+#
+# Copyright (c) 2004 Belcarra
+#
+
+# OMAP - TI OMAP 1610
+#
+
+# CONFIG_OTG_PLATFORM_OTG           # Offer OTG Configuration
+
+# CONFIG_OTG_OMAP               # Make OMAP driver
+# CONFIG_OTG_ISP1301            # Make ISP1301 driver
+
+# CONFIG_OTG_ISP1301_OMAP_H2    # Compile ISP1301 OMAP H2 driver
+
+# CONFIG_OTG_OMAP_H2            # OMAP Helen 2 board
+# CONFIG_OTG_OMAP_H2_3_WIRE     # Use 3 Wire OTG Configuration
+# CONFIG_OTG_OMAP_H2_4_WIRE     # Use 4 Wire OTG Configuration
+# CONFIG_OTG_OMAP_H2_DR         # Compile as OTG Dual-role Device
+# CONFIG_OTG_OMAP_H2_TR         # Compile as Traditional USB Peripheral
+
+config OTG_OMAP_H2
+	tristate "OMAP 1610 H2 Development Board"
+	depends on OTG && ARCH_OMAP
+        ---help---
+        This implements On-The-Go USB Support for the Helen 2 OMAP 
+        Development Board.
+
+choice
+	prompt "Select Transceiver wire configuration"	
+	depends on OTG && ARCH_OMAP && OTG_OMAP_H2
+        config OTG_OMAP_H2_3_WIRE
+        	bool 'Enable Pin Group 1, 3 Wire Configuration'
+        	depends on OMAP_H2 !=n
+        	---help---
+                The H2 board ISP1301 can be configured in either 
+                the 3 wire or 4 wire configuration.
+                This enables the ISP1301 on the H2 board on Pin Group 1
+                using the 3-Wire OTG Transceiver Configuration. This
+                requires that the ISP1301 be configured for DAT_SE0.
+        
+        config OTG_OMAP_H2_4_WIRE
+        	bool 'Enable Pin Group 1, 4 Wire Configuration'
+        	depends on OMAP_H2 !=n
+        	---help---
+                The H2 board ISP1301 can be configured in either 
+                the 3 wire or 4 wire configuration.
+                This enables the ISP1301 on the H2 board on Pin Group 1
+                using the 3-Wire OTG Transceiver Configuration. This
+                requires that the ISP1301 be configured for VP_VM.
+
+endchoice
+
+config OTG_PLATFORM_OTG
+        bool 
+        default OTG_OMAP_H2
+
+config OTG_OMAP_H2_TR
+        tristate
+        depends on OTG_CFG_TR
+        default OTG_OMAP_H2
+
+config OTG_OMAP_H2_HO
+        tristate
+        depends on OTG_CFG_HO
+        default OTG_OMAP_H2
+
+config OTG_OMAP_H2_PO
+        tristate
+        depends on OTG_CFG_PO
+        default OTG_OMAP_H2
+
+config OTG_OMAP_H2_DR
+        tristate
+        depends on OTG_CFG_DR
+        default OTG_OMAP_H2
+
+
+config OTG_ISP1301
+        tristate
+        depends on OTG_OMAP_H2
+        default OTG_OMAP_H2
+
+config OTG_ISP1301_OMAP_H2
+        tristate
+        depends on OTG_OMAP_H2
+        default OTG_OMAP_H2
+
diff -uNr linux/drivers/no-otg/config/README-CONFIG.txt linux/drivers/otg/config/README-CONFIG.txt
--- linux/drivers/no-otg/config/README-CONFIG.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/config/README-CONFIG.txt	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,106 @@
+OTG System Configuration                                        Stuart Lynne
+Belcarra                                        Thu Jan 13 15:45:19 PST 2005 
+
+This directory contains the linux system configurations to create
+architecture or board level drivers for On-The-Go or USB Device support.
+
+There are four generic configurations available
+
+    - tr - Traditional USB Peripheral    
+    - po - OTG Peripheral only
+    - dr - OTG Dual-Role device
+
+Traditional USB Peripheral    
+**************************
+
+Older types of systems supported USB peripherals as a separate module. It is
+not generally possible to configure these with On-The-Go support. In most
+cases the only customization available is for detection of the Vbus (cable
+attached) and control over the D-plus pullup resistor (soft-connect.)
+
+For most of these types of systems the generated driver will be of the form:
+
+    xxx_tr
+
+Where xxx is the system architecture:
+
+    au1x00
+    lh7a400
+    mx1
+    pxa
+    sa1100
+    smdk2500
+    superh
+
+
+OTG Modes
+*********
+
+Generally new systems that support On-The-Go have (at least) the following
+components:
+
+    - USB Peripheral
+    - USB Host
+    - OTG Transceiver
+    - Charge Pump (optional)
+
+In general the combination of the above is customized at the board or
+platform level, not the architecture (chip) level. There may be up to four
+different drivers implementing various combinations of the required support.
+
+Required support:
+
+    - pcd - Peripheral Controller Driver
+    - tcd - Transceiver Controller Driver
+    - hcd - Host Controller Driver
+    - ocd - OTG Controller Driver
+
+Typically the pcd and ocd drivers will be in a single module. This module
+will be named:
+
+    xxxx_ss
+
+Where xxxx is the platform, e.g.:
+
+    mainstone
+    mx1ads
+    omap-h2
+
+And ss is the type of OTG support being compiled:
+
+    - tr - traditonal usb
+    - ho - host only
+    - po - peripheral only
+    - dr - dual-role
+
+
+
+OTG Peripheral Only (po)
+************************
+
+This mode allows for implementing a restricted mode of On-The-Go support.
+The host driver module is not configured or available.
+
+
+OTG Dual-Role Device (dr)
+*************************
+
+This mode implements the full On-The-Go stack with both USB Device and Usb
+Host support.
+
+
+Configuration File
+******************
+
+Under linux, older systems (those that support only traditional devices) will
+have a generic Config.in / Kconfig file to generate the required driver.
+
+For newer systems that support OTG type configurations there should be a
+Configuration file for each major platform supported. This will specifically
+enable defines for all of the required drivers and their options. 
+
+Platform files may have several sub-types with appropriate configuration
+selectors.
+
+
+
diff -uNr linux/drivers/no-otg/dirs linux/drivers/otg/dirs
--- linux/drivers/no-otg/dirs	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/dirs	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,11 @@
+!if 0
+Copyright (c) 2004 Belcarra
+!endif
+
+DIRS= \
+        wince \
+        otgcore \
+        functions/mouse
+
+OPTIONAL_DIRS= \
+
diff -uNr linux/drivers/no-otg/functions/Makefile linux/drivers/otg/functions/Makefile
--- linux/drivers/no-otg/functions/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/Makefile	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,53 @@
+#
+# Belcarra OTG - On-The-Go 
+#
+# Copyright (c) 2004 Belcarra Technologies Corp
+
+TOPDIR ?= ../../../..
+
+subdir-y 	:= 
+subdir-m 	:=
+subdir-n 	:=
+subdir- 	:=
+
+# The target object and module list name.
+
+O_TARGET        := function_target.o
+
+# Function Drivers
+subdir-$(CONFIG_OTG_ACM) += acm
+subdir-$(CONFIG_OTG_ISOTEST) += isotest
+subdir-$(CONFIG_OTG_MSC) += msc
+subdir-$(CONFIG_OTG_MOUSE) += mouse
+subdir-$(CONFIG_OTG_NETWORK) += network
+
+# Object file lists.
+
+obj-y           :=
+obj-m           :=
+obj-n           :=
+obj-            :=
+
+# Function drivers
+ifeq ($(CONFIG_OTG_ACM),y)
+obj-y += acm/acm_fd_drv.o
+endif
+ifeq ($(CONFIG_OTG_MOUSE),y)
+obj-y += mouse/mouse_target.o
+endif
+ifeq ($(CONFIG_OTG_NETWORK),y)
+obj-y += network/network_target.o
+endif
+ifeq ($(CONFIG_OTG_MSC),y)
+obj-y += msc/msc_target.o
+endif
+ifeq ($(CONFIG_OTG_PST),y)
+obj-y += pst/pst_target.o
+endif
+ifeq ($(CONFIG_OTG_TEST),y)
+obj-y += test/test_target.o
+endif
+
+include $(TOPDIR)/Rules.make
+EXTRA_CFLAGS += -Wno-format -Wall
+
diff -uNr linux/drivers/no-otg/functions/Makefile-l26 linux/drivers/otg/functions/Makefile-l26
--- linux/drivers/no-otg/functions/Makefile-l26	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/Makefile-l26	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,12 @@
+#
+# Belcarra OTG - On-The-Go 
+#
+# Copyright (c) 2004 Belcarra Technologies Corp
+
+EXTRA_CFLAGS += -Wno-format -Wall
+# Function Drivers
+obj-$(CONFIG_OTG_ACM) += acm/
+obj-$(CONFIG_OTG_MSC) += msc/
+obj-$(CONFIG_OTG_MOUSE) += mouse/
+obj-$(CONFIG_OTG_NETWORK) += network/
+
diff -uNr linux/drivers/no-otg/functions/acm/Config.in linux/drivers/otg/functions/acm/Config.in
--- linux/drivers/no-otg/functions/acm/Config.in	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/Config.in	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,28 @@
+#
+# CDC ACM Function Driver
+#
+# Copyright (C) 2003,2004 Belcarra
+#
+
+mainmenu_option next_comment
+comment "USB Peripheral Function Driver - CDC ACM"
+
+dep_tristate '  CDC ACM Function' CONFIG_OTG_ACM $CONFIG_OTG
+if [ "$CONFIG_OTG_ACM" != "n" ]; then
+   hex     'VendorID (hex value)' CONFIG_OTG_ACM_VENDORID "15ec"
+   hex     'ProductID (hex value)' CONFIG_OTG_ACM_PRODUCTID "f002"
+   hex     'bcdDevice (binary-coded decimal)' CONFIG_OTG_ACM_BCDDEVICE "0100"
+
+   string 'iManufacturer (string)' CONFIG_OTG_ACM_MANUFACTURER "Belcarra"
+   string 'iProduct (string)' CONFIG_OTG_ACM_PRODUCT_NAME "Belcarra ACM Device"
+
+   string 'iConfiguration (string)' CONFIG_OTG_ACM_DESC "Acm Cfg"
+   string 'Comm Interface iInterface (string)' CONFIG_OTG_ACM_COMM_INTF "Comm Intf"
+   string 'Data Interface iInterface (string)' CONFIG_OTG_ACM_DATA_INTF "Data Intf"
+
+   comment ''
+   #bool   'Communications Device'  CONFIG_OTG_ACM_COMM
+   #bool   'TTY Device'  CONFIG_OTG_ACM_TTY
+fi
+
+endmenu
diff -uNr linux/drivers/no-otg/functions/acm/Kconfig linux/drivers/otg/functions/acm/Kconfig
--- linux/drivers/no-otg/functions/acm/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/Kconfig	2006-09-01 21:41:25.000000000 +0200
@@ -0,0 +1,54 @@
+menu "OTG ACM Function"
+
+config OTG_ACM
+         tristate "  CDC ACM Function"
+         depends on OTG
+
+menu "OTG ACM function options"
+	depends on OTG && OTG_ACM
+
+config OTG_ACM_VENDORID
+        hex "VendorID (hex value)"
+	depends on OTG_ACM && OTG
+        default "0x15ec"
+
+config OTG_ACM_PRODUCTID
+	depends on OTG_ACM && OTG
+        hex "ProductID (hex value)"
+        default "0xe003"
+config OTG_ACM_BCDDEVICE
+	depends on OTG_ACM && OTG
+        hex "bcdDevice (binary-coded decimal)"
+        default "0x0100"
+
+config OTG_ACM_MANUFACTURER
+	depends on OTG_ACM && OTG
+        string "iManufacturer (string)"
+        default "Belcarra"
+
+config OTG_ACM_PRODUCT_NAME
+	depends on OTG_ACM && OTG
+        string "iProduct (string)"
+        default "Belcarra ACM Device"
+
+config OTG_ACM_DESC
+	depends on OTG_ACM && OTG
+        string "iConfiguration (string)"
+        default "Acm Cfg"
+
+config OTG_ACM_COMM_INTF
+	depends on OTG_ACM && OTG
+        string "Comm Interface iInterface (string)"
+        default "Comm Intf"
+
+config OTG_ACM_DATA_INTF
+	depends on OTG_ACM && OTG
+        string "Data Interface iInterface (string)"
+        default "Data Intf"
+
+config OTG_ACM_TRACE
+	depends on OTG_ACM && OTG
+        bool "  ACM Tracing"
+        default n
+endmenu
+endmenu
diff -uNr linux/drivers/no-otg/functions/acm/Makefile linux/drivers/otg/functions/acm/Makefile
--- linux/drivers/no-otg/functions/acm/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/Makefile	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,80 @@
+#
+# Function driver for a CDC ACM USB Device
+#
+# Copyright (c) 2003 Belcarra
+
+# Multipart objects.
+
+O_TARGET	:= acm_fd_drv.o
+list-multi	:= acm_fd.o tty_fd.o
+
+#modem_fd-objs	:= acm-fd.o modem-l24-os.o modem.o
+#obex_fd-objs	:= acm-fd.o obex-l24-os.o obex.o
+tty_fd-objs	:= acm-fd.o tty-l24-os.o tty-fd.o
+
+# Objects that export symbols.
+#export-objs	:= acm-fd.o 
+
+# Object file lists.
+
+obj-y	:=
+obj-m	:=
+obj-n	:=
+obj-	:=
+
+# Each configuration option enables a list of files.
+
+#obj-$(CONFIG_OTG_ACM)   += modem_fd.o
+#obj-$(CONFIG_OTG_ACM)   += obex_fd.o
+obj-$(CONFIG_OTG_ACM)   += tty_fd.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+int-m		:= $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
+OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+
+# The global Rules.make.
+
+ACMD=$(OTG)/functions/acm
+
+OTG_DIR=$(TOPDIR)/drivers/otg
+OTGCORE_DIR=$(OTG_DIR)/otgcore
+#USBDCORE_DIR=$(OTG_DIR)/usbdcore
+include $(TOPDIR)/Rules.make
+EXTRA_CFLAGS +=  -I$(OTG_DIR) -Wno-unused -Wno-format  -I$(OTGCORE_DIR)
+EXTRA_CFLAGS_nostdinc += -I$(OTG_DIR) -Wno-unused -Wno-format  -I$(OTGCORE_DIR)
+
+# Link rules for multi-part drivers.
+
+modem_fd.o: $(modem_fd-objs)
+	$(LD) -r -o $@ $(modem_fd-objs)
+
+obex_fd.o: $(obex_fd-objs)
+	$(LD) -r -o $@ $(obex_fd-objs)
+
+tty_fd.o: $(tty_fd-objs)
+	$(LD) -r -o $@ $(tty_fd-objs)
+
+# dependencies:
+
+#modem.o: $(USBDCORE_DIR)/usbd.h $(USBDCORE_DIR)/usbd-bus.h $(USBDCORE_DIR)/usbd-func.h
+#obex.o: $(USBDCORE_DIR)/usbd.h $(USBDCORE_DIR)/usbd-bus.h $(USBDCORE_DIR)/usbd-func.h
+#tty.o: $(USBDCORE_DIR)/usbd.h $(USBDCORE_DIR)/usbd-bus.h $(USBDCORE_DIR)/usbd-func.h
+
diff -uNr linux/drivers/no-otg/functions/acm/Makefile-l26 linux/drivers/otg/functions/acm/Makefile-l26
--- linux/drivers/no-otg/functions/acm/Makefile-l26	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/Makefile-l26	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,13 @@
+# Function driver for a CDC ACM OTG Device
+#
+# Copyright (c) 2004 Belcarra
+
+acm_fd-objs	:= acm-fd.o acm-l26-os.o
+
+obj-$(CONFIG_OTG_ACM) += acm_fd.o
+
+OTG=$(TOPDIR)/drivers/otg
+ACMD=$(OTG)/functions/acm
+USBDCORE_DIR=$(OTG)/usbdcore
+EXTRA_CFLAGS += -I$(ACMD) -I$(OTG) -Wno-unused -Wno-format  -I$(USBDCORE_DIR)
+EXTRA_CFLAGS_nostdinc += -I$(ACMD) -I$(OTG) -Wno-unused -Wno-format  -I$(USBDCORE_DIR)
diff -uNr linux/drivers/no-otg/functions/acm/OBEX-TODO.txt linux/drivers/otg/functions/acm/OBEX-TODO.txt
--- linux/drivers/no-otg/functions/acm/OBEX-TODO.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/OBEX-TODO.txt	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,16 @@
+OBEX TODO List                                                  Stuart Lynne
+Belcarra                                        Tue Aug 24 21:36:09 PDT 2004 
+
+
+1. OBEX documentation
+
+
+2. define obex requirements
+
+        - similiar to acm
+        - uses comm interface for ?
+        - impelements data/nodata inteface
+
+        - socket family interface
+        - char device interface
+
diff -uNr linux/drivers/no-otg/functions/acm/TODO.txt linux/drivers/otg/functions/acm/TODO.txt
--- linux/drivers/no-otg/functions/acm/TODO.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/TODO.txt	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,143 @@
+ACM TODO List                                                   Stuart Lynne
+Belcarra                                        Wed Sep 01 19:48:38 PDT 2004 
+
+
+1. The ACM driver needs to be expanded to allow it to build three ways:
+
+
+        - tty   equivalent of old acm, uses linux tty layer
+        - modem present two simple char devices for data and comm interfaces
+        - obex  single simple char device
+
+TTY 
+        - present a single char device with TTY line discipline
+        - TIOCM calls represent "state" of emulated serial port on this
+          side of null modem
+        - notifications and line state only affect far side of null modem
+
+MODEM 
+        - present two simple char device interfaces
+        - data char device will implement TIOCM ioctls
+        - comm char device will use encapsulated data over endpoint zero
+        - TIOCM calls represent state passed to/from host via notifications
+          and line state requests
+
+OBEX
+        - present a single simple char device interface
+        - no requirement for either TIOCM or TTY line discipline
+        - TIOCM calls not implemented
+
+
+
+2. The modem device must implement a virtual NULL modem and support the 
+following IOCTL's.
+
+
+
+Virtual NULL Modem
+
+Peripheral to Host via Serial State Notification (write ioctls)
+
+Application             TIOCM           Null Modem      ACM (DCE)       Notificaiton    Host (DTE)
+-------------------------------------------------------------------------------------------------------------
+Request to send         TIOCM_RTS       RTS ->  CTS     CTS             Not Available   Clear to Send (N/A)
+Data Terminal Ready     TIOCM_DTR       DTR ->  DSR     DSR             bTxCarrier      Data Set Ready
+                                        DTR ->  DCD     DCD             bRXCarrier      Carrier Detect
+Ring Indicator          TIOCM_OUT1      OUT1 -> RI      RI              bRingSignal     Ring Indicator
+Send Break              TIOCM_OUT2      OUT2 -> Break   Break           bBreak          Break Received
+-------------------------------------------------------------------------------------------------------------
+
+
+Host to Peripheral via Set Control Line State
+
+Host (DTE)              Line State      ACM (DCE)       Null Modem      TIOCM           Peripheral (DTE)
+-------------------------------------------------------------------------------------------------------------
+Data Terminal Ready     D0              DTR             DTR ->  DSR     TIOCM_DSR       Data Set Ready
+                                                        DTR ->  DCD     TIOCM_CAR       Carrier Detect
+Request To Send         D1              RTS             RTS ->  CTS     TIOCM_CTS       Clear to Send
+-------------------------------------------------------------------------------------------------------------
+
+
+3. The following DEVICE REQUESTS have to be implemented and where
+possible support added to hook the results to the upper layers
+and applications.
+
+        SetCommFeature 
+        GetCommFeature 
+        ClearCommFeature 
+
+        SendEncapsulatedCommand 
+        GetEncapsulatedResponse
+
+        SetLineCoding 
+        GetLineCoding
+
+        SetControlLineState
+
+        SendBreak
+
+4. The following NOTIFICATIONS need to be implemented and where 
+possible hooked to appropriate indications from upper layers
+and applications.
+
+
+        RESPONSE_AVAILABLE
+        NETWORK_CONNECTION
+        SERIAL_STATE
+
+
+
+5. ACM documentation needs to be updated to reflect implementation(s).
+
+
+6. POSIX IOCTLS
+        - TIOCM*
+        - hook into flow control or set from flow control as required
+        - baudrate and other device settings        
+        - CTS should disable receive urb
+
+7. COMM Interface 
+        - GET / SEND Encapsulated command
+        - response available notification
+        - char device interface
+
+8. Optional TTY
+        - register as TTY device only if requested
+        - register as simple char device otherwise
+
+9. select() 
+        - trackdown tty layer problem with select()
+        - sometimes fails under stress testing
+
+
+Notes..
+
+1. implementation of the comm and simple char device can probably share
+the same code base. These should queue received urbs. This will mean 
+a small change in the os between acm_recv_urb() and the os specific
+layer. 
+
+2. Now it is acm_os_recv_chars(), this must change to acm_os_recv_urbs().
+The acm_os_recv_urbs() function will be responsible for deallocing the
+urb when delivered.
+
+3. The various os specific functions will need to have a method to
+distinguish between the comm and data interfaces. 
+
+
+
+
+10. WMC  - Wireless Mobice Class
+
+        Call Management - bmCapabilities allow call management over data interface
+        ACM - bmCapabilities - 0x06, only SEND_BREAK, SET/GET LINE_CODING
+
+        NETWORK_CONNECTION, XXX_COMM_FEATURE not allowed
+
+        Call management over COMM interface optional
+
+        COMM_FEATURE - optional?
+
+
+
+
diff -uNr linux/drivers/no-otg/functions/acm/acm-fd.c linux/drivers/otg/functions/acm/acm-fd.c
--- linux/drivers/no-otg/functions/acm/acm-fd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/acm-fd.c	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,1077 @@
+/*
+ * otg/functions/acm/acm-fd.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ */
+/*!
+ * @file otg/functions/acm/acm-fd.c
+ * @brief ACM Function Driver private defines
+ *
+ * An ACM (Abstract Control Model) driver is composed of several pieces:
+ *
+ *    1) An OS and function specific piece that handles creating and operating
+ *       a device for the given OS suitable for a specific function.
+ *
+ *    2) A set descriptors suitable for the function.
+ *
+ *    3) This acm-fd library which implements the interface to
+ *       the usb peripheral and otgcore stacks.
+ *
+ * If the USB piece interfaces with the host usbcore layer you get
+ * an ACM class driver.  If the USB piece interfaces with the otgcore
+ * layer you get an ACM function driver.
+ *
+ *
+ * @ingroup ACMFunction
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include "acm.h"
+#include "acm-fd.h"
+#include "acm-os.h"
+
+
+static u32 max_queued_urbs;
+static u32 max_queued_bytes;
+
+// Define the low order 16 bits of an urb's memory address as it's ID for tracing.
+#define urbID(urb) (0xffff & (u32) (void *) urb)
+
+/* ******************************************************************************************* */
+
+STATIC int acm_send_int_notification(struct acm_private *acm, int , int );
+STATIC int acmfd_urb_sent_bulk (struct usbd_urb *urb, int rc);
+STATIC int acmfd_urb_sent_int (struct usbd_urb *urb, int rc);
+STATIC int acmfd_recv_urb (struct usbd_urb *urb, int rc);
+STATIC void acm_schedule_recv(struct acm_private *acm, int interface);
+
+/* ******************************************************************************************* */
+
+/*! acm_ready
+ * @param acm
+ */
+STATIC int acm_ready(struct acm_private *acm) 
+{
+        TRACE_MSG5(acm->trace_tag,"CONFIGURED: %x OPENED: %x THROTTLED: %x CARRIER: %x READY: %d", 
+                        acm->flags & ACM_CONFIGURED, acm->flags & ACM_OPENED,
+                        acm->flags & ACM_THROTTLED, acm->flags & ACM_CARRIER,
+                        (acm->flags & ACM_CONFIGURED) && (acm->flags & ACM_CARRIER) ? 1 : 0);
+
+        return (acm->flags & ACM_CONFIGURED) && 
+                (acm->flags & ACM_OPENED) &&
+                !(acm->flags & ACM_THROTTLED) &&
+                ((acm->flags & ACM_LOCAL) ? 1 : (acm->flags & ACM_CARRIER) ) 
+                ;
+
+}
+
+/*! acm_open
+ * @param acm
+ * @param interface
+ * @return int
+ */
+STATIC int acm_open(struct acm_private *acm, int interface) 
+{
+        TRACE_MSG0(acm->trace_tag,"OPEN");
+        acm->flags |= ACM_OPENED;
+        acm->flags &= ~ACM_THROTTLED;
+        acm->bmUARTState = CDC_UARTSTATE_BRXCARRIER_DCD | CDC_UARTSTATE_BTXCARRIER_DSR;
+        acm_schedule_recv(acm, interface);
+        TRACE_MSG1(acm->trace_tag,"bmUARTState: %04x", acm->bmUARTState);
+        acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
+        return 0;
+}
+
+/*! acm_flush
+ * @param acm
+ * @param interface
+ * @return number of urbs in queue
+ */
+STATIC void acm_flush(struct acm_private *acm, int interface) 
+{
+        struct usbd_function_instance *function = acm->function;
+        unsigned long flags;
+        TRACE_MSG0(acm->trace_tag,"FLUSH");
+        RETURN_UNLESS(function);
+        local_irq_save(flags);
+        acm->bytes_received = 0;
+        acm->bytes_forwarded = 0;
+        acm->bmUARTState = CDC_UARTSTATE_BRXCARRIER_DCD | CDC_UARTSTATE_BTXCARRIER_DSR;
+        TRACE_MSG1(acm->trace_tag,"bmUARTState: %04x", acm->bmUARTState);
+        // TBR: 20040705 use ...le32() not le16, spotted by Zhao Liang
+        acm->line_coding.dwDTERate = cpu_to_le32(0x1c200); // 115200
+        acm->line_coding.bDataBits = 0x08;
+
+        usbd_flush_endpoint_index(function, BULK_IN);
+        usbd_flush_endpoint_index(function, BULK_OUT);
+        local_irq_restore(flags);
+}
+
+/*! acm_close
+ * @param acm
+ * @param interface
+ * @return number of urbs in queue
+ */
+STATIC int acm_close(struct acm_private *acm, int interface) 
+{
+        TRACE_MSG0(acm->trace_tag,"CLOSE");
+        acm->flags &= ~ACM_OPENED;
+        acm->flags &= ~ACM_THROTTLED;
+        acm_flush(acm, interface);
+        acm->bmUARTState = 0;
+        TRACE_MSG1(acm->trace_tag,"bmUARTState: %04x", acm->bmUARTState);
+        acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
+        return 0;
+}
+
+
+/*! acmfd_start_recv_urbs
+ * @param acm
+ * @param interface
+ * @return number of urbs in queue
+ */
+STATIC int acmfd_start_recv_urbs(struct acm_private *acm, int interface) 
+{
+        /*
+         * Queue as many receive urbs as the OS layer has room for.  Return
+         * the number in the queue (may be more than we queue here).
+         */
+        struct usbd_function_instance *function = acm->function;
+        unsigned long flags;
+        int num_in_queue = 0;
+
+        switch (interface) {
+        case COMM_INTF:
+                return 0;
+        case DATA_INTF:
+                TRACE_MSG1(acm->trace_tag,"START RECV: acm: %x", (int)acm);
+                TRACE_MSG2(acm->trace_tag,"START RECV: connected: %x recv_urbs: %d", 
+                                acm->flags & ACM_CONFIGURED, acm->recv_urbs);
+
+                local_irq_save(flags);
+                if (acm_ready(acm)) {
+
+                        TRACE_MSG2(acm->trace_tag,"START RECV: throttled: %d space_avail: %d", acm->flags & ACM_THROTTLED, 
+                                        acm->function_services->recv_space_available(acm, DATA_INTF));
+
+                        while (((acm->recv_urbs + 1) * 64) < acm->function_services->recv_space_available(acm, DATA_INTF)) {
+                                struct usbd_urb *urb;
+
+                                BREAK_IF(!(urb = usbd_alloc_urb(function, BULK_OUT, usbd_endpoint_transferSize(function, 
+                                                                BULK_OUT, usbd_high_speed(function)), acmfd_recv_urb)));
+                                acm->recv_urbs++;
+                                urb->function_privdata = acm;
+                                TRACE_MSG3(acm->trace_tag,"START RECV: %d urb#%p privdata#%p",acm->recv_urbs,urb,acm);
+                                CONTINUE_UNLESS (usbd_start_out_urb(urb));
+                                acm->recv_urbs--;
+                                TRACE_MSG1(acm->trace_tag,"START RECV: %d", acm->recv_urbs);
+                                usbd_free_urb(urb);
+                                break;
+                        }
+                        if (!acm->recv_urbs)
+                                acm_schedule_recv(acm, interface);
+                }
+                /* There needs to be at least one recv urb queued in order
+                 * to keep driving the push to the OS layer, so return how
+                 * many there are in case the OS layer must try again later.
+                 */
+                num_in_queue = acm->recv_urbs;
+                local_irq_restore(flags);
+                break;
+        }
+        return(num_in_queue);
+}
+
+
+struct acm_work acm_work;
+
+/*! acmfd_start_recv
+ * @param data
+ */
+STATIC void acmfd_start_recv(void *data) 
+{
+        struct acm_work *work = data;
+        struct acm_private *acm;
+        unsigned long flags;
+        int interface;
+
+        local_irq_save(flags);
+        acm = work->acm;
+        interface = work->interface;
+        work->acm = NULL;
+        work->interface = -1;
+        acm->recv_tqueue.data = NULL;
+        local_irq_restore(flags);
+        acmfd_start_recv_urbs(acm, interface);
+}
+
+
+/*! acm_schedule_recv
+ * @param acm
+ * @param interface
+ */
+void acm_schedule_recv(struct acm_private *acm, int interface)
+{
+        unsigned long flags;
+        struct acm_work *work = &acm_work;
+        TRACE_MSG1(acm->trace_tag, "sync: %d", acm->recv_tqueue.sync);
+        local_irq_save(flags);
+
+        UNLESS (acm->recv_tqueue.sync && acm->recv_tqueue.data) {
+                work->acm = acm;
+                work->interface = interface;
+                acm->recv_tqueue.routine = &acmfd_start_recv;
+                acm->recv_tqueue.data = work;
+                #if defined(LINUX24)
+                queue_task(&acm->recv_tqueue, &tq_timer);
+                #else
+                SCHEDULE_WORK(acm->recv_tqueue);
+                #endif
+        }
+
+        local_irq_restore(flags);
+}
+
+/* Transmit INTERRUPT ************************************************************************** */
+
+/*! acm_send_int_notfication
+ * Generates a response urb on the notification (INTERRUPT) endpoint.
+ * CALLED from interrupt context.
+ * @return non-zero if error
+ */
+STATIC int acm_send_int_notification(struct acm_private *acm, int bnotification, int data)
+{
+        struct usbd_function_instance *function = acm->function;
+        struct usbd_urb *urb = NULL;
+        struct cdc_notification_descriptor *notification;
+        unsigned long flags;
+        int rc = 0;
+
+        TRACE_MSG4(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d data: %04x",
+                        atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED, data);
+
+        RETURN_ZERO_UNLESS((acm->flags & ACM_CONFIGURED));
+
+        local_irq_save(flags);
+
+        do {
+                BREAK_IF(!(urb = usbd_alloc_urb(function, INT_IN,
+                                                sizeof(struct cdc_notification_descriptor),
+                                                acmfd_urb_sent_int))); 
+
+                urb->function_privdata = acm;
+
+                memset(urb->buffer, 0, urb->buffer_length);
+                urb->actual_length = sizeof(struct cdc_notification_descriptor);
+
+                /* fill in notification structure */
+                notification = (struct cdc_notification_descriptor *) urb->buffer;
+
+                notification->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+                notification->bNotification = bnotification;
+
+                switch (bnotification) {
+                case CDC_NOTIFICATION_NETWORK_CONNECTION:
+                        notification->wValue = data;
+                        break;
+                case CDC_NOTIFICATION_SERIAL_STATE:
+                        notification->wLength = cpu_to_le16(2);
+                        *((unsigned short *)notification->data) = cpu_to_le16(data);
+                        break;
+                }
+
+                BREAK_IF(!(rc = usbd_start_in_urb (urb)));
+
+                urb->function_privdata = NULL;
+                usbd_free_urb (urb);
+
+                TRACE_MSG1(acm->trace_tag,"urbID#%04x --> 0",urbID(urb));
+
+        } while(0);
+
+        local_irq_restore(flags);
+        return(rc);
+}
+
+/* Callback functions for TX urb completion (function chosen when urb is allocated) ***********/
+
+/*! acmfd_urb_sent_bulk - called to indicate bulk URB transmit finished
+ * @param urb pointer to struct usbd_urb
+ * @param rc result
+ * @return non-zero for error
+ */
+STATIC int acmfd_urb_sent_bulk (struct usbd_urb *urb, int rc)
+{
+        struct acm_private *acm = urb->function_privdata;
+        struct usbd_function_instance *function;
+
+        TRACE_MSG2(acm->trace_tag,"entered urbID#%04x rc=%d",urbID(urb),rc);
+        TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
+                        atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
+
+        if (!urb || !(function = urb->function_instance)) {
+                TRACE_MSG1(acm->trace_tag,"urbID#%04x --> -EINVAL",urbID(urb));
+                return(-EINVAL);
+        }
+        TRACE_MSG1(acm->trace_tag,"IN length=%d",urb->actual_length);
+
+        atomic_sub(urb->actual_length, &acm->queued_bytes);
+        atomic_dec(&acm->queued_urbs);
+        urb->function_privdata = NULL;
+        usbd_free_urb (urb);
+        if (acm->flags & ACM_OPENED)
+                acm->function_services->schedule_wakeup_writers(acm);
+        TRACE_MSG1(acm->trace_tag,"urbID#%04x --> 0",urbID(urb));
+        return 0;
+}
+
+/*! acmfd_urb_sent_int - called to indicate int URB transmit finished
+ * @param urb pointer to struct usbd_urb
+ * @param rc result
+ * @return non-zero for error
+ */
+STATIC int acmfd_urb_sent_int (struct usbd_urb *urb, int rc)
+{
+        struct acm_private *acm = urb->function_privdata;
+        struct usbd_function_instance *function;
+
+        TRACE_MSG2(acm->trace_tag,"entered urbID#%04x rc=%d",urbID(urb),rc);
+        TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
+                        atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
+        if (!urb || !(function = urb->function_instance)) {
+                TRACE_MSG1(acm->trace_tag,"urbID#%04x --> -EINVAL",urbID(urb));
+                return(-EINVAL);
+        }
+        TRACE_MSG1(acm->trace_tag,"INT length=%d",urb->actual_length);
+
+        urb->function_privdata = NULL;
+        usbd_free_urb(urb);
+        TRACE_MSG1(acm->trace_tag,"urbID#%04x --> 0",urbID(urb));
+        return 0;
+}
+
+/*! acmfd_urb_sent_ep0 - called to indicate ep0 URB transmit finished
+ * @param urb pointer to struct usbd_urb
+ * @param rc result
+ * @return non-zero for error
+ */
+STATIC int acmfd_urb_sent_ep0 (struct usbd_urb *urb, int rc)
+{
+        struct acm_private *acm = urb->function_privdata;
+        struct usbd_function_instance *function;
+
+        TRACE_MSG2(acm->trace_tag,"entered urbID#%04x rc=%d",urbID(urb),rc);
+        TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
+                        atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
+
+        RETURN_EINVAL_IF (!urb || !(function = urb->function_instance));
+        
+        TRACE_MSG1(acm->trace_tag,"INT length=%d",urb->actual_length);
+
+        urb->function_privdata = NULL;
+        usbd_free_urb(urb);
+        return 0;
+}
+
+/* USB Device Functions ************************************************************************ */
+
+typedef enum mesg {
+        mesg_unknown,
+        mesg_configured,
+        mesg_reset,
+} mesg_t;
+mesg_t acm_last_mesg;
+
+char * acm_messages[3] = {
+        "",
+        "ACM Configured",
+        "ACM Reset",
+};
+
+
+/*! acmfd_check_mesg
+ * @param curr_mesg
+ */
+void acmfd_check_mesg(mesg_t curr_mesg)
+{
+        RETURN_UNLESS(acm_last_mesg != curr_mesg);
+        acm_last_mesg = curr_mesg;
+        otg_message(acm_messages[curr_mesg]);
+}
+
+
+/*! acmfd_event_handler - process a device event
+ * @param function
+ * @param event
+ * @param data
+ */
+void acmfd_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
+{
+        struct acm_private *acm = function->privdata;
+        int i;
+
+        TRACE_MSG1(acm->trace_tag,"entered ev: %d",event);
+        TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d ready: %d", atomic_read(&acm->used), MOD_IN_USE, acm_ready(acm));
+
+        switch (event) {
+
+        case DEVICE_CONFIGURED:
+                TRACE_MSG0(acm->trace_tag,"CONFIGURED");
+                acm->flags |= ACM_CONFIGURED;
+                acmfd_check_mesg(mesg_configured);
+                acmfd_start_recv_urbs(acm, DATA_INTF);
+                break;
+
+        case DEVICE_RESET:
+        case DEVICE_DE_CONFIGURED:
+                TRACE_MSG0(acm->trace_tag,"RESET");
+
+                /* if configured and open then schedule hangup
+                 */
+                if ((acm->flags & ACM_OPENED) && (acm->flags & ACM_CONFIGURED))
+                        acm->function_services->schedule_hangup(acm);
+
+                acm->flags &= ~(ACM_CONFIGURED | ACM_CARRIER);
+                acmfd_check_mesg(mesg_reset);
+                BREAK_IF(!acm->flags & ACM_CONFIGURED);
+                TRACE_MSG0(acm->trace_tag,"RESET continue");
+                // XXX flush
+                // Release any queued urbs
+                break;
+
+        default:
+                break;
+        }
+        TRACE_MSG0(acm->trace_tag,"exited");
+}
+
+/*! acm_write_room
+ * @param acm
+ * @param interface
+ * @return non-zero if error
+ */
+STATIC int acm_write_room(struct acm_private *acm, int interface)
+{
+        switch (interface) {
+        case COMM_INTF:
+                return 0;
+        case DATA_INTF:
+                return (!acm->function || max_queued_urbs <= atomic_read(&acm->queued_urbs) ||
+                                max_queued_bytes <= atomic_read(&acm->queued_bytes) ) ?  0 : acm->writesize ;
+        }
+        return 0;
+}
+
+/*! acm_chars_in_buffer
+ * @param acm
+ * @param interface
+ * @return non-zero if error
+ */
+STATIC int acm_chars_in_buffer(struct acm_private *acm, int interface)
+{
+        int rc;
+        switch (interface) {
+        case COMM_INTF:
+                return 0;
+        case DATA_INTF:
+                return atomic_read(&acm->queued_bytes);
+        }
+        return 0;
+}
+
+static int throttle_count = 0;
+static int unthrottle_count = 0;
+
+/*! acm_throttle
+ * @param acm
+ * @param interface
+ */
+STATIC void acm_throttle(struct acm_private *acm, int interface)
+{
+        switch (interface) {
+        case COMM_INTF:
+                break;
+        case DATA_INTF:
+                throttle_count += 1;
+                TRACE_MSG1(acm->trace_tag,"entered %d",throttle_count);
+                acm->flags |= ACM_THROTTLED;
+                TRACE_MSG1(acm->trace_tag,"exited %d",throttle_count);
+                break;
+        }
+}
+
+/*! acm_unthrottle
+ * @param acm
+ * @param interface
+ */
+STATIC void acm_unthrottle(struct acm_private *acm, int interface)
+{
+        switch (interface) {
+        case COMM_INTF:
+                break;
+        case DATA_INTF:
+                unthrottle_count += 1;
+                TRACE_MSG1(acm->trace_tag,"entered %d",unthrottle_count);
+                acm->flags &= ~ACM_THROTTLED;
+                TRACE_MSG1(acm->trace_tag,"exited %d",unthrottle_count);
+                UNLESS(acm->recv_urbs)
+                        acm_schedule_recv(acm, interface);
+                break;
+        }
+}
+
+/*! acm_xmit_chars
+ * @param acm
+ * @param interface
+ * @param count
+ * @param from_user
+ * @param buf
+ * @return number of bytes sent.
+ */
+STATIC int acm_xmit_chars(struct acm_private *acm, int interface, int count, int from_user, const unsigned char *buf)
+{
+        struct usbd_function_instance *function = acm->function;
+        struct usbd_urb *urb;
+
+        RETURN_ZERO_UNLESS((acm->flags & ACM_CONFIGURED) /*&& (acm->flags & ACM_CARRIER)*/);
+
+        TRACE_MSG2(acm->trace_tag, "count: %d from_user: %d", count, from_user);   
+
+        switch (interface) {
+        case COMM_INTF:
+                return 0;
+        case DATA_INTF:
+                // sanity check and are we connect
+                RETURN_ZERO_UNLESS(atomic_read(&acm->used));
+                TRACE_MSG0(acm->trace_tag,"used OK");
+                RETURN_ZERO_UNLESS (count);
+                RETURN_ZERO_UNLESS (acm->flags & ACM_CONFIGURED);
+                TRACE_MSG0(acm->trace_tag,"connected OK");  
+                RETURN_ZERO_IF(max_queued_urbs <= atomic_read(&acm->queued_urbs));
+                TRACE_MSG0(acm->trace_tag,"max_queued_urbs OK");
+
+                // allocate a write urb
+                count = MIN(count, acm->writesize);
+
+                RETURN_ZERO_UNLESS ((urb = usbd_alloc_urb (function, BULK_IN, count, acmfd_urb_sent_bulk)));
+
+                if (from_user)
+                        copy_from_user ((void *)urb->buffer, (void *)buf, count);
+                else
+                        memcpy ((void *)urb->buffer, (void *)buf, count);
+
+                urb->function_privdata = acm;
+                urb->actual_length = count;
+                atomic_add(count, &acm->queued_bytes);
+                atomic_inc(&acm->queued_urbs);
+                usbd_start_in_urb(urb);
+                TRACE_MSG2(acm->trace_tag,"urbID#%04x --> count: %d",urbID(urb),count);
+                return count;
+        default:
+                break;
+        }
+        return 0;
+}
+
+/*! acmfd_recv_urb
+ * @param urb
+ * @param rc
+ * @return non-zero if error
+ */
+STATIC int acmfd_recv_urb (struct usbd_urb *urb, int rc)
+{
+        /* Return 0 if urb has been accepted,
+         * return 1 and expect caller to deal with urb release otherwise. 
+         */
+        struct acm_private *acm = urb->function_privdata;
+        unsigned long flags;
+
+        local_irq_save(flags);
+        acm->recv_urbs--;               // this could probably be atomic operation....
+        local_irq_restore(flags);
+
+        if (RECV_CANCELLED == rc) {
+                TRACE_MSG1(acm->trace_tag,"cancelled URB=%p",urb);
+                return -EINVAL;
+        }
+        if (RECV_OK != rc) {
+                TRACE_MSG2(acm->trace_tag,"rejected URB=%p rc=%d",urb,rc);
+                usbd_free_urb(urb);
+                acm_schedule_recv(acm, DATA_INTF);
+                //acmfd_start_recv_urbs(acm, DATA_INTF);
+                return 0;
+        }
+
+        /* loopback mode
+         */
+        if (acm->flags & ACM_LOOPBACK) 
+                acm_xmit_chars(acm, DATA_INTF, urb->actual_length, 0, urb->buffer);
+
+        /* acmfd_start_recv_urbs() will never queue more urbs than there is currently
+         * room in the upper layer buffer for. So we are guaranteed that any data actually
+         * received can be given to the upper layers without worrying if we will 
+         * actually have room. 
+         */
+        else 
+                if ((rc = acm->function_services->recv_chars(acm, DATA_INTF, urb->buffer, urb->actual_length))) 
+                        return(rc); // XXX
+
+
+        acm->bytes_received += urb->actual_length;
+        TRACE_MSG1(acm->trace_tag,"bytes_received: %d",acm->bytes_received);
+        usbd_free_urb(urb);
+        acm_schedule_recv(acm, DATA_INTF);
+        return 0;
+
+#if 0
+        // XXX it may be reasonable to schedule here....
+        UNLESS (acmfd_start_recv_urbs(acm, DATA_INTF)) {
+                /* If start recv returns zero it means that there are no-queued urbs,
+                 * and we should queue a work item to restart.
+                 */
+                acm_schedule_recv(acm, DATA_INTF);
+        }
+#endif
+        return 0;
+}
+
+/*! acmfd_line_coding_urb_received - callback for sent URB
+ *
+ * Handles notification that an urb has been sent (successfully or otherwise).
+ *
+ * @param urb
+ * @param urb_rc
+ * @return non-zero for failure.
+ */
+STATIC int acmfd_line_coding_urb_received (struct usbd_urb *urb, int urb_rc)
+{
+        struct acm_private *acm = urb->function_privdata;
+        TRACE_MSG2(acm->trace_tag,"urbID#%04x rc=%d",urbID(urb),urb_rc);
+
+        RETURN_EINVAL_IF (RECV_OK != urb_rc);
+        RETURN_EINVAL_IF (urb->actual_length < sizeof(struct cdc_acm_line_coding));
+
+        RETURN_EINVAL_UNLESS (memcpy(&acm->line_coding, urb->buffer, sizeof(struct cdc_acm_line_coding)));
+
+        // something changed, copy and notify
+        
+        memcpy(&acm->line_coding, urb->buffer, sizeof(struct cdc_acm_line_coding));
+
+        // XXX notify application if baudrate has changed
+
+        return -EINVAL;         // caller will de-allocate
+}
+
+/*! acmfd_device_request - called to indicate urb has been received
+ * @param function
+ * @param request
+ * @return non-zero if error
+ */
+int acmfd_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
+{
+        struct acm_private *acm = (struct acm_private *) (function->privdata);
+
+        TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
+                        atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
+
+        TRACE_SETUP(acm->trace_tag,request);
+
+        // verify that this is a usb class request per cdc-acm specification or a vendor request.
+        if (!(request->bmRequestType & (USB_REQ_TYPE_CLASS | USB_REQ_TYPE_VENDOR))) {
+                TRACE_MSG0(acm->trace_tag,"--> 0");
+                return(0);
+        }
+
+        // determine the request direction and process accordingly
+        switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
+
+        case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_CLASS:
+                switch (request->bRequest) {
+                case CDC_CLASS_REQUEST_SEND_ENCAPSULATED: break;
+                case CDC_CLASS_REQUEST_SET_COMM_FEATURE: break;
+                case CDC_CLASS_REQUEST_CLEAR_COMM_FEATURE: break;
+                case CDC_CLASS_REQUEST_SET_LINE_CODING:
+                        {
+                                struct usbd_urb *urb;
+                                int len = le16_to_cpu(request->wLength);
+                                TRACE_MSG1(acm->trace_tag,"SET_LINE_CODING wLength=%d",len);
+                                if (len <= 0) {
+                                        TRACE_MSG0(acm->trace_tag,"(len<=0)--> 0");
+                                        return(0);
+                                }
+
+                                /* Set up an ep0 recv urb for the rest of it. */
+                                UNLESS ((urb = usbd_alloc_urb_ep0(function, len, acmfd_line_coding_urb_received))) {
+                                        TRACE_MSG0(acm->trace_tag,"no mem for ep0 recv urb");
+                                        return(-ENOMEM);
+                                }
+                                urb->function_privdata = acm;
+                                if (usbd_start_out_urb(urb)) {
+                                        TRACE_MSG0(acm->trace_tag,"usbd_start_out_urb() failed");
+                                        usbd_free_urb(urb);          // de-alloc if error
+                                        TRACE_MSG0(acm->trace_tag,"--> -EINVAL");
+                                        return(-EINVAL);
+                                }
+                        }
+                        break;
+
+                case CDC_CLASS_REQUEST_SET_CONTROL_LINE_STATE:
+                        {
+                                unsigned int prev_bmLineState = acm->bmLineState;
+                                acm->bmLineState = le16_to_cpu(request->wValue);
+
+                                // schedule writers or hangup IFF open
+                                BREAK_IF(!acm->privdata);
+                                TRACE_MSG3(acm->trace_tag,"set control state, bmLineState: %04x previous: %04x changed: %04x",
+                                                acm->bmLineState, prev_bmLineState, acm->bmLineState ^ prev_bmLineState);
+
+                                // make sure there really is a state change
+                                if ((acm->bmLineState ^ prev_bmLineState) & CDC_LINESTATE_D0_DTR) {
+
+                                        TRACE_MSG1(acm->trace_tag,"DTR state changed -> %x",
+                                                        (acm->bmLineState & CDC_LINESTATE_D0_DTR));
+
+                                        if (acm->bmLineState & CDC_LINESTATE_D0_DTR) {
+                                                if (acm->flags & ACM_OPENED)
+                                                        acm->function_services->schedule_wakeup_writers(acm);
+                                                acm->flags |= ACM_CARRIER;
+                                                acm_schedule_recv(acm, DATA_INTF);
+                                        }
+                                        else {
+                                                if (acm->flags & ACM_OPENED)
+                                                        acm->function_services->schedule_hangup(acm);
+
+                                                acm->flags &= ~ACM_CARRIER;
+                                                acm_flush(acm, DATA_INTF);
+                                        }
+                                        
+                                        /* wake up blocked opens */
+                                        acm->function_services->wakeup_opens(acm);
+
+                                        /* wake up blocked ioctls */
+                                        acm->function_services->wakeup_state(acm);
+
+                                }
+
+
+
+                                /* send notification if we have DCD */
+                                TRACE_MSG2(acm->trace_tag,"bmUARTState: %04x privdata: %p sending (DCD|DSR) notification",
+                                                acm->bmUARTState, acm->privdata);
+                                
+                                acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
+                        }
+                        break;
+
+                case CDC_CLASS_REQUEST_SEND_BREAK: break;
+                default: break;
+                }
+                TRACE_MSG0(acm->trace_tag,"--> 0");
+                return 0;
+
+        case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_CLASS:
+                switch (request->bRequest) {
+                case CDC_CLASS_REQUEST_GET_ENCAPSULATED: break;
+                case CDC_CLASS_REQUEST_GET_COMM_FEATURE: break;
+                case CDC_CLASS_REQUEST_GET_LINE_CODING: 
+                        {
+                                struct usbd_urb *urb;
+                                RETURN_ENOMEM_IF (!(urb = usbd_alloc_urb_ep0(function, sizeof(struct cdc_acm_line_coding), 
+                                                                acmfd_urb_sent_ep0)));
+                                urb->function_privdata = acm;
+
+                                memcpy(urb->buffer, &acm->line_coding, sizeof(struct cdc_acm_line_coding));
+
+                                urb->actual_length = sizeof(struct cdc_acm_line_coding);
+
+                                TRACE_MSG1(acm->trace_tag,"sending line coding urb: %p",(u32)(void*)urb);
+                                RETURN_ZERO_UNLESS(usbd_start_in_urb(urb));
+                                usbd_free_urb(urb);
+                                TRACE_MSG0(acm->trace_tag,"(send failed)--> -EINVAL");
+                        }
+                        return -EINVAL;
+                default: break;
+                }
+                TRACE_MSG0(acm->trace_tag,"--> 0");
+                return 0;
+
+        case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_VENDOR: break;
+        case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_VENDOR: break;
+
+        default: break;
+        }
+        TRACE_MSG0(acm->trace_tag,"--> 0");
+        return 0;
+}
+
+
+/*! acmfd_function_enable
+ * @param function
+ * @return non-zero if error
+ */
+STATIC int acmfd_function_enable (struct usbd_function_instance *function)
+{
+        struct acm_private *acm = (struct acm_private *) (function->privdata);
+        
+        TRACE_MSG0(acm->trace_tag,"entered");
+        TRACE_MSG1(acm->trace_tag,"INC: %d", MOD_IN_USE);
+        acm->function_services->enable(function);
+        acm->writesize = usbd_endpoint_wMaxPacketSize(function, BULK_OUT, 0) * 24;
+
+        TRACE_MSG0(acm->trace_tag,"-> 0");
+        return 0;
+}
+
+/*! acmfd_function_disable
+ * @param function
+ */
+STATIC void acmfd_function_disable (struct usbd_function_instance *function)
+{
+        struct acm_private *acm = (struct acm_private *) (function->privdata);
+        
+        TRACE_MSG0(acm->trace_tag,"entered");
+        acm->writesize = 0;
+        acm->function_services->disable(function);
+        TRACE_MSG1(acm->trace_tag,"DEC: %d", MOD_IN_USE);
+        TRACE_MSG0(acm->trace_tag,"exited");
+}
+
+
+/*! function_ops 
+ */
+struct usbd_function_operations function_ops = {
+        event_handler: acmfd_event_handler,
+        device_request: acmfd_device_request,
+        function_enable: acmfd_function_enable,
+        function_disable: acmfd_function_disable,
+};
+
+/*! acm_fd_init
+ * @param acm
+ * @param usbd_module_info
+ * @param vendor_id
+ * @param product_id
+ * @param wmax_urbs
+ * @param wmax_bytes
+ * @return non-zero if error
+ */
+STATIC int acm_fd_init(struct acm_private *acm, char *usbd_module_info, u32 vendor_id, u32 product_id,
+                            u32 wmax_urbs, u32 wmax_bytes)
+{
+        
+        TRACE_MSG0(acm->trace_tag,"entered");
+
+        if (vendor_id) 
+                acm->function_driver->idVendor = cpu_to_le16(vendor_id);
+        if (product_id) 
+                acm->function_driver->idProduct = cpu_to_le16(product_id);
+        max_queued_urbs = wmax_urbs;
+        max_queued_bytes = wmax_bytes;
+
+        THROW_IF (NULL == (acm->function = usbd_register_function (acm->function_driver, "acm-fd", acm)), error);
+
+        CATCH(error) {
+                printk(KERN_ERR"%s: ERROR\n", __FUNCTION__);
+
+                if (acm->function) {
+                        usbd_deregister_function (acm->function);
+                        acm->function = NULL;
+                }
+                TRACE_MSG0(acm->trace_tag,"--> -EINVAL");
+                return -EINVAL;
+        }
+        TRACE_MSG0(acm->trace_tag,"--> 0");
+        return 0;
+}
+
+
+
+/*! acm_wait_task
+ * @param acm
+ * @param queue
+ */
+void acm_wait_task(struct acm_private *acm, WORK_ITEM *queue)
+{
+        TRACE_MSG1(acm->trace_tag,"entered data=%p",queue->data);
+        RETURN_IF(!queue->data);
+        queue->data = NULL;
+#if defined(LINUX24)
+        while (queue->sync) {
+                TRACE_MSG1(acm->trace_tag,"waiting for queue: %p",queue);
+                schedule_timeout(HZ);
+        }
+#else
+        while(PENDING_WORK_ITEM((*queue))){
+                TRACE_MSG1(acm->trace_tag,"waiting for queue: %p",queue);
+                SCHEDULE_TIMEOUT(1);  // 1 second delay 
+        }
+#endif
+        TRACE_MSG0(acm->trace_tag,"exited");
+}
+
+
+/*! acm_get_dtr
+ * Get DTR status.
+ */
+int acm_get_dtr(struct acm_private *acm)
+{
+        return (acm->bmLineState & CDC_LINESTATE_D0_DTR) ? 1 : 0;
+}
+
+/*! acm_get_dsr
+ * Get DSR status
+ */
+int acm_get_dsr(struct acm_private *acm)
+{
+        return (acm->bmUARTState & CDC_UARTSTATE_BTXCARRIER_DSR) ? 1 : 0;
+}
+
+/*! acm_get_dcd
+ * Get DCD status
+ */
+int acm_get_dcd(struct acm_private *acm)
+{
+        return (acm->bmUARTState & CDC_UARTSTATE_BRXCARRIER_DCD) ? 1 : 0;
+}
+
+/*! acm_set_dsr
+ * Set DSR status
+ * @param acm
+ * @param value
+ */
+void acm_set_dsr(struct acm_private *acm, int value)
+{
+        acm->bmUARTState &= ~CDC_UARTSTATE_BTXCARRIER_DSR;
+        acm->bmUARTState |= value ? CDC_UARTSTATE_BTXCARRIER_DSR : 0;
+        acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
+}
+
+/*! acm_set_dcd
+ * Set DCD status
+ * @param acm
+ * @param value
+ */
+void acm_set_dcd(struct acm_private *acm, int value)
+{
+        acm->bmUARTState &= ~CDC_UARTSTATE_BRXCARRIER_DCD;
+        acm->bmUARTState |= value ? CDC_UARTSTATE_BRXCARRIER_DCD : 0;
+        acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
+}
+
+/*! acm_ring
+ * Indicate Ring signal to host.
+ */
+void acm_ring(struct acm_private *acm)
+{
+        acm->bmUARTState |= CDC_UARTSTATE_BRINGSIGNAL;
+        acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
+        acm->bmUARTState &= ~CDC_UARTSTATE_BRINGSIGNAL;
+}
+
+/*! acm_send_break
+ * Indicate Break signal to host.
+ */
+void acm_send_break(struct acm_private *acm)
+{
+        acm->bmUARTState |= CDC_UARTSTATE_BBREAK;
+        acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
+        acm->bmUARTState &= ~CDC_UARTSTATE_BBREAK;
+}
+
+/*! acm_overrun
+ * Indicate Overrun signal to host.
+ */
+void acm_overrun(struct acm_private *acm)
+{
+        acm->bmUARTState |= CDC_UARTSTATE_BOVERRUN;
+        acm_send_int_notification(acm, CDC_NOTIFICATION_SERIAL_STATE, acm->bmUARTState);
+        acm->bmUARTState &= ~CDC_UARTSTATE_BOVERRUN;
+}
+
+/*! acm_set_local
+ * Set LOCAL status
+ * @param acm
+ * @param value
+ */
+void acm_set_local(struct acm_private *acm, int value)
+{
+        acm->flags &= ~ACM_LOCAL;
+        acm->flags |= value ? ACM_LOCAL : 0;
+}
+
+/*! acm_set_loopback
+ * Set LOOPBACK status
+ * @param acm
+ * @param value
+ */
+void acm_set_loopback(struct acm_private *acm, int value)
+{
+        acm->flags &= ~ACM_LOOPBACK;
+        acm->flags |= value ? ACM_LOOPBACK : 0;
+}
+
+
+
+/*! acm_fd_term
+ * @param acm
+ */
+STATIC void acm_fd_exit(struct acm_private *acm)
+{
+        //acm_wait_task(acm->recv_tqueue);
+        RETURN_UNLESS (acm->function);
+        usbd_deregister_function (acm->function);
+        acm->function = NULL;
+}
+
+/*!
+ * Function table exported to the OS specific upper layer.
+ */
+struct acm_usb_services acm_fd_usb_ops = {
+        .fd_init = acm_fd_init,
+        .fd_exit = acm_fd_exit,
+        .xmit_chars = acm_xmit_chars,
+        .send_int_notification = acm_send_int_notification,
+        .throttle = acm_throttle,
+        .unthrottle = acm_unthrottle,
+        .write_room = acm_write_room,
+        .chars_in_buffer = acm_chars_in_buffer,
+        .wait_task = acm_wait_task,
+        .schedule_recv = acm_schedule_recv,
+        .open = acm_open, 
+        .close = acm_close, 
+        .flush = acm_flush, 
+        .ready = acm_ready, 
+        .get_dtr = acm_get_dtr,
+        .get_dsr = acm_get_dsr,
+        .get_dcd = acm_get_dcd,
+        .set_dsr = acm_set_dsr,
+        .set_dcd = acm_set_dcd,
+        .ring = acm_ring,
+        .send_break = acm_send_break,
+        .overrun = acm_overrun,
+        .set_local = acm_set_local,
+        .set_loopback = acm_set_loopback,
+};
+
diff -uNr linux/drivers/no-otg/functions/acm/acm-fd.h linux/drivers/otg/functions/acm/acm-fd.h
--- linux/drivers/no-otg/functions/acm/acm-fd.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/acm-fd.h	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,242 @@
+/* 
+ * otg/functions/acm/acm-fd.h
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/functions/acm/acm-fd.h
+ * @brief ACM Function Driver private defines
+ *
+ * The top and bottom halves of the driver comunication via these structures.
+ *
+ * @ingroup ACMFunction
+ */
+
+#ifndef ACM_FD_H
+#define ACM_FD_H 1
+
+typedef void (*cpy_fn)(u8 *dst, u8 *src, int len);
+
+/*! acm_usb_services
+ * Services that the acm_fd library provides.
+ */
+struct acm_usb_services {
+
+        /*! fd_init - called to initialize the acm_fd library
+         * This call initialized the acm_fd library and registers the function driver 
+         * with the USB Peripheral Stack.
+         */
+        int (*fd_init)(struct acm_private *acm, char *inf, u32 vendor_id, u32 product_id, u32 wmax_urbs, u32 wmax_bytes);
+
+        /*! fd_exit - called before exiting
+         * This call will cause the function driver to be de-registered.
+         */
+        void (*fd_exit)(struct acm_private *acm);
+
+        /*! open - device open
+         * This is called the device is opened (first open only if non-exclusive opens allowed).
+         */
+        int (*open)(struct acm_private *acm, int interface);
+
+        /*! close - Device close
+         * This is called when the device closed (last close only if non-exclusive opens allowed.)
+         */
+        int (*close)(struct acm_private *acm, int interface);
+
+
+        /*! flush - flush data urbs.
+         * Cancel outstanding data urbs.
+         */
+        void (*flush)(struct acm_private *acm, int interface);
+
+        /*! schedule_recv - queue as many data receive urbs as possible
+         * This will schedule a bottom half hander that will will start as
+         * many receive data urbs as are allowed given the amount of room
+         * available in the upper layer. If no urbs are queued by the
+         * bottom half handler it will re-schedule itself.
+         */
+        void (*schedule_recv)(struct acm_private *acm, int interface);
+
+        /*! throttle - set throttle flag for specified interface
+         * Receive urbs will not be queued when throttled.
+         */
+        void (*throttle)(struct acm_private *acm, int interface);
+
+        /*! unthrottle - reset throttle flag for specified interface
+         * Receive urbs are allowed to be queued. If no urbs are queued a
+         * bottom half handler will be scheduled to queue them.
+         */
+        void (*unthrottle)(struct acm_private *acm, int interface);
+
+
+        /*! xmit_chars - send data via specified interface
+         * This will start a transmit urb to send the specified data. The
+         * number of characters sent will be returned.
+         */
+        int (*xmit_chars)(struct acm_private *acm, int interface, int count, int from_user, const unsigned char *buf);
+
+        /*! write_room
+         * Return amount of data that could be queued for sending.
+         */
+        int (*write_room)(struct acm_private *acm, int interface);
+
+        /*! chars_in_buffer
+         * Return number of chars in xmit buffer.
+         */
+        int (*chars_in_buffer)(struct acm_private *acm, int interface);
+
+
+        /*! send_int_notification - send notification via interrupt endpoint
+         *  This can be used to queue network, serial state change notifications.
+         */
+        int (*send_int_notification)(struct acm_private *acm, int bnotification, int data);
+
+        /*! wait_task - wait for task to complete.
+        */
+        void (*wait_task)(struct acm_private *acm, WORK_ITEM *queue);
+
+        /*! ready - return true if connected and carrier
+        */
+        int (*ready)(struct acm_private *acm);
+
+        /*! get_dtr
+         * Get DTR status.
+         */
+        int (*get_dtr)(struct acm_private *acm);
+
+        /*! get_dsr
+         * Get DSR status
+         */
+        int (*get_dsr)(struct acm_private *acm);
+
+        /*! get_dcd
+         * Get DCD status
+         */
+        int (*get_dcd)(struct acm_private *acm);
+
+        /*! set_dsr
+         * Set DSR status
+         */
+        void (*set_dsr)(struct acm_private *acm, int value);
+
+        /*! set_dcd
+         * Set DCD status
+         */
+        void (*set_dcd)(struct acm_private *acm, int value);
+
+        /*! ring
+         * Indicate Ring signal to host.
+         */
+        void (*ring)(struct acm_private *acm);
+
+        /*! send_break
+         * Indicate Break signal to host.
+         */
+        void (*send_break)(struct acm_private *acm);
+
+        /*! overrun
+         * Indicate Overrun signal to host.
+         */
+        void (*overrun)(struct acm_private *acm);
+
+
+        /*! set_local
+         * Set LOCAL status
+         */
+        void (*set_local)(struct acm_private *acm, int value);
+
+        /*! set_loopback - set loopback mode
+         * Sets LOOP flag, data received from the host will be immediately
+         * returned without passing to the upper layer.
+         */
+        void (*set_loopback)(struct acm_private *acm, int value);
+};
+
+/*! acm_function_services
+ * Services that the top level driver provides to the lower library.
+ */
+struct acm_function_services {
+        /*! enable
+         * Enable the function driver.
+         */
+        void (*enable)(struct usbd_function_instance *function);
+
+        /*! disable
+         * Disable the function driver.
+         */
+        void (*disable)(struct usbd_function_instance *function);
+
+        /*! wakeup_opens
+         * Wakeup processes waiting for DTR.
+         */
+        void (*wakeup_opens)(struct acm_private *acm);
+
+        /*! wakeup_opens
+         * Wakeup processes waiting for state change.
+         */
+        void (*wakeup_state)(struct acm_private *acm);
+
+        /*! wakeup writers
+         * Wakeup pending writes.
+         */
+        void (*schedule_wakeup_writers)(struct acm_private *acm);
+
+        /*! recv_space_available
+         * Check for amount of receive space that is available, controls
+         * amount of receive urbs that will be queued.
+         */
+        int (*recv_space_available)(struct acm_private *acm, int interface);
+
+        /*! recv_chars
+         * Process chars received on specified interface.
+         */
+        int (*recv_chars)(struct acm_private *acm, int interface, u8 *cp, int n);
+
+
+        /*! schedule_hangup
+         * Schedule a work item that will perform a hangup.
+         */
+        void (*schedule_hangup)(struct acm_private *acm);
+
+        /*! comm_feature
+         * Tell function that comm feature has changed.
+         */
+        void (*comm_feature)(struct acm_private *acm);
+
+        /*! line_coding
+         * Tell function that line coding has changed.
+         */
+        void (*line_coding)(struct acm_private *acm);
+
+        /*! control_state
+         * Tell function that control state has changed.
+         */
+        void (*control_state)(struct acm_private *acm);
+
+        /*! send_break
+         * Tell function to send a break signal.
+         */
+        void (*send_break)(struct acm_private *acm);
+
+};
+
+extern struct acm_usb_services acm_fd_usb_ops;
+extern struct usbd_function_operations function_ops;
+
+
+/*
+ * otg-trace tag.
+ */
+extern otg_tag_t acm_fd_trace_tag;
+
+#define MAX_QUEUED_BYTES        256
+#define MAX_QUEUED_URBS         10     // Max for write
+
+
+#endif
diff -uNr linux/drivers/no-otg/functions/acm/acm-os.h linux/drivers/otg/functions/acm/acm-os.h
--- linux/drivers/no-otg/functions/acm/acm-os.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/acm-os.h	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,74 @@
+/*
+ * otg/functions/acm/acm-os.h
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ */
+/*!
+ * @file otg/functions/acm/acm-os.h
+ * @brief ACM Function Driver private defines
+ *
+ * An ACM (Abstract Control Model) driver is composed of two pieces:
+ *    1) An OS specific piece that handles creating and operating
+ *       a serial device for the given OS.
+ *    2) A USB specific piece that interfaces either with the host
+ *       usbcore layer, or with the otgcore layer.
+ *
+ * If the USB piece interfaces with the host usbcore layer you get
+ * an ACM class driver.  If the USB piece interfaces with the otgcore
+ * layer you get an ACM function driver.
+ *
+ * This file describes the functions exported by the various acm-*-os.c
+ * files (implementing (1)) for use in acm-fd.c (2).
+ *
+ * @ingroup ACMFunction
+ */
+
+#ifndef ACM_OS_H
+#define ACM_OS_H 1
+
+/*
+ * acm_os_recv_space_available - return the number of bytes of data
+ *                               the OS specific piece can accept without
+ *                               dropping some.
+ */
+extern int acm_os_recv_space_available(struct acm_private *acm);
+
+/*
+ * acm_os_recv_chars - receive n bytes starting at cp.  This will never be
+ *                     more than the last call to acm_os_recv_space_available().
+ *                     This will be called from interrupt context.
+ */
+extern int acm_os_recv_chars(struct acm_private *acm, u8 *cp, int n);
+
+/*
+ * acm_os_wakeup_writers - wakeup any blocked writers.  This is called
+ *                         from interrupt context, so may need to queue
+ *                         the actual wakeup in a "bottom half".
+ */
+extern void acm_os_wakeup_writers(struct acm_private *acm);
+
+/*
+ * acm_os_hangup - send a hangup to any readers or writers.  This can be
+ *                 called from interrupt context, so may need to queue
+ *                 the actual hangup in a "bottom half".
+ */
+extern void acm_os_hangup(struct acm_private *acm);
+
+/*
+ * acm_os_wakeup_opens - wakeup any blocked opens.  This is called
+ *                       from interrupt context, so may need to queue
+ *                       the actual wakeup in a "bottom half".
+ */
+extern void acm_os_wakeup_opens(struct acm_private *acm);
+
+extern void acm_os_enable(struct usbd_function_instance *function);
+extern void acm_os_disable(struct usbd_function_instance *function);
+
+#endif
diff -uNr linux/drivers/no-otg/functions/acm/acm.h linux/drivers/otg/functions/acm/acm.h
--- linux/drivers/no-otg/functions/acm/acm.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/acm.h	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,113 @@
+/*
+ * otg/functions/acm/acm.h
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+/*!
+ * @defgroup ACMFunction ACM
+ * @ingroup functiongroup 
+ */
+
+/*!
+ * @file otg/functions/acm/acm.h
+ * @brief ACM Function Driver private defines
+ *
+ * This is an ACM Function Driver. The upper edge is exposed
+ * to the hosting OS as a Posix type character device. The lower
+ * edge implements the USB Device Stack API.
+ *
+ * This driver implements the CDC ACM driver model and uses the CDC ACM
+ * protocols. 
+ *
+ * Note that it appears to be impossible to determine the end of a receive
+ * bulk transfer larger than wMaxPacketsize. The host is free to send
+ * wMaxPacketsize chars in a single transfer. This means that we cannot
+ * queue receive urbs larger than wMaxPacketsize (typically 64 bytes.)
+ *
+ * This does not however prevent queuing transmit urbs with larger amounts
+ * of data. It is interpreted at the receiving (host) end as a series of
+ * wMaxPacketsize transfers but because there is no interpretation to the
+ * amounts of data sent it does affect anything if we treat the data as a
+ * single larger transfer.
+ *
+ * @ingroup ACMFunction
+ */
+
+
+// Endpoint indexes in acm_endpoint_requests[] and the endpoint map.
+#define BULK_OUT        0x00
+#define BULK_IN         0x01
+#define INT_IN          0x02
+#define ENDPOINTS       0x03
+
+#define COMM_INTF       0x00
+#define DATA_INTF       0x01
+
+
+
+// Most hosts don't care about BMAXPOWER, but the UUT tests want it to be 1
+#define BMAXPOWER   1
+#define BMATTRIBUTE 0
+
+#define STATIC
+//#define STATIC static
+//
+
+/*! @name ACM Flags
+ * @{
+ */
+#define ACM_OPENED      (1 << 0)        /*!< upper layer has opened the device port */
+#define ACM_CONFIGURED  (1 << 1)        /*!< device is configured */
+#define ACM_THROTTLED   (1 << 2)        /*!< upper layer doesn't want to receive data  */
+#define ACM_CARRIER     (1 << 3)        /*!< host has set DTR, i.e. host has opened com device */
+#define ACM_LOOPBACK    (1 << 4)        /*!< upper layer wants local loopback */
+#define ACM_LOCAL       (1 << 5)        /*!< upper layer specified LOCAL mode */
+
+/*! @} */
+
+/*! struct acm_private
+ */
+struct acm_private {
+        struct usbd_function_instance *function;
+        struct usbd_function_driver *function_driver;
+        struct acm_function_services *function_services;
+        otg_tag_t trace_tag;
+
+        u32 flags;
+
+        int recv_urbs;
+        atomic_t used;
+        atomic_t queued_bytes;
+        atomic_t queued_urbs;
+        unsigned int writesize;                 // packetsize * 4
+
+        /*TBR debug receive flow control */
+        unsigned long bytes_received;
+        unsigned long bytes_forwarded;
+        /*TBR end debug */
+
+        struct cdc_acm_line_coding line_coding; // C.f. Table 50 - [GS]ET_LINE_CODING Device Request (to/from host)
+        cdc_acm_bmUARTState bmUARTState;        // C.f. Table 51 - SET_CONTROL_LINE_STATE Device Request (from host)
+        cdc_acm_bmLineState bmLineState;        // C.f. Table 69 - SERIAL_STATE Notification (to host)
+
+
+
+        struct tq_struct recv_tqueue;
+
+        void *privdata;
+
+};
+
+
+struct acm_work {
+        struct acm_private *acm;
+        int interface;
+};
+
diff -uNr linux/drivers/no-otg/functions/acm/modem-l24-os.c linux/drivers/otg/functions/acm/modem-l24-os.c
--- linux/drivers/no-otg/functions/acm/modem-l24-os.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/modem-l24-os.c	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,194 @@
+/*
+ * otg/functions/acm/modem-l24-os.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/functions/acm/modem-l24-os.c
+ * @brief ACM Function Driver private defines
+ *
+ * An ACM (Abstract Control Model) driver is composed of two pieces:
+ *    1) An OS specific piece that handles creating and operating
+ *       a serial device for the given OS.
+ *    2) A USB specific piece that interfaces either with the host
+ *       usbcore layer, or with the otgcore layer.
+ *
+ * If the USB piece interfaces with the host usbcore layer you get
+ * an ACM class driver.  If the USB piece interfaces with the otgcore
+ * layer you get an ACM function driver.
+ *
+ * This file is the OS specific piece that interfaces with Linux
+ * (kernel versions 2.4.*).  It creates two simple characters devices.
+ * One for the data transport and one for the communications interface.
+ *
+ * @ingroup ACMFunction
+ */
+
+
+//#include <otg/osversion.h>
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+MOD_AUTHOR ("tbr@belcarra.com, sl@belcarra.com");
+
+MOD_DESCRIPTION ("Belcarra CDC-ACM Function");
+EMBED_LICENSE();
+
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include <linux/capability.h>
+#include <otg/otg-trace.h>
+#include "acm.h"
+#include "acm-fd.h"
+#include "acm-os.h"
+
+// May need an ifdef here to pick up the acm_cl_usb_ops in the future.
+static struct acm_usb_services *usb_ops = &acm_fd_usb_ops;
+
+#define MDM mdm_fd_trace_tag
+otg_tag_t mdm_fd_trace_tag;
+
+/* Module Parameters ************************************************************************* */
+
+static u32 vendor_id;
+static u32 product_id;
+static u32 max_queued_urbs = MAX_QUEUED_URBS;
+static u32 max_queued_bytes = MAX_QUEUED_BYTES;
+
+MOD_PARM (vendor_id, "i");
+MOD_PARM (product_id, "i");
+MOD_PARM (max_queued_urbs, "i");
+MOD_PARM (max_queued_bytes, "i");
+
+MOD_PARM_DESC (vendor_id, "Device Vendor ID");
+MOD_PARM_DESC (product_id, "Device Product ID");
+MOD_PARM_DESC (max_queued_urbs, "Maximum TX Queued Urbs");
+MOD_PARM_DESC (max_queued_bytes, "Maximum TX Queued Bytes");
+
+
+/* ACM ***************************************************************************************** */
+
+#define ACM_TTY_MAJOR   166
+#define ACM_TTY_MINOR   0
+#define ACM_TTY_MINORS  1
+
+static struct acm_private acm_private;
+
+/* USB Simple Char Device ********************************************************************** */
+
+
+/* USB Comm Char Device ************************************************************************ */
+
+
+/* USB Module init/exit ************************************************************************ */
+/*
+ * acm_modinit - module init
+ *
+ */
+STATIC int acm_modinit (void)
+{
+        int i;
+        printk (KERN_INFO "Copyright (c) 2003-2004 sl@belcarra.com, tbr@belcarra.com\n");
+        MDM = otg_trace_obtain_tag();
+
+        // initialize private structure
+        //acm_private.tty_driver = &acm_tty_driver;
+        //acm_private.wqueue.routine = acm_wakeup_writers;
+        //acm_private.wqueue.data = &acm_private;
+        //acm_private.hqueue.routine = acm_hangup;
+        //acm_private.hqueue.data = &acm_private;
+        //acm_private.recv_tqueue.routine = &acm_start_recv;
+        //acm_private.recv_tqueue.data = &acm_private;
+
+        //init_waitqueue_head(&acm_private.open_wait);
+
+
+        // register as usb function driver
+
+        THROW_IF (usb_ops->initialize_usb_part(&acm_private,"acm_fd",vendor_id,product_id,
+                                               max_queued_urbs,max_queued_bytes ), error);
+
+        CATCH(error) {
+                printk(KERN_ERR"%s: ERROR\n", __FUNCTION__);
+
+                TRACE_MSG0(MDM,"--> -EINVAL");
+                return -EINVAL;
+        }
+        TRACE_MSG0(MDM,"--> 0");
+        return 0;
+}
+
+void acm_wait_task(WORK_ITEM *queue)
+{
+        TRACE_MSG1(MDM,"entered data=%p",queue->data);
+        RETURN_IF(!queue->data);
+        queue->data = NULL;
+#if defined(LINUX24)
+        while (queue->sync) {
+                TRACE_MSG1(MDM,"waiting for queue: %p",queue);
+                schedule_timeout(HZ);
+        }
+#else
+        while(PENDING_WORK_ITEM((*queue))){
+                TRACE_MSG1(MDM,"waiting for queue: %p",queue);
+                SCHEDULE_TIMEOUT(1);  // 1 second delay 
+        }
+#endif
+        TRACE_MSG0(MDM,"exited");
+}
+
+/* acm_modexit - module cleanup
+ */
+STATIC void acm_modexit (void)
+{
+        unsigned long flags;
+        struct usbd_urb *urb;
+        TRACE_MSG0(MDM,"entered");
+
+        // Wake up any pending opens after setting the exiting flag.
+        local_irq_save(flags);
+        acm_private.exiting = 1;
+        //if (acm_private.open_wait_count > 0) {
+        //        wake_up_interruptible(&acm_private.open_wait);
+        //}
+        local_irq_restore(flags);
+
+        // verify no tasks are running
+        //acm_wait_task(&acm_private.wqueue);
+        //acm_wait_task(&acm_private.hqueue);
+
+//#if defined(LINUX24)
+//        run_task_queue(&tq_timer);
+//#else 
+//        blk_run_queues();
+//#endif
+ 
+        //acm_wait_task(&acm_private.recv_tqueue);
+
+        usb_ops->terminate_usb_part(&acm_private);
+        otg_trace_invalidate_tag(MDM);
+}
+
+
+module_init (acm_modinit);
+module_exit (acm_modexit);
diff -uNr linux/drivers/no-otg/functions/acm/modem.c linux/drivers/otg/functions/acm/modem.c
--- linux/drivers/no-otg/functions/acm/modem.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/modem.c	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,263 @@
+/*
+ * otg/functions/acm/modem.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ */
+/*!
+ * @file otg/functions/acm/modem.c
+ * @brief ACM-MODEM Descriptor Set
+ *
+ * This file is the USB specific piece that interfaces with the otgcore layer.
+ * If you're looking for the USB specific piece that interfaces with the
+ * host usbcore layer, that's in otg/functions/acm/acm-cl.c
+ *
+ * Note: this function driver requires the following endpoints:
+ *
+ *      BULK-IN
+ *      BULK-OUT
+ *      INTERRUPT-IN
+ *
+ * This function driver cannot be used on devices (such as the StrongArm
+ * SA1100) that do not have an interrupt endpoint.
+ *
+ * @ingroup MODEMFunction
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include <otg/otg-trace.h>
+#include "acm.h"
+#include "acm-fd.h"
+#include "acm-os.h"
+
+
+
+/*
+ * CDC ACM Configuration
+ *
+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
+ */
+
+/*! BULK OUT Data Endpoint Descriptor
+ */
+static u8 mdn_alt_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK,      0, 0x00, 0x00, };
+
+/*! BULK In Data Endpoint Descriptor
+ */
+static u8 mdn_alt_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  BULK,     0,  0x00, 0x00, };
+
+/*! Data Endpoint Descriptor List
+ */
+static struct usbd_endpoint_descriptor *mdn_alt_endpoints[] = { 
+        (struct usbd_endpoint_descriptor *) mdn_alt_1, 
+        (struct usbd_endpoint_descriptor *) mdn_alt_2, };
+
+/*! Data Endpoint Index List
+ */
+u8 mdn_alt_indexes[] = { BULK_OUT, BULK_IN, };
+
+/*! INTERRUPT In Comm Endpoint Descriptor
+ */
+static u8 mdn_comm_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  INTERRUPT, 0, 0x00, 0x0a, };
+
+/*! Comm Endpoint Descriptor List
+ */
+static struct usbd_endpoint_descriptor *mdn_comm_endpoints[] = { (struct usbd_endpoint_descriptor *) mdn_comm_1 };
+
+
+/*! Comm Endpoint Index List
+ */
+u8 mdn_comm_indexes[] = { INT_IN, };
+
+/*! @{
+ * Class Descriptors
+ */
+static u8 cdc_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x01, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
+static u8 cdc_class_2[] = { 0x05, CS_INTERFACE, USB_ST_CMF, 0x03, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
+static u8 cdc_class_3[] = { 0x05, CS_INTERFACE, USB_ST_UF, 0x00, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
+/*! @} */
+
+/*! ACMF Class Descriptor
+ * ACMF - c.f. Table 28
+ * currenty set to 0x2 - Support Set_Line_Coding etc, 
+ *
+ * XXX Should we also set 0x4 - Supports Network_Notification?
+ */
+static u8 cdc_class_4[] = { 0x04, CS_INTERFACE, USB_ST_ACMF, 0x02, };
+
+static struct usbd_generic_class_descriptor *cdc_comm_class_descriptors[] = 
+        { (struct usbd_generic_class_descriptor *) cdc_class_1, 
+        (struct usbd_generic_class_descriptor *) cdc_class_2, 
+        (struct usbd_generic_class_descriptor *) cdc_class_3, 
+        (struct usbd_generic_class_descriptor *) cdc_class_4, };
+
+
+
+/* Alternate Descriptors */
+// First two bytes are identical in all: bLength, bDescriptorType (0x09 0x04)
+
+/*! Comm Alternate Descriptor
+ */
+static u8 cdc_comm_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
+        0x09, USB_DT_INTERFACE, COMM_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
+        COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_ACM_SUBCLASS, 0x01, 0x00, };
+
+/*! Data Alternate Descriptor
+ */
+static u8 cdc_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
+        0x09, USB_DT_INTERFACE, DATA_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
+        DATA_INTERFACE_CLASS, COMMUNICATIONS_NO_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00, };
+
+
+
+/*! Comm alternate descriptions 
+ */
+static struct usbd_alternate_description cdc_comm_alternate_descriptions[] = {
+      { iInterface: CONFIG_OTG_ACM_COMM_INTF,
+              interface_descriptor: (struct usbd_interface_descriptor *)&cdc_comm_alternate_descriptor,
+              classes:sizeof (cdc_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
+              class_list: cdc_comm_class_descriptors,
+              endpoint_list: mdn_comm_endpoints,
+              endpoints:sizeof (mdn_comm_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+              endpoint_indexes: mdn_comm_indexes,
+      }, };
+
+/*! Data alternate descriptions 
+ */
+static struct usbd_alternate_description cdc_data_alternate_descriptions[] = {
+      { iInterface: CONFIG_OTG_ACM_DATA_INTF,
+              interface_descriptor: (struct usbd_interface_descriptor *)&cdc_data_alternate_descriptor,
+              endpoint_list: mdn_alt_endpoints,
+              endpoints:sizeof (mdn_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+              endpoint_indexes: mdn_alt_indexes,
+              }, };
+
+
+/*! Interface Descriptions List */
+static struct usbd_interface_description cdc_interfaces[] = {
+      { 
+                alternates:sizeof (cdc_comm_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:cdc_comm_alternate_descriptions,
+      },
+
+      { 
+                alternates:sizeof (cdc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:cdc_data_alternate_descriptions,
+      },
+};
+
+
+/*! Configuration Descriptor 
+ */
+static u8 cdc_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
+        0x09, USB_DT_CONFIGURATION, 0x00, 0x00, sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
+        0x01, 0x00, BMATTRIBUTE, BMAXPOWER, };
+
+/*! Configuration Description 
+ */
+struct usbd_configuration_description mdn_description[] = {
+      { iConfiguration: CONFIG_OTG_ACM_DESC,
+              configuration_descriptor: (struct usbd_configuration_descriptor *)cdc_configuration_descriptor,
+      }, };
+
+/*! Device Descriptor 
+ */
+static struct usbd_device_descriptor mdn_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+/*! High Speed Device Qualifier Descriptor 
+ */
+static struct usbd_device_qualifier_descriptor mdn_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+
+/*! Endpoint Request List
+ */
+static struct usbd_endpoint_request mdn_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 1, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, 64, 512, },
+        { 1, 1, 0, USB_DIR_IN | USB_ENDPOINT_BULK, 64 /* * 4 */, 512, },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
+        { 0, },
+};
+
+/*! OTG Descriptor
+ */
+static struct usbd_otg_descriptor mdn_otg_descriptor = {
+        bLength : sizeof(struct usbd_otg_descriptor),
+        bDescriptorType: USB_DT_OTG,
+        bmAttributes: 0,
+};
+
+/*! Device Description
+ */
+struct usbd_device_description mdn_device_description = {
+        device_descriptor: &mdn_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &mdn_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &mdn_otg_descriptor,
+        iManufacturer: CONFIG_OTG_ACM_MANUFACTURER,
+        iProduct: CONFIG_OTG_ACM_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR, 
+#endif
+};
+
+
+
+
+/*! function_driver 
+ */
+struct usbd_function_driver modem_function_driver = {
+        name: "ACM-MDM",
+        fops:&function_ops,
+        device_description:&mdn_device_description,
+        bNumConfigurations:sizeof (mdn_description) / sizeof (struct usbd_configuration_description),
+        configuration_description:mdn_description,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
+        bNumInterfaces:sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
+        interface_list:cdc_interfaces,
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: mdn_endpoint_requests,
+};
+
diff -uNr linux/drivers/no-otg/functions/acm/modem.h linux/drivers/otg/functions/acm/modem.h
--- linux/drivers/no-otg/functions/acm/modem.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/modem.h	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,118 @@
+/*
+ * otg/functions/acm/modem.h
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @defgroup MODEMFunction ACM-Modem 
+ * @ingroup functiongroup
+ */
+/*!
+ * @file otg/functions/acm/modem.h
+ * @brief ACM Function Driver private defines
+ *
+ *
+ * This is an ACM Function Driver. The upper edge is exposed
+ * to the hosting OS as a Posix type character device. The lower
+ * edge implements the USB Device Stack API.
+ *
+ * These are emulated and set by the modem driver as appropriate
+ * to model a virutal serial port. The
+ *
+ *      TIOCM_RNG       RNG (Ring)                              not used
+ *      TIOCM_LE        DSR (Data Set Ready / Line Enable)      
+ *      TIOCM_DSR       DSR (Data Set Ready)
+ *      TIOCM_CAR       DCD (Data Carrier Detect)
+ *      TIOCM_CTS       CTS (Clear to Send)
+ *      TIOCM_CD        TIOCM_CAR
+ *      TIOCM_RI        TIOCM_RNG
+ *
+ * These are set by the application:
+ *
+ *      TIOCM_DTR       DTR (Data Terminal Ready)
+ *      TIOCM_RTS       RTS (Request to Send)
+ *
+ *      TIOCM_LOOP      Set into loopback mode
+ *      TIOCM_OUT1      Not used.
+ *      TIOCM_OUT2      Not used.
+ *
+ *
+ * The following File and  termio c_cflags are used:
+ *
+ *      O_NONBLOCK      don't block in modem_open()
+ *      O_EXCL          don't allow more than one open
+ *
+ *      CLOCAL          ignore DTR status
+ *      CBAUD           send break if set to B0
+ *
+ * Virtual NULL Modem
+ *
+ * Peripheral to Host via Serial State Notification (write ioctls)
+ *
+ * Application             TIOCM           Null Modem      ACM (DCE)       Notificaiton    Host (DTE)
+ * -------------------------------------------------------------------------------------------------------------
+ * Request to send         TIOCM_RTS       RTS ->  CTS     CTS             Not Available   Clear to Send (N/A)
+ * Data Terminal Ready     TIOCM_DTR       DTR ->  DSR     DSR             bTxCarrier      Data Set Ready
+ *                                         DTR ->  DCD     DCD             bRXCarrier      Carrier Detect
+ * Ring Indicator          TIOCM_OUT1      OUT1 -> RI      RI              bRingSignal     Ring Indicator
+ * Overrun                 TIOCM_OUT2      OUT2 -> Overrun Overrun         bOverrun        Overrun
+ * Send Break              B0              B0   -> Break   Break           bBreak          Break Received
+ * -------------------------------------------------------------------------------------------------------------
+ *
+ *
+ * Host to Peripheral via Set Control Line State
+ *
+ * Host (DTE)              Line State      ACM (DCE)       Null Modem      TIOCM           Peripheral (DTE)
+ * -------------------------------------------------------------------------------------------------------------
+ * Data Terminal Ready     D0              DTR             DTR ->  DSR     TIOCM_DSR       Data Set Ready
+ *                                                         DTR ->  DCD     TIOCM_CAR       Carrier Detect
+ * Request To Send         D1              RTS             RTS ->  CTS     TIOCM_CTS       Clear to Send
+ * -------------------------------------------------------------------------------------------------------------
+ *
+ *      
+ * @ingroup MODEMFunction
+ */
+
+
+extern struct usbd_function_driver modem_function_driver;
+
+//#define MODEM_OPENED      (1 << 0)                /*!< OPENED flag */
+#define MODEMFD_CLOCAL      (1 << 1)                /*!< CLOCAL flag */
+//#define MODEMFD_LOOPBACK    (1 << 2)                /*!< LOOPBACK flag */
+#define MODEMFD_EXCLUSIVE   (1 << 3)                /*!< EXCLUSIVE flag */
+#define MODEMFD_THROTTLED   (1 << 4)                /*!< THROTTLED flag */
+
+/*! struct modem_private
+ */
+struct modem_private {
+
+        struct modem_driver *modem_driver;          /*!< modem structure */
+        int modem_driver_registered;              /*!< non-zero if modem_driver registered */
+        int usb_driver_registered;              /*!< non-zero if usb function registered */
+
+        struct modem_struct *modem;                 /*!< non-null if modem open */
+        struct tq_struct wqueue;                /*!< task queue for writer wakeup  */
+        struct tq_struct hqueue;                /*!< task queue for hangup */
+
+        u32 flags;                              /*!< flags */
+
+        u32 tiocm;                              /*!< tiocm settings */
+
+        struct serial_struct serial_struct;     /*!< serial structure used for TIOCSSERIAL and TIOCGSERIAL */
+
+        wait_queue_head_t tiocm_wait;
+        u32 tiocgicount;
+
+        u32 c_cflag;
+
+        wait_queue_head_t open_wait;            // wait queue for blocking open
+        int exiting;                            // True if module exiting
+};
+
+
diff -uNr linux/drivers/no-otg/functions/acm/obex-l24-os.c linux/drivers/otg/functions/acm/obex-l24-os.c
--- linux/drivers/no-otg/functions/acm/obex-l24-os.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/obex-l24-os.c	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,194 @@
+/*
+ * otg/functions/acm/obex-l24-os.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/functions/acm/obex-l24-os.c
+ * @brief ACM Function Driver private defines
+ *
+ * An ACM (Abstract Control Model) driver is composed of two pieces:
+ *    1) An OS specific piece that handles creating and operating
+ *       a serial device for the given OS.
+ *    2) A USB specific piece that interfaces either with the host
+ *       usbcore layer, or with the otgcore layer.
+ *
+ * If the USB piece interfaces with the host usbcore layer you get
+ * an ACM class driver.  If the USB piece interfaces with the otgcore
+ * layer you get an ACM function driver.
+ *
+ * This file is the OS specific piece that interfaces with Linux
+ * (kernel versions 2.4.*).  It creates two simple characters devices.
+ * One for the data transport and one for the communications interface.
+ *
+ * @ingroup ACMFunction
+ */
+
+
+//#include <otg/osversion.h>
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+MOD_AUTHOR ("tbr@belcarra.com, sl@belcarra.com");
+
+MOD_DESCRIPTION ("Belcarra CDC-ACM Function");
+EMBED_LICENSE();
+
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include <linux/capability.h>
+#include <otg/otg-trace.h>
+#include "acm.h"
+#include "acm-fd.h"
+#include "acm-os.h"
+
+// May need an ifdef here to pick up the acm_cl_usb_ops in the future.
+static struct acm_usb_services *usb_ops = &acm_fd_usb_ops;
+
+#define OBX obx_fd_trace_tag
+otg_tag_t obx_fd_trace_tag;
+
+/* Module Parameters ************************************************************************* */
+
+static u32 vendor_id;
+static u32 product_id;
+static u32 max_queued_urbs = MAX_QUEUED_URBS;
+static u32 max_queued_bytes = MAX_QUEUED_BYTES;
+
+MOD_PARM (vendor_id, "i");
+MOD_PARM (product_id, "i");
+MOD_PARM (max_queued_urbs, "i");
+MOD_PARM (max_queued_bytes, "i");
+
+MOD_PARM_DESC (vendor_id, "Device Vendor ID");
+MOD_PARM_DESC (product_id, "Device Product ID");
+MOD_PARM_DESC (max_queued_urbs, "Maximum TX Queued Urbs");
+MOD_PARM_DESC (max_queued_bytes, "Maximum TX Queued Bytes");
+
+
+/* ACM ***************************************************************************************** */
+
+#define ACM_TTY_MAJOR   166
+#define ACM_TTY_MINOR   0
+#define ACM_TTY_MINORS  1
+
+static struct acm_private acm_private;
+
+/* USB Simple Char Device ********************************************************************** */
+
+
+/* USB Comm Char Device ************************************************************************ */
+
+
+/* USB Module init/exit ************************************************************************ */
+/*
+ * acm_modinit - module init
+ *
+ */
+STATIC int acm_modinit (void)
+{
+        int i;
+        printk (KERN_INFO "Copyright (c) 2003-2004 sl@belcarra.com, tbr@belcarra.com\n");
+        OBX = otg_trace_obtain_tag();
+
+        // initialize private structure
+        //acm_private.tty_driver = &acm_tty_driver;
+        //acm_private.wqueue.routine = acm_wakeup_writers;
+        //acm_private.wqueue.data = &acm_private;
+        //acm_private.hqueue.routine = acm_hangup;
+        //acm_private.hqueue.data = &acm_private;
+        //acm_private.recv_tqueue.routine = &acm_start_recv;
+        //acm_private.recv_tqueue.data = &acm_private;
+
+        //init_waitqueue_head(&acm_private.open_wait);
+
+
+        // register as usb function driver
+
+        THROW_IF (usb_ops->initialize_usb_part(&acm_private,"acm_fd",vendor_id,product_id,
+                                               max_queued_urbs,max_queued_bytes ), error);
+
+        CATCH(error) {
+                printk(KERN_ERR"%s: ERROR\n", __FUNCTION__);
+
+                TRACE_MSG0(OBX,"--> -EINVAL");
+                return -EINVAL;
+        }
+        TRACE_MSG0(OBX,"--> 0");
+        return 0;
+}
+
+void acm_wait_task(WORK_ITEM *queue)
+{
+        TRACE_MSG1(OBX,"entered data=%p",queue->data);
+        RETURN_IF(!queue->data);
+        queue->data = NULL;
+#if defined(LINUX24)
+        while (queue->sync) {
+                TRACE_MSG1(OBX,"waiting for queue: %p",queue);
+                schedule_timeout(HZ);
+        }
+#else
+        while(PENDING_WORK_ITEM((*queue))){
+                TRACE_MSG1(OBX,"waiting for queue: %p",queue);
+                SCHEDULE_TIMEOUT(1);  // 1 second delay 
+        }
+#endif
+        TRACE_MSG0(OBX,"exited");
+}
+
+/* acm_modexit - module cleanup
+ */
+STATIC void acm_modexit (void)
+{
+        unsigned long flags;
+        struct usbd_urb *urb;
+        TRACE_MSG0(OBX,"entered");
+
+        // Wake up any pending opens after setting the exiting flag.
+        local_irq_save(flags);
+        acm_private.exiting = 1;
+        //if (acm_private.open_wait_count > 0) {
+        //        wake_up_interruptible(&acm_private.open_wait);
+        //}
+        local_irq_restore(flags);
+
+        // verify no tasks are running
+        //acm_wait_task(&acm_private.wqueue);
+        //acm_wait_task(&acm_private.hqueue);
+
+//#if defined(LINUX24)
+//        run_task_queue(&tq_timer);
+//#else 
+//        blk_run_queues();
+//#endif
+ 
+        //acm_wait_task(&acm_private.recv_tqueue);
+
+        usb_ops->terminate_usb_part(&acm_private);
+        otg_trace_invalidate_tag(OBX);
+}
+
+
+module_init (acm_modinit);
+module_exit (acm_modexit);
diff -uNr linux/drivers/no-otg/functions/acm/obex.c linux/drivers/otg/functions/acm/obex.c
--- linux/drivers/no-otg/functions/acm/obex.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/obex.c	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,263 @@
+/*
+ * otg/functions/acm/obex.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ */
+/*!
+ * @file otg/functions/acm/obex.c
+ * @brief ACM-OBEX Descriptor Set
+ *
+ * This file is the USB specific piece that interfaces with the otgcore layer.
+ * If you're looking for the USB specific piece that interfaces with the
+ * host usbcore layer, that's in otg/functions/acm/acm-cl.c
+ *
+ * Note: this function driver requires the following endpoints:
+ *
+ *      BULK-IN
+ *      BULK-OUT
+ *      INTERRUPT-IN
+ *
+ * This function driver cannot be used on devices (such as the StrongArm
+ * SA1100) that do not have an interrupt endpoint.
+ *
+ * @ingroup OBEXFunction
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include <otg/otg-trace.h>
+#include "acm.h"
+#include "acm-fd.h"
+#include "acm-os.h"
+
+
+
+/*
+ * CDC ACM Configuration
+ *
+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
+ */
+
+/*! BULK OUT Data Endpoint Descriptor
+ */
+static u8 obx_alt_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK,      0, 0x00, 0x00, };
+
+/*! BULK In Data Endpoint Descriptor
+ */
+static u8 obx_alt_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  BULK,     0,  0x00, 0x00, };
+
+/*! Data Endpoint Descriptor List
+ */
+static struct usbd_endpoint_descriptor *obx_alt_endpoints[] = { 
+        (struct usbd_endpoint_descriptor *) obx_alt_1, 
+        (struct usbd_endpoint_descriptor *) obx_alt_2, };
+
+/*! Data Endpoint Index List
+ */
+u8 obx_alt_indexes[] = { BULK_OUT, BULK_IN, };
+
+/*! INTERRUPT In Comm Endpoint Descriptor
+ */
+static u8 obx_comm_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  INTERRUPT, 0, 0x00, 0x0a, };
+
+/*! Comm Endpoint Descriptor List
+ */
+static struct usbd_endpoint_descriptor *obx_comm_endpoints[] = { (struct usbd_endpoint_descriptor *) obx_comm_1 };
+
+
+/*! Comm Endpoint Index List
+ */
+u8 obx_comm_indexes[] = { INT_IN, };
+
+/*! @{
+ * Class Descriptors
+ */
+static u8 cdc_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x01, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
+static u8 cdc_class_2[] = { 0x05, CS_INTERFACE, USB_ST_CMF, 0x03, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
+static u8 cdc_class_3[] = { 0x05, CS_INTERFACE, USB_ST_UF, 0x00, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
+/*! @} */
+
+/*! ACMF Class Descriptor
+ * ACMF - c.f. Table 28
+ * currenty set to 0x2 - Support Set_Line_Coding etc, 
+ *
+ * XXX Should we also set 0x4 - Supports Network_Notification?
+ */
+static u8 cdc_class_4[] = { 0x04, CS_INTERFACE, USB_ST_ACMF, 0x02, };
+
+static struct usbd_generic_class_descriptor *cdc_comm_class_descriptors[] = 
+        { (struct usbd_generic_class_descriptor *) cdc_class_1, 
+        (struct usbd_generic_class_descriptor *) cdc_class_2, 
+        (struct usbd_generic_class_descriptor *) cdc_class_3, 
+        (struct usbd_generic_class_descriptor *) cdc_class_4, };
+
+
+
+/* Alternate Descriptors */
+// First two bytes are identical in all: bLength, bDescriptorType (0x09 0x04)
+
+/*! Comm Alternate Descriptor
+ */
+static u8 cdc_comm_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
+        0x09, USB_DT_INTERFACE, COMM_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
+        COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_ACM_SUBCLASS, 0x01, 0x00, };
+
+/*! Data Alternate Descriptor
+ */
+static u8 cdc_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
+        0x09, USB_DT_INTERFACE, DATA_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
+        DATA_INTERFACE_CLASS, COMMUNICATIONS_NO_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00, };
+
+
+
+/*! Comm alternate descriptions 
+ */
+static struct usbd_alternate_description cdc_comm_alternate_descriptions[] = {
+      { iInterface: CONFIG_OTG_ACM_COMM_INTF,
+              interface_descriptor: (struct usbd_interface_descriptor *)&cdc_comm_alternate_descriptor,
+              classes:sizeof (cdc_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
+              class_list: cdc_comm_class_descriptors,
+              endpoint_list: obx_comm_endpoints,
+              endpoints:sizeof (obx_comm_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+              endpoint_indexes: obx_comm_indexes,
+      }, };
+
+/*! Data alternate descriptions 
+ */
+static struct usbd_alternate_description cdc_data_alternate_descriptions[] = {
+      { iInterface: CONFIG_OTG_ACM_DATA_INTF,
+              interface_descriptor: (struct usbd_interface_descriptor *)&cdc_data_alternate_descriptor,
+              endpoint_list: obx_alt_endpoints,
+              endpoints:sizeof (obx_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+              endpoint_indexes: obx_alt_indexes,
+              }, };
+
+
+/*! Interface Descriptions List */
+static struct usbd_interface_description cdc_interfaces[] = {
+      { 
+                alternates:sizeof (cdc_comm_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:cdc_comm_alternate_descriptions,
+      },
+
+      { 
+                alternates:sizeof (cdc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:cdc_data_alternate_descriptions,
+      },
+
+};
+
+
+/*! Configuration Descriptor 
+ */
+static u8 cdc_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
+        0x09, USB_DT_CONFIGURATION, 0x00, 0x00, sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
+        0x01, 0x00, BMATTRIBUTE, BMAXPOWER, };
+
+/*! Configuration Description 
+ */
+struct usbd_configuration_description obx_description[] = {
+      { iConfiguration: CONFIG_OTG_ACM_DESC,
+              configuration_descriptor: (struct usbd_configuration_descriptor *)cdc_configuration_descriptor,
+      }, };
+
+/*! Device Descriptor 
+ */
+static struct usbd_device_descriptor obx_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+/*! High Speed Device Qualifier Descriptor 
+ */
+static struct usbd_device_qualifier_descriptor obx_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+
+/*! Endpoint Request List
+ */
+static struct usbd_endpoint_request obx_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 1, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, 64, 512, },
+        { 1, 1, 0, USB_DIR_IN | USB_ENDPOINT_BULK, 64 /* * 4 */, 512, },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
+        { 0, },
+};
+
+/*! OTG Descriptor
+ */
+static struct usbd_otg_descriptor obx_otg_descriptor = {
+        bLength : sizeof(struct usbd_otg_descriptor),
+        bDescriptorType: USB_DT_OTG,
+        bmAttributes: 0,
+};
+
+/*! Device Description
+ */
+struct usbd_device_description obx_device_description = {
+        device_descriptor: &obx_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &obx_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &obx_otg_descriptor,
+        iManufacturer: CONFIG_OTG_ACM_MANUFACTURER,
+        iProduct: CONFIG_OTG_ACM_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR, 
+#endif
+};
+
+
+
+/*! function_driver 
+ */
+struct usbd_function_driver obex_function_driver = {
+        name: "ACM-OBX",
+        fops:&function_ops,
+        device_description:&obx_device_description,
+        bNumConfigurations:sizeof (obx_description) / sizeof (struct usbd_configuration_description),
+        configuration_description:obx_description,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
+        bNumInterfaces:sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
+        interface_list:cdc_interfaces,
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: obx_endpoint_requests,
+};
+
diff -uNr linux/drivers/no-otg/functions/acm/obex.h linux/drivers/otg/functions/acm/obex.h
--- linux/drivers/no-otg/functions/acm/obex.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/obex.h	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,66 @@
+/*
+ * otg/functions/acm/obex.h
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @defgroup OBEXFunction ACM-OBEX 
+ * @ingroup functiongroup 
+ */
+/*!
+ * @file otg/functions/acm/obex.h
+ * @brief ACM Function Driver private defines
+ *
+ *
+ * This is an ACM Function Driver. The upper edge is exposed
+ * to the hosting OS as a Posix type character device. The lower
+ * edge implements the USB Device Stack API.
+ *
+ *
+ *      
+ * @ingroup OBEXFunction
+ */
+
+
+extern struct usbd_function_driver tty_function_driver;
+
+//#define TTY_OPENED      (1 << 0)                /*!< OPENED flag */
+#define TTYFD_CLOCAL      (1 << 1)                /*!< CLOCAL flag */
+//#define TTYFD_LOOPBACK    (1 << 2)                /*!< LOOPBACK flag */
+#define TTYFD_EXCLUSIVE   (1 << 3)                /*!< EXCLUSIVE flag */
+#define TTYFD_THROTTLED   (1 << 4)                /*!< THROTTLED flag */
+
+/*! struct obex_private
+ */
+struct obex_private {
+
+        struct tty_driver *tty_driver;          /*!< tty structure */
+        int tty_driver_registered;              /*!< non-zero if tty_driver registered */
+        int usb_driver_registered;              /*!< non-zero if usb function registered */
+
+        struct tty_struct *tty;                 /*!< non-null if tty open */
+        struct tq_struct wqueue;                /*!< task queue for writer wakeup  */
+        struct tq_struct hqueue;                /*!< task queue for hangup */
+
+        u32 flags;                              /*!< flags */
+
+        u32 tiocm;                              /*!< tiocm settings */
+
+        struct serial_struct serial_struct;     /*!< serial structure used for TIOCSSERIAL and TIOCGSERIAL */
+
+        wait_queue_head_t tiocm_wait;
+        u32 tiocgicount;
+
+        u32 c_cflag;
+
+        wait_queue_head_t open_wait;            // wait queue for blocking open
+        int exiting;                            // True if module exiting
+};
+
+
diff -uNr linux/drivers/no-otg/functions/acm/tty-fd.c linux/drivers/otg/functions/acm/tty-fd.c
--- linux/drivers/no-otg/functions/acm/tty-fd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/tty-fd.c	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,263 @@
+/*
+ * otg/functions/acm/tty-fd.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ */
+/*!
+ * @file otg/functions/acm/tty-fd.c
+ * @brief ACM-TTY Descriptor Set
+ *
+ * This file is the USB specific piece that interfaces with the otgcore layer.
+ * If you're looking for the USB specific piece that interfaces with the
+ * host usbcore layer, that's in otg/functions/acm/acm-cl.c
+ *
+ * Note: this function driver requires the following endpoints:
+ *
+ *      BULK-IN
+ *      BULK-OUT
+ *      INTERRUPT-IN
+ *
+ * This function driver cannot be used on devices (such as the StrongArm
+ * SA1100) that do not have an interrupt endpoint.
+ *
+ * @ingroup TTYFunction
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include <otg/otg-trace.h>
+#include "acm.h"
+#include "acm-fd.h"
+#include "acm-os.h"
+
+
+
+/*
+ * CDC ACM Configuration
+ *
+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
+ */
+
+/*! BULK OUT Data Endpoint Descriptor
+ */
+static u8 tty_alt_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK,      0, 0x00, 0x00, };
+
+/*! BULK In Data Endpoint Descriptor
+ */
+static u8 tty_alt_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  BULK,     0,  0x00, 0x00, };
+
+/*! Data Endpoint Descriptor List
+ */
+static struct usbd_endpoint_descriptor *tty_alt_endpoints[] = { 
+        (struct usbd_endpoint_descriptor *) tty_alt_1, 
+        (struct usbd_endpoint_descriptor *) tty_alt_2, };
+
+/*! Data Endpoint Index List
+ */
+u8 tty_alt_indexes[] = { BULK_OUT, BULK_IN, };
+
+/*! INTERRUPT In Comm Endpoint Descriptor
+ */
+static u8 tty_comm_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  INTERRUPT, 0, 0x00, 0x0a, };
+
+/*! Comm Endpoint Descriptor List
+ */
+static struct usbd_endpoint_descriptor *tty_comm_endpoints[] = { (struct usbd_endpoint_descriptor *) tty_comm_1 };
+
+
+/*! Comm Endpoint Index List
+ */
+u8 tty_comm_indexes[] = { INT_IN, };
+
+/*! @{
+ * Class Descriptors
+ */
+static u8 cdc_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x01, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
+static u8 cdc_class_2[] = { 0x05, CS_INTERFACE, USB_ST_CMF, 0x03, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
+static u8 cdc_class_3[] = { 0x05, CS_INTERFACE, USB_ST_UF, 0x00, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
+/*! @} */
+
+/*! ACMF Class Descriptor
+ * ACMF - c.f. Table 28
+ * currenty set to 0x2 - Support Set_Line_Coding etc, 
+ *
+ * XXX Should we also set 0x4 - Supports Network_Notification?
+ */
+static u8 cdc_class_4[] = { 0x04, CS_INTERFACE, USB_ST_ACMF, 0x02, };
+
+static struct usbd_generic_class_descriptor *cdc_comm_class_descriptors[] = 
+        { (struct usbd_generic_class_descriptor *) cdc_class_1, 
+        (struct usbd_generic_class_descriptor *) cdc_class_2, 
+        (struct usbd_generic_class_descriptor *) cdc_class_3, 
+        (struct usbd_generic_class_descriptor *) cdc_class_4, };
+
+
+
+/* Alternate Descriptors */
+// First two bytes are identical in all: bLength, bDescriptorType (0x09 0x04)
+
+/*! Comm Alternate Descriptor
+ */
+static u8 cdc_comm_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
+        0x09, USB_DT_INTERFACE, COMM_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
+        COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_ACM_SUBCLASS, 0x01, 0x00, };
+
+/*! Data Alternate Descriptor
+ */
+static u8 cdc_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
+        0x09, USB_DT_INTERFACE, DATA_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
+        DATA_INTERFACE_CLASS, COMMUNICATIONS_NO_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00, };
+
+
+
+/*! Comm alternate descriptions 
+ */
+static struct usbd_alternate_description cdc_comm_alternate_descriptions[] = {
+      { iInterface: CONFIG_OTG_ACM_COMM_INTF,
+              interface_descriptor: (struct usbd_interface_descriptor *)&cdc_comm_alternate_descriptor,
+              classes:sizeof (cdc_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
+              class_list: cdc_comm_class_descriptors,
+              endpoint_list: tty_comm_endpoints,
+              endpoints:sizeof (tty_comm_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+              endpoint_indexes: tty_comm_indexes,
+      }, };
+
+/*! Data alternate descriptions 
+ */
+static struct usbd_alternate_description cdc_data_alternate_descriptions[] = {
+      { iInterface: CONFIG_OTG_ACM_DATA_INTF,
+              interface_descriptor: (struct usbd_interface_descriptor *)&cdc_data_alternate_descriptor,
+              endpoint_list: tty_alt_endpoints,
+              endpoints:sizeof (tty_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+              endpoint_indexes: tty_alt_indexes,
+              }, };
+
+
+/*! Interface Descriptions List */
+static struct usbd_interface_description cdc_interfaces[] = {
+      { 
+                alternates:sizeof (cdc_comm_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:cdc_comm_alternate_descriptions,
+      },
+
+      { 
+                alternates:sizeof (cdc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:cdc_data_alternate_descriptions,
+      },
+
+};
+
+
+/*! Configuration Descriptor 
+ */
+static u8 cdc_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
+        0x09, USB_DT_CONFIGURATION, 0x00, 0x00, sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
+        0x01, 0x00, BMATTRIBUTE, BMAXPOWER, };
+
+/*! Configuration Description 
+ */
+struct usbd_configuration_description tty_description[] = {
+      { iConfiguration: CONFIG_OTG_ACM_DESC,
+              configuration_descriptor: (struct usbd_configuration_descriptor *)cdc_configuration_descriptor,
+      }, };
+
+/*! Device Descriptor 
+ */
+static struct usbd_device_descriptor tty_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+/*! High Speed Device Qualifier Descriptor 
+ */
+static struct usbd_device_qualifier_descriptor tty_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+
+/*! Endpoint Request List
+ */
+static struct usbd_endpoint_request tty_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 1, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, 64, 512, },
+        { 1, 1, 0, USB_DIR_IN | USB_ENDPOINT_BULK, 64 /* * 4 */, 512, },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
+        { 0, },
+};
+
+/*! OTG Descriptor
+ */
+static struct usbd_otg_descriptor tty_otg_descriptor = {
+        bLength : sizeof(struct usbd_otg_descriptor),
+        bDescriptorType: USB_DT_OTG,
+        bmAttributes: 0,
+};
+
+/*! Device Description
+ */
+struct usbd_device_description tty_device_description = {
+        device_descriptor: &tty_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &tty_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &tty_otg_descriptor,
+        iManufacturer: CONFIG_OTG_ACM_MANUFACTURER,
+        iProduct: CONFIG_OTG_ACM_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR, 
+#endif
+};
+
+/*! function_driver 
+ */
+struct usbd_function_driver tty_function_driver = {
+        name: "ACM-TTY",
+        fops:&function_ops,
+        device_description:&tty_device_description,
+        bNumConfigurations:sizeof (tty_description) / sizeof (struct usbd_configuration_description),
+        configuration_description:tty_description,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
+        bNumInterfaces:sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
+        interface_list:cdc_interfaces,
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: tty_endpoint_requests,
+};
+
+
+
diff -uNr linux/drivers/no-otg/functions/acm/tty-if.c linux/drivers/otg/functions/acm/tty-if.c
--- linux/drivers/no-otg/functions/acm/tty-if.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/tty-if.c	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,263 @@
+/*
+ * otg/functions/acm/tty-if.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ */
+/*!
+ * @file otg/functions/acm/tty-if.c
+ * @brief ACM-TTY Descriptor Set
+ *
+ * This file is the USB specific piece that interfaces with the otgcore layer.
+ * If you're looking for the USB specific piece that interfaces with the
+ * host usbcore layer, that's in otg/functions/acm/acm-cl.c
+ *
+ * Note: this function driver requires the following endpoints:
+ *
+ *      BULK-IN
+ *      BULK-OUT
+ *      INTERRUPT-IN
+ *
+ * This function driver cannot be used on devices (such as the StrongArm
+ * SA1100) that do not have an interrupt endpoint.
+ *
+ * @ingroup TTYFunction
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include <otg/otg-trace.h>
+#include "acm.h"
+#include "acm-fd.h"
+#include "acm-os.h"
+
+
+
+/*
+ * CDC ACM Configuration
+ *
+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
+ */
+
+/*! BULK OUT Data Endpoint Descriptor
+ */
+static u8 tty_alt_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK,      0, 0x00, 0x00, };
+
+/*! BULK In Data Endpoint Descriptor
+ */
+static u8 tty_alt_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  BULK,     0,  0x00, 0x00, };
+
+/*! Data Endpoint Descriptor List
+ */
+static struct usbd_endpoint_descriptor *tty_alt_endpoints[] = { 
+        (struct usbd_endpoint_descriptor *) tty_alt_1, 
+        (struct usbd_endpoint_descriptor *) tty_alt_2, };
+
+/*! Data Endpoint Index List
+ */
+u8 tty_alt_indexes[] = { BULK_OUT, BULK_IN, };
+
+/*! INTERRUPT In Comm Endpoint Descriptor
+ */
+static u8 tty_comm_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  INTERRUPT, 0, 0x00, 0x0a, };
+
+/*! Comm Endpoint Descriptor List
+ */
+static struct usbd_endpoint_descriptor *tty_comm_endpoints[] = { (struct usbd_endpoint_descriptor *) tty_comm_1 };
+
+
+/*! Comm Endpoint Index List
+ */
+u8 tty_comm_indexes[] = { INT_IN, };
+
+/*! @{
+ * Class Descriptors
+ */
+static u8 cdc_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x01, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
+static u8 cdc_class_2[] = { 0x05, CS_INTERFACE, USB_ST_CMF, 0x03, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
+static u8 cdc_class_3[] = { 0x05, CS_INTERFACE, USB_ST_UF, 0x00, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
+/*! @} */
+
+/*! ACMF Class Descriptor
+ * ACMF - c.f. Table 28
+ * currenty set to 0x2 - Support Set_Line_Coding etc, 
+ *
+ * XXX Should we also set 0x4 - Supports Network_Notification?
+ */
+static u8 cdc_class_4[] = { 0x04, CS_INTERFACE, USB_ST_ACMF, 0x02, };
+
+static struct usbd_generic_class_descriptor *cdc_comm_class_descriptors[] = 
+        { (struct usbd_generic_class_descriptor *) cdc_class_1, 
+        (struct usbd_generic_class_descriptor *) cdc_class_2, 
+        (struct usbd_generic_class_descriptor *) cdc_class_3, 
+        (struct usbd_generic_class_descriptor *) cdc_class_4, };
+
+
+
+/* Alternate Descriptors */
+// First two bytes are identical in all: bLength, bDescriptorType (0x09 0x04)
+
+/*! Comm Alternate Descriptor
+ */
+static u8 cdc_comm_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
+        0x09, USB_DT_INTERFACE, COMM_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
+        COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_ACM_SUBCLASS, 0x01, 0x00, };
+
+/*! Data Alternate Descriptor
+ */
+static u8 cdc_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
+        0x09, USB_DT_INTERFACE, DATA_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
+        DATA_INTERFACE_CLASS, COMMUNICATIONS_NO_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00, };
+
+
+
+/*! Comm alternate descriptions 
+ */
+static struct usbd_alternate_description cdc_comm_alternate_descriptions[] = {
+      { iInterface: CONFIG_OTG_ACM_COMM_INTF,
+              interface_descriptor: (struct usbd_interface_descriptor *)&cdc_comm_alternate_descriptor,
+              classes:sizeof (cdc_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
+              class_list: cdc_comm_class_descriptors,
+              endpoint_list: tty_comm_endpoints,
+              endpoints:sizeof (tty_comm_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+              endpoint_indexes: tty_comm_indexes,
+      }, };
+
+/*! Data alternate descriptions 
+ */
+static struct usbd_alternate_description cdc_data_alternate_descriptions[] = {
+      { iInterface: CONFIG_OTG_ACM_DATA_INTF,
+              interface_descriptor: (struct usbd_interface_descriptor *)&cdc_data_alternate_descriptor,
+              endpoint_list: tty_alt_endpoints,
+              endpoints:sizeof (tty_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+              endpoint_indexes: tty_alt_indexes,
+              }, };
+
+
+/*! Interface Descriptions List */
+static struct usbd_interface_description cdc_interfaces[] = {
+      { 
+                alternates:sizeof (cdc_comm_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:cdc_comm_alternate_descriptions,
+      },
+
+      { 
+                alternates:sizeof (cdc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:cdc_data_alternate_descriptions,
+      },
+
+};
+
+
+/*! Configuration Descriptor 
+ */
+static u8 cdc_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
+        0x09, USB_DT_CONFIGURATION, 0x00, 0x00, sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
+        0x01, 0x00, BMATTRIBUTE, BMAXPOWER, };
+
+/*! Configuration Description 
+ */
+struct usbd_configuration_description tty_description[] = {
+      { iConfiguration: CONFIG_OTG_ACM_DESC,
+              configuration_descriptor: (struct usbd_configuration_descriptor *)cdc_configuration_descriptor,
+      }, };
+
+/*! Device Descriptor 
+ */
+static struct usbd_device_descriptor tty_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+/*! High Speed Device Qualifier Descriptor 
+ */
+static struct usbd_device_qualifier_descriptor tty_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+
+/*! Endpoint Request List
+ */
+static struct usbd_endpoint_request tty_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 1, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, 64, 512, },
+        { 1, 1, 0, USB_DIR_IN | USB_ENDPOINT_BULK, 64 /* * 4 */, 512, },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
+        { 0, },
+};
+
+/*! OTG Descriptor
+ */
+static struct usbd_otg_descriptor tty_otg_descriptor = {
+        bLength : sizeof(struct usbd_otg_descriptor),
+        bDescriptorType: USB_DT_OTG,
+        bmAttributes: 0,
+};
+
+/*! Device Description
+ */
+struct usbd_device_description tty_device_description = {
+        device_descriptor: &tty_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &tty_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &tty_otg_descriptor,
+        iManufacturer: CONFIG_OTG_ACM_MANUFACTURER,
+        iProduct: CONFIG_OTG_ACM_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR, 
+#endif
+};
+
+/*! function_driver 
+ */
+struct usbd_function_driver tty_function_driver = {
+        name: "ACM-TTY",
+        fops:&function_ops,
+        device_description:&tty_device_description,
+        bNumConfigurations:sizeof (tty_description) / sizeof (struct usbd_configuration_description),
+        configuration_description:tty_description,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_ACM_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_ACM_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ACM_BCDDEVICE),
+        bNumInterfaces:sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
+        interface_list:cdc_interfaces,
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: tty_endpoint_requests,
+};
+
+
+
diff -uNr linux/drivers/no-otg/functions/acm/tty-l24-os.c linux/drivers/otg/functions/acm/tty-l24-os.c
--- linux/drivers/no-otg/functions/acm/tty-l24-os.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/tty-l24-os.c	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,1291 @@
+/*
+ * otg/functions/acm/tty-l24-os.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By:
+ *      Tom Rushworth <tbr@belcarra.com>,
+ *      Stuart Lynne <sl@belcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+/*!
+ * @file otg/functions/acm/tty-l24-os.c
+ * @brief ACM Function Driver private defines
+ *
+ * An ACM (Abstract Control Model) driver is composed of two pieces:
+ *
+ *    1) An OS specific piece that handles creating and operating
+ *       a serial device for the given OS.
+ *
+ *    2) A USB specific piece that interfaces either with the host
+ *       usbcore layer, or with the otgcore layer.
+ *
+ * If the USB piece interfaces with the host usbcore layer you get an ACM
+ * class driver.  If the USB piece interfaces with the otgcore layer you get
+ * an ACM function driver.
+ *
+ * This file is the OS specific piece that interfaces with Linux (kernel
+ * versions 2.4.*).  It talks to the bottom edge of the Linux tty layer.
+ *
+ * See the file acm/tty.c for USB descriptor definitions used for this
+ * function.
+ *
+ * @ingroup TTYFunction
+ */
+
+
+//#include <otg/osversion.h>
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+MOD_AUTHOR ("tbr@belcarra.com, sl@belcarra.com");
+
+MOD_DESCRIPTION ("Belcarra TTY Function");
+EMBED_LICENSE();
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+#include <linux/serial.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include <linux/capability.h>
+#include "tty.h"
+#include <otg/otg-trace.h>
+#include "acm.h"
+#include "acm-fd.h"
+#include "acm-os.h"
+
+static struct acm_usb_services *usb_ops = &acm_fd_usb_ops;
+
+#define TTY tty_fd_trace_tag
+otg_tag_t tty_fd_trace_tag;
+
+/* Module Parameters ************************************************************************* */
+
+static u32 vendor_id;
+static u32 product_id;
+static u32 max_queued_urbs = MAX_QUEUED_URBS;
+static u32 max_queued_bytes = MAX_QUEUED_BYTES;
+
+MOD_PARM (vendor_id, "i");
+MOD_PARM (product_id, "i");
+MOD_PARM (max_queued_urbs, "i");
+MOD_PARM (max_queued_bytes, "i");
+
+MOD_PARM_DESC (vendor_id, "Device Vendor ID");
+MOD_PARM_DESC (product_id, "Device Product ID");
+MOD_PARM_DESC (max_queued_urbs, "Maximum TX Queued Urbs");
+MOD_PARM_DESC (max_queued_bytes, "Maximum TX Queued Bytes");
+
+
+/* ACM ***************************************************************************************** */
+
+#define ACM_TTY_MAJOR   166
+#define ACM_TTY_MINOR   0
+#define ACM_TTY_MINORS  1
+
+extern struct acm_private acmfd_private;
+extern struct tty_private ttyfd_private;
+
+
+/* ******************************************************************************************* */
+
+#define TTY_OVERFLOW_SIZE       512
+
+u8 tty_overflow_buffer[TTY_OVERFLOW_SIZE];
+int tty_overflow_used;
+
+/* ******************************************************************************************* */
+
+/*! ttyfd_schedule
+ *
+ * Schedule a bottom half handler work item.
+ *
+ * @param queue
+ */
+STATIC void ttyfd_schedule(WORK_ITEM *queue)
+{
+        RETURN_IF(NO_WORK_DATA((*queue)) || PENDING_WORK_ITEM((*queue)));
+#if defined(LINUX24)
+        queue_task(queue, &tq_immediate);
+        mark_bh(IMMEDIATE_BH);
+        TRACE_MSG1(TTY,"task %p scheduled and marked",queue);
+#else
+        SCHEDULE_WORK((*queue));
+        TRACE_MSG1(TTY,"task %p scheduled",queue);
+#endif
+}
+
+
+/*! ttyfd_block_until_ready
+ *
+ * Called from tty_open to implement blocking open. Wait for DTR indication
+ * from acm-fd.
+ *
+ * Called by TTY layer to open device.
+ *
+ * @param tty
+ * @param filp
+ * @param acm
+ * @returns non-zero for error
+ */
+STATIC int ttyfd_block_until_ready(struct tty_struct *tty, struct file *filp, struct acm_private *acm)
+{
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+        unsigned long flags;
+        int rc = 0;
+
+        local_irq_save(flags);
+        //TRACE_MSG1(TTY,"open_wait_count: %d --> at entry", tty_private->open_wait_count);
+        //tty_private->open_wait_count += 1;
+        for (;;) {
+                /* check if the file has been closed */
+                if (tty_hung_up_p(filp)) {
+                        TRACE_MSG0(TTY,"tty_hung_up_p()");
+                        rc = -ERESTARTSYS;
+                        break;
+                }
+                /* check for pending signals */
+                if (signal_pending(current)) {
+                        TRACE_MSG0(TTY,"signal_pending()");
+                        rc = -ERESTARTSYS;
+                        break;
+                }
+                /* check if the module is unloading */
+                if (tty_private->exiting) {
+                        TRACE_MSG0(TTY,"module exiting()");
+                        rc = -ENODEV;
+                        break;
+                }
+                /* check for what we want, do we have DTR?
+                 */
+                if (acm->bmLineState & CDC_LINESTATE_D0_DTR) {
+                        // OK, there's somebody on the other end, let's go...
+                        TRACE_MSG0(TTY,"found DTR");
+                        rc = 0;
+                        break;
+                }
+                //TRACE_MSG1(TTY,"open_wait_count: %d sleeping...", tty_private->open_wait_count);
+
+                /* restore irqs */
+                local_irq_restore(flags);
+
+                /* sleep */
+                interruptible_sleep_on(&tty_private->open_wait);
+
+                /* lock irqs again */
+                local_irq_save(flags);
+
+                //TRACE_MSG1(TTY,"open_wait_count: %d got WAKEUP", tty_private->open_wait_count);
+        }
+        //tty_private->open_wait_count -= 1;
+        //TRACE_MSG1(TTY,"open_wait_count: %d <-- at exit", tty_private->open_wait_count);
+        local_irq_restore(flags);
+        return(rc);
+}
+
+/*! ttyfd_call_hangup
+ *
+ * Bottom half handler to safely send hangup signal to process group.
+ *
+ * @param private - point to acm_private dat structure
+ */
+STATIC void ttyfd_call_hangup(void *private)
+{
+        struct acm_private *acm = (struct acm_private *) private;
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+
+        struct tty_struct *tty = (NULL == acm) ? NULL : tty_private->tty;
+
+        TRACE_MSG5(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d c_cflag: %04x clocal: %d",
+                        atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED,
+                        tty_private->c_cflag, tty_private->c_cflag & CLOCAL);
+
+
+        if (tty && !(tty_private->c_cflag & CLOCAL))
+                tty_hangup(tty);
+
+        wake_up_interruptible(&tty_private->open_wait);
+
+        TRACE_MSG0(TTY,"exited");
+}
+
+/*! ttyfd_schedule_hangup
+ *
+ * Schedule hangup bottom half handler.
+ *
+ * @param acm - point to acm_private dat structure
+ */
+void ttyfd_schedule_hangup(struct acm_private *acm)
+{
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+
+        TRACE_MSG0(TTY, "entered");
+        ttyfd_schedule(&tty_private->hqueue);
+}
+
+
+/*! tty_open
+ *
+ * Called by TTY layer to open device.
+ *
+ * @param tty
+ * @param filp
+ * @returns non-zero for error
+ */
+STATIC int tty_open(struct tty_struct *tty, struct file *filp)
+{
+        struct acm_private *acm = &acmfd_private;
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+        int used;
+        int nonblocking;
+        int rc = 0;
+        unsigned long flags;
+
+        TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
+                        atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
+
+        TRACE_MSG2(TTY,"f_flags: %08x NONBLOCK: %x",
+                        filp->f_flags, filp->f_flags & O_NONBLOCK);
+
+        nonblocking = filp->f_flags & O_NONBLOCK;
+
+        /* Lock and increment used counter, save current value.
+         * Check for exclusive open at the same time.
+         */
+        local_irq_save(flags);
+
+        /* The value of acm->used controls MOD_{INC/DEC}_USE_COUNT, so
+         * it has to be incremented unconditionally, and no early return
+         * made until after USE_COUNT has been adjusted to match.
+         */
+        used = atomic_post_inc(&acm->used);
+#ifdef MCEL
+        filp->f_flags |= O_EXCL;  // QQQ Can we persuade MCEL to add this to their app?
+        if (nonblocking && !(acm->connected)) {
+                // QQQ Is MCEL actually using this "feature"?  (See below for printk)
+                rc = -EINVAL;
+        }
+        else
+#endif
+#if 0
+        if (filp->f_flags & O_EXCL) {
+                /* This is intended to be an exclusive open, so
+                 * make sure no one has the device open already, and
+                 * set the exclusive flag so no one can open it later.
+                 */
+                if (used > 0) {
+                        // Someone already has it.
+                        rc = -EBUSY;
+                }
+                else {
+                        tty_private->flags |= TTYFD_EXCLUSIVE;
+                        set_bit(TTY_EXCLUSIVE, &tty->flags);
+                }
+        }
+#if defined(LINUX24)
+        else if ((tty_private->flags & TTYFD_EXCLUSIVE) && !suser())
+#else
+	if ((tty_private->flags & TTYFD_EXCLUSIVE) && !capable(CAP_SYS_TTY_CONFIG))
+#endif
+        {
+                // Only the superuser can do a normal open of an O_EXCL tty
+                rc = -EBUSY;
+        }
+#endif
+        local_irq_restore(flags);
+
+        // OK, now it's safe to make an early return if we are failing.
+        if (rc) {
+#ifdef MCEL
+                // This can dissappear when the "feature" above does.
+                if (-EINVAL == rc)
+                        //printk(KERN_INFO "\nusb cable not connected!\n");
+#endif
+                return(rc);
+        }
+        local_irq_save(flags);
+
+
+        /* To truly emulate the old dual-device approach of having a non-blocking
+         * device (e.g cu0) and a blocking device (e.g. tty0) we would need to
+         * track blocking and non-blocking opens separately.  We don't.  This
+         * may lead to funny behavior in the multiple open case.
+         */
+        UNLESS (used) {
+                MOD_INC_USE_COUNT;
+                TRACE_MSG1(TTY,"INC: %d", MOD_IN_USE);
+                // First open.
+                TRACE_MSG2(TTY, "FIRST OPEN nonblocking: %x exclusive: %x", nonblocking, tty_private->flags & TTYFD_EXCLUSIVE);
+                tty->driver_data = acm;
+                tty_private->tty = tty;
+                tty->low_latency = 1;
+                usb_ops->open(acm, DATA_INTF);
+                usb_ops->set_local(acm, 1);
+        }
+        local_irq_restore(flags);
+
+
+        /* All done if configured
+         */
+        RETURN_ZERO_UNLESS(usb_ops->ready(acm));
+
+        /* All done if non blocking open
+         */
+        RETURN_ZERO_IF(nonblocking);
+
+        /* Block open - wait until ready
+         */
+        TRACE_MSG0(TTY, "BLOCKING - wait until ready");
+        rc = ttyfd_block_until_ready(tty,filp,acm);
+
+        /* The tty layer calls tty_close() even if this open fails,
+         * so any cleanup (rc != 0) will be done there.
+         */
+        TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
+                        atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
+        return(rc);
+}
+
+/*! ttyfd_wakeup_opens
+ *
+ * Called by acm_fd to wakeup processes blocked in open waiting for DTR.
+ *
+ * @param acm - pointer to acm private data structure
+ */
+void ttyfd_wakeup_opens(struct acm_private *acm)
+{
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+        TRACE_MSG0(TTY, "entered");
+        //if (tty_private->open_wait_count > 0)
+        wake_up_interruptible(&tty_private->open_wait);
+}
+
+/*! tty_close
+ *
+ * Called by TTY layer to close device.
+ *
+ * @param tty
+ * @param filp
+ * @returns non-zero for error
+ */
+STATIC void tty_close(struct tty_struct *tty, struct file *filp)
+{
+        struct acm_private *acm = tty->driver_data;
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+        struct usbd_function_instance *function;
+        int used;
+
+        TRACE_MSG0(TTY, "entered");
+
+        //UNLESS (acm) {
+        //        printk(KERN_INFO"%s: ACM null\n", __FUNCTION__);
+        //        return;
+        //}
+
+        usb_ops->close(acm, DATA_INTF);
+        tty_private = (struct tty_private *) acm->privdata;
+        function = acm->function;
+        TRACE_MSG3(acm->trace_tag,"used: %d MOD_IN_USE: %d configured: %d",
+                        atomic_read(&acm->used), MOD_IN_USE, acm->flags & ACM_CONFIGURED);
+
+        // lock and decrement used counter, save result
+        used = atomic_pre_dec(&acm->used);
+
+        // finished unless this is the last close
+
+        RETURN_IF (used > 0);
+
+        TRACE_MSG0(TTY,"FINAL CLOSE");
+
+        tty_private->tty = NULL;
+
+        /* This should never happen if this is the last close,
+         * but it can't hurt to check.
+         */
+        //if (tty_private->open_wait_count)
+        wake_up_interruptible(&tty_private->open_wait);
+
+        if (tty_private->flags & TTYFD_EXCLUSIVE) {
+                tty_private->flags &= ~TTYFD_EXCLUSIVE;
+                if (tty)
+                        clear_bit(TTYFD_EXCLUSIVE, &tty->flags);
+        }
+
+        _MOD_DEC_USE_COUNT;
+        TRACE_MSG1(TTY,"DEC: %d", MOD_IN_USE);
+        TRACE_MSG1(TTY,"LAST CLOSE r-f=%d",(acm->bytes_received-acm->bytes_forwarded));
+
+        MOD_DEC_USE_COUNT;
+
+        TRACE_MSG0(TTY,"FINISHED");
+}
+
+/* Transmit Function - called by tty layer ****************************************************** */
+
+int ttyfd_recv_space_available(struct acm_private *acm, int interface);
+int ttyfd_recv_chars(struct acm_private *acm, int interface, u8 *cp, int n);
+
+#define LOOP_BUF 16
+/*! ttyfd_loop_xmit_chars
+ *
+ * Implement data loop back, send xmit data back as received data.
+ *
+ * @param acm - pointer to acm private data structure
+ * @param interface - data interface to send on
+ * @param count - number of bytes to send
+ * @param from_user - true if from user memory space
+ * @param buf - pointer to data to send
+ * @return count - number of bytes actually sent.
+ */
+STATIC int ttyfd_loop_xmit_chars(struct acm_private *acm, int interface, int count, int from_user, const unsigned char *buf)
+{
+        int received = 0;
+        while (count > 0) {
+                u8 copybuf[LOOP_BUF];
+                int i;
+                int space = ttyfd_recv_space_available(acm, DATA_INTF);
+                int recv = MIN (space, LOOP_BUF);
+                recv = MIN(recv, count);
+
+                //TRACE_MSG7(TTY, "buf: %8x buf+received: %8x received: %d from_user: %d count: %d space: %d recv: %d\n",
+                //                buf, buf + received, received, from_user, count, space, recv);
+
+                BREAK_UNLESS(recv);
+
+                if (from_user)
+                        copy_from_user ((void *)copybuf, (void*)(buf + received), recv);
+                else
+                        memcpy ((void *)copybuf, (void*)(buf + received), recv);
+
+                count -= recv;
+                received += recv;
+                TRACE_MSG3(TTY, "count: %d recv: %d received: %d", count, recv, received);
+                ttyfd_recv_chars(acm, DATA_INTF, copybuf, recv);
+        }
+        return received;
+}
+
+/*! ttyfd_overflow_send
+ *
+ * Check if there is data in overflow buffer and send if neccessary.
+ *
+ * @param acm - pointer to acm private data structure
+ * @param interface - data interface to send on
+ * @param force - force the send
+ */
+void ttyfd_overflow_send(struct acm_private *acm, int interface, int force)
+{
+        int chars_in_buffer;
+        int count;
+
+        unsigned long flags;
+        local_irq_save(flags);
+
+        chars_in_buffer = usb_ops->chars_in_buffer(acm, DATA_INTF);
+
+        TRACE_MSG3(TTY, "overflow_used: %d chars_in_buffer: %d force: %d", tty_overflow_used, chars_in_buffer, force);
+
+        if (force || !chars_in_buffer || tty_overflow_used > 200) {
+
+                count = usb_ops->xmit_chars(acm, DATA_INTF, tty_overflow_used, 0, tty_overflow_buffer);
+
+                TRACE_MSG2(TTY, "overflow_used: %d count: %d", tty_overflow_used, count);
+
+                tty_overflow_used = 0;
+
+        }
+        local_irq_restore(flags);
+}
+
+
+/*! ttyfd_overflow_xmit_chars
+ *
+ * Implement overflow buffer. The TTY layer implements echo with single
+ * character writes which can quickly exhaust the urbs allowed for sending.
+ * This results in data being lost.
+ *
+ * This function is called to accumulate small amounts of data when there is
+ * already an bulk in urb in the queue.
+ *
+ * The urb sent function calls wakeup writers which will call
+ * ttyfd_overflow_send which will send the data.
+ *
+ * @param acm - pointer to acm private data structure
+ * @param interface - data interface to send on
+ * @param count - number of bytes to send
+ * @param from_user - true if from user memory space
+ * @param buf - pointer to data to send
+ * @return count - number of bytes actually sent.
+ */
+STATIC int ttyfd_overflow_xmit_chars(struct acm_private *acm, int interface, int count, int from_user, const unsigned char *buf)
+{
+        unsigned long flags;
+        int overflow_room;
+        int write_room = usb_ops->write_room(acm, DATA_INTF);
+
+        TRACE_MSG2(TTY,"-> count: %d from_usr: %d", count, from_user);
+        local_irq_save(flags);
+
+        if ((overflow_room = TTY_OVERFLOW_SIZE - tty_overflow_used) > 0) {
+
+                count = MIN(overflow_room, count);
+                if (from_user)
+                        copy_from_user ((void *)tty_overflow_buffer + tty_overflow_used, (void*)buf, count);
+                else
+                        memcpy ((void *)tty_overflow_buffer + tty_overflow_used, (void*)buf, count);
+
+                tty_overflow_used += count;
+        }
+        else
+                count = 0;
+
+        local_irq_restore(flags);
+
+        /* start sending from overflow if neccessary
+         */
+        ttyfd_overflow_send(acm, interface, 0);
+
+        return count;
+}
+
+/*! tty_chars_in_buffer
+ *
+ * Called by TTY layer to determine amount of pending write data.
+ *
+ * @param tty - pointer to tty data structure
+ * @return amount of pending write data
+ */
+STATIC int tty_chars_in_buffer(struct tty_struct *tty)
+{
+        struct acm_private *acm = tty->driver_data;
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+        int rc;
+
+        //TRACE_MSG0(TTY, "entered");
+
+        rc = usb_ops->chars_in_buffer(acm, DATA_INTF);
+        TRACE_MSG1(TTY, "chars in buffer: %d", rc);
+        return rc;
+        //return(usb_ops->chars_in_buffer(acm, DATA_INTF));
+}
+
+/*! tty_write
+ *
+ * Called by TTY layer to write data.
+ * @param tty - pointer to tty data structure
+ * @param from_user - true if from user memory space
+ * @param buf - pointer to data to send
+ * @param  count - number of bytes want to send.
+ * @return count - number of bytes actually sent.
+ */
+STATIC int tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
+{
+        struct acm_private *acm = tty->driver_data;
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+
+        TRACE_MSG3(TTY,"-> count: %d loopback: %d from_usr: %d", count, tty_private->tiocm & TIOCM_LOOP, from_user);
+
+        /* loopback mode
+         */
+        if (tty_private->tiocm & TIOCM_LOOP)
+                return ttyfd_loop_xmit_chars(acm, DATA_INTF, count, from_user, buf);
+
+        /* overflow mode
+         */
+        if (tty_overflow_used || (tty_chars_in_buffer(tty_private->tty) && (count < 64)))
+                return ttyfd_overflow_xmit_chars(acm, DATA_INTF, count, from_user, buf);
+
+        /* straight through mode
+         */
+        return usb_ops->xmit_chars(acm, DATA_INTF, count, from_user, buf);
+
+}
+
+/*! tty_write_room
+ *
+ * Called by TTY layer get amount of write room available.
+ *
+ * @param tty - pointer to tty data structure
+ * @return amount of write room available
+ */
+STATIC int tty_write_room(struct tty_struct *tty)
+{
+        struct acm_private *acm = tty->driver_data;
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+        int rc;
+
+        TRACE_MSG0(TTY, "entered");
+        /* loopback mode
+         */
+        if (tty_private->tiocm & TIOCM_LOOP)
+                return ttyfd_recv_space_available(acm, DATA_INTF);
+
+        rc = usb_ops->write_room(acm, DATA_INTF) + (TTY_OVERFLOW_SIZE - tty_overflow_used);
+        TRACE_MSG1(TTY, "write room: %d", rc);
+
+        return rc;
+
+
+        //return(usb_ops->write_room(acm, DATA_INTF));
+}
+
+static int throttle_count = 0;
+static int unthrottle_count = 0;
+
+/*! tty_throttle
+ *
+ * Called by TTY layer to throttle (do not allow received data.)
+ *
+ * @return amount of write room available
+ */
+STATIC void tty_throttle(struct tty_struct *tty)
+{
+        struct acm_private *acm = tty->driver_data;
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+
+        TRACE_MSG0(TTY, "entered");
+        //tty_private->flags |= TTYFD_THROTTLED;
+        usb_ops->throttle(acm, DATA_INTF);
+}
+
+/*! tty_unthrottle
+ *
+ * Called by TTY layer to unthrottle (allow received data.)
+ *
+ * @return amount of write room available
+ */
+STATIC void tty_unthrottle(struct tty_struct *tty)
+{
+        struct acm_private *acm = tty->driver_data;
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+
+        TRACE_MSG0(TTY, "entered");
+        //tty_private->flags &= ~TTYFD_THROTTLED;
+        usb_ops->unthrottle(acm, DATA_INTF);
+
+        /* This function is called while the TTY_DONT_FLIP flag is still
+         * set, so there is no point trying to push the flip buffer.  Just
+         * try to queue some recv urbs, and keep trying until we do manage
+         * to get some queued.
+         */
+        tty_schedule_flip(tty);
+}
+
+/* ********************************************************************************************** */
+
+/*! ttyfd_tiocm
+ * @param acm
+ * @param tiocm
+ * @return - computed tiocm value
+ */
+unsigned int ttyfd_tiocm(struct acm_private *acm, unsigned int tiocm)
+{
+        tiocm &= ~ ( TIOCM_DTR | TIOCM_DSR | TIOCM_CAR);
+
+        return tiocm |
+                usb_ops->get_dtr(acm) ? TIOCM_DTR : 0 |
+                usb_ops->get_dsr(acm) ? TIOCM_DSR : 0 |
+                usb_ops->get_dcd(acm) ? TIOCM_CAR : 0 ;
+}
+
+/*! tty_ioctl
+ *
+ * Used by TTY layer to execute IOCTL command.
+ *
+ * Called by TTY layer to open device.
+ *
+ * Unhandled commands must return -ENOIOCTLCMD for correct operation.
+ *
+ * @param tty
+ * @param file
+ * @param cmd
+ * @param arg
+ * @returns non-zero for error
+ */
+STATIC int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+{
+        struct acm_private *acm = tty->driver_data;
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+        unsigned int mask;
+        unsigned int newctrl;
+        unsigned int tiocm;
+        unsigned int saved_tiocm;
+        unsigned int changed_tiocm;
+        int rc;
+
+        //TRACE_MSG3(TTY,"entered: %8x dir: %x size: %x", cmd, _IOC_DIR(cmd), _IOC_SIZE(cmd));
+
+        switch(cmd) {
+
+        case TIOCMGET:
+                TRACE_MSG1(TTY, "TIOCMGET: tiocm: %08x", tiocm);
+                tty_private->tiocm = ttyfd_tiocm(acm, tiocm);
+                RETURN_EINVAL_IF (copy_to_user((void *)arg, &tty_private->tiocm, sizeof(int)));
+                return 0;
+
+        case TIOCMBIS:
+        case TIOCMBIC:
+        case TIOCMSET:
+                TRACE_MSG0(TTY, "TIOCMXXX: copying tiocm arguement");
+
+                TRACE_MSG1(TTY, "access: %d", access_ok(VERIFY_READ, (void *)arg, sizeof(int)));
+                RETURN_EINVAL_UNLESS(access_ok(VERIFY_READ, (void *)arg, sizeof(int)));
+
+
+                //RETURN_EINVAL_IF (copy_from_user(&tiocm, (void *)arg, sizeof(int)));
+                rc = copy_from_user((void *)&tiocm, (void *)arg, sizeof(int));
+                TRACE_MSG2(TTY, "copy_from_user: %d tiocm: %08x", rc, tiocm);
+
+                TRACE_MSG2(TTY, "tiocm: %08x mask: %08x", tiocm,
+                                TIOCM_RTS | TIOCM_DTR | TIOCM_OUT1 | TIOCM_OUT2 | TIOCM_LOOP);
+
+                tiocm &= TIOCM_RTS | TIOCM_DTR | TIOCM_OUT1 | TIOCM_OUT2 | TIOCM_LOOP;
+                saved_tiocm = tty_private->tiocm;
+
+                switch (cmd) {
+                case TIOCMBIS:
+                        TRACE_MSG1(TTY, "TIOCMBIS: tiocm: %08x", tiocm);
+                        tty_private->tiocm |= tiocm;      /* turn on flags set in tiocm */
+                        break;
+                case TIOCMBIC:
+                        TRACE_MSG1(TTY, "TIOCMBIC: tiocm: %08x", tiocm);
+                        tty_private->tiocm &= ~tiocm;     /* turn off flags set in tiocm */
+                        break;
+                case TIOCMSET:
+                        TRACE_MSG1(TTY, "TIOCMSET: tiocm: %08x", tiocm);
+                        tty_private->tiocm = tiocm;       /* set all flags as in tiocm */
+                        break;
+                }
+                /* make changes
+                 */
+                changed_tiocm = saved_tiocm ^ tty_private->tiocm;
+                TRACE_MSG4(TTY, "TIOCMSET: tiocm: %08x saved: %08x set: %08x changed: %d",
+                                tiocm, saved_tiocm, tty_private->tiocm, changed_tiocm);
+
+                if (changed_tiocm) {
+                        /* DTR -> (DSR/DCD) */
+                        tiocm = tty_private->tiocm;
+                        if (changed_tiocm & TIOCM_DTR) {
+                                usb_ops->set_dsr(acm, tiocm & TIOCM_DTR);
+                                usb_ops->set_dcd(acm, tiocm & TIOCM_DTR);
+                        }
+                        /* OUT1 -> Ring */
+                        if (changed_tiocm & TIOCM_OUT1)
+                                usb_ops->ring(acm);
+                        /* OUT2 -> Overrun */
+                        if (changed_tiocm & TIOCM_OUT2)
+                                usb_ops->overrun(acm);
+                        /* LOOPBACK */
+                        if (changed_tiocm & TIOCM_OUT2)
+                                usb_ops->set_loopback(acm, tiocm & TIOCM_LOOP);
+                }
+
+                return 0;
+
+        case TIOCGSERIAL:
+                TRACE_MSG0(TTY, "TIOCGSERIAL");
+                RETURN_EINVAL_IF (copy_to_user((void *)arg, &tty_private->serial_struct, sizeof(struct serial_struct)));
+                return 0;
+
+        case TIOCSSERIAL:
+                TRACE_MSG0(TTY, "TIOCSSERIAL");
+                RETURN_EFAULT_IF (copy_from_user(&tty_private->serial_struct, (void *)arg, sizeof(struct serial_struct)));
+                return 0;
+
+        case TIOCSERCONFIG:
+        case TIOCSERGETLSR: /* Get line status register */
+        case TIOCSERGSTRUCT:
+                TRACE_MSG0(TTY, "TIOCSER*");
+                return -EINVAL;
+
+                /*
+                 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+                 * - mask passed in arg for lines of interest
+                 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+                 * Caller should use TIOCGICOUNT to see which one it was
+                 */
+        case TIOCMIWAIT:
+                TRACE_MSG0(TTY, "TIOCGMIWAIT");
+                while (1) {
+
+                        saved_tiocm = tty_private->tiocm;
+
+                        interruptible_sleep_on(&tty_private->tiocm_wait);
+
+                        /* see if a signal did it */
+                        if (signal_pending(current))
+                                return -ERESTARTSYS;
+
+                        tty_private->tiocm = ttyfd_tiocm(acm, tiocm);
+                        changed_tiocm = saved_tiocm ^ tty_private->tiocm;
+                        RETURN_ZERO_IF ( (changed_tiocm | TIOCM_CAR) | (changed_tiocm | TIOCM_DSR) );
+                        /* loop */
+                }
+                /* NOTREACHED */
+
+                /*
+                 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+                 * Return: write counters to the user passed counter struct
+                 * NB: both 1->0 and 0->1 transitions are counted except for
+                 *     RI where only 0->1 is counted.
+                 */
+        case TIOCGICOUNT:
+                TRACE_MSG0(TTY, "TIOCGICOUNT");
+                if (copy_to_user((void *)arg, &tty_private->tiocgicount, sizeof(int)))
+                        return -EFAULT;
+                return 0;
+
+        case TCSETS:
+                TRACE_MSG1(TTY, "TCSETS: tiocm: %08x", tiocm);
+                return -ENOIOCTLCMD;
+        case TCFLSH:
+                TRACE_MSG1(TTY, "TCFLSH: tiocm: %08x", tiocm);
+                return -ENOIOCTLCMD;
+
+        case TCGETS:
+                TRACE_MSG1(TTY, "TCGETS: tiocm: %08x", tiocm);
+                return -ENOIOCTLCMD;
+
+        default:
+                TRACE_MSG1(TTY, "unknown cmd: %08x", cmd);
+                return -ENOIOCTLCMD;
+        }
+        return -ENOIOCTLCMD;
+}
+
+/*! ttyfd_wakeup_state
+ *
+ * Called by acm_fd to wakeup processes blocked waiting for state change
+ *
+ * @param acm - pointer to acm private data structure
+ */
+void ttyfd_wakeup_state(struct acm_private *acm)
+{
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+        TRACE_MSG0(TTY, "entered");
+        wake_up_interruptible(&tty_private->tiocm_wait);
+}
+
+
+/*! tty_set_termios
+ *
+ * Used by TTY layer to set termios structure according to current status.
+ *
+ * @param tty - pointer to acm private data structure
+ * @param termios_old - termios structure
+ */
+STATIC void tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
+{
+        struct acm_private *acm = tty->driver_data;
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+
+        unsigned int c_cflag = tty->termios->c_cflag;
+
+        /* see if CLOCAL has changed */
+        if ((termios_old->c_cflag ^ tty->termios->c_cflag ) & CLOCAL)
+                usb_ops->set_local(acm, tty->termios->c_cflag & CLOCAL);
+
+        /* save cflags
+         */
+        tty_private->c_cflag = c_cflag;
+
+        /* send break?
+         */
+        if ((termios_old->c_cflag & CBAUD) && !(c_cflag & CBAUD))
+                usb_ops->send_break(acm);
+}
+
+/* ********************************************************************************************* */
+/*! ttyfd_wakeup_writers
+ *
+ * Bottom half handler to wakeup pending writers.
+ *
+ * @param data - pointer to acm private data structure
+ */
+STATIC void ttyfd_wakeup_writers(void *data)
+{
+        struct acm_private *acm = (struct acm_private *) data;
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+        struct tty_struct *tty = tty_private->tty;
+        unsigned long flags;
+
+        TRACE_MSG2(TTY,"used: %d MOD_IN_USE: %d", atomic_read(&acm->used), MOD_IN_USE);
+
+        RETURN_UNLESS(usb_ops->ready(acm));
+        RETURN_UNLESS(atomic_read(&acm->used));
+        RETURN_UNLESS(tty);
+
+        /* start sending from overflow buffer if necessary
+         */
+        ttyfd_overflow_send(acm, DATA_INTF, 0);
+
+        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+                (tty->ldisc.write_wakeup)(tty);
+
+        wake_up_interruptible(&tty->write_wait);
+}
+
+/*! ttyfd_schedule_wakeup_writers
+ *
+ * Called by acm-fd to schedule a wakeup writes bottom half handler.
+ *
+ * @param acm - pointer to acm private data structure
+ */
+void ttyfd_schedule_wakeup_writers(struct acm_private *acm)
+{
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+
+        TRACE_MSG2(TTY,"used: %d MOD_IN_USE: %d", atomic_read(&acm->used), MOD_IN_USE);
+        ttyfd_schedule(&tty_private->wqueue);
+}
+
+/* ********************************************************************************************* */
+
+/*! ttyfd_recv_space_available
+ *
+ * Used by acm-fd to determine receive space available. This will determine
+ * how many receive urbs can be queued as there are never more receive urbs
+ * pending than there is currently room for data to be received.
+ *
+ * @param acm - pointer to acm private data structure
+ * @param interface - data interface to send on
+ * @return count - number of bytes available
+ */
+int ttyfd_recv_space_available(struct acm_private *acm, int interface)
+{
+        struct tty_private *tty_private;
+        struct tty_struct *tty;
+        int rc;
+
+        TRACE_MSG0(TTY, "entered");
+        RETURN_ZERO_UNLESS(acm);
+
+        tty_private = (struct tty_private *) acm->privdata;
+
+        RETURN_ZERO_UNLESS(tty_private);
+
+        RETURN_ZERO_UNLESS(tty_private->tty);
+
+        switch (interface) {
+        case COMM_INTF:
+                return 0;
+        case DATA_INTF:
+                tty = tty_private->tty;
+                rc = TTY_FLIPBUF_SIZE - tty->flip.count;
+                TRACE_MSG1(TTY, "recv space available: %d", rc);
+                return rc;
+                return(TTY_FLIPBUF_SIZE - tty->flip.count);
+        }
+        return 0;
+}
+
+/*! ttyfd_recv_chars
+ *
+ * Called by acm-fd when data has been received. This will
+ * receive n bytes starting at cp.  This will never be
+ * more than the last call to ttyfd_recv_space_available().
+ * This will be called from interrupt context.
+ *
+ * @param acm - pointer to acm private data structure
+ * @param interface - data interface to send on
+ * @param n - number of bytes to send
+ * @param cp - pointer to data to send
+ * @return non-zero if error
+ */
+int ttyfd_recv_chars(struct acm_private *acm, int interface, u8 *cp, int n)
+{
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+        struct tty_struct *tty = tty_private->tty;
+        unsigned long flags;
+
+        /* acm_start_recv_urbs() will never queue more urbs than there is currently
+         * room in the upper layer buffer for. So we are guaranteed that any data actually
+         * received can be given to the upper layers without worrying if we will
+         * actually have room.
+         *
+         * XXX I think that if the tty layer does get behind and we reach a point where
+         * there are no outstanding receive urbs, then we will also have been throttled
+         * so we will have an oppourtunity to queue more receive urbs when we get unthrottled.
+         *
+         * XXX If the above assumption is not true that a timer will be needed to periodically
+         * check if we can restart.
+         *
+         * YYY What can happen is that the tty_flip_buffer_push() call can fail for
+         * a variety of reasons (locked out while a read call is in progress, ldisc
+         * buffer is full, and probably others).  We need to ensure that we keep
+         * trying to push the flip buffer until it does go, and there is room for
+         * more receive urbs.  acm_start_recv_urbs() will queue a task to push and
+         * try again if it can't queue any now.
+         *
+         * ZZZ Yet another failure mode is to call tty_flip_buffer_push() too many
+         * times while throttled.  This will result in the ldisc layer silently
+         * dropping data inside the n_tty_receive_buf() routine.  (Acutal numbers
+         * for the 2.4.20 kernel this was discovered on are 128 bytes left in the
+         * ldisc buffer when throttle is called, and upto 7 64 byte urbs outstanding.
+         * The urbs will fit into the flip buffer, but NOT the ldisc buffer.)  This
+         * means we must not call tty_flip_buffer_push() when throttled.  We will
+         * count on the tty_unthrottle() call to kick off the final push.
+         */
+
+        {
+                int i;
+                local_irq_save(flags);
+                TRACE_MSG2(TTY, "recv: %d buffer: %x", n, cp);
+
+                for (i = 0; i < n; i += 8) {
+                        TRACE_MSG8(TTY, "%02x %02x %02x %02x %02x %02x %02x %02x", 
+                                        cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3], 
+                                        cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
+                                  );
+                }
+
+                local_irq_restore(flags);
+        }
+        switch (interface) {
+        case COMM_INTF:
+                return 0;
+        case DATA_INTF:
+
+                RETURN_EINVAL_UNLESS(tty);
+
+#define WORD_COPY 1
+#if defined(WORD_COPY)
+                local_irq_save(flags);
+                memcpy(tty->flip.char_buf_ptr,cp,n);
+                memset(tty->flip.flag_buf_ptr,TTY_NORMAL,n);
+                tty->flip.count += n;
+                tty->flip.char_buf_ptr += n;
+                tty->flip.flag_buf_ptr += n;
+                acm->bytes_forwarded += n;
+                local_irq_restore(flags);
+#else
+                int i;
+                for (i = 0; i < n; i++) {
+                        /* tty_flip_char() has no lock out from any calls
+                         * to tty_flip_buffer_push() that may have been queued
+                         * by acm_unthrottle() or acm_start_recv_urbs(), so... 
+                         */
+                        local_irq_save(flags);
+                        tty_insert_flip_char(tty, *cp++, TTY_NORMAL);
+                        local_irq_restore(flags);
+                }
+                acm->bytes_forwarded += n;
+#endif
+
+                UNLESS (test_bit(TTY_THROTTLED, &tty->flags)) 
+                        tty_flip_buffer_push(tty);
+
+                //UNLESS (tty_private->flags & TTYFD_THROTTLED) 
+                //        tty_flip_buffer_push(tty);
+
+                return 0;
+        }
+        return 0;
+}
+
+/* ********************************************************************************************* */
+
+/*! ttyfd_enable
+ *
+ * Called by acm-fd when the function driver is enabled.
+ */
+void ttyfd_enable(struct usbd_function_instance *function)
+{
+        //function->privdata = &acm_private;
+        //acm_private.function = function;
+}
+
+/*! ttyfd_enable
+ *
+ * Called by acm-fd when the function driver is disabled.
+ */
+void ttyfd_disable(struct usbd_function_instance *function)
+{
+        //function->privdata = NULL;
+        //acm_private.function = NULL;
+}
+
+/* ************************************************************************** */
+
+#if defined(LINUX24)
+static int tty_refcount;
+#else
+//Maintained inside tty_driver in LINUX 2.6
+#endif
+static struct tty_struct *tty_table[ACM_TTY_MINORS];
+static struct termios *tty_termios[ACM_TTY_MINORS];
+static struct termios *tty_termios_locked[ACM_TTY_MINORS];
+
+/*! tty_driver
+ */
+static struct tty_driver tty_driver = {
+        .magic =                 TTY_DRIVER_MAGIC,
+        .type =                  TTY_DRIVER_TYPE_SERIAL,
+        .subtype =               SERIAL_TYPE_NORMAL,
+        .flags =                 TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+        .driver_name =           "acm-CDC",
+        .name =                  "usb/acm/%d",
+        .major =                 ACM_TTY_MAJOR,
+        .num =                   ACM_TTY_MINORS,
+        .minor_start =           0, 
+
+        .open =                  tty_open,
+        .close =                 tty_close,
+        .write =                 tty_write,
+        .write_room =            tty_write_room,
+        .ioctl =                 acm_tty_ioctl,
+        .throttle =              tty_throttle,
+        .unthrottle =            tty_unthrottle,
+        .chars_in_buffer =       tty_chars_in_buffer,
+        .set_termios =           tty_set_termios,
+
+#if defined(LINUX24)
+        .refcount =              &tty_refcount,
+#else
+        .refcount =              0,
+#endif
+        .table =                 tty_table,
+        .termios =               tty_termios,
+        .termios_locked =        tty_termios_locked,
+};      
+
+/* USB Module init/exit ************************************************************************ */
+
+struct tty_private ttyfd_private = {
+        .tty_driver = &tty_driver,
+        //.wqueue.routine = ttyfd_wakeup_writers,
+        //.wqueue.data = &acmfd_private,
+        .wqueue = {
+                .routine = ttyfd_wakeup_writers,
+                .data = &acmfd_private,
+        },
+        //.hqueue.routine = ttyfd_call_hangup,
+        //.hqueue.data = &acmfd_private,
+        .hqueue = {
+                .routine = ttyfd_call_hangup,
+                .data = &acmfd_private,
+        },
+};
+
+
+/*! tty_function_services
+ * 
+ * This structure contains the list of services 
+ */
+struct acm_function_services tty_function_services = {
+        .schedule_wakeup_writers = ttyfd_schedule_wakeup_writers,
+        .recv_space_available = ttyfd_recv_space_available,
+        .recv_chars = ttyfd_recv_chars,
+        .enable = ttyfd_enable,
+        .disable = ttyfd_disable,
+        .schedule_hangup = ttyfd_schedule_hangup,
+        .wakeup_opens = ttyfd_wakeup_opens,
+        .wakeup_state = ttyfd_wakeup_state,
+};
+
+struct acm_private acmfd_private = {
+        .function_driver = &tty_function_driver,
+        .function_services = &tty_function_services,
+        .privdata = &ttyfd_private,
+        // TBR: 20040705 use ...le32() not le16, spotted by Zhao Liang
+        //.line_coding.dwDTERate = __constant_cpu_to_le32(0x1c200), // 115200
+        //.line_coding.bDataBits = 0x08,
+        .line_coding = {
+                .dwDTERate = __constant_cpu_to_le32(0x1c200), // 115200
+                .bDataBits = 0x08,
+        },
+};
+
+
+/*! ttyfd_modinit - module init
+ *
+ * This is called immediately after the module is loaded or during
+ * the kernel driver initialization if linked into the kernel.
+ *
+ */
+STATIC int ttyfd_modinit (void)
+{
+        int i;
+
+        /* initialize private structures */
+        acmfd_private.trace_tag = TTY = otg_trace_obtain_tag();
+        init_waitqueue_head(&ttyfd_private.open_wait);
+        init_waitqueue_head(&ttyfd_private.tiocm_wait);
+
+        /* update init_termios and register as tty driver */
+        tty_driver.init_termios = tty_std_termios;
+        tty_driver.init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+        tty_driver.init_termios.c_lflag &= ~(ECHO | ICANON);
+        THROW_IF(tty_register_driver(&tty_driver), error);
+        tty_register_devfs(&tty_driver, 0, ACM_TTY_MINOR);
+        ttyfd_private.tty_driver_registered++;
+
+        /* register as usb function driver via acm-fd */
+        THROW_IF (usb_ops->fd_init(&acmfd_private, "acm_fd", vendor_id, product_id, max_queued_urbs,max_queued_bytes ), error);
+
+        CATCH(error) {
+                printk(KERN_ERR"%s: ERROR\n", __FUNCTION__);
+                if (ttyfd_private.tty_driver_registered) {
+                        tty_unregister_driver(&tty_driver);
+                        ttyfd_private.tty_driver_registered = 0;
+                }
+                return -EINVAL;
+        }
+        return 0;
+}
+
+
+/*! ttyfd_modexit - module cleanup
+ *
+ * This is called prior to the module being unloaded.
+ */
+STATIC void ttyfd_modexit (void)
+{
+        struct acm_private *acm = &acmfd_private;
+        struct tty_private *tty_private = (struct tty_private *) acm->privdata;
+        unsigned long flags;
+        struct usbd_urb *urb;
+
+        /* Wake up any pending opens after setting the exiting flag. */
+        local_irq_save(flags);
+        ttyfd_private.exiting = 1;
+        //if (ttyfd_private.open_wait_count > 0) 
+        wake_up_interruptible(&ttyfd_private.open_wait);
+        local_irq_restore(flags);
+
+        /* verify no tasks are running */
+        usb_ops->wait_task(acm, &acm->recv_tqueue);
+        usb_ops->wait_task(acm, &ttyfd_private.wqueue);
+        usb_ops->wait_task(acm, &ttyfd_private.hqueue);
+
+#if defined(LINUX24)
+        run_task_queue(&tq_timer);
+#else 
+        blk_run_queues();
+#endif
+        /* de-register as tty  and usb drivers */
+        if (ttyfd_private.tty_driver_registered) 
+                tty_unregister_driver(&tty_driver);
+
+        /* de-register as function driver via acm-fd */
+        usb_ops->fd_exit(&acmfd_private);
+        otg_trace_invalidate_tag(TTY);
+}
+
+module_init (ttyfd_modinit);
+module_exit (ttyfd_modexit);
+
diff -uNr linux/drivers/no-otg/functions/acm/tty-os.h linux/drivers/otg/functions/acm/tty-os.h
--- linux/drivers/no-otg/functions/acm/tty-os.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/tty-os.h	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,74 @@
+/*
+ * otg/functions/acm/tty-os.h
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ */
+/*!
+ * @file otg/functions/acm/tty-os.h
+ * @brief ACM Function Driver private defines
+ *
+ * An ACM (Abstract Control Model) driver is composed of two pieces:
+ *    1) An OS specific piece that handles creating and operating
+ *       a serial device for the given OS.
+ *    2) A USB specific piece that interfaces either with the host
+ *       usbcore layer, or with the otgcore layer.
+ *
+ * If the USB piece interfaces with the host usbcore layer you get
+ * an ACM class driver.  If the USB piece interfaces with the otgcore
+ * layer you get an ACM function driver.
+ *
+ * This file describes the functions exported by the various acm-*-os.c
+ * files (implementing (1)) for use in acm-fd.c (2).
+ *
+ * @ingroup TTYFunction
+ */
+
+#ifndef ACM_OS_H
+#define ACM_OS_H 1
+
+/*
+ * acm_os_recv_space_available - return the number of bytes of data
+ *                               the OS specific piece can accept without
+ *                               dropping some.
+ */
+extern int acm_os_recv_space_available(struct acm_private *acm);
+
+/*
+ * acm_os_recv_chars - receive n bytes starting at cp.  This will never be
+ *                     more than the last call to acm_os_recv_space_available().
+ *                     This will be called from interrupt context.
+ */
+extern int acm_os_recv_chars(struct acm_private *acm, u8 *cp, int n);
+
+/*
+ * acm_os_wakeup_writers - wakeup any blocked writers.  This is called
+ *                         from interrupt context, so may need to queue
+ *                         the actual wakeup in a "bottom half".
+ */
+extern void acm_os_wakeup_writers(struct acm_private *acm);
+
+/*
+ * acm_os_hangup - send a hangup to any readers or writers.  This can be
+ *                 called from interrupt context, so may need to queue
+ *                 the actual hangup in a "bottom half".
+ */
+extern void acm_os_hangup(struct acm_private *acm);
+
+/*
+ * acm_os_wakeup_opens - wakeup any blocked opens.  This is called
+ *                       from interrupt context, so may need to queue
+ *                       the actual wakeup in a "bottom half".
+ */
+extern void acm_os_wakeup_opens(struct acm_private *acm);
+
+extern void acm_os_enable(struct usbd_function_instance *function);
+extern void acm_os_disable(struct usbd_function_instance *function);
+
+#endif
diff -uNr linux/drivers/no-otg/functions/acm/tty.h linux/drivers/otg/functions/acm/tty.h
--- linux/drivers/no-otg/functions/acm/tty.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/acm/tty.h	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,117 @@
+/*
+ * otg/functions/acm/tty.h
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @defgroup TTYFunction ACM-TTY 
+ * @ingroup functiongroup
+ */
+/*!
+ * @file otg/functions/acm/tty.h
+ * @brief ACM Function Driver private defines
+ *
+ *
+ * This is an ACM Function Driver. The upper edge is exposed
+ * to the hosting OS as a Posix type character device. The lower
+ * edge implements the USB Device Stack API.
+ *
+ * These are emulated and set by the tty driver as appropriate
+ * to model a virutal serial port. The
+ *
+ *      TIOCM_RNG       RNG (Ring)                              not used
+ *      TIOCM_LE        DSR (Data Set Ready / Line Enable)      
+ *      TIOCM_DSR       DSR (Data Set Ready)
+ *      TIOCM_CAR       DCD (Data Carrier Detect)
+ *      TIOCM_CTS       CTS (Clear to Send)
+ *      TIOCM_CD        TIOCM_CAR
+ *      TIOCM_RI        TIOCM_RNG
+ *
+ * These are set by the application:
+ *
+ *      TIOCM_DTR       DTR (Data Terminal Ready)
+ *      TIOCM_RTS       RTS (Request to Send)
+ *
+ *      TIOCM_LOOP      Set into loopback mode
+ *      TIOCM_OUT1      Not used.
+ *      TIOCM_OUT2      Not used.
+ *
+ *
+ * The following File and  termio c_cflags are used:
+ *
+ *      O_NONBLOCK      don't block in tty_open()
+ *      O_EXCL          don't allow more than one open
+ *
+ *      CLOCAL          ignore DTR status
+ *      CBAUD           send break if set to B0
+ *
+ * Virtual NULL Modem
+ *
+ * Peripheral to Host via Serial State Notification (write ioctls)
+ *
+ * Application             TIOCM           Null Modem      ACM (DCE)       Notificaiton    Host (DTE)
+ * -------------------------------------------------------------------------------------------------------------
+ * Request to send         TIOCM_RTS       RTS ->  CTS     CTS             Not Available   Clear to Send (N/A)
+ * Data Terminal Ready     TIOCM_DTR       DTR ->  DSR     DSR             bTxCarrier      Data Set Ready
+ *                                         DTR ->  DCD     DCD             bRXCarrier      Carrier Detect
+ * Ring Indicator          TIOCM_OUT1      OUT1 -> RI      RI              bRingSignal     Ring Indicator
+ * Overrun                 TIOCM_OUT2      OUT2 -> Overrun Overrun         bOverrun        Overrun
+ * Send Break              B0              B0   -> Break   Break           bBreak          Break Received
+ * -------------------------------------------------------------------------------------------------------------
+ *
+ *
+ * Host to Peripheral via Set Control Line State
+ *
+ * Host (DTE)              Line State      ACM (DCE)       Null Modem      TIOCM           Peripheral (DTE)
+ * -------------------------------------------------------------------------------------------------------------
+ * Data Terminal Ready     D0              DTR             DTR ->  DSR     TIOCM_DSR       Data Set Ready
+ *                                                         DTR ->  DCD     TIOCM_CAR       Carrier Detect
+ * Request To Send         D1              RTS             RTS ->  CTS     TIOCM_CTS       Clear to Send
+ * -------------------------------------------------------------------------------------------------------------
+ *
+ *      
+ * @ingroup TTYFunction
+ */
+
+extern struct usbd_function_driver tty_function_driver;
+
+//#define TTY_OPENED      (1 << 0)                /*! OPENED flag */
+#define TTYFD_CLOCAL      (1 << 1)                /*! CLOCAL flag */
+//#define TTYFD_LOOPBACK    (1 << 2)               /*! LOOPBACK flag */
+#define TTYFD_EXCLUSIVE   (1 << 3)                /*! EXCLUSIVE flag */
+#define TTYFD_THROTTLED   (1 << 4)                /*! THROTTLED flag */
+
+/*! @struct tty_private
+ */
+struct tty_private {
+
+        struct tty_driver *tty_driver;          /*!< tty structure */
+        int tty_driver_registered;              /*!< non-zero if tty_driver registered */
+        int usb_driver_registered;              /*!< non-zero if usb function registered */
+
+        struct tty_struct *tty;                 /*!< non-null if tty open */
+        struct tq_struct wqueue;                /*!< task queue for writer wakeup  */
+        struct tq_struct hqueue;                /*!< task queue for hangup */
+
+        u32 flags;                              /*!< flags */
+
+        u32 tiocm;                              /*!< tiocm settings */
+
+        struct serial_struct serial_struct;     /*!< serial structure used for TIOCSSERIAL and TIOCGSERIAL */
+
+        wait_queue_head_t tiocm_wait;
+        u32 tiocgicount;
+
+        u32 c_cflag;
+
+        wait_queue_head_t open_wait;            /*! wait queue for blocking open*/
+        int exiting;                            /*! True if module exiting */
+};
+
+
diff -uNr linux/drivers/no-otg/functions/isotest/Config.in linux/drivers/otg/functions/isotest/Config.in
--- linux/drivers/no-otg/functions/isotest/Config.in	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/isotest/Config.in	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,28 @@
+#
+# Loop Function
+#
+# Copyright (C) 2003-2004 Belcarra
+# Enhanced Jan 2004 to provide greater runtime selection
+# of xmit buffer patterns  from the device to the host
+#
+
+mainmenu_option next_comment
+comment "ISO Test Function"
+
+dep_tristate '  Loop Function Driver' CONFIG_OTG_ISOTEST $CONFIG_OTG
+
+if [ "$CONFIG_OTG_ISOTEST" = "y" -o "$CONFIG_OTG_ISOTEST" = "m" ]; then
+
+   hex     ' idVendor (hex value)' CONFIG_OTG_ISOTEST_VENDORID "15ec"
+   hex     ' idProduct (hex value)' CONFIG_OTG_ISOTEST_PRODUCTID "f004"
+   hex     ' bcdDevice (binary-coded decimal)' CONFIG_OTG_ISOTEST_BCDDEVICE "0100"
+   string ' iManufacturer (string)' CONFIG_OTG_ISOTEST_MANUFACTURER ""
+   string ' iProduct (string)' CONFIG_OTG_ISOTEST_PRODUCT_NAME ""
+
+   string ' iConfiguration (string)' CONFIG_OTG_ISOTEST_DESC "ISO Test Cfg"
+   string ' Data Interface iInterface (string)' CONFIG_OTG_ISOTEST_DATA_INTF "ISO Data Intf"
+   #bool	  ' Runtime pattern buffer selection ' CONFIG_OTG_ISOTEST_XMIT_PATTERN "y"
+
+fi
+
+endmenu
diff -uNr linux/drivers/no-otg/functions/isotest/Makefile linux/drivers/otg/functions/isotest/Makefile
--- linux/drivers/no-otg/functions/isotest/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/isotest/Makefile	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,73 @@
+#
+# Function driver ISO Test Device
+#
+# Copyright (c) 2003 Belcarra
+
+# Multipart objects.
+
+O_TARGET	:= isotest_fd_drv.o 
+list-multi	:= isotest_fd.o isotest.o
+
+isotest_fd-objs	:= iso.o test.o fermat.o
+isotest-objs	:= host.o test.o
+
+# Objects that export symbols.
+export-objs	:= iso.o
+
+# Object file lists.
+
+obj-y	:=
+obj-m	:=
+obj-n	:=
+obj-	:=
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_OTG_ISOTEST)   += isotest_fd.o isotest.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+int-m		:= $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
+OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+
+# The global Rules.make.
+
+OTG=$(TOPDIR)/drivers/otg
+ISOD=$(OTG)/functions/isotest
+USBDCORE_DIR=$(OTG)/usbdcore
+include $(TOPDIR)/Rules.make
+EXTRA_CFLAGS += -I$(ISOD) -I$(OTG) -Wno-unused -Wno-format  
+EXTRA_CFLAGS_nostdinc += -I$(ISOD) -I$(OTG) -Wno-unused -Wno-format  
+
+# Link rules for multi-part drivers.
+
+isotest_fd.o: $(isotest_fd-objs)
+	$(LD) -r -o $@ $(isotest_fd-objs)
+
+isotest.o: $(isotest-objs)
+	$(LD) -r -o $@ $(isotest-objs)
+
+# dependencies:
+
+isotest.o: $(USBDCORE_DIR)/usbd.h $(USBDCORE_DIR)/usbd-bus.h $(USBDCORE_DIR)/usbd-func.h test.h
+host.o: host.c test.h
+
+test.o:test.h
+
diff -uNr linux/drivers/no-otg/functions/isotest/fermat.c linux/drivers/otg/functions/isotest/fermat.c
--- linux/drivers/no-otg/functions/isotest/fermat.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/isotest/fermat.c	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,132 @@
+/*
+ * otg/network_fd/fermat.c - Network Function Driver
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#ifdef CONFIG_OTG_ISOTEST_MODULE
+
+#include "fermat.h"
+
+#ifndef ISO_FERMAT_DEFINED
+typedef unsigned char BYTE;
+typedef struct fermat {
+        int length;
+        BYTE power[256];
+} FERMAT;
+#endif
+
+
+static int fermat_setup(FERMAT *p, int seed){
+        int i = 0;
+        unsigned long x,y;
+        y = 1;
+        do{
+                x = y;
+                p->power[i] = ( x == 256 ? 0 : x);
+                y = ( seed * x ) % 257;
+                i += 1;
+        }while( y != 1);
+        p->length = i;
+        return i;
+}
+
+static void fermat_xform(FERMAT *p, BYTE *data, int length){
+        BYTE *pw = p->power;
+        int   i, j;
+        BYTE * q ;
+        for(i = 0, j=0, q = data; i < length; i++, j++, q++){
+                if(j>=p->length){
+                        j = 0;
+                }
+                *q ^= pw[j];
+        }
+}
+
+static FERMAT default_fermat;
+static const int primitive_root = 5;
+void fermat_init(){
+        (void) fermat_setup(&default_fermat, primitive_root); 
+}
+
+// Here are the public official versions.
+// Change the primitive_root above to another primitive root
+// if you need better scatter. Possible values are 3 and 7
+
+
+void fermat_encode(BYTE *data, int length){
+        fermat_xform(&default_fermat, data, length);
+}
+
+void fermat_decode(BYTE *data, int length){
+        fermat_xform(&default_fermat, data, length);
+}
+
+
+// Note: the seed must be a "primitive root" of 257. This means that
+// the return value of the setup routine must be 256 (otherwise the
+// seed is not a primitive root.  The routine will still work fine
+// but will be less pseudo-random.
+
+#undef TEST 
+#if TEST
+#include <stdio.h>
+#include <memory.h>
+
+// Use FERMAT in two ways: to encode, and to generate test data.
+
+main(){
+        //Note 3, 5, and 7 are primitive roots of 257
+        // 11 is not a primitive root
+        FERMAT three, five, seven;
+
+        FERMAT three2;
+        printf("Cycle lengths: 3,5,7 %d %d %d \n", 
+                        fermat_setup(&three, 3), 
+                        fermat_setup(&five, 5), 
+                        fermat_setup(&seven, 7));
+        three2=three; // Copy data from three
+        fermat_xform(&three,three2.power,three2.length);
+        fermat_xform(&five,three2.power,three2.length);
+        fermat_xform(&seven,three2.power,three2.length);
+        fermat_xform(&seven,three2.power,three2.length);
+        fermat_xform(&five,three2.power,three2.length);
+        fermat_xform(&three,three2.power,three2.length);
+
+        //At this stage, three2 and three should be identical
+        if(memcpy(&three,&three2,sizeof(FERMAT))){
+                printf("Decoded intact\n");
+        }
+
+        fermat_init();
+        fermat_encode(three2.power,256);
+
+}
+#endif
+
+#endif /* CONFIG_OTG_ISOTEST */
+
diff -uNr linux/drivers/no-otg/functions/isotest/fermat.h linux/drivers/otg/functions/isotest/fermat.h
--- linux/drivers/no-otg/functions/isotest/fermat.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/isotest/fermat.h	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,38 @@
+/*
+ * otg/network_fd/fermat.h - Network Function Driver
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+
+#ifndef ISO_FERMAT_DEFINED
+#define ISO_FERMAT_DEFINED 1
+typedef unsigned char BYTE;
+typedef struct fermat {
+        int length;
+        BYTE power[256];
+} FERMAT;
+
+void fermat_init(void);
+void fermat_encode(BYTE *data, int length);
+void fermat_decode(BYTE *data, int length);
+#endif
+
diff -uNr linux/drivers/no-otg/functions/isotest/host.c linux/drivers/otg/functions/isotest/host.c
--- linux/drivers/no-otg/functions/isotest/host.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/isotest/host.c	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,840 @@
+/*
+ * otg/isotest_fd/host.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * USB ISO Test
+ *
+ * 
+ *      Copyright (c) 2003, 2004 sl@belcarra.com
+ *
+ */
+
+//#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+//#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+//#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+
+#include <linux/vmalloc.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+
+
+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
+#include <asm/dma.h>
+#include <asm/mach/dma.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/types.h>
+#endif
+
+#if defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
+#include <asm/au1000.h>
+#include <asm/au1000_dma.h>
+#include <asm/mipsregs.h>
+#endif
+
+#if defined(CONFIG_ARCH_SAMSUNG)
+#include <asm/arch/timers.h>
+#include <asm/arch/hardware.h>
+#endif
+
+#include "test.h"
+
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)
+
+#define MIN(a,b) (((a) < (b))?(a):(b))
+#define MAX(a,b) (((a) > (b))?(a):(b))
+
+#define THROW(x) goto x
+#define CATCH(x) while(0) x:
+#define THROW_IF(e, x) if (e) { goto x; }
+#define BREAK_IF(x) if (x) { break; }
+#define CONTINUE_IF(x) if (x) { continue; }
+#define RETURN_IF(y) if (y) { return; }
+#define RETURN_ZERO_IF(y) if (y) { return 0; }
+#define RETURN_NULL_IF(y) if (y) { return NULL; }
+
+
+/* Version Information */
+#define DRIVER_VERSION "v0.9"
+#define DRIVER_AUTHOR "sl@belcarra.com"
+#define DRIVER_DESC "USB ISO Test"
+
+/* Define these values to match your device */
+
+#ifdef CONFIG_OTG_ISOTEST_VENDORID
+        #undef USB_ISOTEST_VENDOR_ID
+        #define USB_ISOTEST_VENDOR_ID   CONFIG_OTG_ISOTEST_VENDORID
+#else
+        #define USB_ISOTEST_VENDOR_ID   0xfff0
+#endif
+
+#ifdef CONFIG_OTG_ISOTEST_PRODUCTID
+        #undef USB_ISOTEST_PRODUCT_ID
+        #define USB_ISOTEST_PRODUCT_ID  CONFIG_OTG_ISOTEST_PRODUCTID
+#else
+        #define USB_ISOTEST_PRODUCT_ID  0xfff1
+#endif
+
+/* Module paramaters */
+//MODULE_PARM(debug, "i");
+//MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+static int send;
+MODULE_PARM(send, "i");
+MODULE_PARM_DESC(send, "send test");
+
+static int recv;
+MODULE_PARM(recv, "i");
+MODULE_PARM_DESC(recv, "recv test");
+
+static u32    vendor_id;         // no default
+static u32    product_id;        // no default
+
+
+MODULE_PARM_DESC(vendor_id, "User specified USB idVendor");
+MODULE_PARM_DESC(product_id, "User specified USB idProduct");
+MODULE_PARM(vendor_id, "i");
+MODULE_PARM(product_id, "i");
+
+
+/* table of devices that work with this driver */
+static struct usb_device_id isotest_table [] = {
+        { USB_DEVICE(USB_ISOTEST_VENDOR_ID, USB_ISOTEST_PRODUCT_ID) },
+        { },                            /* extra entry */
+        { },                            /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, isotest_table);
+
+/* ********************************************************************************************* */
+
+
+/* ********************************************************************************************* */
+/*
+struct iso_test_data {
+
+        // sender info
+        u32     sender_id;
+        time_t  send_time;
+        u32     send_crc;
+
+        // loop info
+        u32     recv_id;
+        time_t  recv_time;
+        u32     recv_crc;
+
+        // payload
+        u32     size;
+        u8      data[0];
+};
+*/
+
+#define IN_URBS 10
+#define OUT_URBS 10
+
+
+
+
+/* Structure to hold all of our device specific stuff */
+struct usb_isotest {
+        struct usb_device *     udev;           /* save off the usb device pointer */
+        struct usb_interface *  interface;      /* the interface for this device */
+
+        u8                    closing;
+        u8                    num_interrupt_in;       /* number of interrupt in endpoints we have */
+        u8                    num_iso_in;             /* number of iso in endpoints we have */
+        u8                    num_iso_out;            /* number of iso out endpoints we have */
+
+        int                     iso_in_size;            /* the size of the receive buffer */
+        struct urb *            iso_in_urbs[IN_URBS];   /* the urb used to send data */
+        u8                    iso_in_endpointAddr;    /* the address of the iso in endpoint */
+        int                     in_urbs;
+
+        int                     iso_out_size;           /* the size of the send buffer */
+        struct urb *            iso_out_urbs[OUT_URBS]; /* the urb used to send data */
+        u8                    iso_out_endpointAddr;   /* the address of the iso out endpoint */
+        int                     out_urbs;
+
+        struct semaphore        sem;                    /* locks this structure */
+        struct tq_struct        iso_bh;
+        wait_queue_head_t       iso_wq;
+
+        struct isotest_stats    stats;
+
+        int                     first;
+};
+
+
+/* local function prototypes */
+
+static void * isotest_probe     (struct usb_device *, unsigned int , const struct usb_device_id *);
+static void isotest_disconnect  (struct usb_device *, void *);
+
+
+void isotest_schedule_bh(struct usb_isotest *isotest);
+
+
+/* ISO OUT - Transmit ************************************************************************** */
+
+
+#if 1
+static void isotest_iso_out_free_urb(struct urb *urb)
+{
+        struct usb_isotest *isotest;
+        int i;
+        unsigned long   flags;
+
+        //printk(KERN_INFO"%s: urb: %p\n", __FUNCTION__, urb);
+
+        RETURN_IF(!urb);
+
+        if (urb->transfer_buffer) {
+                kfree(urb->transfer_buffer);
+        }
+
+        isotest = (struct usb_isotest *)urb->context;
+        usb_free_urb(urb);
+
+        RETURN_IF(!isotest);
+
+        local_irq_save (flags);
+        for (i = 0; i < OUT_URBS; i++) {
+                CONTINUE_IF(isotest->iso_out_urbs[i] != urb);
+                //printk(KERN_INFO"%s: zeroing %d urb: %p\n", __FUNCTION__, i, urb);
+                isotest->iso_out_urbs[i] = NULL;
+                break;
+        }
+        local_irq_restore (flags);
+}
+#endif
+
+static int iso_transfer_count;
+
+int iso_out_submit(struct usb_isotest *isotest, struct urb *urb) 
+{
+        int                     i;
+        int                     j;
+        int                     rc = 0;
+
+        //printk(KERN_INFO"%s: transfer: %d size: %d frames: %x\n", __FUNCTION__, 
+        //                iso_transfer_count, urb->transfer_buffer_length, urb->number_of_packets);
+
+        RETURN_ZERO_IF(isotest->closing);
+
+        urb->dev = isotest->udev;
+
+        iso_transfer_count++;
+
+        for (j = urb->transfer_buffer_length, i = 0; i < urb->number_of_packets; i++) {
+
+                int                     send = MIN(isotest->iso_out_size, j);
+
+                u8                      *cp = urb->transfer_buffer + (isotest->iso_out_size * i);
+
+                j -= send;
+
+                urb->iso_frame_desc[i].offset = i * isotest->iso_out_size;
+                urb->iso_frame_desc[i].length = send;
+
+                // iso_transfer_count
+                *cp++ = cpu_to_le16(iso_transfer_count) & 0xff;
+                *cp++ = (cpu_to_le16(iso_transfer_count) >> 8) & 0xff;
+                *cp++ = (cpu_to_le16(iso_transfer_count) >> 16) & 0xff;
+                *cp++ = (cpu_to_le16(iso_transfer_count) >> 24) & 0xff;
+
+                // iso transfer length
+                *cp++ = cpu_to_le16(urb->transfer_buffer_length) & 0xff;
+                *cp++ = (cpu_to_le16(urb->transfer_buffer_length) >> 8) & 0xff;
+
+                // iso frame size
+                *cp++ = cpu_to_le16(isotest->iso_out_size) & 0xff;
+                *cp++ = (cpu_to_le16(isotest->iso_out_size) >> 8) & 0xff;
+
+                // total frames
+                *cp++ = cpu_to_le16(urb->number_of_packets) & 0xff;
+                *cp++ = (cpu_to_le16(urb->number_of_packets) >> 8) & 0xff;
+
+                // this packet number
+                *cp++ = cpu_to_le16(i+1) & 0xff;
+                *cp++ = (cpu_to_le16(i+1) >> 8) & 0xff;
+
+        }
+
+        //printk(KERN_INFO"%s: submitting\n", __FUNCTION__);
+
+        RETURN_ZERO_IF(!(rc = usb_submit_urb(urb)));
+        printk(KERN_INFO"%s: FAILED rc: %x\n", __FUNCTION__, rc);
+
+        return rc;
+}
+
+void isotest_iso_out_complete (struct urb *urb)
+{
+        struct usb_isotest *isotest = (struct usb_isotest *)urb->context;
+        int rc;
+
+        //printk(KERN_INFO"%s: urb: %p\n", __FUNCTION__, urb);
+
+        RETURN_IF(!urb);
+
+        if (urb->status /* && (urb->status != -ENOENT) && (urb->status != -ECONNRESET)*/) {
+                //printk(KERN_INFO"%s: - nonzero write iso status received: %d\n", __FUNCTION__, urb->status);
+        }
+
+        iso_out_submit(isotest, urb);
+}
+
+
+#define ISO_SEND_TOTAL  1000
+#define ISO_SEND_TRANSFERS 1200
+
+static int out_count;
+
+struct urb *iso_out_start(struct usb_isotest *isotest)
+{
+        struct urb *            urb = NULL;
+        int                     rc = 0;
+        int                     i;
+        int                     j;
+
+
+        int                     size = ((ISO_SEND_TOTAL % isotest->iso_out_size) < 20) ? ISO_SEND_TOTAL + 20 : ISO_SEND_TOTAL;
+        int                     frames = (size / isotest->iso_out_size) + 1;
+
+        //RETURN_NULL_IF(out_count-- <= 0);
+
+        //printk(KERN_INFO"%s: %d %02x\n", __FUNCTION__, out_count, isotest->iso_out_endpointAddr);
+
+
+        //printk(KERN_INFO"%s: frames: %x packet: %d size: %d\n", __FUNCTION__, frames, isotest->iso_out_size, size);
+
+        // allocate urb and buffer, fill buffer with some data
+        THROW_IF(!(urb = usb_alloc_urb(frames + 1)), error);
+
+        THROW_IF (!(urb->transfer_buffer = kmalloc(size, GFP_ATOMIC)), error);
+
+        for (i = 0; i < size; i++) {
+                unsigned char *cp = urb->transfer_buffer + i;
+                *cp = i % 256;
+        }
+
+        //printk(KERN_INFO"%s: CCC\n", __FUNCTION__);
+
+        urb->hcpriv = NULL;
+        urb->context = isotest;
+        urb->transfer_flags = USB_ISO_ASAP;
+        urb->complete = isotest_iso_out_complete;
+        urb->pipe = usb_sndisocpipe(isotest->udev, isotest->iso_out_endpointAddr);
+
+        urb->transfer_buffer_length = size;
+
+        urb->number_of_packets = frames;
+
+        THROW_IF((rc = iso_out_submit(isotest, urb)), error);
+
+        //printk(KERN_INFO"%s: OK frames: %d\n", __FUNCTION__, frames);
+
+        CATCH(error) {
+                printk(KERN_INFO"%s: FAILED rc: %d\n", __FUNCTION__, rc);
+                //isotest_iso_out_free_urb(urb);
+                return NULL;
+        }
+        return urb;
+}
+
+/* ISO IN - Receive **************************************************************************** */
+
+static int in_count = 5;
+static int in_submitted;
+static int in_resubmitted;
+static long in_completed;
+static long in_total_received;
+
+#if 0
+static void isotest_iso_in_free_urb(struct urb *urb)
+{
+        struct usb_isotest *isotest;
+        int i;
+        unsigned long   flags;
+
+        //printk(KERN_INFO"%s: urb: %p\n", __FUNCTION__, urb);
+
+        RETURN_IF(!urb);
+
+        if (urb->transfer_buffer) {
+                kfree(urb->transfer_buffer);
+        }
+
+        isotest = (struct usb_isotest *)urb->context;
+        usb_free_urb(urb);
+
+        RETURN_IF(!isotest);
+
+        local_irq_save (flags);
+        for (i = 0; i < IN_URBS; i++) {
+                CONTINUE_IF(isotest->iso_in_urbs[i] != urb);
+                //printk(KERN_INFO"%s: clearing %d urb: %p\n", __FUNCTION__, i, urb);
+                isotest->iso_in_urbs[i] = NULL;
+                break;
+        }
+        local_irq_restore (flags);
+}
+#endif
+
+struct urb *iso_in_start(struct usb_isotest *isotest);
+
+int iso_in_submit(struct usb_isotest *isotest, struct urb *urb) 
+{
+        int                     i;
+        int                     j;
+        int                     rc = 0;
+
+        //printk(KERN_INFO"%s: %p\n", __FUNCTION__, urb->complete);
+        
+        RETURN_ZERO_IF(isotest->closing);
+
+        urb->dev = isotest->udev;
+        urb->actual_length = 0;
+
+        for (j = urb->transfer_buffer_length, i = 0; i < urb->number_of_packets; i++) {
+                
+                int                     send = MIN(isotest->iso_in_size, j);
+                j -= send;
+                urb->iso_frame_desc[i].offset = i * isotest->iso_in_size;
+                urb->iso_frame_desc[i].length = send;
+        }       
+
+        RETURN_ZERO_IF(!(rc = usb_submit_urb(urb)));
+        printk(KERN_INFO"%s: FAILED rc: %x\n", __FUNCTION__, rc);
+
+        //isotest_iso_in_free_urb(urb);
+        return rc;
+}
+
+
+/**
+ * isotest_iso_in_complete
+ */
+void isotest_iso_in_complete (struct urb *urb)
+{
+        struct usb_isotest *isotest = (struct usb_isotest *)urb->context;
+        int i;
+        int rc;
+        int status;
+
+        //printk(KERN_INFO"%s: urb: %p\n", __FUNCTION__, urb);
+
+        RETURN_IF(!urb);
+
+        if (isotest->closing) {
+                //printk(KERN_INFO"%s: urb: %p pre urbs: %d\n", __FUNCTION__, urb, isotest->in_urbs);
+                if (urb->transfer_buffer) {
+                        kfree(urb->transfer_buffer);
+                }
+                usb_free_urb(urb);
+                isotest->in_urbs--;
+                //printk(KERN_INFO"%s: urb: %p pre urbs: %d\n", __FUNCTION__, urb, isotest->in_urbs);
+                return;
+        }
+        status = urb->status;
+
+        if (status /* && (status != -ENOENT) && (status != -ECONNRESET)*/) {
+                //printk(KERN_INFO"%s: - urb: %p nonzero write iso status received: %x\n", __FUNCTION__, urb, status);
+        }
+
+        else if (urb->actual_length) {
+                //printk(KERN_INFO"%s: urb: %p lenght: %d\n", __FUNCTION__, urb, urb->actual_length);
+                in_completed++;
+                in_total_received += urb->actual_length;
+
+                //printk(KERN_INFO"%s: ", __FUNCTION__);
+                for (i = 0; i < urb->number_of_packets; i++) {
+
+                        iso_trace_recv_data(&isotest->stats, 
+                                        urb->transfer_buffer + urb->iso_frame_desc[i].offset,
+                                        urb->iso_frame_desc[i].actual_length, 0);
+
+                //        printk("%d:%d:%x ", i, 
+                //                        urb->iso_frame_desc[i].actual_length,
+                //                        urb->iso_frame_desc[i].status);
+
+
+                }       
+                //printk("\n");
+        }
+
+        THROW_IF((rc = iso_in_submit(isotest, urb)), error);
+
+        in_resubmitted++;
+
+        CATCH(error) {
+                printk(KERN_INFO"%s: FAILED rc: %x\n", __FUNCTION__, rc);
+        }
+}
+
+
+struct urb *iso_in_start(struct usb_isotest *isotest)
+{
+        struct urb *            urb = NULL;
+        int                     frames = (ISO_SEND_TOTAL + isotest->iso_in_size) / isotest->iso_in_size;
+        int                     iso_transfer_size;
+        int                     rc = 0;
+
+
+        //RETURN_NULL_IF(in_count-- <= 0);
+
+        //printk(KERN_INFO"%s: %d %02x\n", __FUNCTION__, in_count, isotest->iso_in_endpointAddr);
+
+        //iso_transfer_size = ((ISO_SEND_TOTAL % isotest->iso_in_size) > 20) ?
+        //        ISO_SEND_TOTAL :
+        //        ISO_SEND_TOTAL + (20 - (ISO_SEND_TOTAL % isotest->iso_in_size));
+
+        iso_transfer_size = frames * isotest->iso_in_size;
+
+        THROW_IF(!(urb = usb_alloc_urb(frames + 1)), error);
+        THROW_IF (!(urb->transfer_buffer = kmalloc(iso_transfer_size, GFP_ATOMIC)), error);
+        memset(urb->transfer_buffer, 0, isotest->iso_in_size);
+
+        urb->hcpriv = NULL;
+        urb->context = isotest;
+        urb->transfer_flags = USB_ISO_ASAP;
+        urb->complete = isotest_iso_in_complete;
+        urb->pipe = usb_rcvisocpipe(isotest->udev, isotest->iso_in_endpointAddr);
+
+        urb->transfer_buffer_length = iso_transfer_size;
+        urb->number_of_packets = frames;
+
+        THROW_IF((rc = iso_in_submit(isotest, urb)), error);
+        in_submitted++;
+        isotest->in_urbs++;
+        //printk(KERN_INFO"%s: new urbs: %d\n", __FUNCTION__, isotest->in_urbs);
+        return urb;
+
+        CATCH(error) {
+                printk(KERN_INFO"%s: FAILED rc: %x\n", __FUNCTION__, rc);
+                //isotest_iso_in_free_urb(urb);
+                return NULL;
+        }
+}
+
+
+
+
+/* ********************************************************************************************* */
+
+void isotest_schedule_bh(struct usb_isotest *isotest)
+{
+        unsigned long   flags;
+
+        //RETURN_IF(!isotest->iso_bh.data);
+
+        // schedule more data
+        local_irq_save (flags);
+        if (isotest->iso_bh.data && !isotest->iso_bh.sync) {
+                MOD_INC_USE_COUNT;
+                queue_task(&isotest->iso_bh, &tq_immediate);
+                mark_bh(IMMEDIATE_BH);
+        }
+        local_irq_restore (flags);
+}
+
+
+static void bottomhalf(void *data)
+{
+        int i;
+        unsigned long   flags;
+        struct usb_isotest *isotest = (struct usb_isotest *) data;
+
+        if (isotest->first) {
+                //sleep_on_timeout(&isotest->iso_wq, 200);
+                udelay(100);
+                isotest->first = 0;
+        }
+
+        THROW_IF(!isotest, error);
+
+        if (isotest->closing) {
+                struct urb *urb;
+                //printk(KERN_INFO"%s: closing\n", __FUNCTION__);
+
+                // unlink outstanding urbs, this has side-effect of calling completion routing
+                local_irq_save (flags);
+                for (i = 0; i < IN_URBS; i++) {
+                        CONTINUE_IF(!(urb = isotest->iso_in_urbs[i]));
+                        //printk(KERN_INFO"%s: unlinking: %d IN urb: %p\n", __FUNCTION__, i, urb);
+                        isotest->iso_in_urbs[i] = NULL;
+                        urb->transfer_flags |= USB_ASYNC_UNLINK;
+                        usb_unlink_urb(urb);
+                }
+                local_irq_restore (flags);
+
+                local_irq_save (flags);
+                for (i = 0; i < OUT_URBS; i++) {
+                        CONTINUE_IF(!(urb = isotest->iso_out_urbs[i]));
+                        //printk(KERN_INFO"%s: unlinking: %d OUT urb: %p\n", __FUNCTION__, i, urb);
+                        isotest->iso_out_urbs[i] = NULL;
+                        urb->transfer_flags |= USB_ASYNC_UNLINK;
+                        usb_unlink_urb(urb);
+                }
+                local_irq_restore (flags);
+
+                // tell disconnect that we are finished
+                isotest->iso_bh.data = NULL;
+
+        }
+        else {
+
+                //printk(KERN_INFO"%s: normal\n", __FUNCTION__);
+
+                if (send && out_count) {
+                        local_irq_save (flags);
+                        for (i = 0; i < OUT_URBS; i++) {
+                                CONTINUE_IF(isotest->iso_out_urbs[i]);
+                                isotest->iso_out_urbs[i] = iso_out_start(isotest);
+                                //printk(KERN_INFO"%s: starting: %d OUT urb: %p\n", __FUNCTION__, i, isotest->iso_out_urbs[i]);
+                        }
+                        local_irq_restore (flags);
+                }
+
+                if (recv && in_count) {
+                        local_irq_save (flags);
+                        for (i = 0; i < IN_URBS; i++) {
+                                CONTINUE_IF(isotest->iso_in_urbs[i]);
+                                isotest->iso_in_urbs[i] = iso_in_start(isotest);
+                                //printk(KERN_INFO"%s: starting: %d IN urb: %p\n", __FUNCTION__, i, isotest->iso_in_urbs[i]);
+                        }
+                        local_irq_restore (flags);
+                }
+        }
+
+        CATCH(error) {
+                printk(KERN_ERR"%s: isotest NULL\n", __FUNCTION__);
+        }
+        MOD_DEC_USE_COUNT;
+}
+
+/* ********************************************************************************************* */
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver isotest_driver = {
+        name:           "isotest",
+        probe:          isotest_probe,
+        disconnect:     isotest_disconnect,
+        id_table:       isotest_table,
+};
+
+/**
+ * isotest_probe
+ *
+ * Called by the usb core when a new device is connected that it thinks
+ * this driver might be interested in.
+ */
+static void * isotest_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
+{
+        struct usb_isotest *isotest = NULL;
+        struct usb_interface *interface;
+        struct usb_device_descriptor *device = &udev->descriptor;
+        struct usb_interface_descriptor *interface_descriptor;
+        int i;
+
+        printk(KERN_INFO"%s: %04x %04x\n", __FUNCTION__, device->idVendor, device->idProduct);
+
+        // See if the device offered us matches what we can accept 
+        //if ((device->idVendor != vendor_id) || (device->idProduct != product_id)) {
+        //        printk(KERN_INFO"%s: FAILED\n", __FUNCTION__);
+        // return NULL;
+        //}
+
+        // allocate memory for our device state and intialize it 
+        if (!(isotest = kmalloc (sizeof(struct usb_isotest), GFP_KERNEL))) {
+                printk(KERN_INFO"%s: Out of memory\n", __FUNCTION__);
+                return NULL;
+        }
+
+        memset (isotest, 0x00, sizeof (*isotest));
+        init_MUTEX (&isotest->sem);
+        init_waitqueue_head(&isotest->iso_wq);
+
+        isotest->udev = udev;
+        isotest->first = 1;
+        isotest->closing = 0;
+        isotest->in_urbs = 0;
+        isotest->interface = interface = &udev->actconfig->interface[ifnum];
+        isotest->iso_bh.routine = bottomhalf;
+        isotest->iso_bh.data = (void *)isotest;
+        interface_descriptor = &interface->altsetting[0];
+
+        // set up the endpoint information and check out the endpoints 
+
+        for (i = 0; i < interface_descriptor->bNumEndpoints; ++i) {
+
+                struct usb_endpoint_descriptor *endpoint = &interface_descriptor->endpoint[i];
+
+                //printk(KERN_INFO"%s: looking at %02x\n", __FUNCTION__, endpoint->bEndpointAddress);
+
+                if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x01)) {
+
+                        //printk(KERN_INFO"%s: found ISO IN %02x\n", __FUNCTION__, endpoint->bEndpointAddress);
+                        isotest->iso_in_size = endpoint->wMaxPacketSize;
+                        isotest->iso_in_endpointAddr = endpoint->bEndpointAddress;
+                }
+
+                if (((endpoint->bEndpointAddress & 0x80) == 0x00) && ((endpoint->bmAttributes & 3) == 0x01)) {
+
+                        //printk(KERN_INFO"%s: found ISO OUT %02x\n", __FUNCTION__, endpoint->bEndpointAddress);
+
+                        isotest->iso_out_size = endpoint->wMaxPacketSize;
+                        isotest->iso_out_endpointAddr = endpoint->bEndpointAddress;
+                }
+        }
+
+        out_count = ISO_SEND_TRANSFERS;
+
+        // let the user know what node this device is now attached to 
+        //printk(KERN_INFO"%s: USB TEST device now attached to ISOTEST\n", __FUNCTION__);
+
+        isotest_schedule_bh(isotest);
+
+        return isotest;
+}
+
+/**
+ * isotest_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ */
+static void isotest_disconnect(struct usb_device *udev, void *ptr)
+{
+        struct usb_isotest *isotest;
+
+        printk(KERN_INFO"%s: in_submitted: %d in_resubmitted: %d in_completed: %ld in_total: %ld\n", 
+                        __FUNCTION__, in_submitted, in_resubmitted, in_completed, in_total_received);
+
+        RETURN_IF(!(isotest = (struct usb_isotest *)ptr));
+
+        // set flag to say we are closing
+        isotest->closing = 1;
+        isotest_schedule_bh(isotest);
+
+        while (isotest->iso_bh.data) {
+                isotest_schedule_bh(isotest);
+                printk(KERN_INFO"%s: waiting for bh\n", __FUNCTION__);
+                sleep_on_timeout(&isotest->iso_wq, 20);
+        }
+
+        while (isotest->in_urbs) {
+                printk(KERN_INFO"%s: waiting for urbs\n", __FUNCTION__);
+                sleep_on_timeout(&isotest->iso_wq, 20);
+        }
+
+        kfree(isotest);
+
+        printk(KERN_INFO"%s: USB ISOTEST now disconnected\n", __FUNCTION__);
+}
+
+
+/* ********************************************************************************************* */
+
+void iso_start_in(int count)
+{
+
+}
+
+void iso_start_out(int count)
+{
+
+}
+
+
+/**
+ * isotest_init
+ */
+static int isotest_init(void)
+{
+        int result;
+
+        printk(KERN_INFO"%s:\n", __FUNCTION__);
+
+        if (vendor_id && product_id) {
+                int i;
+                for (i = 0; i < (sizeof(isotest_table) / sizeof(struct usb_device_id) - 1); i++) {
+
+                        if ((isotest_table[i].idVendor == vendor_id) && isotest_table[i].idProduct == product_id ) {
+                                printk(KERN_INFO"%s: vendor_id: %04x product_id: %04x already in table\n",
+                                                __FUNCTION__, vendor_id, product_id);
+                                break;
+                        }
+                        printk(KERN_INFO"%s: vendor_id: %04x product_id: %04x\n",
+                                        __FUNCTION__, isotest_table[i].idVendor, isotest_table[i].idProduct);
+                }
+                if (!isotest_table[i].idVendor && !isotest_table[i].idProduct) {
+                        printk(KERN_INFO"%s: inserting vendor_id: %04x product_id: %04x into table\n",
+                                        __FUNCTION__, vendor_id, product_id);
+
+                        isotest_table[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+                        isotest_table[i].idVendor = vendor_id;
+                        isotest_table[i].idProduct = product_id;
+                        isotest_table[i].bDeviceClass = 0;
+                        isotest_table[i].bDeviceSubClass = 0;
+                }
+        }
+
+        iso_trace_init("isotest_host");
+
+        /* register this driver with the USB subsystem */
+        result = usb_register(&isotest_driver);
+        if (result < 0) {
+                printk(KERN_INFO"%s: usb_register failed for the "__FILE__" driver. Error number %d\n", KERN_INFO, result);
+                return -1;
+        }
+
+        printk(KERN_INFO "%s: " DRIVER_DESC " " DRIVER_VERSION "\n", __FUNCTION__);
+        return 0;
+}
+
+
+/**
+ * isotest_exit
+ */
+static void isotest_exit(void)
+{
+        /* deregister this driver with the USB subsystem */
+        usb_deregister(&isotest_driver);
+
+        iso_trace_exit("isotest_host");
+}
+
+
+module_init (isotest_init);
+module_exit (isotest_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
+MODULE_LICENSE("PRIVATE");
+#endif
+
diff -uNr linux/drivers/no-otg/functions/isotest/iso.c linux/drivers/otg/functions/isotest/iso.c
--- linux/drivers/no-otg/functions/isotest/iso.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/isotest/iso.c	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,620 @@
+/*
+ * otg/isotest_fd/iso.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
+MODULE_DESCRIPTION ("USB Device Serial Function");
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
+MODULE_LICENSE("GPL");
+#endif
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/smp_lock.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+
+#include "usbp-chap9.h"
+#include <usbp-mem.h>
+#include <usbp-func.h>
+#include <usbp-admin.h>
+
+USBD_MODULE_INFO ("isotest_fd 2.0-beta");
+
+#include "test.h"
+#include "fermat.h"
+
+struct usb_isotest {
+        int interface;
+        struct usbd_function_instance *function;
+        rwlock_t rwlock;
+
+        int open;
+        int closing;
+        struct tq_struct iso_bh;
+        wait_queue_head_t       iso_wq;
+};
+
+#define ISO_OUT        0x00
+#define ISO_IN         0x01
+
+#define ENDPOINTS       0x02
+
+
+u8 isotest_requested_endpoints[ENDPOINTS+1] = {
+        USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS,
+        USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS,
+        0,
+};
+
+#define ISO_OUT_PKTSIZE 90
+#define ISO_IN_PKTSIZE 90
+#define isotest_requested_transferSizes xfer_sizes
+
+u16 xfer_sizes[ENDPOINTS+1] = {
+        ISO_OUT_PKTSIZE,
+        ISO_IN_PKTSIZE,
+        0,
+};
+
+
+
+/* Module Parameters ************************************************************************* */
+// override vendor ID
+static u32 vendor_id;
+MODULE_PARM (vendor_id, "i");
+MODULE_PARM_DESC (vendor_id, "vendor id");
+
+// override product ID
+static u32 product_id;
+MODULE_PARM (product_id, "i");
+MODULE_PARM_DESC (product_id, "product id");
+
+MODULE_PARM (xfer_sizes, "3-3h");
+MODULE_PARM_DESC (xfer_sizes, "Requested transfer sizes for each endpoint; default 90 for iso in and out");
+
+// packet sizes
+static u32 in = ISO_IN_PKTSIZE;
+MODULE_PARM (in, "i");
+MODULE_PARM_DESC (in, "in size");
+
+static u32 out = ISO_OUT_PKTSIZE;
+MODULE_PARM (out, "i");
+MODULE_PARM_DESC (out, "out size");
+
+static int fermat=0;
+MODULE_PARM (fermat, "i");
+MODULE_PARM_DESC (fermat, "Apply randomization to buffer");
+
+static int custom=0;
+MODULE_PARM (custom, "i");
+MODULE_PARM_DESC (custom, "Supply custom pattern via xmit_pattern parameter");
+
+static int print_all=0;
+MODULE_PARM (print_all, "i");
+MODULE_PARM_DESC (print_all, "Print all buffers, not just the first");
+
+#define ZERO4 0,0,0,0
+#define ZERO16 ZERO4,ZERO4,ZERO4,ZERO4
+#define ZERO64 ZERO16,ZERO16,ZERO16,ZERO16
+static u8 xmit_pattern[256]={1,0xE,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe, ZERO16,ZERO16,ZERO16,ZERO64,ZERO64,ZERO64};
+MODULE_PARM(xmit_pattern,"1-256b");
+MODULE_PARM_DESC(xmit_pattern, "pattern to be transmitted, count, size, payload; size is "
+                "the size of the payload following. count is the number of times to repeat the pattern (0=infinite)");
+static struct {
+        int     count;
+        int     size;
+        u8      *payload_start, *payload_end;
+        u8      *current;
+        int     total_size;
+        int     sent;
+} xps; // Transmit pattern state
+
+static void xmit_pattern_state_init(void);
+static u8 xmit_pattern_next(void);
+static void fill_xmit_buffer(u32 size, u8*buffer);
+
+static void xmit_pattern_state_init(){
+        xps.count = xmit_pattern[0];
+        xps.size = xmit_pattern[1];
+        xps.payload_start = xmit_pattern+2;
+        xps.payload_end = xps.payload_start + xps.size;
+        xps.current = xps.payload_start;
+        xps.sent = 0;
+        xps.total_size = xps.count * xps.size;
+}
+
+static u8 xmit_pattern_next(){
+
+        // current always points at the next character to send
+        u8      next_value = *xps.current++;
+
+        xps.sent += 1;
+
+        if (xps.current >= xps.payload_end)
+                xps.current = xps.payload_start; //Rewind buffer
+
+        // if Total pattern has been sent; rewind
+        if (xps.sent >= xps.total_size){
+                xmit_pattern_state_init();
+        }
+
+        return next_value;
+}
+
+static void fill_xmit_buffer(u32 size, u8 *buffer)
+{
+        u8 * limit = buffer + size;
+        xmit_pattern_state_init();
+        while(buffer < limit){
+                *buffer++ = xmit_pattern_next();
+        }
+}
+
+static void fill_xmit_buffer_default(u32 size, u8 * buffer){
+        int  j;
+        for(j = 0; j < size; j++){
+                buffer[j] = j & 0xff;
+        }
+}
+
+static void print_buffer(u32 size, u8 * buffer){
+        // Print up to 16 bytes of the buffer, first time called only
+        static int first = 1;
+        int n = ( size >=16 ? 16 : size);
+        int j;
+        if((first) || (print_all)){
+                char *prefix = first? "\n" : "";
+                printk(KERN_INFO "%sxmit buffer:", prefix);
+                for( j=0 ; j < n; j++){
+                        printk("%02x",buffer[j]);
+                }
+                printk("\n");
+                first = 0;
+        }
+}
+
+
+
+/* ************************************************************************** */
+
+static struct isotest_stats isotest_stats;
+static struct usb_isotest isotest;
+
+
+/* Classes descriptors
+ */
+
+static u8 isotest_ep_1[7] = { 0x07, USB_DT_ENDPOINT, 0, ISOCHRONOUS, ISO_OUT_PKTSIZE&0xff, (ISO_OUT_PKTSIZE>>8)&0xff, 0x00};
+static u8 isotest_ep_2[7] = { 0x07, USB_DT_ENDPOINT, 0, ISOCHRONOUS, ISO_IN_PKTSIZE&0xff, (ISO_IN_PKTSIZE>>8)&0xff, 0x00};
+
+static struct usbd_endpoint_descriptor *isotest_data_endpoints[] = { 
+        (struct usbd_endpoint_descriptor *) &isotest_ep_1, 
+        (struct usbd_endpoint_descriptor *) &isotest_ep_2 };
+
+u8 isotest_data_indexes [] = { ISO_OUT, ISO_IN, };
+
+
+/* Alternate descriptors
+ */
+static u8 isotest_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
+        0x09, USB_DT_INTERFACE, 0x00, 0x00, 0x01, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
+        0x00, 0x00, 0x00, 0x00,
+};
+
+
+/* Alternate descriptions
+ */
+static struct usbd_alternate_description isotest_data_alternate_descriptions[] = {
+        { iInterface:CONFIG_OTG_ISOTEST_DATA_INTF,
+                interface_descriptor: (struct usbd_interface_descriptor *)&isotest_data_alternate_descriptor,
+                endpoints:sizeof (isotest_data_endpoints) / sizeof(u8 *),
+                endpoint_list: isotest_data_endpoints, 
+                endpoint_indexes: isotest_data_indexes,
+        },
+};
+
+
+/* Interface descriptions
+ */
+static struct usbd_interface_description isotest_interfaces[] = {
+        { alternates:sizeof (isotest_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+alternate_list:isotest_data_alternate_descriptions,
+        },
+};
+
+
+/* Configuration descriptions
+ */
+static u8 isotest_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
+        0x09, USB_DT_CONFIGURATION, 0x00, 0x00, // wLength
+        sizeof (isotest_interfaces) / sizeof (struct usbd_interface_description),
+        0x01, 0x00, // bConfigurationValue, iConfiguration
+        0, 0,
+};
+
+
+struct usbd_configuration_description isotest_description[] = {
+        { iConfiguration:CONFIG_OTG_ISOTEST_DESC,
+                configuration_descriptor: (struct usbd_configuration_descriptor *)isotest_configuration_descriptor,
+        },
+};
+
+/* Device Description
+ */
+static struct usbd_device_descriptor isotest_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x00,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_ISOTEST_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_ISOTEST_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ISOTEST_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+static struct usbd_device_qualifier_descriptor isotest_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x00,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+static struct usbd_endpoint_request iso_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS, ISO_OUT_PKTSIZE, ISO_OUT_PKTSIZE * 4, },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS, ISO_IN_PKTSIZE, ISO_OUT_PKTSIZE * 4, },
+        { 1, },
+};
+
+static struct usbd_otg_descriptor iso_otg_descriptor = {
+bLength : sizeof(struct usbd_otg_descriptor),
+bDescriptorType: USB_DT_OTG,
+bmAttributes: 0,
+};
+
+struct usbd_device_description isotest_device_description = {
+        device_descriptor: &isotest_device_descriptor,
+        #ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &isotest_device_qualifier_descriptor,
+        #endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &iso_otg_descriptor,
+        iManufacturer: CONFIG_OTG_ISOTEST_MANUFACTURER,
+        iProduct: CONFIG_OTG_ISOTEST_PRODUCT_NAME,
+        #if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR,
+        #endif
+};
+
+void iso_start_in(int count);
+void iso_start_out(int count);
+
+void schedule_bh(void) 
+{
+        unsigned long   flags;
+
+        //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
+
+        local_irq_save (flags);
+        if (!isotest.iso_bh.sync) {
+                MOD_INC_USE_COUNT;
+                queue_task(&isotest.iso_bh, &tq_immediate);
+                mark_bh(IMMEDIATE_BH);
+        }
+        local_irq_restore (flags);
+
+        //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
+}
+
+
+int isotest_urb_sent (struct usbd_urb *urb, int rc);
+int isotest_recv_urb (struct usbd_urb *urb, int rc);
+
+/* Transmit Function *************************************************************************** */
+
+static int out_count;
+static int in_count;
+static int send_size = 1000;
+static int iso_transfer_in_count;
+
+static int isotest_xmit_data (void)
+{
+        int i; 
+        int j; 
+        int frames;
+        int size = ((send_size % in) < 20) ? send_size + 20 : send_size;
+        struct usbd_urb *urb;
+        struct usbd_function_instance *function = isotest.function;
+
+        //printk(KERN_INFO"%s: open: %d in_count: %d\n", __FUNCTION__, isotest.open, in_count);
+
+        RETURN_ZERO_IF(!isotest.open);
+
+        RETURN_EINVAL_IF(!(urb = usbd_alloc_urb (isotest.function, ISO_IN, size, isotest_urb_sent)));
+
+        frames = (size / in) + 1;
+
+        iso_transfer_in_count++;
+
+        for (i = 0; i < frames; i++) {
+
+                u8 *cp = urb->buffer + (i * in);
+                if(custom){
+                        (void) fill_xmit_buffer(in, cp);
+                } else {
+                        (void) fill_xmit_buffer_default(in,cp);
+                }
+                if(fermat){
+                        fermat_encode(cp, in);
+                }
+                print_buffer(in, cp);
+
+                // iso_transfer_count
+                *cp++ = cpu_to_le16(iso_transfer_in_count) & 0xff;
+                *cp++ = (cpu_to_le16(iso_transfer_in_count) >> 8) & 0xff;
+                *cp++ = (cpu_to_le16(iso_transfer_in_count) >> 16) & 0xff;
+                *cp++ = (cpu_to_le16(iso_transfer_in_count) >> 24) & 0xff;
+
+                // iso transfer length
+                *cp++ = cpu_to_le16(size) & 0xff;
+                *cp++ = (cpu_to_le16(size) >> 8) & 0xff;
+
+                // iso frame size
+                *cp++ = cpu_to_le16(in) & 0xff;
+                *cp++ = (cpu_to_le16(in) >> 8) & 0xff;
+
+                // total frames
+                *cp++ = cpu_to_le16(frames) & 0xff;
+                *cp++ = (cpu_to_le16(frames) >> 8) & 0xff;
+
+                // this packet number
+                *cp++ = cpu_to_le16(i+1) & 0xff;
+                *cp++ = (cpu_to_le16(i+1) >> 8) & 0xff;
+
+        }
+        urb->actual_length = size;
+
+        // push it down into the usb-device layer
+        //printk(KERN_INFO"%s: sending: %p length: %d\n", __FUNCTION__, urb, urb->actual_length);
+        return usbd_start_in_urb (urb);
+}
+
+
+/* isotest_urb_sent - called to indicate URB transmit finished
+ * @urb: pointer to struct usbd_urb
+ * @rc: result
+ */
+int isotest_urb_sent (struct usbd_urb *urb, int rc)
+{
+        //printk(KERN_INFO"%s: sent: %p status: %d\n", __FUNCTION__, urb, urb->status);
+
+        usbd_free_urb (urb);
+
+        //printk(KERN_INFO"%s: calling schedule_bh\n", __FUNCTION__);
+        schedule_bh();
+        return 0;
+}
+
+
+/* USB Device Functions ************************************************************************ */
+
+/* isotest_event_handler - process a device event
+ *
+ */
+void isotest_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
+{
+        int i;
+        switch (event) {
+
+        case DEVICE_RESET:
+        case DEVICE_DESTROY:
+                if (isotest.open) 
+                        usbd_disable_irq(NULL);
+
+                isotest.open = 0;
+                break;
+
+        case DEVICE_CONFIGURED:
+                isotest.open = 1;
+                for (i = 0; i < 2; i++) {
+                        struct usbd_urb *urb;
+                        BREAK_IF(!(urb = usbd_alloc_urb (function, ISO_OUT, 
+                                                        usbd_endpoint_transferSize(
+                                                                function, ISO_OUT,usbd_high_speed(function)), 
+                                                        isotest_recv_urb
+                                                        )));
+                        if (usbd_start_out_urb(urb)) 
+                                usbd_free_urb(urb);
+                }
+                iso_start_in(100);
+                break;
+
+        case DEVICE_BUS_INACTIVE:
+                break;
+
+        case DEVICE_BUS_ACTIVITY:
+                break;
+
+        default:
+                break;
+        }
+}
+
+
+/* isotest_recv_urb - called to indicate URB has been received
+ * @urb - pointer to struct usbd_urb
+ *
+ * Return non-zero if we failed and urb is still valid (not disposed)
+ */
+int isotest_recv_urb (struct usbd_urb *urb, int rc)
+{
+        //struct usbd_device_instance *device = urb->device;
+#if 0
+        printk(KERN_INFO"%s: urb: %p length: %d framenum: %04x %d\n", __FUNCTION__, 
+                        urb, urb->actual_length, urb->framenum, urb->framenum);
+#endif
+        iso_trace_recv_data(&isotest_stats, urb->buffer, urb->actual_length, 0);
+
+        // start_recv urb
+        return (usbd_start_out_urb (urb));
+}
+
+
+/* ********************************************************************************************* */
+
+void iso_start_in(int count)
+{
+        in_count = count;
+        //printk(KERN_INFO"%s: calling schedule_bh\n", __FUNCTION__);
+        schedule_bh();
+}
+
+void iso_start_out(int count)
+{
+        out_count = count;
+        //printk(KERN_INFO"%s: calling schedule_bh\n", __FUNCTION__);
+        schedule_bh();
+}
+
+static void
+bottomhalf(void *data)
+{       
+        //printk(KERN_INFO"%s: closing: %d\n", __FUNCTION__, isotest.closing);
+        if (isotest.closing) 
+                isotest.iso_bh.data = NULL;
+
+        else if (isotest.open) 
+                isotest_xmit_data ();
+
+        MOD_DEC_USE_COUNT;
+        //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
+}
+
+
+/* ********************************************************************************************* */
+
+static int isotest_function_enable (struct usbd_function_instance *function)
+{
+        //printk(KERN_INFO"%s:\n", __FUNCTION__);
+        MOD_INC_USE_COUNT;
+
+        //printk(KERN_INFO"%s: calling schedule_bh\n", __FUNCTION__);
+        isotest.closing = 0;
+        schedule_bh();
+        return 0;
+}
+
+static void isotest_function_disable (struct usbd_function_instance *function)
+{
+        isotest.closing = 1;
+        while (isotest.iso_bh.data) {
+                //printk(KERN_INFO"%s: calling schedule_bh\n", __FUNCTION__);
+                schedule_bh();
+                //printk(KERN_INFO"%s: waiting\n", __FUNCTION__);
+                sleep_on_timeout(&isotest.iso_wq, 20);
+        }
+        MOD_DEC_USE_COUNT;
+}
+
+
+struct usbd_function_operations function_ops = {
+        event_handler:isotest_event_handler,
+        function_enable: isotest_function_enable,
+        function_disable: isotest_function_disable,
+};
+
+struct usbd_function_driver function_driver = {
+        name:"ISO Test Function",
+        fops:&function_ops,
+        device_description:&isotest_device_description,
+        bNumConfigurations:sizeof (isotest_description) / sizeof (struct usbd_configuration_description),
+        configuration_description:isotest_description,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_ISOTEST_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_ISOTEST_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_ISOTEST_BCDDEVICE),
+        bNumInterfaces:sizeof (isotest_interfaces) / sizeof (struct usbd_interface_description),
+        interface_list:isotest_interfaces,
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: iso_endpoint_requests,
+};
+
+
+/*
+ * isotest_modinit - module init
+ *
+ */
+static int isotest_modinit (void)
+{
+        printk (KERN_INFO "vendor_id: %04x product_id: %04x in: %02x out: %02x\n", 
+                        vendor_id, product_id, in, out);
+
+        if (vendor_id) 
+                function_driver.idVendor = cpu_to_le16(vendor_id);
+
+        if (product_id) 
+                function_driver.idProduct = cpu_to_le16(product_id);
+
+
+        isotest_ep_1[4] = out&0xff;
+        isotest_ep_1[5] = (out>>8)&0xff;
+        isotest_ep_2[4] = in&0xff;
+        isotest_ep_2[5] = (in>>8)&0xff;
+
+        // XXX should this be the endpoint request structure?
+        iso_endpoint_requests[0].fs_requestedTransferSize = out;
+        iso_endpoint_requests[1].fs_requestedTransferSize = in;
+
+        iso_trace_init("isotest_fd");
+        if(fermat){
+                fermat_init();
+        }
+
+        isotest.iso_bh.routine = bottomhalf;
+        isotest.iso_bh.data = (void *)&isotest;
+        init_waitqueue_head(&isotest.iso_wq);
+
+        // register us with the usb device support layer
+        RETURN_EINVAL_IF (usbd_register_function (&function_driver, "isotest", NULL));
+
+        // return
+        return 0;
+}
+
+
+/* isotest_modexit - module cleanup
+ */
+static void isotest_modexit (void)
+{
+        usbd_deregister_function (&function_driver);
+        iso_trace_exit("isotest_fd");
+}
+
+module_init (isotest_modinit);
+module_exit (isotest_modexit);
+
diff -uNr linux/drivers/no-otg/functions/isotest/iso_fermat linux/drivers/otg/functions/isotest/iso_fermat
--- linux/drivers/no-otg/functions/isotest/iso_fermat	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/isotest/iso_fermat	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,34 @@
+#!/bin/sh
+XFER=$1
+PATTERN=$2
+if [ -z "$PATTERN" ]
+then
+	PATTERN="0x1,0x8,1,2,3,4,5,6,7,8"
+fi
+echo "Using PATTERN='$PATTERN'"
+set -x
+
+insmod  /tmp/usbdcore.o 
+insmod /tmp/usbdprocfs.o
+
+insmod  /tmp/isotest_fd.o vendor_id=0xfff0 product_id=0xfff1 in=$XFER out=$XFER xmit_pattern="$PATTERN" print_all=0 fermat=1 custom=0
+
+insmod  /tmp/au1x00_bi.o 
+echo "enable" > /proc/usbd-switch
+
+
+set +x
+echo -n "INSERT CABLE"
+sleep 15
+echo -n ";  REMOVE CABLE AND PRESS RETURN"
+read junk
+set -x
+cp /proc/isotest_fd client
+cp /proc/isotest_host host
+echo "disable" > /proc/usbd-switch
+
+rmmod au1x00_bi
+rmmod isotest_fd
+rmmod usbdprocfs
+rmmod usbdcore
+
diff -uNr linux/drivers/no-otg/functions/isotest/iso_one linux/drivers/otg/functions/isotest/iso_one
--- linux/drivers/no-otg/functions/isotest/iso_one	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/isotest/iso_one	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,34 @@
+#!/bin/sh
+XFER=$1
+PATTERN=$2
+if [ -z "$PATTERN" ]
+then
+	PATTERN="0x1,0x1,0xFF"
+fi
+echo "Using PATTERN='$PATTERN'"
+set -x
+
+insmod  /tmp/usbdcore.o 
+insmod /tmp/usbdprocfs.o
+
+insmod  /tmp/isotest_fd.o vendor_id=0xfff0 product_id=0xfff1 in=$XFER out=$XFER xmit_pattern="$PATTERN" print_all=1 fermat=0 custom=1
+
+insmod  /tmp/au1x00_bi.o 
+echo "enable" > /proc/usbd-switch
+
+
+set +x
+echo -n "INSERT CABLE"
+sleep 15
+echo -n ";  REMOVE CABLE AND PRESS RETURN"
+read junk
+set -x
+cp /proc/isotest_fd client
+cp /proc/isotest_host host
+echo "disable" > /proc/usbd-switch
+
+rmmod au1x00_bi
+rmmod isotest_fd
+rmmod usbdprocfs
+rmmod usbdcore
+
diff -uNr linux/drivers/no-otg/functions/isotest/iso_zero linux/drivers/otg/functions/isotest/iso_zero
--- linux/drivers/no-otg/functions/isotest/iso_zero	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/isotest/iso_zero	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,34 @@
+#!/bin/sh
+XFER=$1
+PATTERN=$2
+if [ -z "$PATTERN" ]
+then
+	PATTERN="0x1,0x1,0x00"
+fi
+echo "Using PATTERN='$PATTERN'"
+set -x
+
+insmod  /tmp/usbdcore.o 
+insmod /tmp/usbdprocfs.o
+
+insmod  /tmp/isotest_fd.o vendor_id=0xfff0 product_id=0xfff1 in=$XFER out=$XFER xmit_pattern="$PATTERN" print_all=1 fermat=0 custom=1
+
+insmod  /tmp/au1x00_bi.o 
+echo "enable" > /proc/usbd-switch
+
+
+set +x
+echo -n "INSERT CABLE"
+sleep 15
+echo -n ";  REMOVE CABLE AND PRESS RETURN"
+read junk
+set -x
+cp /proc/isotest_fd client
+cp /proc/isotest_host host
+echo "disable" > /proc/usbd-switch
+
+rmmod au1x00_bi
+rmmod isotest_fd
+rmmod usbdprocfs
+rmmod usbdcore
+
diff -uNr linux/drivers/no-otg/functions/isotest/iso_zero_silent linux/drivers/otg/functions/isotest/iso_zero_silent
--- linux/drivers/no-otg/functions/isotest/iso_zero_silent	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/isotest/iso_zero_silent	2006-09-01 21:41:26.000000000 +0200
@@ -0,0 +1,34 @@
+#!/bin/sh
+XFER=$1
+PATTERN=$2
+if [ -z "$PATTERN" ]
+then
+	PATTERN="0x1,0x1,0x00"
+fi
+echo "Using PATTERN='$PATTERN'"
+set -x
+
+insmod  /tmp/usbdcore.o 
+insmod /tmp/usbdprocfs.o
+
+insmod  /tmp/isotest_fd.o vendor_id=0xfff0 product_id=0xfff1 in=$XFER out=$XFER xmit_pattern="$PATTERN" print_all=0 fermat=0 custom=1
+
+insmod  /tmp/au1x00_bi.o 
+echo "enable" > /proc/usbd-switch
+
+
+set +x
+echo -n "INSERT CABLE"
+sleep 15
+echo -n ";  REMOVE CABLE AND PRESS RETURN"
+read junk
+set -x
+cp /proc/isotest_fd client
+cp /proc/isotest_host host
+echo "disable" > /proc/usbd-switch
+
+rmmod au1x00_bi
+rmmod isotest_fd
+rmmod usbdprocfs
+rmmod usbdcore
+
diff -uNr linux/drivers/no-otg/functions/isotest/test.c linux/drivers/otg/functions/isotest/test.c
--- linux/drivers/no-otg/functions/isotest/test.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/isotest/test.c	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,456 @@
+/*
+ * otg/isotest_fd/test.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+//#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+//#include <linux/poll.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+//#include <linux/interrupt.h>
+//#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include <asm/io.h>
+#include <asm/string.h>
+
+#include <linux/proc_fs.h>
+
+#include <linux/netdevice.h>
+#include <linux/cache.h>
+
+
+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
+#include <asm/dma.h>
+#include <asm/mach/dma.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/types.h>
+#endif
+
+#if defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
+#include <asm/au1000.h>
+#include <asm/au1000_dma.h>
+#include <asm/mipsregs.h>
+#endif
+
+#if defined(CONFIG_ARCH_SAMSUNG)
+#include <asm/arch/timers.h>
+#include <asm/arch/hardware.h>
+#endif
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include "test.h"
+
+
+int iso_trace_first;
+int iso_trace_next;
+iso_trace_t *iso_traces;
+
+
+/* ******************************************************************************************* */
+
+void dump_stats(struct isotest_stats *stats)
+{
+        if (stats->errors || ((stats->ok % 100) == 99)) {
+                TRACE_ISO(stats->iso_transfer_number, stats->total_frames,
+                                stats->received, stats->errors, stats->missed, stats->skipped, stats->ok);
+        }
+        if (stats->errors) {
+                memset(stats, 0, sizeof(struct isotest_stats));
+        }
+        else {
+                stats->ok++;
+                stats->iso_transfer_number++;
+                stats->last_packet = 0;
+        }
+}
+
+u16 getu16(u8 **cp)
+{
+        u16     val = 0;
+
+        val = *(*cp)++;
+        val |= *(*cp)++ << 8;
+
+        return val;
+}
+
+u16 getu32(u8 **cp)
+{
+        u32     val = 0;
+
+        val = *(*cp)++;
+        val |= *(*cp)++ << 8;
+        val |= *(*cp)++ << 16;
+        val |= *(*cp)++ << 24;
+
+        return val;
+}
+
+static int iso_in_received;
+
+void iso_trace_recv_data (struct isotest_stats *stats, u8 *cp, int length, int framenum)
+{
+        //struct usb_device_instance *device = urb->device;
+
+        u16     iso_transfer_number;
+        u16     total_size;
+        u16     packet_size;
+        u16     total_frames;
+        u16     this_packet;
+        u8      frames;
+        
+        
+        iso_transfer_number = getu32(&cp);
+        total_size = getu16(&cp);
+        packet_size = getu16(&cp);
+        total_frames = getu16(&cp);
+        this_packet = getu16(&cp);
+
+                
+        // did we miss the end of the last ISO transfer?
+        if (stats->iso_transfer_number && (stats->iso_transfer_number != iso_transfer_number)) {
+                stats->errors++;
+                stats->missed++;
+                //printk(KERN_INFO"%s: ERROR bad iso number: %x %x %x %x %x expecting: %x\n", __FUNCTION__, iso_transfer_number,
+                //                total_size, packet_size, total_frames, this_packet, stats->iso_transfer_number);
+                dump_stats(stats);
+                return;
+        }
+                
+        if (!stats->iso_transfer_number) {
+                stats->framenum = framenum;
+                stats->iso_transfer_number = iso_transfer_number;
+                stats->total_frames = total_frames;
+        }
+
+        // is this the packet we are expecting?
+        if (stats->last_packet && ((stats->last_packet + 1) != this_packet)) {
+                stats->errors++;
+                stats->missed++;
+                //printk(KERN_INFO"%s: ERROR bad packet: %x %x %x %x %x expecting: %x\n", __FUNCTION__, iso_transfer_number,
+                //                total_size, packet_size, total_frames, this_packet, stats->last_packet + 1);
+        }
+        
+        // did we miss a frame? 
+        frames = (stats->framenum < framenum) ?  (framenum - stats->framenum) : (stats->framenum - framenum);
+        
+        if (frames > 1) {
+                stats->errors++;
+                stats->skipped++;
+                //printk(KERN_INFO"%s: SKIPPED %x %x %x %x %x\n", __FUNCTION__, iso_transfer_number,
+                //                total_size, packet_size, total_frames, this_packet);
+        }
+
+        // update stats
+        stats->received++;
+        stats->last_packet = this_packet;
+
+        // last packet?
+        if (stats->total_frames == this_packet) 
+                dump_stats(stats);
+}
+
+
+
+/* Proc Filesystem *************************************************************************** */
+        
+/* *    
+ * iso_trace_proc_read - implement proc file system read.
+ * @file        
+ * @buf         
+ * @count
+ * @pos 
+ *      
+ * Standard proc file system read function.
+ */         
+static ssize_t iso_trace_proc_read (struct file *file, char *buf, size_t count, loff_t * pos)
+{                                  
+        unsigned long page;
+        int len = 0;
+        int index;
+        int oindex;
+        int previous;
+
+        MOD_INC_USE_COUNT;
+        //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
+        // get a page, max 4095 bytes of data...
+        if (!(page = get_free_page (GFP_KERNEL))) {
+                MOD_DEC_USE_COUNT;
+                //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
+                return -ENOMEM;
+        }
+
+        len = 0;
+        oindex = index = (*pos)++;
+
+        if (index == 0) {
+              //len += sprintf ((char *) page + len, "      uS              Exp  Rcv   Err  Miss  Skip  OK\n");
+              //len += sprintf ((char *) page + len, "      uS            Exp  Rcv   Err  Miss  Skip  Xfers\n");
+                len += sprintf ((char *) page + len, "      uS           Tr   Exp   Rcv   Err  Miss  Skip  Xfers\n");
+
+//      uS            Exp  Rcv   Err  Miss  Skip  Xfers
+//      uS          Tr     Exp  Rcv   Err  Miss  Skip  Xfers
+//        0  |      100     9   900     0     0     0    99
+
+        }       
+                         
+        index += iso_trace_first;
+        if (index >= TRACE_MAX) {
+                index -= TRACE_MAX;
+        }
+        previous = (index) ? (index - 1) : (TRACE_MAX - 1);
+
+        //printk(KERN_INFO"first: %d next: %d index: %d %d prev: %d\n", iso_trace_first, iso_trace_next, oindex, index, previous);
+
+        if (
+                        ((iso_trace_first < iso_trace_next) && (index >= iso_trace_first) && (index < iso_trace_next)) ||
+                        ((iso_trace_first > iso_trace_next) && ((index < iso_trace_next) || (index >= iso_trace_first)))
+           )
+        {
+
+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA) || defined(CONFIG_MIPS_AU1000)  || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
+                u32 ticks = 0;
+#elif defined(CONFIG_ARCH_SAMSUNG)
+                u32 ticks = 0;
+#else
+                u64 jifs = 0;
+#endif
+                iso_trace_t *p = iso_traces + index;
+                //unsigned char *cp;
+                //int skip = 0;
+
+                if (oindex > 0) {
+                        iso_trace_t *o = iso_traces + previous;
+
+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
+                        /*
+                         * oscr is 3.6864 Mhz free running counter, 
+                         *
+                         *      1/3.6864 = .2712
+                         *      60/221   = .2714
+                         *
+                         */
+                        if (o->ocsr) {
+                                ticks = (p->ocsr > o->ocsr) ? (p->ocsr - o->ocsr) : (o->ocsr - p->ocsr) ;
+                                ticks = (ticks * 60) / 221;
+                        }
+
+#elif defined(CONFIG_MIPS_AU1000)  || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
+                        /*
+                         * cp0_count is incrementing timer at system clock
+                         */
+                        if (o->cp0_count) {
+                                //ticks = (p->cp0_count > o->cp0_count) ? 
+                                //        (p->cp0_count - o->cp0_count) : (o->cp0_count - p->cp0_count) ;
+                                ticks = (p->cp0_count - o->cp0_count) ;
+                                ticks = ticks / CONFIG_OTG_AU1X00_SCLOCK;
+                        }
+
+#elif defined(CONFIG_ARCH_SAMSUNG)
+                        /*
+                         * tcnt1 is a count-down timer running at the system bus clock
+                         * The divisor must be set as a configuration value, typically 66 or 133.
+                         */
+                        if (o->tcnt1) {
+                                ticks = (p->tcnt1 < o->tcnt1) ?  (o->tcnt1 - p->tcnt1) : (p->tcnt1 - o->tcnt1) ;
+                                ticks /= CONFIG_OTG_SMDK2500_BCLOCK;
+                        }
+#else
+                        if (o->jiffies) {
+                                jifs = p->jiffies - iso_traces[previous].jiffies;
+                        }
+#endif
+
+                        //if (o->interrupts != p->interrupts) {
+                        //        skip++;
+                        //}
+                }
+                
+
+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA) || defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
+                len += sprintf ((char *) page + len, "%9d  ", ticks);
+#elif defined(CONFIG_ARCH_SAMSUNG)
+                //len += sprintf ((char *) page + len, "%8u ", p->jiffies);
+                //len += sprintf ((char *) page + len, "%8u ", p->tcnt0);
+                len += sprintf ((char *) page + len, "%8u ", p->tcnt1);
+                if (ticks > 1024*1024) {
+                        len += sprintf ((char *) page + len, "%8dM ", ticks>>20);
+                }
+                else {
+                        len += sprintf ((char *) page + len, "%8d  ", ticks);
+                }
+#else
+                if (jifs > 1024) {
+                        len += sprintf ((char *) page + len, "%4dK", (int)jifs>>20);
+                }
+                else {
+                        len += sprintf ((char *) page + len, "%4d  ", (int)jifs);
+                }
+#endif
+
+                len += sprintf ((char *) page + len, "| %8d", p->iso_transfer_number);
+                len += sprintf ((char *) page + len, "%6d", p->expected);
+                len += sprintf ((char *) page + len, "%6d", p->received);
+                len += sprintf ((char *) page + len, "%6d", p->errors);
+                len += sprintf ((char *) page + len, "%6d", p->missed);
+                len += sprintf ((char *) page + len, "%6d", p->skipped);
+                len += sprintf ((char *) page + len, "%6d", p->ok);
+                len += sprintf ((char *) page + len, "\n");
+        }
+
+#if 1
+        if ((len > count) ) {
+                printk(KERN_INFO"%s: ((len > count)  count=%d len=%d\n", __FUNCTION__, count, len);
+                len = -EINVAL;
+        } 
+
+#else
+        if ((len > count) || (len == 0)) {
+                printk(KERN_INFO"%s: ((len > count) || (len == 0)) count=%d len=%d\n", __FUNCTION__, count, len);
+                len = -EINVAL;
+        } 
+#endif
+        else if (len > 0 && copy_to_user (buf, (char *) page, len)) {
+                printk(KERN_INFO"%s: (len > 0 && copy_to_user (buf, (char *) page, len) \n", __FUNCTION__);
+                len = -EFAULT;
+        }
+        free_page (page);
+        MOD_DEC_USE_COUNT;
+        //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
+        return len;
+}
+
+void iso_start_in(int count);
+void iso_start_out(int count);
+
+/* *
+ * iso_trace_proc_write - implement proc file system write.
+ * @file
+ * @buf
+ * @count
+ * @pos
+ *
+ * Proc file system write function, used to signal monitor actions complete.
+ * (Hotplug script (or whatever) writes to the file to signal the completion
+ * of the script.)  An ugly hack.
+ */
+static ssize_t iso_trace_proc_write (struct file *file, const char *buf, size_t count, loff_t * pos)
+{
+        //struct usb_device_instance *device;
+        size_t n = count;
+        char command[64];
+        char *cp = command;
+        int i = 0;
+
+        MOD_INC_USE_COUNT;
+        //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
+        //printk(KERN_DEBUG "%s: count=%u\n",__FUNCTION__,count);
+        while ((n > 0) && (i < 64)) {
+                // Not too efficient, but it shouldn't matter
+                if (copy_from_user (cp++, buf + (count - n), 1)) {
+                        count = -EFAULT;
+                        break;
+                }
+                *cp = '\0';
+                i++;
+                n -= 1;
+                //printk(KERN_DEBUG "%s: %u/%u %02x\n",__FUNCTION__,count-n,count,c);
+        }
+        if (!strncmp (command, "in", 2)) {
+                iso_start_in (10);
+        } 
+        else if (!strncmp (command, "out", 3)) {
+                iso_start_out (10);
+        } 
+        // XXX need to be able to set serial number here
+        MOD_DEC_USE_COUNT;
+        //printk(KERN_INFO"%s: GET_USE_COUNT: %d\n", __FUNCTION__, GET_USE_COUNT(THIS_MODULE));
+        return (count);
+}
+
+static struct file_operations iso_trace_proc_operations_functions = {
+read:iso_trace_proc_read,
+write:iso_trace_proc_write,
+};
+
+#if defined(CONFIG_ARCH_SAMSUNG)
+#endif
+
+/**
+ * iso_trace_init
+ *
+ * Return non-zero if not successful.
+ */
+int iso_trace_init (char *name)
+{
+        printk(KERN_INFO"%s:\n", __FUNCTION__);
+        if (!(iso_traces = vmalloc(sizeof(iso_trace_t) * TRACE_MAX))) {
+                printk(KERN_ERR"%s: malloc failed %p %d\n", __FUNCTION__, iso_traces, sizeof(iso_trace_t) * TRACE_MAX);
+                return -EINVAL;
+        }
+        memset(iso_traces, 0, sizeof(iso_trace_t) * TRACE_MAX);
+
+        {
+                struct proc_dir_entry *p;
+
+                // create proc filesystem entries
+                if ((p = create_proc_entry (name, 0, 0)) == NULL) {
+                        printk(KERN_INFO"BITRACE PROC FS failed\n");
+                }
+                else {
+                        p->proc_fops = &iso_trace_proc_operations_functions;
+                }
+        }
+#if defined(CONFIG_ARCH_SAMSUNG)
+        *(volatile u32 *)TMOD |= 0x3 << 3;
+#endif
+        printk(KERN_INFO"%s: OK\n", __FUNCTION__);
+        return 0;
+}
+
+/**
+ * udc_release_io - release UDC io region
+ */
+void iso_trace_exit (char *name)
+{
+        {
+                unsigned long flags;
+                local_irq_save (flags);
+                remove_proc_entry (name, NULL);
+                if (iso_traces) {
+                        iso_trace_t *p = iso_traces;
+                        iso_traces = 0;
+                        vfree(p);
+                }
+                local_irq_restore (flags);
+        }
+}
+
+
+/* End of FILE */
+
diff -uNr linux/drivers/no-otg/functions/isotest/test.h linux/drivers/otg/functions/isotest/test.h
--- linux/drivers/no-otg/functions/isotest/test.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/isotest/test.h	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,129 @@
+/*
+ * otg/isotest_fd/test.h
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *
+ */
+
+#if defined(CONFIG_ARCH_SAMSUNG)
+#ifndef CONFIG_OTG_SMDK2500_BCLOCK 
+#define CONFIG_OTG_SMDK2500_BCLOCK 66
+#endif
+#endif
+
+#define NUSBD_FRAMENUM             0xB0200038
+
+
+struct isotest_stats {
+
+        u16     count;
+
+        u16     iso_transfer_number;
+        u16     total_size;
+        u16     packet_size;
+        u16     total_frames;
+        u16     last_packet;
+
+
+        u16     framenum;
+        u16     received;
+        u16     missed;
+        u16     skipped;
+        u16     errors;
+
+        u32     ok;
+
+};
+
+
+
+
+
+typedef struct iso_trace_types {
+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
+        u32     ocsr;
+#elif defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
+        u32     cp0_count;
+#elif defined(CONFIG_ARCH_SAMSUNG)
+        u32     tcnt1;
+#else
+        u64     jiffies;
+#endif
+        u16     iso_transfer_number;
+
+        u16     expected;
+        u16     received;
+        u16     errors;
+        u16     missed;
+        u16     skipped;
+
+        u32     ok;
+
+} iso_trace_t;
+
+
+#define TRACE_MAX       3000
+
+extern int iso_trace_first;
+extern int iso_trace_next;
+
+extern iso_trace_t *iso_traces;
+
+static __inline__ iso_trace_t *ISO_TRACE_NEXT(void)
+{
+        iso_trace_t *p;
+
+        p = iso_traces + iso_trace_next;
+
+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
+        p->ocsr = OSCR;
+#elif defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
+        p->cp0_count = read_c0_count();
+#elif defined(CONFIG_ARCH_SAMSUNG)
+        p->tcnt1 = *(volatile u32 *)TCNT1;
+#else
+        p->jiffies = jiffies;
+#endif
+//#if defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
+//        p->iso_transfer_number = au_readl(NUSBD_FRAMENUM);
+//#endif
+
+        iso_trace_next++;
+        iso_trace_next = (iso_trace_next == TRACE_MAX) ? 0 : iso_trace_next;
+
+        if (iso_trace_next == iso_trace_first) {
+                iso_trace_first++;
+                iso_trace_first = (iso_trace_first == TRACE_MAX) ? 0 : iso_trace_first;
+        }
+
+        return p;
+}
+
+static __inline__ void TRACE_ISO(u16 iso_transfer_number, u16 expected, u16 received, u16 errors, u16 missed, u16 skipped, u32 ok)
+{
+        iso_trace_t *p = NULL;
+
+        //printk(KERN_INFO"%s: %d %d %d %d %d first: %d next: %d traces: %p\n", __FUNCTION__, 
+        //                expected, received, errors, missed, skipped, iso_trace_first, iso_trace_next, traces);
+
+        if (!iso_traces) return;
+
+        p = ISO_TRACE_NEXT();
+        p->iso_transfer_number = iso_transfer_number;
+        p->expected = expected;
+        p->received = received;
+        p->errors = errors;
+        p->missed = missed;
+        p->skipped = skipped;
+        p->ok = ok;
+}
+
+void iso_trace_recv_data (struct isotest_stats *stats, u8 *cp, int length, int framenum);
+int iso_trace_init (char *str);
+void iso_trace_exit (char *str);
+
diff -uNr linux/drivers/no-otg/functions/mouse/Config.in linux/drivers/otg/functions/mouse/Config.in
--- linux/drivers/no-otg/functions/mouse/Config.in	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/mouse/Config.in	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,28 @@
+#
+# Mouse Function Driver
+#
+# Copyright (C) 2003 Belcarra
+#
+
+
+mainmenu_option next_comment
+
+comment "USB Peripheral Function Driver - Random Mouse"
+dep_tristate '  Mouse Function' CONFIG_OTG_MOUSE $CONFIG_OTG
+
+if [ "$CONFIG_OTG_MOUSE" != "n" ]; then
+   hex    'VendorID (hex value)' CONFIG_OTG_MOUSE_VENDORID "15ec"
+   hex    'ProductID (hex value)' CONFIG_OTG_MOUSE_PRODUCTID "f003"
+   hex    'bcdDevice (binary-coded decimal)' CONFIG_OTG_MOUSE_BCDDEVICE "0100"
+
+   string 'iManufacturer (string)' CONFIG_OTG_MOUSE_MANUFACTURER "Belcarra"
+   #string 'iProduct (string)' CONFIG_OTG_MOUSE_PRODUCT_NAME "Belcarra Mouse"
+
+   string 'iConfiguration (string)' CONFIG_OTG_MOUSE_DESC "Mouse Cfg"
+   string 'Comm Interface iInterface (string)' CONFIG_OTG_MOUSE_COMM_INTF "Comm Intf"
+   bool   'Mouse BH Test'  CONFIG_OTG_MOUSE_BH
+   int    'Number of packets (zero is continous ' CONFIG_OTG_MOUSE_PACKETS "10"
+   int    'Polling Interval ' CONFIG_OTG_MOUSE_INTERVAL "1"
+
+fi
+endmenu
diff -uNr linux/drivers/no-otg/functions/mouse/Kconfig linux/drivers/otg/functions/mouse/Kconfig
--- linux/drivers/no-otg/functions/mouse/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/mouse/Kconfig	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,74 @@
+menu "OTG Random Mouse function"
+	depends on OTG
+
+config OTG_MOUSE
+        tristate "  Random Mouse Function"
+        depends on OTG
+	---help---
+        This implements a simple Mouse driver that sends HID packets with
+        small random movements. This is a good function for initial testing
+        of Peripheral Controller Drivers as it provides for a complicated
+        enumeration but a simple uni-directional (send Interrupt only) data
+        transport.
+
+menu "OTG Random Mouse function options"
+	depends on OTG && OTG_MOUSE
+
+config OTG_MOUSE_VENDORID
+        hex "VendorID (hex value)"
+        depends on OTG && OTG_MOUSE
+        default "0x15ec"
+
+config OTG_MOUSE_PRODUCTID
+        hex "ProductID (hex value)"
+        depends on OTG && OTG_MOUSE
+        default "0xf003"
+
+config OTG_MOUSE_BCDDEVICE
+        hex "bcdDevice (binary-coded decimal)"
+        depends on OTG && OTG_MOUSE
+        default "0x0100"
+
+config OTG_MOUSE_MANUFACTURER
+        string "iManufacturer (string)"
+        depends on OTG && OTG_MOUSE
+        default "Belcarra"
+
+config OTG_MOUSE_PRODUCT_NAME
+        string "iProduct (string)"
+        depends on OTG && OTG_MOUSE
+        default "Random Mouse Class - Interrupt"
+
+config OTG_MOUSE_COMM_INTF
+        string "MOUSE Bulk Only iInterface (string)"
+        depends on OTG && OTG_MOUSE
+        default "MOUSE Data Intf"
+
+config OTG_MOUSE_DESC
+        string "Data Interface iConfiguration (string)"
+        depends on OTG && OTG_MOUSE
+        default "MOUSE Configuration"
+
+config OTG_MOUSE_BH
+        bool "  MOUSE BH Test"
+        depends on OTG && OTG_MOUSE
+        default n
+	---help---
+        Implement the Mouse send packet in a bottom half handler,
+        this will delay responses to test the PCD works correctly
+        when the host polls before a send data urb is queued.
+
+
+config OTG_MOUSE_PACKETS
+        int "Number of packets (zero is continous)"
+        depends on OTG && OTG_MOUSE
+        default 10
+	---help---
+        Number of Mouse packets to send, will run
+        forever if set to zero.
+
+
+endmenu
+
+
+endmenu
diff -uNr linux/drivers/no-otg/functions/mouse/Makefile linux/drivers/otg/functions/mouse/Makefile
--- linux/drivers/no-otg/functions/mouse/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/mouse/Makefile	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,81 @@
+#
+# Function driver for a Mouse USB Device
+#
+# Copyright (c) 2003 Belcarra
+
+# Multipart objects.
+
+O_TARGET	:= mouse_target.o
+#list-multi	:= mouse_fd.o cmouse_fd.o
+list-multi     := mouse_fd.o
+
+mouse_fd-objs	:= mouse-fd.o mouse-l24.o
+#cmouse_fd-objs	:= mouse-cf.o mouse-if.o cmouse-l24.o
+#cmouse_fd-objs := mouse-if.o cmouse-l24.o
+
+# Objects that export symbols.
+#export-objs	:= mouse.o
+
+# Object file lists.
+
+obj-y	:=
+obj-m	:=
+obj-n	:=
+obj-	:=
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_OTG_MOUSE)   += mouse_fd.o
+#obj-$(CONFIG_OTG_MOUSE)   += cmouse_fd.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+int-m		:= $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
+OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+
+# The global Rules.make.
+
+#MOUSED=$(OTG)/functions/mouse
+
+OTG_WARNINGS=-Wno-unused -Wno-format
+OTG=$(TOPDIR)/drivers/otg
+OTG_INCLUDES=-I$(OTG)
+OTG_EXTRA=$(OTG_INCLUDES) $(OTG_WARNINGS)
+OTGCORE_DIR=$(OTG)/otgcore
+##USBDCORE_DIR=$(OTG)/usbdcore
+include $(TOPDIR)/Rules.make
+#EXTRA_CFLAGS +=  -I$(OTG) -Wno-unused -Wno-format  -I$(USBDCORE_DIR) -I$(OTGCORE_DIR)
+#EXTRA_CFLAGS_nostdinc += -I$(OTG) -Wno-unused -Wno-format  -I$(USBDCORE_DIR) -I$(OTGCORE_DIR)
+EXTRA_CFLAGS += $(OTG_EXTRA) 
+EXTRA_CFLAGS_nostdinc += $(OTG_EXTRA)
+
+# Link rules for multi-part drivers.
+
+mouse_fd.o: $(mouse_fd-objs)
+	$(LD) -r -o $@ $(mouse_fd-objs)
+
+#cmouse_fd.o: $(cmouse_fd-objs)
+#	$(LD) -r -o $@ $(cmouse_fd-objs)
+
+# dependencies:
+
+#mouse.o: $(USBDCORE_DIR)/usbd.h $(USBDCORE_DIR)/usbd-bus.h $(USBDCORE_DIR)/usbd-func.h
+
+
diff -uNr linux/drivers/no-otg/functions/mouse/Makefile-l26 linux/drivers/otg/functions/mouse/Makefile-l26
--- linux/drivers/no-otg/functions/mouse/Makefile-l26	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/mouse/Makefile-l26	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,14 @@
+# Function driver for a Random Mouse
+#
+# Copyright (c) 2004 Belcarra
+
+mouse_fd-objs	:= mouse-fd.o mouse-l24.o
+
+obj-$(CONFIG_OTG_MOUSE) += mouse_fd.o
+
+OTG=$(TOPDIR)/drivers/otg
+ACMD=$(OTG)/functions/mouse
+OTGCORE_DIR=$(OTG)/otgcore
+USBDCORE_DIR=$(OTG)/usbdcore
+EXTRA_CFLAGS += -I$(ACMD) -I$(OTG) -Wno-unused -Wno-format  -I$(USBDCORE_DIR) -I$(OTGCORE_DIR)
+EXTRA_CFLAGS_nostdinc += -I$(ACMD) -I$(OTG) -Wno-unused -Wno-format  -I$(USBDCORE_DIR) -I$(OTGCORE_DIR)
diff -uNr linux/drivers/no-otg/functions/mouse/cmouse-l24.c linux/drivers/otg/functions/mouse/cmouse-l24.c
--- linux/drivers/no-otg/functions/mouse/cmouse-l24.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/mouse/cmouse-l24.c	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,199 @@
+/*
+ * otg/functions/mouse/cmouse-l24.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/functions/mouse/cmouse-l24.c
+ * @brief Mouse Function Driver Linux 2.4 initialization
+ *
+ *
+ * This file contains the Linux 2.4 module init and exit functions
+ * to load and unload the Random Mouse Function.
+ *
+ * Notes
+ *
+ * This driver does not export any upper edge functionality to
+ * for the user or applications to use. It simply sends a configurable
+ * number of data packets to the USB Host when configured. Each data
+ * packet contains the equivalent of a small mouse report which will
+ * cause the mouse cursor to move on the host.
+ *
+ * To use simply load with something like:
+ *
+ *      insmod cmouse_fd.o vendor_id=0xffff product_id=0xffff
+ *
+ * And attach to a Windows box. Windows should recognize as a mouse and
+ * immediately start receiving a stream of data. 
+ *
+ * To terminate simply unplug.
+ *
+ *
+ * 1. The mouse driver is product name is hard coded to a string that will
+ *    generate a string descriptor that is 32 bytes long. This will test
+ *    most UDC's ep0 ZLP handling as it is a multiple of the most common
+ *    UDC endpoint zero size. (An option can be added later to allow for
+ *    64 byte ep0 packetsize.)
+ *
+ * 2. The CONFIG_OTG_MOUSE_BH option can be enabled to delay the HID report 
+ *    to being generated by a bottom half handler. This will verify that 
+ *    the bus interface driver properly handles the case of a delayed
+ *    CONTROL READ. I.e. when the usbd_device_request() function returns
+ *    zero for successful completion but there is no tx_urb containing the
+ *    requested data. The bus interface driver must setup the conditions for
+ *    ACK'ing the SETUP packet but then NAK the IN data for endpoint zero
+ *    until the tx_urb is started later.
+ *
+ * 3. The CONFIG_OTG_MOUSE_PACKETS option is used to set the number of
+ *    mouse data reports to send. Set to zero for a continous stream
+ *    of data.
+ *
+ * @ingroup MouseFunction
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/otg-trace.h>
+
+#include "cmouse.h"
+
+
+/* Module Parameters ******************************************************** */
+/* ! 
+ * @name XXXXX MODULE Parameters
+ */
+/* ! @{ */
+
+MOD_AUTHOR ("sl@belcarra.com"); 
+EMBED_LICENSE();
+MOD_DESCRIPTION ("Belcarra Random Walk MOUSE Function");
+
+static u32 vendor_id;           /*!< override built-in vendor ID */
+static u32 product_id;          /*!< override built-in product ID */
+
+MOD_PARM (vendor_id, "i");
+MOD_PARM (product_id, "i");
+
+MOD_PARM_DESC (vendor_id, "Device Vendor ID");
+MOD_PARM_DESC (product_id, "Device Product ID");
+
+otg_tag_t MOUSE;
+/* ! *} */
+
+/* USB Module init/exit ***************************************************** */
+
+struct mouse_private mouse_private;
+
+char *mouse_interface_list[2] = {
+        "mouse-random-interface",
+        NULL,
+};
+
+/*! 
+ * mouse_modinit() - module init
+ *
+ * This is called by the Linux kernel; either when the module is loaded
+ * if compiled as a module, or during the system intialization if the 
+ * driver is linked into the kernel.
+ *
+ * This function will parse module parameters if required and then register
+ * the mouse driver with the USB Device software.
+ *
+ * If the CONFIG_OTG_MOUSE_BH option is enabled it will also setup the mouse
+ * bottom half handler.
+ *
+ */
+static int mouse_modinit (void)
+{
+        struct usbd_function_instance *mfi;
+        printk (KERN_INFO "%s: vendor_id: %04x product_id: %04x\n", __FUNCTION__, vendor_id, product_id);
+
+        #if !defined(OTG_C99)
+        mouse_global_init();
+        mouse_ops_init();
+        #endif /* defined(OTG_C99) */
+        
+        MOUSE = otg_trace_obtain_tag();
+        TRACE_MSG2(MOUSE, "vendor_id: %04x product_id: %04x",vendor_id, product_id);
+
+        if (vendor_id) 
+                mouse_composite_driver.idVendor = cpu_to_le16(vendor_id);
+        if (product_id) 
+                mouse_composite_driver.idProduct = cpu_to_le16(product_id);
+
+        mouse_hid.wItemLength = cpu_to_le16(0x34);      // XXX mips compiler bug.....
+
+        // register as usb function driver
+        TRACE_MSG2(MOUSE, "%s %d", mouse_interface_driver.name, mouse_interface_driver.endpointsRequested);
+        THROW_UNLESS ((mouse_private.interface = 
+                                usbd_register_interface (&mouse_interface_driver, "mouse-random-interface", NULL)), error);
+
+        TRACE_MSG2(MOUSE, "%s %d", mouse_interface_driver.name, mouse_interface_driver.endpointsRequested);
+
+        THROW_UNLESS ((mouse_private.composite = 
+                                usbd_register_composite (&mouse_composite_driver, "mouse-random-cf", 
+                                        mouse_interface_list, NULL)), error);
+
+        #ifdef CONFIG_OTG_MOUSE_BH
+        mouse_private.notification_bh.routine = mouse_hid_bh;
+        mouse_private.notification_bh.data = NULL;
+        #endif
+        CATCH(error) {
+                if (mouse_private.interface) {
+                        usbd_deregister_function (mouse_private.interface);
+                        mouse_private.interface = NULL;
+                }
+                if (mouse_private.composite) {
+                        usbd_deregister_function (mouse_private.composite);
+                        mouse_private.composite = NULL;
+                }
+                otg_trace_invalidate_tag(MOUSE);
+                return -EINVAL;
+        }
+        return 0;
+}
+
+module_init (mouse_modinit);
+
+#if OTG_EPILOGUE
+/*! 
+ * mouse_modexit() - module init
+ *
+ * This is called by the Linux kernel; when the module is being unloaded 
+ * if compiled as a module. This function is never called if the 
+ * driver is linked into the kernel.
+ *
+ * @param void
+ * @return void
+ */
+static void mouse_modexit (void)
+{
+        #ifdef CONFIG_OTG_MOUSE_BH
+        while (PENDING_WORK_ITEM(mouse_private.notification_bh)) {
+                printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
+                schedule_timeout(10 * HZ);
+        }
+        #endif
+        if (mouse_private.interface) {
+                usbd_deregister_function (mouse_private.interface);
+                mouse_private.interface = NULL;
+        }
+        if (mouse_private.composite) {
+                usbd_deregister_function (mouse_private.composite);
+                mouse_private.composite = NULL;
+        }
+
+        otg_trace_invalidate_tag(MOUSE);
+}
+
+module_exit (mouse_modexit);
+#endif
+
diff -uNr linux/drivers/no-otg/functions/mouse/cmouse.h linux/drivers/otg/functions/mouse/cmouse.h
--- linux/drivers/no-otg/functions/mouse/cmouse.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/mouse/cmouse.h	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,64 @@
+/*
+ * otg/functions/mouse/mouse.h
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+/*!
+ * @defgroup MouseFunction Random Mouse
+ * @ingroup functiongroup
+ */
+/*!
+ * @file otg/functions/mouse/mouse.h
+ * @brief Mouse Function Driver private defines
+ *
+ *
+ * This is a test USB HID Function Driver designed to test and
+ * verify that INTERRUPT IN endpoints work properly.
+ *
+ *
+ * @ingroup MouseFunction
+ */
+
+
+/*!
+ * The mouse_private structure is used to collect all of the mouse driver 
+ * global variables into one place.
+ */
+struct mouse_private {
+        struct usbd_function_instance *interface; /*!< function instance for this module */
+        struct usbd_function_instance *composite; /*!< function instance for this module */
+
+#ifdef CONFIG_OTG_MOUSE_BH
+        struct WORK_STRUCT notification_bh;
+#endif /* CONFIG_OTG_MOUSE_BH */
+        int usb_driver_registered;              /*!< non-zero if usb function registered */
+        unsigned char connected;                /*!< non-zero if connected to host (configured) */
+        unsigned int writesize;                 /*!< packetsize * 4 */
+        struct usbd_urb *tx_urb;                /*!< saved copy of current tx urb */
+        int wLength;                            
+        int x;
+        int y;
+        int last_x;
+        int last_y;
+        int n;
+};
+
+extern struct mouse_private mouse_private;
+extern struct usbd_function_driver mouse_interface_driver;
+extern struct usbd_function_driver mouse_composite_driver;
+extern struct hid_descriptor mouse_hid;
+
+#ifndef OTG_C99
+extern void mouse_global_init(void);
+#endif /* OTG_C99 */
+
+#define MOUSE mouse_trace_tag
+extern otg_tag_t MOUSE;
+
diff -uNr linux/drivers/no-otg/functions/mouse/getmouse.c linux/drivers/otg/functions/mouse/getmouse.c
--- linux/drivers/no-otg/functions/mouse/getmouse.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/mouse/getmouse.c	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,107 @@
+/*
+ *
+ *
+ * 3.2. Non-Canonical Input Processing
+ * 
+ * In non-canonical input processing mode, input is not assembled into lines and
+ * input processing (erase, kill, delete, etc.) does not occur. Two parameters
+ * control the behavior of this mode: c_cc[VTIME] sets the character timer, and
+ * c_cc[VMIN] sets the minimum number of characters to receive before satisfying
+ * the read.
+ * 
+ * If MIN > 0 and TIME = 0, MIN sets the number of characters to receive before
+ * the read is satisfied. As TIME is zero, the timer is not used.
+ * 
+ * If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will be
+ * satisfied if a single character is read, or TIME is exceeded (t = TIME *0.1
+ * s). If TIME is exceeded, no character will be returned.
+ * 
+ * If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The read
+ * will be satisfied if MIN characters are received, or the time between two
+ * characters exceeds TIME. The timer is restarted every time a character is
+ * received and only becomes active after the first character has been received.
+ * 
+ * If MIN = 0 and TIME = 0, read will be satisfied immediately. The number of
+ * characters currently available, or the number of characters requested will be
+ * returned. According to Antonino (see contributions), you could issue a fcntl
+ * (fd, F_SETFL, FNDELAY); before reading to get the same result.
+ * 
+ * By modifying newtio.c_cc[VTIME] and newtio.c_cc[VMIN] all modes described
+ * above can be tested.
+ * 
+ */
+
+#include <sys/types.h>                                                    
+#include <sys/stat.h>                                                     
+#include <fcntl.h>                                                        
+#include <termios.h>                                                      
+#include <stdio.h>                                                        
+
+#define BAUDRATE B1200                                                   
+#define MODEMDEVICE "/dev/ttyS0"                                          
+#define _POSIX_SOURCE 1 /* POSIX compliant source */                      
+#define FALSE 0                                                           
+#define TRUE 1                                                            
+
+volatile int STOP=FALSE;                                                  
+
+main()                                                                    
+{                                                                         
+        int fd,c, res;                                                          
+        struct termios oldtio,newtio;                                           
+        unsigned char buf[255];                                                          
+
+        int bytes;
+        unsigned char mouse[3];
+
+        fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );                             
+        if (fd <0) {perror(MODEMDEVICE); exit(-1); }                            
+
+        tcgetattr(fd,&oldtio); /* save current port settings */                 
+
+        bzero(&newtio, sizeof(newtio));                                         
+        newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;             
+        newtio.c_iflag = IGNPAR;                                                
+        newtio.c_oflag = 0;                                                     
+
+        /* set input mode (non-canonical, no echo,...) */                       
+        newtio.c_lflag = 0;                                                     
+
+        newtio.c_cc[VTIME]    = 0;   /* inter-character timer unused */         
+        newtio.c_cc[VMIN]     = 1;   /* blocking read until 5 chars received */ 
+
+        tcflush(fd, TCIFLUSH);                                                  
+        tcsetattr(fd,TCSANOW,&newtio);                                          
+
+
+        bytes = 0;
+        while (STOP==FALSE) {       /* loop for input */                        
+                unsigned char c;
+
+                res = read(fd,buf,1);   /* returns after 5 chars have been input */ 
+                buf[res]=0;               /* so we can printf... */                   
+                //fprintf(stderr, ":%02x:%d\n", buf[0], res);                                         
+                //if (buf[0]=='z') STOP=TRUE;                                           
+
+                c = buf[0];
+
+                if ( c & 0x40 ) {
+                        bytes = 1;
+                        mouse[0] = c;
+                }
+                else if (bytes == 1) {
+                        bytes = 2;
+                        mouse[1] = c;
+                }
+                else if (bytes == 2) {
+                        bytes = 0;
+                        mouse[2] = c;
+                        fprintf(stderr, "%02x %02x %02x\n", mouse[0], mouse[1], mouse[2]);
+                        //printf("%c%c%c", mouse[0], mouse[1], mouse[2]);
+                }
+        }                                                                       
+        tcsetattr(fd,TCSANOW,&oldtio);                                          
+}                                                                         
+
+
+/* End of FILE */
diff -uNr linux/drivers/no-otg/functions/mouse/mouse-ce42.c linux/drivers/otg/functions/mouse/mouse-ce42.c
--- linux/drivers/no-otg/functions/mouse/mouse-ce42.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/mouse/mouse-ce42.c	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,89 @@
+/*
+ * otg/functions/mouse/mouse-ce42.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Chris Lynne <sl@belcarra.com>, 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *
+ * This is a test USB HID Function Driver designed to test and
+ * verify that INTERRUPT IN endpoints work properly.
+ *
+ * This emulates a simple USB mouse and generates a constant stream
+ * of small random mouse movements.
+ *
+ * To use simply load with something like:
+ *
+ *      insmod mouse_fd.o vendor_id=0xffff product_id=0xffff
+ *
+ * And attach to a Windows box. Windows should recognize as a mouse and
+ * immediately start receiving a stream of data. 
+ *
+ * To terminate simply unplug.
+ *
+ * The mouse driver has several other characteristics to allow testing of
+ * other features of the bus interface driver:
+ *
+ *      - ep0 ZLP handling
+ *
+ *      - ep0 delayed CONTROL READ
+ *
+ *
+ * Notes
+ *
+ * 1. The mouse driver is product name is hard coded to a string that will
+ *    generate a string descriptor that is 32 bytes long. This will test
+ *    most UDC's ep0 ZLP handling as it is a multiple of the most common
+ *    UDC endpoint zero size. (An option can be added later to allow for
+ *    64 byte ep0 packetsize.)
+ *
+ * 2. The CONFIG_OTG_MOUSE_BH option can be enabled to delay the HID report 
+ *    to being generated by a bottom half handler. This will verify that 
+ *    the bus interface driver properly handles the case of a delayed
+ *    CONTROL READ. I.e. when the usbd_device_requesdevice_requesdevice_request
+ *    zero for successful completion but there is no tx_urb containing the
+ *    requested data. The bus interface driver must setup the conditions for
+ *    ACK'ing the SETUP packet but then NAK the IN data for endpoint zero
+ *    until the tx_urb is started later.
+ */
+
+
+
+#include "otg/usbp-chap9.h"
+#include <otg/usbp-mem.h>
+#include <otg/usbp-func.h>
+
+/*
+ * mouse_modinit - module init
+ *
+ */
+static int mouse_modinit (void)
+{
+
+        // register as usb function driver
+        THROW_IF (NULL == (mouse_private.function = usbd_register_function (&mouse_function_driver, "mouse", NULL)), error);
+#ifdef CONFIG_OTG_MOUSE_BH
+        mouse_private.notification_bh.routine = mouse_hid_bh;
+        mouse_private.notification_bh.data = NULL;
+#endif
+        CATCH(error) {
+                if (mouse_private.function) {
+                        usbd_deregister_function (mouse_private.function);
+                        mouse_private.function = NULL;
+                }
+                return -EINVAL;
+        }
+        return 0;
+}
+
+/* mouse_modexit - module cleanup
+ */
+static void mouse_modexit (void)
+{
+        if (mouse_private.function) {
+                usbd_deregister_function (mouse_private.function);
+                mouse_private.function = NULL;
+        }
+}
+
diff -uNr linux/drivers/no-otg/functions/mouse/mouse-fd.c linux/drivers/otg/functions/mouse/mouse-fd.c
--- linux/drivers/no-otg/functions/mouse/mouse-fd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/mouse/mouse-fd.c	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,826 @@
+/*
+ * otg/functions/mouse/mouse-fd.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/functions/mouse/mouse-fd.c
+ * @brief Mouse Function Driver protocol implementation.
+ *
+ * This file implements the Mouse HID protocols and will generate
+ * random mouse data on the INTERRUPT endpoint.
+ *
+ * The primary purpose of this driver is to demonstrate how to
+ * implement a simple function driver and to provide a simple
+ * uni-directional driver for testing USB Device peripheral drivers.
+ *
+ * The mouse driver has several other characteristics to allow testing of
+ * other features of USB Device peripheral drivers:
+ *
+ *      - ep0 ZLP handling
+ *
+ *      - ep0 delayed CONTROL READ
+ *
+ * To verify that ep0 ZLP processing is being handling correctly this
+ * driver has a hard coded Product name that is returned as a 32 byte
+ * string. This forces most any implementations that have an endpoint
+ * zero packetsize of 8, 16 or 32 to send a Zero Length Packet to 
+ * terminate the string transfer when the Product name is requested
+ * by the host.
+ *
+ * The delayed CONTROL READ test verifies that that USB Device peripheral
+ * drivers will correctly NAK until data is provide for device requests.
+ * This is done by (optionally) delaying the HID report via a bottom half
+ * handler. The device request returns normally and the peripheral driver
+ * must properly recognize that while the device request had a non-zero
+ * wLength field, there is currently no queued urb. 
+ *
+ * When the bottom half handler is scheduled the HID report urb will be
+ * queued on endpoint zero and then returned to the host.
+ *
+ *
+ * @ingroup MouseFunction
+ */
+
+#include <linux/config.h>
+#include <otg/otg-compat.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+
+#include "mouse.h"
+
+struct mouse_private mouse_private;
+
+/*
+ * ep0 testing.... ensure that this is exactly 16 bytes
+ */
+#undef CONFIG_OTG_MOUSE_PRODUCT_NAME
+#define CONFIG_OTG_MOUSE_PRODUCT_NAME "Belcarra  Mouse"
+
+/*! 
+ * @name Mouse Descriptors
+ *
+ * MouseHIDReport
+ * MOUSE Configuration
+ *
+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
+ */
+
+/*! 
+ * Mouse Descriptors 
+ * @{ 
+ */ 
+
+#define BULK_INT        0x00    /*!< Interrupt endpoint number */
+#define ENDPOINTS       0x01    /*!< Number of endpoints required */
+
+/*! List of required endpoint numbers
+ */
+static u8 mouse_indexes[] = { BULK_INT, };
+
+/*! List of requested endpoints
+ */
+static struct usbd_endpoint_request mouse_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
+        { 0, },
+};
+
+/*! This is the HID report returned for the HID Device Request.
+ *  There is no pre-defined descriptor type for this.
+ */
+static char MouseHIDReport[52] = {
+    0x05, 0x01,                    /*!< USAGE_PAGE (Generic Desktop)            */
+    0x09, 0x02,                    /*!< USAGE (Mouse)                           */
+    0xa1, 0x01,                    /*!< COLLECTION (Application)                */
+    0x09, 0x01,                    /*!<   USAGE (Pointer)                       */
+    0xa1, 0x00,                    /*!<   COLLECTION (Physical)                 */
+    0x05, 0x09,                    /*!<     USAGE_PAGE (Button)                 */
+    0x19, 0x01,                    /*!<     USAGE_MINIMUM (Button 1)            */
+    0x29, 0x03,                    /*!<     USAGE_MAXIMUM (Button 3)            */
+    0x15, 0x00,                    /*!<     LOGICAL_MINIMUM (0)                 */
+    0x25, 0x01,                    /*!<     LOGICAL_MAXIMUM (1)                 */
+    0x95, 0x03,                    /*!<     REPORT_COUNT (3)                    */
+    0x75, 0x01,                    /*!<     REPORT_SIZE (1)                     */
+    0x81, 0x02,                    /*!<     INPUT (Data,Var,Abs)                */
+    0x95, 0x01,                    /*!<     REPORT_COUNT (1)                    */
+    0x75, 0x05,                    /*!<     REPORT_SIZE (5)                     */
+    0x81, 0x03,                    /*!<     INPUT (Cnst,Var,Abs)                */
+    0x05, 0x01,                    /*!<     USAGE_PAGE (Generic Desktop)        */
+    0x09, 0x30,                    /*!<     USAGE (X)                           */
+    0x09, 0x31,                    /*!<     USAGE (Y)                           */
+    0x09, 0x38,                    /*!<     USAGE (WHEEL)                       */
+    0x15, 0x81,                    /*!<     LOGICAL_MINIMUM (-127)              */
+    0x25, 0x7f,                    /*!<     LOGICAL_MAXIMUM (127)               */
+    0x75, 0x08,                    /*!<     REPORT_SIZE (8)                     */
+    0x95, 0x03,                    /*!<     REPORT_COUNT (3)                    */
+    0x81, 0x06,                    /*!<     INPUT (Data,Var,Rel)                */
+    0xc0,                          /*!<   END_COLLECTION                        */
+    0xc0                           /*!< END_COLLECTION                        */
+};
+
+#if !defined(OTG_C99)
+/*! This is the interrupt endpoint descriptor.
+ */
+static struct usbd_endpoint_descriptor mouse_data;
+
+/*! The list of endpoint descriptors 
+ */
+static struct usbd_endpoint_descriptor *mouse_default[] = { &mouse_data, };
+
+
+/*! This is the HID desccriptor.
+ */
+struct hid_descriptor mouse_hid;
+
+/*! List of class descriptors 
+ */
+static struct usbd_generic_class_descriptor *mouse_hid_descriptors[] = { 
+        (struct usbd_generic_class_descriptor *)&mouse_hid, };
+
+
+/*! Data Interface Alternate description
+ */
+static struct usbd_interface_descriptor  mouse_data_alternate_descriptor;
+
+/*! Interface Descriptions
+ */
+static struct usbd_alternate_description mouse_data_alternate_descriptions[1];
+
+/*! List of Interface description(s)
+ */
+static struct usbd_interface_description mouse_interfaces[1];
+
+/*! Configuration description(s)
+ */
+static struct usbd_configuration_descriptor  mouse_configuration_descriptor;
+
+/*! Mouse Configuration Description
+ */
+struct usbd_configuration_description mouse_configuration_description[1];
+
+/*! Device Description
+ */
+static struct usbd_device_descriptor mouse_device_descriptor;
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+/*! High Speed Device Description 
+ */
+static struct usbd_device_qualifier_descriptor mouse_device_qualifier_descriptor;
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+/*! OTG Descriptor
+ */
+static struct usbd_otg_descriptor mouse_otg_descriptor;
+
+/*! Device Description
+ */
+struct usbd_device_description mouse_device_description;
+
+void mouse_global_init(void)
+{
+
+        /*! This is the interrupt endpoint descriptor.
+         */
+        ZERO(mouse_data);
+        mouse_data.bLength = 0x07;
+        mouse_data.bDescriptorType = USB_DT_ENDPOINT;
+        mouse_data.bEndpointAddress = USB_DIR_IN;
+        mouse_data.bmAttributes = INTERRUPT;
+        mouse_data.wMaxPacketSize = __constant_cpu_to_le16(0x10);
+#if defined (CONFIG_OTG_MOUSE_INTERVAL)
+        mouse_data.bInterval = CONFIG_OTG_MOUSE_INTERVAL;
+#else
+        mouse_data.bInterval = 0x01;
+#endif /* defined (CONFIG_OTG_MOUSE_INTERVAL) */
+
+
+        /*! This is the HID desccriptor.
+         */
+        ZERO(mouse_hid);
+        mouse_hid.bLength = 0x09; 
+        mouse_hid.bDescriptorType = 0x21; 
+        mouse_hid.bcdHID = __constant_cpu_to_le16(0x110); 
+        mouse_hid.bCountryCode = 0x00; 
+        mouse_hid.bNumDescriptors = 0x01; 
+        mouse_hid.bReportType = 0x22; 
+        mouse_hid.wItemLength = __constant_cpu_to_le16(0x34); 
+
+
+        /*! Data Interface Alternate description
+         */
+        ZERO(mouse_data_alternate_descriptor);
+        mouse_data_alternate_descriptor.bLength = 0x09;
+        mouse_data_alternate_descriptor.bDescriptorType = USB_DT_INTERFACE;
+        mouse_data_alternate_descriptor.bInterfaceNumber = 0x00;
+        mouse_data_alternate_descriptor.bAlternateSetting = 0x00;
+        mouse_data_alternate_descriptor.bNumEndpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor);
+        mouse_data_alternate_descriptor.bInterfaceClass = 0x03;
+        mouse_data_alternate_descriptor.bInterfaceSubClass = 0x01;
+        mouse_data_alternate_descriptor.bInterfaceProtocol = 0x02;
+        mouse_data_alternate_descriptor.iInterface = 0x00;
+
+        /*! Interface Descriptions
+         */
+        ZERO(mouse_data_alternate_descriptions);
+        mouse_data_alternate_descriptions[0].iInterface = "Random Mouse Interface - Interrupt";
+        mouse_data_alternate_descriptions[0].interface_descriptor =  &mouse_data_alternate_descriptor;
+        mouse_data_alternate_descriptions[0].classes = 
+                sizeof (mouse_hid_descriptors) / sizeof (struct usbd_generic_class_descriptor *);
+        mouse_data_alternate_descriptions[0].class_list = mouse_hid_descriptors;
+        mouse_data_alternate_descriptions[0].endpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor *);
+        mouse_data_alternate_descriptions[0].endpoint_list = mouse_default;
+        mouse_data_alternate_descriptions[0].endpoint_indexes = mouse_indexes;
+
+        /*! List of Interface description(s)
+         */
+        ZERO(mouse_interfaces);
+        mouse_interfaces[0].alternates = sizeof (mouse_data_alternate_descriptions) / sizeof (struct usbd_alternate_description);
+        mouse_interfaces[0].alternate_list = mouse_data_alternate_descriptions;
+
+
+        /*! Configuration description(s)
+         */
+        ZERO(mouse_configuration_descriptor);
+        mouse_configuration_descriptor.bLength = 0x09;
+        mouse_configuration_descriptor.bDescriptorType = USB_DT_CONFIGURATION;
+        mouse_configuration_descriptor.wTotalLength = 0x00;
+        mouse_configuration_descriptor.bNumInterfaces = sizeof (mouse_interfaces) / sizeof (struct usbd_interface_description);
+        mouse_configuration_descriptor.bConfigurationValue = 0x01;
+        mouse_configuration_descriptor.iConfiguration = 0x00;
+        mouse_configuration_descriptor.bmAttributes = 0;
+        mouse_configuration_descriptor.bMaxPower = 0;
+
+        /*! Mouse Configuration Description
+         */
+        ZERO(mouse_configuration_description);
+        mouse_configuration_description[0].configuration_descriptor = &mouse_configuration_descriptor;
+        mouse_configuration_description[0].iConfiguration = "USB Random Mouse Configuration";
+        mouse_configuration_description[0].bNumInterfaces = 
+                sizeof (mouse_interfaces) / sizeof (struct usbd_interface_description);
+        mouse_configuration_description[0].interface_list = mouse_interfaces;
+
+        /*! Device Description
+         */
+        ZERO(mouse_device_descriptor);
+        mouse_device_descriptor.bLength = sizeof(struct usbd_device_descriptor);
+        mouse_device_descriptor.bDescriptorType = USB_DT_DEVICE;
+        mouse_device_descriptor.bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION);
+        mouse_device_descriptor.bDeviceClass = 0x00;
+        mouse_device_descriptor.bDeviceSubClass = 0x00;
+        mouse_device_descriptor.bDeviceProtocol = 0x00;
+        mouse_device_descriptor.bMaxPacketSize0 = 0x00;
+        mouse_device_descriptor.idVendor = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_VENDORID);
+        mouse_device_descriptor.idProduct = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_PRODUCTID);
+        mouse_device_descriptor.bcdDevice = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_BCDDEVICE);
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+        /*! High Speed Device Description 
+         */
+        ZERO(mouse_device_qualifier_descriptor);
+        mouse_device_qualifier_descriptor.bLength = sizeof(struct usbd_device_qualifier_descriptor);
+        mouse_device_qualifier_descriptor.bDescriptorType = USB_DT_DEVICE_QUALIFIER;
+        mouse_device_qualifier_descriptor.bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION);
+        mouse_device_qualifier_descriptor.bDeviceClass = 0x00;
+        mouse_device_qualifier_descriptor.bDeviceSubClass = 0x00;
+        mouse_device_qualifier_descriptor.bDeviceProtocol = 0x00;
+        mouse_device_qualifier_descriptor.bMaxPacketSize0 = 0x00;
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+        /*! OTG Descriptor
+         */
+        ZERO(mouse_otg_descriptor);
+        mouse_otg_descriptor.bLength = sizeof(struct usbd_otg_descriptor);
+        mouse_otg_descriptor.bDescriptorType = USB_DT_OTG;
+        mouse_otg_descriptor.bmAttributes = 0;
+
+        /*! Device Description
+         */
+        ZERO(mouse_device_description);
+        mouse_device_description.device_descriptor = &mouse_device_descriptor;
+#ifdef CONFIG_OTG_HIGH_SPEED
+        mouse_device_description.device_qualifier_descriptor = &mouse_device_qualifier_descriptor;
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        mouse_device_description.otg_descriptor = &mouse_otg_descriptor;
+        mouse_device_description.iManufacturer = CONFIG_OTG_MOUSE_MANUFACTURER;
+        mouse_device_description.iProduct = CONFIG_OTG_MOUSE_PRODUCT_NAME;
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        mouse_device_description.iSerialNumber = CONFIG_OTG_SERIAL_NUMBER_STR; 
+#endif
+}
+
+#else /* defined(OTG_C99) */
+
+/*! This is the interrupt endpoint descriptor.
+ */
+static struct usbd_endpoint_descriptor mouse_data = {
+        .bLength = 0x07, 
+        .bDescriptorType = USB_DT_ENDPOINT, 
+        .bEndpointAddress = USB_DIR_IN, 
+        .bmAttributes = INTERRUPT, 
+        .wMaxPacketSize = __constant_cpu_to_le16(0x10), 
+#if defined (CONFIG_OTG_MOUSE_INTERVAL)
+        .bInterval = CONFIG_OTG_MOUSE_INTERVAL, 
+#else
+        .bInterval = 0x01, 
+#endif /* defined (CONFIG_OTG_MOUSE_INTERVAL) */
+};
+
+/*! The list of endpoint descriptors 
+ */
+static struct usbd_endpoint_descriptor *mouse_default[] = { &mouse_data, };
+
+/*! This is the HID desccriptor.
+ */
+struct hid_descriptor mouse_hid = {
+        .bLength = 0x09, 
+        .bDescriptorType = 0x21, 
+        .bcdHID = __constant_cpu_to_le16(0x110), 
+        .bCountryCode = 0x00, 
+        .bNumDescriptors = 0x01, 
+        .bReportType = 0x22, 
+        .wItemLength = __constant_cpu_to_le16(0x34), 
+};
+
+/*! List of class descriptors 
+ */
+static struct usbd_generic_class_descriptor *mouse_hid_descriptors[] = { 
+        (struct usbd_generic_class_descriptor *)&mouse_hid, };
+
+
+/*! Data Interface Alternate description
+ */
+static struct usbd_interface_descriptor  mouse_data_alternate_descriptor = {
+        .bLength = 0x09, 
+        .bDescriptorType = USB_DT_INTERFACE, 
+        .bInterfaceNumber = 0x00, 
+        .bAlternateSetting = 0x00, 
+        .bNumEndpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor), 
+        .bInterfaceClass = 0x03, 
+        .bInterfaceSubClass = 0x01, 
+        .bInterfaceProtocol = 0x02, 
+        .iInterface = 0x00,
+};
+
+/*! Interface Descriptions
+ */
+static struct usbd_alternate_description mouse_data_alternate_descriptions[] = {
+        { .iInterface = "Random Mouse Interface - Interrupt",
+                .interface_descriptor =  &mouse_data_alternate_descriptor,
+                .classes = sizeof (mouse_hid_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
+                .class_list =  mouse_hid_descriptors,
+                .endpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor *),
+                .endpoint_list =  mouse_default,
+                .endpoint_indexes =  mouse_indexes,
+        },
+};
+
+/*! List of Interface description(s)
+ */
+static struct usbd_interface_description mouse_interfaces[] = {
+      { .alternates = sizeof (mouse_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                .alternate_list = mouse_data_alternate_descriptions,},
+};
+
+
+/*! Configuration description(s)
+ */
+static struct usbd_configuration_descriptor  mouse_configuration_descriptor = {
+        .bLength = 0x09, 
+        .bDescriptorType = USB_DT_CONFIGURATION, 
+        .wTotalLength = 0x00, 
+        .bNumInterfaces = sizeof (mouse_interfaces) / sizeof (struct usbd_interface_description),
+        .bConfigurationValue = 0x01, 
+        .iConfiguration = 0x00, 
+        .bmAttributes = 0, 
+        .bMaxPower = 0,
+};
+
+/*! Mouse Configuration Description
+ */
+struct usbd_configuration_description mouse_configuration_description[] = {
+      { .configuration_descriptor = &mouse_configuration_descriptor,
+              .iConfiguration = "USB Random Mouse Configuration",
+      },
+};
+
+/*! Device Description
+ */
+static struct usbd_device_descriptor mouse_device_descriptor = {
+        .bLength = sizeof(struct usbd_device_descriptor),
+        .bDescriptorType = USB_DT_DEVICE,
+        .bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION),
+        .bDeviceClass = 0x00,
+        .bDeviceSubClass = 0x00,
+        .bDeviceProtocol = 0x00,
+        .bMaxPacketSize0 = 0x00,
+        .idVendor = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_VENDORID),
+        .idProduct = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_PRODUCTID),
+        .bcdDevice = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+/*! High Speed Device Description 
+ */
+static struct usbd_device_qualifier_descriptor mouse_device_qualifier_descriptor = {
+        .bLength = sizeof(struct usbd_device_qualifier_descriptor),
+        .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
+        .bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION),
+        .bDeviceClass = 0x00,
+        .bDeviceSubClass = 0x00,
+        .bDeviceProtocol = 0x00,
+        .bMaxPacketSize0 = 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+/*! OTG Descriptor
+ */
+static struct usbd_otg_descriptor mouse_otg_descriptor = {
+        .bLength = sizeof(struct usbd_otg_descriptor),
+        .bDescriptorType = USB_DT_OTG,
+        .bmAttributes = 0,
+};
+
+/*! Device Description
+ */
+struct usbd_device_description mouse_device_description = {
+        .device_descriptor = &mouse_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        .device_qualifier_descriptor = &mouse_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        .otg_descriptor = &mouse_otg_descriptor,
+        .iManufacturer = CONFIG_OTG_MOUSE_MANUFACTURER,
+        .iProduct = CONFIG_OTG_MOUSE_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        .iSerialNumber = CONFIG_OTG_SERIAL_NUMBER_STR, 
+#endif
+};
+#endif /* defined(OTG_C99) */
+
+
+/*! @} */ 
+
+static int mouse_count;
+
+/* MOUSE ***************************************************************************************** */
+/* Transmit Function *************************************************************************** */
+
+int get_xy[8] = {
+         0,  0,  1,  1, 
+         0,  0, -1, -1, 
+};
+
+/*!
+ * mouse_send() - send a mouse data urb with random data
+ * @param function
+ * @return void
+ */
+void mouse_send(struct usbd_function_instance *function)
+{
+        struct mouse_private *mouse = &mouse_private;
+        int new_x = 0;
+        int new_y = 0;
+        u8 random;
+
+        memset(mouse->tx_urb->buffer, 0, 4);
+        if (!mouse->n) {
+
+                get_random_bytes(&random, 1);
+
+                mouse->last_x = MAX(-4, MIN(4, mouse->last_x + get_xy[random & 0x7]));
+                mouse->last_y = MAX(-4, MIN(4, mouse->last_y + get_xy[(random >> 3) & 0x7]));
+                mouse->n = (random>>6) & 0x3;
+
+                new_x = mouse->x + mouse->last_x;
+                new_y = mouse->y + mouse->last_y;
+
+                mouse->tx_urb->buffer[1] = mouse->last_x;
+                mouse->x = new_x;
+                mouse->tx_urb->buffer[2] = mouse->last_y;
+                mouse->y = new_y;
+                mouse->tx_urb->actual_length = 4;
+
+        }
+        else if ((mouse->n)&1) {
+                mouse->n--;
+        } 
+        else {
+                mouse->n--;
+                mouse->tx_urb->buffer[1] = mouse->last_x;
+                mouse->x = new_x;
+                mouse->tx_urb->buffer[2] = mouse->last_y;
+                mouse->y = new_y;
+        }
+        usbd_start_in_urb(mouse->tx_urb);
+}
+
+/*! 
+ * mouse_urb_sent() - called to indicate URB transmit finished
+ * This function is the callback function for sent urbs.
+ * It simply queues up another urb until the packets to be sent
+ * configuration parameter is reached (or forever if zero.)
+ * @param urb The urb to be sent.
+ * @param rc result
+ * @return int Return non-zero for failure.
+ */
+int mouse_urb_sent (struct usbd_urb *urb, int rc)
+{
+        struct mouse_private *mouse = &mouse_private;
+        struct usbd_function_instance *function = mouse->function;
+
+        RETURN_ZERO_IF(usbd_get_device_status(function) == USBD_CLOSING);
+        RETURN_ZERO_IF(usbd_get_device_status(function) != USBD_OK);
+        RETURN_ZERO_IF(usbd_get_device_state(function) != STATE_CONFIGURED);
+        TRACE_MSG1(MOUSE, "mouse_count: %d", mouse_count);
+        #ifdef CONFIG_OTG_MOUSE_PACKETS
+        RETURN_ZERO_IF (CONFIG_OTG_MOUSE_PACKETS && (mouse_count++ > CONFIG_OTG_MOUSE_PACKETS));
+        #endif /* CONFIG_OTG_MOUSE_PACKETS */
+        mouse_send(function);                                                   // re-send
+        return 0;
+}
+
+/* USB Device Functions ************************************************************************ */
+
+typedef enum mesg {
+        mesg_unknown,
+        mesg_configured,
+        mesg_reset,
+} mesg_t;
+mesg_t mouse_last_mesg;
+
+char * mouse_messages[3] = {
+        "",
+        "Mouse Configured",
+        "Mouse Reset",
+};
+
+void mouse_check_mesg(mesg_t curr_mesg)
+{
+        RETURN_UNLESS(mouse_last_mesg != curr_mesg);
+        mouse_last_mesg = curr_mesg;
+        otg_message(mouse_messages[curr_mesg]);
+}
+
+/*! 
+ * mouse_event_handler() - process a device event
+ * This function is called to process USB Device Events.
+ *
+ * The DEVICE_CONFIGURED event causes the mouse_send() to be called
+ * to start the data flow.
+ *
+ * The DEVICE_RESET or DEVICE_DE_CONFIGURED events cause the outstanding
+ * transmit urb to be cancelled.
+ *
+ * @param function the function instance 
+ * @param event the event 
+ * @param data
+ * @return void
+ *
+ */
+void mouse_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
+{
+        struct mouse_private *mouse = &mouse_private;
+
+        switch (event) {
+        case DEVICE_CONFIGURED:
+                TRACE_MSG0(MOUSE, "Mouse Configured");
+                mouse_check_mesg(mesg_configured);
+                mouse_count = 0;
+                mouse->connected = 1;
+                if (!(mouse->tx_urb = usbd_alloc_urb (function, BULK_INT, 4, mouse_urb_sent))) 
+                        printk(KERN_INFO"%s: alloc failed\n", __FUNCTION__);
+                mouse_send(function);                                           // start sending
+                break;
+
+        case DEVICE_RESET:
+        case DEVICE_DE_CONFIGURED:
+                TRACE_MSG0(MOUSE, "Mouse De-Configured");
+                mouse_check_mesg(mesg_reset);
+                BREAK_IF(!mouse->connected);
+                mouse->connected = 0;
+                if (mouse->tx_urb) {
+                        usbd_free_urb (mouse->tx_urb);
+                        mouse->tx_urb = NULL;
+                }
+                break;
+        default: 
+                break;
+        }
+}
+
+/*! copy_report()
+ * This function copies the Mouse HID report into the provided URB.
+ * @param urb Destination
+ * @param data Source
+ * @param size Amount of data to copy.
+ * @param max_buf Size of buffer
+ * @return Non-zero if error.
+ *
+ */
+static int copy_report (struct usbd_urb *urb, void *data, int size, int max_buf)
+{
+        int available;
+        int length;
+
+        RETURN_EINVAL_IF (!urb);
+        RETURN_EINVAL_IF (!data);
+        RETURN_EINVAL_IF (!(length = size));
+        RETURN_EINVAL_IF ((available = max_buf - urb->actual_length) <= 0);
+
+        length = (length < available) ? length : available;
+        memcpy (urb->buffer + urb->actual_length, data, length);
+        urb->actual_length += length;
+        return 0;
+}
+
+/*! 
+ * mouse_send_hid() - send an EP0 urb containing HID report
+ * This is called to send the Mouse HID report.
+ */
+static int mouse_send_hid (void *data)
+{
+        struct mouse_private *mouse = &mouse_private;
+        struct usbd_function_instance *function = mouse->function;
+        struct usbd_urb *urb = usbd_alloc_urb_ep0(function, mouse->wLength, NULL);
+        int wMaxPacketSize = usbd_endpoint_zero_wMaxPacketSize(urb->function_instance, 0);
+
+        TRACE_MSG1(MOUSE, "Send Hid wLength: %d", mouse->wLength);
+        RETURN_EINVAL_IF (copy_report(urb, MouseHIDReport, sizeof(MouseHIDReport), mouse->wLength));
+        RETURN_EINVAL_UNLESS (wMaxPacketSize);
+
+        if (!(urb->actual_length % wMaxPacketSize) && (urb->actual_length < mouse->wLength)) 
+                urb->flags |= USBD_URB_SENDZLP;
+
+        RETURN_ZERO_IF(!usbd_start_in_urb(urb));
+        usbd_free_urb(urb);
+        return -EINVAL;
+}
+
+#ifdef CONFIG_OTG_MOUSE_BH
+/*! 
+ * mouse_hid_bh() - Bottom half handler to send a HID report
+ * @param data
+ */
+static void mouse_hid_bh (void *data)
+{
+        struct usbd_function_instance *function = mouse_private.function;
+        mouse_send_hid(function);
+}
+
+/*! mouse_schedule_bh - schedule a call for mouse_hid_bh
+ * @param void
+ */
+static int mouse_schedule_bh (void)
+{
+        TRACE_MSG0(MOUSE, "Scheduling");
+        return (!schedule_task (&mouse_private.notification_bh)) ? EINVAL : 0;
+}
+#endif /* CONFIG_OTG_MOUSE_BH */
+
+/*! 
+ * mouse_device_request - called to indicate urb has been received
+ * @param function
+ * @param request
+ */
+int mouse_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
+{
+        /* verify that this is a usb class request per cdc-mouse specification or a vendor request.
+         * determine the request direction and process accordingly
+         */
+
+        switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
+
+        case USB_REQ_HOST2DEVICE:
+        case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_CLASS:
+        case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_VENDOR: 
+                return 0;
+
+        case USB_REQ_DEVICE2HOST :
+        case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_CLASS:
+        case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_VENDOR:
+
+                switch (request->bRequest) {
+                case USB_REQ_GET_DESCRIPTOR:
+                        switch (le16_to_cpu(request->wValue)>>8) {
+                        case HID_REPORT:
+                                mouse_private.wLength = request->wLength;
+                                #ifdef CONFIG_OTG_MOUSE_BH
+                                return mouse_schedule_bh();
+                                #else
+                                return mouse_send_hid(function);
+                                #endif
+                        }
+                default: break;
+                }
+                break;
+
+        default:
+                break;
+        }
+        return -EINVAL;
+}
+
+
+/*! mouse_function_enable - called by USB Device Core to enable the driver
+ * @param function The function instance for this driver to use.
+ * @return non-zero if error.
+ */
+static int mouse_function_enable (struct usbd_function_instance *function)
+{
+        struct mouse_private *mouse = &mouse_private;
+        mouse->function = function;
+        mouse->n = 0;
+        mouse->x = 0;
+        mouse->y = 0;
+        mouse->last_x = 0;
+        mouse->last_y = 0;
+        mouse->writesize = usbd_endpoint_wMaxPacketSize(function, BULK_INT, 0);
+        return 0;
+}
+
+/*! mouse_function_disable - called by the USB Device Core to disable the driver
+ * @param function The function instance for this driver
+ */
+static void mouse_function_disable (struct usbd_function_instance *function)
+{               
+        struct mouse_private *mouse = &mouse_private;
+        mouse->function = NULL;
+        mouse->writesize = 0;
+        mouse->function = NULL;
+}
+
+/* ********************************************************************************************* */
+#if !defined(OTG_C99)
+/*! function_ops - operations table for the USB Device Core
+ */
+static struct usbd_function_operations mouse_function_ops;
+
+/*! mouse_function_driver - USB Device Core function driver definition
+ */
+struct usbd_function_driver mouse_function_driver;
+
+void mouse_ops_init(void)
+{
+        /*! function_ops - operations table for the USB Device Core
+         */
+        ZERO(mouse_function_ops);
+        mouse_function_ops.event_handler = mouse_event_handler;              /*! called for each USB Device Event */
+        mouse_function_ops.device_request = mouse_device_request;          /*! called for each received device request */
+        mouse_function_ops.function_enable = mouse_function_enable;         /*! called to enable the function driver */
+        mouse_function_ops.function_disable = mouse_function_disable;       /*! called to disable the function driver */
+
+        /*! function_driver - USB Device Core function driver definition
+         */
+        ZERO(mouse_function_driver);
+        mouse_function_driver.name = "mouse-random";                            /*! driver name */
+        mouse_function_driver.fops = &mouse_function_ops;                             /*! operations table */
+        mouse_function_driver.device_description = &mouse_device_description;   /*! mouse device description */
+        mouse_function_driver.bNumConfigurations = 
+                sizeof (mouse_configuration_description) / sizeof (struct usbd_configuration_description);
+        mouse_function_driver.configuration_description = 
+                mouse_configuration_description;    /*! mouse configuration description */
+        mouse_function_driver.idVendor = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_VENDORID);
+        mouse_function_driver.idProduct = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_PRODUCTID);
+        mouse_function_driver.bcdDevice = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_BCDDEVICE);
+
+
+        mouse_function_driver.bNumInterfaces = sizeof (mouse_interfaces) / sizeof (struct usbd_interface_description);
+        mouse_function_driver.interface_list = mouse_interfaces;
+        mouse_function_driver.endpointsRequested = ENDPOINTS;
+        mouse_function_driver.requestedEndpoints = mouse_endpoint_requests;
+}
+#else /* defined(OTG_C99) */
+/*! function_ops - operations table for the USB Device Core
+ */
+static struct usbd_function_operations mouse_function_ops = {
+        .event_handler = mouse_event_handler,                     /*!< called for each USB Device Event */
+        .device_request = mouse_device_request,           /*!< called for each received device request */
+        .function_enable = mouse_function_enable,         /*!< called to enable the function driver */
+        .function_disable = mouse_function_disable,       /*!< called to disable the function driver */
+};
+
+/*! mouse_function_driver - USB Device Core function driver definition
+ */
+struct usbd_function_driver mouse_function_driver = {
+        .name = "mouse-random",                            /*!< driver name */
+        .fops = &mouse_function_ops,                             /*!< operations table */
+        .device_description = &mouse_device_description,   /*!< mouse device description */
+        .bNumConfigurations = sizeof (mouse_configuration_description) / sizeof (struct usbd_configuration_description),
+        .configuration_description = mouse_configuration_description,    /*!< mouse configuration description */
+        .idVendor = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_VENDORID),
+        .idProduct = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_PRODUCTID),
+        .bcdDevice = __constant_cpu_to_le16(CONFIG_OTG_MOUSE_BCDDEVICE),
+        .bNumInterfaces = sizeof (mouse_interfaces) / sizeof (struct usbd_interface_description),
+        .interface_list = mouse_interfaces,
+        .endpointsRequested = ENDPOINTS,
+        .requestedEndpoints = mouse_endpoint_requests,
+};
+#endif /* defined(OTG_C99) */
+
diff -uNr linux/drivers/no-otg/functions/mouse/mouse-if.c linux/drivers/otg/functions/mouse/mouse-if.c
--- linux/drivers/no-otg/functions/mouse/mouse-if.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/mouse/mouse-if.c	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,499 @@
+/*
+ * otg/functions/mouse/mouse-if.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/functions/mouse/mouse-if.c
+ * @brief Mouse Interface Function Driver protocol implementation.
+ *
+ * This file implements the Mouse HID protocols and will generate
+ * random mouse data on the INTERRUPT endpoint.
+ *
+ * The primary purpose of this driver is to demonstrate how to
+ * implement a simple function driver and to provide a simple
+ * uni-directional driver for testing USB Device peripheral drivers.
+ *
+ * The mouse driver has several other characteristics to allow testing of
+ * other features of USB Device peripheral drivers:
+ *
+ *      - ep0 ZLP handling
+ *
+ *      - ep0 delayed CONTROL READ
+ *
+ * To verify that ep0 ZLP processing is being handling correctly this
+ * driver has a hard coded Product name that is returned as a 32 byte
+ * string. This forces most any implementations that have an endpoint
+ * zero packetsize of 8, 16 or 32 to send a Zero Length Packet to 
+ * terminate the string transfer when the Product name is requested
+ * by the host.
+ *
+ * The delayed CONTROL READ test verifies that that USB Device peripheral
+ * drivers will correctly NAK until data is provide for device requests.
+ * This is done by (optionally) delaying the HID report via a bottom half
+ * handler. The device request returns normally and the peripheral driver
+ * must properly recognize that while the device request had a non-zero
+ * wLength field, there is currently no queued urb. 
+ *
+ * When the bottom half handler is scheduled the HID report urb will be
+ * queued on endpoint zero and then returned to the host.
+ *
+ *
+ * @ingroup MouseFunction
+ */
+
+#include <linux/config.h>
+#include <otg/otg-compat.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+
+#include "mouse.h"
+
+
+/*
+ * ep0 testing.... ensure that this is exactly 16 bytes
+ */
+#undef CONFIG_OTG_MOUSE_PRODUCT_NAME
+#define CONFIG_OTG_MOUSE_PRODUCT_NAME "Belcarra  Mouse"
+
+/*! 
+ * @name Mouse Descriptors
+ *
+ * MouseHIDReport
+ * MOUSE Configuration
+ *
+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
+ */
+
+/*! 
+ * Mouse Descriptors 
+ * @{ 
+ */ 
+
+#define BULK_INT        0x00    /*!< Interrupt endpoint number */
+#define ENDPOINTS       0x01    /*!< Number of endpoints required */
+
+/*! List of required endpoint numbers
+ */
+static u8 mouse_indexes[] = { BULK_INT, };
+
+/*! List of requested endpoints
+ */
+static struct usbd_endpoint_request mouse_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
+        { 0, },
+};
+
+#if !defined(OTG_C99)
+/*! This is the interrupt endpoint descriptor.
+ */
+static struct usbd_endpoint_descriptor mouse_data;
+
+/*! The list of endpoint descriptors 
+ */
+static struct usbd_endpoint_descriptor *mouse_default[] = { &mouse_data, };
+
+
+/*! List of class descriptors 
+ */
+static struct usbd_generic_class_descriptor *mouse_hid_descriptors[] = { 
+        (struct usbd_generic_class_descriptor *)&mouse_hid, };
+
+
+/*! Data Interface Alternate description
+ */
+static struct usbd_interface_descriptor  mouse_data_alternate_descriptor;
+
+/*! Interface Descriptions
+ */
+static struct usbd_alternate_description mouse_data_alternate_descriptions[1];
+
+/*! List of Interface description(s)
+ */
+static struct usbd_interface_description mouse_interfaces[1];
+
+
+void mouse_if_global_init(void)
+{
+
+        /*! This is the interrupt endpoint descriptor.
+         */
+        ZERO(mouse_data);
+        mouse_data.bLength = 0x07;
+        mouse_data.bDescriptorType = USB_DT_ENDPOINT;
+        mouse_data.bEndpointAddress = USB_DIR_IN;
+        mouse_data.bmAttributes = INTERRUPT;
+        mouse_data.wMaxPacketSize = __constant_cpu_to_le16(0x10);
+#if defined (CONFIG_OTG_MOUSE_INTERVAL)
+        mouse_data.bInterval = CONFIG_OTG_MOUSE_INTERVAL;
+#else
+        mouse_data.bInterval = 0x01;
+#endif /* defined (CONFIG_OTG_MOUSE_INTERVAL) */
+
+
+        /*! Data Interface Alternate description
+         */
+        ZERO(mouse_data_alternate_descriptor);
+        mouse_data_alternate_descriptor.bLength = 0x09;
+        mouse_data_alternate_descriptor.bDescriptorType = USB_DT_INTERFACE;
+        mouse_data_alternate_descriptor.bInterfaceNumber = 0x00;
+        mouse_data_alternate_descriptor.bAlternateSetting = 0x00;
+        mouse_data_alternate_descriptor.bNumEndpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor);
+        mouse_data_alternate_descriptor.bInterfaceClass = 0x03;
+        mouse_data_alternate_descriptor.bInterfaceSubClass = 0x01;
+        mouse_data_alternate_descriptor.bInterfaceProtocol = 0x02;
+        mouse_data_alternate_descriptor.iInterface = 0x00;
+
+        /*! Interface Descriptions
+         */
+        ZERO(mouse_data_alternate_descriptions);
+        mouse_data_alternate_descriptions[0].iInterface = "Random Mouse Interface - Interrupt";
+        mouse_data_alternate_descriptions[0].interface_descriptor =  &mouse_data_alternate_descriptor;
+        mouse_data_alternate_descriptions[0].classes = 
+                sizeof (mouse_hid_descriptors) / sizeof (struct usbd_generic_class_descriptor *);
+        mouse_data_alternate_descriptions[0].class_list = mouse_hid_descriptors;
+        mouse_data_alternate_descriptions[0].endpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor *);
+        mouse_data_alternate_descriptions[0].endpoint_list = mouse_default;
+        mouse_data_alternate_descriptions[0].endpoint_indexes = mouse_indexes;
+
+        /*! List of Interface description(s)
+         */
+        ZERO(mouse_interfaces);
+        mouse_interfaces[0].alternates = sizeof (mouse_data_alternate_descriptions) / sizeof (struct usbd_alternate_description);
+        mouse_interfaces[0].alternate_list = mouse_data_alternate_descriptions;
+
+
+#else /* defined(OTG_C99) */
+
+/*! This is the interrupt endpoint descriptor.
+ */
+static struct usbd_endpoint_descriptor mouse_data = {
+        .bLength = 0x07, 
+        .bDescriptorType = USB_DT_ENDPOINT, 
+        .bEndpointAddress = USB_DIR_IN, 
+        .bmAttributes = INTERRUPT, 
+        .wMaxPacketSize = __constant_cpu_to_le16(0x10), 
+#if defined (CONFIG_OTG_MOUSE_INTERVAL)
+        .bInterval = CONFIG_OTG_MOUSE_INTERVAL, 
+#else
+        .bInterval = 0x01, 
+#endif /* defined (CONFIG_OTG_MOUSE_INTERVAL) */
+};
+
+/*! The list of endpoint descriptors 
+ */
+static struct usbd_endpoint_descriptor *mouse_default[] = { &mouse_data, };
+
+
+/*! List of class descriptors 
+ */
+static struct usbd_generic_class_descriptor *mouse_hid_descriptors[] = { 
+        (struct usbd_generic_class_descriptor *)&mouse_hid, };
+
+
+/*! Data Interface Alternate description
+ */
+static struct usbd_interface_descriptor  mouse_data_alternate_descriptor = {
+        .bLength = 0x09, 
+        .bDescriptorType = USB_DT_INTERFACE, 
+        .bInterfaceNumber = 0x00, 
+        .bAlternateSetting = 0x00, 
+        .bNumEndpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor), 
+        .bInterfaceClass = 0x03, 
+        .bInterfaceSubClass = 0x01, 
+        .bInterfaceProtocol = 0x02, 
+        .iInterface = 0x00,
+};
+
+/*! Interface Descriptions
+ */
+static struct usbd_alternate_description mouse_data_alternate_descriptions[] = {
+        { .iInterface = "Random Mouse Interface - Interrupt",
+                .interface_descriptor =  &mouse_data_alternate_descriptor,
+                .classes = sizeof (mouse_hid_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
+                .class_list =  mouse_hid_descriptors,
+                .endpoints = sizeof (mouse_default) / sizeof(struct usbd_endpoint_descriptor *),
+                .endpoint_list =  mouse_default,
+                .endpoint_indexes =  mouse_indexes,
+        },
+};
+
+/*! List of Interface description(s)
+ */
+static struct usbd_interface_description mouse_interfaces[] = {
+      { .alternates = sizeof (mouse_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                .alternate_list = mouse_data_alternate_descriptions,},
+};
+
+#endif /* defined(OTG_C99) */
+
+/*! @} */ 
+
+static int mouse_count;
+
+/* MOUSE ***************************************************************************************** */
+/* Transmit Function *************************************************************************** */
+
+int get_xy[8] = {
+         0,  0,  1,  1, 
+         0,  0, -1, -1, 
+};
+
+/*!
+ * mouse_send() - send a mouse data urb with random data
+ * @param function
+ * @return void
+ */
+void mouse_send(struct usbd_function_instance *function)
+{
+        struct mouse_private *mouse = &mouse_private;
+        int new_x = 0;
+        int new_y = 0;
+        u8 random;
+
+        memset(mouse->tx_urb->buffer, 0, 4);
+        if (!mouse->n) {
+
+                get_random_bytes(&random, 1);
+
+                mouse->last_x = MAX(-4, MIN(4, mouse->last_x + get_xy[random & 0x7]));
+                mouse->last_y = MAX(-4, MIN(4, mouse->last_y + get_xy[(random >> 3) & 0x7]));
+                mouse->n = (random>>6) & 0x3;
+
+                new_x = mouse->x + mouse->last_x;
+                new_y = mouse->y + mouse->last_y;
+
+                mouse->tx_urb->buffer[1] = mouse->last_x;
+                mouse->x = new_x;
+                mouse->tx_urb->buffer[2] = mouse->last_y;
+                mouse->y = new_y;
+                mouse->tx_urb->actual_length = 4;
+
+        }
+        else if ((mouse->n)&1) {
+                mouse->n--;
+        } 
+        else {
+                mouse->n--;
+                mouse->tx_urb->buffer[1] = mouse->last_x;
+                mouse->x = new_x;
+                mouse->tx_urb->buffer[2] = mouse->last_y;
+                mouse->y = new_y;
+        }
+        usbd_start_in_urb(mouse->tx_urb);
+}
+
+/*! 
+ * mouse_urb_sent() - called to indicate URB transmit finished
+ * This function is the callback function for sent urbs.
+ * It simply queues up another urb until the packets to be sent
+ * configuration parameter is reached (or forever if zero.)
+ * @param urb The urb to be sent.
+ * @param rc result
+ * @return int Return non-zero for failure.
+ */
+int mouse_urb_sent (struct usbd_urb *urb, int rc)
+{
+        struct mouse_private *mouse = &mouse_private;
+        struct usbd_function_instance *function = mouse->function;
+
+        RETURN_ZERO_IF(usbd_get_device_status(function) == USBD_CLOSING);
+        RETURN_ZERO_IF(usbd_get_device_status(function) != USBD_OK);
+        RETURN_ZERO_IF(usbd_get_device_state(function) != STATE_CONFIGURED);
+        TRACE_MSG1(MOUSE, "mouse_count: %d", mouse_count);
+        #ifdef CONFIG_OTG_MOUSE_PACKETS
+        RETURN_ZERO_IF (CONFIG_OTG_MOUSE_PACKETS && (mouse_count++ > CONFIG_OTG_MOUSE_PACKETS));
+        #endif /* CONFIG_OTG_MOUSE_PACKETS */
+        mouse_send(function);                                                   // re-send
+        return 0;
+}
+
+/* USB Device Functions ************************************************************************ */
+
+typedef enum mesg {
+        mesg_unknown,
+        mesg_configured,
+        mesg_reset,
+} mesg_t;
+static mesg_t mouse_last_mesg;
+
+static char * mouse_messages[3] = {
+        "",
+        "Mouse-if Configured",
+        "Mouse-if Reset",
+};
+
+static void mouse_check_mesg(mesg_t curr_mesg)
+{
+        RETURN_UNLESS(mouse_last_mesg != curr_mesg);
+        mouse_last_mesg = curr_mesg;
+        otg_message(mouse_messages[curr_mesg]);
+}
+
+/*! 
+ * mouse_event_handler() - process a device event
+ * This function is called to process USB Device Events.
+ *
+ * The DEVICE_CONFIGURED event causes the mouse_send() to be called
+ * to start the data flow.
+ *
+ * The DEVICE_RESET or DEVICE_DE_CONFIGURED events cause the outstanding
+ * transmit urb to be cancelled.
+ *
+ * @param function the function instance 
+ * @param event the event 
+ * @param data
+ * @return void
+ *
+ */
+static void mouse_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
+{
+        struct mouse_private *mouse = &mouse_private;
+
+        switch (event) {
+        case DEVICE_CONFIGURED:
+                TRACE_MSG0(MOUSE, "Mouse-if Configured");
+                mouse_check_mesg(mesg_configured);
+                mouse_count = 0;
+                mouse->connected = 1;
+                if (!(mouse->tx_urb = usbd_alloc_urb (function, BULK_INT, 4, mouse_urb_sent))) 
+                        printk(KERN_INFO"%s: alloc failed\n", __FUNCTION__);
+                mouse_send(function);                                           // start sending
+                break;
+
+        case DEVICE_RESET:
+        case DEVICE_DE_CONFIGURED:
+                TRACE_MSG0(MOUSE, "Mouse-if De-Configured");
+                mouse_check_mesg(mesg_reset);
+                BREAK_IF(!mouse->connected);
+                mouse->connected = 0;
+                if (mouse->tx_urb) {
+                        usbd_free_urb (mouse->tx_urb);
+                        mouse->tx_urb = NULL;
+                }
+                break;
+        default: 
+                break;
+        }
+}
+
+#ifdef CONFIG_OTG_MOUSE_BH
+/*! 
+ * mouse_hid_bh() - Bottom half handler to send a HID report
+ * @param data
+ */
+static void mouse_hid_bh (void *data)
+{
+        struct usbd_function_instance *function = mouse_private.function;
+        mouse_send_hid(function);
+}
+
+/*! mouse_schedule_bh - schedule a call for mouse_hid_bh
+ * @param void
+ */
+static int mouse_schedule_bh (void)
+{
+        TRACE_MSG0(MOUSE, "Scheduling");
+        return (!schedule_task (&mouse_private.notification_bh)) ? EINVAL : 0;
+}
+#endif /* CONFIG_OTG_MOUSE_BH */
+
+/*! 
+ * mouse_device_request - called to indicate urb has been received
+ * @param function
+ * @param request
+ */
+static int mouse_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
+{
+        return -EINVAL;
+}
+
+
+/*! mouse_function_enable - called by USB Device Core to enable the driver
+ * @param function The function instance for this driver to use.
+ * @return non-zero if error.
+ */
+static int mouse_function_enable (struct usbd_function_instance *function)
+{
+        struct mouse_private *mouse = &mouse_private;
+        mouse->function = function;
+        mouse->n = 0;
+        mouse->x = 0;
+        mouse->y = 0;
+        mouse->last_x = 0;
+        mouse->last_y = 0;
+        mouse->writesize = usbd_endpoint_wMaxPacketSize(function, BULK_INT, 0);
+        return 0;
+}
+
+/*! mouse_function_disable - called by the USB Device Core to disable the driver
+ * @param function The function instance for this driver
+ */
+static void mouse_function_disable (struct usbd_function_instance *function)
+{               
+        struct mouse_private *mouse = &mouse_private;
+        mouse->function = NULL;
+        mouse->writesize = 0;
+        mouse->function = NULL;
+}
+
+/* ********************************************************************************************* */
+#if !defined(OTG_C99)
+/*! function_ops - operations table for the USB Device Core
+ */
+static struct usbd_function_operations mouse_function_ops;
+
+/*! mouse_interfacedriver - USB Device Core function driver definition
+ */
+struct usbd_function_driver mouse_interfacedriver;
+
+void mouse_if_ops_init(void)
+{
+        /*! function_ops - operations table for the USB Device Core
+         */
+        ZERO(mouse_function_ops);
+        mouse_function_ops.event_handler = mouse_event_handler;              /*! called for each USB Device Event */
+        mouse_function_ops.device_request = mouse_device_request;          /*! called for each received device request */
+        mouse_function_ops.function_enable = mouse_function_enable;         /*! called to enable the function driver */
+        mouse_function_ops.function_disable = mouse_function_disable;       /*! called to disable the function driver */
+
+        /*! function_driver - USB Device Core function driver definition
+         */
+        ZERO(mouse_interfacedriver);
+        mouse_interface_driver.name = "mouse-random-if-driver-noc99";                            /*! driver name */
+        mouse_interface_driver.fops = &mouse_function_ops;                             /*! operations table */
+
+        mouse_function_driver.bNumInterfaces = sizeof (mouse_interfaces) / sizeof (struct usbd_interface_description);
+        mouse_function_driver.interface_list = mouse_interfaces;
+        mouse_interface_driver.endpointsRequested = ENDPOINTS;
+        mouse_interface_driver.requestedEndpoints = mouse_endpoint_requests;
+
+}
+#else /* defined(OTG_C99) */
+/*! function_ops - operations table for the USB Device Core
+ */
+static struct usbd_function_operations mouse_function_ops = {
+        .event_handler = mouse_event_handler,                     /*!< called for each USB Device Event */
+        .device_request = mouse_device_request,           /*!< called for each received device request */
+        .function_enable = mouse_function_enable,         /*!< called to enable the function driver */
+        .function_disable = mouse_function_disable,       /*!< called to disable the function driver */
+};
+
+/*! mouse_interface_driver - USB Device Core function driver definition
+ */
+struct usbd_function_driver mouse_interface_driver = {
+        .name = "mouse-random-if-driver",                        /*!< driver name */
+        .fops = &mouse_function_ops,                             /*!< operations table */
+        .endpointsRequested = ENDPOINTS,
+        .requestedEndpoints = mouse_endpoint_requests,
+};
+#endif /* defined(OTG_C99) */
+
diff -uNr linux/drivers/no-otg/functions/mouse/mouse-l24.c linux/drivers/otg/functions/mouse/mouse-l24.c
--- linux/drivers/no-otg/functions/mouse/mouse-l24.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/mouse/mouse-l24.c	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,175 @@
+/*
+ * otg/functions/mouse/mouse-l24.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/functions/mouse/mouse-l24.c
+ * @brief Mouse Function Driver Linux 2.4 initialization
+ *
+ *
+ * This file contains the Linux 2.4 module init and exit functions
+ * to load and unload the Random Mouse Function.
+ *
+ * Notes
+ *
+ * This driver does not export any upper edge functionality to
+ * for the user or applications to use. It simply sends a configurable
+ * number of data packets to the USB Host when configured. Each data
+ * packet contains the equivalent of a small mouse report which will
+ * cause the mouse cursor to move on the host.
+ *
+ * To use simply load with something like:
+ *
+ *      insmod mouse_fd.o vendor_id=0xffff product_id=0xffff
+ *
+ * And attach to a Windows box. Windows should recognize as a mouse and
+ * immediately start receiving a stream of data. 
+ *
+ * To terminate simply unplug.
+ *
+ *
+ * 1. The mouse driver is product name is hard coded to a string that will
+ *    generate a string descriptor that is 32 bytes long. This will test
+ *    most UDC's ep0 ZLP handling as it is a multiple of the most common
+ *    UDC endpoint zero size. (An option can be added later to allow for
+ *    64 byte ep0 packetsize.)
+ *
+ * 2. The CONFIG_OTG_MOUSE_BH option can be enabled to delay the HID report 
+ *    to being generated by a bottom half handler. This will verify that 
+ *    the bus interface driver properly handles the case of a delayed
+ *    CONTROL READ. I.e. when the usbd_device_request() function returns
+ *    zero for successful completion but there is no tx_urb containing the
+ *    requested data. The bus interface driver must setup the conditions for
+ *    ACK'ing the SETUP packet but then NAK the IN data for endpoint zero
+ *    until the tx_urb is started later.
+ *
+ * 3. The CONFIG_OTG_MOUSE_PACKETS option is used to set the number of
+ *    mouse data reports to send. Set to zero for a continous stream
+ *    of data.
+ *
+ * @ingroup MouseFunction
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/otg-trace.h>
+
+#include "mouse.h"
+
+
+/* Module Parameters ******************************************************** */
+/* ! 
+ * @name XXXXX MODULE Parameters
+ */
+/* ! @{ */
+
+MOD_AUTHOR ("sl@belcarra.com, tbr@belcarra.com"); 
+EMBED_LICENSE();
+MOD_DESCRIPTION ("Belcarra Random Walk MOUSE Function");
+
+static u32 vendor_id;           /*!< override built-in vendor ID */
+static u32 product_id;          /*!< override built-in product ID */
+
+MOD_PARM (vendor_id, "i");
+MOD_PARM (product_id, "i");
+
+MOD_PARM_DESC (vendor_id, "Device Vendor ID");
+MOD_PARM_DESC (product_id, "Device Product ID");
+
+otg_tag_t MOUSE;
+/* ! *} */
+
+/* USB Module init/exit ***************************************************** */
+
+/*! 
+ * mouse_modinit() - module init
+ *
+ * This is called by the Linux kernel; either when the module is loaded
+ * if compiled as a module, or during the system intialization if the 
+ * driver is linked into the kernel.
+ *
+ * This function will parse module parameters if required and then register
+ * the mouse driver with the USB Device software.
+ *
+ * If the CONFIG_OTG_MOUSE_BH option is enabled it will also setup the mouse
+ * bottom half handler.
+ *
+ */
+static int mouse_modinit (void)
+{
+        struct usbd_function_instance *mfi;
+        printk (KERN_INFO "%s: vendor_id: %04x product_id: %04x\n", __FUNCTION__, vendor_id, product_id);
+
+        #if !defined(OTG_C99)
+        mouse_global_init();
+        mouse_ops_init();
+        #endif /* defined(OTG_C99) */
+        
+        MOUSE = otg_trace_obtain_tag();
+        TRACE_MSG2(MOUSE, "vendor_id: %04x product_id: %04x",vendor_id, product_id);
+
+        if (vendor_id) 
+                mouse_function_driver.idVendor = cpu_to_le16(vendor_id);
+        if (product_id) 
+                mouse_function_driver.idProduct = cpu_to_le16(product_id);
+
+        mouse_hid.wItemLength = cpu_to_le16(0x34);      // XXX mips compiler bug.....
+
+        // register as usb function driver
+        THROW_UNLESS ((mouse_private.function = usbd_register_function (&mouse_function_driver, "mouse",  NULL)), error);
+        #ifdef CONFIG_OTG_MOUSE_BH
+        mouse_private.notification_bh.routine = mouse_hid_bh;
+        mouse_private.notification_bh.data = NULL;
+        #endif
+        CATCH(error) {
+                if (mouse_private.function) {
+                        usbd_deregister_function (mouse_private.function);
+                        mouse_private.function = NULL;
+                }
+                otg_trace_invalidate_tag(MOUSE);
+                return -EINVAL;
+        }
+        return 0;
+}
+
+module_init (mouse_modinit);
+
+#if OTG_EPILOGUE
+/*! 
+ * mouse_modexit() - module init
+ *
+ * This is called by the Linux kernel; when the module is being unloaded 
+ * if compiled as a module. This function is never called if the 
+ * driver is linked into the kernel.
+ *
+ * @param void
+ * @return void
+ */
+static void mouse_modexit (void)
+{
+        #ifdef CONFIG_OTG_MOUSE_BH
+        while (PENDING_WORK_ITEM(mouse_private.notification_bh)) {
+                printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
+                schedule_timeout(10 * HZ);
+        }
+        #endif
+        if (mouse_private.function) {
+                usbd_deregister_function (mouse_private.function);
+                mouse_private.function = NULL;
+        }
+
+        otg_trace_invalidate_tag(MOUSE);
+}
+
+module_exit (mouse_modexit);
+#endif
+
diff -uNr linux/drivers/no-otg/functions/mouse/mouse.h linux/drivers/otg/functions/mouse/mouse.h
--- linux/drivers/no-otg/functions/mouse/mouse.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/mouse/mouse.h	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,63 @@
+/*
+ * otg/functions/mouse/mouse.h
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+/*!
+ * @defgroup MouseFunction Random Mouse
+ * @ingroup functiongroup
+ */
+/*!
+ * @file otg/functions/mouse/mouse.h
+ * @brief Mouse Function Driver private defines
+ *
+ *
+ * This is a test USB HID Function Driver designed to test and
+ * verify that INTERRUPT IN endpoints work properly.
+ *
+ *
+ * @ingroup MouseFunction
+ */
+
+
+/*!
+ * The mouse_private structure is used to collect all of the mouse driver 
+ * global variables into one place.
+ */
+struct mouse_private {
+        struct usbd_function_instance *function; /*!< function instance for this module */
+#ifdef CONFIG_OTG_MOUSE_BH
+        struct WORK_STRUCT notification_bh;
+#endif /* CONFIG_OTG_MOUSE_BH */
+        int usb_driver_registered;              /*!< non-zero if usb function registered */
+        unsigned char connected;                /*!< non-zero if connected to host (configured) */
+        unsigned int writesize;                 /*!< packetsize * 4 */
+        struct usbd_urb *tx_urb;                /*!< saved copy of current tx urb */
+        int wLength;                            
+        int x;
+        int y;
+        int last_x;
+        int last_y;
+        int n;
+};
+
+extern struct mouse_private mouse_private;
+extern struct usbd_function_driver mouse_function_driver;
+extern struct usbd_function_driver mouse_interface_driver;
+extern struct usbd_function_driver mouse_composite_driver;
+extern struct hid_descriptor mouse_hid;
+
+#ifndef OTG_C99
+extern void mouse_global_init(void);
+#endif /* OTG_C99 */
+
+#define MOUSE mouse_trace_tag
+extern otg_tag_t MOUSE;
+
diff -uNr linux/drivers/no-otg/functions/msc/Config.in linux/drivers/otg/functions/msc/Config.in
--- linux/drivers/no-otg/functions/msc/Config.in	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/Config.in	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,25 @@
+#
+# Mass Storage Class Function Drivers
+#
+# Copyright (C) 2003 Belcarra
+#
+
+
+mainmenu_option next_comment
+
+comment "Mass Storage Function "
+dep_tristate '  Mass Storage Function' CONFIG_OTG_MSC $CONFIG_OTG
+
+if [ "$CONFIG_OTG_MSC" = "y" -o "$CONFIG_OTG_MSC" = "m" ]; then
+   hex     'VendorID (hex value)' CONFIG_OTG_MSC_VENDORID "15ec"
+   hex     'ProductID (hex value)' CONFIG_OTG_MSC_PRODUCTID "f006"
+   hex     'bcdDevice (binary-coded decimal)' CONFIG_OTG_MSC_BCDDEVICE "0100"
+
+   string  'iManufacturer (string)' CONFIG_OTG_MSC_MANUFACTURER "Belcarra"
+   string  'iProduct (string)' CONFIG_OTG_MSC_PRODUCT_NAME "Mass Storage Class - Bulk Only"
+   string  'MSC Bulk Only iInterface (string)' CONFIG_OTG_MSC_INTF "MSC BO Data Intf"
+   string  'Data Interface iConfiguration (string)' CONFIG_OTG_MSC_DESC "MSC BO Configuration"	
+
+fi
+
+endmenu
diff -uNr linux/drivers/no-otg/functions/msc/Kconfig linux/drivers/otg/functions/msc/Kconfig
--- linux/drivers/no-otg/functions/msc/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/Kconfig	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,52 @@
+menu "OTG Mass Storage function"
+	depends on OTG
+
+config OTG_MSC
+        tristate "  Mass Storage Function"
+        depends on OTG
+
+menu "OTG Mass Storage function options"
+	depends on OTG && OTG_MSC
+
+config OTG_MSC_VENDORID
+        hex "VendorID (hex value)"
+        depends on OTG && OTG_MSC
+        default "Ox15ec"
+
+config OTG_MSC_PRODUCTID
+        hex "ProductID (hex value)"
+        depends on OTG && OTG_MSC
+        default "Oxf006"
+
+config OTG_MSC_BCDDEVICE
+        hex "bcdDevice (binary-coded decimal)"
+        depends on OTG && OTG_MSC
+        default "Ox0100"
+
+config OTG_MSC_MANUFACTURER
+        string "iManufacturer (string)"
+        depends on OTG && OTG_MSC
+        default "Belcarra"
+
+config OTG_MSC_PRODUCT_NAME
+        string "iProduct (string)"
+        depends on OTG && OTG_MSC
+        default "Mass Storage Class - Bulk Only"
+
+config OTG_MSC_INTF
+        string "MSC Bulk Only iInterface (string)"
+        depends on OTG && OTG_MSC
+        default "MSC BO Data Intf"
+
+config OTG_MSC_DESC
+        string "Data Interface iConfiguration (string)"
+        depends on OTG && OTG_MSC
+        default "MSC BO Configuration"
+
+config OTG_MSC_REGISTER_TRACE
+        bool "  MSC Tracing"
+        depends on OTG && OTG_MSC
+        default n
+endmenu
+
+endmenu
diff -uNr linux/drivers/no-otg/functions/msc/Makefile linux/drivers/otg/functions/msc/Makefile
--- linux/drivers/no-otg/functions/msc/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/Makefile	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,68 @@
+#
+# Function driver for a Mass Storage USB Device
+#
+# Copyright (c) 2003 Belcarra
+
+# Multipart objects.
+
+O_TARGET	:= msc_target.o
+list-multi	:= msc_fd.o 
+
+#msc_fd-objs	:= msc.o crc.o 
+msc_fd-objs	:= msc-fd.o crc.o msc-linux.o msc-bo.o msc-io-l24.o
+
+# Objects that export symbols.
+#export-objs	:= msc.o 
+export-objs	:= msc-fd.o msc-linux.o msc-bo.o
+
+# Object file lists.
+
+obj-y	:=
+obj-m	:=
+obj-n	:=
+obj-	:=
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_OTG_MSC)   += msc_fd.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+int-m		:= $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
+OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+
+# The global Rules.make.
+
+MSCD=$(OTG)/functions/msc
+
+OTG=$(TOPDIR)/drivers/otg
+include $(TOPDIR)/Rules.make
+EXTRA_CFLAGS +=  -I$(OTG) -Wno-unused -Wno-format  
+EXTRA_CFLAGS_nostdinc += -I$(OTG) -Wno-unused -Wno-format 
+
+# Link rules for multi-part drivers.
+
+msc_fd.o: $(msc_fd-objs)
+	$(LD) -r -o $@ $(msc_fd-objs)
+
+# dependencies:
+
+mass.o: $(USBDCORE_DIR)/usbd.h $(USBDCORE_DIR)/usbd-bus.h $(USBDCORE_DIR)/usbd-func.h
+
diff -uNr linux/drivers/no-otg/functions/msc/TODO.txt linux/drivers/otg/functions/msc/TODO.txt
--- linux/drivers/no-otg/functions/msc/TODO.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/TODO.txt	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,118 @@
+MSC TODO List                                                   Stuart Lynne
+Belcarra                                        Mon Oct 25 00:51:12 PDT 2004 
+
+
+1. MSC documentation
+
+        - requirements and specifications
+        - comparison to mass storage specification, bulk-only and rbc
+        - implementation specifics
+        - rbc/spc commands
+        - sense keys
+        - control and usage
+
+2. PSC requirements
+
+        - notification to PSM layer for addroot and deleteroot
+
+
+3. expunge non Belcarra code and header files
+
+
+4. Insertion emulation
+
+        i. If not connected,
+                - do bdget(),
+                - do blkdev_get()
+                - set flags appropriately.
+
+        ii. If connected,
+                - ensure that there are no active requests (sleep if neccessary)
+                - do bdget()
+                - do blkdev_get()
+                - ensure that overlapped requests from the host while
+                  doing the open will not cause problems
+
+5. Removal emulation
+
+        i. If not connected
+                - reset flags appropriately
+
+        ii. If connected,
+                - wait for any active requests to complete (sleep if necessary),
+                - reset flags
+                - ensure that overlapped requests from host while
+                  resetting the flags will not cause problems
+                - wait for acknowledgement from host
+
+
+Note that all of the above must take place in the thread of execution of
+the ioctl call (i.e. a normal user thread or process.)
+
+The ioctl should not complete until all of the above is complete OR
+cannot complete and you return an error.
+
+
+6. ioctls
+
+Finish ioctl implementation.
+
+        start           start using block device (major, minor specified)
+        stop            stop using block device
+        status          return current connection status
+        connect         wait for connection
+        disconnect      wait for dis-connection
+        connected       return zero if connected, error otherwise
+        disconnected    return zero if dis-connected, error otherwise
+
+
+7. tests
+
+Get the tests in the scripts directory working. 
+
+These should verify the following:
+
+        1. connect/disconnect while started/stopped
+        2. start/stop while connected/disconnected
+       
+
+Or as two matrixes:
+
+                        Connected       Disconnected
+        Start
+        Stop
+
+
+                        Started         Stopped
+        Connect
+        DisConnect
+
+
+All valid combinations of starting, stopping, connecting and disconnecting
+must be verified.
+                
+
+
+8. Windows
+
+Get Windows test applicatoin working.
+
+9. Compatibility
+
+Test against:
+
+        WinXP
+        Win2k
+        Linux 2.4
+        (Linux 2.6)
+        (WinME)
+
+
+
+10. code review
+
+        - review other drivers to verify we have implemented all required 
+        rbc/spc-2 commands and sense codes
+
+11. prevent removal
+
diff -uNr linux/drivers/no-otg/functions/msc/crc.c linux/drivers/otg/functions/msc/crc.c
--- linux/drivers/no-otg/functions/msc/crc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/crc.c	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,74 @@
+/*
+ * otg/msc_fd/crc.c - crc table
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Chris Lynne <cl@belcarra.com>
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <otg/otg-compat.h>
+
+//#include <usbd-chap9.h>
+//#include <usbd-mem.h>
+//#include <usbd.h>
+//#include <usbd-func.h>
+
+#include "crc.h"
+
+unsigned int *msc_crc32_table;
+
+/**
+ * Generate the crc32 table
+ *
+ * return non-zero if malloc fails
+ */
+int make_crc_table(void)
+{
+        unsigned int n;
+        if (msc_crc32_table) return 0;
+        if (!(msc_crc32_table = (unsigned int *)ckmalloc(256*4, GFP_KERNEL))) return -EINVAL;
+        for (n = 0; n < 256; n++) {
+                int k;
+                unsigned int c = n;
+                for (k = 0; k < 8; k++) {
+                        c =  (c & 1) ? (CRC32_POLY ^ (c >> 1)) : (c >> 1);
+                }
+                msc_crc32_table[n] = c;
+        }
+        return 0;
+}
+
+void free_crc_table(void)
+{
+        if (msc_crc32_table) {
+                lkfree(msc_crc32_table);
+                msc_crc32_table = NULL;
+        }
+}
+
+unsigned int crc32_compute(unsigned char *src, int len, unsigned int val)
+{
+        for (; len-- > 0; val = COMPUTE_FCS (val, *src++));
+        return val;
+}
+
diff -uNr linux/drivers/no-otg/functions/msc/crc.h linux/drivers/otg/functions/msc/crc.h
--- linux/drivers/no-otg/functions/msc/crc.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/crc.h	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,29 @@
+/*
+ * otg/msc_fd/crc.c - crc table
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Chris Lynne <cl@belcarra.com>
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *      Ted Powell <ted@belcarra.com>
+ *
+ *
+ */
+
+
+extern unsigned int *msc_crc32_table;
+
+#define CRC32_INIT   0xffffffff      // Initial FCS value
+#define CRC32_GOOD   0xdebb20e3      // Good final FCS value
+
+#define CRC32_POLY   0xedb88320      // Polynomial for table generation
+        
+#define COMPUTE_FCS(val, c) (((val) >> 8) ^ msc_crc32_table[((val) ^ (c)) & 0xff])
+
+int make_crc_table(void);
+void free_crc_table(void);
+unsigned int crc32_compute(unsigned char *src, int len, unsigned int val);
+
+
diff -uNr linux/drivers/no-otg/functions/msc/msc-bo.c linux/drivers/otg/functions/msc/msc-bo.c
--- linux/drivers/no-otg/functions/msc/msc-bo.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/msc-bo.c	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,176 @@
+/*
+ * otg/function/msc/msc-bo.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/functions/msc/msc-bo.c
+ * @brief Mass Storage Driver private defines
+ *
+ * This is a Mass Storage Class Function that uses the Bulk Only protocol.
+ *
+ *
+ * @ingroup MSCFunction
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/otg-trace.h>
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+
+#include <linux/blkdev.h>
+
+
+#include "msc-scsi.h"
+#include "msc.h"
+#include "msc-fd.h"
+#include "crc.h"
+
+//#include "rbc.h"
+
+/*!
+ * Mass Storage Class - Bulk Only
+ *
+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
+ */
+
+static u8 msc_data_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK,     0, 0x00, 0x00,  };
+static u8 msc_data_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  BULK,     0, 0x00, 0x00, };
+static struct usbd_endpoint_descriptor *msc_default[] = { 
+        (struct usbd_endpoint_descriptor *) msc_data_1, 
+        (struct usbd_endpoint_descriptor *) msc_data_2, };
+u8 msc_indexes[] = { BULK_OUT, BULK_IN, };
+
+
+/*! Endpoint, Interface, Configuration and Device descriptions and descriptors
+ */
+static u8 msc_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
+        0x09, USB_DT_INTERFACE, 
+        0x00, 0x00, // bInterfaceNumber, bAlternateSetting
+        sizeof (msc_default) / sizeof(struct usbd_endpoint_descriptor), // bNumEndpoints
+        MASS_STORAGE_CLASS,
+        MASS_STORAGE_SUBCLASS_SCSI,
+        MASS_STORAGE_PROTO_BULK_ONLY,
+        0x00,
+};
+
+static struct usbd_alternate_description msc_data_alternate_descriptions[] = {
+        { iInterface: CONFIG_OTG_MSC_INTF,
+                interface_descriptor: (struct usbd_interface_descriptor *)&msc_data_alternate_descriptor,
+                endpoints:sizeof (msc_default) / sizeof(struct usbd_endpoint_descriptor *),
+                endpoint_list: msc_default,
+                endpoint_indexes: msc_indexes,
+                },
+};
+
+
+struct usbd_interface_description msc_interfaces[] = {
+        { alternates:sizeof (msc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:msc_data_alternate_descriptions,},
+};
+
+u8 msc_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
+        0x09, USB_DT_CONFIGURATION, 0x00, 0x00, // wLength
+        sizeof (msc_interfaces) / sizeof (struct usbd_interface_description),
+        0x01, 0x00, // bConfigurationValue, iConfiguration
+        0, 0,
+};
+
+struct usbd_configuration_description msc_description[] = {
+        { iConfiguration: CONFIG_OTG_MSC_DESC,
+                configuration_descriptor: (struct usbd_configuration_descriptor *)msc_configuration_descriptor,
+        },
+};
+
+
+static struct usbd_device_descriptor msc_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: 0x00,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_MSC_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_MSC_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_MSC_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+static struct usbd_device_qualifier_descriptor msc_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: 0x00,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+
+
+
+static struct usbd_endpoint_request msc_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, PAGE_SIZE, PAGE_SIZE, },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, PAGE_SIZE, PAGE_SIZE, },
+        { 0, },
+};
+
+struct usbd_otg_descriptor msc_otg_descriptor = {
+        bLength : sizeof(struct usbd_otg_descriptor),
+        bDescriptorType: USB_DT_OTG,
+        bmAttributes: 0,
+};
+
+struct usbd_device_description msc_device_description = {
+        device_descriptor: &msc_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &msc_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &msc_otg_descriptor,
+        iManufacturer: CONFIG_OTG_MSC_MANUFACTURER,
+        iProduct: CONFIG_OTG_MSC_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR, 
+#endif
+};
+
+
+extern struct usbd_function_operations msc_function_ops;
+
+struct usbd_function_driver msc_function_driver = {
+        name: "msc-bulkonly",
+        fops:&msc_function_ops,
+        device_description:&msc_device_description,
+        bNumConfigurations:sizeof (msc_description) / sizeof (struct usbd_configuration_description),
+        configuration_description:msc_description,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_MSC_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_MSC_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_MSC_BCDDEVICE),
+        bNumInterfaces:sizeof (msc_interfaces) / sizeof (struct usbd_interface_description),
+        interface_list:msc_interfaces,
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: msc_endpoint_requests,
+};
+
diff -uNr linux/drivers/no-otg/functions/msc/msc-fd.c linux/drivers/otg/functions/msc/msc-fd.c
--- linux/drivers/no-otg/functions/msc/msc-fd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/msc-fd.c	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,1233 @@
+/*
+ * otg/function/msc/msc.-fd.cc
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By:
+ *      Stuart Lynne <sl@belcarra.com>,
+ *      Tom Rushworth <tbr@belcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+/*!
+ * @file otg/functions/msc/msc-fd.c
+ * @brief Mass Storage Driver private defines
+ *
+ * This is a Mass Storage Class Function that uses the Bulk Only protocol.
+ *
+ *
+ * Notes:
+ *
+ * 1. Currently we only support the Bulk Only model. Microsoft states that
+ * further support for the mass storage driver will only be done for devices
+ * that conform to the Bulk Only model.
+ *
+ * 2. Multiple LUN's are not supported, but in theory they could be.
+ *
+ * 3. Error handling should be done with STALL but using ZLP seems to also
+ * work. ZLP is usually easier to implement (except possibly on the SA1100.)
+ * We may need to make STALL an option if we find devices (perhaps SA1100)
+ * that cannot reliaby send a ZLP on BULK-IN endpoint.
+ *
+ *
+ * 4. WinXP will match the following:
+ *
+ *      USB: Class_08&SubClass_02&Prot_50
+ *      USB: Class_08&SubClass_05&Prot_50
+ *      USB: Class_08&SubClass_06&Prot_50
+ *
+ * SubClass 02 is MMC or SFF8020I
+ * SubClass 05 is SFF or SFF8070I
+ * SubClass 06 is SCSI
+ *
+ * From the Windows USB Storage FAQ:
+ *
+ *      RBC not supported
+ *
+ *      SubClass = 6 (SCSI)
+ *              CDBs SHOULD NOT be padded to 12 bytes
+ *              ModeSense/ModeSelect SHOULD NOT be translated from 1ah/15h to 5ah/55h
+ *              should be used for FLASH
+ *
+ *      SubClass !=6
+ *              CDBs SHOULD be padded to 12 bytes
+ *              ModeSense/ModeSelect SHOULD be translated from 1ah/15h to 5ah/55h
+ *
+ * We are using the former, SubClass = 6, and implement the required SCSI operations.
+ *
+ * 
+ * TODO
+ *
+ *
+ * 
+ * TODO FIXME Bus Interface Notes
+ *
+ * 1. The bus interface driver must correctly implement NAK'ing if not rcv_urb is
+ * present (see au1x00.c or wmmx.c for examples.)
+ *
+ * 2. The bus interface driver must implement USBD_URB_SENDZLP flag (see au1x00.c 
+ * for example.)
+ *
+ * @ingroup MSCFunction
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/otg-trace.h>
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+
+#include <linux/blkdev.h>
+
+
+#include "msc-scsi.h"
+#include "msc.h"
+#include "msc-fd.h"
+#include "crc.h"
+
+
+/* Module Parameters ************************************************************************* */
+
+
+#define DEVICE_EJECTED          0x0001          // MEDIA_EJECTED
+#define DEVICE_INSERTED         0x0002          // MEDIA_INSERT
+
+#define DEVICE_OPEN             0x0004          // WR_PROTECT_OFF
+#define DEVICE_WRITE_PROTECTED  0x0008          // WR_PROTECT_ON
+
+#define DEVICE_CHANGE_ON        0x0010          // MEDIA_CHANGE_ON
+
+#define DEVICE_PREVENT_REMOVAL  0x0020
+
+
+#define DEF_NUMBER_OF_HEADS     0x10
+#define DEF_SECTORS_PER_TRACK   0x20
+
+
+
+/* MSC ******************************************************************************************** */
+
+extern struct msc_private msc_private;
+
+int msc_urb_sent (struct usbd_urb *tx_urb, int rc);
+static int msc_recv_urb (struct usbd_urb *urb, int rc);
+
+otg_tag_t msc_fd_trace_tag;
+
+/* Sense Key *********************************************************************************** */
+
+/*! set_sense_data - set sensedata in msc private struture
+ * @param msc
+ * @param sensedata
+ * @param info
+ *
+ * This saves sense data. Sense data indicates what type of error
+ * has occurred and will be returned to the host when a request sense
+ * command is sent.
+ */
+void set_sense_data(struct msc_private *msc, u32 sensedata, u32 info)
+{
+        TRACE_SENSE(sensedata, info);
+        msc->sensedata = sensedata;
+        msc->info = info;
+}
+
+/* Check blockdev ****************************************************************************** */
+
+/*! msc_check_blockdev_name - check current status of the block device
+ *
+ * Check if the block device is operational, either generate a failed CSW 
+ * or a ZLP if not ready.
+ *
+ * Returns non-zero if the block device is not available for I/O operations
+ * and a failed CSW has already been sent.
+ */
+int msc_check_blockdev_name(struct msc_private *msc, int zlp, char *name)
+{
+        if (msc->block_dev_state & DEVICE_EJECTED) {
+                TRACE_MSG0(MSC,"CHECK BLOCKDEV DEVICE_EJECTED");
+                ((SENDZLP == zlp) ? msc_dispatch_query_urb_zlp : msc_start_sending_csw_failed)
+                        (msc, SCSI_SENSEKEY_MEDIA_NOT_PRESENT, msc->lba, USB_MSC_FAILED);
+                return -EINVAL;
+        }
+        if (msc->block_dev_state & DEVICE_CHANGE_ON) {
+                msc->block_dev_state &= ~DEVICE_CHANGE_ON;
+                TRACE_MSG0(MSC,"CHECK BLOCKDEV DEVICE_CHANGE_ON");
+                ((SENDZLP == zlp) ? msc_dispatch_query_urb_zlp : msc_start_sending_csw_failed)
+                        (msc, SCSI_SENSEKEY_NOT_READY_TO_READY_CHANGE, msc->lba, USB_MSC_FAILED);
+                return -EINVAL;
+        }
+        //TRACE_MSG0(MSC,"CHECK BLOCKDEV DEVICE_INSERTED");
+        return 0;
+}
+
+/* Generic start recv urb and send csw ********************************************************* */
+
+/*! msc_start_recv - queue a receive urb
+ *
+ * Ensure that size is a multiple of the endpoint packetsize.
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_start_recv_urb(struct usbd_function_instance *function, struct msc_private *msc, int size)
+{
+        struct usbd_urb *rcv_urb = NULL;
+        int wMaxPacketSize = usbd_endpoint_wMaxPacketSize(function, BULK_OUT, usbd_high_speed(function));
+        if ((size % wMaxPacketSize)) 
+                size = ((size + wMaxPacketSize) / wMaxPacketSize) * wMaxPacketSize;
+
+        RETURN_EINVAL_UNLESS((rcv_urb = usbd_alloc_urb (function, BULK_OUT, size, msc_recv_urb)));
+        rcv_urb->function_privdata = msc;
+        msc->rcv_urb_finished = NULL;
+        RETURN_ZERO_UNLESS(usbd_start_out_urb(rcv_urb));
+        TRACE_MSG0(MSC,"START RECV URB ERROR"); 
+        usbd_free_urb(rcv_urb);
+        return -EINVAL;
+}
+
+/*! msc_start_sending - start sending a new data or csw urb
+ *
+ * Generate a CSW (Command Status Wrapper) to send to the the host.
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_start_sending_csw(struct usbd_function_instance *function, struct msc_private *msc, u8 status)
+{
+        COMMAND_STATUS_WRAPPER *csw;
+        int length = sizeof(COMMAND_STATUS_WRAPPER);
+        struct usbd_urb *tx_urb;
+
+        //TRACE_MSG1(MSC,"START SENDING CSW %08x", status); 
+
+        msc->command_state = MSC_STATUS;
+
+        RETURN_EINVAL_UNLESS((tx_urb = usbd_alloc_urb (function, BULK_IN, length, msc_urb_sent)));
+
+        tx_urb->actual_length = length;
+        tx_urb->function_privdata = msc;
+
+        // fill in CSW and queue the urb
+        csw = (COMMAND_STATUS_WRAPPER *) tx_urb->buffer;
+        csw->dCSWSignature = CSW_SIGNATURE;
+        csw->dCSWTag = msc->command.dCBWTag;
+        csw->dCSWDataResidue = msc->command.dCBWDataTransferLength - msc->data_transferred_in_bytes;
+        csw->bCSWStatus = status;
+
+        TRACE_MSG2(MSC,"START SENDING CSW status: %02x data residue: %d", status, csw->dCSWDataResidue); 
+
+        RETURN_ZERO_UNLESS(usbd_start_in_urb (tx_urb));
+        TRACE_MSG0(MSC,"START SENDING CSW FAILED");
+        usbd_free_urb (tx_urb);
+        return -EINVAL;
+}
+
+/*! msc_start_sending_csw_failed - starting sending a CSW showing failure
+ *
+ * Sets sensedata and generates a CSW with status set to USB_MSC_FAILED.
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_start_sending_csw_failed(struct msc_private *msc, u32 sensedata, u32 info, int status)
+{
+        TRACE_MSG2(MSC, "sensedata: %x status: %x", sensedata, status);
+        set_sense_data(msc, sensedata, info);
+        return msc_start_sending_csw(msc->function, msc, status);
+}
+
+
+/* ********************************************************************************************* */
+
+/*! msc_alloc_urb - allocate an urb for returning a query
+ *
+ * Returns NULL if there is an error in the USB layer.
+ */
+struct usbd_urb * msc_alloc_urb(struct msc_private *msc, int length)
+{
+        struct usbd_function_instance *function;
+        struct usbd_urb *urb;
+
+        THROW_IF(!(function = msc->function), error);
+        THROW_IF(!(urb = usbd_alloc_urb (function, BULK_IN, length, msc_urb_sent)), error);
+        return urb;
+        CATCH(error) {
+                msc->command_state = MSC_READY;
+                return NULL;
+        }
+}
+
+/*! msc_dispatch_query_urb - dispatch an urb containing query data
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_dispatch_query_urb(struct usbd_urb *urb, struct msc_private *msc, int length, int status)
+{
+        int rc;
+        unsigned long flags;
+
+        TRACE_MSG1(MSC,"DISPATCH URB len: %d", length);
+
+        // save information in msc and urb
+        //
+        urb->function_privdata = msc;
+        urb->actual_length = msc->TransferLength_in_bytes = length;
+
+        // dispatch urb
+        local_irq_save(flags);
+        if ((rc = usbd_start_in_urb (urb))) {
+
+                TRACE_MSG0(MSC,"DISPATCH URB FAILED");
+                usbd_free_urb (urb);
+
+                // stall?
+                msc->command_state = MSC_READY;
+                local_irq_restore(flags);
+                return -EINVAL;
+        }
+        msc->command_state = MSC_QUERY;
+        msc->status = status;
+        local_irq_restore(flags);
+        return 0;
+}
+
+/*! msc_dispatch_query_urb_zlp - send a ZLP
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_dispatch_query_urb_zlp(struct msc_private *msc, u32 sensedata, u32 info, int status)
+{
+        struct usbd_urb *urb;
+        TRACE_MSG2(MSC, "sensedata: %x status: %x", sensedata, status);
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, 1))); 
+        set_sense_data(msc, sensedata, info);
+        urb->flags |= USBD_URB_SENDZLP;
+        return msc_dispatch_query_urb(urb, msc, 0, status);
+}
+
+/* READ 10 COMMAND - read and send data to the host ******************************************** */
+extern int msc_scsi_read_10(struct msc_private *msc, char *name, int op);
+extern int msc_in_read_10_urb_sent(struct usbd_urb *tx_urb, struct msc_private *msc);
+
+/* WRITE 10 - receive data from host and write to block device ********************************* */
+extern int msc_scsi_write_10(struct msc_private *msc, char *name, int op);
+extern void msc_recv_out_blocks(struct usbd_urb *rcv_urb, struct msc_private *msc);
+
+/* SCSI Commands ******************************************************************************* */
+
+/*! msc_scsi_inquiry - process an inquiry
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_inquiry(struct msc_private *msc, char *name, int op) 
+{
+        SCSI_INQUIRY_COMMAND *command = (SCSI_INQUIRY_COMMAND *)&msc->command.CBWCB;
+        SCSI_INQUIRY_DATA *data;
+        struct usbd_urb *urb;
+        int length = sizeof(SCSI_INQUIRY_DATA);
+
+        /*
+         * C.f. SPC2 7.3 INQUIRY command
+         * C.f. Table 46 - Standard INQUIRY data format
+         *
+         * C.f. Table 47 - Peripheral Qualifier
+         *
+         * 000b The specified peripheral device type is currently connected to this
+         *      logical unit.....
+         * 001b The device server is capable of of supporting the peripheral device
+         *      type on this logical unit. However, the physical device is not currently 
+         *      connected to this logical unit.....
+         * 010b Reserved
+         * 011b The device server is not capable of supporting a physical device on
+         *      this logical unit....
+         *      
+         */
+
+        TRACE_MSG4(MSC,"INQUIRY EnableVPD: %02x LogicalUnitNumber: %02x PageCode: %02x AllocLen: %02x",
+                        command->EnableVPD, command->LogicalUnitNumber, command->PageCode, command->AllocationLength);
+
+        // XXX THROW_IF(msc->command_state != MSC_READY, error);
+
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
+
+        data = (SCSI_INQUIRY_DATA *)urb->buffer;
+        data->PeripheralQaulifier = msc->block_dev_state & (DEVICE_EJECTED | DEVICE_CHANGE_ON) ? 0x1 : 0;
+        data->PeripheralDeviceType = 0x00;
+        data->RMB = 0x1;
+        data->ResponseDataFormat = 0x1;
+        data->AdditionalLength = 0x1f;
+        
+        strncpy(data->VendorInformation, CONFIG_OTG_MSC_MANUFACTURER, strlen(CONFIG_OTG_MSC_MANUFACTURER));
+        strncpy(data->ProductIdentification, CONFIG_OTG_MSC_PRODUCT_NAME, strlen(CONFIG_OTG_MSC_PRODUCT_NAME));
+
+        return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
+}
+
+/*! msc_scsi_read_format_capacity - process a query
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_read_format_capacity(struct msc_private *msc, char *name, int op) 
+{
+        SCSI_READ_FORMAT_CAPACITY_DATA *data;
+        struct usbd_urb *urb;
+        int length = sizeof(SCSI_READ_FORMAT_CAPACITY_DATA);
+        u32 block_num = msc->capacity;
+        u32 block_len;
+
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length))); 
+
+        data = (SCSI_READ_FORMAT_CAPACITY_DATA *) urb->buffer;
+
+        data->CapacityListHeader.CapacityListLength = sizeof(data->CurrentMaximumCapacityDescriptor);
+
+        data->CurrentMaximumCapacityDescriptor.NumberofBlocks = block_num;
+        data->CurrentMaximumCapacityDescriptor.DescriptorCode = 0x03;
+        memcpy(data->CurrentMaximumCapacityDescriptor.BlockLength + 1, &block_len, sizeof(block_len));
+
+        return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
+}
+
+/*! msc_read_capacity - process a read_capacity command
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_read_capacity(struct msc_private *msc, char *name, int op) 
+{
+        SCSI_READ_CAPACITY_COMMAND *command = (SCSI_READ_CAPACITY_COMMAND *)&msc->command.CBWCB;
+        SCSI_READ_CAPACITY_DATA *data;
+        struct usbd_urb *urb;
+        int length = 8;
+        u32 lba;
+
+        /*
+         * C.f. RBC 5.3
+         */
+        lba = be32_to_cpu(command->LogicalBlockAddress);
+
+        TRACE_MSG1(MSC,"READ CAPACITY LBA: %d", lba);
+
+        if ((command->PMI > 1) || (!command->PMI && lba)) {
+                TRACE_MSG1(MSC,"READ CAPACITY PMI: %d", command->PMI);
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD_IN_CDB, lba, USB_MSC_FAILED);
+        }
+
+        // alloc urb
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
+
+        data = (SCSI_READ_CAPACITY_DATA *) urb->buffer;
+
+        data->LastLogicalBlockAddress = cpu_to_be32(msc->capacity);
+        data->BlockLengthInBytes = cpu_to_be32(msc->block_size);
+
+        TRACE_MSG2(MSC,"RECV READ CAPACITY lba: %x block_size: %x", 
+                        be32_to_cpu(data->LastLogicalBlockAddress), be32_to_cpu(data->BlockLengthInBytes));
+
+        return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
+}
+
+
+/*! msc_scsi_request_sense - process a request_sense command
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_request_sense(struct msc_private *msc, char *name, int op)
+{
+        SCSI_REQUEST_SENSE_COMMAND*    command = (SCSI_REQUEST_SENSE_COMMAND *)&msc->command.CBWCB;
+        SCSI_REQUEST_SENSE_DATA *data;
+
+        /*
+         * C.f. SPC2 7.20 REQUEST SENSE command
+         */
+
+        struct usbd_urb *urb;
+        int length = sizeof(SCSI_REQUEST_SENSE_DATA);
+
+        // alloc urb
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
+
+        data = (SCSI_REQUEST_SENSE_DATA *) urb->buffer;
+        memset(command, 0x0, length);
+        data->ErrorCode = SCSI_ERROR_CURRENT;
+        data->SenseKey = msc->sensedata >> 16;
+        data->AdditionalSenseLength = 0xa; /* XXX is this needed */
+        data->AdditionalSenseCode = msc->sensedata >> 8;
+        data->AdditionalSenseCodeQualifier = msc->sensedata;
+        data->Valid = 1;
+
+        set_sense_data(msc, SCSI_SENSEKEY_NO_SENSE, 0);
+
+        return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
+}
+
+/*! msc_scsi_mode_sense - process a request_sense command
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_mode_sense(struct msc_private *msc, char *name, int op)
+{
+        SCSI_MODE_SENSE_COMMAND *command = (SCSI_MODE_SENSE_COMMAND *)&msc->command.CBWCB;
+        SCSI_MODE_SENSE_DATA *data;
+        int length = sizeof(SCSI_MODE_SENSE_DATA);
+
+        struct usbd_urb *urb;
+        u8 *cp;
+
+        TRACE_MSG4(MSC,"MODE SENSE dbd: %02x PageControl: %02x PageCode: %02x Alloc: %02x", 
+                        command->DBD, command->PageControl, command->PageCode, 0);
+        length = 8;
+
+        // alloc urb
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
+
+        cp = (u8 *) urb->buffer;
+        memset(cp, 0x0, length);
+
+        cp[0] = 0;
+        cp[1] = 0;
+        cp[2] = 0;              // 0x80 is writeprotect
+        cp[3] = 0x08;
+        cp[4] = 0;
+        cp[5] = 0;
+        cp[6] = 0;
+        cp[7] = 0;
+
+        return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
+}
+
+/*! msc_scsi_mode_sense - process a request_sense command
+ *
+ * Used by:
+ *      win2k
+ *
+ * XXX this doesn't work, need to re-implement and add these pages.
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int new_msc_scsi_mode_sense(struct msc_private *msc, char *name, int op)
+{
+
+        /*
+         * C.f. SPC2 7.8.1 MODE SENSE(6) command
+         */
+
+        static READ_WRITE_ERROR_RECOVERY_PAGE           page_01 = {
+                PageCode:0x01,
+                PageLength:0x0A,
+                ReadRetryCount:0x03,
+                WriteRetryCount:0x80,
+        };
+        static FLEXIBLE_DISK_PAGE                       page_05 = {
+                PageCode:0x05,
+                PageLength:0x1E,
+                TransferRate:__constant_cpu_to_be16(0xFA00),
+                NumberofHeads:0xA0,
+                SectorsperTrack:0x00,
+                DataBytesperSector:__constant_cpu_to_be16(0x0002),
+                NumberofCylinders:__constant_cpu_to_be16(0x0000),
+                MotorOnDelay:0x05,
+                MotorOffDelay:0x1E,
+                MediumRotationRate:__constant_cpu_to_be16(0x6801),
+        };
+        static REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE page_1b = {
+                PageCode:0x1B,
+                PageLength:0x0A,
+                TLUN:0x01,
+        };
+        static TIMER_AND_PROTECT_PAGE                   page_1c = {
+                PageCode:0x1c,
+                PageLength:0x06,
+                InactivityTimeMultiplier:0x0A,
+        };
+
+        SCSI_MODE_SENSE_COMMAND *command = (SCSI_MODE_SENSE_COMMAND *)&msc->command.CBWCB;
+        SCSI_MODE_SENSE_DATA *data;
+        struct usbd_urb *urb;
+        int length = sizeof(SCSI_MODE_SENSE_DATA);
+
+
+        TRACE_MSG4(MSC,"MODE SENSE dbd: %02x PageControl: %02x PageCode: %02x Alloc: %02x", 
+                        command->DBD, command->PageControl, command->PageCode, 0);
+
+
+        if (msc->block_dev_state & DEVICE_EJECTED) {
+                u16 sector   = htons((unsigned short)msc->block_size);
+                u16 cylinder = 0;
+                page_05.NumberofHeads = 0;
+                page_05.SectorsperTrack = 0;
+                memcpy(&page_05.DataBytesperSector, &sector, sizeof(sector));
+                memcpy(&page_05.NumberofCylinders, &cylinder, sizeof(cylinder));
+        }
+        else {
+                u16 sector   = htons((unsigned short)msc->block_size);
+                u32 size = DEF_NUMBER_OF_HEADS * DEF_SECTORS_PER_TRACK * sector;
+                u16 cylinder = htons(msc->capacity / size);
+                page_05.NumberofHeads = DEF_NUMBER_OF_HEADS;
+                page_05.SectorsperTrack = DEF_SECTORS_PER_TRACK;
+                memcpy(&page_05.DataBytesperSector, &sector, sizeof(sector));
+                memcpy(&page_05.NumberofCylinders, &cylinder, sizeof(cylinder));
+        }
+
+        if (SCSI_MODEPAGE_CONTROL_CURRENT != command->PageControl) {
+                TRACE_MSG2(MSC,"MODE SENSE - requeested other than CONTROL_CURRENT: %d %d", 
+                                command->PageControl, command->PageCode);
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD_IN_CDB, msc->lba, USB_MSC_FAILED);
+        }
+
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
+        data = (SCSI_MODE_SENSE_DATA *) urb->buffer;
+
+        data->ModeParameterHeader.WriteProtect = msc->block_dev_state & DEVICE_WRITE_PROTECTED ? 1 : 0;
+
+        switch (command->PageCode) {
+        case SCSI_MODEPAGE_ERROR_RECOVERY:
+                TRACE_MSG0(MSC, "MODEPAGE ERROR_RECOVERY");
+                length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_01);
+                data->ModeParameterHeader.ModeDataLength = length - 1;
+                memcpy(&data->ModePages, &page_01, sizeof(page_01));
+                break;
+        case SCSI_MODEPAGE_FLEXIBLE_DISK_PAGE:
+                TRACE_MSG0(MSC, "MODEPAGE FLEXIBLE_DISK_PAGE");
+                length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_05);
+                data->ModeParameterHeader.ModeDataLength = length - 1;
+                memcpy(&data->ModePages, &page_05, sizeof(page_05));
+                break;
+        case SCSI_MODEPAGE_REMOVABLE_BLOCK_ACCESS:
+                TRACE_MSG0(MSC, "MODEPAGE REMOVABLE_BLOCK_ACCESS");
+                length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1b);
+                data->ModeParameterHeader.ModeDataLength = length - 1;
+                memcpy(&data->ModePages, &page_1b, sizeof(page_1b));
+                break;
+        case SCSI_MODEPAGE_INFORMATION_EXCEPTIONS:
+                TRACE_MSG0(MSC, "MODEPAGE INFORMATION_EXCEPTIONS");
+                length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1c);
+                data->ModeParameterHeader.ModeDataLength = length - 1;
+                memcpy(&data->ModePages, &page_1c, sizeof(page_1c));
+                break;
+        case SCSI_MODEPAGE_ALL_SUPPORTED:
+                TRACE_MSG0(MSC, "MODEPAGE ALL_SUPPORTED");
+                length = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_ALL_PAGES);
+                data->ModeParameterHeader.ModeDataLength = length - 1;
+                memcpy(&data->ModePages.ModeAllPages.ReadWriteErrorRecoveryPage, &page_01, sizeof(page_01));
+                memcpy(&data->ModePages.ModeAllPages.FlexibleDiskPage, &page_05, sizeof(page_05));
+                memcpy(&data->ModePages.ModeAllPages.RemovableBlockAccessCapabilitiesPage, &page_1b, sizeof(page_1b));
+                memcpy(&data->ModePages.ModeAllPages.TimerAndProtectPage, &page_1c, sizeof(page_1c));
+                break;
+        case SCSI_MODEPAGE_CACHING:
+                // see file_storage.c for an example if we want to support this
+                TRACE_MSG0(MSC, "MODEPAGE CACHING (not supported)");
+                break;
+        }
+
+        TRACE_MSG2(MSC,"LENGTH: %d %d", msc->command.dCBWDataTransferLength, length);
+
+        /*
+         * XXX verify that length is <= 256 bytes, return CHECK_CONDITION if it is
+         */
+        length = MIN(msc->command.dCBWDataTransferLength, length);
+
+        return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
+}
+
+
+/*! msc_scsi_test_unit_ready - process a request_sense command
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_test_unit_ready(struct msc_private *msc, char *name, int op)
+{
+        return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+
+/*! msc_scsi_prevent_allow - process a request_sense command
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_prevent_allow(struct msc_private *msc, char *name, int op)
+{
+        SCSI_PREVENT_ALLOW_MEDIA_REMOVAL_COMMAND* command = (SCSI_PREVENT_ALLOW_MEDIA_REMOVAL_COMMAND*)&msc->command.CBWCB;
+
+        /*
+         * C.f. SPC2 7.12 Table 78 PREVENT ALLOW MEDIA REMOVAL Prevent Field
+         *
+         * 00b  Medium removal shall be allowed from both the data transport
+         *      element and the attached medium changer (if any).
+         * 01b  Medium removal shall be prohibited from the data transport
+         *      element but allowed from the attached medium changer (if any).
+         * 10b  Medium removal shall be allowed for the data transport element
+         *      but prohibited for the attached medium changer.
+         * 11b  Medium remval shall be prohibited from both the data transport
+         *      element and the attached medium changer
+         *
+         * Prevention shall terminate after 00b or 10b, after a SYNC CACHE or hard reset.
+         */
+
+        // XXX TODO 
+        // this is from storageproto.c, shouldn't we implement something?
+        if (command->Prevent) 
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD_IN_CDB, msc->lba, USB_MSC_FAILED);
+
+        return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+
+/*! msc_scsi_start_stop - process a request_sense command
+ *
+ * C.f. RBC 5.4 and 5.4.2
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_start_stop(struct msc_private *msc, char *name, int op)
+{
+        SCSI_START_STOP_COMMAND* command = (SCSI_START_STOP_COMMAND*)&msc->command.CBWCB;
+
+        TRACE_MSG4(MSC,"START STOP: Immed: %d Power: %x LoEj: %d Start: %d", 
+                        command->IMMED, command->PowerConditions, command->LoEj, command->Start);
+        /*
+         * C.f. 5.4 
+         *
+         * IMMED - if set return status immediately after command validation, otherwise
+         * return status as soon operation is completed.
+         *
+         * C.f. 5.4.1 Table 8 POWER CONDITIONS
+         *
+         * 0 - M - no change in power condition
+         * 1 - M - place device in active condition
+         * 2 - M - place device in idle condition
+         * 3 - M - place device in Standby condition
+         * 4 -   - reserved
+         * 5 - M - place device in Sleep condition
+         * 6 -   - reserved
+         * 7 - 0 - Device Control
+         *
+         * C.f. 5.4.2 Table 9 START STOP control bit definitions
+         *
+         * Power        Load/Eject      Start   
+         * 1-7          x               x               LoEj and Start Ignored
+         * 0            0               0               Stop the medium
+         * 0            0               1               Make the medium ready
+         * 0            1               0               Unload the medium
+         * 0            1               1               Load the medium
+         *
+         */
+        // XXX TODO 
+        // this is from storageproto.c, shouldn't we implement something?
+        
+        if (command->Start && command->LoEj) 
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD_IN_CDB, msc->lba, USB_MSC_FAILED);
+
+        return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+/*! msc_scsi_verify - process a verify command
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_verify(struct msc_private *msc, char *name, int op)
+{
+        SCSI_VERIFY_COMMAND *command = (SCSI_VERIFY_COMMAND *)&msc->command.CBWCB; 
+
+        /*
+         * C.f. RBC 5.7 VERIFY command
+         */
+        // XXX This actually should use the read_10 function and when
+        // finished reading simply send the following
+        return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+
+/*! msc_scsi_mode_select - process a select command
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_mode_select(struct msc_private *msc, char *name, int op)
+{
+        //SCSI_MODE_SELECT_COMMAND *command = (SCSI_MODE_SELECT_COMMAND *)&msc->command.CBWCB; 
+       
+        /*
+         * C.f. SPC2 7.6 MODE SELECT(6) command
+         */
+
+        // if less than correct amount of data return USB_MSC_PHASE_ERROR - see MV
+        //
+        return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+/*! msc_private_pcs - process a private command
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_cmd_private_pcs(struct msc_private *msc, char *name, int op)
+{
+        return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
+}
+
+/*! msc_cmd_unknown - process an unknown command
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_cmd_unknown(struct msc_private *msc, char *name, int op)
+{
+        return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
+}
+
+struct rbc_dispatch {
+        u8      op;
+        char    *name;
+        int     (*rbc_command) (struct msc_private *, char *, int op);
+        int     device_check;
+};
+
+/*! Command cross reference 
+ *
+ * This is the list of commands observed from each host OS. It is necessarily
+ * incomplete in that we not have reached some condition necessary to have
+ * other commands used.
+ *                                      Win2k   WinXP
+ * SCSI_TEST_UNIT_READY                 yes     yes
+ * SCSI_READ_10                         yes     yes
+ * SCSI_WRITE_10                        yes     yes
+ * SCSI_READ_CAPACITY                   yes     yes
+ * SCSI_VERIFY                          yes
+ * SCSI_INQUIRY                         yes     yes
+ * SCSI_MODE_SENSE                      yes
+ * SCSI_READ_FORMAT_CAPACITY            yes     yes
+ * SCSI_REQUEST_SENSE                   
+ * SCSI_PREVENT_ALLOW_MEDIA_REMOVAL    
+ * SCSI_START_STOP                      
+ * SCSI_MODE_SELECT                     
+ * SCSI_FORMAT_UNIT                     
+ *
+ */
+
+struct rbc_dispatch rbc_dispatch_table[] = {
+        { SCSI_TEST_UNIT_READY,         "SCSI_TEST_UNIT_READY",         msc_scsi_test_unit_ready,               NOZLP },    
+        { SCSI_READ_10,                 "SCSI_READ_10",                 msc_scsi_read_10,                       SENDZLP },
+        { SCSI_WRITE_10,                "SCSI_WRITE_10",                msc_scsi_write_10,                      NOZLP },
+        { SCSI_READ_CAPACITY,           "SCSI_READ_CAPACITY",           msc_scsi_read_capacity,                 SENDZLP },
+        { SCSI_VERIFY,                  "SCSI_VERIFY",                  msc_scsi_verify,                        NOCHK },
+        { SCSI_INQUIRY,                 "SCSI_INQUIRY",                 msc_scsi_inquiry,                       NOCHK },
+        { SCSI_MODE_SENSE,              "SCSI_MODE_SENSE",              msc_scsi_mode_sense,                    NOCHK },
+        { SCSI_READ_FORMAT_CAPACITY,    "SCSI_READ_FORMAT_CAPACITY",    msc_scsi_read_format_capacity,          SENDZLP },
+        { SCSI_REQUEST_SENSE,           "SCSI_REQUEST_SENSE",           msc_scsi_request_sense,                 NOCHK },
+        { SCSI_PREVENT_ALLOW_MEDIA_REMOVAL, "SCSI_PREVENT_ALLOW_MEDIA_REMOVAL", msc_scsi_prevent_allow,         NOZLP }, 
+        { SCSI_START_STOP,              "SCSI_START_STOP",              msc_scsi_start_stop,                    NOZLP },
+        { SCSI_MODE_SELECT,             "SCSI_MODE_SELECT",             msc_scsi_mode_select,                   NOCHK },
+        { SCSI_FORMAT_UNIT,             "SCSI_FORMAT_UNIT",             msc_cmd_unknown,                        NOCHK },
+
+        { SCSI_READ_6,                  "SCSI_READ_6",                  msc_cmd_unknown,                        NOCHK },
+        { SCSI_WRITE_6,                 "SCSI_WRITE_6",                 msc_cmd_unknown,                        NOCHK },
+        { SCSI_RESERVE,                 "SCSI_RESERVE",                 msc_cmd_unknown,                        NOCHK },
+        { SCSI_RELEASE,                 "SCSI_RELEASE",                 msc_cmd_unknown,                        NOCHK },
+        { SCSI_SEND_DIAGNOSTIC,         "SCSI_SEND_DIAGNOSTIC",         msc_cmd_unknown,                        NOCHK },
+        { SCSI_SYNCHRONIZE_CACHE,       "SCSI_SYNCHRONIZE_CACHE",       msc_cmd_unknown,                        NOCHK },
+        { SCSI_MODE_SENSE_10,           "SCSI_MODE_SENSE_10",           msc_cmd_unknown,                        NOCHK },
+        { SCSI_REZERO_UNIT,             "SCSI_REZERO_UNIT",             msc_cmd_unknown,                        NOCHK },
+        { SCSI_SEEK_10,                 "SCSI_SEEK_10",                 msc_cmd_unknown,                        NOCHK },
+        { SCSI_WRITE_AND_VERIFY,        "SCSI_WRITE_AND_VERIFY",        msc_cmd_unknown,                        NOCHK },
+        { SCSI_WRITE_12,                "SCSI_WRITE_12",                msc_cmd_unknown,                        NOCHK },
+        { SCSI_READ_12,                 "SCSI_READ_12",                 msc_cmd_unknown,                        NOCHK },
+
+        { SCSI_PRIVATE_PCS,             "SCSI_PRIVATE_PCS",             msc_cmd_private_pcs,                    NOCHK },
+
+        { 0xff,                         "SCSI_UNKNOWN",                 msc_cmd_unknown,                        NOCHK },
+};
+
+
+/*! msc_recv_command - process a new CBW
+ *
+ * Return non-zero if urb was not disposed of.
+ */
+void msc_recv_command(struct usbd_urb *urb, struct msc_private *msc)
+{
+        COMMAND_BLOCK_WRAPPER *command = (COMMAND_BLOCK_WRAPPER *)urb->buffer;
+        u8 op = command->CBWCB[0];
+        struct rbc_dispatch *dispatch;
+
+        /*
+         * c.f. section 6.2 - Valid and Meaningful CBW
+         * c.f. section 6.2.1 - Valid CBW
+         *
+         * The CBW was received after the device had sent a CSW or after a
+         * reset XXX check that we only set MSC_READY after reset or sending
+         * CSW.
+         *
+         * The CBW is 31 (1Fh) bytes in length and the bCBWSignature is
+         * equal to 43425355h.
+         */
+        THROW_IF(31 != urb->actual_length, error);
+        THROW_IF(CBW_SIGNATURE != le32_to_cpu(command->dCBWSignature), error);
+        
+        /*
+         * c.f. section 6.2.2 - Meaningful CBW
+         *
+         * no reserved bits are set
+         * the bCBWLUN contains a valid LUN supported by the device
+         * both bCBWCBlength and the content of the CBWCB are in accordance with bInterfaceSubClass
+         */
+
+        // XXX checklun etc
+
+        /* 
+         * Success 
+         */
+        memcpy(&msc->command, command, sizeof(COMMAND_BLOCK_WRAPPER));
+        msc->data_transferred_in_bytes = msc->TransferLength_in_blocks = msc->TransferLength_in_bytes = 0;
+
+        TRACE_TAG(command->dCBWTag, urb->framenum);
+        usbd_free_urb(urb);
+        urb = NULL;
+
+        /*
+         * Search using the opcode to find the dispatch function to use and
+         * call it.
+         */
+        for (dispatch = rbc_dispatch_table; dispatch->op != 0xff; dispatch++) {
+                CONTINUE_UNLESS ((dispatch->op == op));
+
+                TRACE_CBW(dispatch->name, dispatch->op, dispatch->device_check);
+                TRACE_RECV(&(command->CBWCB[1]));
+
+                /* Depending on the command we may need to check if the device is available
+                 * and either fail or send a ZLP if it is not
+                 */
+                if (dispatch->device_check) 
+                        RETURN_IF (msc_check_blockdev_name(msc, dispatch->device_check, dispatch->name));  
+
+                /* Call the specific function that implements the specified command
+                 */
+                if (dispatch->rbc_command(msc, dispatch->name, op)) 
+                        TRACE_MSG0(MSC,"COMMAND ERROR");
+                return;
+        }
+
+        /* FALL THROUGH if no match is found */
+
+        CATCH(error) {
+                TRACE_MSG0(MSC,"RECV CBW ERROR");
+                if (urb)
+                        usbd_free_urb(urb);
+
+                /* XXX which of these do we stall?
+                 */
+                usbd_halt_endpoint(urb->function_instance, BULK_IN);
+                usbd_halt_endpoint(urb->function_instance, BULK_OUT);
+        }
+        msc_cmd_unknown(msc, "CMD_UNKNOWN", op);
+}
+
+
+/* Sent Function - process a sent urb ********************************************************** */
+
+/*! msc_urb_sent - called to indicate URB transmit finished
+ * @param tx_urb: pointer to struct usbd_urb
+ * @param rc: result
+ *
+ * This is called when an urb is sent. Depending on current state
+ * it may:
+ *
+ *      - continue sending data
+ *      - send a CSW
+ *      - start a recv for a CBW
+ *
+ * This is called from BOTTOM HALF context.
+ *
+ * @return non-zero if urb was not disposed of.
+ */
+int msc_urb_sent (struct usbd_urb *tx_urb, int rc)
+{
+        struct usbd_function_instance *function;
+        struct msc_private *msc = &msc_private;
+
+        RETURN_EINVAL_IF(!(function = tx_urb->function_instance));
+        RETURN_EINVAL_IF(usbd_get_device_status(function) == USBD_CLOSING);
+        RETURN_EINVAL_IF(usbd_get_device_state(function) != STATE_CONFIGURED);
+
+        switch (msc->command_state) {
+        case MSC_DATA_IN_READ:
+        case MSC_DATA_IN_READ_FINISHED:
+                TRACE_MSG0(MSC,"URB SENT READ");
+                return msc_in_read_10_urb_sent(tx_urb, msc);
+
+        case MSC_QUERY:
+                // finished, send CSW
+                TRACE_MSG0(MSC,"URB SENT QUERY");
+                msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+                break;
+
+        case MSC_STATUS:
+        default:
+                // sent a CSW need to receive the next CBW
+                TRACE_MSG0(MSC,"URB SENT STATUS");
+                msc->command_state = MSC_READY;
+                msc_start_recv_urb(msc->function, msc, sizeof(COMMAND_BLOCK_WRAPPER));
+                break;
+        }
+        usbd_free_urb (tx_urb);
+        return 0;
+}
+
+
+/* Receive Function - receiving an urb ********************************************************* */
+
+/*! msc_recv_urb - process a received urb
+ *
+ * Return non-zero if urb was not disposed of.
+ */
+static int msc_recv_urb (struct usbd_urb *rcv_urb, int rc)
+{
+        struct msc_private *msc = &msc_private;
+
+        RETURN_EINVAL_IF(!msc->connected);
+
+        //TRACE_MSG2(MSC, "RECV URB length: %d state: %d", rcv_urb->actual_length, msc->command_state);
+
+        switch(msc->command_state) {
+
+                // ready to start a new transaction
+        case MSC_READY:
+                msc_recv_command(rcv_urb, msc);
+                return 0;
+
+                // we think we are receiving data
+        case MSC_DATA_OUT_WRITE:
+        case MSC_DATA_OUT_WRITE_FINISHED:
+                msc_recv_out_blocks(rcv_urb, msc);
+                return 0;
+
+                // we think we are sending data
+        case MSC_DATA_IN_READ:
+        case MSC_DATA_IN_READ_FINISHED:
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
+                break;
+
+                // we think we are sending status
+        case MSC_STATUS:
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
+                break;
+
+                // we don't think
+        case MSC_UNKNOWN:
+        default:
+                TRACE_MSG0(MSC,"RECV URB ERROR");
+                usbd_halt_endpoint(rcv_urb->function_instance, BULK_OUT);
+        }
+        // let caller dispose of urb
+        return -EINVAL;
+}
+
+/* USB Device Functions ************************************************************************ */
+
+
+static void msc_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
+{
+        TRACE_MSG0(MSC,"--");
+}
+
+static void msc_set_configuration (struct usbd_function_instance *function, int wValue)
+{
+        TRACE_MSG1(MSC,"wValue: %02x", wValue);
+
+}
+
+static void msc_set_interface (struct usbd_function_instance *function, int wIndex, int wValue)
+{
+        TRACE_MSG2(MSC,"wIndex: %02x wValue: %02x", wIndex, wValue);
+
+}
+
+static void msc_endpoint_cleared (struct usbd_function_instance *function, int bEndpointAddress)
+{
+        TRACE_MSG1(MSC,"bEndpointAddress: %02x", bEndpointAddress);
+
+}
+
+/* USB Device Functions ************************************************************************ */
+/*! msc_event_handler - process a device event
+ *
+ * This function is called when an USBD event occurs.
+ *
+ * This is called from INTERRUPT context.
+ */
+void msc_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
+{
+        unsigned long flags;
+        struct msc_private *msc = &msc_private;
+        int connected;
+        switch (event) {
+        case DEVICE_CONFIGURED:
+                TRACE_MSG0(MSC,"EVENT CONFIGURED");
+                msc->connected = 1;
+                msc->command_state = MSC_READY;
+                msc_start_recv_urb(function, msc, sizeof(COMMAND_BLOCK_WRAPPER));
+                #if 0
+                local_irq_save(flags);
+                if (msc->io_state & MSC_IOCTL_WAITING) {
+                        msc->io_state &= ~MSC_IOCTL_WAITING;
+                        TRACE_MSG0(MSC, "WAKEUP");
+                }
+                local_irq_restore(flags);
+                #endif
+                wake_up_interruptible(&msc->ioctl_wq);
+                break;
+
+        case DEVICE_BUS_INACTIVE:
+        case DEVICE_RESET:
+        case DEVICE_DE_CONFIGURED:
+                TRACE_MSG2(MSC,"EVENT RESET: connected %d msc->io_state", msc->connected, msc->io_state);
+                connected = msc->connected;
+                msc->connected = 0;
+                #if 0
+                local_irq_save(flags);
+                if (msc->io_state & MSC_IOCTL_WAITING) {
+                        msc->io_state &= ~MSC_IOCTL_WAITING;
+                        TRACE_MSG0(MSC, "WAKEUP");
+                        wake_up_interruptible(&msc->ioctl_wq);
+                }
+                local_irq_restore(flags);
+                #endif
+                wake_up_interruptible(&msc->ioctl_wq);
+                BREAK_UNLESS(connected);
+
+                // XXX we should have a semaphore to protect this 
+                BREAK_UNLESS (msc->rcv_urb_finished);
+                usbd_free_urb (msc->rcv_urb_finished);
+                msc->rcv_urb_finished = NULL;
+                break;
+
+        default: 
+                TRACE_MSG0(MSC,"EVENT IGNORED");
+                break;
+        }
+}
+
+/*! msc_device_request - called to indicate urb has been received
+ *
+ * This function is called when a SETUP packet has been received that
+ * should be handled by the function driver. It will not be called to
+ * process the standard chapter nine defined requests.
+ *
+ * Return non-zero for failure.
+ */
+int msc_device_handler (struct usbd_function_instance *function, struct usbd_device_request *request)
+{
+        struct msc_private *msc = &msc_private;
+        struct usbd_urb *urb;
+
+        TRACE_MSG0(MSC,"RECV SETUP");
+
+        // verify that this is a usb class request per cdc-acm specification or a vendor request.
+        RETURN_ZERO_IF (!(request->bmRequestType & (USB_REQ_TYPE_CLASS | USB_REQ_TYPE_VENDOR)));
+       
+        // determine the request direction and process accordingly
+        switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
+
+        case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_CLASS:
+                switch (request->bRequest) {
+                case MSC_BULKONLY_RESET:
+                        // XXX TODO FIXME
+                        return 0;
+                }
+
+        case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_CLASS:
+                switch (request->bRequest) {
+                case MSC_BULKONLY_GETMAXLUN: 
+                        RETURN_EINVAL_IF(!(urb = usbd_alloc_urb_ep0(function, 1, NULL)));
+                        urb->buffer[0] = 0;
+                        urb->actual_length = 1;
+                        RETURN_ZERO_IF(!usbd_start_in_urb(urb));
+                        usbd_free_urb(urb);
+                        return -EINVAL;
+                }
+        default: 
+                break;
+        }
+        return -EINVAL;
+}
+
+/*! msc_function_enable - this is called by the USBD core layer 
+ *
+ * This is called to initialize the function when a bus interface driver
+ * is loaded.
+ */
+static int msc_function_enable (struct usbd_function_instance *function)
+{
+        struct msc_private *msc = &msc_private;
+
+        MOD_INC_USE_COUNT;
+
+        // XXX TODO need to verify that serial number is minimum of 12 
+        
+        msc->function = function;
+        msc->command_state = MSC_READY;
+
+        return 0;
+}
+
+/*! msc_function_disable - this is called by the USBD core layer 
+ *
+ * This is called to close the function when a bus interface driver
+ * is unloaded.
+ */
+static void msc_function_disable (struct usbd_function_instance *function)
+{               
+        struct msc_private *msc = &msc_private;
+
+        TRACE_MSG0(MSC,"FUNCTION EXIT");
+
+        msc->function = NULL;
+
+        MOD_DEC_USE_COUNT;
+}
+
+/* ********************************************************************************************* */
+struct usbd_function_operations msc_function_ops = {
+        event_handler: msc_event_handler,
+        device_request: msc_device_request,
+        function_enable: msc_function_enable,
+        function_disable: msc_function_disable,
+        endpoint_cleared: msc_device_request,
+        endpoint_cleared: msc_set_configuration,
+        endpoint_cleared: msc_set_interface,
+        endpoint_cleared: msc_endpoint_cleared,
+};
+
+/* ********************************************************************************************* */
diff -uNr linux/drivers/no-otg/functions/msc/msc-fd.h linux/drivers/otg/functions/msc/msc-fd.h
--- linux/drivers/no-otg/functions/msc/msc-fd.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/msc-fd.h	2006-09-01 21:41:27.000000000 +0200
@@ -0,0 +1,64 @@
+/*
+ * otg/msc_fd/msc.h - Mass Storage Class
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+#ifndef MSC_FD_H
+#define MSC_FD_H 1
+
+extern int msc_dispatch_query_urb(struct usbd_urb *urb, struct msc_private *msc, int length, int status);
+extern int msc_start_sending_csw(struct usbd_function_instance *function, struct msc_private *msc, u8 status);
+extern int msc_dispatch_query_urb_zlp(struct msc_private *msc, u32 sensedata, u32 info, int status);
+extern int msc_start_sending_csw_failed(struct msc_private *msc, u32 sensedata, u32 info, int status);
+extern int msc_start_recv_urb(struct usbd_function_instance *function, struct msc_private *msc, int size);
+
+#define NOCHK 0
+#define NOZLP 1
+#define SENDZLP 2
+
+#if 1
+static __inline__ void TRACE_SENSE(unsigned int sense, unsigned int info)
+{
+        TRACE_MSG2(MSC, "-->             SENSE: %06x INFO: %08x", sense, info);
+}
+static __inline__ void TRACE_RLBA(unsigned int lba, unsigned int crc)
+{
+        TRACE_MSG2(MSC, "<--             rlba [%8x %08x]", lba, crc);
+}
+static __inline__ void TRACE_SLBA(unsigned int lba, unsigned int crc)
+{
+        TRACE_MSG2(MSC, "-->             slba [%8x %08x]", lba, crc);
+}
+static __inline__ void TRACE_TLBA(unsigned int lba, unsigned int crc)
+{
+        TRACE_MSG2(MSC, "-->             tlba [%8x %08x]", lba, crc);
+}
+static __inline__ void TRACE_TAG(unsigned int tag, unsigned int frame)
+{
+        TRACE_MSG2(MSC, "-->             TAG: %8x FRAME: %03x", tag, frame);
+}
+static __inline__ void TRACE_CBW(char *msg, int val, int check)
+{
+        TRACE_MSG3(MSC,  " -->            %s %02x check: %d", msg, val, check);
+}
+static __inline__ void TRACE_RECV(unsigned char *cp)
+{
+        TRACE_MSG8(MSC, "<--             recv [%02x %02x %02x %02x %02x %02x %02x %02x]",
+                        cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+}
+static __inline__ void TRACE_SENT(unsigned char *cp)
+{
+        TRACE_MSG8(MSC, "-->             sent [%02x %02x %02x %02x %02x %02x %02x %02x]",
+                        cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+}
+
+#endif
+
+
+#endif /* MSC_H */
diff -uNr linux/drivers/no-otg/functions/msc/msc-io-l24.c linux/drivers/otg/functions/msc/msc-io-l24.c
--- linux/drivers/no-otg/functions/msc/msc-io-l24.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/msc-io-l24.c	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,272 @@
+/*
+ * otg/function/msc/msc-io-l24.c - MSC IO
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/functions/msc/msc-io-l24.c
+ * @brief 
+ *
+ * NOTES
+ *
+ * TODO
+ *
+ * 1. implement prevent removal command.
+ *
+ * @ingroup MSCFunction
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include "msc-scsi.h"
+#include "msc.h"
+#include "msc-fd.h"
+#include "crc.h"
+#include "msc-io.h"
+
+extern void msc_open_blockdev (struct msc_private *msc);
+extern void msc_close_blockdev (struct msc_private *msc);
+extern int msc_connection_blockdev (struct msc_private *msc); 
+extern struct msc_private msc_private;
+
+#define DEVICE_EJECTED	0x0001		//MEDIA_EJECTED
+#define DEVICE_INSERTED	0x0002		//MEDIA_INSERT
+#define DEVICE_MOUNTED  0x0001		//DEVICE_MOUNTED
+#define DEVICE_UNMOUNTED 0x0002		//DEVICE_UNMOUNTED
+
+extern u32 major;
+extern u32 minor;
+#if 0
+void msc_io_wait(struct msc_private *msc, u32 flag)
+{
+	unsigned long flags;
+        msc->io_state |= MSC_IOCTL_WAITING | flag;
+        TRACE_MSG1(MSC, "SLEEPING io_state: %x", msc->io_state);
+        interruptible_sleep_on(&msc->ioctl_wq);
+}
+
+void msc_io_wakup(struct msc_private *msc)
+{
+	unsigned long flags;
+        local_irq_save(flags);
+        if (msc->io_state & MSC_IOCTL_WAITING) {
+                msc->io_state &= ~MSC_IOCTL_WAITING;
+                TRACE_MSG0(MSC, "WAKEUP");
+                wake_up_interruptible(&msc->ioctl_wq);
+        }
+        local_irq_restore(flags);
+}
+#endif
+/*! msc_io_ioctl_internal
+ */
+int msc_io_ioctl_internal(unsigned int cmd, unsigned long arg)
+{
+        int i;
+        int len;
+        int flag;
+
+        static char func_buf[32];
+        struct otgmsc_mount mount;
+	struct msc_private *msc = &msc_private;
+	unsigned long flags;
+
+        TRACE_MSG2(MSC, "cmd: %d connect: %d", cmd, msc->connected);
+        memset(&mount, 0, sizeof(mount));
+        switch (cmd) {
+
+                /* Mount - make the specified major/minof device available for use
+                 * by the USB Host, this does not require an active connection.
+                 */
+	case OTGMSC_START:
+		TRACE_MSG0(MSC, "Mounting the device");
+		RETURN_EINVAL_IF(copy_from_user(&mount, (void *)arg, _IOC_SIZE(cmd)));
+                
+		TRACE_MSG3(MSC, "major=%d minor=%d state=%d", mount.major, mount.minor, msc->block_dev_state);
+		major = mount.major;
+		minor = mount.minor;
+		
+		//msc->io_state = MSC_INACTIVE;
+		msc_open_blockdev (msc);
+                RETURN_EAGAIN_UNLESS(msc->command_state == MSC_READY);
+
+		mount.status = (msc->block_dev_state == DEVICE_INSERTED) ? DEVICE_MOUNTED : DEVICE_UNMOUNTED;
+
+		TRACE_MSG1(MSC, "Device is mounted status: %d", mount.status);
+
+                // XXX Need to copy result back to user space
+                RETURN_EINVAL_IF (copy_to_user((void *)arg, &mount, sizeof(mount)));
+		TRACE_MSG0(MSC,  "Device mounted");
+		return 0; 
+
+                /* Umount - make the currently mounted device unavailable to the USB Host,
+                 * if there is pending block i/o block until it has finished.
+                 * Note that if the driver is unloaded the waiting ioctl process 
+                 * must be woken up and informed with error code.
+                 */
+	case OTGMSC_STOP:
+
+		TRACE_MSG0(MSC,  "Unmounting the device");
+                
+		RETURN_EINVAL_IF (copy_from_user (&mount, (void *)arg, _IOC_SIZE(cmd)));
+
+                if (msc->command_state != MSC_READY) {
+                        TRACE_MSG0(MSC, "SLEEPING");
+                        interruptible_sleep_on(&msc->ioctl_wq);
+                        TRACE_MSG0(MSC, "AWAKE");
+                }
+
+                RETURN_EAGAIN_UNLESS(msc->command_state == MSC_INACTIVE);
+
+                // XXX Need to copy result back to user space
+		msc->major = mount.major;
+		msc->minor = mount.minor;
+		msc_close_blockdev(msc);
+		mount.status = DEVICE_UNMOUNTED;
+                RETURN_EINVAL_IF (copy_to_user((void *)arg, &mount, sizeof(mount)));
+		TRACE_MSG0(MSC,  "Device unmounted");
+		return 0;
+
+
+                /* Status - return the current mount status.
+                 */
+        case OTGMSC_STATUS:
+		TRACE_MSG0(MSC, "Mount status");
+                RETURN_EINVAL_IF (copy_from_user (&mount, (void *)arg, _IOC_SIZE(cmd)));
+		if (msc->block_dev_state == DEVICE_EJECTED)
+			mount.status = DEVICE_UNMOUNTED;
+		else
+			mount.status = DEVICE_MOUNTED;
+
+                // XXX Need to copy result back to user space
+                RETURN_EINVAL_IF (copy_to_user((void *)arg, &mount, sizeof(mount)));
+		return 0;
+                
+                /* Wait_Connect - if not already connected wait until connected,
+                 * Note that if the driver is unloaded the waiting ioctl process 
+                 * must be woken up and informed with error code.
+                 */
+        case OTGMSC_WAIT_CONNECT:
+		TRACE_MSG1(MSC, "Wait for connect: connected: %d", msc->connected);
+                local_irq_save(flags);
+
+                if (msc->connected == 0) {
+                        TRACE_MSG0(MSC, "SLEEPING");
+			interruptible_sleep_on (&msc->ioctl_wq);
+                        TRACE_MSG0(MSC, "AWAKE");
+                }
+                RETURN_EAGAIN_UNLESS(msc->connected);
+
+		RETURN_EINVAL_IF (copy_from_user (&mount, (void *)arg, _IOC_SIZE(cmd)));
+		RETURN_EINVAL_IF (copy_to_user((void *)arg, &mount, sizeof(mount)));
+		TRACE_MSG0(MSC,  "Device connected");
+		return 0;
+                
+                /* Wait_DisConnect - if not already disconnected wait until disconnected,
+                 * Note that if the driver is unloaded the waiting ioctl process 
+                 * must be woken up and informed with error code.
+                 */
+        case OTGMSC_WAIT_DISCONNECT:
+		TRACE_MSG1(MSC, "Wait for disconnect: connected: %d", msc->connected);
+
+                if (msc->connected == 1) {
+                        TRACE_MSG0(MSC, "SLEEPING");
+			interruptible_sleep_on (&msc->ioctl_wq);
+                        TRACE_MSG0(MSC, "AWAKE");
+                }
+                RETURN_EAGAIN_IF(msc->connected);
+		RETURN_EINVAL_IF (copy_from_user (&mount, (void *)arg, _IOC_SIZE(cmd)));
+		RETURN_EINVAL_IF (copy_to_user((void *)arg, &mount, sizeof(mount)));
+		TRACE_MSG0(MSC,  "Device disconnected");
+		return 0; 
+                
+        default:
+		TRACE_MSG1(MSC,  "Unknown command: %x", cmd);
+		TRACE_MSG1(MSC,  "OTGMSC_START: %x", OTGMSC_START);
+		TRACE_MSG1(MSC,  "OTGMSC_WRITEPROTECT: %x", OTGMSC_WRITEPROTECT);
+		TRACE_MSG1(MSC,  "OTGMSC_STOP: %x", OTGMSC_STOP);
+		TRACE_MSG1(MSC,  "OTGMSC_STATUS: %x", OTGMSC_STATUS);
+		TRACE_MSG1(MSC,  "OTGMSC_WAIT_CONNECT: %x", OTGMSC_WAIT_CONNECT);
+		TRACE_MSG1(MSC,  "OTGMSC_WAIT_DISCONNECT: %x", OTGMSC_WAIT_DISCONNECT);
+                return -EINVAL;
+        }
+        return 0;
+}
+
+
+
+/*! msc_io_ioctl
+ */
+int msc_io_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+        int i;
+        int len;
+        int flag;
+
+        //printk(KERN_INFO"%s: cmd: %08x arg: %08x\n", __FUNCTION__, cmd, arg);
+        TRACE_MSG6(MSC, "cmd: %08x arg: %08x type: %02d nr: %02d dir: %02d size: %02d", 
+                        cmd, arg, _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_DIR(cmd), _IOC_SIZE(cmd));
+        
+        RETURN_EINVAL_UNLESS (_IOC_TYPE(cmd) == OTGMSC_MAGIC);
+        RETURN_EINVAL_UNLESS (_IOC_NR(cmd) <= OTGMSC_MAXNR);
+
+        RETURN_EFAULT_IF((_IOC_DIR(cmd) == _IOC_READ) && !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)));
+        RETURN_EFAULT_IF((_IOC_DIR(cmd) == _IOC_WRITE) && !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)));
+
+        return msc_io_ioctl_internal(cmd, arg);
+}
+
+
+
+int msc_io_proc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+        return msc_io_ioctl(inode, filp, cmd, arg);
+}
+
+
+static struct file_operations msc_io_proc_switch_functions = {
+        ioctl:msc_io_proc_ioctl,
+};
+
+
+/* msc_io_init_l24 - initialize
+ */
+int msc_io_init_l24(void)
+{
+        struct proc_dir_entry *message = NULL;
+
+        THROW_IF (!(message = create_proc_entry ("msc_io", 0666, 0)), error);
+        message->proc_fops = &msc_io_proc_switch_functions;
+        CATCH(error) {
+                printk(KERN_ERR"%s: creating /proc/msc_io failed\n", __FUNCTION__);
+                if (message)
+                        remove_proc_entry("msc_io", NULL);
+                return -EINVAL;
+        }
+        return 0;
+}
+
+/* msc_io_exit_l24 - exit
+ */
+void msc_io_exit_l24(void)
+{
+        remove_proc_entry("msc_io", NULL);
+}
+
+
+
diff -uNr linux/drivers/no-otg/functions/msc/msc-io.h linux/drivers/otg/functions/msc/msc-io.h
--- linux/drivers/no-otg/functions/msc/msc-io.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/msc-io.h	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,57 @@
+/*
+ * otg/functions/msc/msc-io.h - Mass Storage Class
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/functions/msc/msc-io.h
+ * @brief Mass Storage Driver private defines
+ *
+ * OTGMSC_START                 - make specified major/minor device available to USB Host
+ * OTGMSC_WRITEPROTECT          - set or reset write protect flag
+ *
+ * OTGMSC_STOP                  - remove access to current device, block until pending I/O finished
+ * OTGMSC_STATUS                - remove current USB connection status (connected or disconnected)
+ * OTGMSC_WAIT_CONNECT          - wait until device is connected (may return immediately if already connected)
+ * OTGMSC_WAIT_DISCONNECT       - wait until device is disconnected (may return immediately if already disconnected)
+ *
+ * @ingroup MSCFunction
+ */
+
+//#ifndef MSC_H
+//#define MSC_H 1
+
+#define MSC_IO "/proc/msc_io"
+
+struct otgmsc_mount {
+        int     major;
+        int     minor;
+        int     lun;
+        int     writeprotect;
+        int     result;
+        int     status;
+};
+
+#define OTGMSC_MAGIC    'M'
+#define OTGMSC_MAXNR	10
+
+#define OTGMSC_START            _IOWR(OTGMSC_MAGIC, 1, struct otgmsc_mount)
+#define OTGMSC_WRITEPROTECT     _IOWR(OTGMSC_MAGIC, 2, struct otgmsc_mount)
+
+#define OTGMSC_STOP             _IOR(OTGMSC_MAGIC, 1, struct otgmsc_mount)
+#define OTGMSC_STATUS           _IOR(OTGMSC_MAGIC, 2, struct otgmsc_mount)
+#define OTGMSC_WAIT_CONNECT     _IOR(OTGMSC_MAGIC, 3, struct otgmsc_mount)
+#define OTGMSC_WAIT_DISCONNECT  _IOR(OTGMSC_MAGIC, 4, struct otgmsc_mount)
+
+
+#define MSC_CONNECTED           0x01
+#define MSC_DISCONNECTED        0x02
+#define MSC_WRITEPROTECTED      0x04
+
+//#endif /* MSC_H */
+
diff -uNr linux/drivers/no-otg/functions/msc/msc-linux.c linux/drivers/otg/functions/msc/msc-linux.c
--- linux/drivers/no-otg/functions/msc/msc-linux.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/msc-linux.c	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,935 @@
+/*
+ * otg/function/msc/msc-linux.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ */
+
+/*!
+ * @file otg/functions/msc/msc-linux.c
+ * @brief Mass Storage Driver private defines
+ *
+ *
+ * This is a Mass Storage Class Function that uses the Bulk Only protocol.
+ *
+ * To use simply load with something like:
+ *
+ *      insmod msc_fd.o vendor_id=0xffff product_id=0xffff
+ *
+ * Notes:
+ *
+ * 1. Currently block I/O is done a page at a time. I have not determined if
+ * it is possible to dispatch a multiple page generic request. It should at
+ * least be possible to queue page requests. 
+ *
+ * 2. Currently for READ operations we have a maximum of one outstanding
+ * read block I/O and send urb. These are allowed to overlap so that we can
+ * continue to read data while sending data to the host.
+ *
+ * 3. Currently for WRITE operations we have a maximum of one outstanding
+ * recv urb and one outstanding write block I/O. These are allowed to
+ * overlap so that we can continue to receive data from the host while
+ * waiting for writing to complete.
+ *
+ * 4. It would be possible to allow multiple writes to be pending, to the
+ * limit of the page cache, if desired. 
+ *
+ * 5. It should be possible to allow multiple outstanding reads to be
+ * pending, to the limit of the page cache, but this potentially could
+ * require dealing with out of order completions of the reads. Essentially a
+ * list of completed buffer heads would be required to hold any completed
+ * buffer heads that cannot be sent prior to another, earlier request being
+ * completed. 
+ *
+ * 6. Currently ioctl calls are available to start and stop device i/o.
+ *
+ * 7. The driver can optionally generate trace messages showing each sectors 
+ * CRC as read or written with LBA. These can be compared by user programs to
+ * ensure that the correct data was read and/or written.
+ *
+ * 
+ * TODO
+ *
+ * 1. error handling for block io, e.g. what if using with removable block
+ * device (like CF card) and it is removed.
+ *
+ * 2. Currently we memcpy() data from between the urb buffer and buffer
+ * head page. It should be possible to simply use the page buffer for the
+ * urb.
+ *
+ * 3. Should we offer using fileio as an option? This would allow direct access
+ * to a block device image stored in a normal file or direct access to (for example)
+ * ram disks. It would require implementing a separate file I/O kernel thread to
+ * do the actual I/O.
+ *
+ * 4. It may be interesting to support use of SCSI block device and pass the
+ * scsi commands directly to that. This would allow vendor commands for real
+ * devices to be passed through and executed with results being properly
+ * returned to the host. [This is the intended design for the mass storage
+ * specification.]
+ *
+ * 
+ * TODO FIXME Bus Interface Notes
+ *
+ *
+ * @ingroup MSCFunction
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/otg-trace.h>
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+
+#include <linux/blkdev.h>
+
+
+#include "msc-scsi.h"
+#include "msc.h"
+#include "msc-fd.h"
+#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
+#include "crc.h"
+#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
+#include "msc-io.h"
+
+
+//#include "rbc.h"
+
+
+/* Module Parameters ************************************************************************* */
+
+u32 vendor_id;
+u32 product_id;
+
+u32 major;
+u32 minor;
+
+MODULE_PARM (vendor_id, "i");
+MODULE_PARM (product_id, "i");
+MODULE_PARM (major, "i");
+MODULE_PARM (minor, "i");
+
+MODULE_PARM_DESC (vendor_id, "Device Vendor ID");
+MODULE_PARM_DESC (product_id, "Device Product ID");
+MODULE_PARM_DESC (major, "Device Major");
+MODULE_PARM_DESC (minor, "Device Minor");
+
+
+#define DEVICE_EJECTED          0x0001          // MEDIA_EJECTED
+#define DEVICE_INSERTED         0x0002          // MEDIA_INSERT
+
+#define DEVICE_OPEN             0x0004          // WR_PROTECT_OFF
+#define DEVICE_WRITE_PROTECTED  0x0008          // WR_PROTECT_ON
+
+#define DEVICE_CHANGE_ON        0x0010          // MEDIA_CHANGE_ON
+
+#define DEVICE_PREVENT_REMOVAL  0x0020
+
+
+#define DEF_NUMBER_OF_HEADS     0x10
+#define DEF_SECTORS_PER_TRACK   0x20
+
+
+DECLARE_MUTEX(msc_sem);
+
+
+/* MSC ******************************************************************************************** */
+
+struct msc_private msc_private;
+
+int msc_urb_sent (struct usbd_urb *tx_urb, int rc);
+
+
+/* Block Device ******************************************************************************** */
+
+/*! msc_open_blockdev - open the block device specified in msc->major, msc->minor
+ *
+ * Sets appropriate fields to show current status of block device.
+ *
+ * XXX TODO - this needs to be tested against RO and absent devices.
+ *
+ */
+void msc_open_blockdev(struct msc_private *msc)
+{
+        int rc;
+
+        down(&msc_sem);
+        msc->block_dev_state = DEVICE_EJECTED;
+
+        TRACE_MSG2(MSC, "OPEN BLOCKDEV: Major: %x Minor: %x", major, minor);
+
+        /*
+         * Check device information and verify access to the block device.
+         */
+        THROW_IF (!major, ejected);
+
+        msc->dev = MKDEV(major, minor);
+
+        THROW_IF (!(msc->bdev = bdget(kdev_t_to_nr(msc->dev))), ejected);
+
+        if ((rc = blkdev_get(msc->bdev, FMODE_READ | FMODE_WRITE, 0, BDEV_RAW))) {
+
+                TRACE_MSG0(MSC,"OPEN BLOCKDEV: cannot open RW");
+                THROW_IF ((rc = blkdev_get(msc->bdev, FMODE_READ, 0, BDEV_RAW)), ejected);
+                msc->block_dev_state |= DEVICE_WRITE_PROTECTED;
+        }
+
+        msc->io_state = MSC_INACTIVE;
+        msc->block_dev_state &= ~DEVICE_EJECTED;
+        msc->block_dev_state |= DEVICE_INSERTED | DEVICE_CHANGE_ON;
+
+        TRACE_MSG1(MSC,"OPEN BLOCKDEV: opened block_dev_state: %x", msc->block_dev_state);
+
+        /*
+         * Note that capacity must return the LBA of the last addressable block
+         * c.f. RBC 4.4, RBC 5.3 and notes below RBC Table 6
+         *
+         * The blk_size array contains the number of addressable blocks or N, 
+         * capacity is therefore N-1.
+         */
+         
+        msc->capacity = (blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1) - 1;
+        msc->block_size = get_hardsect_size(msc->dev);
+        msc->max_blocks = PAGE_SIZE / msc->block_size;
+
+        TRACE_MSG2(MSC,"blk_size: %x %d", 
+                        blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1,
+                        blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1); 
+
+        TRACE_MSG2(MSC,"capacity: %x %d", msc->capacity, msc->capacity); 
+        TRACE_MSG2(MSC,"block_size: %x %d", msc->block_size, msc->block_size); 
+        TRACE_MSG2(MSC,"max_blocks: %x %d", msc->max_blocks, msc->max_blocks); 
+
+        /* setup generic buffer_head
+         * XXX do we need two pages? it should be possible to have a single page
+         * for both read and write, in fact do we need a read_bh and write_bh?
+         * XXX ensure the page (or pages) get deallocated
+         */
+        msc->write_pending = msc->read_pending = 0;
+        msc->write_bh.b_rdev = msc->read_bh.b_rdev = msc->dev;
+        msc->write_bh.b_private = msc->read_bh.b_private = msc;
+        msc->read_bh.b_page = alloc_page(GFP_NOIO);     // XXX ensure that this gets de-allocated
+        msc->write_bh.b_page = alloc_page(GFP_NOIO);    // XXX ensure that this gets de-allocated
+        msc->read_bh.b_data = page_address(msc->read_bh.b_page);
+        msc->write_bh.b_data = page_address(msc->write_bh.b_page);
+
+        CATCH(ejected) {
+                TRACE_MSG1(MSC,"OPEN BLOCKDEV: EJECTED block_dev_state: %x", msc->block_dev_state);
+                printk(KERN_INFO"%s: Cannot get device %d %d\n", __FUNCTION__, major, minor); 
+        }
+        up(&msc_sem);
+}
+
+/*! msc_close_blockdev - close the device for host
+ */
+
+void msc_close_blockdev(struct msc_private *msc)
+{
+
+        RETURN_IF(msc->block_dev_state == DEVICE_EJECTED);
+
+        down(&msc_sem);
+	msc->block_dev_state = DEVICE_EJECTED;
+	if (msc->bdev)
+		blkdev_put(msc->bdev, BDEV_RAW);
+
+        // XXX this should be a wait for read_bh/write_bh to go to NULL
+        //while (msc->read_bh.b_data || msc->write_bh.b_data) {
+	while (msc->read_pending || msc->write_pending) {
+                printk(KERN_INFO"%s: sleeping on read or write bh\n", __FUNCTION__);
+                sleep_on_timeout(&msc->msc_wq, 20);
+        }
+        __free_page((void *)&msc->read_bh.b_page);
+        msc->read_bh.b_page = NULL;
+        __free_page((void *)&msc->write_bh.b_page);
+        msc->write_bh.b_page = NULL;
+        up(&msc_sem);
+}
+
+
+/* READ 10 COMMAND - read and send data to the host ******************************************** */
+
+int msc_start_reading_block_data(struct usbd_function_instance *function, struct msc_private *msc);
+void msc_block_read_finished(struct buffer_head *bh, int flag);
+
+
+/*! msc_scsi_read_10 - process a read(10) command
+ *
+ * We have received a READ(10) CBW, if transfer length is non-zero
+ * initiate a generic block i/o otherwise send a CSW.
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_read_10(struct msc_private *msc, char *name, int op)
+{
+        SCSI_READ_10_COMMAND *command = (SCSI_READ_10_COMMAND *)&msc->command.CBWCB;
+
+        /*
+         * save the CBW information and setup for transmitting data read from the block device
+         */
+        msc->lba = be32_to_cpu(command->LogicalBlockAddress);
+        msc->TransferLength_in_blocks = be16_to_cpu(command->TransferLength);
+        msc->TransferLength_in_bytes = msc->TransferLength_in_blocks * msc->block_size;
+        msc->command_state = MSC_DATA_IN_READ;
+        msc->io_state = MSC_INACTIVE;
+
+        /*
+         * Start reading blocks to send or simply send the CSW if the host
+         * didn't actually ask for a non-zero length.
+         */
+        return (msc->TransferLength_in_blocks) ?  msc_start_reading_block_data(msc->function, msc) :
+                msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+
+/*! msc_start_reading_block_data - start reading data
+ *
+ * Generate a generic block io request to read some data to transmit.
+ *
+ * This function is initially called by msc_scsi_read_10() but can also be called
+ * by msc_urb_sent() if the amount of data requested was too large.
+ *
+ * The function msc_block_read_finished() will be called to actually send the data
+ * to the host when the I/O request is complete.
+ *
+ */
+int msc_start_reading_block_data(struct usbd_function_instance *function, struct msc_private *msc)
+{
+        int TransferLength_in_blocks = MIN(msc->max_blocks, msc->TransferLength_in_blocks);
+        unsigned long flags;
+        
+        TRACE_MSG3(MSC,"START READING BLOCK DATA lba:    %x blocks: %d %d ", 
+                        msc->lba, msc->TransferLength_in_blocks, TransferLength_in_blocks); 
+
+        /* ensure that device state is ok
+         */
+        if (msc->block_dev_state != DEVICE_INSERTED) {
+                TRACE_MSG0(MSC,"START READ MEDIA NOT PRESENT");
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_MEDIA_NOT_PRESENT, msc->lba, USB_MSC_FAILED);
+        }
+
+        // XXX an ioctl has requested that pending io be aborted
+        local_irq_save(flags);
+        if (msc->io_state & MSC_ABORT_IO) {
+                msc->io_state &= ~MSC_ABORT_IO;
+                TRACE_MSG0(MSC,"BLOCK READ ABORTED"); 
+                local_irq_restore(flags);
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_UNRECOVERED_READ_ERROR, msc->lba, USB_MSC_FAILED);
+        }
+        local_irq_restore(flags);
+
+        /* sanity check lba against capacity 
+         */
+        if (msc->lba >= msc->capacity) {
+                TRACE_MSG2(MSC, "START READ LBA out of range: lba: %d capacity: %d", msc->lba, msc->capacity);
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_BLOCK_ADDRESS_OUT_OF_RANGE, msc->lba, USB_MSC_FAILED);
+        }
+
+        /* setup buffer head - msc_block_read_finished() will be called when block i/o is finished
+         */
+        msc->read_bh.b_end_io = msc_block_read_finished;
+        msc->read_bh.b_size = TransferLength_in_blocks * msc->block_size;
+        msc->read_bh.b_rsector = msc->lba;
+        msc->read_bh.b_state = (1UL << BH_Mapped) | (1UL << BH_Lock);
+        msc->io_state |= MSC_BLOCKIO_PENDING;
+	msc->read_pending=1;
+	
+        memset(msc->read_bh.b_data, 0x0, msc->read_bh.b_size);
+
+        generic_make_request(READ, &msc->read_bh);
+        generic_unplug_device(blk_get_queue(msc->read_bh.b_rdev));
+        return 0;
+}
+
+
+/*! msc_block_read_finished - called by generic request 
+ *
+ * Called when block i/o read is complete, send the data to the host if possible.
+ *
+ * The function msc_urb_sent() will be called when the data is sent to
+ * either send additional data or the CSW as appropriate.
+ *
+ * If more data is required then call msc_start_reading_block_data() to
+ * issue another block i/o to get more data.
+ *
+ * These means that there can be two outstanding actions when this
+ * function completes:
+ *
+ *      1. a transmit urb may be pending, sending the most recently
+ *         read data to the host
+ *      2. another block i/o may be pending to read additional data
+ *
+ * This leads to a race condition, if the block i/o finished before the urb
+ * transmit, then we must simply exit. The msc_in_read_10_urb_sent()
+ * function will ensure that this is restarted.
+ */
+void msc_block_read_finished(struct buffer_head *bh, int uptodate)
+{
+        //struct msc_private *msc = bh->b_private;
+        //int TransferLength_in_blocks = bh->b_size / msc->block_size;
+        
+        struct msc_private *msc;
+        int TransferLength_in_blocks;
+
+        struct usbd_function_instance *function;
+        struct usbd_urb *tx_urb;
+        unsigned long flags;
+        int rc;
+#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
+        u32 crc;
+#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
+        int i;
+
+        msc = bh->b_private;
+        TransferLength_in_blocks = bh->b_size / msc->block_size;
+
+        TRACE_MSG1(MSC,"BLOCK READ FINISHED size: %x", bh->b_size); 
+
+        #if 0
+        local_irq_save(flags);
+        if (msc->io_state & MSC_IOCTL_WAITING) {
+                wake_up_interruptible(&msc->ioctl_wq);
+                msc->io_state &= ~MSC_IOCTL_WAITING;
+        }
+        local_irq_restore(flags);
+        #endif
+
+        wake_up_interruptible(&msc->ioctl_wq);
+        
+        /*
+         * Race condition here, if we have not finished sending the
+         * previous tx_urb then we want to simply exit and let
+         * msc_in_read_10_urb_sent() call us again.
+         *
+         * Ensure that we do not reset BLOCKIO flags if SEND PENDING and
+         * that we do reset BLOCKIO if not SEND PENDING
+         */
+        {
+                unsigned long flags;
+                local_irq_save(flags);
+                if (msc->io_state & MSC_SEND_PENDING) {
+                        TRACE_MSG0(MSC,"BLOCK READ SEND PENDING");
+                        msc->io_state |= MSC_BLOCKIO_FINISHED;
+                        msc->uptodate = uptodate;
+                        local_irq_restore(flags);
+                        return;
+                }
+                msc->io_state &= ~(MSC_BLOCKIO_PENDING | MSC_BLOCKIO_FINISHED);
+
+                local_irq_restore(flags);
+        }
+
+        /* verify that the I/O completed
+         */
+        if (1 != uptodate) {
+                TRACE_MSG0(MSC,"BLOCK READ FAILED"); 
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_UNRECOVERED_READ_ERROR, msc->lba, USB_MSC_FAILED);
+                return;
+        }
+
+#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
+        /* debug output trace - dump rlba and computed crc
+         */
+        for (i = 0; i < bh->b_size / msc->block_size; i++) {
+                crc = crc32_compute(bh->b_data + (i * msc->block_size), msc->block_size, CRC32_INIT);
+                TRACE_RLBA(bh->b_rsector + i, crc);
+        }
+#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
+        /* allocate a tx_urb and copy into it
+         */
+        THROW_IF(!(function = msc->function), error);
+        THROW_IF(!(tx_urb = usbd_alloc_urb (function, BULK_IN, bh->b_size, msc_urb_sent)), error);
+        TRACE_MSG1(MSC,"BLOCK READ FINISHED urb: %p", (int)tx_urb);
+
+        tx_urb->function_privdata = msc;
+        tx_urb->actual_length = tx_urb->buffer_length = bh->b_size;
+        memcpy(tx_urb->buffer, bh->b_data, bh->b_size);
+
+	msc->read_pending=0;
+
+        {
+                unsigned long flags;
+                local_irq_save(flags);
+
+                msc->io_state |= MSC_SEND_PENDING;
+                msc->TransferLength_in_bytes -= bh->b_size;
+                msc->TransferLength_in_blocks -= TransferLength_in_blocks; 
+                msc->lba += TransferLength_in_blocks;
+
+                if (!msc->TransferLength_in_blocks) {
+                        TRACE_MSG0(MSC,"BLOCK READ FINISHED - IO FINISHED");
+                        // set flag so that CSW can be sent
+                        msc->io_state |= MSC_DATA_IN_READ_FINISHED;
+                }
+                local_irq_restore(flags);
+        }
+
+        /* dispatch urb - msc_urb_sent() will be called when urb is finished
+         */
+        if ((rc = usbd_start_in_urb (tx_urb))) {
+                TRACE_MSG0(MSC,"BLOCK READ FINISHED FAILED"); 
+                usbd_free_urb (tx_urb);
+                THROW(error);
+        }
+
+        /* if more data is required then call msc_start_reading_block_data() to
+         * issue another block i/o to get more data.
+         */
+        if (!(msc->io_state & MSC_DATA_IN_READ_FINISHED)) {
+                TRACE_MSG0(MSC,"BLOCK READ SEND RESTARTING");
+                msc_start_reading_block_data(msc->function, msc);
+        }
+
+        CATCH(error) {
+                TRACE_MSG0(MSC,"BLOCK READ FINISHED ERROR"); 
+                // stall?
+        }
+}
+
+/*! msc_in_read_10_urb_sent - called by msc_urb_sent when state is MSC_DATA_IN_READ
+ *
+ * This will process a read_10 urb that has been sent. Specifically if any previous
+ * read_10 block I/O has finished we recall the msc_block_read_finished() function
+ * to transmit another read_10 urb. 
+ *
+ * If there is no other pending read_10 to do we create and send a CSW.
+ *
+ * If there is more I/O to do or there is already an outstanding I/O we simply
+ * return after freeing the URB.
+ *
+ * Return non-zero if urb was not disposed of.
+ */
+int msc_in_read_10_urb_sent(struct usbd_urb *tx_urb, struct msc_private *msc)
+{
+        unsigned long flags;
+
+        TRACE_MSG0(MSC,"URB SENT DATA IN");
+
+        /*
+         * Potential race condition here, we may need to restart blockio.
+         */
+        local_irq_save(flags);
+
+        msc->io_state &= ~MSC_SEND_PENDING;
+        msc->data_transferred_in_bytes += tx_urb->actual_length;
+
+        TRACE_MSG1(MSC,"URB SENT DATA IN data transferred: %d", msc->data_transferred_in_bytes);
+
+        if (!tx_urb->actual_length) 
+                msc->TransferLength_in_blocks = 0;
+
+        /* XXX We should be checking urb status
+         */
+
+        usbd_free_urb (tx_urb);
+
+        /*
+         * Check to see if we need to send CSW.
+         */
+        if (MSC_DATA_IN_READ_FINISHED & msc->io_state) {
+                TRACE_MSG0(MSC,"URB SENT DATA IN - FINISHED SENDING CSW");
+                local_irq_restore(flags);
+                return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+        }
+        /*
+         * Check to see if there is a block read needs to be finished.
+         */
+        if (MSC_BLOCKIO_FINISHED & msc->io_state) {
+                TRACE_MSG0(MSC,"URB SENT DATA IN - RESTART");
+                local_irq_restore(flags);
+                // XXX uptodate?
+                msc_block_read_finished(&msc->read_bh, msc->uptodate);
+                return 0;
+        }
+        local_irq_restore(flags);
+        return 0;
+}
+
+
+/* WRITE 10 - receive data from host and write to block device ********************************* */
+
+int msc_start_receiving_data(struct usbd_function_instance *function, struct msc_private *msc);
+void msc_data_written(struct buffer_head *bh, int flag);
+void msc_data_test(struct buffer_head *bh, int flag);
+
+/*! msc_scsi_write_10 - process a write command
+ *
+ * Call either msc_start_receiving_data() or msc_start_sending_csw() as appropriate.
+ * Normally msc_start_receiving_data() is called and it will use msc_start_recv_urb() 
+ * to setup a receive urb of the appropriate size. 
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_write_10(struct msc_private *msc, char *name, int op)
+{
+        SCSI_WRITE_10_COMMAND *command = (SCSI_WRITE_10_COMMAND *)&msc->command.CBWCB;
+
+        /* save the CBW and setup for receiving data to be written to the block device
+         */
+        msc->lba = be32_to_cpu(command->LogicalBlockAddress);
+        msc->TransferLength_in_blocks = be16_to_cpu(command->TransferLength);
+        msc->TransferLength_in_bytes = msc->TransferLength_in_blocks * msc->block_size;
+
+        msc->command_state = MSC_DATA_OUT_WRITE;
+        msc->io_state = MSC_INACTIVE;
+
+        TRACE_MSG1(MSC,"RECV WRITE lba: %x", msc->lba); 
+        TRACE_MSG1(MSC,"RECV WRITE blocks: %d", msc->TransferLength_in_blocks); 
+
+        return (msc->TransferLength_in_blocks) ?
+                msc_start_receiving_data(msc->function, msc) :
+                msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+
+/*! msc_start_receiving_data - called to initiate an urb to receive WRITE(10) data
+ *
+ * Initiate a receive urb to receive upto PAGE_SIZE WRITE(10) data. The
+ * msc_recv_urb() function will call msc_recv_out_blocks() to actually
+ * write the data. 
+ *
+ * This is called from msc_scsi_write_10() to initiate the WRITE(10) and
+ * called from msc_data_written() to start the next page sized receive
+ * urb.
+ */
+int msc_start_receiving_data(struct usbd_function_instance *function, struct msc_private *msc)
+{
+        /*
+         * Calculating the length is most of the work we do :-)
+         */
+        int TransferLength_in_blocks = MIN(msc->max_blocks, msc->TransferLength_in_blocks);
+
+        TRACE_MSG1(MSC,"START RECEIVING DATA lba: %x", msc->lba); 
+        TRACE_MSG1(MSC,"START RECEIVING DATA blocks: %d", msc->TransferLength_in_blocks);
+        TRACE_MSG1(MSC,"START RECEIVING DATA blocks: %d", TransferLength_in_blocks);
+        TRACE_MSG1(MSC,"START RECEIVING DATA bytes: %d", TransferLength_in_blocks * msc->block_size);
+
+        THROW_IF(msc->command_state != MSC_DATA_OUT_WRITE, error);
+        THROW_IF(!msc->TransferLength_in_blocks, error);
+
+        msc->io_state |= MSC_RECV_PENDING;
+
+        return msc_start_recv_urb(function, msc, TransferLength_in_blocks * msc->block_size);
+
+        CATCH(error) {
+                TRACE_MSG0(MSC,"START RECEIVING DATA ERROR");
+                return -EINVAL;
+        }
+}
+
+
+/*! msc_recv_out_blocks - process received WRITE(10) data by writing to block device
+ *
+ * We get here indirectly from msc_recv_urb() when state is MSC_DATA_OUT_WRITE.
+ *
+ * Dealloc the urb and call Initiate the generic request to write the
+ * received data. The b_end_io function msc_data_written() will send the
+ * CSW.
+ *
+ */
+void msc_recv_out_blocks(struct usbd_urb *rcv_urb, struct msc_private *msc)
+{
+        int TransferLength_in_bytes = rcv_urb->actual_length;
+        int TransferLength_in_blocks = TransferLength_in_bytes / msc->block_size;
+#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
+        u32 crc;
+#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
+        int i;
+
+        TRACE_MSG1(MSC,"RECV OUT            bytes: %d", TransferLength_in_bytes);
+        TRACE_MSG1(MSC,"RECV OUT          iostate: %x", msc->io_state);
+        TRACE_MSG1(MSC,"RECV OUT data transferred: %d", msc->data_transferred_in_bytes);
+
+        /*
+         * Race condition here, we may get to here before the previous block
+         * write completed. If so just exit and the msc_data_written()
+         * function will recall us.
+         */
+        {
+                unsigned long flags;
+                local_irq_save(flags);
+                if (msc->io_state & MSC_BLOCKIO_PENDING) {
+                        TRACE_MSG0(MSC,"RECV OUT  BLOCKIO PENDING");
+                        msc->io_state |= MSC_RECV_FINISHED;
+                        msc->rcv_urb_finished = rcv_urb;
+                        local_irq_restore(flags);
+                        return;
+                }
+                msc->io_state &= ~(MSC_RECV_PENDING |MSC_RECV_FINISHED);
+                local_irq_restore(flags);
+        }
+
+        msc->data_transferred_in_bytes += rcv_urb->actual_length;
+
+#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
+        for (i = 0; i < TransferLength_in_blocks; i++) {
+                crc = crc32_compute(rcv_urb->buffer + (i * msc->block_size), msc->block_size, CRC32_INIT);
+                TRACE_SLBA(msc->lba + i, crc);
+        }
+#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
+        
+	msc->write_pending=1;
+
+        memcpy(msc->write_bh.b_data, rcv_urb->buffer, rcv_urb->actual_length);
+
+        usbd_free_urb(rcv_urb);
+
+        /* ensure media state is ok
+         */
+        if (msc->block_dev_state != DEVICE_INSERTED) {
+                TRACE_MSG0(MSC,"START READ MEDIA NOT PRESENT");
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_MEDIA_NOT_PRESENT, msc->lba, USB_MSC_FAILED);
+                return;
+        }
+
+        // XXX an ioctl has requested that pending io be aborted
+        if (msc->io_state & MSC_ABORT_IO) {
+                unsigned long flags;
+                local_irq_save(flags);
+                msc->io_state &= ~MSC_ABORT_IO;
+                TRACE_MSG0(MSC,"BLOCK READ ABORTED"); 
+                local_irq_restore(flags);
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_UNRECOVERED_READ_ERROR, msc->lba, USB_MSC_FAILED);
+                return;
+        }
+
+        /* sanity check lba against capacity
+         */
+        if (msc->lba >= msc->capacity) {
+                TRACE_MSG2(MSC, "START READ LBA out of range: lba: %d capacity: %d", msc->lba, msc->capacity);
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_BLOCK_ADDRESS_OUT_OF_RANGE, msc->lba, USB_MSC_FAILED);
+                return;
+        }
+
+        /* additional sanity check for lba - ensure non-zero
+         */
+        if (!msc->TransferLength_in_blocks) {
+                TRACE_MSG0(MSC,"START READ LBA TransferLength_in_blocks zero:");
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_BLOCK_ADDRESS_OUT_OF_RANGE, msc->lba, USB_MSC_FAILED);
+                return;
+        }
+        
+        /* XXX additional sanity check required here - verify that the transfer
+         * size agrees with what we where expecting, specifically I think
+         * we need to verify that we have received a multiple of the block
+         * size and either a full bulk transfer (so more will come) or
+         * the actual exact amount that the host said it would send.
+         * An error should generate a CSW with a USB_MSC_PHASE_ERROR
+         */
+
+
+        TRACE_MSG1(MSC,"RECV OUT              lba: %x", msc->lba); 
+        TRACE_MSG1(MSC,"RECV OUT   blocks    left: %d", msc->TransferLength_in_blocks); 
+        TRACE_MSG1(MSC,"RECV OUT   blocks current: %d", TransferLength_in_blocks); 
+
+        /* Initiate writing the data - msc_data_written() will be called
+         * when finished.
+         */
+        msc->write_bh.b_end_io = msc_data_written;
+
+        /* set address in buffer head
+         */
+        msc->write_bh.b_size = TransferLength_in_bytes;
+        msc->write_bh.b_rsector = msc->lba;
+
+        /* decrement counters and increment address
+         */
+        msc->TransferLength_in_bytes -= TransferLength_in_bytes;
+        msc->TransferLength_in_blocks -= TransferLength_in_blocks;
+        msc->lba += TransferLength_in_blocks;
+        msc->write_bh.b_state = (1UL << BH_Mapped) | (1UL << BH_Lock);
+        msc->io_state |= MSC_BLOCKIO_PENDING;
+
+
+        /* Check current status of TransferLength - if non-zero then we need
+         * to queue another urb to receive more data.
+         */
+        if (!msc->TransferLength_in_blocks) 
+                msc->command_state = MSC_DATA_OUT_WRITE_FINISHED;
+        else 
+                msc_start_receiving_data(msc->function, msc);
+
+        /* initiate the block i/o request
+         */
+        generic_make_request(WRITE, &msc->write_bh);
+        generic_unplug_device(blk_get_queue(msc->write_bh.b_rdev));
+}
+
+
+/*! msc_data_written - called by generic request 
+ *
+ * Called when current block i/o read is finished, restart block i/o or send the CSW.
+ *
+ */
+void msc_data_written(struct buffer_head *bh, int uptodate)
+{
+        struct msc_private *msc = bh->b_private;
+        unsigned long flags;
+        u8 io_state;
+
+        TRACE_MSG4(MSC,"DATA WRITTEN uptodate: %x b_state: %x state: %x io: %x", 
+                        uptodate, bh->b_state, msc->command_state, msc->io_state); 
+
+        TRACE_MSG1(MSC,"DATA WRITTEN lba: %x", msc->lba); 
+
+        local_irq_save(flags);
+        io_state = msc->io_state &= ~MSC_BLOCKIO_PENDING;
+	msc->write_pending=0;
+
+        local_irq_restore(flags);
+       
+        // XXX an ioctl has waited for io to complete, need to wake it up
+        #if 0
+        local_irq_save(flags);
+        if (msc->io_state & MSC_IOCTL_WAITING) {
+                wake_up_interruptible(&msc->ioctl_wq);
+                msc->io_state &= ~MSC_IOCTL_WAITING;
+        }
+        local_irq_restore(flags);
+        #endif
+
+        wake_up_interruptible(&msc->ioctl_wq);
+
+        /*
+         * verify that the I/O completed
+         */
+        if (1 != uptodate) {
+                TRACE_MSG0(MSC,"BLOCK READ FAILED"); 
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_UNRECOVERED_READ_ERROR, msc->lba, USB_MSC_FAILED);
+                // XXX CHECKME
+                if (msc->rcv_urb_finished) {
+                        usbd_free_urb(msc->rcv_urb_finished);
+                        msc->rcv_urb_finished = NULL;
+                }
+                return;
+        }
+
+        /*
+         * If there was a rcv_urb that was not processed then we need
+         * to process it now. This is done by simply restarting msc_recv_out()
+         */
+        if ((io_state & MSC_RECV_FINISHED) && msc->rcv_urb_finished) {
+                struct usbd_urb *rcv_urb = msc->rcv_urb_finished;
+                msc->rcv_urb_finished = NULL;
+                TRACE_MSG0(MSC,"DATA WRITTEN RECV FINISHED");
+                msc_recv_out_blocks(rcv_urb, msc);
+        }
+        /*
+         * DATA_IN mode and no more data to write
+         */
+        if (MSC_DATA_OUT_WRITE_FINISHED == msc->command_state) {
+                // finished, send CSW
+                TRACE_MSG0(MSC,"DATA WRITTEN send CSW");
+                msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+        }
+}
+
+extern struct usbd_function_operations msc_function_ops;
+extern struct usbd_function_driver msc_function_driver;
+
+
+/* USB Module init/exit ************************************************************************ */
+
+int msc_io_init_l24(void);
+void msc_io_exit_l24(void);
+
+/*! msc_modinit - module init
+ *
+ */
+static int msc_modinit (void)
+{
+        int rc;
+        struct msc_private *msc = &msc_private;
+
+        printk(KERN_INFO "Copyright (c) 2004 Belcarra Technologies; www.belcarra.com; sl@belcarra.com\n");
+        printk (KERN_INFO "%s vendor_id: %04x product_id: %04x major: %d minor: %d\n", __FUNCTION__, 
+                        vendor_id, product_id, major, minor);
+
+
+        MSC = otg_trace_obtain_tag();
+
+        if (vendor_id) 
+                msc_function_driver.idVendor = cpu_to_le16(vendor_id);
+        if (product_id) 
+                msc_function_driver.idProduct = cpu_to_le16(product_id);
+
+        init_waitqueue_head(&msc->msc_wq);
+        init_waitqueue_head(&msc->ioctl_wq);
+
+        msc->block_dev_state = DEVICE_EJECTED;
+
+
+        msc->command_state = MSC_READY;
+        msc->io_state = MSC_INACTIVE;
+
+#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
+        make_crc_table();
+#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
+
+        TRACE_MSG3(MSC,"PAGE_SHIFT: %x PAGE_SIZE: %x %d", PAGE_SHIFT, PAGE_SIZE, PAGE_SIZE); 
+
+        THROW_IF(msc_io_init_l24(), error);
+
+        /* register as usb function driver
+         */
+        THROW_UNLESS ((msc->function = usbd_register_function (&msc_function_driver, "msc", NULL)), error);
+        msc->usb_driver_registered++;
+
+        CATCH(error) {
+                if (msc->usb_driver_registered) {
+                        usbd_deregister_function (msc->function);
+                        msc->usb_driver_registered = 0;
+                }
+                otg_trace_invalidate_tag(MSC);
+                return -EINVAL;
+        }
+        return 0;
+}
+
+/*! msc_modexit - module cleanup
+ */
+static void msc_modexit (void)
+{
+        struct msc_private *msc = &msc_private;
+
+        /* destroy control io interface
+         */
+        msc_io_exit_l24();
+
+        /* flush io and free page buffers
+         */
+        msc_close_blockdev(msc);
+
+        if (msc->usb_driver_registered) 
+                usbd_deregister_function (msc->function);
+
+#ifdef CONFIG_OTG_MSC_BLOCK_TRACE
+        free_crc_table();
+#endif /* CONFIG_OTG_MSC_BLOCK_TRACE */
+        otg_trace_invalidate_tag(MSC);
+}
+
+
+module_init (msc_modinit);
+module_exit (msc_modexit);
+
diff -uNr linux/drivers/no-otg/functions/msc/msc-original.c linux/drivers/otg/functions/msc/msc-original.c
--- linux/drivers/no-otg/functions/msc/msc-original.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/msc-original.c	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,2209 @@
+/*
+ * otg/msc_fd/msc.c
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ * This is a Mass Storage Class Function that uses the Bulk Only protocol.
+ *
+ * To use simply load with something like:
+ *
+ *      insmod msc_fd.o vendor_id=0xffff product_id=0xffff
+ *
+ * Notes:
+ *
+ * 1. Currently block I/O is done a page at a time. I have not determined if
+ * it is possible to dispatch a multiple page generic request. It should at
+ * least be possible to queue page requests. 
+ *
+ * 2. Currently for READ operations we have a maximum of one outstanding
+ * read block I/O and send urb. These are allowed to overlap so that we can
+ * continue to read data while sending data to the host.
+ *
+ * 3. Currently for WRITE operations we have a maximum of one outstanding
+ * recv urb and one outstanding write block I/O. These are allowed to
+ * overlap so that we can continue to receive data from the host while
+ * waiting for writing to complete.
+ *
+ * 4. It would be possible to allow multiple writes to be pending, to the
+ * limit of the page cache, if desired. 
+ *
+ * 5. It should be possible to allow multiple outstanding reads to be
+ * pending, to the limit of the page cache, but this potentially could
+ * require dealing with out of order completions of the reads. Essentially a
+ * list of completed buffer heads would be required to hold any completed
+ * buffer heads that cannot be sent prior to another, earlier request being
+ * completed. 
+ *
+ * 6. Currently we only support the Bulk Only model. Microsoft states that
+ * further support for the mass storage driver will only be done for devices
+ * that conform to the Bulk Only model.
+ *
+ * 7. Multiple LUN's are not supported, but in theory they could be.
+ *
+ * 8. It should be possible to use the removalble disk model to allow for a
+ * hotplug script to umount locally and signal that the block device is now
+ * available. An insertion event would notify the host that it can now use
+ * the device. Similarily applications could notify us to send a removal
+ * event to the host so that the device can be mounted locally.
+ *
+ * 9. Error handling should be done with STALL but using ZLP seems to also
+ * work. ZLP is usually easier to implement (except possibly on the SA1100.)
+ * We may need to make STALL an option if we find devices (perhaps SA1100)
+ * that cannot reliaby send a ZLP on BULK-IN endpoint.
+ *
+ *
+ * 10. WinXP will match the following:
+ *
+ *      USB\Class_08&SubClass_02&Prot_50
+ *      USB\Class_08&SubClass_05&Prot_50
+ *      USB\Class_08&SubClass_06&Prot_50
+ *
+ * SubClass 02 is MMC or SFF8020I
+ * SubClass 05 is SFF or SFF8070I
+ * SubClass 06 is SCSI
+ *
+ * From the Windows USB Storage FAQ:
+ *
+ *      RBC not supported
+ *
+ *      SubClass = 6 (SCSI)
+ *              CDBs SHOULD NOT be padded to 12 bytes
+ *              ModeSense/ModeSelect SHOULD NOT be translated from 1ah/15h to 5ah/55h
+ *              should be used for FLASH
+ *
+ *      SubClass !=6
+ *              CDBs SHOULD be padded to 12 bytes
+ *              ModeSense/ModeSelect SHOULD be translated from 1ah/15h to 5ah/55h
+ *
+ * We are using the former, SubClass = 6, and implement the required SCSI operations.
+ *
+ * 
+ * TODO
+ *
+ * 1. error handling for block io, e.g. what if using with removable block
+ * device (like CF card) and it is removed.
+ *
+ * 2. Currently we memcpy() data from between the urb buffer and buffer
+ * head page. It should be possible to simply use the page buffer for the
+ * urb.
+ *
+ * 3. Should we offer using fileio as an option? This would allow direct access
+ * to a block device image stored in a normal file or direct access to (for example)
+ * ram disks. It would require implementing a separate file I/O kernel thread to
+ * do the actual I/O.
+ *
+ * 
+ * TODO FIXME Bus Interface Notes
+ *
+ * 1. The bus interface driver must correctly implement NAK'ing if not rcv_urb is
+ * present (see au1x00.c or wmmx.c for examples.)
+ *
+ * 2. The bus interface driver must implement USBD_URB_SENDZLP flag (see au1x00.c 
+ * for example.)
+ *
+ */
+
+#if 1
+#include <otg/otg-compat.h>
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-mesg.h>
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+
+#include <linux/blkdev.h>
+
+
+#include "msc-scsi.h"
+#include "msc.h"
+#include "crc.h"
+
+static __inline__ void TRACE_SENSE(unsigned int sense, unsigned int info)
+{
+        TRACE_MSG2(MSC, "-->             SENSE: %06x INFO: %08x", sense, info);
+}
+static __inline__ void TRACE_RLBA(unsigned int lba, unsigned int crc)
+{
+        TRACE_MSG2(MSC, "<--             rlba [%8x %08x]", lba, crc);
+}
+static __inline__ void TRACE_SLBA(unsigned int lba, unsigned int crc)
+{
+        TRACE_MSG2(MSC, "-->             slba [%8x %08x]", lba, crc);
+}
+static __inline__ void TRACE_TLBA(unsigned int lba, unsigned int crc)
+{
+        TRACE_MSG2(MSC, "-->             tlba [%8x %08x]", lba, crc);
+}
+static __inline__ void TRACE_TAG(unsigned int tag, unsigned int frame)
+{
+        TRACE_MSG2(MSC, "-->             TAG: %8x FRAME: %03x", tag, frame);
+}
+static __inline__ void TRACE_CBW(char *msg, int val)
+{
+        TRACE_MSG2(MSC,  " -->                  %s %02x", msg, val);
+}
+static __inline__ void TRACE_RECV(unsigned char *cp)
+{
+        TRACE_MSG8(MSC, "<--             recv [%02x %02x %02x %02x %02x %02x %02x %02x]",
+                        cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+}
+static __inline__ void TRACE_SENT(unsigned char *cp)
+{
+        TRACE_MSG8(MSC, "-->             sent [%02x %02x %02x %02x %02x %02x %02x %02x]",
+                        cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+}
+
+
+#else
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
+MODULE_LICENSE("PROPRIETARY");
+MODULE_DESCRIPTION ("Belcarra Mass Storage Class Bulk Only Function");
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+
+#include <linux/blkdev.h>
+
+#include "usbp-chap9.h"
+#include <usbp-mem.h>
+#include <otg-compat.h>
+#include <usbp-func.h>
+
+USBD_MODULE_INFO ("msc_fd 2.0-beta");
+
+#include "msc-scsi.h"
+#include "msc.h"
+
+#include "trace.h"
+#include "crc.h"
+#endif
+
+//#include "rbc.h"
+
+
+/* Module Parameters ************************************************************************* */
+
+static u32 vendor_id;
+static u32 product_id;
+
+static u32 major;
+static u32 minor;
+
+MODULE_PARM (vendor_id, "i");
+MODULE_PARM (product_id, "i");
+MODULE_PARM (major, "i");
+MODULE_PARM (minor, "i");
+
+MODULE_PARM_DESC (vendor_id, "Device Vendor ID");
+MODULE_PARM_DESC (product_id, "Device Product ID");
+MODULE_PARM_DESC (major, "Device Major");
+MODULE_PARM_DESC (minor, "Device Minor");
+
+/*
+ * MSC Configuration
+ *
+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
+ */
+
+#define BULK_OUT        0x00
+#define BULK_IN         0x01
+#define ENDPOINTS       0x02
+
+/*
+ * Mass Storage Class - Bulk Only
+ *
+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
+ */
+
+static u8 msc_data_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK,     0, 0x00, 0x00,  };
+static u8 msc_data_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  BULK,     0, 0x00, 0x00, };
+static struct usbd_endpoint_descriptor *msc_default[] = { 
+        (struct usbd_endpoint_descriptor *) msc_data_1, 
+        (struct usbd_endpoint_descriptor *) msc_data_2, };
+u8 msc_indexes[] = { BULK_OUT, BULK_IN, };
+
+
+/* Endpoint, Interface, Configuration and Device descriptions and descriptors
+ */
+static u8 msc_data_alternate_descriptor[sizeof(struct usbd_interface_descriptor)] = {
+        0x09, USB_DT_INTERFACE, 
+        0x00, 0x00, // bInterfaceNumber, bAlternateSetting
+        sizeof (msc_default) / sizeof(struct usbd_endpoint_descriptor), // bNumEndpoints
+        MASS_STORAGE_CLASS,
+        MASS_STORAGE_SUBCLASS_SCSI,
+        MASS_STORAGE_PROTO_BULK_ONLY,
+        0x00,
+};
+
+static struct usbd_alternate_description msc_data_alternate_descriptions[] = {
+        { iInterface: CONFIG_OTG_MSC_INTF,
+                interface_descriptor: (struct usbd_interface_descriptor *)&msc_data_alternate_descriptor,
+                endpoints:sizeof (msc_default) / sizeof(struct usbd_endpoint_descriptor *),
+                endpoint_list: msc_default,
+                endpoint_indexes: msc_indexes,
+                },
+};
+
+
+struct usbd_interface_description msc_interfaces[] = {
+        { alternates:sizeof (msc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:msc_data_alternate_descriptions,},
+};
+
+u8 msc_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
+        0x09, USB_DT_CONFIGURATION, 0x00, 0x00, // wLength
+        sizeof (msc_interfaces) / sizeof (struct usbd_interface_description),
+        0x01, 0x00, // bConfigurationValue, iConfiguration
+        0, 0,
+};
+
+struct usbd_configuration_description msc_description[] = {
+        { iConfiguration: CONFIG_OTG_MSC_DESC,
+                configuration_descriptor: (struct usbd_configuration_descriptor *)msc_configuration_descriptor,
+        },
+};
+
+
+static struct usbd_device_descriptor msc_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: 0x00,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_MSC_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_MSC_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_MSC_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+static struct usbd_device_qualifier_descriptor msc_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: 0x00,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+
+
+
+static struct usbd_endpoint_request msc_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, PAGE_SIZE, PAGE_SIZE, },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, PAGE_SIZE, PAGE_SIZE, },
+        { 0, },
+};
+
+struct usbd_otg_descriptor msc_otg_descriptor = {
+        bLength : sizeof(struct usbd_otg_descriptor),
+        bDescriptorType: USB_DT_OTG,
+        bmAttributes: 0,
+};
+
+struct usbd_device_description msc_device_description = {
+        device_descriptor: &msc_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &msc_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &msc_otg_descriptor,
+        iManufacturer: CONFIG_OTG_MSC_MANUFACTURER,
+        iProduct: CONFIG_OTG_MSC_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        iSerialNumber: CONFIG_OTG_SERIAL_NUMBER_STR, 
+#endif
+};
+
+
+#define DEVICE_EJECTED          0x0001          // MEDIA_EJECTED
+#define DEVICE_INSERTED         0x0002          // MEDIA_INSERT
+
+#define DEVICE_OPEN             0x0004          // WR_PROTECT_OFF
+#define DEVICE_WRITE_PROTECTED  0x0008          // WR_PROTECT_ON
+
+#define DEVICE_CHANGE_ON        0x0010          // MEDIA_CHANGE_ON
+
+#define DEVICE_PREVENT_REMOVAL  0x0020
+
+
+#define DEF_NUMBER_OF_HEADS     0x10
+#define DEF_SECTORS_PER_TRACK   0x20
+
+
+
+/* MSC ******************************************************************************************** */
+
+static struct msc_private msc_private;
+int msc_interrupts;
+
+int msc_urb_sent (struct usbd_urb *tx_urb, int rc);
+static int msc_recv_urb (struct usbd_urb *urb, int rc);
+
+
+/* Sense Key *********************************************************************************** */
+
+void set_sense_data(struct msc_private *msc, u32 sensedata, u32 info)
+{
+        TRACE_SENSE(sensedata, info);
+        msc->sensedata = sensedata;
+        msc->info = info;
+}
+
+
+static int msc_reset(void)
+{
+        struct msc_private *msc = &msc_private;
+        msc->device_state = MSC_DEVICE_DN;
+        msc->command_state = MSC_READY;
+        msc->io_state = MSC_INACTIVE;
+        msc->block_dev_state = 0;
+        msc->sensedata = 0;
+        msc->info = 0;
+        return 0;
+}
+
+
+/* Generic start recv urb and send csw ********************************************************* */
+
+/* msc_start_recv - queue a receive urb
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_start_recv_urb(struct usbd_function_instance *function, struct msc_private *msc, int size)
+{
+        struct usbd_urb *rcv_urb = NULL;
+        int wMaxPacketSize;
+
+        TRACE_MSG1(MSC, "START RECV URB size: %d", size); 
+
+        // ensure that we are a multiple of the endpoint packetsize
+        wMaxPacketSize = usbd_endpoint_wMaxPacketSize(function, BULK_OUT, usbd_high_speed(function));
+        if ((size % wMaxPacketSize)) {
+                size += wMaxPacketSize;
+                size = (size / wMaxPacketSize) * wMaxPacketSize;
+        }
+
+        // allocate urb and queue it
+        THROW_IF(!(rcv_urb = usbd_alloc_urb (function, BULK_OUT, size, msc_recv_urb)), error);
+        TRACE_MSG1(MSC, "START RECV urb: %p", (int)rcv_urb);
+
+        rcv_urb->function_privdata = msc;
+        msc->rcv_urb_finished = NULL;
+        THROW_IF(usbd_start_out_urb(rcv_urb), error);
+        return 0;
+
+        CATCH(error) {
+                TRACE_MSG0(MSC,"START RECV URB ERROR"); 
+                if (rcv_urb)
+                        usbd_free_urb(rcv_urb);
+                return -EINVAL;
+        }
+}
+
+/* msc_start_sending - start sending a new data or csw urb
+ *
+ * Generate a CSW (Command Status Wrapper) to send to the the host.
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_start_sending_csw(struct usbd_function_instance *function, struct msc_private *msc, u8 status)
+{
+        COMMAND_STATUS_WRAPPER *csw;
+        int length = sizeof(COMMAND_STATUS_WRAPPER);
+        struct usbd_urb *tx_urb;
+
+        TRACE_MSG1(MSC,"START SENDING CSW %08x", status); 
+
+        msc->command_state = MSC_STATUS;
+
+        THROW_IF(!(tx_urb = usbd_alloc_urb (function, BULK_IN, length, msc_urb_sent)), error);
+        TRACE_MSG1(MSC,"START sending csw urb: %p", (int)tx_urb);
+        tx_urb->actual_length = length;
+        tx_urb->function_privdata = msc;
+
+        // fill in CSW and queue the urb
+        csw = (COMMAND_STATUS_WRAPPER *) tx_urb->buffer;
+        csw->dCSWSignature = CSW_SIGNATURE;
+        csw->dCSWTag = msc->command.dCBWTag;
+        csw->dCSWDataResidue = msc->command.dCBWDataTransferLength - msc->data_transferred_in_bytes;
+        csw->bCSWStatus = status;
+
+        TRACE_MSG1(MSC,"START SENDING CSW data residue: %d", csw->dCSWDataResidue); 
+
+        THROW_IF (usbd_start_in_urb (tx_urb), error);
+
+        CATCH(error) {
+                TRACE_MSG0(MSC,"START SENDING CSW FAILED");
+                if (tx_urb) usbd_free_urb (tx_urb);
+                return -EINVAL;
+        }
+        return 0;
+}
+
+/* msc_start_sending_csw_failed - starting sending a CSW showing failure
+ *
+ * Sets sensedata and generates a CSW with status set to USB_MSC_FAILED.
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_start_sending_csw_failed(struct msc_private *msc, u32 sensedata, u32 info, int status)
+{
+        set_sense_data(msc, sensedata, info);
+        return msc_start_sending_csw(msc->function, msc, status);
+}
+
+
+/* ********************************************************************************************* */
+
+/* msc_alloc_urb - allocate an urb for returning a query
+ *
+ * Returns NULL if there is an error in the USB layer.
+ */
+struct usbd_urb * msc_alloc_urb(struct msc_private *msc, int length)
+{
+        struct usbd_function_instance *function;
+        struct usbd_urb *urb;
+
+        THROW_IF(!(function = msc->function), error);
+        THROW_IF(!(urb = usbd_alloc_urb (function, BULK_IN, length, msc_urb_sent)), error);
+        return urb;
+
+        CATCH(error) {
+                msc->command_state = MSC_READY;
+                return NULL;
+        }
+}
+
+
+/* msc_dispatch_query_urb - dispatch an urb containing query data
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_dispatch_query_urb(struct usbd_urb *urb, struct msc_private *msc, int length, int status)
+{
+        int rc;
+
+        TRACE_MSG1(MSC,"DISPATCH URB len: %d", length);
+
+        // save information in msc and urb
+        //
+        urb->function_privdata = msc;
+        urb->actual_length = msc->TransferLength_in_bytes = length;
+
+        // dispatch urb
+        {
+                unsigned long flags;
+                local_irq_save(flags);
+                if ((rc = usbd_start_in_urb (urb))) {
+
+                        TRACE_MSG0(MSC,"DISPATCH URB FAILED");
+                        usbd_free_urb (urb);
+
+                        // stall?
+                        msc->command_state = MSC_READY;
+                        local_irq_restore(flags);
+                        return -EINVAL;
+                }
+                msc->command_state = MSC_QUERY;
+                msc->status = status;
+                local_irq_restore(flags);
+        }
+        return 0;
+}
+
+
+/* msc_dispatch_query_urb_zlp - send a ZLP
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_dispatch_query_urb_zlp(struct msc_private *msc, u32 sensedata, u32 info, int status)
+{
+        struct usbd_urb *urb;
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, 1))); 
+        set_sense_data(msc, sensedata, info);
+        urb->flags |= USBD_URB_SENDZLP;
+        return msc_dispatch_query_urb(urb, msc, 0, status);
+}
+
+
+
+/* Block Device ******************************************************************************** */
+
+/* msc_open_blockdev - open the block device specified in msc->major, msc->minor
+ *
+ * Sets appropriate fields to show current status of block device.
+ *
+ * XXX TODO - this needs to be tested against RO and absent devices.
+ *
+ */
+void msc_open_blockdev(struct msc_private *msc)
+{
+        int rc;
+        msc->block_dev_state = DEVICE_EJECTED;
+
+        TRACE_MSG2(MSC, "OPEN BLOCKDEV: Major: %x Minor: %x", major, minor);
+        //printk(KERN_INFO"%s: major: %d minor: %d\n", __FUNCTION__, major, minor);
+
+        /*
+         * Check device information and verify access to the block device.
+         */
+        THROW_IF (!major, ejected);
+
+        msc->dev = MKDEV(major, minor);
+
+        THROW_IF (!(msc->bdev = bdget(kdev_t_to_nr(msc->dev))), ejected);
+
+        if ((rc = blkdev_get(msc->bdev, FMODE_READ | FMODE_WRITE, 0, BDEV_RAW))) {
+
+                TRACE_MSG0(MSC,"OPEN BLOCKDEV: cannot open RW");
+                //printk(KERN_INFO"%s: cannot open RW\n", __FUNCTION__);
+                THROW_IF ((rc = blkdev_get(msc->bdev, FMODE_READ, 0, BDEV_RAW)), ejected);
+                msc->block_dev_state |= DEVICE_WRITE_PROTECTED;
+        }
+
+        msc->block_dev_state &= ~DEVICE_EJECTED;
+        msc->block_dev_state |= DEVICE_INSERTED;
+
+        TRACE_MSG1(MSC,"OPEN BLOCKDEV: opened block_dev_state: %x", msc->block_dev_state);
+
+        /*
+         * Note that capacity must return the LBA of the last addressable block
+         * c.f. RBC 4.4, RBC 5.3 and notes below RBC Table 6
+         *
+         * The blk_size array contains the number of addressable blocks or N, 
+         * capacity is therefore N-1.
+         */
+         
+        msc->capacity = (blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1) - 1;
+        msc->block_size = get_hardsect_size(msc->dev);
+        msc->max_blocks = PAGE_SIZE / msc->block_size;
+
+        TRACE_MSG1(MSC,"blk_size: %x", blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1); 
+        TRACE_MSG1(MSC,"blk_size: %d", blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1); 
+
+        TRACE_MSG1(MSC,"capacity: %x", msc->capacity); 
+        TRACE_MSG1(MSC,"capacity: %d", msc->capacity); 
+
+        TRACE_MSG1(MSC,"block_size: %x", msc->block_size); 
+        TRACE_MSG1(MSC,"block_size: %d", msc->block_size); 
+
+        TRACE_MSG1(MSC,"max_blocks: %d", msc->max_blocks); 
+
+        printk(KERN_INFO"%s: finis\n", __FUNCTION__);
+
+        CATCH(ejected) {
+                TRACE_MSG1(MSC,"OPEN BLOCKDEV: EJECTED block_dev_state: %x", msc->block_dev_state);
+                printk(KERN_INFO"%s: cannot open R)\n", __FUNCTION__);
+                printk(KERN_INFO"%s: Cannot get device %d %d\n", __FUNCTION__, major, minor); 
+        }
+}
+
+/* msc_check_blockdev - check current status of the block device
+ *
+ * Check if the block device is operational, generate a failed CSW if not.
+ *
+ * Returns non-zero if the block device is not available for I/O operations
+ * and a failed CSW has already been sent.
+ */
+int msc_check_blockdev(struct msc_private *msc, int zlp)
+{
+        if (msc->block_dev_state & DEVICE_EJECTED) {
+                TRACE_MSG0(MSC,"CHECK BLOCKDEV DEVICE_EJECTED");
+
+                (zlp ? msc_dispatch_query_urb_zlp : msc_start_sending_csw_failed) 
+                        (msc, SCSI_SENSEKEY_MEDIUM_NOT_PRESENT, msc->lba, USB_MSC_FAILED);
+
+                return -EINVAL;
+        }
+        if (msc->block_dev_state & DEVICE_CHANGE_ON) {
+                TRACE_MSG0(MSC,"CHECK BLOCKDEV DEVICE_CHANGE_ON");
+                (zlp ? msc_dispatch_query_urb_zlp : msc_start_sending_csw_failed) 
+                        (msc, SCSI_SENSEKEY_NOT_READY_TO_CHANGE, msc->lba, USB_MSC_FAILED);
+                return -EINVAL;
+        }
+        return 0;
+}
+
+
+/* READ 10 COMMAND - read and send data to the host ******************************************** */
+
+int msc_start_reading_block_data(struct usbd_function_instance *function, struct msc_private *msc);
+void msc_block_read_finished(struct buffer_head *bh, int flag);
+
+
+/* msc_scsi_read_10 - process a read(10) command
+ *
+ * We have received a READ(10) CBW, if transfer length is non-zero
+ * initiate a generic block i/o otherwise send a CSW.
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_read_10(struct msc_private *msc, char *name, int op)
+{
+        SCSI_READ_10_COMMAND *command = (SCSI_READ_10_COMMAND *)&msc->command.CBWCB;
+
+        RETURN_ZERO_IF (msc_check_blockdev(msc, 1));
+
+        /*
+         * save the CBW information and setup for transmitting data read from the block device
+         */
+        msc->lba = be32_to_cpu(command->LogicalBlockAddress);
+        msc->TransferLength_in_blocks = be16_to_cpu(command->TransferLength);
+        msc->TransferLength_in_bytes = msc->TransferLength_in_blocks * msc->block_size;
+        msc->command_state = MSC_DATA_IN_READ;
+        msc->io_state = MSC_INACTIVE;
+
+        /*
+         * Start reading blocks to send or simply send the CSW if the host
+         * didn't actually ask for a non-zero length.
+         */
+        return (msc->TransferLength_in_blocks) ?  msc_start_reading_block_data(msc->function, msc) :
+                msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+
+/* msc_start_reading_block_data - start reading data
+ *
+ * Generate a generic block io request to read some data to transmit.
+ *
+ * This function is initially called by msc_scsi_read_10() but can also be called
+ * by msc_urb_sent() if the amount of data requested was too large.
+ *
+ * The function msc_block_read_finished() will be called to actually send the data
+ * to the host when the I/O request is complete.
+ *
+ */
+int msc_start_reading_block_data(struct usbd_function_instance *function, struct msc_private *msc)
+{
+        int TransferLength_in_blocks = MIN(msc->max_blocks, msc->TransferLength_in_blocks);
+        
+        TRACE_MSG1(MSC,"START READING BLOCK DATA lba:    %x", msc->lba); 
+        TRACE_MSG1(MSC,"START READING BLOCK DATA blocks: %d", msc->TransferLength_in_blocks); 
+        TRACE_MSG1(MSC,"START READING BLOCK DATA blocks: %d", TransferLength_in_blocks); 
+
+        if (msc->block_dev_state != DEVICE_INSERTED) {
+                TRACE_MSG0(MSC,"START READ MEDIUM NOT PRESENT");
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_MEDIUM_NOT_PRESENT, msc->lba, USB_MSC_FAILED);
+        }
+
+        if (msc->lba >= msc->capacity) {
+                TRACE_MSG2(MSC, "START READ LBA out of range: lba: %d capacity: %d", msc->lba, msc->capacity);
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_LOGICAL_BLOCK_OUT_OF_RANGE, msc->lba, USB_MSC_FAILED);
+        }
+
+        // setup buffer head
+        msc->read_bh.b_size = TransferLength_in_blocks * msc->block_size;
+        msc->read_bh.b_end_io = msc_block_read_finished;
+        msc->read_bh.b_rsector = msc->lba;
+        msc->read_bh.b_state = (1UL << BH_Mapped) | (1UL << BH_Lock);
+        msc->io_state |= MSC_BLOCKIO_PENDING;
+        msc->read_bh.b_data = page_address(msc->read_bh.b_page);
+        memset(msc->read_bh.b_data, 0x0, msc->read_bh.b_size);
+
+        generic_make_request(READ, &msc->read_bh);
+        generic_unplug_device(blk_get_queue(msc->read_bh.b_rdev));
+
+        return 0;
+}
+
+
+/* msc_block_read_finished - called by generic request 
+ *
+ * Called when block i/o read is complete, send the data to the host if possible.
+ *
+ * The function msc_urb_sent() will be called when the data is sent to
+ * either send additional data or the CSW as appropriate.
+ *
+ */
+void msc_block_read_finished(struct buffer_head *bh, int uptodate)
+{
+        struct msc_private *msc = bh->b_private;
+        int TransferLength_in_blocks = bh->b_size / msc->block_size;
+        struct usbd_function_instance *function;
+        struct usbd_urb *tx_urb;
+        int rc;
+        u32 crc;
+        int i;
+
+        msc_interrupts++;
+        TRACE_MSG1(MSC,"BLOCK READ FINISHED size: %x", bh->b_size); 
+
+        /*
+         * Race condition here, if we have not finished sending the
+         * previous tx_urb then we want to simply exit and let
+         * msc_in_read_10_urb_sent() call us again.
+         *
+         * Ensure that we do not reset BLOCKIO flags if SEND PENDING and
+         * that we do reset BLOCKIO if not SEND PENDING
+         */
+        {
+                unsigned long flags;
+                local_irq_save(flags);
+                if (msc->io_state & MSC_SEND_PENDING) {
+                        TRACE_MSG0(MSC,"BLOCK READ SEND PENDING");
+                        msc->io_state |= MSC_BLOCKIO_FINISHED;
+                        msc->uptodate = uptodate;
+                        local_irq_restore(flags);
+                        return;
+                }
+                msc->io_state &= ~(MSC_BLOCKIO_PENDING | MSC_BLOCKIO_FINISHED);
+                local_irq_restore(flags);
+        }
+
+        // verify that the I/O completed
+        //
+        if (1 != uptodate) {
+                TRACE_MSG0(MSC,"BLOCK READ FAILED"); 
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_UNRECOVERED_READ_ERROR, msc->lba, USB_MSC_FAILED);
+                return;
+        }
+
+        // debug output trace
+        //
+        for (i = 0; i < bh->b_size / msc->block_size; i++) {
+                crc = crc32_compute(bh->b_data + (i * msc->block_size), msc->block_size, CRC32_INIT);
+                TRACE_RLBA(bh->b_rsector + i, crc);
+        }
+
+        // allocate a tx_urb and copy into it
+        //
+        THROW_IF(!(function = msc->function), error);
+        THROW_IF(!(tx_urb = usbd_alloc_urb (function, BULK_IN, bh->b_size, msc_urb_sent)), error);
+        TRACE_MSG1(MSC,"BLOCK READ FINISHED urb: %p", (int)tx_urb);
+
+        tx_urb->function_privdata = msc;
+        tx_urb->actual_length = tx_urb->buffer_length = bh->b_size;
+        memcpy(tx_urb->buffer, bh->b_data, bh->b_size);
+
+        msc->read_bh.b_data = NULL;
+        {
+                unsigned long flags;
+                local_irq_save(flags);
+
+                msc->io_state |= MSC_SEND_PENDING;
+                msc->TransferLength_in_bytes -= bh->b_size;
+                msc->TransferLength_in_blocks -= TransferLength_in_blocks; 
+                msc->lba += TransferLength_in_blocks;
+
+                if (!msc->TransferLength_in_blocks) {
+                        TRACE_MSG0(MSC,"BLOCK READ FINISHED - IO FINISHED");
+                        // set flag so that CSW can be sent
+                        msc->io_state |= MSC_DATA_IN_READ_FINISHED;
+                }
+                local_irq_restore(flags);
+        }
+
+        // dispatch urb
+        if ((rc = usbd_start_in_urb (tx_urb))) {
+                TRACE_MSG0(MSC,"BLOCK READ FINISHED FAILED"); 
+                usbd_free_urb (tx_urb);
+                THROW(error);
+        }
+        if (!(msc->io_state & MSC_DATA_IN_READ_FINISHED)) {
+                TRACE_MSG0(MSC,"BLOCK READ SEND RESTARTING");
+                msc_start_reading_block_data(msc->function, msc);
+                return;
+        }
+
+        CATCH(error) {
+                TRACE_MSG0(MSC,"BLOCK READ FINISHED ERROR"); 
+                // stall?
+        }
+}
+
+/* msc_in_read_10_urb_sent - called by msc_urb_sent when state is MSC_DATA_IN_READ
+ *
+ * This will process a read_10 urb that has been sent. Specifically if any previous
+ * read_10 block I/O has finished we recall the msc_block_read_finished() function
+ * to transmit another read_10 urb. 
+ *
+ * If there is no other pending read_10 to do we create and send a CSW.
+ *
+ * If there is more I/O to do or there is already an outstanding I/O we simply
+ * return after freeing the URB.
+ *
+ * Return non-zero if urb was not disposed of.
+ */
+int msc_in_read_10_urb_sent(struct usbd_urb *tx_urb, struct msc_private *msc)
+{
+        unsigned long flags;
+
+        TRACE_MSG0(MSC,"URB SENT DATA IN");
+
+        /*
+         * Potential race condition here, we may need to restart blockio.
+         */
+
+        local_irq_save(flags);
+
+        msc->io_state &= ~MSC_SEND_PENDING;
+        msc->data_transferred_in_bytes += tx_urb->actual_length;
+
+        TRACE_MSG1(MSC,"URB SENT DATA IN data transferred: %d", msc->data_transferred_in_bytes);
+
+        if (!tx_urb->actual_length) 
+                msc->TransferLength_in_blocks = 0;
+
+        usbd_free_urb (tx_urb);
+
+        /*
+         * Check to see if we need to send CSW.
+         */
+        if (MSC_DATA_IN_READ_FINISHED & msc->io_state) {
+                TRACE_MSG0(MSC,"URB SENT DATA IN - FINISHED SENDING CSW");
+                local_irq_restore(flags);
+                return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+        }
+        /*
+         * Check to see if there is a block read needs to be finished.
+         */
+        if (MSC_BLOCKIO_FINISHED & msc->io_state) {
+                TRACE_MSG0(MSC,"URB SENT DATA IN - RESTART");
+                local_irq_restore(flags);
+                // XXX uptodate?
+                msc_block_read_finished(&msc->read_bh, msc->uptodate);
+                return 0;
+        }
+        local_irq_restore(flags);
+        return 0;
+}
+
+
+/* WRITE 10 - receive data from host and write to block device ********************************* */
+
+int msc_start_receiving_data(struct usbd_function_instance *function, struct msc_private *msc);
+void msc_data_written(struct buffer_head *bh, int flag);
+void msc_data_test(struct buffer_head *bh, int flag);
+
+/* msc_scsi_write_10 - process a write command
+ *
+ * Call either msc_start_receiving_data() or msc_start_sending_csw() as appropriate.
+ * Normally msc_start_receiving_data() is called and it will use msc_start_recv_urb() 
+ * to setup a receive urb of the appropriate size. 
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_write_10(struct msc_private *msc, char *name, int op)
+{
+        SCSI_WRITE_10_COMMAND *command = (SCSI_WRITE_10_COMMAND *)&msc->command.CBWCB;
+
+        RETURN_ZERO_IF (msc_check_blockdev(msc, 0));
+
+        // save the CBW and setup for receiving data to be written to the block device
+        //
+        msc->lba = be32_to_cpu(command->LogicalBlockAddress);
+        msc->TransferLength_in_blocks = be16_to_cpu(command->TransferLength);
+        msc->TransferLength_in_bytes = msc->TransferLength_in_blocks * msc->block_size;
+
+        msc->command_state = MSC_DATA_OUT_WRITE;
+        msc->io_state = MSC_INACTIVE;
+
+        TRACE_MSG1(MSC,"RECV WRITE lba: %x", msc->lba); 
+        TRACE_MSG1(MSC,"RECV WRITE blocks: %d", msc->TransferLength_in_blocks); 
+
+        return (msc->TransferLength_in_blocks) ?
+                msc_start_receiving_data(msc->function, msc) :
+                msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+
+/* msc_start_receiving_data - called to initiate an urb to receive WRITE(10) data
+ *
+ * Initiate a receive urb to receive upto PAGE_SIZE WRITE(10) data. The
+ * msc_recv_urb() function will call msc_recv_out_blocks() to actually
+ * write the data. 
+ *
+ * This is called from msc_scsi_write_10() to initiate the WRITE(10) and
+ * called from msc_data_written() to start the next page sized receive
+ * urb.
+ *
+ */
+int msc_start_receiving_data(struct usbd_function_instance *function, struct msc_private *msc)
+{
+        /*
+         * Calculating the length is most of the work we do :-)
+         */
+        int TransferLength_in_blocks = MIN(msc->max_blocks, msc->TransferLength_in_blocks);
+
+        TRACE_MSG1(MSC,"START RECEIVING DATA lba: %x", msc->lba); 
+        TRACE_MSG1(MSC,"START RECEIVING DATA blocks: %d", msc->TransferLength_in_blocks);
+        TRACE_MSG1(MSC,"START RECEIVING DATA blocks: %d", TransferLength_in_blocks);
+        TRACE_MSG1(MSC,"START RECEIVING DATA bytes: %d", TransferLength_in_blocks * msc->block_size);
+
+        THROW_IF(msc->command_state != MSC_DATA_OUT_WRITE, error);
+        THROW_IF(!msc->TransferLength_in_blocks, error);
+
+        msc->io_state |= MSC_RECV_PENDING;
+
+        return msc_start_recv_urb(function, msc, TransferLength_in_blocks * msc->block_size);
+
+        CATCH(error) {
+                TRACE_MSG0(MSC,"START RECEIVING DATA ERROR");
+                return -EINVAL;
+        }
+}
+
+
+/* msc_recv_out_blocks - process received WRITE(10) data by writing to block device
+ *
+ * We get here indirectly from msc_recv_urb() when state is MSC_DATA_OUT_WRITE.
+ *
+ * Dealloc the urb and call Initiate the generic request to write the
+ * received data. The b_end_io function msc_data_written() will send the
+ * CSW.
+ *
+ */
+void msc_recv_out_blocks(struct usbd_urb *rcv_urb, struct msc_private *msc)
+{
+        int TransferLength_in_bytes = rcv_urb->actual_length;
+        int TransferLength_in_blocks = TransferLength_in_bytes / msc->block_size;
+        u32 crc;
+        int i;
+
+        TRACE_MSG1(MSC,"RECV OUT            bytes: %d", TransferLength_in_bytes);
+        TRACE_MSG1(MSC,"RECV OUT          iostate: %x", msc->io_state);
+        TRACE_MSG1(MSC,"RECV OUT data transferred: %d", msc->data_transferred_in_bytes);
+
+        /*
+         * Race condition here, we may get to here before the previous block
+         * write completed. If so just exit and the msc_data_written()
+         * function will recall us.
+         */
+        {
+                unsigned long flags;
+                local_irq_save(flags);
+                if (msc->io_state & MSC_BLOCKIO_PENDING) {
+                        TRACE_MSG0(MSC,"RECV OUT  BLOCKIO PENDING");
+                        msc->io_state |= MSC_RECV_FINISHED;
+                        msc->rcv_urb_finished = rcv_urb;
+                        local_irq_restore(flags);
+                        return;
+                }
+                msc->io_state &= ~(MSC_RECV_PENDING |MSC_RECV_FINISHED);
+                local_irq_restore(flags);
+        }
+
+        msc->data_transferred_in_bytes += rcv_urb->actual_length;
+
+        for (i = 0; i < TransferLength_in_blocks; i++) {
+                crc = crc32_compute(rcv_urb->buffer + (i * msc->block_size), msc->block_size, CRC32_INIT);
+                TRACE_SLBA(msc->lba + i, crc);
+        }
+        
+        msc->write_bh.b_data = page_address(msc->write_bh.b_page);
+        memcpy(msc->write_bh.b_data, rcv_urb->buffer, rcv_urb->actual_length);
+
+        usbd_free_urb(rcv_urb);
+
+        if (msc->block_dev_state != DEVICE_INSERTED) {
+                TRACE_MSG0(MSC,"START READ MEDIUM NOT PRESENT");
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_MEDIUM_NOT_PRESENT, msc->lba, USB_MSC_FAILED);
+                return;
+        }
+
+        if (msc->lba >= msc->capacity) {
+                TRACE_MSG2(MSC, "START READ LBA out of range: lba: %d capacity: %d", msc->lba, msc->capacity);
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_LOGICAL_BLOCK_OUT_OF_RANGE, msc->lba, USB_MSC_FAILED);
+                return;
+        }
+
+        if (!msc->TransferLength_in_blocks) {
+                TRACE_MSG0(MSC,"START READ LBA TransferLength_in_blocks zero:");
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_LOGICAL_BLOCK_OUT_OF_RANGE, msc->lba, USB_MSC_FAILED);
+                return;
+        }
+
+        // Initiate writing the data
+
+        TRACE_MSG1(MSC,"RECV OUT              lba: %x", msc->lba); 
+        TRACE_MSG1(MSC,"RECV OUT   blocks    left: %d", msc->TransferLength_in_blocks); 
+        TRACE_MSG1(MSC,"RECV OUT   blocks current: %d", TransferLength_in_blocks); 
+
+
+        // set address in buffer head
+        msc->write_bh.b_size = TransferLength_in_bytes;
+        msc->write_bh.b_rsector = msc->lba;
+
+        // decrement counters and increment address
+        msc->TransferLength_in_bytes -= TransferLength_in_bytes;
+        msc->TransferLength_in_blocks -= TransferLength_in_blocks;
+        msc->lba += TransferLength_in_blocks;
+        msc->write_bh.b_state = (1UL << BH_Mapped) | (1UL << BH_Lock);
+        msc->write_bh.b_end_io = msc_data_written;
+        msc->io_state |= MSC_BLOCKIO_PENDING;
+
+
+        // start new urb here
+        if (!msc->TransferLength_in_blocks) 
+                msc->command_state = MSC_DATA_OUT_WRITE_FINISHED;
+        else 
+                msc_start_receiving_data(msc->function, msc);
+
+        generic_make_request(WRITE, &msc->write_bh);
+        generic_unplug_device(blk_get_queue(msc->write_bh.b_rdev));
+}
+
+
+/* msc_data_written - called by generic request 
+ *
+ * Called when current block i/o read is finished, restart block i/o or send the CSW.
+ *
+ */
+void msc_data_written(struct buffer_head *bh, int uptodate)
+{
+        struct msc_private *msc = bh->b_private;
+        unsigned long flags;
+        u8 io_state;
+
+        msc_interrupts++;
+
+        TRACE_MSG4(MSC,"DATA WRITTEN uptodate: %x b_state: %x state: %x io: %x", 
+                        uptodate, bh->b_state, msc->command_state, msc->io_state); 
+
+        TRACE_MSG1(MSC,"DATA WRITTEN lba: %x", msc->lba); 
+
+        local_irq_save(flags);
+        io_state = msc->io_state &= ~MSC_BLOCKIO_PENDING;
+        msc->write_bh.b_data = NULL;
+        local_irq_restore(flags);
+
+        /*
+         * verify that the I/O completed
+         */
+        if (1 != uptodate) {
+                TRACE_MSG0(MSC,"BLOCK READ FAILED"); 
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_UNRECOVERED_READ_ERROR, msc->lba, USB_MSC_FAILED);
+                // XXX CHECKME
+                if (msc->rcv_urb_finished) {
+                        usbd_free_urb(msc->rcv_urb_finished);
+                        msc->rcv_urb_finished = NULL;
+                }
+                return;
+        }
+        /*
+         * If there was a rcv_urb that was not processed then we need
+         * to process it now. This is done by simply restarting msc_recv_out()
+         */
+        if ((io_state & MSC_RECV_FINISHED) && msc->rcv_urb_finished) {
+                struct usbd_urb *rcv_urb = msc->rcv_urb_finished;
+                msc->rcv_urb_finished = NULL;
+                TRACE_MSG0(MSC,"DATA WRITTEN RECV FINISHED");
+                msc_recv_out_blocks(rcv_urb, msc);
+        }
+        /*
+         * DATA_IN mode and no more data to write
+         */
+        if (MSC_DATA_OUT_WRITE_FINISHED == msc->command_state) {
+                // finished, send CSW
+                TRACE_MSG0(MSC,"DATA WRITTEN send CSW");
+                msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+        }
+}
+
+
+/* SCSI Commands ******************************************************************************* */
+
+/* msc_scsi_inquiry - process an inquiry
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_inquiry(struct msc_private *msc, char *name, int op) 
+{
+        SCSI_INQUIRY_COMMAND *command = (SCSI_INQUIRY_COMMAND *)&msc->command.CBWCB;
+        SCSI_INQUIRY_DATA *data;
+        struct usbd_urb *urb;
+        int length = sizeof(SCSI_INQUIRY_DATA);
+
+        /*
+         * C.f. SPC2 7.3 INQUIRY command
+         * C.f. Table 46 - Standard INQUIRY data format
+         *
+         * C.f. Table 47 - Peripheral Qualifier
+         *
+         * 000b The specified peripheral device type is currently connected to this
+         *      logical unit.....
+         * 001b The device server is capable of of supporting the peripheral device
+         *      type on this logical unit. However, the physical device is not currently 
+         *      connected to this logical unit.....
+         * 010b Reserved
+         * 011b The device server is not capable of supporting a physical device on
+         *      this logical unit....
+         *      
+         */
+
+        TRACE_MSG4(MSC,"INQUIRY EnableVPD: %02x LogicalUnitNumber: %02x PageCode: %02x AllocLen: %02x",
+                        command->EnableVPD, command->LogicalUnitNumber, command->PageCode, command->AllocationLength);
+
+        // XXX THROW_IF(msc->command_state != MSC_READY, error);
+
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
+
+        data = (SCSI_INQUIRY_DATA *)urb->buffer;
+        data->PeripheralQaulifier = msc->block_dev_state & (DEVICE_EJECTED | DEVICE_CHANGE_ON) ? 0x1 : 0;
+        data->PeripheralDeviceType = 0x00;
+        data->RMB = 0x1;
+        data->ResponseDataFormat = 0x1;
+        data->AdditionalLength = 0x1f;
+        
+        strncpy(data->VendorInformation, CONFIG_OTG_MSC_MANUFACTURER, strlen(CONFIG_OTG_MSC_MANUFACTURER));
+        strncpy(data->ProductIdentification, CONFIG_OTG_MSC_PRODUCT_NAME, strlen(CONFIG_OTG_MSC_PRODUCT_NAME));
+
+        return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
+}
+
+
+/* old_msc_scsi_read_format_capacity - process a query
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int old_msc_scsi_read_format_capacity(struct msc_private *msc, char *name, int op) 
+{
+        // send ZLP then CSW
+        return msc_dispatch_query_urb_zlp(msc, 0, 0, USB_MSC_PASSED);
+}
+
+/* msc_scsi_read_format_capacity - process a query
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_read_format_capacity(struct msc_private *msc, char *name, int op) 
+{
+        SCSI_READ_FORMAT_CAPACITY_DATA *data;
+        struct usbd_urb *urb;
+        int length = sizeof(SCSI_READ_FORMAT_CAPACITY_DATA);
+        u32 block_num = msc->capacity;
+        u32 block_len;
+
+
+
+        /*
+         * If we don't have a valid block device then simply
+         * send a ZLP.
+         *
+         * XXX VERIFY this is correct thing to do for this situation.
+         */
+        //if (msc->block_dev_state & (DEVICE_EJECTED | DEVICE_CHANGE_ON)) 
+        //        return msc_dispatch_query_urb_zlp(msc);
+        RETURN_ZERO_IF (msc_check_blockdev(msc, 1));
+
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length))); 
+
+        data = (SCSI_READ_FORMAT_CAPACITY_DATA *) urb->buffer;
+
+        data->CapacityListHeader.CapacityListLength = sizeof(data->CurrentMaximumCapacityDescriptor);
+
+        data->CurrentMaximumCapacityDescriptor.NumberofBlocks = block_num;
+        data->CurrentMaximumCapacityDescriptor.DescriptorCode = 0x03;
+        memcpy(data->CurrentMaximumCapacityDescriptor.BlockLength + 1, &block_len, sizeof(block_len));
+
+        return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
+}
+
+/* msc_read_capacity - process a read_capacity command
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_read_capacity(struct msc_private *msc, char *name, int op) 
+{
+        SCSI_READ_CAPACITY_COMMAND *command = (SCSI_READ_CAPACITY_COMMAND *)&msc->command.CBWCB;
+        SCSI_READ_CAPACITY_DATA *data;
+        struct usbd_urb *urb;
+        int length = 8;
+        u32 lba;
+
+        /*
+         * C.f. RBC 5.3
+         */
+
+        /*
+         * If we don't have a valid block device then simply
+         * send a ZLP.
+         *
+         * XXX VERIFY this is correct thing to do for this situation.
+         */
+        //if (msc->block_dev_state & (DEVICE_EJECTED | DEVICE_CHANGE_ON)) 
+        //        return msc_dispatch_query_urb_zlp(msc);
+
+        RETURN_ZERO_IF (msc_check_blockdev(msc, 1));
+
+        //memcpy(&lba, &command->LogicalBlockAddress, 4);
+        //lba = be32_to_cpu(lba);
+
+        lba = be32_to_cpu(command->LogicalBlockAddress);
+
+        TRACE_MSG1(MSC,"READ CAPACITY LBA: %d", lba);
+
+        if ((command->PMI > 1) || (!command->PMI && lba)) {
+                TRACE_MSG1(MSC,"READ CAPACITY PMI: %d", command->PMI);
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD_IN_CDB, lba, USB_MSC_FAILED);
+        }
+
+        // alloc urb
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
+
+        data = (SCSI_READ_CAPACITY_DATA *) urb->buffer;
+
+        data->LastLogicalBlockAddress = cpu_to_be32(msc->capacity);
+        data->BlockLengthInBytes = cpu_to_be32(msc->block_size);
+
+        TRACE_MSG1(MSC,"RECV READ CAPACITY lba: %x", be32_to_cpu(data->LastLogicalBlockAddress));
+        TRACE_MSG1(MSC,"RECV READ CAPACITY block_size: %x", be32_to_cpu(data->BlockLengthInBytes));
+
+        return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
+}
+
+
+/* msc_scsi_request_sense - process a request_sense command
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_request_sense(struct msc_private *msc, char *name, int op)
+{
+        SCSI_REQUEST_SENSE_COMMAND*    command = (SCSI_REQUEST_SENSE_COMMAND *)&msc->command.CBWCB;
+        SCSI_REQUEST_SENSE_DATA *data;
+
+        /*
+         * C.f. SPC2 7.20 REQUEST SENSE command
+         */
+
+        struct usbd_urb *urb;
+        int length = sizeof(SCSI_REQUEST_SENSE_DATA);
+
+        // alloc urb
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
+
+        data = (SCSI_REQUEST_SENSE_DATA *) urb->buffer;
+        memset(command, 0x0, length);
+        data->ErrorCode = SCSI_ERROR_CURRENT;
+        data->SenseKey = msc->sensedata >> 16;
+        data->AdditionalSenseCode = msc->sensedata >> 8;
+        data->AdditionalSenseCodeQualifier = msc->sensedata;
+        data->Valid = 1;
+
+        set_sense_data(msc, SCSI_SENSEKEY_NO_SENSE, 0);
+
+        return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
+}
+
+/* msc_scsi_mode_sense - process a request_sense command
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int old_msc_scsi_mode_sense(struct msc_private *msc, char *name, int op)
+{
+        SCSI_MODE_SENSE_COMMAND *command = (SCSI_MODE_SENSE_COMMAND *)&msc->command.CBWCB;
+        SCSI_MODE_SENSE_DATA *data;
+        int length = sizeof(SCSI_MODE_SENSE_DATA);
+
+        struct usbd_urb *urb;
+        u8 *cp;
+
+
+        TRACE_MSG4(MSC,"MODE SENSE dbd: %02x PageControl: %02x PageCode: %02x Alloc: %02x", 
+                        command->DBD, 
+                        command->PageControl, 
+                        command->PageCode, 
+                        0);
+
+        length = 8;
+
+        // alloc urb
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
+
+        cp = (u8 *) urb->buffer;
+        memset(cp, 0x0, length);
+
+        cp[0] = 0;
+        cp[1] = 0;
+        cp[2] = 0;              // 0x80 is writeprotect
+        cp[3] = 0x08;
+        cp[4] = 0;
+        cp[5] = 0;
+        cp[6] = 0;
+        cp[7] = 0;
+
+        return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
+}
+
+/* msc_scsi_mode_sense - process a request_sense command
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_mode_sense(struct msc_private *msc, char *name, int op)
+{
+
+        /*
+         * C.f. SPC2 7.8.1 MODE SENSE(6) command
+         */
+
+        static READ_WRITE_ERROR_RECOVERY_PAGE           page_01 = {
+                PageCode:0x01,
+                PageLength:0x0A,
+                ReadRetryCount:0x03,
+                WriteRetryCount:0x80,
+        };
+        static FLEXIBLE_DISK_PAGE                       page_05 = {
+                PageCode:0x05,
+                PageLength:0x1E,
+                TransferRate:__constant_cpu_to_be16(0xFA00),
+                NumberofHeads:0xA0,
+                SectorsperTrack:0x00,
+                DataBytesperSector:__constant_cpu_to_be16(0x0002),
+                NumberofCylinders:__constant_cpu_to_be16(0x0000),
+                MotorOnDelay:0x05,
+                MotorOffDelay:0x1E,
+                MediumRotationRate:__constant_cpu_to_be16(0x6801),
+        };
+        static REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE page_1b = {
+                PageCode:0x1B,
+                PageLength:0x0A,
+                TLUN:0x01,
+        };
+        static TIMER_AND_PROTECT_PAGE                   page_1c = {
+                PageCode:0x1c,
+                PageLength:0x06,
+                InactivityTimeMultiplier:0x0A,
+        };
+
+        SCSI_MODE_SENSE_COMMAND *command = (SCSI_MODE_SENSE_COMMAND *)&msc->command.CBWCB;
+        SCSI_MODE_SENSE_DATA *data;
+        struct usbd_urb *urb;
+        int length = sizeof(SCSI_MODE_SENSE_DATA);
+
+        TRACE_MSG4(MSC,"MODE SENSE dbd: %02x PageControl: %02x PageCode: %02x Alloc: %02x", 
+                        command->DBD, 
+                        command->PageControl, 
+                        command->PageCode, 
+                        0);
+
+
+        if (msc->block_dev_state & DEVICE_EJECTED) {
+                u16 sector   = htons((unsigned short)msc->block_size);
+                u16 cylinder = 0;
+                page_05.NumberofHeads = 0;
+                page_05.SectorsperTrack = 0;
+                memcpy(&page_05.DataBytesperSector, &sector, sizeof(sector));
+                memcpy(&page_05.NumberofCylinders, &cylinder, sizeof(cylinder));
+        }
+        else {
+                u16 sector   = htons((unsigned short)msc->block_size);
+                u32 size = DEF_NUMBER_OF_HEADS * DEF_SECTORS_PER_TRACK * sector;
+                u16 cylinder = htons(msc->capacity / size);
+                page_05.NumberofHeads = DEF_NUMBER_OF_HEADS;
+                page_05.SectorsperTrack = DEF_SECTORS_PER_TRACK;
+                memcpy(&page_05.DataBytesperSector, &sector, sizeof(sector));
+                memcpy(&page_05.NumberofCylinders, &cylinder, sizeof(cylinder));
+
+        }
+
+
+        if (SCSI_MODEPAGE_CONTROL_CURRENT != command->PageControl) {
+                TRACE_MSG2(MSC,"MODE SENSE - requeested other than CONTROL_CURRENT: %d %d", 
+                                command->PageControl, command->PageCode);
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD_IN_CDB, msc->lba, USB_MSC_FAILED);
+        }
+
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, length)));
+        data = (SCSI_MODE_SENSE_DATA *) urb->buffer;
+
+        data->ModeParameterHeader.WriteProtect = msc->block_dev_state & DEVICE_WRITE_PROTECTED ? 1 : 0;
+
+        switch (command->PageCode) {
+        case SCSI_MODEPAGE_ERROR_RECOVERY:
+                length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_01);
+                data->ModeParameterHeader.ModeDataLength = length - 1;
+                memcpy(&data->ModePages, &page_01, sizeof(page_01));
+                break;
+        case SCSI_MODEPAGE_FLEXIBLE_DISK_PAGE:
+                length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_05);
+                data->ModeParameterHeader.ModeDataLength = length - 1;
+                memcpy(&data->ModePages, &page_05, sizeof(page_05));
+                break;
+        case SCSI_MODEPAGE_REMOVABLE_BLOCK_ACCESS:
+                length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1b);
+                data->ModeParameterHeader.ModeDataLength = length - 1;
+                memcpy(&data->ModePages, &page_1b, sizeof(page_1b));
+                break;
+        case SCSI_MODEPAGE_INFORMATION_EXCEPTIONS:
+                length = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1c);
+                data->ModeParameterHeader.ModeDataLength = length - 1;
+                memcpy(&data->ModePages, &page_1c, sizeof(page_1c));
+                break;
+        case SCSI_MODEPAGE_ALL_SUPPORTED:
+                length = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_ALL_PAGES);
+                data->ModeParameterHeader.ModeDataLength = length - 1;
+                memcpy(&data->ModePages.ModeAllPages.ReadWriteErrorRecoveryPage, &page_01, sizeof(page_01));
+                memcpy(&data->ModePages.ModeAllPages.FlexibleDiskPage, &page_05, sizeof(page_05));
+                memcpy(&data->ModePages.ModeAllPages.RemovableBlockAccessCapabilitiesPage, &page_1b, sizeof(page_1b));
+                memcpy(&data->ModePages.ModeAllPages.TimerAndProtectPage, &page_1c, sizeof(page_1c));
+                break;
+        case SCSI_MODEPAGE_CACHING:
+                // see file_storage.c for an example if we want to support this
+                break;
+        }
+
+        TRACE_MSG2(MSC,"LENGTH: %d %d", msc->command.dCBWDataTransferLength, length);
+
+        /*
+         * XXX verify that length is <= 256 bytes, return CHECK_CONDITION if it is
+         */
+        length = MIN(msc->command.dCBWDataTransferLength, length);
+
+        return msc_dispatch_query_urb(urb, msc, length, USB_MSC_PASSED);
+}
+
+
+/* msc_scsi_test_unit_ready - process a request_sense command
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_test_unit_ready(struct msc_private *msc, char *name, int op)
+{
+        /*
+         * C.f. SPC2 7.25 TEST UNIT READY command
+         *
+         * Return GOOD, illegal request for bad LUN or NOT READY
+         *
+         */
+        RETURN_EINVAL_IF (msc_check_blockdev(msc, 0));
+        return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+
+/* msc_scsi_prevent_allow - process a request_sense command
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_prevent_allow(struct msc_private *msc, char *name, int op)
+{
+        SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND* command = (SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND*)&msc->command.CBWCB;
+
+        /*
+         * C.f. SPC2 7.12 Table 78 PREVENT ALLOW MEDIUM REMOVAL Prevent Field
+         *
+         * 00b  Medium removal shall be allowed from both the data transport
+         *      element and the attached medium changer (if any).
+         * 01b  Medium removal shall be prohibited from the data transport
+         *      element but allowed from the attached medium changer (if any).
+         * 10b  Medium removal shall be allowed for the data transport element
+         *      but prohibited for the attached medium changer.
+         * 11b  Medium remval shall be prohibited from both the data transport
+         *      element and the attached medium changer
+         *
+         * Prevention shall terminate after 00b or 10b, after a SYNC CACHE or hard reset.
+         */
+
+        TRACE_MSG1(MSC,"PREVENT: %d", command->Prevent);
+
+        RETURN_EINVAL_IF (msc_check_blockdev(msc, 0));
+
+
+        // XXX TODO 
+        // this is from storageproto.c, shouldn't we implement something?
+        if (command->Prevent) 
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD, msc->lba, USB_MSC_FAILED);
+
+        return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+
+/* msc_scsi_start_stop - process a request_sense command
+ *
+ * C.f. RBC 5.4 and 5.4.2
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_start_stop(struct msc_private *msc, char *name, int op)
+{
+        SCSI_START_STOP_COMMAND* command = (SCSI_START_STOP_COMMAND*)&msc->command.CBWCB;
+
+        TRACE_MSG4(MSC,"START STOP: Immed: %d Power: %x LoEj: %d Start: %d", 
+                        command->IMMED, command->PowerConditions, command->LoEj, command->Start);
+
+        /*
+         * C.f. 5.4 
+         *
+         * IMMED - if set return status immediately after command validation, otherwise
+         * return status as soon operation is completed.
+         *
+         * C.f. 5.4.1 Table 8 POWER CONDITIONS
+         *
+         * 0 - M - no change in power condition
+         * 1 - M - place device in active condition
+         * 2 - M - place device in idle condition
+         * 3 - M - place device in Standby condition
+         * 4 -   - reserved
+         * 5 - M - place device in Sleep condition
+         * 6 -   - reserved
+         * 7 - 0 - Device Control
+         *
+         * C.f. 5.4.2 Table 9 START STOP control bit definitions
+         *
+         * Power        Load/Eject      Start   
+         * 1-7          x               x               LoEj and Start Ignored
+         * 0            0               0               Stop the medium
+         * 0            0               1               Make the medium ready
+         * 0            1               0               Unload the medium
+         * 0            1               1               Load the medium
+         *
+         */
+         
+
+        RETURN_EINVAL_IF (msc_check_blockdev(msc, 0));
+        
+        // XXX TODO 
+        // this is from storageproto.c, shouldn't we implement something?
+        
+        if (command->Start && command->LoEj) 
+                return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_FIELD, msc->lba, USB_MSC_FAILED);
+
+        return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+
+/* msc_scsi_verify - process a verify command
+ *
+ * Used by:
+ *      win2k
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_verify(struct msc_private *msc, char *name, int op)
+{
+        SCSI_VERIFY_COMMAND *command = (SCSI_VERIFY_COMMAND *)&msc->command.CBWCB; 
+        /*
+         * C.f. RBC 5.7 VERIFY command
+         */
+        // XXX This actually should use the read_10 function and when
+        // finished reading simply send the following
+        return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+
+/* msc_scsi_mode_select - process a select command
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_scsi_mode_select(struct msc_private *msc, char *name, int op)
+{
+        //SCSI_MODE_SELECT_COMMAND *command = (SCSI_MODE_SELECT_COMMAND *)&msc->command.CBWCB; 
+       
+        /*
+         * C.f. SPC2 7.6 MODE SELECT(6) command
+         */
+
+        // if less than correct amount of data return USB_MSC_PHASE_ERROR - see MV
+        //
+        return msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+}
+
+
+/* msc_cmd_unknown - process an unknown command
+ *
+ *
+ * Returns non-zero if there is an error in the USB layer.
+ */
+int msc_cmd_unknown(struct msc_private *msc, char *name, int op)
+{
+        /*
+        struct usbd_urb *urb;
+        RETURN_EINVAL_IF(!(urb = msc_alloc_urb(msc, 1)));         // XXX +1 ?
+        urb->flags |= USBD_URB_SENDZLP;
+        return msc_dispatch_query_urb(urb, msc, 0);
+        */
+
+        printk(KERN_ERR"%s: NOT IMPLEMENTED %s opcode: %02x\n", __FUNCTION__, name, op);
+
+        // should we send ZLP for unknow commands?
+        // return msc_dispatch_query_urb_zlp(msc);
+
+        // or failed
+        return msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
+}
+
+
+struct rbc_dispatch {
+        u8      op;
+        char    *name;
+        int     (*rbc_command) (struct msc_private *, char *, int op);
+};
+
+/* Command cross reference 
+ *
+ * This is the list of commands observed from each host OS. It is necessarily
+ * incomplete in that we not have reached some condition necessary to have
+ * other commands used.
+ *                                      Win2k   WinXP
+ * SCSI_TEST_UNIT_READY                 yes     yes
+ * SCSI_READ_10                         yes     yes
+ * SCSI_WRITE_10                        yes     yes
+ * SCSI_READ_CAPACITY                   yes     yes
+ * SCSI_VERIFY                          yes
+ * SCSI_INQUIRY                         yes     yes
+ * SCSI_MODE_SENSE                      yes
+ * SCSI_READ_FORMAT_CAPACITY            yes     yes
+ * SCSI_REQUEST_SENSE                   
+ * SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL    
+ * SCSI_START_STOP                      
+ * SCSI_MODE_SELECT                     
+ * SCSI_FORMAT_UNIT                     
+ *
+ */
+
+struct rbc_dispatch rbc_dispatch_table[] = {
+        { SCSI_TEST_UNIT_READY,         "SCSI_TEST_UNIT_READY",         msc_scsi_test_unit_ready },          //
+        { SCSI_READ_10,                 "SCSI_READ_10",                 msc_scsi_read_10 },                  //
+        { SCSI_WRITE_10,                "SCSI_WRITE_10",                msc_scsi_write_10 },                 //
+        { SCSI_READ_CAPACITY,           "SCSI_READ_CAPACITY",           msc_scsi_read_capacity },            //
+        { SCSI_VERIFY,                  "SCSI_VERIFY",                  msc_scsi_verify },                   //
+        { SCSI_INQUIRY,                 "SCSI_INQUIRY",                 msc_scsi_inquiry },                  //
+        { SCSI_MODE_SENSE,              "SCSI_MODE_SENSE",              msc_scsi_mode_sense },               //
+        { SCSI_READ_FORMAT_CAPACITY,    "SCSI_READ_FORMAT_CAPACITY",    msc_scsi_read_format_capacity },     //
+        { SCSI_REQUEST_SENSE,           "SCSI_REQUEST_SENSE",           msc_scsi_request_sense },            //
+        { SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, "SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL", msc_scsi_prevent_allow }, //
+        { SCSI_START_STOP,              "SCSI_START_STOP",              msc_scsi_start_stop },               //
+        { SCSI_MODE_SELECT,             "SCSI_MODE_SELECT",             msc_scsi_mode_select },
+        { SCSI_FORMAT_UNIT,             "SCSI_FORMAT_UNIT",             msc_cmd_unknown },
+
+        { SCSI_READ_6,                  "SCSI_READ_6",                  msc_cmd_unknown },
+        { SCSI_WRITE_6,                 "SCSI_WRITE_6",                 msc_cmd_unknown },
+        { SCSI_RESERVE,                 "SCSI_RESERVE",                 msc_cmd_unknown },
+        { SCSI_RELEASE,                 "SCSI_RELEASE",                 msc_cmd_unknown },
+        { SCSI_SEND_DIAGNOSTIC,         "SCSI_SEND_DIAGNOSTIC",         msc_cmd_unknown },
+        { SCSI_SYNCHRONIZE_CACHE,       "SCSI_SYNCHRONIZE_CACHE",       msc_cmd_unknown },
+        { SCSI_MODE_SENSE_10,           "SCSI_MODE_SENSE_10",           msc_cmd_unknown },
+        { SCSI_REZERO_UNIT,             "SCSI_REZERO_UNIT",             msc_cmd_unknown },
+        { SCSI_SEEK_10,                 "SCSI_SEEK_10",                 msc_cmd_unknown },
+        { SCSI_WRITE_AND_VERIFY,        "SCSI_WRITE_AND_VERIFY",        msc_cmd_unknown },
+        { SCSI_WRITE_12,                "SCSI_WRITE_12",                msc_cmd_unknown },
+        { SCSI_READ_12,                 "SCSI_READ_12",                 msc_cmd_unknown },
+
+        { 0xff,                         "SCSI_UNKNOWN",                      msc_cmd_unknown },
+};
+
+
+/* msc_recv_command - process a new CBW
+ *
+ * Return non-zero if urb was not disposed of.
+ */
+int msc_recv_command(struct usbd_urb *urb, struct msc_private *msc)
+{
+        COMMAND_BLOCK_WRAPPER *command = (COMMAND_BLOCK_WRAPPER *)urb->buffer;
+        u8 op = command->CBWCB[0];
+        struct rbc_dispatch *dispatch;
+
+        /*
+         * c.f. section 6.2 - Valid and Meaningful CBW
+         * c.f. section 6.2.1 - Valid CBW
+         *
+         * The CBW was received after the device had sent a CSW or after a
+         * reset XXX check that we only set MSC_READY after reset or sending
+         * CSW.
+         *
+         * The CBW is 31 (1Fh) bytes in length and the bCBWSignature is
+         * equal to 43425355h.
+         */
+        THROW_IF(31 != urb->actual_length, error);
+        THROW_IF(CBW_SIGNATURE != le32_to_cpu(command->dCBWSignature), error);
+        
+        /*
+         * c.f. section 6.2.2 - Meaningful CBW
+         *
+         * no reserved bits are set
+         * the bCBWLUN contains a valid LUN supported by the device
+         * both bCBWCBlength and the content of the CBWCB are in accordance with bInterfaceSubClass
+         */
+
+        // XXX checklun etc
+
+        /* 
+         * Success 
+         */
+        memcpy(&msc->command, command, sizeof(COMMAND_BLOCK_WRAPPER));
+        msc->data_transferred_in_bytes = msc->TransferLength_in_blocks = msc->TransferLength_in_bytes = 0;
+
+        TRACE_TAG(command->dCBWTag, urb->framenum);
+        usbd_free_urb(urb);
+
+        /*
+         * Search using the opcode to find the dispatch function to use and
+         * call it.
+         */
+        for (dispatch = rbc_dispatch_table; dispatch->op != 0xff; dispatch++) {
+                if ((dispatch->op == op)) {
+                        TRACE_CBW(dispatch->name, dispatch->op);
+                        TRACE_RECV(&(command->CBWCB[1]));
+                        if (dispatch->rbc_command(msc, dispatch->name, op)) 
+                                TRACE_MSG0(MSC,"COMMAND ERROR");
+                        return 0;
+                }
+        }
+        /* FALL THROUGH if no match is found */
+
+        THROW_IF(msc_cmd_unknown(msc, "CMD_UNKNOWN", op), error);
+        return 0;
+
+        CATCH(error) {
+                TRACE_MSG0(MSC,"RECV CBW ERROR");
+        }
+        
+        /*
+         * default behaviour is to stall or send ZLP on BULK-IN endpoint
+         */
+        TRACE_CBW("UNKNOWN COMMAND", op);
+
+        /*
+         * We cannot return error as we have deallocated urb and there is no
+         * other sensible course of action that the usbdcore layer can take
+         * for us.
+         */
+        return 0;
+}
+
+
+/* Sent Function - process a sent urb ********************************************************** */
+
+/* msc_urb_sent - called to indicate URB transmit finished
+ * @urb: pointer to struct usbd_urb
+ * @rc: result
+ *
+ * This is called when an urb is sent. Depending on current state
+ * it may:
+ *
+ *      - continue sending data
+ *      - send a CSW
+ *      - start a recv for a CBW
+ *
+ * This is called from BOTTOM HALF context.
+ *
+ * Return non-zero if urb was not disposed of.
+ */
+int msc_urb_sent (struct usbd_urb *tx_urb, int rc)
+{
+        struct usbd_function_instance *function;
+        struct msc_private *msc = &msc_private;
+
+        msc_interrupts++;
+
+        TRACE_MSG1(MSC,"URB SENT tx_urb: %p", (int)tx_urb);
+        TRACE_MSG1(MSC,"URB SENT function: %p", (int)tx_urb->function_instance);
+
+        RETURN_EINVAL_IF(!(function = tx_urb->function_instance)); 
+
+        TRACE_MSG1(MSC,"URB SENT status: %p", usbd_get_device_status(function));
+        RETURN_EINVAL_IF(usbd_get_device_status(function) == USBD_CLOSING);
+
+        TRACE_MSG1(MSC,"URB SENT state: %p", usbd_get_device_state(function));
+        RETURN_EINVAL_IF(usbd_get_device_state(function) != STATE_CONFIGURED);
+
+        switch (msc->command_state) {
+        case MSC_DATA_IN_READ:
+        case MSC_DATA_IN_READ_FINISHED:
+                TRACE_MSG0(MSC,"URB SENT READ");
+                return msc_in_read_10_urb_sent(tx_urb, msc);
+        case MSC_QUERY:
+                // finished, send CSW
+                TRACE_MSG0(MSC,"URB SENT QUERY");
+                msc_start_sending_csw(msc->function, msc, USB_MSC_PASSED);
+                break;
+        case MSC_STATUS:
+        default:
+                // sent a CSW need to receive the next CBW
+                TRACE_MSG0(MSC,"URB SENT STATUS");
+                msc->command_state = MSC_READY;
+                msc_start_recv_urb(msc->function, msc, sizeof(COMMAND_BLOCK_WRAPPER));
+                break;
+        }
+        usbd_free_urb (tx_urb);
+        return 0;
+}
+
+
+/* Receive Function - receiving an urb ********************************************************* */
+
+/* msc_recv_urb - process a received urb
+ *
+ * Return non-zero if urb was not disposed of.
+ */
+static int msc_recv_urb (struct usbd_urb *rcv_urb, int rc)
+{
+        struct msc_private *msc = &msc_private;
+
+        msc_interrupts++;
+
+        RETURN_EINVAL_IF(!msc->connected);
+
+        TRACE_MSG2(MSC, "RECV URB length: %d state: %d", rcv_urb->actual_length, msc->command_state);
+
+        switch(msc->command_state) {
+
+                // ready to start a new transaction
+        case MSC_READY:
+                return msc_recv_command(rcv_urb, msc);
+
+                // we think we are receiving data 
+        case MSC_DATA_OUT_WRITE:
+        case MSC_DATA_OUT_WRITE_FINISHED:
+                msc_recv_out_blocks(rcv_urb, msc);
+                return 0;
+
+                // we think we are sending data
+        case MSC_DATA_IN_READ:
+        case MSC_DATA_IN_READ_FINISHED:
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
+                break;
+
+                // we think we are sending status
+        case MSC_STATUS:
+                msc_start_sending_csw_failed (msc, SCSI_SENSEKEY_INVALID_COMMAND, msc->lba, USB_MSC_FAILED);
+                break;
+
+                // we don't think
+        case MSC_UNKNOWN:
+        default:
+                TRACE_MSG0(MSC,"RECV URB ERROR");
+        }
+        // let caller dispose of urb
+        return -EINVAL;
+}
+
+/* USB Device Functions ************************************************************************ */
+
+/* msc_event_handler - process a device event
+ *
+ * This function is called when an USBD event occurs. 
+ *
+ * This is called from INTERRUPT context.
+ */
+void msc_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
+{
+        struct msc_private *msc = &msc_private;
+
+        msc_interrupts++;
+
+        TRACE_MSG1(MSC,"EVENT IRQ %d", event);
+
+        switch (event) {
+        case DEVICE_CONFIGURED:
+                TRACE_MSG0(MSC,"EVENT CONFIGURED");
+                msc->connected = 1;
+                msc->command_state = MSC_READY;
+                msc_start_recv_urb(function, msc, sizeof(COMMAND_BLOCK_WRAPPER));
+                break;
+
+        case DEVICE_BUS_INACTIVE:
+        case DEVICE_RESET:
+        case DEVICE_DE_CONFIGURED:
+                TRACE_MSG0(MSC,"EVENT RESET");
+                BREAK_IF(!msc->connected);
+                msc->connected = 0;
+                if (msc->rcv_urb_finished) {
+                        usbd_free_urb (msc->rcv_urb_finished);
+                        msc->rcv_urb_finished = NULL;
+                }
+                break;
+
+        default: 
+                TRACE_MSG0(MSC,"EVENT IGNORED");
+                break;
+        }
+}
+
+
+/* msc_device_request - called to indicate urb has been received
+ *
+ * This function is called when a SETUP packet has been received that
+ * should be handled by the function driver. It will not be called to
+ * process the standard chapter nine defined requests.
+ *
+ * Return non-zero for failure.
+ */
+int msc_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
+{
+        struct msc_private *msc = &msc_private;
+        struct usbd_urb *urb;
+
+        TRACE_MSG0(MSC,"RECV SETUP");
+        msc_interrupts++;
+
+        // verify that this is a usb class request per cdc-acm specification or a vendor request.
+        RETURN_ZERO_IF (!(request->bmRequestType & (USB_REQ_TYPE_CLASS | USB_REQ_TYPE_VENDOR)));
+       
+        // determine the request direction and process accordingly
+        switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
+
+        case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_CLASS:
+                switch (request->bRequest) {
+                case MSC_BULKONLY_RESET:
+                        // XXX TODO FIXME
+                        return 0;
+                }
+
+        case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_CLASS:
+                switch (request->bRequest) {
+                case MSC_BULKONLY_GETMAXLUN: 
+                        RETURN_EINVAL_IF(!(urb = usbd_alloc_urb_ep0(function, 1, NULL)));
+                        urb->buffer[0] = 0;
+                        urb->actual_length = 1;
+                        RETURN_ZERO_IF(!usbd_start_in_urb(urb));
+                        usbd_free_urb(urb);
+                        return -EINVAL;
+                }
+        default: 
+                break;
+        }
+        return -EINVAL;
+}
+
+/* msc_function_enable - this is called by the USBD core layer 
+ *
+ * This is called to initialize the function when a bus interface driver
+ * is loaded.
+ */
+static int msc_function_enable (struct usbd_function_instance *function)
+{
+        struct msc_private *msc = &msc_private;
+
+        MOD_INC_USE_COUNT;
+
+        // XXX TODO need to verify that serial number is minimum of 12 
+        
+        msc_interrupts++;
+
+        msc->function = function;
+        msc->command_state = MSC_READY;
+
+        //msc_open_blockdev(msc);
+        return 0;
+}
+
+/* msc_function_disable - this is called by the USBD core layer 
+ *
+ * This is called to close the function when a bus interface driver
+ * is unloaded.
+ */
+static void msc_function_disable (struct usbd_function_instance *function)
+{               
+        struct msc_private *msc = &msc_private;
+
+        msc_interrupts++;
+
+        TRACE_MSG0(MSC,"FUNCTION EXIT");
+
+        msc->function = NULL;
+
+        MOD_DEC_USE_COUNT;
+}
+
+static struct usbd_function_operations function_ops = {
+        event_handler: msc_event_handler,
+        device_request: msc_device_request,
+        function_enable: msc_function_enable,
+        function_disable: msc_function_disable,
+};
+
+static struct usbd_function_driver function_driver = {
+        name: "msc-bulkonly",
+        fops:&function_ops,
+        device_description:&msc_device_description,
+        bNumConfigurations:sizeof (msc_description) / sizeof (struct usbd_configuration_description),
+        configuration_description:msc_description,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_MSC_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_MSC_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_MSC_BCDDEVICE),
+        bNumInterfaces:sizeof (msc_interfaces) / sizeof (struct usbd_interface_description),
+        interface_list:msc_interfaces,
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: msc_endpoint_requests,
+};
+
+
+/* USB Module init/exit ************************************************************************ */
+
+/*
+ * msc_modinit - module init
+ *
+ */
+static int msc_modinit (void)
+{
+        int rc;
+        struct msc_private *msc = &msc_private;
+
+        printk(KERN_INFO "Copyright (c) 2004 Belcarra Technologies; www.belcarra.com; sl@belcarra.com\n");
+        printk (KERN_INFO "%s vendor_id: %04x product_id: %04x major: %d minor: %d\n", __FUNCTION__, 
+                        vendor_id, product_id, major, minor);
+
+        if (vendor_id) 
+                function_driver.idVendor = cpu_to_le16(vendor_id);
+        if (product_id) 
+                function_driver.idProduct = cpu_to_le16(product_id);
+
+        init_waitqueue_head(&msc->msc_wq);
+#if 0
+        /*
+         * Check device information and verify access to the block device.
+         */
+        RETURN_EINVAL_IF(!major && !minor);
+        msc->dev = MKDEV(major, minor);
+        if(!(msc->bdev = bdget(kdev_t_to_nr(msc->dev)))) {
+                printk(KERN_INFO"%s: Cannot find device %d %d\n", __FUNCTION__, major, minor); 
+                return -EINVAL;
+        }
+        if ((rc = blkdev_get(msc->bdev, FMODE_READ | FMODE_WRITE, 0, BDEV_RAW))) {
+                printk(KERN_INFO"%s: Cannot get device %d %d\n", __FUNCTION__, major, minor); 
+                return -EINVAL;
+        }
+        
+        /*
+         * Note that capacity must return the LBA of the last addressable block
+         * c.f. RBC 4.4, RBC 5.3 and notes below RBC Table 6
+         *
+         * The blk_size array contains the number of addressable blocks or N, 
+         * capacity is therefore N-1.
+         */
+         
+        msc->capacity = (blk_size[MAJOR(msc_private.dev)][MINOR(msc_private.dev)] << 1) - 1;
+        msc->block_size = get_hardsect_size(msc->dev);
+        msc->max_blocks = PAGE_SIZE / msc->block_size;
+#endif
+
+        msc->block_dev_state = DEVICE_EJECTED;
+
+        msc_open_blockdev(msc);
+
+        /*
+         * setup generic buffer_head
+         */
+
+        msc->read_bh.b_rdev = msc->dev;
+        msc->read_bh.b_private = msc;
+        msc->read_bh.b_page = alloc_page(GFP_NOIO);
+
+        msc->write_bh.b_rdev = msc->dev;
+        msc->write_bh.b_private = msc;
+        msc->write_bh.b_page = alloc_page(GFP_NOIO);
+
+        msc->command_state = MSC_READY;
+        msc->io_state = MSC_INACTIVE;
+
+        msc_trace_init("msctrace", &msc_private);
+        make_crc_table();
+
+        TRACE_MSG1(MSC,"PAGE_SHIFT: %x", PAGE_SHIFT); 
+        TRACE_MSG1(MSC,"PAGE_SIZE: %x", PAGE_SIZE); 
+        TRACE_MSG1(MSC,"PAGE_SIZE: %d", PAGE_SIZE); 
+
+        // register as usb function driver
+        THROW_IF (usbd_register_function (&function_driver, NULL), error);
+        msc->usb_driver_registered++;
+
+        CATCH(error) {
+                if (msc->usb_driver_registered) {
+                        usbd_deregister_function (&function_driver);
+                        msc->usb_driver_registered = 0;
+                }
+                return -EINVAL;
+        }
+        return 0;
+}
+
+/* msc_modexit - module cleanup
+ */
+static void msc_modexit (void)
+{
+        struct msc_private *msc = &msc_private;
+
+        if (msc->bdev) {
+                blkdev_put(msc->bdev, BDEV_RAW);
+        }
+        // XXX this should be a wait for read_bh/write_bh to go to NULL
+        while (msc->read_bh.b_data) {
+                printk(KERN_INFO"%s: sleeping on read bh\n", __FUNCTION__);
+                sleep_on_timeout(&msc->msc_wq, 20);
+        }
+
+        while (msc->write_bh.b_data) {
+                printk(KERN_INFO"%s: sleeping on read bh\n", __FUNCTION__);
+                sleep_on_timeout(&msc->msc_wq, 20);
+        }
+
+        printk(KERN_INFO"%s: freeing read bh\n", __FUNCTION__);
+        __free_page((void *)&msc->read_bh.b_page);
+        msc->read_bh.b_page = NULL;
+
+        printk(KERN_INFO"%s: freeing write bh\n", __FUNCTION__);
+        __free_page((void *)&msc->write_bh.b_page);
+        msc->write_bh.b_page = NULL;
+
+        if (msc->usb_driver_registered) {
+                usbd_deregister_function (&function_driver);
+        }
+
+        msc_trace_exit("msctrace");
+        free_crc_table();
+}
+
+
+module_init (msc_modinit);
+module_exit (msc_modexit);
diff -uNr linux/drivers/no-otg/functions/msc/msc-scsi.h linux/drivers/otg/functions/msc/msc-scsi.h
--- linux/drivers/no-otg/functions/msc/msc-scsi.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/msc-scsi.h	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,795 @@
+/*
+ * otg/msc_fd/msc_scsi.h - mass storage protocol library header
+ *
+ *      Copyright(c) 2004, Belcarra
+ *
+ * Adapated from work:
+ *
+ *      Copyright (c) 2003 Lineo Solutions, Inc.
+ *
+ * Written by Shunnosuke kabata
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/*
+ *
+ * Documents
+ *      Universal Serial Bus Mass Storage Class - Specification Overview
+ *      Universal Serial Bus Mass Storage Class - Bulk-Only Transport
+ *      T10/1240-D - Information technology - Reduced Block Commands
+ *
+ * Notes
+ *
+ * 1. Reduced Block Command set C.f. Table 2 RBC
+ *
+ *                                              Command Support
+ *      Name                            OpCode  Fixed   Removable       Reference
+ *      Format Unit                     04h     O       O               RBC
+ *      Inquiry                         12h     M       M               SPC-2
+ *      Mode Select (6)                 15h     M       M               SPC-2
+ *      Mode Sense (6)                  1Ah     M       M               SPC-2
+ *      Perisstent Reserve In           5Eh     O       O               SPC-2
+ *      Persistent Reserve Out          5Fh     O       O               SPC-2
+ *      Prevent/Allow Medium Removal    1Eh     N/A     M               SPC-2
+ *      Read (10)                       28h     M       M               RBC
+ *      Read Capacity                   25h     M       M               RBC
+ *      Reelase (6)                     17h     O       O               SPC-2
+ *      Request Sense                   03h     O       O               SPC-2
+ *      Reserve (6)                     16h     O       O               SPC-2
+ *      Start Stop Unit                 1Bh     M       M               RBC
+ *      Synchronize Cache               35h     O       O               RBC
+ *      Test Unit Ready                 00h     M       M               SPC-2
+ *      Verify (10)                     2Fh     M       M               RBC
+ *      Write (10)                      2Ah     M       M               RBC
+ *      Write Buffer                    3Bh     M       O               SPC-2
+ *
+ * 2. Other commands seen?
+ *                                                      Sh      MV      FS
+ *      SCSI_REZERO_UNIT                     0x01       no
+ *      SCSI_READ_6                          0x08                       yes
+ *      SCSI_WRITE_6                         0x0a                       yes
+ *      SCSI_SEND_DIAGNOSTIC                 0x1d       no              yes
+ *      SCSI_READ_FORMAT_CAPACITY            0x23       yes             yes
+ *      SCSI_WRITE_AND_VERIFY                0x2e       no
+ *      SCSI_SEEK_10                         0x2b       no
+ *      SCSI_MODE_SELECT_10                  0x55       no      yes     yes
+ *      SCSI_READ_12                         0xa8       no              yes
+ *      SCSI_WRITE_12                        0xaa       no              yes
+ *
+ *
+ * 3. Status - C.f. Chapter 5 - RBC
+ *
+ *      Check Condition                 02h
+ *
+ *
+ * 4. Sense Keys - C.f. Chapter 5 - RBC
+ *      
+ *      Not Ready                       02h
+ *      Media Error                     03h
+ *      Illegal Request                 05h
+ *      Unit Attention                  06h
+ *
+ * 5. ASC/ASCQ - C.f. Chapter 5 - RBC
+ *
+ *      Logical Unit Not Ready                                          04h
+ *      Logical Unit Not Ready, Format in Progress                      04h,04h
+ *      Invalid Command Operation Code                                  20h
+ *      Invalide Field in CDB                                           24h
+ *      Format Command Failed                                           31h,01h
+ *      Status Notification / Power Management Class Event              38h,02h
+ *      Status Notification / Media Class Event                         38h,04h
+ *      Status Notification / Device Busy Class Event                   38h,06h
+ *      Low Power Condition Active                                      5Eh,00
+ *      Power Condition Change to Active                                5Eh,41h
+ *      Power Condition Change to Idle                                  5Eh,42h
+ *      Power Condition Change to Standby                               5Eh,43h
+ *      Power Condition Change to Sleep                                 5Eh,45h
+ *      Power Condition Change to Device Control                        5Eh,47h
+ *
+ * 6. ASCQ - C.f. Chapter 5 - RBC
+ *
+ *
+ *
+ * 7. Sense Keys C.f. Chapter 5 - RBC
+ *
+ * Command                      Status                  Sense Key      ASC/ASCQ
+ *
+ * 5.1 Format Unit
+ *   Format progress            Check Condition         Not Ready,      Logical Unit Note Ready, Format in Progress
+ *   Sueccsful completion       Check Condition         Unit Attention, Status Notification / Media Class Event
+ *   Failure                    Check Condition         Media error,    Format Command Failed
+ *
+ * 5.2 Read (10)
+ *
+ * 5.3 Read Capacity
+ *   No Media                   Check Condition         Not Ready,      Logical Unit Not Ready
+ *
+ * 5.4 Start Stop Unit
+ *   Power Consumption          Check Condition         Illegal Request,Low Power Condition Active
+ *
+ * 5.5 Synchronize Cache        Check Condition         Illegal Request,Invalid Command Operation Code
+ *
+ * 5.6 Write (10
+ *
+ * 5.7 Verify
+ *
+ * 5.8 Mode
+ * 
+ * 6.1 Inquiry
+ *
+ * 6.2 Mode Select (6)
+ *   Cannot Save                Check Condition         Illegal Request,Invalid Field in CDB
+ *
+ * 6.3 Mode Sense (6)
+ *
+ * 6.4 Prevent Allow Medium Removal
+ *
+ * 6.5 Request Sense
+ *
+ * 6.6 Test Unit Ready
+ *
+ * 6.7 Write Buffer
+ *
+ * 7.1 Unit Attention
+ *   Power Contition change     Check Condition         Unit Attention, Power Condition Change Notification
+ *
+ * 7.4.1 Event Status Sense
+ *
+ *   Power Management Event     Check Condition         Unit Attention, Event Status Notification / Power Managment
+ *   Media Class Event          Check Condition         Unit Attention, Event Status Notification / Media Class
+ *   Device Busy Event          Check Condition         Unit Attention, Event Status Notification / Device Busy Class
+ *
+ * 7.4.6 Removable Medium Device Initial Response
+ *   Ready                      Check Condition         Unit Attention, Event Status Notification / Media Class Event 
+ *   Power                      Check Condition         Unit Attention, Event Status Notification / Power Management Class Event
+ */
+
+#ifndef _MSCSCSIPROTO_H_
+#define _MSCSCSIPROTO_H_
+
+
+/*
+ * Class Specific Requests - C.f. MSC BO Chapter 3
+ */
+
+#define MSC_BULKONLY_RESET      0xff
+#define MSC_BULKONLY_GETMAXLUN  0xfe
+
+
+/*
+ * Class Code
+ */
+
+#define MASS_STORAGE_CLASS                  0x08
+
+/*
+ * MSC - Specification Overview
+ *
+ * SubClass Codes - C.f MSC Table 2.1
+ */
+
+#define MASS_STORAGE_SUBCLASS_RBC           0x01
+#define MASS_STORAGE_SUBCLASS_SFF8020I      0x02
+#define MASS_STORAGE_SUBCLASS_QIC157        0x03
+#define MASS_STORAGE_SUBCLASS_UFI           0x04
+#define MASS_STORAGE_SUBCLASS_SFF8070I      0x05
+#define MASS_STORAGE_SUBCLASS_SCSI          0x06
+
+/*
+ * Protocol - C.f MSC Table 3.1
+ */
+
+#define MASS_STORAGE_PROTO_CBI_WITH_COMP    0x00
+#define MASS_STORAGE_PROTO_CBI_NO_COMP      0x01
+#define MASS_STORAGE_PROTO_BULK_ONLY        0x50
+
+/*
+ * SCSI Command
+*/
+
+#define SCSI_TEST_UNIT_READY                    0x00
+#define SCSI_REQUEST_SENSE                      0x03
+#define SCSI_FORMAT_UNIT                        0x04
+#define SCSI_INQUIRY                            0x12
+#define SCSI_MODE_SELECT                        0x15    // aka MODE_SELECT_6
+#define SCSI_MODE_SENSE                         0x1a    // aka MODE_SENSE_6
+#define SCSI_START_STOP                         0x1b
+#define SCSI_PREVENT_ALLOW_MEDIA_REMOVAL        0x1e
+#define SCSI_READ_FORMAT_CAPACITY               0x23
+#define SCSI_READ_CAPACITY                      0x25
+#define SCSI_READ_10                            0x28
+#define SCSI_WRITE_10                           0x2a
+#define SCSI_VERIFY                             0x2f
+
+#define SCSI_READ_6                             0x08
+#define SCSI_WRITE_6                            0x0a
+#define SCSI_RESERVE                            0x16
+#define SCSI_RELEASE                            0x17
+#define SCSI_SEND_DIAGNOSTIC                    0x1d
+#define SCSI_SYNCHRONIZE_CACHE                  0x35
+#define SCSI_MODE_SENSE_10                      0x5a
+
+#define SCSI_REZERO_UNIT                        0x01
+#define SCSI_REASSIGN_BLOCKS                    0x07
+#define SCSI_COPY                               0x18
+#define SCSI_RECEIVE_DIAGNOSTIC_RESULTS         0x1c
+#define SCSI_WRITE_AND_VERIFY                   0x2e
+#define SCSI_PREFETCH                           0x34
+#define SCSI_READ_DEFECT_DATA                   0x37
+#define SCSI_COMPARE                            0x39
+#define SCSI_COPY_AND_VERIFY                    0x3a
+#define SCSI_WRITE_BUFFER                       0x3b
+#define SCSI_READ_BUFFER                        0x3c
+#define SCSI_READ_LONG                          0x3e
+#define SCSI_WRITE_LONG                         0x3f
+#define SCSI_CHANGE_DEFINITION                  0x40
+#define SCSI_WRITE_SAME                         0x41
+#define SCSI_LOG_SELECT                         0x4c
+#define SCSI_LOG_SENSE                          0x4d
+#define SCSI_XD_WRITE                           0x50
+#define SCSI_XP_WRITE                           0x51
+#define SCSI_XD_READ                            0x52
+#define SCSI_MODE_SELECT_10                     0x55
+#define SCSI_RESERVE_10                         0x56
+#define SCSI_RELEASE_10                         0x57
+#define SCSI_MODE_SELECT_10                     0x55
+#define SCSI_XD_WRITE_EXTENDED                  0x80
+#define SCSI_REBUILD                            0x81
+#define SCSI_REGENERATE                         0x82
+
+#define SCSI_SEEK_10                            0x2b
+#define SCSI_WRITE_AND_VERIFY                   0x2e
+#define SCSI_WRITE_12                           0xaa
+#define SCSI_READ_12                            0xa8
+
+/*
+ * Private
+ */
+#define SCSI_PRIVATE_PCS                        0xff
+
+/*
+ * SCSI Command Parameter
+ */
+
+#define CBW_SIGNATURE           0x43425355  /* USBC */
+#define CSW_SIGNATURE           0x53425355  /* USBS */
+
+#define PRODUCT_REVISION_LEVEL  "1.00"
+
+/*
+ * Command Block Status Values - C.f MSC BO Table 5.3
+ */
+
+#define USB_MSC_PASSED  0x00            // good
+#define USB_MSC_FAILED  0x01            // bad
+#define USB_MSC_PHASE_ERROR     0x02    // we want to be reset
+
+
+
+
+/*
+ * SCSI Sense 
+ *      SenseKey
+ *      AdditionalSenseCode
+ *      SenseCodeQualifier
+ */
+
+#define SCSI_ERROR_CURRENT                      0x70
+#define SCSI_ERROR_DEFERRED                     0x07
+
+/*
+ *  SCSI Sense Keys
+ */
+
+#define SK_NO_SENSE            0x00
+#define SK_RECOVERED_ERROR     0x01
+#define SK_NOT_READY           0x02
+#define SK_MEDIA_ERROR         0x03
+#define SK_HARDWARE_ERROR      0x04
+#define SK_ILLEGAL_REQUEST     0x05
+#define SK_UNIT_ATTENTION      0x06
+#define SK_DATA_PROTECT        0x07
+#define SK_BLANK_CHECK         0x08
+#define SK_COPY_ABORTED        0x0a
+#define SK_ABORTED_COMMAND     0x0b
+#define SK_VOLUME_OVERFLOW     0x0d
+#define SK_MISCOMPARE          0x0e
+
+/*
+ * 5. ASC/ASCQ - C.f. Chapter 5 - RBC
+ */
+
+#define SK(SenseKey,ASC,ASCQ) ((SenseKey<<16) | (ASC << 8) | (ASCQ))
+
+#define SCSI_SENSEKEY_NO_SENSE                          SK(SK_NO_SENSE,         0x00,0x00)      // 0x000000
+
+#define SCSI_FAILURE_PREDICTION_THRESHOLD_EXCEEDED      SK(SK_RECOVERED_ERROR,  0x5d,0x00)      // 0x015d00
+
+#define SCSI_SENSEKEY_LOGICAL_UNIT_NOT_READY            SK(SK_NOT_READY,        0x04,0x00)      // 0x020400
+#define SCSI_SENSEKEY_FORMAT_IN_PROGRESS                SK(SK_NOT_READY,        0x04,0x04)      // 0x020404
+#define SCSI_SENSEKEY_MEDIA_NOT_PRESENT                 SK(SK_NOT_READY,        0x3a,0x00)      // 0x023a00
+
+#define SCSI_SENSEKEY_WRITE_ERROR                       SK(SK_MEDIA_ERROR,      0x0c,0x02)      // 0x030c02
+#define SCSI_SENSEKEY_UNRECOVERED_READ_ERROR            SK(SK_MEDIA_ERROR,      0x11,0x00)      // 0x031100
+#define SCSI_FORMAT_COMMAND_FAILED                      SK(SK_MEDIA_ERROR,      0x31,0x01)      // 0x033101
+
+#define SCSI_SENSEKEY_COMMUNICATION_FAILURE             SK(SK_HARDWARE_ERROR,   0x08,0x00)       // 0x040800
+
+#define SCSI_SENSEKEY_INVALID_COMMAND                   SK(SK_ILLEGAL_REQUEST,  0x20,0x00)      // 0x052000
+#define SCSI_SENSEKEY_BLOCK_ADDRESS_OUT_OF_RANGE        SK(SK_ILLEGAL_REQUEST,  0x21,0x00)      // 0x052100
+#define SCSI_SENSEKEY_INVALID_FIELD_IN_CDB              SK(SK_ILLEGAL_REQUEST,  0x24,0x00)      // 0x052400
+#define SCSI_SENSEKEY_LOGICAL_UNIT_NOT_SUPPORTED        SK(SK_ILLEGAL_REQUEST,  0x25,0x00)      // 0x052500
+#define SCSI_SENSEKEY_SAVING_PARAMETERS_NOT_SUPPORTED   SK(SK_ILLEGAL_REQUEST,  0x39,0x00)      // 0x053900
+#define SCSI_MEDIA_REMOVAL_PREVENTED                    SK(SK_ILLEGAL_REQUEST,  0x53,0x02)      // 0x055302
+
+#define SCSI_SENSEKEY_NOT_READY_TO_READY_CHANGE         SK(SK_UNIT_ATTENTION,   0x28,0x00)      // 0x062800
+#define SCSI_SENSEKEY_RESET_OCCURRED                    SK(SK_UNIT_ATTENTION,   0x29,0x00)      // 0x062900
+
+#define SCSI_SENSEKEY_STATUS_NOTIFICATION_POWER_CLASS   SK(SK_UNIT_ATTENTION,   0x38,0x02)      // 0x063802
+#define SCSI_SENSEKEY_STATUS_NOTIFICATION_MEDIA_CLASS   SK(SK_UNIT_ATTENTION,   0x38,0x04)      // 0x063804
+#define SCSI_SENSEKEY_STATUS_NOTIFICATION_DEVICE_BUSY   SK(SK_UNIT_ATTENTION,   0x38,0x06)      // 0x063806
+
+#define SCSI_SENSEKEY_LOW_POWER_CONDITION_ACTIVE        SK(SK_UNIT_ATTENTION,   0x5e,0x00)      // 0x065e00
+#define SCSI_SENSEKEY_POWER_CONDITION_CHANGE_TO_ACTIVE  SK(SK_UNIT_ATTENTION,   0x5e,0x41)      // 0x065e41
+#define SCSI_SENSEKEY_POWER_CONDITION_CHANGE_TO_IDLE    SK(SK_UNIT_ATTENTION,   0x5e,0x42)      // 0x065e42
+#define SCSI_SENSEKEY_POWER_CONDITION_CHANGE_TO_STANDBY SK(SK_UNIT_ATTENTION,   0x5e,0x43)      // 0x065e43
+#define SCSI_SENSEKEY_POWER_CONDITION_CHANGE_TO_SLEEP   SK(SK_UNIT_ATTENTION,   0x5e,0x45)      // 0x065e45
+#define SCSI_SENSEKEY_POWER_CONDITION_CHANGE_TO_DEVICE  SK(SK_UNIT_ATTENTION,   0x5e,0x47)      // 0x065e47
+
+
+#define SCSI_SENSEKEY_WRITE_PROTECTED                   SK(SK_DATA_PROTECT,     0x27,0x00)      // 0x072700
+
+
+/*
+ * Mode Page Code and Page Control
+ */
+#define SCSI_MODEPAGE_CONTROL_CURRENT           0x0
+#define SCSI_MODEPAGE_CONTROL_CHANGEABLE        0x1
+#define SCSI_MODEPAGE_CONTROL_DEFAULT           0x2
+#define SCSI_MODEPAGE_CONTROL_SAVED             0x3
+
+#define SCSI_MODEPAGE_UNIT_ATTENTION            0x00
+#define SCSI_MODEPAGE_ERROR_RECOVERY            0x01
+#define SCSI_MODEPAGE_DISCONNNECT_RECONNECT     0x02
+#define SCSI_MODEPAGE_FORMAT                    0x03
+#define SCSI_MODEPAGE_RIGID_DRIVE_GEOMETRY      0x04
+#define SCSI_MODEPAGE_FLEXIBLE_DISK_PAGE        0x05    // check
+#define SCSI_MODEPAGE_VERIFY_ERROR_RECOVERY     0x07
+#define SCSI_MODEPAGE_CACHING                   0x08
+#define SCSI_MODEPAGE_CONTROL_MODE              0x0a
+#define SCSI_MODEPAGE_NOTCH_AND_PARTITION       0x0c
+#define SCSI_MODEPAGE_POWER_CONDITION           0x0d
+#define SCSI_MODEPAGE_XOR                       0x10
+#define SCSI_MODEPAGE_CONTROL_MODE_ALIAS        0x1a
+#define SCSI_MODEPAGE_REMOVABLE_BLOCK_ACCESS    0x1b// check
+#define SCSI_MODEPAGE_INFORMATION_EXCEPTIONS    0x1c
+#define SCSI_MODEPAGE_ALL_SUPPORTED             0x3f
+
+
+
+/*
+ * Command Block Wrapper / Command Status Wrapper
+ */
+
+/*
+ * Command Block Wrapper
+ */
+typedef struct{
+        unsigned long   dCBWSignature;
+        unsigned long   dCBWTag;
+        unsigned long   dCBWDataTransferLength;
+        u8   bmCBWFlags;
+        u8   bCBWLUN:4,
+             Reserved:4;
+        u8   bCBWCBLength:5,
+             Reserved2:3;
+        u8   CBWCB[16];
+} __attribute__((packed)) COMMAND_BLOCK_WRAPPER;
+
+/*
+ * Command Status Wrapper
+ */
+typedef struct{
+        unsigned long   dCSWSignature;
+        unsigned long   dCSWTag;
+        unsigned long   dCSWDataResidue;
+        u8   bCSWStatus;
+} __attribute__((packed)) COMMAND_STATUS_WRAPPER;
+
+/*
+ * SCSI Command
+ */
+
+/*
+ * INQUIRY
+ */
+
+typedef struct{
+        u8   OperationCode;
+        u8   EnableVPD:1,
+             Reserved1:4,
+             LogicalUnitNumber:3;
+        u8   PageCode;
+        u8   Reserved2;
+        u8   AllocationLength;
+        u8   Reserved3;
+        u8   Reserved4;
+        u8   Reserved5;
+        u8   Reserved6;
+        u8   Reserved7;
+        u8   Reserved8;
+        u8   Reserved9;
+} __attribute__((packed)) SCSI_INQUIRY_COMMAND;
+
+typedef struct{
+        u8   PeripheralDeviceType:5,
+             PeripheralQaulifier:3;
+        u8   Reserved2:7,
+             RMB:1;
+        u8   ANSIVersion:3,
+             ECMAVersion:3,
+             ISOVersion:2;
+        u8   ResponseDataFormat:4,
+             Reserved3:4;
+        u8   AdditionalLength;
+        u8   Reserved4;
+        u8   Reserved5;
+        u8   Reserved6;
+        u8   VendorInformation[8];
+        u8   ProductIdentification[16];
+        u8   ProductRevisionLevel[4];
+} __attribute__((packed)) SCSI_INQUIRY_DATA;
+
+/*
+ * READ FORMAT CAPACITY
+ */
+
+typedef struct{
+        u8   OperationCode;
+        u8   Reserved1:5,
+             LogicalUnitNumber:3;
+        u8   Reserved2;
+        u8   Reserved3;
+        u8   Reserved4;
+        u8   Reserved5;
+        u8   Reserved6;
+        u16  AllocationLength;
+        u8   Reserved7;
+        u8   Reserved8;
+        u8   Reserved9;
+} __attribute__((packed)) SCSI_READ_FORMAT_CAPACITY_COMMAND;
+
+typedef struct{
+        struct{
+                u8   Reserved1;
+                u8   Reserved2;
+                u8   Reserved3;
+                u8   CapacityListLength;
+        } __attribute__((packed)) CapacityListHeader;
+
+        struct{
+                u32  NumberofBlocks;
+                u8   DescriptorCode:2,
+                     Reserved1:6;
+                u8   BlockLength[3];
+        } __attribute__((packed)) CurrentMaximumCapacityDescriptor;
+
+} __attribute__((packed)) SCSI_READ_FORMAT_CAPACITY_DATA;
+
+/*
+ * READ FORMAT CAPACITY
+ */
+
+typedef struct{
+        u8   OperationCode;
+        u8   RelAdr:1, 
+             Reserved1:4, 
+             LogicalUnitNumber:3;
+        u32  LogicalBlockAddress;
+        u8   Reserved2;
+        u8   Reserved3;
+        u8   PMI:1, 
+             Reserved4:7;
+        u8   Reserved5;
+        u8   Reserved6;
+        u8   Reserved7;
+} __attribute__((packed)) SCSI_READ_CAPACITY_COMMAND;
+
+typedef struct{
+        u32   LastLogicalBlockAddress;
+        u32   BlockLengthInBytes;
+} __attribute__((packed)) SCSI_READ_CAPACITY_DATA;
+
+/*
+ * REQUEST SENSE
+ */
+
+typedef struct{
+        u8   OperationCode;
+        u8   Reserved1:5, 
+             LogicalUnitNumber:3;
+        u8   Reserved2;
+        u8   Reserved3;
+        u8   AllocationLength;
+        u8   Reserved4;
+        u8   Reserved5;
+        u8   Reserved6;
+        u8   Reserved7;
+        u8   Reserved8;
+        u8   Reserved9;
+        u8   Reserved10;
+} __attribute__((packed)) SCSI_REQUEST_SENSE_COMMAND;
+
+typedef struct{
+        u8   ErrorCode:7, 
+             Valid:1;
+        u8   Reserved1;
+        u8   SenseKey:4, 
+             Reserved2:4;
+        u32  Information;
+        u8   AdditionalSenseLength;
+        u8   Reserved3[4];
+        u8   AdditionalSenseCode;
+        u8   AdditionalSenseCodeQualifier;
+        u8   Reserved4;
+        u8   Reserved5[3];
+} __attribute__((packed)) SCSI_REQUEST_SENSE_DATA;
+
+/*
+ * READ(10)
+ */
+
+typedef struct{
+        u8   OperationCode;
+        u8   RelAdr:1, 
+             Reserved1:2, 
+             FUA:1, 
+             DPO:1, 
+             LogicalUnitNumber:3;
+        u32  LogicalBlockAddress;
+        u8   Reserved2;
+        u16  TransferLength;
+        u8   Reserved3;
+        u8   Reserved4;
+        u8   Reserved5;
+} __attribute__((packed)) SCSI_READ_10_COMMAND;
+
+/*
+ * MODE SENSE
+ */
+typedef struct{
+        u8   OperationCode;
+        u8   Reserved1:3, 
+             DBD:1, 
+             Reserved2:1, 
+             LogicalUnitNumber:3; 
+        u8   PageCode:6, 
+             PageControl:2;          // PC
+        u8   Reserved3;
+        u8   Reserved4;
+        u8   Reserved5;
+        u8   Reserved6;
+        u16   ParameterListLength;
+        u8   Reserved7;
+        u8   Reserved8;
+        u8   Reserved9;
+} __attribute__((packed)) SCSI_MODE_SENSE_COMMAND;
+
+typedef struct{
+        u8   ModeDataLength;
+        u8   MediumTypeCode;
+        u8   Reserved1:4,
+             DPOFUA:1,
+             Reserved2:2,
+             WriteProtect:1;
+        u8   Reserved3;
+} __attribute__((packed)) MODE_PARAMETER_HEADER;
+
+typedef struct{
+        u8   PageCode:6,
+             Reserved1:1,
+             PS:1;
+        u8   PageLength;
+        u8   DCR:1,
+             Reserved2:1,
+             PER:1,
+             Reserved3:1,
+             RC:1,
+             Reserved4:1,
+             Reserved5:1,
+             AWRE:1;
+        u8   ReadRetryCount;
+        u8   Reserved6[4];
+        u8   WriteRetryCount;
+        u8   Reserved7[3];
+} __attribute__((packed)) READ_WRITE_ERROR_RECOVERY_PAGE;
+
+typedef struct{
+        u8   PageCode:6,
+             Reserved1:1,
+             PS:1;
+        u8   PageLength;
+        u16  TransferRate;
+        u8   NumberofHeads;
+        u8   SectorsperTrack;
+        u16  DataBytesperSector;
+        u16  NumberofCylinders;
+        u8   Reserved2[9];
+        u8   MotorOnDelay;
+        u8   MotorOffDelay;
+        u8   Reserved3[7];
+        u16  MediumRotationRate;
+        u8   Reserved4;
+        u8   Reserved5;
+} __attribute__((packed)) FLEXIBLE_DISK_PAGE;
+
+typedef struct{
+        u8   PageCode:6,
+             Reserved1:1,
+             PS:1;
+        u8   PageLength;
+        u8   Reserved2:6,
+             SRFP:1,
+             SFLP:1;
+        u8   TLUN:3,
+             Reserved3:3,
+             SML:1,
+             NCD:1;
+        u8   Reserved4[8];
+} __attribute__((packed)) REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE;
+
+typedef struct{
+        u8   PageCode:6,
+             Reserved1:1,
+             PS:1;
+        u8   PageLength;
+        u8   Reserved2;
+        u8   InactivityTimeMultiplier:4,
+             Reserved3:4;
+        u8   SWPP:1,
+             DISP:1,
+             Reserved4:6;
+        u8   Reserved5;
+        u8   Reserved6;
+        u8   Reserved7;
+} __attribute__((packed)) TIMER_AND_PROTECT_PAGE;
+
+typedef struct{
+        READ_WRITE_ERROR_RECOVERY_PAGE              ReadWriteErrorRecoveryPage;
+        FLEXIBLE_DISK_PAGE                          FlexibleDiskPage;
+        REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE    RemovableBlockAccessCapabilitiesPage;
+        TIMER_AND_PROTECT_PAGE                      TimerAndProtectPage;
+} __attribute__((packed)) MODE_ALL_PAGES;
+
+typedef struct{
+        MODE_PARAMETER_HEADER   ModeParameterHeader;
+        union{
+            READ_WRITE_ERROR_RECOVERY_PAGE              ReadWriteErrorRecoveryPage;
+            FLEXIBLE_DISK_PAGE                          FlexibleDiskPage;
+            REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE    RemovableBlockAccessCapabilitiesPage;
+            TIMER_AND_PROTECT_PAGE                      TimerAndProtectPage;
+            MODE_ALL_PAGES                              ModeAllPages;
+        } __attribute__((packed)) ModePages;
+} __attribute__((packed)) SCSI_MODE_SENSE_DATA;
+
+/*
+ * TEST UNIT READY
+ */
+
+typedef struct{
+        u8   OperationCode;
+        u8   Reserved1:5,
+             LogicalUnitNumber:3;
+        u8   Reserved2;
+        u8   Reserved3;
+        u8   Reserved4;
+        u8   Reserved5;
+        u8   Reserved6;
+        u8   Reserved7;
+        u8   Reserved8;
+        u8   Reserved9;
+        u8   Reserved10;
+        u8   Reserved11;
+} __attribute__((packed)) SCSI_TEST_UNIT_READY_COMMAND;
+
+/*
+ * PREVENT-ALLOW MEDIA REMOVAL
+ */
+
+typedef struct{
+        u8   OperationCode;
+        u8   Reserved1:5,
+             LogicalUnitNumber:3;
+        u8   Reserved2;
+        u8   Reserved3;
+        u8   Prevent:2,
+             Reserved4:6;
+        u8   Reserved5;
+        u8   Reserved6;
+        u8   Reserved7;
+        u8   Reserved8;
+        u8   Reserved9;
+        u8   Reserved10;
+        u8   Reserved11;
+} __attribute__((packed)) SCSI_PREVENT_ALLOW_MEDIA_REMOVAL_COMMAND;
+
+/*
+ * START-STOP UNIT
+ */
+
+typedef struct{
+        u8   OperationCode;
+        u8   IMMED:1,
+             Reserved1:4,
+             LogicalUnitNumber:3;
+        u8   Reserved2;
+        u8   Reserved3;
+        u8   Start:1,
+             LoEj:1,
+             Reserved4:2,
+             PowerConditions:4;
+        u8   Reserved5;
+        u8   Reserved6;
+        u8   Reserved7;
+        u8   Reserved8;
+        u8   Reserved9;
+        u8   Reserved10;
+        u8   Reserved11;
+} __attribute__((packed)) SCSI_START_STOP_COMMAND;
+
+/*
+ * WRITE(10)
+ */
+
+typedef struct{
+        u8   OperationCode;
+        u8   RelAdr:1,
+             Reserved1:2,
+             FUA:1,
+             DPO:1,
+             LogicalUnitNumber:3;
+        u32  LogicalBlockAddress;
+        u8   Reserved2;
+        u16  TransferLength;
+        u8   Reserved3;
+        u8   Reserved4;
+        u8   Reserved5;
+} __attribute__((packed)) SCSI_WRITE_10_COMMAND;
+
+/*
+ * VERIFY
+ */
+
+typedef struct{
+        u8   OperationCode;
+        u8   RelAdr:1,
+             ByteChk:1,
+             Reserved1:1,
+             Reserved2:1,
+             DPO:1,
+             LogicalUnitNumber:3;
+        u32  LogicalBlockAddress;
+        u8   Reserved3;
+        u16  VerificationLength;
+        u8   Reserved4;
+        u8   Reserved5;
+        u8   Reserved6;
+} __attribute__((packed)) SCSI_VERIFY_COMMAND;
+
+#endif  /* _MSCSCSIPROTO_H_ */
+
diff -uNr linux/drivers/no-otg/functions/msc/msc.h linux/drivers/otg/functions/msc/msc.h
--- linux/drivers/no-otg/functions/msc/msc.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/msc.h	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,141 @@
+/*
+ * otg/function/msc/msc.h - Mass Storage Class
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @defgroup MSCFunction Mass Storage 
+ * @ingroup functiongroup
+ */
+/*!
+ * @file otg/functions/msc/msc.h
+ * @brief Mass Storage Driver private defines
+ *
+ *
+ * @ingroup MSCFunction
+ */
+
+#ifndef MSC_H
+#define MSC_H 1
+
+extern otg_tag_t msc_fd_trace_tag;
+#define MSC msc_fd_trace_tag
+
+/*
+ * Command/Data/Status Flow
+ * C.f. 5 - Figure 1 
+ */
+
+typedef enum msc_state {
+        MSC_READY,
+        MSC_DATA_OUT_WRITE,
+        MSC_DATA_OUT_WRITE_FINISHED,
+        MSC_DATA_IN_READ,
+        MSC_DATA_IN_READ_FINISHED,
+        MSC_STATUS,
+        MSC_QUERY,
+        MSC_PHASE_ERROR,
+        MSC_UNKNOWN
+} msc_state_t;
+
+
+/*
+ * Device Transfer state
+ * C.F. Table 6.1
+ */
+
+typedef enum msc_device_state {
+        MSC_DEVICE_DN,                  // The device intends to transfer no data
+        MSC_DEVICE_DI,                  // The device intends to send data to the host
+        MSC_DEVICE_DO,                  // The device intents to received data from the host
+} msc_device_state_t;
+
+#define MSC_INACTIVE            0x0000
+#define MSC_BLOCKIO_PENDING     0x0001
+#define MSC_BLOCKIO_FINISHED    0x0002
+#define MSC_RECV_PENDING        0x0010
+#define MSC_RECV_FINISHED       0x0020
+#define MSC_SEND_PENDING        0x0040
+#define MSC_SEND_FINISHED       0x0080
+#define MSC_IOCTL_WAITING       0x0100          // there is an ioctl call waiting for I/O completion
+#define MSC_ABORT_IO            0x0200          // please abort current i/o
+
+#if 0
+struct SPC_inquiry_cdb {
+        u8            OperationCode; /* 12H */
+        u8            EnableVPD:1;
+        u8            CmdSupportData:1;
+        u8            Reserved0:6;
+        u8            PageCode;
+        u8            Reserved1;
+        u8            AllocationLen;
+        u8            Control;
+} __attribute__((packed));
+#endif
+
+struct msc_private {
+        struct usbd_function_instance *function;
+
+        int                     usb_driver_registered;  // non-zero if usb function registered
+        unsigned char           connected;              // non-zero if connected to host (configured)
+
+        struct usbd_urb         *rcv_urb_finished;
+
+        struct buffer_head      read_bh;
+        struct buffer_head      write_bh;
+
+	u16                     read_pending;
+	u16                     write_pending;
+
+        msc_device_state_t      device_state;
+        msc_state_t             command_state;          // current command state
+        u16                     io_state;               // current IO state
+
+        COMMAND_BLOCK_WRAPPER   command;
+
+        u32                     lba;                    // next lba to read/write from
+        u32                     transfer_blocks;
+        u32                     TransferLength_in_blocks;       // amount of transfer remaining
+        u32                     TransferLength_in_bytes;        // amount of transfer remaining
+        u32                     data_transferred_in_bytes;       // amount of data actually transferred
+
+        int                     major;
+        int                     minor;
+        kdev_t                  dev;
+        struct block_device    *bdev;
+        u32                     block_size;
+        u32                     capacity;                      
+        u32                     max_blocks;                      
+
+        int                     uptodate;
+
+        wait_queue_head_t       msc_wq;
+        wait_queue_head_t       ioctl_wq;
+
+        u32                     status;
+        u32                     block_dev_state;
+        u32                     sensedata;
+        u32                     info;
+};
+
+
+/*
+ * MSC Configuration
+ *
+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
+ */
+
+#define BULK_OUT        0x00
+#define BULK_IN         0x01
+#define ENDPOINTS       0x02
+
+extern struct usbd_function_operations function_ops;
+extern struct usbd_function_driver function_driver;
+
+
+#endif
diff -uNr linux/drivers/no-otg/functions/msc/scripts/test1 linux/drivers/otg/functions/msc/scripts/test1
--- linux/drivers/no-otg/functions/msc/scripts/test1	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/scripts/test1	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# Basic Start/Stop test 
+#  
+#
+# 1. Wait for connection
+# 2. loop making block device available for 10 second intervals 
+# 3. exit if disconnected
+#
+
+MAJOR=7
+MINOR=0
+
+TIMEOUT=5
+
+set -x
+
+# wait for connection
+msc_check connect
+
+while sleep 1
+do
+
+        # make block device available
+        msc_check start $MAJOR $MINOR
+        
+        sleep $TIMEOUT
+
+        # make block device un-available
+        msc_check stop 
+
+        sleep $TIMEOUT
+
+        msc_check connected || break
+
+done
+
diff -uNr linux/drivers/no-otg/functions/msc/scripts/test2 linux/drivers/otg/functions/msc/scripts/test2
--- linux/drivers/no-otg/functions/msc/scripts/test2	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/scripts/test2	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# Basic Start/Stop test on connect/disconnect.
+#
+# Loop
+#       1. wait for connection
+#       2. making block device available for 10 seconds
+#       3. wait for disconnect 
+#       4. continue
+#
+
+MAJOR=7
+MINOR=0
+
+TIMEOUT=5
+
+set -x
+
+while sleep 1
+do
+        # wait for connection
+        msc_check connect
+
+        # make block device available
+        msc_check start $MAJOR $MINOR
+        
+        sleep $TIMEOUT
+
+        # make block device un-available
+        msc_check stop 
+
+        msc_check disconnect
+
+done
+
diff -uNr linux/drivers/no-otg/functions/msc/scripts/test3 linux/drivers/otg/functions/msc/scripts/test3
--- linux/drivers/no-otg/functions/msc/scripts/test3	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/scripts/test3	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# Force connect/disconnect with start/stop.
+#
+# 1. loop making block device available for 10 second intervals 
+# 2. exit if disconnected
+# 3. start
+# 4. stop
+# 5. force disconnect
+#
+
+MAJOR=7
+MINOR=0
+
+TIMEOUT=5
+
+set -x
+
+while sleep 1
+do
+
+        # bus request
+        otgd bus_req
+
+        # wait for connection
+        msc_check connect
+
+        # make block device available
+        msc_check start $MAJOR $MINOR
+        
+        sleep $TIMEOUT
+
+        # make block device un-available
+        msc_check stop 
+
+        sleep $TIMEOUT
+
+        # bus request/
+        otgd bus_req/
+
+        msc_check disconnect 
+
+        sleep $TIMEOUT
+
+done
+
diff -uNr linux/drivers/no-otg/functions/msc/scripts/test4 linux/drivers/otg/functions/msc/scripts/test4
--- linux/drivers/no-otg/functions/msc/scripts/test4	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/scripts/test4	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# Force connect/disconnect without start/stop.
+#
+#
+# 1. loop making block device available for 10 second intervals 
+# 2. exit if disconnected
+# 3. force disconnect
+# 4. force connect
+#
+
+MAJOR=7
+MINOR=0
+
+TIMEOUT=5
+
+set -x
+
+# make block device available
+msc_check start $MAJOR $MINOR
+
+
+while sleep 1
+do
+
+        # bus request
+        otgd bus_req
+
+        # wait for connection
+        msc_check connect
+
+        sleep $TIMEOUT
+
+        sleep $TIMEOUT
+
+        # bus request/
+        otgd bus_req/
+
+        msc_check disconnect 
+
+        sleep $TIMEOUT
+
+done
+
+# make block device un-available
+msc_check stop 
+
diff -uNr linux/drivers/no-otg/functions/msc/scripts/test5 linux/drivers/otg/functions/msc/scripts/test5
--- linux/drivers/no-otg/functions/msc/scripts/test5	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/scripts/test5	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# Force connect/disconnect with start/stop.
+#
+# 1. loop making block device available for 10 second intervals 
+# 2. exit if disconnected
+# 3. start
+# 4. force disconnect
+# 5. stop
+# 6. force connect
+#
+
+MAJOR=7
+MINOR=0
+
+TIMEOUT=5
+
+set -x
+
+while sleep 1
+do
+
+        # bus request
+        otgd bus_req
+
+        # wait for connection
+        msc_check connect
+
+        # make block device available
+        msc_check start $MAJOR $MINOR
+        
+        sleep $TIMEOUT
+
+        # bus request/
+        otgd bus_req/
+
+        # make block device un-available
+        msc_check stop 
+
+        sleep $TIMEOUT
+
+        msc_check disconnect 
+
+        sleep $TIMEOUT
+
+done
+
diff -uNr linux/drivers/no-otg/functions/msc/trace.c linux/drivers/otg/functions/msc/trace.c
--- linux/drivers/no-otg/functions/msc/trace.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/trace.c	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,340 @@
+/*
+ * otg/msc_fd/trace.c
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * Adapted from earlier work:
+ *      Copyright (c) 2002, 2003 Belcarra
+ *      Copyright (c) 2002 Lineo
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+
+#include <linux/proc_fs.h>
+
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/cache.h>
+
+
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+
+#include <usbp-chap9.h>
+#include <usbp-mem.h>
+#include <usbp-func.h>
+#include "msc-scsi.h"
+#include "msc.h"
+#include "trace.h"
+
+
+static struct msc_private *msc_private;
+int msc_trace_first;
+int msc_trace_next;
+msc_trace_t *msc_traces;
+
+extern int msc_interrupts;
+
+
+#if defined(CONFIG_OTG_MSC_REGISTER_TRACE) && defined(CONFIG_PROC_FS)
+
+msc_trace_t *MSC_TRACE_NEXT(msc_trace_types_t msc_trace_type)
+{
+        msc_trace_t *p;
+
+        p = msc_traces + msc_trace_next;
+
+        if (msc_private) {
+                p->ticks = usbd_ticks(msc_private->function);
+                p->sofs = usbd_framenum(msc_private->function);
+        }
+        p->interrupts = msc_interrupts;
+        p->msc_trace_type = msc_trace_type;
+
+        msc_trace_next++;
+        msc_trace_next = (msc_trace_next == TRACE_MAX) ? 0 : msc_trace_next;
+
+        if (msc_trace_next == msc_trace_first) {
+                msc_trace_first++;
+                msc_trace_first = (msc_trace_first == TRACE_MAX) ? 0 : msc_trace_first;
+        }
+
+        return p;
+}
+
+/* Proc Filesystem *************************************************************************** */
+        
+/* *    
+ * msc_trace_proc_read - implement proc file system read.
+ * @file        
+ * @buf         
+ * @count
+ * @pos 
+ *      
+ * Standard proc file system read function.
+ */         
+static ssize_t msc_trace_proc_read (struct file *file, char *buf, size_t count, loff_t * pos)
+{                                  
+        unsigned long page;
+        int len = 0;
+        int index;
+        int oindex;
+        int previous;
+
+        MOD_INC_USE_COUNT;
+        // get a page, max 4095 bytes of data...
+        if (!(page = get_free_page (GFP_KERNEL))) {
+                MOD_DEC_USE_COUNT;
+                return -ENOMEM;
+        }
+
+        len = 0;
+        oindex = index = (*pos)++;
+
+        if (index == 0) 
+                len += sprintf ((char *) page + len, " Index     Ints     Ticks\n");
+               
+                         
+        index += msc_trace_first;
+        if (index >= TRACE_MAX) 
+                index -= TRACE_MAX;
+        
+        previous = (index) ? (index - 1) : (TRACE_MAX - 1);
+
+
+        if (
+                        ((msc_trace_first < msc_trace_next) && (index >= msc_trace_first) && (index < msc_trace_next)) ||
+                        ((msc_trace_first > msc_trace_next) && ((index < msc_trace_next) || (index >= msc_trace_first)))
+           )
+        {
+
+                u64 ticks = 0;
+
+                msc_trace_t *p = msc_traces + index;
+                unsigned char *cp;
+                unsigned int *ip;
+                int skip = 0;
+
+                if (oindex > 0) {
+                        msc_trace_t *o = msc_traces + previous;
+
+                        if (o->ticks) 
+                                ticks = (p->ticks > o->ticks) ? (p->ticks - o->ticks) : (o->ticks - p->ticks) ;
+
+                        if (o->interrupts != p->interrupts) 
+                                skip++;
+                        
+                }
+                
+                //printk(KERN_INFO"index: %d interrupts: %d\n", index, p->interrupts);
+                len += sprintf ((char *) page + len, "%s%6d %8d ", skip?"\n":"", index, p->interrupts);
+
+                if (ticks > 1024*1024) 
+                        len += sprintf ((char *) page + len, "%8dM ", ticks>>20);
+                else 
+                        len += sprintf ((char *) page + len, "%8d  ", ticks);
+                
+                len += sprintf ((char *) page + len, "%6d  ", (int)p->sofs);
+
+                switch (p->msc_trace_type) {
+                case msc_trace_msg:
+                        len += sprintf ((char *) page + len, " --                   ");
+                        len += sprintf ((char *) page + len, p->trace.msg.msg);
+                        break;
+
+                case msc_trace_w:
+                        len += sprintf ((char *) page + len, " -->                  ");
+                        len += sprintf ((char *) page + len, "[%8x] W %s", p->trace.msg32.val, p->trace.msg32.msg);
+                        break;
+
+                case msc_trace_r:
+                        len += sprintf ((char *) page + len, "<--                   ");
+                        len += sprintf ((char *) page + len, "[%8x] R %s", p->trace.msg32.val, p->trace.msg32.msg);
+                        break;
+
+                case msc_trace_msg32:
+                        len += sprintf ((char *) page + len, " --                   ");
+                        len += sprintf ((char *) page + len, p->trace.msg32.msg, p->trace.msg32.val);
+                        break;
+
+                case msc_trace_msg16:
+                        len += sprintf ((char *) page + len, " --                   ");
+                        len += sprintf ((char *) page + len, p->trace.msg16.msg, p->trace.msg16.val0, p->trace.msg16.val1);
+                        break;
+
+                case msc_trace_msg8:
+                        len += sprintf ((char *) page + len, " --                   ");
+                        len += sprintf ((char *) page + len, p->trace.msg8.msg, 
+                                        p->trace.msg8.val0, p->trace.msg8.val1, p->trace.msg8.val2, p->trace.msg8.val3);
+                        break;
+
+                case msc_trace_setup:
+                        cp = (unsigned char *)&p->trace.setup;
+                        len += sprintf ((char *) page + len, 
+                                        " --           request [%02x %02x %02x %02x %02x %02x %02x %02x]", 
+                                        cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+                        break;
+
+                case msc_trace_recv:
+                case msc_trace_sent:
+                        cp = (unsigned char *)&p->trace.sent;
+                        len += sprintf ((char *) page + len, 
+                                        "%s             %s [%02x %02x %02x %02x %02x %02x %02x %02x]", 
+                                        ( p->msc_trace_type == msc_trace_recv)?"<-- ":" -->",
+                                        ( p->msc_trace_type == msc_trace_recv)?"recv":"sent",
+                                        cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+                        break;
+                case msc_trace_rlba:
+                        ip = (unsigned int *)&p->trace.ints;
+                        len += sprintf ((char *) page + len, 
+                                        "%s             %s [%8x %08x]", 
+                                        "<-- ", "rlba", ip[0], ip[1]);
+                        break;
+                case msc_trace_slba:
+                case msc_trace_tlba:
+                        ip = (unsigned int *)&p->trace.ints;
+                        len += sprintf ((char *) page + len, 
+                                        "%s             %s [%8x %08x]", " -->",
+                                        ( p->msc_trace_type == msc_trace_tlba)?"tlba":"slba",
+                                        ip[0], ip[1]);
+                        break;
+
+                case msc_trace_tag:
+                        ip = (unsigned int *)&p->trace.ints;
+                        len += sprintf ((char *) page + len, 
+                                        "%s             TAG: %8x FRAME: %03x", " -->",
+                                        ip[0], ip[1]);
+                        break;
+
+                case msc_trace_sense:
+                        ip = (unsigned int *)&p->trace.ints;
+                        len += sprintf ((char *) page + len, 
+                                        "%s             SENSE: %06x INFO: %08x", " -->",
+                                        ip[0], ip[1]);
+                        break;
+
+                case msc_trace_cbw:
+                        len += sprintf ((char *) page + len, " -->                  ");
+                        len += sprintf ((char *) page + len, "%s %02x", p->trace.msg32.msg, p->trace.msg32.val);
+                        break;
+                }
+                len += sprintf ((char *) page + len, "\n");
+        }
+
+        if ((len > count) || (len == 0))
+                len = -EINVAL;
+        else if (len > 0 && copy_to_user (buf, (char *) page, len)) 
+                len = -EFAULT;
+        
+        free_page (page);
+        MOD_DEC_USE_COUNT;
+        return len;
+}
+
+/* *
+ * msc_trace_proc_write - implement proc file system write.
+ * @file
+ * @buf
+ * @count
+ * @pos
+ *
+ * Proc file system write function, used to signal monitor actions complete.
+ * (Hotplug script (or whatever) writes to the file to signal the completion
+ * of the script.)  An ugly hack.
+ */
+static ssize_t msc_trace_proc_write (struct file *file, const char *buf, size_t count, loff_t * pos)
+{
+        return count;
+}
+
+static struct file_operations msc_trace_proc_operations_functions = {
+        read:msc_trace_proc_read,
+        write:msc_trace_proc_write,
+};
+
+
+/**
+ * msc_trace_init 
+ *
+ * Return non-zero if not successful.
+ */
+int msc_trace_init (char *name, struct msc_private *msc)
+{
+        printk(KERN_INFO"%s:\n", __FUNCTION__);
+        if (!(msc_traces = vmalloc(sizeof(msc_trace_t) * TRACE_MAX))) {
+                printk(KERN_ERR"%s: malloc failed %p %d\n", __FUNCTION__, msc_traces, sizeof(msc_trace_t) * TRACE_MAX);
+                return -EINVAL;
+        }
+        memset(msc_traces, 0, sizeof(msc_trace_t) * TRACE_MAX);
+
+        {
+                struct proc_dir_entry *p;
+
+                // create proc filesystem entries
+                if ((p = create_proc_entry (name, 0, 0)) == NULL) {
+                        printk(KERN_INFO"BITRACE PROC FS failed\n");
+                }
+                else {
+                        p->proc_fops = &msc_trace_proc_operations_functions;
+                }
+        }
+        printk(KERN_INFO"%s: OK\n", __FUNCTION__);
+        msc_private = msc;
+        return 0;
+}
+
+/**
+ * udc_release_io - release UDC io region
+ */
+void msc_trace_exit (char *name)
+{
+        msc_private = NULL;
+        {
+                unsigned long flags;
+                local_irq_save (flags);
+                remove_proc_entry (name, NULL);
+                if (msc_traces) {
+                        msc_trace_t *p = msc_traces;
+                        msc_traces = NULL;
+                        vfree(p);
+                }
+                local_irq_restore (flags);
+        }
+}
+
+
+#else
+int msc_trace_init (void)
+{
+        return 0;
+}
+
+void msc_trace_exit (char *) 
+{
+        return;
+}
+#endif
+
diff -uNr linux/drivers/no-otg/functions/msc/trace.h linux/drivers/otg/functions/msc/trace.h
--- linux/drivers/no-otg/functions/msc/trace.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/msc/trace.h	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,303 @@
+/*
+ * otg/msc_fd/trace.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * Adapted from earlier work:
+ *      Copyright (c) 2002, 2003 Belcarra
+ *      Copyright (c) 2002 Lineo
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *
+ *
+ */
+
+
+typedef enum msc_trace_int_types {
+        msc_trace_int_udc, msc_trace_int_ep0, msc_trace_int_in, msc_trace_int_out, msc_trace_int_int
+} msc_trace_int_types_t;
+
+typedef struct msc_trace_int {
+        u32     last;
+        u32     total;
+        u32     samples;
+} msc_trace_int_t;
+
+
+typedef enum msc_trace_types {
+        msc_trace_setup, msc_trace_msg, msc_trace_msg32, msc_trace_msg16, 
+        msc_trace_msg8, msc_trace_recv, msc_trace_sent, msc_trace_w, msc_trace_r, 
+        msc_trace_rlba, msc_trace_slba, msc_trace_tlba, msc_trace_tag, 
+        msc_trace_sense, msc_trace_cbw
+} msc_trace_types_t;
+
+
+typedef struct msc_trace_regs32 {
+        u32     reg;
+        char *  msg;
+} msc_trace_regs32_t;
+
+
+typedef struct msc_trace_msg {
+        char    *msg;
+} msc_trace_msg_t;
+
+typedef struct msc_trace_msg32 {
+        u32      val;
+        char    *msg;
+} msc_trace_msg32_t;
+
+typedef struct msc_trace_msg16 {
+        u16     val0;
+        u16     val1;
+        char    *msg;
+} msc_trace_msg16_t;
+
+typedef struct msc_trace_msg8 {
+        u8      val0;
+        u8      val1;
+        u8      val2;
+        u8      val3;
+        char    *msg;
+} msc_trace_msg8_t;
+
+
+typedef struct trace {
+        msc_trace_types_t        msc_trace_type;
+        char    *function;
+        u32     interrupts;
+        u64     ticks;
+        u64     sofs;
+
+        union {
+                msc_trace_msg_t        msg;
+                msc_trace_msg8_t       msg8;
+                msc_trace_msg16_t      msg16;
+                msc_trace_msg32_t      msg32;
+
+                struct usbd_device_request       setup;
+                unsigned char      recv[8];
+                unsigned char      sent[8];
+
+                unsigned int       ints[2];
+
+        } trace;
+
+} msc_trace_t;
+
+
+#define TRACE_MAX       30000
+
+extern int msc_trace_first;
+extern int msc_trace_next;
+
+extern msc_trace_int_t *msc_trace_ints;
+extern msc_trace_t *msc_traces;
+
+#ifdef CONFIG_OTG_MSC_REGISTER_TRACE
+
+msc_trace_t *MSC_TRACE_NEXT(msc_trace_types_t msc_trace_type);
+
+static __inline__ void TRACE_SETUP(struct usbd_device_request *setup)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_setup);
+                p->msc_trace_type = msc_trace_setup;
+                memcpy(&p->trace.setup, setup, sizeof(struct usbd_device_request));
+        }
+}
+
+static __inline__ void TRACE_MSG(char *msg)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_msg);
+                p->trace.msg.msg = msg;
+        }
+}
+
+static __inline__ void TRACE_W(char *msg, u32 val)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_w);
+                p->trace.msg32.val = val;
+                p->trace.msg32.msg = msg;
+        }
+}
+
+static __inline__ void TRACE_R(char *msg, u32 val)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_r);
+                p->trace.msg32.val = val;
+                p->trace.msg32.msg = msg;
+        }
+}
+
+static __inline__ void TRACE_MSG32(char *msg, u32 val)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_msg32);
+                p->trace.msg32.val = val;
+                p->trace.msg32.msg = msg;
+        }
+}
+
+static __inline__ void TRACE_MSG16(char *msg, u16 val0, u16 val1)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_msg16);
+                p->trace.msg16.val0 = val0;
+                p->trace.msg16.val1 = val1;
+                p->trace.msg16.msg = msg;
+        }
+}
+
+static __inline__ void TRACE_MSG8(char *msg, u8 val0, u8 val1, u8 val2, u8 val3)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_msg8);
+                p->trace.msg8.val0 = val0;
+                p->trace.msg8.val1 = val1;
+                p->trace.msg8.val2 = val2;
+                p->trace.msg8.val3 = val3;
+                p->trace.msg8.msg = msg;
+        }
+}
+
+static __inline__ void TRACE_RECV(unsigned char *cp)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_recv);
+                memcpy(&p->trace.recv, cp, 8);
+        }
+}
+
+static __inline__ void TRACE_RECVN(unsigned char *cp, int bytes)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_recv);
+                memset(&p->trace.recv, 0, 8);
+                memcpy(&p->trace.recv, cp, bytes);
+        }
+}
+
+static __inline__ void TRACE_SENT(unsigned char *cp)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_sent);
+                memcpy(&p->trace.sent, cp, 8);
+        }
+}
+
+
+static __inline__ void TRACE_RLBA(unsigned int lba, unsigned int crc)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_rlba);
+                p->trace.ints[0] = lba;
+                p->trace.ints[1] = crc;
+        }
+}
+
+static __inline__ void TRACE_SLBA(unsigned int lba, unsigned int crc)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_slba);
+                p->trace.ints[0] = lba;
+                p->trace.ints[1] = crc;
+        }
+}
+
+static __inline__ void TRACE_TLBA(unsigned int lba, unsigned int crc)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_tlba);
+                p->trace.ints[0] = lba;
+                p->trace.ints[1] = crc;
+        }
+}
+
+static __inline__ void TRACE_TAG(unsigned int tag, unsigned int frame)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_tag);
+                p->trace.ints[0] = tag;
+                p->trace.ints[1] = frame;
+        }
+}
+
+static __inline__ void TRACE_SENSE(unsigned int sense, unsigned int info)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_sense);
+                p->trace.ints[0] = sense;
+                p->trace.ints[1] = info;
+        }
+}
+
+static __inline__ void TRACE_CBW(char *msg, int val)
+{
+        if (msc_traces) {
+                msc_trace_t *p = MSC_TRACE_NEXT(msc_trace_cbw);
+                p->trace.msg32.val = val;
+                p->trace.msg32.msg = msg;
+        }
+}
+
+#else
+
+static __inline__ void TRACE_SETUP(struct usbd_device_request *setup)
+{
+}
+
+static __inline__ void TRACE_IRQS(u32 cr, u32 sr)
+{
+}
+
+static __inline__ void TRACE_RECV(unsigned char *cp)
+{
+}
+
+static __inline__ void TRACE_SENT(unsigned char *cp)
+{
+}
+
+static __inline__ void TRACE_W(char *msg, u32 val)
+{
+}
+
+static __inline__ void TRACE_R(char *msg, u32 val)
+{
+}
+
+static __inline__ void TRACE_MSG(char *msg)
+{
+}
+
+static __inline__ void TRACE_MSG32(char *msg, u32 val)
+{
+}
+
+static __inline__ void TRACE_MSG16(char *msg, u16 val0, u16 val1)
+{
+}
+
+static __inline__ void TRACE_TLBA(char *msg, u16 val0, u16 val1)
+{
+}
+
+static __inline__ void TRACE_TAG(char *msg, u16 val0, u16 val1)
+{
+}
+
+static __inline__ void TRACE_SENSE(char *msg, u8 val0, u8 val1, u8 val2, u8 vale)
+{
+}
+
+#endif
+
+int msc_trace_init (char *str, struct msc_private *);
+void msc_trace_exit (char *str);
+
diff -uNr linux/drivers/no-otg/functions/network/Config.in linux/drivers/otg/functions/network/Config.in
--- linux/drivers/no-otg/functions/network/Config.in	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/Config.in	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,70 @@
+#
+# Network Function
+#
+# Copyright (C) 2002-2004 Belcarra
+#
+
+mainmenu_option next_comment
+comment "USB Peripheral Function Driver - Network"
+
+dep_tristate '  Network Function Driver' CONFIG_OTG_NETWORK $CONFIG_OTG
+
+if [ "$CONFIG_OTG_NETWORK" != "n" ]; then
+    
+    hex     'VendorID (hex value)'             CONFIG_OTG_NETWORK_VENDORID "15ec"
+    hex     'ProductID (hex value)'            CONFIG_OTG_NETWORK_PRODUCTID "e003"
+    hex     'bcdDevice (binary-coded decimal)' CONFIG_OTG_NETWORK_BCDDEVICE "0100"
+    
+    string 'iManufacturer (string)' CONFIG_OTG_NETWORK_MANUFACTURER "Belcarra"
+    string 'iProduct (string)'      CONFIG_OTG_NETWORK_PRODUCT_NAME "Belcarra BLAN Device"
+    
+    choice "Mode" "\
+            MDLM-BLAN-Networking-for-personal-devices  CONFIG_OTG_NETWORK_BLAN \
+            MDLM-SAFE-Networking-for-Bridge-Routers CONFIG_OTG_NETWORK_SAFE \
+            CDC-Networking-for-Bridge-Routers CONFIG_OTG_NETWORK_CDC \
+            Failsafe-BASIC-Networking-testing-only CONFIG_OTG_NETWORK_BASIC \
+            Failsafe-BASIC2-Networking-testing-only CONFIG_OTG_NETWORK_BASIC2 \
+            Experimental-Ethernet-Mode-Networking-testing-only CONFIG_OTG_NETWORK_EEM \
+            " MDLM-BLAN-Networking-for-personal-devices
+    
+    if [ "$CONFIG_OTG_NETWORK_BLAN" = "y" ]; then
+        source drivers/otg/functions/network/Config.in-blan
+    fi
+
+    if [ "$CONFIG_OTG_NETWORK_SAFE" = "y" ]; then
+        source drivers/otg/functions/network/Config.in-safe
+    fi
+
+    if [ "$CONFIG_OTG_NETWORK_CDC" = "y" ]; then
+        source drivers/otg/functions/network/Config.in-cdc
+    fi
+
+    if [ "$CONFIG_OTG_NETWORK_BASIC" = "y" ]; then
+        source drivers/otg/functions/network/Config.in-basic
+    fi
+
+    if [ "$CONFIG_OTG_NETWORK_BASIC2" = "y" ]; then
+        source drivers/otg/functions/network/Config.in-basic2
+    fi
+    
+    if [ "$CONFIG_OTG_NETWORK_EEM" = "y" ]; then
+        source drivers/otg/functions/network/Config.in-eem
+    fi
+    
+    comment ''
+    comment 'Testing Options'
+    bool    'Start Single Urb Test' CONFIG_OTG_NETWORK_START_SINGLE
+    bool    'EP0 Test' CONFIG_OTG_NETWORK_EP0TEST
+    dep_bool    "Hotplug-config" CONFIG_OTG_NETWORK_HOTPLUG $CONFIG_HOTPLUG
+
+else
+    define_bool CONFIG_OTG_NETWORK_BLAN n
+    define_bool CONFIG_OTG_NETWORK_SAFE n
+    define_bool CONFIG_OTG_NETWORK_CDC n
+    define_bool CONFIG_OTG_NETWORK_BASIC n
+    define_bool CONFIG_OTG_NETWORK_BASIC2 n
+    define_bool CONFIG_OTG_NETWORK_EEM n
+fi
+
+endmenu
+
diff -uNr linux/drivers/no-otg/functions/network/Config.in-basic linux/drivers/otg/functions/network/Config.in-basic
--- linux/drivers/no-otg/functions/network/Config.in-basic	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/Config.in-basic	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,17 @@
+#
+# Network Function
+#
+# Copyright (C) 2002-2003 Belcarra
+#
+
+mainmenu_option next_comment
+comment "BASIC Networking Configuration"
+
+    #bool " Failsafe BASIC Networking mode" CONFIG_OTG_NETWORK_BASIC
+    if [ "$CONFIG_OTG_NETWORK_BASIC" = "y" ]; then
+        comment 'BASIC Configuration'
+        string 'Data Interface iConfiguration (string)' CONFIG_OTG_NETWORK_BASIC_DESC "BASIC Net Cfg"
+        string 'Data Interface iInterface (string)'     CONFIG_OTG_NETWORK_BASIC_INTF "Data Intf"
+    fi
+
+endmenu
diff -uNr linux/drivers/no-otg/functions/network/Config.in-basic2 linux/drivers/otg/functions/network/Config.in-basic2
--- linux/drivers/no-otg/functions/network/Config.in-basic2	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/Config.in-basic2	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,13 @@
+#
+# Network Function
+#
+# Copyright (C) 2002-2003 Belcarra
+#
+
+mainmenu_option next_comment
+    comment "BASIC2 Networking Configuration"
+    string 'Data Interface iConfiguration (string)' CONFIG_OTG_NETWORK_BASIC2_DESC "BASIC Net Cfg"
+    string 'Comm Interface iInterface (string)'     CONFIG_OTG_NETWORK_BASIC2_COMM_INTF "Comm Intf"
+    string 'Data Interface iInterface (string)'     CONFIG_OTG_NETWORK_BASIC2_DATA_INTF "Data Intf"
+    
+endmenu
diff -uNr linux/drivers/no-otg/functions/network/Config.in-blan linux/drivers/otg/functions/network/Config.in-blan
--- linux/drivers/no-otg/functions/network/Config.in-blan	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/Config.in-blan	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,38 @@
+#
+# Network Function
+#
+# Copyright (C) 2002-2003 Belcarra
+#
+
+mainmenu_option next_comment
+    comment "MBLM-BLAN Networking Configuration"
+
+    string 'iConfiguration (string)' CONFIG_OTG_NETWORK_BLAN_DESC "BLAN Net Cfg"
+    string 'iInterface (string)'     CONFIG_OTG_NETWORK_BLAN_INTF "Comm/Data Intf"
+
+
+    comment 'Special Framing Options'
+    bool "CRC"  CONFIG_OTG_NETWORK_BLAN_CRC
+    if [ "$CONFIG_OTG_NETWORK_BLAN_CRC" = "y" ]; then
+
+        bool "Pad Before CRC (to wMaxPacketSize-1)"  CONFIG_OTG_NETWORK_BLAN_PADBEFORE
+        bool "Pad After CRC"  CONFIG_OTG_NETWORK_BLAN_PADAFTER
+        if [ "$CONFIG_OTG_NETWORK_BLAN" = "y" -a "$CONFIG_OTG_NETWORK_BLAN_PADAFTER" = "y" ]; then
+             int 'Pad multiple' CONFIG_OTG_NETWORK_BLAN_PADBYTES "8"
+        fi
+        bool "Fermat Randomizer"  CONFIG_OTG_NETWORK_BLAN_FERMAT
+    fi
+
+    comment 'USBLAN Options'
+    bool "Do not Set Time"  CONFIG_OTG_NETWORK_BLAN_DO_NOT_SETTIME
+    bool "Request Hostname"  CONFIG_OTG_NETWORK_BLAN_HOSTNAME
+    bool "Infrastructure Device"  CONFIG_OTG_NETWORK_BLAN_NONBRIDGED
+    bool "Data Notification OK"  CONFIG_OTG_NETWORK_BLAN_DATA_NOTIFY_OK
+    int  'Pad multiple' CONFIG_OTG_NETWORK_BLAN_PADBYTES "8"
+    int  'Polling Interval ' CONFIG_OTG_NETWORK_BLAN_INTERVAL "4"
+    bool "Set iProduct from IPADDR" CONFIG_OTG_NETWORK_BLAN_IPADDR
+    bool "Auto-config" CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG
+    comment ''
+
+
+endmenu
diff -uNr linux/drivers/no-otg/functions/network/Config.in-cdc linux/drivers/otg/functions/network/Config.in-cdc
--- linux/drivers/no-otg/functions/network/Config.in-cdc	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/Config.in-cdc	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,16 @@
+#
+# Network Function
+#
+# Copyright (C) 2002-2003 Belcarra
+#
+
+mainmenu_option next_comment
+    comment "CDC Networking Configuration"
+
+    string 'iConfiguration (string)'            CONFIG_OTG_NETWORK_CDC_DESC "SAFE Net Cfg"
+    string 'Comm Interface iInterface (string)' CONFIG_OTG_NETWORK_CDC_COMM_INTF "Comm Intf"
+    string 'Data (diabled) iInterface (string)' CONFIG_OTG_NETWORK_CDC_NODATA_INTF "Data (Disabled) Intf"
+    string 'Data Interface iInterface (string)' CONFIG_OTG_NETWORK_CDC_DATA_INTF "Data Intf"
+      
+
+endmenu
diff -uNr linux/drivers/no-otg/functions/network/Config.in-eem linux/drivers/otg/functions/network/Config.in-eem
--- linux/drivers/no-otg/functions/network/Config.in-eem	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/Config.in-eem	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,17 @@
+#
+# Network Function
+#
+# Copyright (C) 2002-2003 Belcarra
+#
+
+mainmenu_option next_comment
+comment "EEM Networking Configuration"
+
+    #bool " Experimental Ethernet Mode" CONFIG_OTG_NETWORK_EEM
+    if [ "$CONFIG_OTG_NETWORK_EEM" = "y" ]; then
+        comment 'EEM Configuration'
+        string 'Data Interface iConfiguration (string)' CONFIG_OTG_NETWORK_EEM_DESC "EEM Net Cfg"
+        string 'Data Interface iInterface (string)'     CONFIG_OTG_NETWORK_EEM_INTF "Data Intf"
+    fi
+
+endmenu
diff -uNr linux/drivers/no-otg/functions/network/Config.in-safe linux/drivers/otg/functions/network/Config.in-safe
--- linux/drivers/no-otg/functions/network/Config.in-safe	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/Config.in-safe	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,21 @@
+#
+# Network Function
+#
+# Copyright (C) 2002-2003 Belcarra
+#
+
+mainmenu_option next_comment
+    comment "MDLM-SAFE Networking Configuration"
+
+    string 'Data Interface iConfiguration (string)' CONFIG_OTG_NETWORK_SAFE_DESC "SAFE Net Cfg"
+    string 'Data Interface iInterface (string)'     CONFIG_OTG_NETWORK_SAFE_INTF "Data Intf"
+    bool " Do not Set Time"  CONFIG_OTG_NETWORK_SAFE_DO_NOT_SETTIME
+    bool " CRC"  CONFIG_OTG_NETWORK_SAFE_CRC
+    if [ "$CONFIG_OTG_NETWORK_SAFE_CRC" = "y" ]; then
+        bool "Pad Before CRC (to wMaxPacketSize-1)"  CONFIG_OTG_NETWORK_SAFE_PADBEFORE
+    fi
+    bool "Infrastructure Device"  CONFIG_OTG_NETWORK_SAFE_NONBRIDGED
+    comment ''
+    
+
+endmenu
diff -uNr linux/drivers/no-otg/functions/network/Kconfig linux/drivers/otg/functions/network/Kconfig
--- linux/drivers/no-otg/functions/network/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/Kconfig	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,131 @@
+menu "OTG Network Function"
+	depends on OTG
+
+config OTG_NETWORK
+        tristate "  Network Function Driver"
+        depends on OTG
+
+menu "OTG Network Function options"
+	depends on OTG_NETWORK
+
+config OTG_NETWORK_VENDORID
+        hex "VendorID (hex value)"
+        depends on OTG && OTG_NETWORK
+        default "0x15ec"
+
+config OTG_NETWORK_PRODUCTID
+        hex "ProductID (hex value)"
+        depends on OTG && OTG_NETWORK
+        default "0xe003"
+
+config OTG_NETWORK_BCDDEVICE
+        hex "bcdDevice (binary-coded decimal)"
+        depends on OTG && OTG_NETWORK
+        default "0x0100"
+
+config OTG_NETWORK_MANUFACTURER
+        string "iManufacturer (string)"
+        depends on OTG && OTG_NETWORK
+        default "Belcarra"
+
+config OTG_NETWORK_PRODUCT_NAME
+        string "iProduct (string)"
+        depends on OTG && OTG_NETWORK
+        default "Belcarra BLAN Device"
+
+config OTG_NETWORK_BLAN_DESC
+        string "    iConfiguration (string)"
+        depends on OTG && OTG_NETWORK
+        default "BLAN Net Cfg"
+
+config OTG_NETWORK_MANUFACTURER
+        string "iManufacturer (string)"
+        depends on OTG && OTG_NETWORK
+        default "Belcarra"
+
+config OTG_NETWORK_PRODUCT_NAME
+        string "iProduct (string)"
+        depends on OTG && OTG_NETWORK
+        default "Belcarra BLAN Device"
+
+config OTG_NETWORK_BLAN_DESC
+        string "    iConfiguration (string)"
+        depends on OTG && OTG_NETWORK
+        default "BLAN Net Cfg"
+
+config OTG_NETWORK_BLAN_INTF
+        string "    iInterface (string)"
+        depends on OTG && OTG_NETWORK
+        default "Comm/Data Intf"
+
+config OTG_NETWORK_BLAN_PADBYTES
+        int "        Pad multiple"
+        default "8"
+
+config OTG_NETWORK_SAFE_DESC
+        string "    Data Interface iConfiguration (string)"
+        depends on OTG && OTG_NETWORK
+        default "SAFE Net Cfg"
+
+config OTG_NETWORK_SAFE_INTF
+        string "    Data Interface iInterface (string)"
+        depends on OTG && OTG_NETWORK
+        default "Data Intf"
+
+config OTG_NETWORK_CDC_DESC
+        string "    iConfiguration (string)"
+        depends on OTG && OTG_NETWORK
+        default "SAFE Net Cfg"
+
+config OTG_NETWORK_CDC_COMM_INTF
+        string "    Comm Interface iInterface (string)"
+        depends on OTG && OTG_NETWORK
+        default "Comm Intf"
+
+config OTG_NETWORK_CDC_NODATA_INTF
+        string "    Data (diabled) iInterface (string)"
+        depends on OTG && OTG_NETWORK
+        default "Data (Disabled) Intf"
+
+config OTG_NETWORK_CDC_DATA_INTF
+        string "    Data Interface iInterface (string)"
+        depends on OTG && OTG_NETWORK
+        default "Data Intf"
+
+config OTG_NETWORK_BASIC_DESC
+        string "    Data Interface iConfiguration (string)"
+        depends on OTG && OTG_NETWORK
+        default "BASIC Net Cfg"
+
+config OTG_NETWORK_BASIC_INTF
+        string "    Data Interface iInterface (string)"
+        depends on OTG && OTG_NETWORK
+        default "Data Intf"
+
+config OTG_NETWORK_BASIC2_DESC
+        string "    Data Interface iConfiguration (string)"
+        depends on OTG && OTG_NETWORK
+        default "BASIC Net Cfg"
+
+config OTG_NETWORK_BASIC2_COMM_INTF
+        string "    Comm Interface iInterface (string)"
+        depends on OTG && OTG_NETWORK
+        default "Comm Intf"
+
+config OTG_NETWORK_BASIC2_DATA_INTF
+        string "    Data Interface iInterface (string)"
+        depends on OTG && OTG_NETWORK
+        default "Data Intf"
+
+config OTG_NETWORK_START_SINGLE
+        bool " Start Single Urb Test"
+        depends on OTG && OTG_NETWORK
+        default n
+
+config OTG_NETWORK_EP0TEST
+        bool " EP0 Test"
+        depends on OTG && OTG_NETWORK
+        default n
+
+endmenu
+endmenu
diff -uNr linux/drivers/no-otg/functions/network/Makefile linux/drivers/otg/functions/network/Makefile
--- linux/drivers/no-otg/functions/network/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/Makefile	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,70 @@
+#
+# Network Function Driver
+#
+# Copyright (C) 2002-2003 Belcarra
+
+
+O_TARGET	:= network_target.o
+list-multi	:= network_fd.o
+
+network_fd-objs	:= net-l24-os.o net-fd.o basic.o basic2.o blan.o cdc.o safe.o fermat.o
+
+# Objects that export symbols.
+export-objs	:= net-l24-os.o net-fd.o
+
+
+# Object file lists.
+
+obj-y		:=
+obj-m		:=
+obj-n		:=
+obj-		:=
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_OTG_NETWORK)   += network_fd.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+int-m		:= $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
+OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+
+# The global Rules.make.
+
+
+OTG_DIR=$(TOPDIR)/drivers/otg
+NETWORK_DIR=$(OTG_DIR)/functions/network
+include $(TOPDIR)/Rules.make
+EXTRA_CFLAGS += -Wno-unused -Wstrict-prototypes -Wno-format
+EXTRA_CFLAGS += -I$(NETWORK_DIR) -I$(OTG_DIR) 
+EXTRA_CFLAGS_nostdinc += -Wstrict-prototypes -Wno-unused -Wno-format 
+EXTRA_CFLAGS_nostdinc += -I$(NETWORK_DIR) -I$(OTG_DIR) 
+
+# Link rules for multi-part drivers.
+
+network_fd.o: $(network_fd-objs)
+	$(LD) -r -o $@ $(network_fd-objs)
+
+# dependencies:
+
+net-fd.o: net-fd.h net-os.h network.h 
+net-l24-os.o: net-fd.h net-os.h network.h 
+
+
diff -uNr linux/drivers/no-otg/functions/network/Makefile-l26 linux/drivers/otg/functions/network/Makefile-l26
--- linux/drivers/no-otg/functions/network/Makefile-l26	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/Makefile-l26	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,22 @@
+#
+# Network Function Driver
+#
+# Copyright (C) 2002-2004 Belcarra Technologies Corp
+
+
+OTG=$(TOPDIR)/drivers/otg
+NETWORKD=$(OTG)/functions/network
+OTGCORE_DIR=$(OTG)/otgcore
+USBDCORE_DIR=$(OTG)/usbdcore
+EXTRA_CFLAGS += -I$(NETWORKD) -I$(OTG) -Wno-unused -Wno-format  -I$(USBDCORE_DIR) -I$(OTGCORE_DIR)
+EXTRA_CFLAGS_nostdinc += -I$(NETWORKD) -I$(OTG) -Wno-unused -Wno-format  -I$(USBDCORE_DIR) -I$(OTGCORE_DIR)
+
+network_fd-objs := network.o basic.o basic2.o blan.o cdc.o safe.o fermat.o
+obj-$(CONFIG_OTG_NETWORK) += network_fd.o
+
+
+# Link rules for multi-part drivers.
+
+network_fd.o: $(network_fd-objs)
+	$(LD) -r -o $@ $(network_fd-objs)
+
diff -uNr linux/drivers/no-otg/functions/network/TODO.txt linux/drivers/otg/functions/network/TODO.txt
--- linux/drivers/no-otg/functions/network/TODO.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/TODO.txt	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,32 @@
+NETWORK TODO List                                               Stuart Lynne
+Belcarra                                        Tue Aug 24 21:36:09 PDT 2004 
+
+
+1. NETWORK documentation
+
+
+2. BLAN
+        - data notification
+        - timeout to resend data notification after XX mS
+
+3. CDC
+        - filters
+
+
+4. RNDIS
+        - should we add back in?
+
+
+5. NOTIFICATIONS
+
+        NETWORK_CONNECTION
+        CONNECTION_SPEED_CHANGE
+
+
+
+I suspect that we should make the data notification a runtime option, 
+the host driver would "enable" this after a certain number of devices 
+are plugged in (say 5 or more, some configurable number.) This would
+be done by sending a vendor device request to the peripheral to tell
+the network driver that it needs to use this mechanism.
+
diff -uNr linux/drivers/no-otg/functions/network/basic.c linux/drivers/otg/functions/network/basic.c
--- linux/drivers/no-otg/functions/network/basic.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/basic.c	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,247 @@
+/*
+ * otg/functions/network/basic.c - Network Function Driver
+ *
+ *      Copyright (c) 2002, 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Chris Lynne <cl@belcarra.com>
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*!
+ * @file otg/functions/network/basic.c
+ * @brief This file implements the required descriptors to implement
+ * a basic network device with a single interface.
+ *
+ * The BASIC network driver implements a very simple descriptor set.
+ * A single interface with two BULK data endpoints and a optional
+ * INTERRUPT endpoint.
+ *
+ * @ingroup NetworkFunction
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/utsname.h>
+#include <linux/netdevice.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include "network.h"
+
+#define NTT network_fd_trace_tag
+
+#ifdef CONFIG_OTG_NETWORK_BASIC
+/* USB BASIC Configuration ******************************************************************** */
+
+/* BASIC Communication Interface Class descriptors
+ */
+/*! BULK OUT data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor basic_data_1 = { 
+    bLength:sizeof(struct usbd_endpoint_descriptor),
+    bDescriptorType:USB_DT_ENDPOINT,
+    bEndpointAddress:USB_DIR_OUT, 
+    bmAttributes: BULK,     
+    wMaxPacketSize: 0, 
+    bInterval: 0,
+};
+/*! BULK IN data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor basic_data_2 =// { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  BULK,     0, 0x00, 0x00, };
+{
+    bLength:sizeof(struct usbd_endpoint_descriptor),
+    bDescriptorType:USB_DT_ENDPOINT,
+    bEndpointAddress:USB_DIR_IN, 
+    bmAttributes: BULK,     
+    wMaxPacketSize: 0, 
+    bInterval: 0x0,
+};
+
+/*! INTERRUPT IN data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor basic_comm_1 = //{ 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  INTERRUPT,0, 0x00, 0x0a, };
+{
+    bLength:sizeof(struct usbd_endpoint_descriptor),
+    bDescriptorType:USB_DT_ENDPOINT,
+    bEndpointAddress:USB_DIR_IN, 
+    bmAttributes: INTERRUPT,     
+    wMaxPacketSize: 0, 
+    bInterval: 0xa,
+};
+
+/*! Endpoint descriptor list
+ */
+static  struct usbd_endpoint_descriptor  *basic_default[] = { &basic_data_1, 
+    &basic_data_2, 
+    &basic_comm_1, };
+u8 basic_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
+
+/*! Data Interface Descriptor
+ */
+static struct usbd_interface_descriptor  basic_data_alternate_descriptor = {
+    bLength:sizeof(struct usbd_interface_descriptor),
+    bDescriptorType:USB_DT_INTERFACE,
+    bInterfaceNumber: 0x00, 
+    bAlternateSetting: 0x00, // bInterfaceNumber, bAlternateSetting
+    sizeof (basic_default) / sizeof(struct usbd_endpoint_descriptor *), // bNumEndpoints
+    bInterfaceClass:LINEO_CLASS, 
+    bInterfaceSubClass:LINEO_SUBCLASS_BASIC_NET, 
+    bInterfaceProtocol:LINEO_BASIC_NET_CRC, 
+    iInterface:0x00,
+};
+
+/*! Data Alternate Interface Description List
+ */
+static struct usbd_alternate_description basic_data_alternate_descriptions[] = {
+        { iInterface: CONFIG_OTG_NETWORK_BASIC_INTF,
+                interface_descriptor: (struct usbd_interface_descriptor *)&basic_data_alternate_descriptor,
+                endpoints:sizeof (basic_default) / sizeof(struct usbd_endpoint_descriptor *),
+                endpoint_list: basic_default,
+                endpoint_indexes: basic_indexes,
+                },
+};
+
+
+/* BASIC Data Interface Alternate descriptions and descriptors
+ */
+
+/* BASIC Interface descriptions and descriptors
+ */
+/*! Interface Description List
+ */
+struct usbd_interface_description basic_interfaces[] = {
+        { alternates:sizeof (basic_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:basic_data_alternate_descriptions,},
+};
+
+/* BASIC Configuration descriptions and descriptors
+ */
+/*! Configuration Descriptor 
+ */
+u8 basic_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
+        0x09, USB_DT_CONFIGURATION, 0x00, 0x00, // wLength
+        sizeof (basic_interfaces) / sizeof (struct usbd_interface_description),
+        0x01, 0x00, // bConfigurationValue, iConfiguration
+        0, 0,
+};
+
+/*! Configuration Description List 
+ */
+struct usbd_configuration_description basic_description[] = {
+        { iConfiguration: CONFIG_OTG_NETWORK_BASIC_DESC,
+                configuration_descriptor: (struct usbd_configuration_descriptor *)basic_configuration_descriptor,
+        },
+
+};
+
+/* BASIC Device Description
+ */
+/*! Device Descriptor 
+ */
+static struct usbd_device_descriptor basic_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+/*! High Speed Device Qualifier Descriptor 
+ */
+static struct usbd_device_qualifier_descriptor basic_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+/*! Endpoint Request List
+ */
+static struct usbd_endpoint_request basic_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
+        { 0, },
+};
+
+/*! OTG Descriptor
+ */
+static struct usbd_otg_descriptor basic_otg_descriptor = {
+        bLength : sizeof(struct usbd_otg_descriptor),
+        bDescriptorType: USB_DT_OTG,
+        bmAttributes: 0,
+};
+
+/*! Device Description
+ */
+struct usbd_device_description basic_device_description = {
+        device_descriptor: &basic_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &basic_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &basic_otg_descriptor,
+        iManufacturer: CONFIG_OTG_NETWORK_MANUFACTURER,
+        iProduct: CONFIG_OTG_NETWORK_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        iSerialNumber:CONFIG_OTG_SERIAL_NUMBER_STR,
+#endif
+};
+
+
+/*! basic_init
+ * @param function The function instance
+ */
+void basic_init (struct usbd_function_instance *function)
+{
+        basic_data_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 3 : 2;
+}
+
+/*! function driver description
+ */
+struct usbd_function_driver basic_function_driver = {
+        name: "network-BASIC",
+        fops: &net_fd_function_ops,
+        device_description: &basic_device_description,
+        bNumConfigurations: sizeof (basic_description) / sizeof (struct usbd_configuration_description),
+        configuration_description: basic_description,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
+        bNumInterfaces:sizeof (basic_interfaces) / sizeof (struct usbd_interface_description),
+        interface_list:basic_interfaces,
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: basic_endpoint_requests,
+};
+#endif                  /* CONFIG_OTG_NETWORK_BASIC */
+
diff -uNr linux/drivers/no-otg/functions/network/basic2.c linux/drivers/otg/functions/network/basic2.c
--- linux/drivers/no-otg/functions/network/basic2.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/basic2.c	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,320 @@
+/*
+ * otg/functions/network/basic2.c - Network Function Driver
+ *
+ *      Copyright (c) 2002, 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Chris Lynne <cl@belcarra.com>
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*!
+ * @file otg/functions/network/basic2.c
+ * @brief This file implements the required descriptors to implement
+ * a basic network device with two interfaces.
+ *
+ * The BASIC2 network driver implements a very simple descriptor set.
+ * A data interface with two BULK data endpoints and comm interface with
+ * an INTERRUPT endpoint.
+ *
+ * @ingroup NetworkFunction
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/utsname.h>
+#include <linux/netdevice.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/otg-compat.h>
+#include <otg/usbp-func.h>
+
+#include "network.h"
+
+#define NTT network_fd_trace_tag
+
+#ifdef CONFIG_OTG_NETWORK_BASIC2
+/* USB BASIC Configuration ******************************************************************** */
+
+/*
+ * This provides a slight amplification of the basic configuration, it moves the
+ * interrupt endpoint (if available) to a separate interface, so that it is similiar
+ * to the cdc configuration
+ */
+
+/* BASIC Communication Interface Class descriptors
+ */
+//static u8 basic2_data_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_OUT, BULK,     0, 0x00, 0x00,  };
+//static u8 basic2_data_2[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  BULK,     0, 0x00, 0x00, };
+//static u8 basic2_comm_1[] = { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  INTERRUPT,0, 0x00, 0x0a, };
+
+/*! BULK OUT data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor basic2_data_1 = { 
+    bLength:sizeof(struct usbd_endpoint_descriptor),
+    bDescriptorType:USB_DT_ENDPOINT,
+    bEndpointAddress:USB_DIR_OUT, 
+    bmAttributes: BULK,     
+    wMaxPacketSize: 0, 
+    bInterval: 0,
+};
+/*! BULK IN data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor basic2_data_2 = {
+    bLength:sizeof(struct usbd_endpoint_descriptor),
+    bDescriptorType:USB_DT_ENDPOINT,
+    bEndpointAddress:USB_DIR_IN, 
+    bmAttributes: BULK,     
+    wMaxPacketSize: 0, 
+    bInterval: 0x0,
+};
+
+/*! INTERRUPT IN data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor basic2_comm_1 = {
+    bLength:sizeof(struct usbd_endpoint_descriptor),
+    bDescriptorType:USB_DT_ENDPOINT,
+    bEndpointAddress:USB_DIR_IN, 
+    bmAttributes: INTERRUPT,     
+    wMaxPacketSize: 0, 
+    bInterval: 0xa,
+};
+
+/*! Endpoint descriptor list
+ */
+static  struct usbd_endpoint_descriptor  *basic2_default[] = { 
+    &basic2_data_1, 
+    &basic2_data_2, 
+    &basic2_comm_1, };
+u8 basic2_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
+
+static struct usbd_endpoint_descriptor *basic2_comm_endpoints[] = { 
+        (struct usbd_endpoint_descriptor *) &basic2_comm_1, };
+
+/*! Endpoint descriptor list
+ */
+static struct usbd_endpoint_descriptor *basic2_data_endpoints[] = { 
+        (struct usbd_endpoint_descriptor *) &basic2_data_1, 
+        (struct usbd_endpoint_descriptor *) &basic2_data_2, };
+
+u8 basic2_comm_indexes[] = { INT_IN, };
+u8 basic2_data_indexes[] = { BULK_OUT, BULK_IN, };
+
+
+/* BASIC2 Data Interface Alternate endpoints
+ */
+
+
+#ifndef COMMUNICATIONS_NETWORK_SUBCLASS
+#define COMMUNICATIONS_NETWORK_SUBCLASS 0
+#endif
+
+#ifndef VENDOR_PROTOCOL
+#define VENDOR_PROTOCOL 0xFF
+#endif
+/*! Comm Interface Descriptor
+ */
+static struct usbd_interface_descriptor  basic2_comm_alternate_descriptor = {
+    bLength:sizeof(struct usbd_interface_descriptor),
+    bDescriptorType:USB_DT_INTERFACE,
+    bInterfaceNumber: 0x00, 
+    bAlternateSetting: 0x00, // bInterfaceNumber, bAlternateSetting
+    sizeof (basic2_default) / sizeof(struct usbd_endpoint_descriptor *), // bNumEndpoints
+    bInterfaceClass:COMMUNICATIONS_INTERFACE_CLASS,
+    bInterfaceSubClass:COMMUNICATIONS_NETWORK_SUBCLASS, 
+    bInterfaceProtocol:VENDOR_PROTOCOL,
+    iInterface:0x00,
+};
+
+/*! Data Interface Descriptor
+ */
+static struct usbd_interface_descriptor  basic2_data_alternate_descriptor = {
+    bLength:sizeof(struct usbd_interface_descriptor),
+    bDescriptorType:USB_DT_INTERFACE,
+    bInterfaceNumber: 0x01, 
+    bAlternateSetting: 0x00, // bInterfaceNumber, bAlternateSetting
+    sizeof (basic2_default) / sizeof(struct usbd_endpoint_descriptor *), // bNumEndpoints
+    bInterfaceClass:DATA_INTERFACE_CLASS,
+    bInterfaceSubClass:COMMUNICATIONS_NO_SUBCLASS,
+    bInterfaceProtocol:COMMUNICATIONS_NO_PROTOCOL, 
+    iInterface:0x00,
+};
+
+/*! Comm Alternate Interface Description List
+ */
+static struct usbd_alternate_description basic2_comm_alternate_descriptions[] = {
+      { iInterface: CONFIG_OTG_NETWORK_BASIC2_COMM_INTF,
+                interface_descriptor: (struct usbd_interface_descriptor *)&basic2_comm_alternate_descriptor,
+                endpoints:sizeof (basic2_comm_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+                endpoint_list:basic2_comm_endpoints,
+                endpoint_indexes:basic2_comm_indexes,
+                },
+};
+
+
+/*! Data Alternate Interface Description List
+ */
+static struct usbd_alternate_description basic2_data_alternate_descriptions[] = {
+      { iInterface: CONFIG_OTG_NETWORK_BASIC2_DATA_INTF,
+                interface_descriptor: (struct usbd_interface_descriptor *)&basic2_data_alternate_descriptor,
+                endpoints:sizeof (basic2_data_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+                endpoint_list: basic2_data_endpoints,
+                endpoint_indexes: basic2_data_indexes,
+        },
+};
+
+
+/* BASIC Data Interface Alternate descriptions and descriptors
+ */
+
+/* BASIC Interface descriptions and descriptors
+ */
+/*! Interface Description List
+ */
+static struct usbd_interface_description basic2_interfaces[] = {
+        { alternates:sizeof (basic2_comm_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:basic2_comm_alternate_descriptions,},
+
+        { alternates:sizeof (basic2_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:basic2_data_alternate_descriptions,},
+};
+
+
+/* BASIC Configuration descriptions and descriptors
+ */
+/*! Configuration Descriptor 
+ */
+u8 basic2_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
+        0x09, USB_DT_CONFIGURATION, 0x00, 0x00, // wLength
+        sizeof (basic2_interfaces) / sizeof (struct usbd_interface_description),
+        0x01, 0x00, // bConfigurationValue, iConfiguration
+        0, 0,
+};
+
+/*! Configuration Description List 
+ */
+struct usbd_configuration_description basic2_description[] = {
+        { iConfiguration: CONFIG_OTG_NETWORK_BASIC2_DESC,
+                configuration_descriptor: (struct usbd_configuration_descriptor *)basic2_configuration_descriptor,
+        },
+
+};
+
+/* BASIC Device Description
+ */
+/*! Device Descriptor 
+ */
+static struct usbd_device_descriptor basic2_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+/*! High Speed Device Qualifier Descriptor 
+ */
+static struct usbd_device_qualifier_descriptor basic2_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+/*! Endpoint Request List
+ */
+static struct usbd_endpoint_request basic2_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512,  },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
+        { 0, },
+};
+
+/*! OTG Descriptor
+ */
+static struct usbd_otg_descriptor basic2_otg_descriptor = {
+        bLength : sizeof(struct usbd_otg_descriptor),
+        bDescriptorType: USB_DT_OTG,
+        bmAttributes: 0,
+};
+/*! Device Description
+ */
+struct usbd_device_description basic2_device_description = {
+        device_descriptor: &basic2_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &basic2_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &basic2_otg_descriptor,
+        iManufacturer: CONFIG_OTG_NETWORK_MANUFACTURER,
+        iProduct: CONFIG_OTG_NETWORK_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        iSerialNumber:CONFIG_OTG_SERIAL_NUMBER_STR,
+#endif
+};
+
+
+/*! basic2_init
+ * @param function The function instance
+ */
+void basic2_init (struct usbd_function_instance *function)
+{
+        TRACE_MSG0(NTT,"entered");
+
+        basic2_comm_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 1 : 0;
+
+        TRACE_MSG2(NTT,"alternate: %p endpoints: %d",
+                        basic2_data_alternate_descriptions,
+                        basic2_data_alternate_descriptions->endpoints
+        );
+
+        TRACE_MSG0(NTT,"exited");
+}
+
+
+/*! function driver description
+ */
+struct usbd_function_driver basic2_function_driver = {
+        name: "network-BASIC2",
+        fops: &net_fd_function_ops,
+        device_description: &basic2_device_description,
+        bNumConfigurations: sizeof (basic2_description) / sizeof (struct usbd_configuration_description),
+        configuration_description: basic2_description,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
+        bNumInterfaces:sizeof (basic2_interfaces) / sizeof (struct usbd_interface_description),
+        interface_list:basic2_interfaces,
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: basic2_endpoint_requests,
+};
+#endif                          /* CONFIG_OTG_NETWORK_BASIC2 */
+
diff -uNr linux/drivers/no-otg/functions/network/blan.c linux/drivers/otg/functions/network/blan.c
--- linux/drivers/no-otg/functions/network/blan.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/blan.c	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,403 @@
+/*
+ * otg/functions/network/blan.c - Network Function Driver
+ *
+ *      Copyright (c) 2002, 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Chris Lynne <cl@belcarra.com>
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*!
+ * @file otg/functions/network/blan.c
+ * @brief This file implements the required descriptors to implement
+ * a BLAN network device with a single interface.
+ *
+ * The BLAN network driver implements the BLAN protocol descriptors.
+ *
+ * The BLAN protocol is designed to support smart devices that want
+ * to create a virtual network between them host and other similiar
+ * devices.
+ *
+ * @ingroup NetworkFunction
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/utsname.h>
+#include <linux/netdevice.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include "network.h"
+
+#define NTT network_fd_trace_tag
+
+#ifdef CONFIG_OTG_NETWORK_BLAN
+/* USB BLAN  Configuration ******************************************************************** */
+
+/*
+ * BLAN Ethernet Configuration
+ */
+
+/* Communication Interface Class descriptors
+ */
+
+/*! BULK OUT data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor blan_data_1 = { 
+    .bLength = sizeof(struct usbd_endpoint_descriptor),
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = USB_DIR_OUT, 
+    .bmAttributes =  BULK,     
+    .wMaxPacketSize =  0, 
+    .bInterval =  0,
+};
+/*! BULK IN data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor blan_data_2 =// { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  BULK,     0, 0x00, 0x00, };
+{
+    .bLength = sizeof(struct usbd_endpoint_descriptor),
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = USB_DIR_IN, 
+    .bmAttributes =  BULK,     
+    .wMaxPacketSize =  0, 
+    .bInterval =  0x0,
+};
+
+/*! INTERRUPT IN data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor blan_comm_1 = //{ 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  INTERRUPT,0, 0x00, 0x0a, };
+{
+        .bLength = sizeof(struct usbd_endpoint_descriptor),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = USB_DIR_IN, 
+        .bmAttributes = INTERRUPT,     
+        .wMaxPacketSize = 0, 
+#if defined (CONFIG_OTG_NETWORK_BLAN_INTERVAL)
+        .bInterval = CONFIG_OTG_NETWORK_BLAN_INTERVAL, 
+#else
+        .bInterval = 0x08, 
+#endif /* defined (CONFIG_OTG_NETWORK_BLAN_INTERVAL) */
+};
+
+//static u8 blan_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x10, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
+static struct usbd_class_header_function_descriptor blan_class_1 = {
+        .bFunctionLength = 0x05, /* Length */
+        .bDescriptorType =  CS_INTERFACE, 
+        .bDescriptorSubtype = USB_ST_HEADER, 
+        .bcdCDC =  __constant_cpu_to_le16(0x0110) /*Version */
+};
+//static u8 blan_class_2[] = { 0x15, CS_INTERFACE, USB_ST_MDLM, 0x00, 0x01, /* bcdVersion, bcdVersion */
+//                0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70,  /* bGUID */
+static struct usbd_class_mdlm_descriptor blan_class_2 = {
+        .bFunctionLength = 0x15, 
+        .bDescriptorType = CS_INTERFACE, 
+        .bDescriptorSubtype = USB_ST_MDLM, 
+        .bcdVersion = __constant_cpu_to_le16(0x0100), 
+        .bGUID =  {
+            0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70,  /* bGUID */
+            0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37,  /* bGUID */ },
+};
+
+
+
+//static u8 blan_class_3[] = { 0x07, CS_INTERFACE, USB_ST_MDLMD, 0x01, 0x00, 0x00, 0x00, };
+static struct usbd_class_blan_descriptor blan_class_3 = { 
+        .bFunctionLength = 0x07, 
+        .bDescriptorType =  CS_INTERFACE, 
+        .bDescriptorSubtype =  USB_ST_MDLMD, 
+        .bGuidDescriptorType =  0x01,
+        .bmNetworkCapabilities =  0x00,
+        .bmDataCapabilities =  0x00,
+        .bPad =  0x00,
+};
+
+//static u8 blan_class_4[] = { 0x0d, CS_INTERFACE, USB_ST_ENF, 
+//      0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x05, /* 1514 maximum frame size */
+//      0x00, 0x00, 0x00 , };
+static struct usbd_class_ethernet_networking_descriptor blan_class_4 = { 
+        .bFunctionLength = 0x0d, 
+        .bDescriptorType = CS_INTERFACE, 
+        .bDescriptorSubtype = USB_ST_ENF, 
+        .iMACAddress =  0x00, 
+        .bmEthernetStatistics =  0x00, 
+        .wMaxSegmentSize =  0x05ea, /* 1514 maximum frame size */
+        .wNumberMCFilters =   0x00,
+        .bNumberPowerFilters =  0x00 , 
+};
+
+//static u8 blan_class_5[] = { 0x07, CS_INTERFACE, USB_ST_NCT, 0x00, 0x00, 0x00, 0x00, };
+static struct usbd_class_network_channel_descriptor blan_class_5 = {
+        .bFunctionLength =  0x07,
+        .bDescriptorType =  CS_INTERFACE,
+        .bDescriptorSubtype = USB_ST_NCT,
+        .bEntityId =  0,
+        .iName =  0,
+        .bChannelIndex =  0,
+        .bPhysicalInterface =  0,
+};
+
+
+/*! Endpoint descriptor list
+ */
+static struct usbd_endpoint_descriptor *blan_alt_endpoints[] = { 
+        (struct usbd_endpoint_descriptor *) &blan_data_1, 
+        (struct usbd_endpoint_descriptor *) &blan_data_2, 
+        (struct usbd_endpoint_descriptor *) &blan_comm_1, };
+
+u8 blan_alt_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
+
+static struct usbd_generic_class_descriptor *blan_comm_class_descriptors[] = {
+        (struct usbd_generic_class_descriptor *) &blan_class_1, 
+        (struct usbd_generic_class_descriptor *) &blan_class_2, 
+        (struct usbd_generic_class_descriptor *) &blan_class_3, 
+        (struct usbd_generic_class_descriptor *) &blan_class_4, 
+        (struct usbd_generic_class_descriptor *) &blan_class_5, };
+
+
+/*! Data Interface Descriptor
+ */
+static struct usbd_interface_descriptor blan_alternate_descriptor = {
+        .bLength = 0x09, 
+        .bDescriptorType =  USB_DT_INTERFACE, 
+        .bInterfaceNumber = 0x00, 
+        .bAlternateSetting =  0x00, // bInterfaceNumber, bAlternateSetting
+        .bNumEndpoints =  sizeof (blan_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *), // bNumEndpoints
+        .bInterfaceClass = COMMUNICATIONS_INTERFACE_CLASS, 
+        .bInterfaceSubClass =  COMMUNICATIONS_MDLM_SUBCLASS, 
+        .bInterfaceProtocol = COMMUNICATIONS_NO_PROTOCOL, 
+        .iInterface =  0x00,
+};
+
+/*! Data Alternate Interface Description List
+ */
+static struct usbd_alternate_description blan_alternate_descriptions[] = {
+        { 
+                .iInterface =  CONFIG_OTG_NETWORK_BLAN_INTF,
+                .interface_descriptor =  (struct usbd_interface_descriptor *)&blan_alternate_descriptor,
+                .classes = sizeof (blan_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
+                .class_list =  blan_comm_class_descriptors,
+                .endpoints = sizeof (blan_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+                .endpoint_list =  blan_alt_endpoints,
+                .endpoint_indexes =  blan_alt_indexes,
+        },
+};
+/* Interface descriptions and descriptors
+ */
+/*! Interface Description List
+ */
+static struct usbd_interface_description blan_interfaces[] = {
+        { 
+                .alternates =  sizeof (blan_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                .alternate_list =  blan_alternate_descriptions, 
+        },
+};
+
+
+/* Configuration descriptions and descriptors
+ */
+
+/*! Configuration Descriptor 
+ */
+static struct usbd_configuration_descriptor  blan_configuration_descriptor = {
+        .bLength =  0x09, 
+        .bDescriptorType =  USB_DT_CONFIGURATION, 
+        .wTotalLength = 0x00, // wLength
+        .bNumInterfaces =  sizeof (blan_interfaces) / sizeof (struct usbd_interface_description),
+        .bConfigurationValue = 0x01, 
+        .iConfiguration =  0x00, // bConfigurationValue, iConfiguration
+        .bmAttributes = 0, 
+        .bMaxPower = 0,
+};
+
+/*! Configuration Description List 
+ */
+struct usbd_configuration_description blan_description[] = {
+    { 
+        .iConfiguration =  CONFIG_OTG_NETWORK_BLAN_DESC,
+        .configuration_descriptor =  &blan_configuration_descriptor,
+    },
+};
+
+/* Device Description
+ */
+
+/*! Device Descriptor 
+ */
+static struct usbd_device_descriptor blan_device_descriptor = {
+        .bLength =  sizeof(struct usbd_device_descriptor),
+        .bDescriptorType =  USB_DT_DEVICE,
+        .bcdUSB =  __constant_cpu_to_le16(USB_BCD_VERSION),
+        .bDeviceClass =  COMMUNICATIONS_DEVICE_CLASS,
+        .bDeviceSubClass =  0x02,
+        .bDeviceProtocol =  0x00,
+        .bMaxPacketSize0 =  0x00,
+        .idVendor =  __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
+        .idProduct =  __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
+        .bcdDevice =  __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+/*! High Speed Device Qualifier Descriptor 
+ */
+static struct usbd_device_qualifier_descriptor blan_device_qualifier_descriptor = {
+        .bLength =  sizeof(struct usbd_device_qualifier_descriptor),
+        .bDescriptorType =  USB_DT_DEVICE_QUALIFIER,
+        .bcdUSB =  __constant_cpu_to_le16(USB_BCD_VERSION),
+        .bDeviceClass =  COMMUNICATIONS_DEVICE_CLASS,
+        .bDeviceSubClass =  0x02,
+        .bDeviceProtocol =  0x00,
+        .bMaxPacketSize0 =  0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+/*! Endpoint Request List
+ */
+static struct usbd_endpoint_request blan_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512,  },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512,  },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
+        { 0, },
+};
+
+/*! OTG Descriptor
+ */
+static struct usbd_otg_descriptor blan_otg_descriptor = {
+        .bLength  =  sizeof(struct usbd_otg_descriptor),
+        .bDescriptorType =  USB_DT_OTG,
+        .bmAttributes =  0,
+};
+
+/*! Device Description
+ */
+struct usbd_device_description blan_device_description = {
+        .device_descriptor =  &blan_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        .device_qualifier_descriptor =  &blan_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        .otg_descriptor =  &blan_otg_descriptor,
+        .iManufacturer =  CONFIG_OTG_NETWORK_MANUFACTURER,
+        .iProduct =  CONFIG_OTG_NETWORK_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        .iSerialNumber = CONFIG_OTG_SERIAL_NUMBER_STR,
+#endif
+};
+
+
+/*! blan_init
+ * @param function The function instance
+ */
+void blan_init (struct usbd_function_instance *function)
+{
+        struct usbd_class_ethernet_networking_descriptor *ethernet;
+        struct usbd_class_network_channel_descriptor *channel;
+
+        int len = 0;
+        char buf[255];
+
+        buf[0] = 0;
+
+        blan_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 3 : 2;
+
+        // Update the iMACAddress field in the ethernet descriptor
+        {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
+                char address_str[14];
+                snprintf(address_str, 13, "%02x%02x%02x%02x%02x%02x",
+                                local_dev_addr[0], local_dev_addr[1], local_dev_addr[2], 
+                                local_dev_addr[3], local_dev_addr[4], local_dev_addr[5]);
+#else
+                char address_str[20];
+                sprintf(address_str, "%02x%02x%02x%02x%02x%02x",
+                                local_dev_addr[0], local_dev_addr[1], local_dev_addr[2], 
+                                local_dev_addr[3], local_dev_addr[4], local_dev_addr[5]);
+#endif
+                TRACE_MSG0(NTT,"alloc mac string");
+                if ((ethernet = &blan_class_4)) 
+                        ethernet->iMACAddress = usbd_alloc_string(address_str);
+                TRACE_MSG0(NTT,"alloc mac string done");
+        }
+        TRACE_MSG0(NTT,"alloc channel string");
+        if ((channel = &blan_class_5)) 
+                channel->iName = usbd_alloc_string(system_utsname.nodename);
+        TRACE_MSG0(NTT,"alloc channel string done");
+
+#ifdef CONFIG_OTG_NETWORK_BLAN_PADBYTES
+        blan_class_3.bPad = CONFIG_OTG_NETWORK_BLAN_PADBYTES;
+        len += sprintf(buf + len, "PADBYTES: %02x ", blan_class_3.bPad);
+#endif
+#ifdef CONFIG_OTG_NETWORK_BLAN_PADBEFORE
+        blan_class_3.bmDataCapabilities |= BMDATA_PADBEFORE;
+        len += sprintf(buf + len, "PADBEFORE: %02x ", blan_class_3.bmDataCapabilities);
+#endif
+#ifdef CONFIG_OTG_NETWORK_BLAN_PADAFTER
+        blan_class_3.bmDataCapabilities |= BMDATA_PADAFTER;
+        len += sprintf(buf + len, "PADAFTER: %02x ", blan_class_3.bmDataCapabilities);
+#endif
+#ifdef CONFIG_OTG_NETWORK_BLAN_CRC
+        blan_class_3.bmDataCapabilities |= BMDATA_CRC;
+        len += sprintf(buf + len, "CRC: %02x ", blan_class_3.bmDataCapabilities);
+#endif
+#ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT
+        blan_class_3.bmDataCapabilities |= BMDATA_FERMAT;
+        len += sprintf(buf + len, "FERMAT: %02x ", blan_class_3.bmDataCapabilities);
+#endif
+#ifdef CONFIG_OTG_NETWORK_BLAN_HOSTNAME
+        blan_class_3.bmDataCapabilities |= BMDATA_HOSTNAME;
+        len += sprintf(buf + len, "HOSTNAME: %02x ", blan_class_3.bmDataCapabilities);
+#endif
+#ifdef CONFIG_OTG_NETWORK_BLAN_NONBRIDGED
+        blan_class_3.bmNetworkCapabilities |= BMNETWORK_NONBRIDGED;
+        len += sprintf(buf + len, "NONBRIDGE: %02x ", blan_class_3.bmNetworkCapabilities);
+#endif
+#ifdef CONFIG_OTG_NETWORK_BLAN_DATA_NOTIFY_OK
+        blan_class_3.bmNetworkCapabilities |= BMNETWORK_DATA_NOTIFY_OK;
+        len += sprintf(buf + len, "DATA NOTIFY: %02x ", blan_class_3.bmNetworkCapabilities);
+#endif
+        if (strlen(buf))
+                TRACE_MSG1(NTT,"%s", buf);
+}
+
+/*! function driver description
+ */
+struct usbd_function_driver blan_function_driver = {
+        .name =  "network-BLAN",
+        .fops =  &net_fd_function_ops,
+        .device_description =  &blan_device_description,
+        .bNumConfigurations =  sizeof (blan_description) / sizeof (struct usbd_configuration_description),
+        .configuration_description =  blan_description,
+        .idVendor =  __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
+        .idProduct =  __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
+        .bcdDevice =  __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
+        .bNumInterfaces = sizeof (blan_interfaces) / sizeof (struct usbd_interface_description),
+        .interface_list = blan_interfaces, 
+        .endpointsRequested =  ENDPOINTS,
+        .requestedEndpoints =  blan_endpoint_requests,
+};
+#endif                  /* CONFIG_OTG_NETWORK_BLAN */
+
diff -uNr linux/drivers/no-otg/functions/network/cdc.c linux/drivers/otg/functions/network/cdc.c
--- linux/drivers/no-otg/functions/network/cdc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/cdc.c	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,376 @@
+/*
+ * otg/functions/network/cdc.c - Network Function Driver
+ *
+ *      Copyright (c) 2002, 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Chris Lynne <cl@belcarra.com>
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * The CDC network driver implements the standard CDC Ethernet descriptors.
+ *
+ * The CDC protocol is suitable for infrastructure devices that
+ * are implementing a bridged or routed connection betwen an
+ * external network and the USB Host.
+ *
+ */
+/*!
+ * @file otg/functions/network/cdc.c
+ * @brief This file implements the required descriptors to implement
+ * a CDC network device with two interfaces.
+ *
+ * @ingroup NetworkFunction
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <linux/interrupt.h>
+#include <linux/utsname.h>
+#include <linux/netdevice.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include "network.h"
+
+#define NTT network_fd_trace_tag
+
+
+#ifdef CONFIG_OTG_NETWORK_CDC
+/* USB CDC Configuration ********************************************************************* */
+
+/* CDC Communication Interface Class descriptors
+ */
+/*! BULK OUT data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor cdc_data_1 = { 
+    bLength:          0x07, 
+    bDescriptorType:  USB_DT_ENDPOINT,
+    bEndpointAddress: USB_DIR_OUT,
+    bmAttributes:     BULK,
+    wMaxPacketSize:   __constant_cpu_to_le16(0x00),
+    bInterval:        0x00,
+};
+
+/*! BULK IN data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor cdc_data_2 = {
+    bLength:          0x07,
+    bDescriptorType:  USB_DT_ENDPOINT,
+    bEndpointAddress: USB_DIR_IN,
+    bmAttributes:     BULK,
+    wMaxPacketSize:   __constant_cpu_to_le16(0x00),
+    bInterval:        0x00,
+};
+
+/*! INTERRUPT IN data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor cdc_comm_1 = {
+    bLength:          0x07,
+    bDescriptorType:  USB_DT_ENDPOINT,
+    bEndpointAddress: USB_DIR_IN,
+    bmAttributes:     INTERRUPT,
+    wMaxPacketSize:   __constant_cpu_to_le16(0x00),
+    bInterval:        0x0a,
+};
+
+
+
+
+//static u8 cdc_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x10, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
+
+static struct usbd_class_header_function_descriptor cdc_class_1 = {
+    bFunctionLength:	0x05,
+    bDescriptorType:    CS_INTERFACE,
+    bDescriptorSubtype: USB_ST_HEADER,
+    bcdCDC:             __constant_cpu_to_le16(0x0110),
+};
+
+
+//static u8 cdc_class_2[] = { 
+//        0x0d, CS_INTERFACE, USB_ST_ENF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x05, /* 1514 maximum frame size */
+//        0x00, 0x00, 0x00 , };
+static struct usbd_class_ethernet_networking_descriptor cdc_class_2 = {
+    bFunctionLength:    0x0D,
+    bDescriptorType:    CS_INTERFACE,
+    bDescriptorSubtype: USB_ST_HEADER,
+    iMACAddress:        0x00,
+    bmEthernetStatistics: 0x00,
+    wMaxSegmentSize:    __constant_cpu_to_le16(0x05ea),
+    wNumberMCFilters:   0,
+    bNumberPowerFilters: 0,
+};
+
+//static u8 cdc_class_3[] = { 0x05, CS_INTERFACE, USB_ST_UF, 0x00, 0x01, /* bMasterInterface, bSlaveInterface */};
+
+static struct usbd_class_union_function_descriptor cdc_class_3 = 
+{
+     bFunctionLength:    0x05,
+     bDescriptorType:    CS_INTERFACE,
+     bDescriptorSubtype: USB_ST_UF,
+     bMasterInterface:   0x00,
+     bSlaveInterface0:	{1},
+      
+};
+
+static usbd_class_descriptor_t *cdc_comm_class_descriptors[] = { 
+        (struct usbd_generic_class_descriptor *) &cdc_class_1, 
+        (struct usbd_generic_class_descriptor *) &cdc_class_2, 
+        (struct usbd_generic_class_descriptor *) &cdc_class_3, 
+};
+
+/*! Endpoint descriptor list
+ */
+static  usbd_endpoint_descriptor_t  *cdc_data_endpoints[] = { 
+        (struct usbd_endpoint_descriptor *) &cdc_data_1, 
+        (struct usbd_endpoint_descriptor *) &cdc_data_2, 
+};
+static usbd_endpoint_descriptor_t  *cdc_comm_endpoints[] = { 
+        (usbd_endpoint_descriptor_t *) &cdc_comm_1, };
+
+u8 cdc_comm_indexes[] = { INT_IN, };
+u8 cdc_data_indexes[] = { BULK_OUT, BULK_IN, };
+
+
+/*! Comm Interface Descriptor
+ */
+static struct usbd_interface_descriptor cdc_comm_alternate_descriptor  = {
+        bLength: sizeof(struct usbd_interface_descriptor),
+        bDescriptorType: USB_DT_INTERFACE,
+        bInterfaceNumber: 0x00,
+        bAlternateSetting: 0x00,
+        bNumEndpoints: sizeof(cdc_comm_endpoints)/sizeof(usbd_endpoint_descriptor_t *),
+        bInterfaceClass: COMMUNICATIONS_INTERFACE_CLASS,
+        bInterfaceSubClass: COMMUNICATIONS_ENCM_SUBCLASS,
+        bInterfaceProtocol: COMMUNICATIONS_NO_PROTOCOL,
+        iInterface: 0x00
+};
+	
+/*! No Data Interface Descriptor
+ */
+static struct usbd_interface_descriptor  cdc_nodata_alternate_descriptor = {
+        bLength: sizeof(struct usbd_interface_descriptor),
+        bDescriptorType: USB_DT_INTERFACE,
+        bInterfaceNumber: 0x01,
+        bAlternateSetting: 0x00,
+        bNumEndpoints: 0,
+        bInterfaceClass: DATA_INTERFACE_CLASS,
+        bInterfaceSubClass: COMMUNICATIONS_NO_SUBCLASS,
+        bInterfaceProtocol: COMMUNICATIONS_NO_PROTOCOL,
+        iInterface: 0x00
+};
+
+/*! Data Interface Descriptor
+ */
+static struct usbd_interface_descriptor cdc_data_alternate_descriptor  = {
+        bLength: sizeof(struct usbd_interface_descriptor),
+        bDescriptorType: USB_DT_INTERFACE,
+        bInterfaceNumber: 0x01,
+        bAlternateSetting: 0x01,
+        bNumEndpoints: sizeof(cdc_comm_endpoints)/sizeof(usbd_endpoint_descriptor_t *),
+        bInterfaceClass: DATA_INTERFACE_CLASS,
+        bInterfaceSubClass: COMMUNICATIONS_NO_SUBCLASS,
+        bInterfaceProtocol: COMMUNICATIONS_NO_PROTOCOL,
+        iInterface: 0x00
+};
+
+/*! Comm Alternate Interface Description List
+ */
+static struct usbd_alternate_description cdc_comm_alternate_descriptions[] = {
+       {
+         iInterface: CONFIG_OTG_NETWORK_CDC_COMM_INTF,
+         interface_descriptor: &cdc_comm_alternate_descriptor,
+         classes:sizeof (cdc_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
+         class_list:    cdc_comm_class_descriptors,
+
+         endpoints:sizeof (cdc_comm_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+         endpoint_list:  cdc_comm_endpoints,
+         endpoint_indexes: cdc_comm_indexes,
+        },
+};
+
+
+/*! Data Alternate Interface Description List
+ */
+static struct usbd_alternate_description cdc_data_alternate_descriptions[] = {
+        { 
+                iInterface: CONFIG_OTG_NETWORK_CDC_NODATA_INTF,
+                interface_descriptor: (struct usbd_interface_descriptor *)&cdc_nodata_alternate_descriptor, 
+        },
+        { 
+                iInterface: CONFIG_OTG_NETWORK_CDC_DATA_INTF,
+                interface_descriptor: &cdc_data_alternate_descriptor,
+                endpoints:sizeof (cdc_data_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+                endpoint_list: cdc_data_endpoints,
+                endpoint_indexes: cdc_data_indexes,
+        },
+};
+
+/* Interface descriptions and descriptors
+ */
+/*! Interface Description List
+ */
+static struct usbd_interface_description cdc_interfaces[] = {
+        { 
+                alternates:sizeof (cdc_comm_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:cdc_comm_alternate_descriptions,
+        },
+        { 
+                alternates:sizeof (cdc_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:cdc_data_alternate_descriptions,
+        },
+};
+
+
+/* Configuration descriptions and descriptors
+ */
+
+/*! Configuration Descriptor 
+ */
+static struct usbd_configuration_descriptor cdc_configuration_descriptor = {
+        bLength: sizeof(struct usbd_configuration_descriptor),
+        bDescriptorType: USB_DT_CONFIGURATION,
+        wTotalLength:0,
+        bNumInterfaces:sizeof(cdc_interfaces)/sizeof(struct usbd_interface_description *),
+        bConfigurationValue: 0x01,
+        iConfiguration: 0x00,
+        bmAttributes:0,
+        bMaxPower:0,
+};
+
+/*! Configuration Description List 
+ */
+static struct usbd_configuration_description cdc_description[] = {
+        { iConfiguration: CONFIG_OTG_NETWORK_CDC_DESC,
+                configuration_descriptor: &cdc_configuration_descriptor,
+        },
+};
+
+
+
+/* Device Description
+ */
+
+/*! Device Descriptor 
+ */
+static struct usbd_device_descriptor cdc_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+/*! High Speed Device Qualifier Descriptor 
+ */
+static struct usbd_device_qualifier_descriptor cdc_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+/*! Endpoint Request List
+ */
+static struct usbd_endpoint_request cdc_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 1, 1, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512,  },
+        { 1, 1, 1, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512,  },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
+        { 0, },
+};
+
+/*! OTG Descriptor
+ */
+static struct usbd_otg_descriptor cdc_otg_descriptor = {
+        bLength : sizeof(struct usbd_otg_descriptor),
+        bDescriptorType: USB_DT_OTG,
+        bmAttributes: 0,
+};
+
+/*! Device Description
+ */
+struct usbd_device_description cdc_device_description = {
+        device_descriptor: &cdc_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &cdc_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &cdc_otg_descriptor,
+        iManufacturer: CONFIG_OTG_NETWORK_MANUFACTURER,
+        iProduct: CONFIG_OTG_NETWORK_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        iSerialNumber:CONFIG_OTG_SERIAL_NUMBER_STR,
+#endif
+};
+
+
+
+/*! cdc_init
+ * @param function The function instance
+ */
+void cdc_init (struct usbd_function_instance *function)
+{
+        struct usbd_class_ethernet_networking_descriptor *ethernet;
+
+        cdc_comm_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 1 : 0;
+
+        // Update the iMACAddress field in the ethernet descriptor
+        {
+                char address_str[14];
+                snprintf(address_str, 13, "%02x%02x%02x%02x%02x%02x",
+                                remote_dev_addr[0], remote_dev_addr[1], remote_dev_addr[2], 
+                                remote_dev_addr[3], remote_dev_addr[4], remote_dev_addr[5]);
+
+                if ((ethernet = &cdc_class_2)) {
+                        if (ethernet->iMACAddress) {
+                                usbd_free_string_descriptor(ethernet->iMACAddress);
+                        }
+                        ethernet->iMACAddress = usbd_alloc_string(address_str);
+                }
+        }
+}
+
+
+/*! function driver description
+ */
+struct usbd_function_driver cdc_function_driver = {
+        name: "network-CDC",
+        fops: &net_fd_function_ops,
+        device_description: &cdc_device_description,
+        bNumConfigurations: sizeof (cdc_description) / sizeof (struct usbd_configuration_description),
+        configuration_description: cdc_description,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
+        bNumInterfaces:sizeof (cdc_interfaces) / sizeof (struct usbd_interface_description),
+        interface_list:cdc_interfaces,
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: cdc_endpoint_requests,
+};
+#endif                  /* CONFIG_OTG_NETWORK_CDC */
+
diff -uNr linux/drivers/no-otg/functions/network/eem.c linux/drivers/otg/functions/network/eem.c
--- linux/drivers/no-otg/functions/network/eem.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/eem.c	2006-09-01 21:41:28.000000000 +0200
@@ -0,0 +1,247 @@
+/*
+ * otg/functions/network/eem.c - Network Function Driver
+ *
+ *      Copyright (c) 2002, 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Chris Lynne <cl@belcarra.com>
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*!
+ * @file otg/functions/network/eem.c
+ * @brief This file implements the required descriptors to implement
+ * a eem network device with a single interface.
+ *
+ * The BASIC network driver implements a very simple descriptor set.
+ * A single interface with two BULK data endpoints and a optional
+ * INTERRUPT endpoint.
+ *
+ * @ingroup NetworkFunction
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/utsname.h>
+#include <linux/netdevice.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include "network.h"
+
+#define NTT network_fd_trace_tag
+
+#ifdef CONFIG_OTG_NETWORK_BASIC
+/* USB BASIC Configuration ******************************************************************** */
+
+/* BASIC Communication Interface Class descriptors
+ */
+/*! BULK OUT data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor eem_data_1 = { 
+    bLength:sizeof(struct usbd_endpoint_descriptor),
+    bDescriptorType:USB_DT_ENDPOINT,
+    bEndpointAddress:USB_DIR_OUT, 
+    bmAttributes: BULK,     
+    wMaxPacketSize: 0, 
+    bInterval: 0,
+};
+/*! BULK IN data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor eem_data_2 =// { 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  BULK,     0, 0x00, 0x00, };
+{
+    bLength:sizeof(struct usbd_endpoint_descriptor),
+    bDescriptorType:USB_DT_ENDPOINT,
+    bEndpointAddress:USB_DIR_IN, 
+    bmAttributes: BULK,     
+    wMaxPacketSize: 0, 
+    bInterval: 0x0,
+};
+
+/*! INTERRUPT IN data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor eem_comm_1 = //{ 0x07, USB_DT_ENDPOINT, USB_DIR_IN,  INTERRUPT,0, 0x00, 0x0a, };
+{
+    bLength:sizeof(struct usbd_endpoint_descriptor),
+    bDescriptorType:USB_DT_ENDPOINT,
+    bEndpointAddress:USB_DIR_IN, 
+    bmAttributes: INTERRUPT,     
+    wMaxPacketSize: 0, 
+    bInterval: 0xa,
+};
+
+/*! Endpoint descriptor list
+ */
+static  struct usbd_endpoint_descriptor  *eem_default[] = { &eem_data_1, 
+    &eem_data_2, 
+    &eem_comm_1, };
+u8 eem_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
+
+/*! Data Interface Descriptor
+ */
+static struct usbd_interface_descriptor  eem_data_alternate_descriptor = {
+    bLength:sizeof(struct usbd_interface_descriptor),
+    bDescriptorType:USB_DT_INTERFACE,
+    bInterfaceNumber: 0x00, 
+    bAlternateSetting: 0x00, // bInterfaceNumber, bAlternateSetting
+    sizeof (eem_default) / sizeof(struct usbd_endpoint_descriptor *), // bNumEndpoints
+    bInterfaceClass:LINEO_CLASS, 
+    bInterfaceSubClass:LINEO_SUBCLASS_BASIC_NET, 
+    bInterfaceProtocol:LINEO_BASIC_NET_CRC, 
+    iInterface:0x00,
+};
+
+/*! Data Alternate Interface Description List
+ */
+static struct usbd_alternate_description eem_data_alternate_descriptions[] = {
+        { iInterface: CONFIG_OTG_NETWORK_BASIC_INTF,
+                interface_descriptor: (struct usbd_interface_descriptor *)&eem_data_alternate_descriptor,
+                endpoints:sizeof (eem_default) / sizeof(struct usbd_endpoint_descriptor *),
+                endpoint_list: eem_default,
+                endpoint_indexes: eem_indexes,
+                },
+};
+
+
+/* BASIC Data Interface Alternate descriptions and descriptors
+ */
+
+/* BASIC Interface descriptions and descriptors
+ */
+/*! Interface Description List
+ */
+struct usbd_interface_description eem_interfaces[] = {
+        { alternates:sizeof (eem_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+                alternate_list:eem_data_alternate_descriptions,},
+};
+
+/* BASIC Configuration descriptions and descriptors
+ */
+/*! Configuration Descriptor 
+ */
+u8 eem_configuration_descriptor[sizeof(struct usbd_configuration_descriptor)] = {
+        0x09, USB_DT_CONFIGURATION, 0x00, 0x00, // wLength
+        sizeof (eem_interfaces) / sizeof (struct usbd_interface_description),
+        0x01, 0x00, // bConfigurationValue, iConfiguration
+        0, 0,
+};
+
+/*! Configuration Description List 
+ */
+struct usbd_configuration_description eem_description[] = {
+        { iConfiguration: CONFIG_OTG_NETWORK_BASIC_DESC,
+                configuration_descriptor: (struct usbd_configuration_descriptor *)eem_configuration_descriptor,
+        },
+
+};
+
+/* BASIC Device Description
+ */
+/*! Device Descriptor 
+ */
+static struct usbd_device_descriptor eem_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+/*! High Speed Device Qualifier Descriptor 
+ */
+static struct usbd_device_qualifier_descriptor eem_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+/*! Endpoint Request List
+ */
+static struct usbd_endpoint_request eem_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
+        { 0, },
+};
+
+/*! OTG Descriptor
+ */
+static struct usbd_otg_descriptor eem_otg_descriptor = {
+        bLength : sizeof(struct usbd_otg_descriptor),
+        bDescriptorType: USB_DT_OTG,
+        bmAttributes: 0,
+};
+
+/*! Device Description
+ */
+struct usbd_device_description eem_device_description = {
+        device_descriptor: &eem_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &eem_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &eem_otg_descriptor,
+        iManufacturer: CONFIG_OTG_NETWORK_MANUFACTURER,
+        iProduct: CONFIG_OTG_NETWORK_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        iSerialNumber:CONFIG_OTG_SERIAL_NUMBER_STR,
+#endif
+};
+
+
+/*! eem_init
+ * @param function The function instance
+ */
+void eem_init (struct usbd_function_instance *function)
+{
+        eem_data_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 3 : 2;
+}
+
+/*! function driver description
+ */
+struct usbd_function_driver eem_function_driver = {
+        name: "network-BASIC",
+        fops: &net_fd_function_ops,
+        device_description: &eem_device_description,
+        bNumConfigurations: sizeof (eem_description) / sizeof (struct usbd_configuration_description),
+        configuration_description: eem_description,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
+        bNumInterfaces:sizeof (eem_interfaces) / sizeof (struct usbd_interface_description),
+        interface_list:eem_interfaces,
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: eem_endpoint_requests,
+};
+#endif                  /* CONFIG_OTG_NETWORK_BASIC */
+
diff -uNr linux/drivers/no-otg/functions/network/fermat.c linux/drivers/otg/functions/network/fermat.c
--- linux/drivers/no-otg/functions/network/fermat.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/fermat.c	2006-09-01 21:41:30.000000000 +0200
@@ -0,0 +1,140 @@
+/*
+ * otg/functions/network/fermat.c - Network Function Driver
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*!
+ * @file otg/functions/network/fermat.c
+ * @brief This implements a special data munging function that
+ * randomizes data. This is a very specific fix for a device
+ * that had trouble with runs of zeros.
+ *
+ * @ingroup NetworkFunction
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT
+
+#include "fermat.h"
+
+#ifndef FERMAT_DEFINED
+typedef unsigned char BYTE;
+typedef struct fermat {
+        int length;
+        BYTE power[256];
+} FERMAT;
+#endif
+
+
+static int fermat_setup(FERMAT *p, int seed){
+        int i = 0;
+        unsigned long x,y;
+        y = 1;
+        do{
+                x = y;
+                p->power[i] = ( x == 256 ? 0 : x);
+                y = ( seed * x ) % 257;
+                i += 1;
+        }while( y != 1);
+        p->length = i;
+        return i;
+}
+
+static void fermat_xform(FERMAT *p, BYTE *data, int length){
+        BYTE *pw = p->power;
+        int   i, j;
+        BYTE * q ;
+        for(i = 0, j=0, q = data; i < length; i++, j++, q++){
+                if(j>=p->length){
+                        j = 0;
+                }
+                *q ^= pw[j];
+        }
+}
+
+static FERMAT default_fermat;
+static const int primitive_root = 5;
+void fermat_init(){
+        (void) fermat_setup(&default_fermat, primitive_root); 
+}
+
+// Here are the public official versions.
+// Change the primitive_root above to another primitive root
+// if you need better scatter. Possible values are 3 and 7
+
+
+void fermat_encode(BYTE *data, int length){
+        fermat_xform(&default_fermat, data, length);
+}
+
+void fermat_decode(BYTE *data, int length){
+        fermat_xform(&default_fermat, data, length);
+}
+
+
+// Note: the seed must be a "primitive root" of 257. This means that
+// the return value of the setup routine must be 256 (otherwise the
+// seed is not a primitive root.  The routine will still work fine
+// but will be less pseudo-random.
+
+#undef TEST 
+#if TEST
+#include <stdio.h>
+#include <memory.h>
+
+// Use FERMAT in two ways: to encode, and to generate test data.
+
+main(){
+        //Note 3, 5, and 7 are primitive roots of 257
+        // 11 is not a primitive root
+        FERMAT three, five, seven;
+
+        FERMAT three2;
+        printf("Cycle lengths: 3,5,7 %d %d %d \n", 
+                        fermat_setup(&three, 3), 
+                        fermat_setup(&five, 5), 
+                        fermat_setup(&seven, 7));
+        three2=three; // Copy data from three
+        fermat_xform(&three,three2.power,three2.length);
+        fermat_xform(&five,three2.power,three2.length);
+        fermat_xform(&seven,three2.power,three2.length);
+        fermat_xform(&seven,three2.power,three2.length);
+        fermat_xform(&five,three2.power,three2.length);
+        fermat_xform(&three,three2.power,three2.length);
+
+        //At this stage, three2 and three should be identical
+        if(memcpy(&three,&three2,sizeof(FERMAT))){
+                printf("Decoded intact\n");
+        }
+
+        fermat_init();
+        fermat_encode(three2.power,256);
+
+}
+#endif
+
+#endif /* CONFIG_OTG_NETWORK_BLAN_FERMAT */
+
diff -uNr linux/drivers/no-otg/functions/network/fermat.h linux/drivers/otg/functions/network/fermat.h
--- linux/drivers/no-otg/functions/network/fermat.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/fermat.h	2006-09-01 21:41:30.000000000 +0200
@@ -0,0 +1,46 @@
+/*
+ * otg/functions/network/fermat.h - Network Function Driver
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+/*!
+ * @file otg/functions/network/fermat.h
+ * @brief Fermat related data structures.
+ *
+ *
+ * @ingroup NetworkFunction
+ */
+
+#ifndef FERMAT_DEFINED
+#define FERMAT_DEFINED 1
+typedef unsigned char BYTE;
+typedef struct fermat {
+        int length;
+        BYTE power[256];
+} FERMAT;
+
+void fermat_init(void);
+void fermat_encode(BYTE *data, int length);
+void fermat_decode(BYTE *data, int length);
+#endif
+
+
diff -uNr linux/drivers/no-otg/functions/network/net-fd.c linux/drivers/otg/functions/network/net-fd.c
--- linux/drivers/no-otg/functions/network/net-fd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/net-fd.c	2006-09-01 21:41:30.000000000 +0200
@@ -0,0 +1,1463 @@
+/*
+ * otg/functions/network/net-fd.c - Network Function Driver
+ *
+ *      Copyright (c) 2002, 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>
+ *      Chris Lynne <cl@belcarra.com>
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*!
+ * @file otg/functions/network/net-fd.c
+ * @brief The lower edge (USB Device Function) implementation of
+ * the Network Function Driver. This performs the core protocol
+ * handling and data encpasulation.
+ *
+ * This implements the lower edge (USB Device) layer of the Network Function
+ * Driver. Specifically the data encapsulation, envent and protocol handlers.
+ *
+ *
+ *
+ * This network function driver intended to interoperate with 
+ * Belcarra's USBLAN Class drivers. 
+ *
+ * These are available for Windows, Linux and Mac OSX. For more 
+ * information and to download a copy for testing:
+ *
+ *      http://www.belcarra.com/usblan/
+ *
+ * When configured for CDC it can also work with any CDC Class driver.
+ *
+ *
+ * @ingroup NetworkFunction
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+//#include <linux/config.h>
+//#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <net/arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/smp_lock.h>
+#include <linux/ctype.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/atmdev.h>
+#include <linux/pkt_sched.h>
+#include <linux/random.h>
+#include <linux/utsname.h>
+
+#include <linux/ip.h>
+#include <linux/if_ether.h>
+#include <linux/in.h>
+#include <linux/inetdevice.h>
+
+#include <linux/kmod.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <otg/usbp-chap9.h>
+//#include <otg/usbd-mem.h>
+#include <otg/usbp-func.h>
+
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+
+#include "network.h"
+#include "net-fd.h"
+#include "net-os.h"
+#ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT
+#include "fermat.h"
+#endif
+
+otg_tag_t network_fd_trace_tag;
+#define NTT network_fd_trace_tag
+
+#if defined(CONFIG_OTG_NETWORK_CDC)
+void cdc_init(struct usbd_function_instance *);
+extern struct usbd_function_driver cdc_function_driver;
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_EEM
+void eem_init(struct usbd_function_instance *);
+extern struct usbd_function_driver eem_function_driver;
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_BASIC
+void basic_init(struct usbd_function_instance *);
+extern struct usbd_function_driver basic_function_driver;
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_BASIC2
+void basic2_init(struct usbd_function_instance *);
+extern struct usbd_function_driver basic2_function_driver;
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_SAFE
+void safe_init(struct usbd_function_instance *);
+extern struct usbd_function_driver safe_function_driver;
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_BLAN
+void blan_init(struct usbd_function_instance *);
+extern struct usbd_function_driver blan_function_driver;
+#endif
+
+static char ip_addr_str[20];
+u32 ip_addr;
+u32 router_ip;
+u32 network_mask;
+u32 dns_server_ip;
+
+//_________________________________________________________________________________________________
+
+/*
+ * If the following are defined we implement the crc32_copy routine using
+ * Duff's device. This will unroll the copy loop by either 4 or 8. Do not
+ * use these without profiling to test if it actually helps on any specific
+ * device.
+ */
+#undef CONFIG_OTG_NETWORK_CRC_DUFF4
+#undef CONFIG_OTG_NETWORK_CRC_DUFF8
+
+static u32 *network_crc32_table;
+
+#define CRC32_INIT   0xffffffff      // Initial FCS value
+#define CRC32_GOOD   0xdebb20e3      // Good final FCS value
+
+#define CRC32_POLY   0xedb88320      // Polynomial for table generation
+        
+#define COMPUTE_FCS(val, c) (((val) >> 8) ^ network_crc32_table[((val) ^ (c)) & 0xff])
+
+//_________________________________________________________________________________________________
+//                                      crc32_copy
+
+/*! make_crc_table
+ * Generate the crc32 table
+ *
+ * @return non-zero if malloc fails
+ */
+STATIC int make_crc_table(void)
+{
+        u32 n;
+        RETURN_ZERO_IF(network_crc32_table);
+        RETURN_ENOMEM_IF(!(network_crc32_table = (u32 *)ckmalloc(256*4, GFP_KERNEL)));
+        for (n = 0; n < 256; n++) {
+                int k;
+                u32 c = n;
+                for (k = 0; k < 8; k++) {
+                        c =  (c & 1) ? (CRC32_POLY ^ (c >> 1)) : (c >> 1);
+                }
+                network_crc32_table[n] = c;
+        }
+        return 0;
+}
+
+#if !defined(CONFIG_OTG_NETWORK_CRC_DUFF4) && !defined(CONFIG_OTG_NETWORK_CRC_DUFF8)
+/*! crc32_copy
+ * Copies a specified number of bytes, computing the 32-bit CRC FCS as it does so.
+ *
+ * @param dst   Pointer to the destination memory area.
+ * @param src   Pointer to the source memory area.
+ * @param len   Number of bytes to copy.
+ * @param val   Starting value for the CRC FCS.
+ *
+ * @return      Final value of the CRC FCS.
+ *
+ * @sa crc32_pad
+ */
+static u32 __inline__ crc32_copy (u8 *dst, u8 *src, int len, u32 val)
+{
+        for (; len-- > 0; val = COMPUTE_FCS (val, *dst++ = *src++));
+        return val;
+}
+
+#else /* DUFFn */
+
+/*! crc32_copy
+ * Copies a specified number of bytes, computing the 32-bit CRC FCS as it does so.
+ *
+ * @param dst   Pointer to the destination memory area.
+ * @param src   Pointer to the source memory area.
+ * @param len   Number of bytes to copy.
+ * @param val   Starting value for the CRC FCS.
+ *
+ * @return      Final value of the CRC FCS.
+ *
+ * @sa crc32_pad
+ */
+static u32 crc32_copy (u8 *dst, u8 *src, int len, u32 val)
+{
+#if defined(CONFIG_OTG_NETWORK_CRC_DUFF8)
+        int n = (len + 7) / 8;
+        switch (len % 8) 
+#elif defined(CONFIG_OTG_NETWORK_CRC_DUFF4)
+                int n = (len + 3) / 4;
+        switch (len % 4) 
+#endif
+        {
+        case 0: do {
+                        val = COMPUTE_FCS (val, *dst++ = *src++);
+#if defined(CONFIG_OTG_NETWORK_CRC_DUFF8)
+                case 7:
+                        val = COMPUTE_FCS (val, *dst++ = *src++);
+                case 6:
+                        val = COMPUTE_FCS (val, *dst++ = *src++);
+                case 5:
+                        val = COMPUTE_FCS (val, *dst++ = *src++);
+                case 4:
+                        val = COMPUTE_FCS (val, *dst++ = *src++);
+#endif
+                case 3:
+                        val = COMPUTE_FCS (val, *dst++ = *src++);
+                case 2:
+                        val = COMPUTE_FCS (val, *dst++ = *src++);
+                case 1:
+                        val = COMPUTE_FCS (val, *dst++ = *src++);
+                } while (--n > 0);
+        }
+        return val;
+}
+#endif /* DUFFn */
+
+
+//_________________________________________________________________________________________________
+//                                      crc32_pad
+
+/*! crc32_pad - pad and calculate crc32
+ *
+ * @return CRC FCS
+ */
+static u32 __inline__ crc32_pad (u8 *dst, int len, u32 val)
+{
+        for (; len-- > 0; val = COMPUTE_FCS (val, *dst++ = '\0'));
+        return val;
+}
+
+//_________________________________________________________________________________________________
+//                                      net_fd_send_int
+//
+
+/*! net_fd_urb_sent_int - callback for completed INT URB
+ *
+ * Handles notification that an urb has been sent (successfully or otherwise).
+ *
+ * @return non-zero for failure.
+ */
+STATIC int net_fd_urb_sent_int (struct usbd_urb *urb, int urb_rc)
+{
+        unsigned long flags;
+        int rc = -EINVAL;
+        struct usb_network_private *npd = urb->function_privdata;
+
+        TRACE_MSG3(NTT,"urb: %p npd: %p urb_rc: %d", urb, npd, urb_rc);
+
+        local_irq_save(flags);
+        npd->int_urb = NULL;
+        usbd_free_urb (urb);
+        local_irq_restore(flags);
+        return 0;
+}
+
+/*! net_fd_send_int_blan - send an interrupt notification response
+ *
+ * Generates a response urb on the notification (INTERRUPT) endpoint.
+ *
+ * This is called from either a scheduled task or from the process context
+ * that calls network_open() or network_close().
+ * This must be called with interrupts locked out as net_fd_event_handler can
+ * change the NETWORK_ATTACHED status
+ *
+ */
+STATIC void net_fd_send_int_blan(struct usb_network_private *npd, int connected, int data)
+{
+        struct usbd_urb *urb;
+        struct cdc_notification_descriptor *cdc;
+        int rc;
+        struct usbd_function_instance *function = (npd?npd->function:NULL);
+
+        TRACE_MSG2(NTT,"npd=%p function=%p",npd,function);
+
+        do {
+                BREAK_IF(!function);
+
+
+                BREAK_IF(npd->network_type != network_blan);
+                BREAK_IF(!npd->have_interrupt);
+
+                BREAK_IF(!(npd->flags & NETWORK_ATTACHED));
+
+                TRACE_MSG3(NTT,"connected: %d network: %d %d", connected, 
+                           npd->network_type, network_blan);
+
+                BREAK_IF(usbd_get_device_status(function) != USBD_OK);
+
+                //if (npd->int_urb) {
+                //        printk(KERN_INFO"%s: int_urb: %p\n", __FUNCTION__, npd->int_urb);
+                //        usbd_cancel_urb_irq(npd->int_urb);
+                //        npd->int_urb = NULL;
+                //}
+
+                BREAK_IF(!(urb = usbd_alloc_urb (function, INT_IN, 
+                                                sizeof(struct cdc_notification_descriptor), net_fd_urb_sent_int)));
+                
+                urb->actual_length = sizeof(struct cdc_notification_descriptor);
+                memset(urb->buffer, 0, sizeof(struct cdc_notification_descriptor));
+                urb->function_privdata = npd;
+
+                cdc = (struct cdc_notification_descriptor *)urb->buffer;
+
+                cdc->bmRequestType = 0xa1;
+
+                if (data) {
+                        cdc->bNotification = 0xf0;
+                        cdc->wValue = 1;
+                }
+                else {
+                        cdc->bNotification = 0x00;
+                        cdc->wValue = connected ? 0x01 : 0x00;
+                }
+                cdc->wIndex = 0x00; // XXX interface - check that this is correct
+
+
+                npd->int_urb = urb;
+                TRACE_MSG1(NTT,"int_urb: %p", urb);
+                BREAK_IF (!(rc = usbd_start_in_urb (urb)));
+
+                TRACE_MSG1(NTT,"usbd_start_in_urb failed err: %x", rc);
+                printk(KERN_ERR"%s: usbd_start_in_urb failed err: %x\n", __FUNCTION__, rc);
+                urb->function_privdata = NULL;
+                npd->int_urb = NULL;
+                usbd_free_urb (urb);
+
+        } while(0);
+}
+
+//_________________________________________________________________________________________________
+//                                      net_fd_start_xmit
+
+/*! net_fd_urb_sent_bulk - callback for completed BULK xmit URB
+ *
+ * Handles notification that an urb has been sent (successfully or otherwise).
+ *
+ * @param urb     Pointer to the urb that has been sent.
+ * @param urb_rc  Result code from the send operation.
+ *
+ * @return non-zero for failure.
+ */
+STATIC int net_fd_urb_sent_bulk (struct usbd_urb *urb, int urb_rc)
+{
+        unsigned long flags;
+        void *buff_ctx;
+        int rc = -EINVAL;
+
+        TRACE_MSG2(NTT,"urb: %p urb_rc: %d", urb, urb_rc);
+
+        local_irq_save(flags);
+        do {
+
+                BREAK_IF(!urb);
+                buff_ctx = urb->function_privdata;
+                TRACE_MSG2(NTT,"urb: %p buff_ctx: %p", urb, buff_ctx);
+                urb->function_privdata = NULL;
+
+                BREAK_IF(net_os_xmit_done(urb->function_instance,buff_ctx,urb_rc));
+
+                usbd_free_urb (urb);
+                rc = 0;
+
+        } while (0);
+        local_irq_restore(flags);
+        return rc;
+}
+
+/*! net_fd_start_xmit - start sending a buffer
+ *
+ * Called with net_os_mutex_enter()d.
+ *
+ * @return: 0 if all OK
+ *         -EINVAL, -EUNATCH, -ENOMEM
+ *         rc from usbd_start_in_urb() if that fails (is != 0, may be one of err values above) 
+ *         Note: -ECOMM is interpreted by calling routine as signal to leave IF stopped.
+ */
+STATIC int net_fd_start_xmit (struct usb_network_private *npd, u8 *buff, int len, void *buff_ctx)
+{
+        struct usbd_function_instance *function = (npd?npd->function:NULL);
+        struct usbd_urb *urb = NULL;
+        int rc;
+        int in_pkt_sz;
+        u8 *cp;
+        u32 crc;
+        TRACE_MSG2(NTT,"npd=%p function=%p",npd,function);
+
+#if 0
+        printk(KERN_INFO"%s: %s len: %d encap: %d\n", __FUNCTION__, net_device->name, len, npd->encapsulation);
+        printk(KERN_INFO"start_xmit: len: %x data: %p\n", len, buff);
+        {
+                u8 *cp = buff;
+                int i;
+                for (i = 0; i < len; i++) {
+                        if ((i%32) == 0) {
+                                printk("\ntx[%2x] ", i);
+                        }
+                        printk("%02x ", *cp++);
+                }
+                printk("\n");
+        }
+#endif
+
+        if (!(npd->flags & NETWORK_ATTACHED)) {
+                return -EUNATCH;
+        }
+        if (usbd_get_device_status(function) != USBD_OK) {
+                return -EINVAL;
+        }
+
+#if defined(CONFIG_OTG_NETWORK_CDC)
+        // verify interface is enabled - non-zero altsetting means data is enabled
+        if (!usbd_interface_AltSetting(function, DATA_INTF)) {
+                return -EINVAL;
+        }
+#endif
+        in_pkt_sz = usbd_endpoint_wMaxPacketSize(function, BULK_IN, usbd_high_speed(function));
+
+        if (npd->encapsulation != simple_crc) {
+                TRACE_MSG0(NTT,"unknown encapsulation");
+                printk(KERN_ERR"%s: unknown encapsulation\n", __FUNCTION__);
+                // Since we are now only really using one, just fix it.
+                npd->encapsulation = simple_crc;
+        }
+        //TRACE_MSG0(NTT,"SIMPLE_CRC");
+        // allocate urb 5 bytes larger than required
+        if (!(urb = usbd_alloc_urb (function, BULK_IN, len + 5 + 4 + in_pkt_sz, net_fd_urb_sent_bulk ))) {
+                u8 epa = usbd_endpoint_bEndpointAddress(function, BULK_IN, usbd_high_speed(function));
+                TRACE_MSG2(NTT,"urb alloc failed len: %d endpoint: %02x", len, epa);
+                printk(KERN_ERR"%s: urb alloc failed len: %d endpoint: %02x\n", __FUNCTION__, len, epa);
+                return -ENOMEM;
+        }
+
+        switch (npd->network_type) {
+        case network_eem:
+                cp = urb->buffer + 2;
+                urb->actual_length = len + 2;
+                break;
+        default:
+                cp = urb->buffer;
+                urb->actual_length = len;
+                break;
+        }
+        // copy and crc len bytes
+        crc = crc32_copy(cp, buff, len, CRC32_INIT);
+
+        switch (npd->network_type) {
+        case network_eem:
+                break;
+        default:
+                if ((urb->actual_length % in_pkt_sz) == (in_pkt_sz - 4)) {
+
+                        #undef CONFIG_OTG_NETWORK_PADBYTE
+                        #ifdef CONFIG_OTG_NETWORK_PADBYTE
+                        // add a pad byte if required to ensure a short packet, usbdnet driver
+                        // will correctly handle pad byte before or after CRC, but the MCCI driver
+                        // wants it before the CRC.
+                        crc = crc32_pad(urb->buffer + urb->actual_length, 1, crc);
+                        urb->actual_length++;
+                        #else /* CONFIG_OTG_NETWORK_PADBYTE */
+                        urb->flags |= USBD_URB_SENDZLP; 
+                        TRACE_MSG2(NTT,"setting ZLP: urb: %p flags: %x", urb, urb->flags);
+                        #endif /* CONFIG_OTG_NETWORK_PADBYTE */
+                }
+                break;
+        }
+        // munge and append crc
+        crc = ~crc;
+        urb->buffer[urb->actual_length++] = crc & 0xff;
+        urb->buffer[urb->actual_length++] = (crc >> 8) & 0xff;
+        urb->buffer[urb->actual_length++] = (crc >> 16) & 0xff;
+        urb->buffer[urb->actual_length++] = (crc >> 24) & 0xff;
+        // End of CRC processing
+        //
+        switch (npd->network_type) {
+        case network_eem:
+                break;
+        default:
+                break;
+        }
+
+        TRACE_MSG3(NTT,"urb=%p buff_ctx=%p priv=%p",urb,buff_ctx,urb->function_privdata);
+        urb->function_privdata = (void *) buff_ctx;
+#if 0
+        printk(KERN_INFO"start_xmit: len: %d : %d data: %p\n", skb->len, urb->actual_length, urb->buffer);
+        {
+                u8 *cp = urb->buffer;
+                int i;
+                for (i = 0; i < urb->actual_length; i++) {
+                        if ((i%32) == 0) {
+                                printk("\ntx[%2x] ", i);
+                        }
+                        printk("%02x ", *cp++);
+                }
+                printk("\n");
+        }
+#endif
+#if defined(CONFIG_OTG_NETWORK_BLAN_FERMAT)
+        if (npd->fermat) {
+                fermat_encode(urb->buffer, urb->actual_length);
+        }
+#endif
+        TRACE_MSG1(NTT,"sending urb: %p", urb);
+        if ((rc = usbd_start_in_urb (urb))) {
+
+                TRACE_MSG1(NTT,"FAILED: %d", rc);
+                printk(KERN_ERR"%s: FAILED: %d\n", __FUNCTION__, rc);
+                urb->function_privdata = NULL;
+                usbd_free_urb (urb);
+
+                return(rc);
+        }
+        #if 0
+        {
+                static int xmit_count = 0;
+                if (xmit_count++ == 100) {
+                        TRACE_MSG1(NTT, "halt test: %02x", BULK_IN);
+                        usbd_halt_endpoint(function, BULK_IN);
+                }
+        }
+        #endif
+
+        TRACE_MSG0(NTT,"OK");
+        return 0;
+}
+
+
+//_________________________________________________________________________________________________
+
+/*! net_fd_recv_urb - callback to process a received URB
+ *
+ * @return non-zero for failure.
+ */
+STATIC int net_fd_recv_urb(struct usbd_urb *urb, int rc)
+{
+        struct usbd_function_instance *function = urb->function_instance;
+        struct usb_network_private *npd = urb->function_privdata;
+        void *buff_ctx = NULL;
+        u8 *buff;
+        int crc_bad = 0;
+        int trim = 0;
+        int len;
+        int out_pkt_sz;
+        u32 crc;
+
+#if 0
+        printk(KERN_INFO"%s: urb: %p len: %d maxtransfer: %d encap: %d\n", __FUNCTION__, 
+                        urb, urb->actual_length, npd->maxtransfer, npd->encapsulation);
+
+        {
+                u8 *cp = urb->buffer;
+                int i;
+                for (i = 0; i < urb->actual_length; i++) {
+                        if ((i%32) == 0) {
+                                printk("\n[%2x] ", i);
+                        }
+                        printk("%02x ", *cp++);
+                }
+                printk("\n");
+        }
+#endif
+        if (!urb || !urb->function_instance || !npd || !npd->function ||
+            urb->function_instance != npd->function) {
+                TRACE_MSG4(NTT,"urb=%p npd=%p u->f=%p n->f=%p",
+                                 urb,(urb?npd:NULL),(urb?urb->function_instance:NULL),
+                                 ((urb&&npd)?npd->function:NULL));
+        }
+
+        THROW_IF(urb->status != RECV_OK, error);
+
+        out_pkt_sz = usbd_endpoint_wMaxPacketSize(function, BULK_OUT, usbd_high_speed(function));
+        // There is only one working encapsulation.
+        if (npd->encapsulation != simple_crc) {
+                 npd->encapsulation = simple_crc;
+        }
+
+        len = urb->actual_length;
+        trim = 0;
+        buff_ctx = net_os_alloc_buff(npd, &buff, len);
+        THROW_IF((NULL == buff_ctx), error);
+
+#if defined(CONFIG_OTG_NETWORK_BLAN_PADAFTER)
+        {
+                /* This version simply checks for a correct CRC along the 
+                 * entire packet. Some UDC's have trouble with some packet
+                 * sizes, this allows us to add pad bytes after the CRC.
+                 */
+
+                u8 *src = urb->buffer;
+                int copied;
+
+                // XXX this should work, but the MIPS optimizer seems to get it wrong....
+                //copied = (len < out_pkt_sz) ? 0 : ((len / out_pkt_sz) - 1) * out_pkt_sz;
+                        
+                if (len < out_pkt_sz*2) 
+                        copied = 0;
+                else {
+                        int pkts = ((len - out_pkt_sz) / out_pkt_sz);
+                        copied = (pkts - 1) * out_pkt_sz;
+                }
+
+                len -= copied;
+                crc = CRC32_INIT;
+                for (; copied-- > 0 ; crc = COMPUTE_FCS (crc, *buff++ = *src++));
+
+                for (; (len-- > 0) && (CRC32_GOOD != crc); crc = COMPUTE_FCS (crc, *buff++ = *src++));
+
+                trim = len + 4;
+
+                if (CRC32_GOOD != crc) {
+                        TRACE_MSG1(NTT,"AAA frame: %03x", urb->framenum);
+                        THROW_IF(npd->crc, crc_error);
+                }
+                else 
+                        npd->crc = 1;
+        }
+#else
+        /* 
+         * The CRC can be sent in two ways when the size of the transfer 
+         * ends up being a multiple of the packetsize:
+         *
+         *                                           |
+         *                <data> <CRC><CRC><CRC><CRC>|<???>     case 1
+         *                <data> <NUL><CRC><CRC><CRC>|<CRC>     case 2
+         *           <data> <NUL><CRC><CRC><CRC><CRC>|          case 3
+         *     <data> <NUL><CRC><CRC><CRC>|<CRC>     |          case 4
+         *                                           |
+         *        
+         * This complicates CRC checking, there are four scenarios:
+         *
+         *      1. length is 1 more than multiple of packetsize with a trailing byte
+         *      2. length is 1 more than multiple of packetsize 
+         *      3. length is multiple of packetsize
+         *      4. none of the above
+         *
+         * Finally, even though we always compute CRC, we do not actually throw
+         * things away until and unless we have previously seen a good CRC.
+         * This allows backwards compatibility with hosts that do not support
+         * adding a CRC to the frame.
+         *
+         */
+
+        // test if 1 more than packetsize multiple
+        if (1 == (len % out_pkt_sz)) {
+
+                // copy and CRC up to the packetsize boundary
+                crc = crc32_copy(buff, urb->buffer, len - 1, CRC32_INIT);
+                buff += len - 1;
+
+                // if the CRC is good then this is case 1
+                if (CRC32_GOOD != crc) {
+
+                        crc = crc32_copy(buff, urb->buffer + len - 1, 1, crc);
+                        buff += 1;
+
+                        if (CRC32_GOOD != crc) {
+                                //crc_errors[len%64]++;
+                                TRACE_MSG2(NTT,"A CRC error %08x %03x", crc, urb->framenum);
+                                THROW_IF(npd->crc, crc_error);
+                        }
+                        else 
+                                npd->crc = 1;
+                }
+                else 
+                        npd->crc = 1;
+        }
+        else {
+                crc = crc32_copy(buff, urb->buffer, len, CRC32_INIT);
+                buff += len;
+
+                if (CRC32_GOOD != crc) {
+                        //crc_errors[len%64]++;
+                        TRACE_MSG2(NTT,"B CRC error %08x %03x", crc, urb->framenum);
+                        THROW_IF(npd->crc, crc_error);
+                }
+                else 
+                        npd->crc = 1;
+        }
+        // trim IFF we are paying attention to crc
+        if (npd->crc) 
+                trim = 4;
+#endif
+        // catch a simple error, just increment missed error and general error
+        CATCH(error) {
+                TRACE_MSG4(NTT,"CATCH(error) urb: %p status: %d len: %d function: %p",
+                                urb, urb->status, urb->actual_length, function);
+                // catch a CRC error
+                CATCH(crc_error) {
+                        crc_bad = 1;
+#if 0
+                        printk(KERN_INFO"%s: urb: %p status: %d len: %d maxtransfer: %d encap: %d\n", __FUNCTION__, 
+                                        urb, urb->status, urb->actual_length, npd->maxtransfer, 
+                                        npd->encapsulation);
+
+                        {
+                                u8 *cp = urb->buffer;
+                                int i;
+                                for (i = 0; i < urb->actual_length; i++) {
+                                        if ((i%32) == 0) {
+                                                printk("\n[%2x] ", i);
+                                        }
+                                        printk("%02x ", *cp++);
+                                }
+                                printk("\n");
+                        }
+#endif
+                }
+        }
+        net_os_recv_buff(npd,buff_ctx,crc_bad,trim);
+        TRACE_MSG1(NTT,"restart: %p", urb);
+        return (usbd_start_out_urb (urb));
+}
+/*! net_fd_recv_urb_eem - callback to process a received URB
+ *
+ * @return non-zero for failure.
+ */
+STATIC int net_fd_recv_urb_eem(struct usbd_urb *urb, int rc)
+{
+        return 0;
+}
+
+//_________________________________________________________________________________________________
+//                                      net_fd_device_request
+//
+/*! net_fd_urb_received_ep0 - callback for sent URB
+ *
+ * Handles notification that an urb has been sent (successfully or otherwise).
+ *
+ * @return non-zero for failure.
+ */
+STATIC int net_fd_urb_received_ep0 (struct usbd_urb *urb, int urb_rc)
+{
+        TRACE_MSG2(NTT,"urb: %p status: %d", urb, urb->status);
+
+        printk(KERN_INFO"%s:\n", __FUNCTION__);
+        RETURN_EINVAL_IF (RECV_OK != urb->status);
+
+        // TRACE_MSG1(NTT,"%s", urb->buffer); // QQSV  is this really a NUL-terminated string???
+
+        printk(KERN_INFO"%s: ok\n", __FUNCTION__);
+        return -EINVAL;         // caller will de-allocate
+}
+
+/*! net_fd_device_request - process a received SETUP URB
+ *
+ * Processes a received setup packet and CONTROL WRITE data.
+ * Results for a CONTROL READ are placed in urb->buffer.
+ *
+ * @return non-zero for failure.
+ */
+STATIC int net_fd_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
+{
+        struct usb_network_private *npd = (struct usb_network_private *) (function->privdata);
+        struct usbd_urb *urb;
+        int index;
+
+        // Verify that this is a USB Class request per CDC specification or a vendor request.
+        RETURN_ZERO_IF (!(request->bmRequestType & (USB_REQ_TYPE_CLASS | USB_REQ_TYPE_VENDOR)));
+
+        // Determine the request direction and process accordingly
+        switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
+
+        case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_VENDOR:
+
+                switch (request->bRequest) {
+                case MCCI_ENABLE_CRC:
+                        if (make_crc_table()) 
+                                return -EINVAL;
+                        npd->encapsulation = simple_crc;
+                        return 0;
+
+                case BELCARRA_PING:
+                        TRACE_MSG1(NTT,"H2D VENDOR IP: %08x", ip_addr);
+                        if ((npd->network_type == network_blan)) 
+                                net_os_send_notification_later(npd);
+                        break;
+
+#if !defined(CONFIG_OTG_NETWORK_BLAN_DO_NOT_SETTIME) || !defined(CONFIG_OTG_NETWORK_SAFE_DO_NOT_SETTIME) 
+                case BELCARRA_SETTIME:
+                        {
+#if defined(LINUX24)
+                                struct timeval tv;
+#else
+				struct timespec tv;
+#endif
+				memset(&tv, 0, sizeof(tv));
+
+                                // wIndex and wLength contain RFC868 time - seconds since midnight 1 jan 1900
+
+                                tv.tv_sec = ntohl( request->wValue << 16 | request->wIndex);
+                      //        tv.tv_usec = 0;
+
+                                // convert to Unix time - seconds since midnight 1 jan 1970
+                                
+                                tv.tv_sec -= RFC868_OFFSET_TO_EPOCH; 
+
+                                TRACE_MSG1(NTT,"H2D VENDOR TIME: %08x", tv.tv_sec);
+
+                                // set the time
+                                do_settimeofday(&tv);
+                        } break;
+#endif
+                case BELCARRA_SETIP:
+                        ip_addr = ntohl( request->wValue << 16 | request->wIndex);
+                        // XXX need to get in correct order here
+                        npd->local_dev_addr[2] = (ip_addr >> 24) & 0xff;
+                        npd->local_dev_addr[3] = (ip_addr >> 16) & 0xff;
+                        npd->local_dev_addr[4] = (ip_addr >> 8) & 0xff;
+                        npd->local_dev_addr[5] = (ip_addr >> 0) & 0xff;
+#ifdef CONFIG_OTG_NETWORK_BLAN_IPADDR
+                        snprintf(ip_addr_str, sizeof(ip_addr_str), "%d.%d.%d.%d", 
+                                        (ip_addr >> 24) & 0xff, (ip_addr >> 16) & 0xff,
+                                        (ip_addr >> 8) & 0xff, (ip_addr) & 0xff);
+                        index = usbd_realloc_string(
+                                        npd->function_driver->device_description->device_descriptor->iProduct, ip_addr_str);
+#endif /* CONFIG_OTG_NETWORK_IPADDR */
+                        break;
+
+                case BELCARRA_SETMSK:
+                        network_mask = ntohl( request->wValue << 16 | request->wIndex);
+                        break;
+
+                case BELCARRA_SETROUTER:
+                        router_ip = ntohl( request->wValue << 16 | request->wIndex);
+                        break;
+
+                case BELCARRA_SETDNS:
+                        dns_server_ip = ntohl( request->wValue << 16 | request->wIndex);
+                        break;
+#ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT
+                case BELCARRA_SETFERMAT:
+                        npd->fermat = 1;
+                        break;
+#endif
+#ifdef CONFIG_OTG_NETWORK_BLAN_HOSTNAME
+                case BELCARRA_HOSTNAME:
+                        TRACE_MSG0(NTT,"HOSTNAME");
+                        RETURN_EINVAL_IF(!(urb = usbd_alloc_urb_ep0(function, le16_to_cpu(request->wLength), 
+                                                        net_fd_urb_received_ep0) ));
+                        RETURN_ZERO_IF(!usbd_start_out_urb(urb));                  // return if no error
+                        usbd_free_urb(urb);                                  // de-alloc if error
+                        return -EINVAL;
+#endif
+#ifdef CONFIG_OTG_NETWORK_BLAN_DATA_NOTIFY_OK
+                case BELCARRA_DATA_NOTIFY:
+                        TRACE_MSG0(NTT,"DATA NOTIFY");
+                        npd->data_notify = 1;
+                        return -EINVAL;
+#endif
+                }
+                return 0;
+#if 0
+        case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_VENDOR:
+                urb->actual_length = 0;
+                switch (request->bRequest) {
+                case BELCARRA_GETMAC:
+                        {
+                                // copy and free the original buffer
+                                memcpy(urb->buffer, npd->local_dev_addr, ETH_ALEN);
+                                urb->actual_length = ETH_ALEN;
+                                return 0;
+                        }
+                }
+#endif
+                return 0;
+        default:
+                break;
+        }
+        return -EINVAL;
+}
+//_________________________________________________________________________________________________
+
+#ifdef CONFIG_OTG_NETWORK_START_SINGLE
+#define NETWORK_START_URBS 1
+#else
+#define NETWORK_START_URBS 2
+#endif
+
+typedef enum mesg {
+        mesg_unknown,
+        mesg_configured,
+        mesg_reset,
+} mesg_t;
+mesg_t net_last_mesg;
+
+char * net_messages[3] = {
+        "",
+        "Network Configured",
+        "Network Reset",
+};
+
+/*! net_check_mesg
+ */
+void net_check_mesg(mesg_t curr_mesg)
+{
+        RETURN_UNLESS(net_last_mesg != curr_mesg);
+        net_last_mesg = curr_mesg;
+        otg_message(net_messages[curr_mesg]);
+}
+
+
+
+/*! net_fd_start_recv - start recv urb(s)
+ */
+STATIC void net_fd_start_recv(struct usbd_function_instance *function)
+{
+        struct usb_network_private *npd = (struct usb_network_private *) (function->privdata);
+        int i;
+        for (i = 0; i < NETWORK_START_URBS; i++) {
+                struct usbd_urb *urb;
+                BREAK_IF(!(urb = usbd_alloc_urb(function, BULK_OUT, 
+                                                usbd_endpoint_transferSize(function, BULK_OUT, usbd_high_speed(function)), 
+                                                net_fd_recv_urb)));
+                TRACE_MSG5(NTT,"i: %d urb=%p priv=%p npd=%p function=%p",
+                           i, urb, urb->function_privdata, npd, function);
+                
+                urb->function_privdata = npd;
+                if (usbd_start_out_urb(urb)) {
+                        urb->function_privdata = NULL;
+                        usbd_free_urb(urb);
+                }
+        }
+}
+
+/*! net_fd_start_recv_eem - start recv urb(s)
+ */
+STATIC void net_fd_start_recv_eem(struct usbd_function_instance *function)
+{
+}
+
+/*! net_fd_event_handler - Processes a USB event.
+ */
+STATIC void net_fd_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
+{
+        struct usb_network_private *npd = (struct usb_network_private *) (function->privdata);
+
+        switch (event) {
+
+        case DEVICE_RESET:
+        case DEVICE_DESTROY:
+        case DEVICE_BUS_INACTIVE:
+        case DEVICE_DE_CONFIGURED:
+                TRACE_MSG1(NTT,"RESET/DESTROY/BUS_INACTIVE/DE_CONFIGURED %08x",ip_addr);
+                net_check_mesg(mesg_reset);
+                {
+                        // Return if argument is null.
+
+                        // XXX flush
+
+                        npd->flags &= ~NETWORK_ATTACHED;
+                        npd->int_urb = NULL;
+
+                        // Disable our net-device.
+                        // Apparently it doesn't matter if we should do this more than once.
+
+                        net_os_carrier_off(npd);
+
+                        // If we aren't already tearing things down, do it now.
+                        if (!(npd->flags & NETWORK_DESTROYING)) {
+                                npd->flags |= NETWORK_DESTROYING;
+                                //npd->device = NULL;
+                        }
+                }
+                npd->crc = 0;
+                break;
+
+        case DEVICE_CONFIGURED:
+        case DEVICE_BUS_ACTIVITY:
+                TRACE_MSG1(NTT,"CONFIGURED/BUS_ACTIVITY %08x",ip_addr);
+                net_check_mesg(mesg_configured);
+                npd->flags |= NETWORK_ATTACHED;
+                if ((npd->network_type == network_blan) && (npd->flags & NETWORK_OPEN)) 
+                        net_os_send_notification_later(npd);
+                net_os_carrier_on(npd);
+                (npd->network_type == network_eem) ?  net_fd_start_recv_eem : net_fd_start_recv(function);
+                break;
+
+        case DEVICE_SET_INTERFACE:
+                // XXX if CDC then we can check device->alternates[1] and see if we should
+                // enable/disable data flow.
+                // XXX verify ep0.c SET_CONFIGURATION and SET_INTERFACE implmentation are
+                // complete before using this
+                break;
+
+        default:
+                return;
+        }
+        // Let the OS layer know, if it's interested.
+        net_os_config(npd);
+        net_os_hotplug(npd);
+}
+
+
+/*! net_fd_endpoint_cleared - 
+ */
+STATIC void net_fd_endpoint_cleared (struct usbd_function_instance *function, int bEndpointAddress, int wIndex)
+{
+        TRACE_MSG2(NTT, "bEndpointAddress: %02x wIndex: %02x", bEndpointAddress, wIndex);
+}
+
+
+//_________________________________________________________________________________________________
+
+/*! net_fd_function_enable - enable the function driver
+ *
+ * Called for usbd_function_enable() from usbd_register_device()
+ */
+
+STATIC int net_fd_function_enable (struct usbd_function_instance *function)
+{
+        struct usb_network_private *npd;
+#if 0
+        /* This is the first time we've seen the function instance
+           (it's allocated by the usbdcore), so we need to let the OS
+           layer see it and initialize the privdata pointer. */
+        net_os_enable(function);
+        npd = (struct usb_network_private *) (function->privdata);
+        TRACE_MSG0(NTT,"semaphore DOWN");
+        net_os_mutex_enter(npd);
+#else
+        npd = (struct usb_network_private *) (function->privdata);
+        TRACE_MSG0(NTT,"semaphore DOWN");
+        net_os_mutex_enter(npd);
+        net_os_enable(function);
+#endif
+        _MOD_INC_USE_COUNT;  // QQQ Should this be _before_ the mutex_enter()?
+        TRACE_MSG1(NTT, "INC: %d", MOD_IN_USE);
+
+        // set the network device address from the local device address
+        // Now done in net_os_enable() above.
+        // memcpy(npd->net_dev->dev_addr, npd->local_dev_addr, ETH_ALEN);
+
+        npd->have_interrupt = usbd_endpoint_bEndpointAddress(function, INT_IN, usbd_high_speed(function)) ? 1 : 0;
+
+        npd->flags |= NETWORK_ENABLED;
+
+#if defined(CONFIG_OTG_NETWORK_CDC)
+        cdc_init(function);
+#endif                          /* CONFIG_OTG_NETWORK_CDC */
+
+#ifdef CONFIG_OTG_NETWORK_EEM
+        eem_init(function);
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_BASIC
+        basic_init(function);
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_BASIC2
+        basic2_init(function);
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_SAFE
+        safe_init(function);
+#endif
+#ifdef CONFIG_OTG_NETWORK_BLAN
+        blan_init(function);
+#endif
+        net_os_mutex_exit(npd);
+        TRACE_MSG0(NTT,"semaphore UP");
+        return 0;
+}
+
+/*! net_fd_function_disable - disable the function driver
+ *
+ */
+STATIC void net_fd_function_disable (struct usbd_function_instance *function)
+{
+        struct usb_network_private *npd = (struct usb_network_private *) (function->privdata);
+        TRACE_MSG0(NTT,"semaphore DOWN");
+        net_os_mutex_enter(npd);
+        npd->flags &= ~NETWORK_ENABLED;
+        _MOD_DEC_USE_COUNT;  // QQQ Should this be _after_ the up()?
+        TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
+        net_os_mutex_exit(npd);
+        TRACE_MSG0(NTT,"semaphore UP");
+}
+
+/*! net_fd_function_ops - operations table for network function driver
+ */
+struct usbd_function_operations net_fd_function_ops = {
+        device_request: net_fd_device_request,
+        event_handler: net_fd_event_handler,
+        function_enable: net_fd_function_enable,
+        function_disable: net_fd_function_disable,
+        endpoint_cleared: net_fd_endpoint_cleared,
+};
+
+//______________________________________module_init and module_exit________________________________
+
+/*! hexdigit -
+ *
+ * Converts characters in [0-9A-F] to 0..15, characters in [a-f] to 42..47, and all others to 0.
+ */
+static u8 hexdigit (char c)
+{
+        return isxdigit (c) ? (isdigit (c) ? (c - '0') : (c - 'A' + 10)) : 0;
+}
+
+/*! set_address -
+ */
+static void set_address(char *mac_address_str, u8 *dev_addr)
+{
+        int i;
+        if (mac_address_str && strlen(mac_address_str)) {
+                for (i = 0; i < ETH_ALEN; i++) {
+                        dev_addr[i] = 
+                                hexdigit (mac_address_str[i * 2]) << 4 | 
+                                hexdigit (mac_address_str[i * 2 + 1]);
+                }
+        }
+        else {
+                get_random_bytes(dev_addr, ETH_ALEN);
+                dev_addr[0] = (dev_addr[0] & 0xfe) | 0x02;
+        }
+}
+
+/*! macstrtest -
+ */
+static int macstrtest(char *mac_address_str)
+{
+        int l = 0;
+
+        if (mac_address_str) {
+                l = strlen(mac_address_str);
+        }
+        return ((l != 0) && (l != 12));
+}
+
+/*! select_network_type
+ *
+ */
+STATIC network_type_t select_network_type(struct usb_network_params *p)
+{
+        /*
+         * Figure out what network mode to operate in.
+         */
+        network_type_t  network_type = network_unknown;
+        /*
+         * Step 1. Look to see if network_type is specified by something like module params.
+         */
+#if defined(CONFIG_OTG_NETWORK_CDC) 
+        p->cdc_capable = 1;
+        if (p->cdc) {
+                TRACE_MSG0(NTT,"cdc");
+                network_type = network_cdc;
+        }
+#endif
+#ifdef CONFIG_OTG_NETWORK_EEM
+        p->eem_capable = 1;
+        if (p->eem) {
+                THROW_IF (network_type != network_unknown, select_error);
+                TRACE_MSG0(NTT,"eem");
+                network_type = network_eem;
+        }
+#endif
+#ifdef CONFIG_OTG_NETWORK_BASIC
+        p->basic_capable = 1;
+        if (p->basic) {
+                THROW_IF (network_type != network_unknown, select_error);
+                TRACE_MSG0(NTT,"basic");
+                network_type = network_basic;
+        }
+#endif
+#ifdef CONFIG_OTG_NETWORK_BASIC2
+        p->basic2_capable = 1;
+        if (p->basic2) {
+                THROW_IF (network_type != network_unknown, select_error);
+                TRACE_MSG0(NTT,"basic2");
+                network_type = network_basic2;
+        }
+#endif
+#ifdef CONFIG_OTG_NETWORK_SAFE
+        p->safe_capable = 1;
+        if (p->safe) {
+                THROW_IF (network_type != network_unknown, select_error);
+                TRACE_MSG0(NTT,"safe");
+                network_type = network_safe;
+        }
+#endif
+#ifdef CONFIG_OTG_NETWORK_BLAN
+        p->blan_capable = 1;
+        if (p->blan) {
+                THROW_IF (network_type != network_unknown, select_error);
+                TRACE_MSG0(NTT,"blan");
+                network_type = network_blan;
+        }
+#endif
+
+        /*
+         * Step 2. If nothing was specified by parameter, default to
+         *         to the first available (i.e. compiled) of:
+         *            CDC, BASIC, BASIC2, SAFE, BLAN.
+         */
+#if defined(CONFIG_OTG_NETWORK_CDC)
+        if (network_type == network_unknown) {
+                TRACE_MSG0(NTT,"unknown => cdc");
+                network_type = network_cdc;
+        }
+#endif
+#if defined(CONFIG_OTG_NETWORK_EEM)
+        if (network_type == network_unknown) {
+                TRACE_MSG0(NTT,"unknown => eem");
+                network_type = network_eem;
+        }
+#endif
+#if defined(CONFIG_OTG_NETWORK_BASIC)
+        if (network_type == network_unknown) {
+                TRACE_MSG0(NTT,"unknown => basic");
+                network_type = network_basic;
+        }
+#endif
+#if defined(CONFIG_OTG_NETWORK_BASIC2)
+        if (network_type == network_unknown) {
+                TRACE_MSG0(NTT,"unknown => basic2");
+                network_type = network_basic2;
+        }
+#endif
+#if defined(CONFIG_OTG_NETWORK_SAFE)
+        if (network_type == network_unknown) {
+                TRACE_MSG0(NTT,"unknown => safe");
+                network_type = network_safe;
+        }
+#endif
+#if defined(CONFIG_OTG_NETWORK_BLAN)
+        if (network_type == network_unknown) {
+                TRACE_MSG0(NTT,"unknown => blan");
+                network_type = network_blan;
+        }
+#endif
+        CATCH(select_error) {
+                network_type == network_unknown;
+        }
+        return(network_type);
+}
+
+/*! select_descriptors
+ *
+ */
+STATIC struct usbd_function_driver * select_descriptors(network_type_t network_type)
+{
+        // select the function driver descriptors based on network_type
+
+        switch (network_type) {
+
+#if defined(CONFIG_OTG_NETWORK_CDC)
+        case network_cdc:
+                TRACE_MSG0(NTT,"fd=cdc");
+                return(&cdc_function_driver);
+#endif
+#if defined(CONFIG_OTG_NETWORK_EEM)
+        case network_eem:
+                TRACE_MSG0(NTT,"fd=eem");
+                return(&eem_function_driver);
+#endif
+#if defined(CONFIG_OTG_NETWORK_BASIC)
+        case network_basic:
+                TRACE_MSG0(NTT,"fd=basic");
+                return(&basic_function_driver);
+#endif
+#if defined(CONFIG_OTG_NETWORK_BASIC2)
+        case network_basic2:
+                TRACE_MSG0(NTT,"fd=basic2");
+                return(&basic2_function_driver);
+#endif
+#if defined(CONFIG_OTG_NETWORK_SAFE)
+        case network_safe:
+                TRACE_MSG1(NTT,"fd=safe bNumConfigurations: %d",
+                           safe_function_driver.bNumConfigurations);
+                return(&safe_function_driver);
+#endif
+#if defined(CONFIG_OTG_NETWORK_BLAN)
+        case network_blan:
+                TRACE_MSG1(NTT,"fd=blan bNumConfigurations: %d",
+                           blan_function_driver.bNumConfigurations);
+                return(&blan_function_driver);
+#endif
+        default:
+                break;
+        }
+        return(NULL);
+}
+
+/*! net_fd_init - function driver usb part intialization
+ *
+ * @return non-zero for failure.
+ */
+STATIC int net_fd_init(struct usb_network_private *npd, char *info_str)
+{
+        struct usb_network_params *p = npd->params;
+
+        printk(KERN_INFO "Copyright (c) 2002-2004 Belcarra Technologies; www.belcarra.com; sl@belcarra.com\n");
+        NTT = otg_trace_obtain_tag();
+
+        /*
+         * Figure out what network mode to operate in.
+         */
+        if (network_unknown == (npd->network_type = select_network_type(p)) ||
+            NULL == (npd->function_driver = select_descriptors(npd->network_type))) {
+                printk(KERN_INFO"configuration selection error");
+                otg_trace_invalidate_tag(NTT);
+                return -EINVAL;
+        }
+
+#ifdef CONFIG_OTG_NETWORK_ALLOW_SETID
+        TRACE_MSG2(NTT,"checking idVendor: %04x idProduct: %04x", p->vendor_id, p->product_id);
+
+        if (p->vendor_id) 
+                npd->function_driver->idVendor = cpu_to_le16(p->vendor_id);
+
+        if (p->product_id) 
+                npd->function_driver->idProduct = cpu_to_le16(p->product_id);
+#endif
+        printk(KERN_INFO "%s: %s vendor_id: %04x product_id: %04x\n",
+                __FUNCTION__, info_str,
+                le16_to_cpu(npd->function_driver->idVendor),
+                le16_to_cpu(npd->function_driver->idProduct));
+        TRACE_MSG3(NTT,"%s vendor_id: %04x product_id: %04x", info_str,
+                le16_to_cpu(npd->function_driver->idVendor),
+                le16_to_cpu(npd->function_driver->idProduct));
+
+#ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT
+        TRACE_MSG0(NTT,"fermat");
+        fermat_init();
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_EP0TEST
+        /*
+         * ep0test - test that bus interface can do ZLP on endpoint zero
+         *
+         * This will artificially force iProduct string descriptor to be
+         * exactly the same as the endpoint zero packetsize.  When the host
+         * requests this string it will request it not knowing the strength
+         * and will use a max length of 0xff. The bus interface driver must
+         * send a ZLP to terminate the transaction.
+         *
+         * The iProduct descriptor is used because both the Linux and
+         * Windows usb implmentations fetch this in a default enumeration. 
+         *
+         */
+        //UNLESS (ep0test) 
+        //        ep0test = usbd_endpoint_zero_wMaxPacketsize(function);
+
+        if (ep0test) {
+                switch (ep0test) {
+                case 8:  npd->function_driver->device_description->iProduct = "012"; break;
+                case 16: npd->function_driver->device_description->iProduct = "0123456"; break;
+                case 32: npd->function_driver->device_description->iProduct = "0123456789abcde"; break;
+                case 64: npd->function_driver->device_description->iProduct = "0123456789abcdef0123456789abcde"; break;
+                default: printk(KERN_ERR"%s: ep0test: bad value: %d, must be one of 8, 16, 32 or 64\n", 
+                                         __FUNCTION__, ep0test); return -EINVAL;
+                         break;
+                }
+                TRACE_MSG1(NTT,"ep0test: iProduct set to: %s",
+                           npd->function_driver->device_description->iProduct);
+                printk(KERN_INFO"%s: ep0test: iProduct set to: %s\n", __FUNCTION__, 
+                                npd->function_driver->device_description->iProduct);
+        }
+        else {
+                TRACE_MSG0(NTT,"ep0test: not set");
+                printk(KERN_INFO"%s: ep0test: not set\n", __FUNCTION__);
+        }
+#endif /* CONFIG_OTG_NETWORK_EP0TEST */
+
+
+#ifdef CONFIG_OTG_NETWORK_LOCAL_MACADDR
+        if (NULL == p->local_mac_address_str) {
+                /* There is a configured override, and it has NOT been
+                   overridden in turn by a module load time parameter, so use it. */
+                p->local_mac_address_str = CONFIG_OTG_NETWORK_LOCAL_MACADDR;
+        }
+#endif
+#ifdef CONFIG_OTG_NETWORK_REMOTE_MACADDR
+        if (NULL == p->remote_mac_address_str) {
+                /* There is a configured override, and it has NOT been
+                   overridden in turn by a module load time parameter, so use it. */
+                p->remote_mac_address_str = CONFIG_OTG_NETWORK_REMOTE_MACADDR;
+        }
+#endif
+        if ((macstrtest(p->local_mac_address_str) || macstrtest(p->remote_mac_address_str))) {
+                TRACE_MSG2(NTT,"bad size %s %s", p->local_mac_address_str, p->remote_mac_address_str);
+                otg_trace_invalidate_tag(NTT);
+                return -EINVAL;
+        }
+
+        set_address(p->local_mac_address_str, npd->local_dev_addr);
+        set_address(p->remote_mac_address_str, npd->remote_dev_addr);
+        npd->encapsulation = simple_crc;
+
+        if (make_crc_table() ||
+            NULL == (npd->function = usbd_register_function(npd->function_driver, "net-fd", NULL))) {
+                if (network_crc32_table) {
+                        lkfree(network_crc32_table);
+                        network_crc32_table = NULL;
+                }
+                otg_trace_invalidate_tag(NTT);
+                return -EINVAL;
+        }
+        npd->function->privdata = (void *) npd;
+
+        return 0;
+
+}
+
+//_____________________________________________________________________________
+
+/*! net_fd_term - driver exit
+ *
+ * Cleans up the module. Deregisters the function driver and destroys the network object.
+ */
+STATIC void net_fd_term(struct usb_network_private *npd)
+{
+        if (NULL != npd->function) {
+                usbd_deregister_function(npd->function);
+                npd->function = NULL;
+        }
+        if (network_crc32_table) {
+                lkfree(network_crc32_table);
+                network_crc32_table = NULL;
+        }
+        otg_trace_invalidate_tag(NTT);
+}
+
+//_________________________________________________________________________________________________
+
+
+/*! net_fd_usb_ops operations
+ */
+struct net_usb_services net_fd_usb_ops = {
+        .initialize_usb_part = net_fd_init,
+        .terminate_usb_part = net_fd_term,
+        .send_int_notification = net_fd_send_int_blan,
+        .start_xmit = net_fd_start_xmit,
+};
diff -uNr linux/drivers/no-otg/functions/network/net-fd.h linux/drivers/otg/functions/network/net-fd.h
--- linux/drivers/no-otg/functions/network/net-fd.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/net-fd.h	2006-09-01 21:41:30.000000000 +0200
@@ -0,0 +1,48 @@
+/*
+ * otg/functions/network/net-fd.h - Network Function Driver
+ *
+ *      Copyright (c) 2002, 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>
+ *      Chris Lynne <cl@belcarra.com>
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*!
+ * @file otg/functions/network/net-fd.h
+ * @brief These are the functions exported by the USB specific parts
+ * (i.e. net-fd.c and net-cl.c) for use in the OS specific
+ * layers (e.g. net-l24-os.c).
+ *
+ *
+ * @ingroup NetworkFunction
+ */
+#ifndef NET_FD_H
+#define NET_FD_H 1
+
+struct net_usb_services {
+        int (*initialize_usb_part)(struct usb_network_private *npd, char *info_str);
+        void (*terminate_usb_part)(struct usb_network_private *npd);
+        void (*send_int_notification)(struct usb_network_private *npd, int connected, int data);
+        int (*start_xmit)(struct usb_network_private *npd, __u8 *buff, int len, void *buff_ctx);
+};
+
+extern struct net_usb_services net_fd_usb_ops;
+
+#endif
diff -uNr linux/drivers/no-otg/functions/network/net-l24-os.c linux/drivers/otg/functions/network/net-l24-os.c
--- linux/drivers/no-otg/functions/network/net-l24-os.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/net-l24-os.c	2006-09-01 21:41:30.000000000 +0200
@@ -0,0 +1,1395 @@
+/*
+ * otg/functions/network/net-l24-os.c - Network Function Driver
+ *
+ *      Copyright (c) 2002, 2003, 2004 Belcarra Technologies
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*!
+ * @file otg/functions/network/net-l24-os.c
+ * @brief The Linux 2.4 OS specific upper edge (network interface) 
+ * implementation for the Network Function Driver.
+ *
+ * This file implements a standard Linux network driver interface and
+ * the standard Linux 2.4 module init and exit functions.
+ *
+ * If compiled into the kernel, this driver can be used with NFSROOT to
+ * provide the ROOT filesystem. Please note that the kernel NFSROOT support
+ * (circa 2.4.20) can have problems if there are multiple interfaces. So 
+ * it is best to ensure that there are no other network interfaces compiled
+ * in.
+ *
+ *
+ * @ingroup NetworkFunction
+ */
+
+
+/* OS-specific #includes */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/ctype.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/random.h>
+#include <linux/utsname.h>
+#include <linux/kmod.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+/* Networking #includes from OS */
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <net/arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/atmdev.h>
+#include <linux/pkt_sched.h>
+#include <linux/ip.h>
+#include <linux/if_ether.h>
+#include <linux/in.h>
+#include <linux/inetdevice.h>
+
+
+
+/* Belcarra public interfaces */
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+#include <otg/usbp-chap9.h>
+//#include <otg/usbd-mem.h>
+#include <otg/usbp-func.h>
+
+/* Belcarra private interfaces SUBJECT TO CHANGE WITHOUT NOTICE */
+#include "network.h"
+#include "net-os.h"
+#include "net-fd.h"
+
+MOD_AUTHOR ("sl@belcarra.com, tbr@belcarra.com, balden@belcarra.com");
+
+EMBED_LICENSE();
+
+MOD_DESCRIPTION ("USB Network Function");
+
+
+
+EMBED_USBD_INFO ("network_fd 2.0-beta");
+
+
+#define NTT network_fd_trace_tag
+
+wait_queue_head_t usb_netif_wq;
+#ifdef CONFIG_OTG_NET_NFS_SUPPORT
+int usb_is_configured;
+#endif
+
+/* Module Parameters ************************************************************************* */
+
+STATIC struct usb_network_params params;
+
+#ifdef CONFIG_OTG_NETWORK_ALLOW_SETID
+// override vendor ID
+static int vendor_id;
+MOD_PARM (vendor_id, "i");
+MOD_PARM_DESC (vendor_id, "vendor id");
+
+// override product ID
+static int product_id;
+MOD_PARM (product_id, "i");
+MOD_PARM_DESC (product_id, "product id");
+#endif
+
+// override local mac address
+static char *local_mac_address_str;
+MOD_PARM (local_mac_address_str, "s");
+MOD_PARM_DESC (local_mac_address_str, "Local MAC");
+
+// override remote mac address
+static char *remote_mac_address_str;
+MOD_PARM (remote_mac_address_str, "s");
+MOD_PARM_DESC (remote_mac_address_str, "Remote MAC");
+
+#ifdef CONFIG_OTG_NETWORK_EP0TEST
+static int ep0test;
+MOD_PARM (ep0test, "i");
+MOD_PARM_DESC (ep0test, "Test EP0 String Handling - set to ep0 packetsize [8,16,32,64]");
+#endif
+
+static int zeroconf;
+MOD_PARM (zeroconf, "i");
+MOD_PARM_DESC (zeroconf, "Use usbz%d for network name");
+
+#if defined(CONFIG_OTG_NETWORK_CDC)
+static int cdc;
+MOD_PARM (cdc, "i");
+MOD_PARM_DESC (cdc, "Enable CDC mode");
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_BASIC
+static int basic;
+MOD_PARM (basic, "i");
+MOD_PARM_DESC (basic, "Enable BASIC mode");
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_BASIC2
+static int basic2;
+MOD_PARM (basic2, "i");
+MOD_PARM_DESC (basic2, "Enable BASIC2 mode");
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_SAFE
+static int safe;
+MOD_PARM (safe, "i");
+MOD_PARM_DESC (safe, "Enable SAFE mode");
+#endif
+
+#ifdef CONFIG_OTG_NETWORK_BLAN
+static int blan;
+MOD_PARM (blan, "i");
+MOD_PARM_DESC (blan, "Enable BLAN mode");
+#endif
+
+/* End of Module Parameters ****************************************************************** */
+
+
+u8 local_dev_addr[ETH_ALEN];
+
+u8 remote_dev_addr[ETH_ALEN];
+static u8 zeros[ETH_ALEN];
+
+extern u32 ip_addr;
+extern u32 router_ip;
+extern u32 network_mask;
+extern u32 dns_server_ip;
+
+/* Prevent overlapping of bus administrative functions:
+ *
+ *      network_function_enable
+ *      network_function_disable
+ *      network_hard_start_xmit
+ */
+DECLARE_MUTEX(usbd_network_sem);
+
+
+struct net_device Network_net_device;
+struct usb_network_private Usb_network_private;
+
+void notification_schedule_bh (void);
+int network_urb_sent_bulk (struct usbd_urb *urb, int urb_rc);
+int network_urb_sent_int (struct usbd_urb *urb, int urb_rc);
+
+
+//_________________________________________________________________________________________________
+
+/*
+ * Synchronization
+ *
+ *
+ * Notification bottom half
+ *   
+ *  This is a scheduled task that will send an interrupt notification. Because it
+ *  is called from the task scheduler context it needs to verify that the device is
+ *  still usable.
+ *
+ *      static int network_send_int_blan(struct usbd_function_instance *, int )
+ *      static void notification_bh (void *)
+ *      void notification_schedule_bh (void)
+ *
+ *
+ * Netdevice functions
+ *
+ *   These are called by the Linux network layer. They must be protected by irq locks
+ *   if necessary to prevent interruption by IRQ level events.
+ *
+ *      int network_init (struct net_device *net_device)
+ *      void network_uninit (struct net_device *net_device)
+ *      int network_open (struct net_device *net_device)
+ *      int network_stop (struct net_device *net_device)
+ *      struct net_device_stats *network_get_stats (struct net_device *net_device)
+ *      int network_set_mac_addr (struct net_device *net_device, void *p)
+ *      void network_tx_timeout (struct net_device *net_device)
+ *      int network_set_config (struct net_device *net_device, struct ifmap *map)
+ *      int network_stop (struct net_device *net_device)
+ *      int network_hard_start_xmit (struct sk_buff *skb, struct net_device *net_device)
+ *      int network_do_ioctl (struct net_device *net_device, struct ifreq *rp, int cmd)
+ *
+ *
+ * Data bottom half functions
+ *
+ *  These are called from the bus bottom half handler. 
+ *
+ *      static int network_recv (struct usb_network_private *, struct net_device *, struct sk_buff *)
+ *      int network_recv_urb (struct usbd_urb *)
+ *      int network_urb_sent (struct usbd_urb *, int )
+ *      
+ *
+ * Hotplug bottom half:
+ *
+ *  This is a scheduled task that will send do a hotplug call. Because it is
+ *  called from the task scheduler context it needs to verify that the
+ *  device is still usable.
+ *
+ *      static int hotplug_attach (u32 ip, u32 mask, u32 router, int attach)
+ *      static void hotplug_bh (void *data)
+ *      void net_os_hotplug (void)
+ *
+ *
+ * Irq level functions:
+ *
+ *   These are called at interrupt time do process or respond to USB setup
+ *   commands. 
+ *
+ *      int network_device_request (struct usbd_device_request *)
+ *      void network_event_handler (struct usbd_function_instance *function, usbd_device_event_t event, int data)
+ *
+ *      
+ * Enable and disable functions:
+ *
+ *      void network_function_enable (struct usbd_function_instance *, struct usbd_function_instance *)
+ *      void network_function_disable (struct usbd_function_instance *function)
+ *
+ *
+ * Driver initialization and exit:
+ *
+ *      static  int network_create (struct usb_network_private *)
+ *      static  void network_destroy (struct usb_network_private *)
+ *
+ *      int network_modinit (void)
+ *      void network_modexit (void)
+ */
+
+
+//_______________________________USB part Functions_________________________________________
+
+/*
+ * net_os_mutex_enter - enter mutex region
+ */
+void net_os_mutex_enter(struct usb_network_private *npd)
+{
+        down(&usbd_network_sem);
+}
+
+/*
+ * net_os_mutex_exit - exit mutex region
+ */
+void net_os_mutex_exit(struct usb_network_private *npd)
+{
+        up(&usbd_network_sem);
+}
+
+/* notification_bh - Bottom half handler to send a notification status 
+ *
+ * Send a notification with open/close status
+ *
+ * It should not be possible for this to be called more than once at a time
+ * as it is only called via schedule_task() which protects against a second
+ * invocation.
+ */
+STATIC void notification_bh (void *data)
+{
+        struct usb_network_private *npd = (struct usb_network_private *) data;
+        unsigned long flags;
+        local_irq_save(flags);
+        (*(npd->fd_ops->send_int_notification))(npd, npd->flags & NETWORK_OPEN, 0);
+        local_irq_restore(flags);
+        //_MOD_DEC_USE_COUNT;
+        TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
+}
+
+/* notification_schedule_bh - schedule a call for notification_bh
+ */
+void net_os_send_notification_later(struct usb_network_private *npd)
+{
+#ifdef LINUX24
+        //LINUX 2.4 is the only supported OS to need the USE_COUNT
+        //_MOD_INC_USE_COUNT;
+        TRACE_MSG1(NTT, "INC: %d", MOD_IN_USE);
+        if (!SCHEDULE_WORK(npd->notification_bh)) {
+                //_MOD_DEC_USE_COUNT;
+                TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
+        }
+#else
+        SCHEDULE_WORK(npd->notification_bh);
+        //XXX No provision for failure of schedule ....
+#endif
+}
+
+/*! net_os_xmit_done - called from USB part when a transmit completes, good or bad.
+ *                    tx_rc is SEND_FINISHED_ERROR, SEND_CANCELLED or...
+ *                    buff_ctx is the pointer passed to fd_ops->start_xmit().
+ * @return non-zero only if network does not exist, ow 0.
+ */
+int net_os_xmit_done(struct usbd_function_instance *function, void *buff_ctx, int tx_rc)
+{
+        struct sk_buff *skb = (struct sk_buff *) buff_ctx;
+        struct usb_network_private *npd;
+        struct net_device *net_device;
+        int rc = 0;
+
+        npd = (function ? (struct usb_network_private *) (function->privdata) : NULL);
+        if (skb) {
+                if (NULL != npd && 0 == (rc = !(npd->flags & NETWORK_CREATED))) {
+                        switch (tx_rc) {
+                        case SEND_FINISHED_ERROR:
+                                npd->stats.tx_errors++;
+                                npd->stats.tx_dropped++;
+                                break;
+                        case SEND_CANCELLED:
+                                npd->stats.tx_errors++;
+                                npd->stats.tx_carrier_errors++;
+                                break;
+                        default:
+                                break;
+                        }
+
+                        npd->avg_queue_entries += npd->queued_entries;
+                        npd->queued_entries--;
+                        npd->samples++;
+                        npd->jiffies += jiffies - *(time_t *) (&skb->cb);
+                        npd->queued_bytes -= skb->len;
+                        if (NULL != (net_device = npd->net_dev) &&
+                            netif_queue_stopped(net_device)) {
+                                netif_wake_queue(net_device);
+                                npd->restarts++;
+                        }
+                }
+                dev_kfree_skb_any(skb);
+        }
+        return rc;
+}
+
+/*! net_os_alloc_buf
+ */
+void *net_os_alloc_buff(struct usb_network_private *npd, u8 **cp, int n)
+{
+        struct sk_buff *skb;
+        // allocate skb of appropriate length, reserve 2 to align ip
+        if (!(skb = dev_alloc_skb(n+2))) {
+                *cp = NULL;
+                return(NULL);
+        }
+        skb_reserve(skb, 2);
+        *cp = skb_put(skb, n);
+        return((void*) skb);
+}
+
+/*! network_recv - function to process an received data URB
+ *
+ * Passes received data to the network layer. Passes skb to network layer.
+ *
+ * @return non-zero for failure.
+ */
+STATIC __inline__ int network_recv (struct usb_network_private *npd, 
+                struct net_device *net_device, struct sk_buff *skb)
+{
+        int rc;
+#if 0
+        printk(KERN_INFO"%s: len: %x head: %p data: %p tail: %p\n", __FUNCTION__, 
+                        skb->len, skb->head, skb->data, skb->tail);
+        {
+                u8 *cp = skb->data;
+                int i;
+                for (i = 0; i < skb->len; i++) {
+                        if ((i%32) == 0) {
+                                printk("\nrx[%2x] ", i);
+                        }
+                        printk("%02x ", *cp++);
+                }
+                printk("\n");
+        }
+#endif
+
+        // refuse if no device present
+        if (!netif_device_present (net_device)) {
+                TRACE_MSG0(NTT,"device not present");
+                printk(KERN_INFO"%s: device not present\n", __FUNCTION__);
+                return -EINVAL;
+        }
+
+        // refuse if no carrier
+        if (!netif_carrier_ok (net_device)) {
+                TRACE_MSG0(NTT,"no carrier");
+                printk(KERN_INFO"%s: no carrier\n", __FUNCTION__);
+                return -EINVAL;
+        }
+
+        // refuse if the net device is down
+        if (!(net_device->flags & IFF_UP)) {
+                TRACE_MSG1(NTT,"not up net_dev->flags: %x", net_device->flags);
+                //printk(KERN_INFO"%s: not up net_dev->flags: %x\n", __FUNCTION__, net_device->flags);
+                //npd->stats.rx_dropped++;
+                return -EINVAL;
+        }
+
+        skb->dev = net_device;
+        skb->pkt_type = PACKET_HOST;
+        skb->protocol = eth_type_trans (skb, net_device);
+        skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+        //TRACE_MSG4(NTT,"len: %x head: %p data: %p tail: %p",
+        //                skb->len, skb->head, skb->data, skb->tail);
+
+
+        // pass it up to kernel networking layer
+        if ((rc = netif_rx (skb))) {
+                TRACE_MSG1(NTT,"netif_rx rc: %d", rc);
+        }
+        // QQSV - should be else case for stats?
+        npd->stats.rx_bytes += skb->len;
+        npd->stats.rx_packets++;
+
+        return 0;
+}
+
+/*! net_os_recv_buff - forward a received URB, or clean up after a bad one.
+ *      buff_ctx == NULL --> just accumulate stats (count 1 bad buff)
+ *      crc_bad != 0     --> count a crc error and free buff_ctx/skb
+ *      trim             --> amount to trim from valid skb
+ */
+void net_os_recv_buff(struct usb_network_private *npd, void *buff_ctx, int crc_bad, int trim)
+{
+        struct sk_buff *skb = (struct sk_buff *) buff_ctx;
+
+        if (NULL == skb) {
+                /* Lower layer never got around to allocating an skb, but
+                   needs to count a packet it can't forward. */
+                npd->stats.rx_frame_errors++;
+                npd->stats.rx_errors++;
+        } else {
+                // There is an skb, either forward it or free it.
+                if (crc_bad) {
+                        npd->stats.rx_crc_errors++;
+                        npd->stats.rx_errors++;
+                } else if ((npd->flags & NETWORK_ATTACHED) && NULL != npd->net_dev) {
+                        // All good, forward it.
+                        if (trim) {
+                                skb_trim(skb, skb->len - trim);
+                        }
+                        // all done if network_recv() == 0, ow fall through to error handling
+                        RETURN_IF(!network_recv(npd, npd->net_dev, skb));
+                        // Network layer wouldn't take it.
+                        // rx_dropped gets counted below, any other counter we need?
+                }
+                // Something wrong, free the skb
+                dev_kfree_skb_any (skb);
+        }
+        // The received buffer didn't get forwarded, so...
+        npd->stats.rx_dropped++;
+}
+
+/*! net_os_enable
+ *
+ */
+void net_os_enable(struct usbd_function_instance *function)
+{
+        //struct usb_network_private *npd = &Usb_network_private;
+        struct usb_network_private *npd = (struct usb_network_private *) function->privdata;
+#if 0
+        /* This is the first time we've gotten access to the function instance,
+           and it's an allocated structure.  Fill in the links to our private data. */
+        function->privdata = (void *) npd;
+        npd->function = function;
+#endif
+        TRACE_MSG3(NTT,"npd=%p function=%p, f->p=%p",npd,function,function->privdata);
+
+        // set the network device address from the local device address
+        memcpy(npd->net_dev->dev_addr, npd->local_dev_addr, ETH_ALEN);
+}
+
+/*! net_os_disable
+ * 
+ */
+extern void net_os_disable(struct usbd_function_instance *function)
+{
+#if 0
+        struct usb_network_private *npd = (struct usb_network_private *) (function->privdata);
+        function->privdata = NULL;
+        npd->function = NULL;
+#endif
+}
+
+/*
+ *
+ */
+void net_os_carrier_on(struct usb_network_private *npd)
+{
+        netif_carrier_on(npd->net_dev);
+        netif_wake_queue(npd->net_dev);
+#ifdef CONFIG_OTG_NET_NFS_SUPPORT
+        if (!usb_is_configured) {
+                wake_up(&usb_netif_wq);
+                usb_is_configured = 1;
+        }
+#endif
+
+}
+
+/*
+ *
+ */
+void net_os_carrier_off(struct usb_network_private *npd)
+{
+        netif_stop_queue(npd->net_dev);
+        netif_carrier_off(npd->net_dev);
+}
+
+
+//_______________________________Network Layer Functions____________________________________
+
+/*
+ * In general because the functions are called from an independant layer it is necessary
+ * to verify that the device is still ok and to lock interrupts out to prevent in-advertant
+ * closures while in progress.
+ */
+
+/* network_init -
+ *
+ * Initializes the specified network device.
+ *
+ * Returns non-zero for failure.
+ */
+STATIC int network_init (struct net_device *net_device)
+{
+        TRACE_MSG0(NTT,"no-op");
+        return 0;
+}
+
+
+/* network_uninit -
+ *
+ * Uninitializes the specified network device.
+ */
+STATIC void network_uninit (struct net_device *net_device)
+{
+        TRACE_MSG0(NTT,"no-op");
+        return;
+}
+
+
+/* network_open -
+ *
+ * Opens the specified network device.
+ *
+ * Returns non-zero for failure.
+ */
+STATIC int network_open (struct net_device *net_device)
+{
+        struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
+        unsigned long flags;
+
+        _MOD_INC_USE_COUNT;
+        TRACE_MSG1(NTT, "INC: %d", MOD_IN_USE);
+        npd->flags |= NETWORK_OPEN;
+        netif_wake_queue (net_device);
+
+        local_irq_save(flags);
+        (*(npd->fd_ops->send_int_notification))(npd, 1, 0);
+        local_irq_restore(flags);
+
+#ifdef CONFIG_OTG_NET_NFS_SUPPORT
+        if (!usb_is_configured) {
+                if (!in_interrupt()) {
+                        TRACE_MSG0(NTT,"Please replug USB cable and then ifconfig host interface.\n");
+                        printk(KERN_ERR"Please replug USB cable and then ifconfig host interface.\n");
+                        interruptible_sleep_on(&usb_netif_wq);
+                }
+                else {
+                        TRACE_MSG_0(NTT,"Warning! In interrupt\n");
+                        printk(KERN_ERR"Warning! In interrupt\n");
+                }
+        }
+#endif
+        return 0;
+}
+
+
+/* network_stop -
+ *
+ * Stops the specified network device.
+ *
+ * Returns non-zero for failure.
+ */
+STATIC int network_stop (struct net_device *net_device)
+{
+        struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
+        unsigned long flags;
+
+        TRACE_MSG0(NTT,"-");
+
+        //netif_stop_queue (net_device);
+
+        npd->flags &= ~NETWORK_OPEN;
+
+        local_irq_save(flags);
+        (*(npd->fd_ops->send_int_notification))(npd, 0, 0);
+        local_irq_restore(flags);
+
+        _MOD_DEC_USE_COUNT;
+        TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
+        return 0;
+}
+
+
+/* network_get_stats -
+ *
+ * Gets statistics from the specified network device.
+ *
+ * Returns pointer to net_device_stats structure with the required information.
+ */
+STATIC struct net_device_stats *network_get_stats (struct net_device *net_device)
+{
+        struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
+        return &npd->stats;
+}
+
+
+/* network_set_mac_addr
+ *
+ * Sets the MAC address of the specified network device. Fails if the device is in use.
+ *
+ * Returns non-zero for failure.
+ */
+STATIC int network_set_mac_addr (struct net_device *net_device, void *p)
+{
+        struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
+        struct sockaddr *addr = p;
+        unsigned long flags;
+
+        TRACE_MSG0(NTT,"--");
+
+        RETURN_EBUSY_IF(netif_running (net_device));
+        local_irq_save(flags);
+        memcpy(net_device->dev_addr, addr->sa_data, net_device->addr_len);
+        memcpy(npd->local_dev_addr, npd->net_dev->dev_addr, ETH_ALEN);
+        local_irq_restore(flags);
+        return 0;
+}
+
+
+/* network_tx_timeout -
+ *
+ * Tells the specified network device that its current transmit attempt has timed out.
+ */
+STATIC void network_tx_timeout (struct net_device *net_device)
+{
+        struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
+#if 0
+        //printk(KERN_ERR"%s:\n", __FUNCTION__);
+        npd->stats.tx_errors++;
+        npd->stats.tx_dropped++;
+        usbd_cancel_urb_irq (npd->bus, NULL);  // QQSV
+#endif
+#if 0
+        // XXX attempt to wakeup the host...
+        if ((npd->network_type == network_blan) && (npd->flags & NETWORK_OPEN)) {
+                notification_schedule_bh();
+        }
+#endif
+}
+
+
+/** network_set_config -
+ *
+ * Sets the specified network device's configuration. Fails if the device is in use.
+ *
+ * map           An ifmap structure containing configuration values.
+ *                      Those values which are non-zero/non-null update the corresponding fields
+ *                      in net_device.
+ *
+ * Returns non-zero for failure.
+ */
+STATIC int network_set_config (struct net_device *net_device, struct ifmap *map)
+{
+        RETURN_EBUSY_IF(netif_running (net_device));
+        if (map->base_addr) 
+                net_device->base_addr = map->base_addr;
+        if (map->mem_start) 
+                net_device->mem_start = map->mem_start;
+        if (map->irq) 
+                net_device->irq = map->irq;
+        return 0;
+}
+
+
+/* network_change_mtu -
+ *
+ * Sets the specified network device's MTU. Fails if the new value is larger and
+ * the device is in use.
+ *
+ * Returns non-zero for failure.
+ */
+STATIC int network_change_mtu (struct net_device *net_device, int mtu)
+{
+        struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
+
+        TRACE_MSG0(NTT,"-");
+
+        RETURN_EBUSY_IF(netif_running (net_device));
+        RETURN_EBUSY_IF(mtu > npd->mtu);
+
+        npd->mtu = mtu;
+        return 0;
+}
+
+//_________________________________________________________________________________________________
+//                                      network_hard_start_xmit
+
+/*
+ * net_os_start_xmit - start sending an skb, with usbd_network_sem already held.
+ *
+ * Return non-zero (1) if busy. QQSV - this code always returns 0.
+ */
+STATIC __inline__ int net_os_start_xmit (struct sk_buff *skb, struct net_device *net_device)
+{
+        struct usb_network_private *npd = (struct usb_network_private *)(net_device->priv);
+        int rc;
+
+        if (!netif_carrier_ok(net_device)) {
+                dev_kfree_skb_any (skb);
+                npd->stats.tx_dropped++;
+                //netif_stop_queue(net_device); // XXX
+                // XXX this is what we should do, blows up on some 2.4.20 kernels
+                // return(NET_XMIT_DROP);
+                return(0);
+        }
+
+        // stop queue, it will be restarted only when we are ready for another skb
+        netif_stop_queue(net_device);
+        npd->stopped++;
+
+        // Set the timestamp for tx timeout
+        net_device->trans_start = jiffies;
+
+        // XXX request IN, should start a timer to resend this. 
+        if (npd->data_notify)
+                (*(npd->fd_ops->send_int_notification))(npd, 0, 1);
+
+        rc = (*(npd->fd_ops->start_xmit))(npd,skb->data,skb->len,(void*)skb);
+        switch (rc) {
+        case 0:
+                TRACE_MSG1(NTT,"OK: %d", rc);
+                // update some stats
+                npd->queued_entries++;
+                npd->queued_bytes += skb->len;
+                npd->stats.tx_packets++;
+                npd->stats.tx_bytes += skb->len;
+
+                // Should we restart network queue
+                if ((npd->queued_entries < npd->max_queue_entries) && 
+                                (npd->queued_bytes < npd->max_queue_bytes)) 
+                        netif_wake_queue (net_device);
+
+                break;
+
+        case -EINVAL:
+        case -EUNATCH:
+                TRACE_MSG1(NTT,"not attached, send failed: %d", rc);
+                printk(KERN_ERR"%s: not attached, send failed: %d\n", __FUNCTION__, rc);
+                npd->stats.tx_errors++;
+                npd->stats.tx_carrier_errors++;
+                netif_wake_queue(net_device);
+                break;
+
+        case -ENOMEM:
+                TRACE_MSG1(NTT,"no mem, send failed: %d", rc);
+                printk(KERN_ERR"%s: no mem, send failed: %d\n", __FUNCTION__, rc);
+                npd->stats.tx_errors++;
+                npd->stats.tx_fifo_errors++;
+                netif_wake_queue(net_device);
+                break;
+
+        case -ECOMM:
+                TRACE_MSG2(NTT,"comm failure, send failed: %d %p", rc, net_device);
+                printk(KERN_ERR"%s: comm failure, send failed: %d %p\n", __FUNCTION__, rc, net_device);
+                // Leave the IF queue stopped.
+                npd->stats.tx_dropped++;
+                break;
+
+        }
+        if (0 != rc) {
+                dev_kfree_skb_any (skb);
+                // XXX this is what we should do, blows up on some 2.4.20 kernels
+                // return(NET_XMIT_DROP);
+                return(0);
+        }
+
+        return 0;
+}
+
+/*
+ * network_hard_start_xmit - start sending an skb.  Called by the OS network layer.
+ *
+ * Return non-zero (1) if busy. QQSV - this code always returns 0.
+ */
+STATIC int network_hard_start_xmit (struct sk_buff *skb, struct net_device *net_device)
+{
+        int rc;
+        down(&usbd_network_sem);
+        rc = net_os_start_xmit(skb,net_device);
+        up(&usbd_network_sem);
+        return rc;
+}
+
+
+/* network_do_ioctl - perform an ioctl call 
+ *
+ * Carries out IOCTL commands for the specified network device.
+ *
+ * rp            Points to an ifreq structure containing the IOCTL parameter(s).
+ * cmd           The IOCTL command.
+ *
+ * Returns non-zero for failure.
+ */
+STATIC int network_do_ioctl (struct net_device *net_device, struct ifreq *rp, int cmd)
+{
+        return -ENOIOCTLCMD;
+}
+
+//_________________________________________________________________________________________________
+
+struct net_device Network_net_device = {
+        get_stats: network_get_stats,
+        tx_timeout: network_tx_timeout,
+        do_ioctl: network_do_ioctl,
+        set_config: network_set_config,
+        set_mac_address: network_set_mac_addr,
+        hard_start_xmit: network_hard_start_xmit,
+        change_mtu: network_change_mtu,
+        init: network_init,
+        uninit: network_uninit,
+        open: network_open,
+        stop: network_stop,
+        priv: &Usb_network_private,
+};
+
+//_________________________________________________________________________________________________
+
+#ifdef CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG
+/* sock_ioctl - perform an ioctl call to inet device
+ */
+int sock_ioctl(u32 cmd, struct ifreq *ifreq)
+{
+        int rc = 0;
+        mm_segment_t save_get_fs = get_fs();
+        TRACE_MSG1(NTT, "cmd: %x", cmd);
+        set_fs(get_ds());
+        rc = devinet_ioctl(cmd, ifreq);
+        set_fs(save_get_fs);
+        return rc;
+}
+
+/* sock_addr - setup a socket address for specified interface
+ */
+static int sock_addr(char * ifname, u32 cmd, u32 s_addr)
+{
+        struct ifreq ifreq;
+        struct sockaddr_in *sin = (void *) &(ifreq.ifr_ifru.ifru_addr);
+
+        TRACE_MSG2(NTT, "ifname: %s addr: %x", ifname, ntohl(s_addr));
+
+        memset(&ifreq, 0, sizeof(ifreq));
+        strcpy(ifreq.ifr_ifrn.ifrn_name, ifname); 
+
+        sin->sin_family = AF_INET;
+        sin->sin_addr.s_addr = s_addr;
+        
+        return sock_ioctl(cmd, &ifreq);
+}
+
+
+/* sock_flags - set flags for specified interface
+ */
+static int sock_flags(char * ifname, u16 oflags, u16 sflags, u16 rflags)
+{
+        int rc = 0;
+        struct ifreq ifreq;
+
+        TRACE_MSG4(NTT, "ifname: %s oflags: %x s_flags: %x r_flags: %x", ifname, oflags, sflags, rflags);
+
+        memset(&ifreq, 0, sizeof(ifreq));
+        strcpy(ifreq.ifr_ifrn.ifrn_name, ifname); 
+
+        oflags |= sflags;
+        oflags &= ~rflags;
+        ifreq.ifr_flags = oflags;
+
+        TRACE_MSG1(NTT, "-> ifr_flags: %x ", ifreq.ifr_flags);
+
+        THROW_IF ((rc = sock_ioctl(SIOCSIFFLAGS, &ifreq)), error);
+
+        TRACE_MSG1(NTT, "<- ifr_flags: %x ", ifreq.ifr_flags);
+
+        CATCH(error) {
+                TRACE_MSG1(NTT, "ifconfig: cannot get/set interface flags (%d)", rc);
+                return rc;
+        }
+        return rc;
+}
+
+/* network_attach - configure interface
+ *
+ * This will use socket calls to configure the interface to the supplied
+ * ip address and make it active.
+ */
+STATIC int network_attach(struct usb_network_private *npd, u32 ip, u32 mask, u32 router, int attach)
+{
+        int err = 0;
+
+        if (attach) {
+                TRACE_MSG5(NTT, "ATTACH npd: %x ip: %08x mask: %08x router: %08x attach: %d", npd, ip, mask, router, attach);
+                u16 oflags = (npd && npd->net_dev) ? npd->net_dev->flags : 0;
+
+                if (npd->net_dev)
+                        memcpy(npd->net_dev->dev_addr, npd->local_dev_addr, ETH_ALEN);
+
+                /* setup ip address, netwask, and broadcast address */
+                if (ip) {
+                        THROW_IF ((err = sock_addr("usbl0", SIOCSIFADDR, htonl(ip))), error);
+                        if (mask) {
+                                THROW_IF ((err = sock_addr("usbl0", SIOCSIFNETMASK, htonl(mask))), error);
+                                THROW_IF ((err = sock_addr("usbl0", SIOCSIFBRDADDR, htonl(ip | ~mask))), error);
+                        }
+                        /* bring the interface up */
+                        THROW_IF ((err = sock_flags("usbl0", oflags, IFF_UP, 0)), error);
+                }
+        }
+        else {
+                TRACE_MSG5(NTT, "DETACH npd: %x ip: %08x mask: %08x router: %08x attach: %d", npd, ip, mask, router, attach);
+                u16 oflags = (npd && npd->net_dev) ? npd->net_dev->flags : 0;
+                /* bring the interface down */
+                THROW_IF ((err = sock_flags("usbl0", oflags, 0, IFF_UP)), error);
+        }
+
+        CATCH(error) {
+                TRACE_MSG1(NTT, "ifconfig: cannot configure interface (%d)", err);
+                return err;
+        }
+        return 0;
+}
+
+/* network_config - configure network
+ *
+ * Check connected status and load/unload as appropriate.
+ *
+ */
+STATIC void config_bh (void *data)
+{
+        struct usb_network_private *npd = (struct usb_network_private *) data;
+        struct usbd_function_instance *function = npd->function;
+
+        TRACE_MSG5(NTT, "function: %x enabled: %x status: %x state: %x npd->config_status: %d", 
+                        function, 
+                        npd->flags & NETWORK_ENABLED,
+                        usbd_get_device_status(function),
+                        usbd_get_device_state(function),
+                        npd->config_status);
+
+        if ((npd->flags & NETWORK_ENABLED ) && (function && (USBD_OK == usbd_get_device_status(function)) 
+                         && (STATE_CONFIGURED == usbd_get_device_state(function))
+                         && ip_addr
+                         )) 
+        {
+                TRACE_MSG2(NTT,"BUS state: %d status: %d", usbd_get_device_state(function), usbd_get_device_status(function));
+                if (config_attached != npd->config_status) {
+                        TRACE_MSG0(NTT,"ATTACH");
+                        npd->config_status = config_attached;
+                        network_attach (npd, ip_addr, network_mask, router_ip, 1);
+                }
+                return;
+        }
+
+        if (config_detached != npd->config_status) {
+                TRACE_MSG0(NTT,"DETACH");
+                npd->config_status = config_detached;
+                network_attach (npd, ip_addr, network_mask, router_ip, 0);
+        }
+        //_MOD_DEC_USE_COUNT;
+        TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
+}
+
+/*
+ * net_os_config - schedule a call to config bottom half
+ */
+void net_os_config(struct usb_network_private *npd)
+{
+        //_MOD_INC_USE_COUNT;
+        TRACE_MSG1(NTT, "INC: %d", MOD_IN_USE);
+        if (!SCHEDULE_WORK(npd->config_bh)) {
+                //_MOD_DEC_USE_COUNT;
+                TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
+        }
+}
+#else /* CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG */
+void net_os_config(struct usb_network_private *npd)
+{
+        TRACE_MSG0(NTT, "NOT CONFIGURED");
+        // Do nothing, config not configured.
+}
+#endif /* CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG */
+//______________________________________ Hotplug Functions ________________________________________
+
+#ifdef CONFIG_OTG_NETWORK_HOTPLUG
+
+#define AGENT "network_fd"
+
+/* hotplug_attach - call hotplug 
+ */
+STATIC int hotplug_attach(struct usb_network_private *npd, u32 ip, u32 mask, u32 router, int attach)
+{
+        static int count = 0;
+        char *argv[3];
+        char *envp[10];
+        char ifname[20+12 + IFNAMSIZ];
+        int i;
+        char count_str[20];
+
+        RETURN_EINVAL_IF(!hotplug_path[0]);
+
+        argv[0] = hotplug_path;
+        argv[1] = AGENT;
+        argv[2] = 0;
+
+        sprintf (ifname, "INTERFACE=%s", npd->net_dev->name);
+        sprintf (count_str, "COUNT=%d", count++);
+
+        i = 0;
+        envp[i++] = "HOME=/";
+        envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+        envp[i++] = ifname;
+
+
+        if (attach) {
+                unsigned char *cp;
+                char ip_str[20+32];
+                char mask_str[20+32];
+                char router_str[20+32];
+                u32 nh;
+
+                nh = htonl(ip);
+                cp = (unsigned char*) &nh;
+                sprintf (ip_str, "IP=%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
+
+                nh = htonl(mask);
+                cp = (unsigned char*) &nh;
+                sprintf (mask_str, "MASK=%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
+
+                nh = htonl(router);
+                cp = (unsigned char*) &nh;
+                sprintf (router_str, "ROUTER=%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
+
+                //TRACE_MSG3(NTT, "attach %s %s %s", ifname, ip_str, count_str);
+
+                envp[i++] = "ACTION=attach";
+                envp[i++] = ip_str;
+                envp[i++] = mask_str;
+                envp[i++] = router_str;
+
+                TRACE_MSG3(NTT, "attach ip: %08x mask: %08x router: %08x", ip, mask, router);
+        }
+        else {
+                //TRACE_MSG2(NTT,"detach %s %s", ifname, count_str);
+                envp[i++] = "ACTION=detach";
+                TRACE_MSG3(NTT, "detach ip: %08x mask: %08x router: %08x", ip, mask, router);
+        }
+
+        envp[i++] = count_str;
+        envp[i++] = 0;
+
+        return call_usermodehelper (argv[0], argv, envp);
+}
+
+
+/* hotplug_bh - bottom half handler to call hotplug script to signal ATTACH or DETACH
+ *
+ * Check connected status and load/unload as appropriate.
+ *
+ * It should not be possible for this to be called more than once at a time
+ * as it is only called via schedule_task() which protects against a second
+ * invocation.
+ */
+STATIC void hotplug_bh (void *data)
+{
+        //struct usb_network_private *network_private = &Usb_network_private;
+        struct usb_network_private *npd = (struct usb_network_private *) data;
+        struct usbd_function_instance *function = NULL; 
+
+        UNLESS (npd) {
+              //_MOD_DEC_USE_COUNT;
+              TRACE_MSG1(NTT, "NPD NULL DEC: %d", MOD_IN_USE);
+              return;
+        }
+
+        function = npd->function;
+
+        TRACE_MSG2(NTT, "function: %x npd->hotplug_status: %d", function, npd->hotplug_status);
+
+
+        if ((npd->flags & NETWORK_ENABLED ) && (function && (USBD_OK == usbd_get_device_status(function)) 
+                         && (STATE_CONFIGURED == usbd_get_device_state(function)))) 
+        {
+                TRACE_MSG2(NTT,"BUS state: %d status: %d", usbd_get_device_state(function), usbd_get_device_status(function));
+                if (hotplug_attached != npd->hotplug_status) {
+                        TRACE_MSG0(NTT,"ATTACH");
+                        npd->hotplug_status = hotplug_attached;
+                        hotplug_attach (npd, ip_addr, network_mask, router_ip, 1);
+                }
+                return;
+        }
+
+        if (hotplug_detached != npd->hotplug_status) {
+                TRACE_MSG0(NTT,"DETACH");
+                npd->hotplug_status = hotplug_detached;
+                hotplug_attach (npd, ip_addr, network_mask, router_ip, 0);
+        }
+        //_MOD_DEC_USE_COUNT;
+        TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
+}
+
+/*
+ * net_os_hotplug - schedule a call to hotplug bottom half
+ */
+void net_os_hotplug(struct usb_network_private *npd)
+{
+        //_MOD_INC_USE_COUNT;
+        TRACE_MSG1(NTT, "INC: %d", MOD_IN_USE);
+        if (!SCHEDULE_WORK(npd->hotplug_bh)) {
+                //_MOD_DEC_USE_COUNT;
+                TRACE_MSG1(NTT, "DEC: %d", MOD_IN_USE);
+        }
+}
+#else
+void net_os_hotplug(struct usb_network_private *npd)
+{
+        TRACE_MSG0(NTT, "NOT CONFIGURED");
+        // Do nothing, hotplug not configured.
+}
+#endif                  /* CONFIG_OTG_NETWORK_HOTPLUG */
+
+//_________________________________________________________________________________________________
+
+/* network_create - create and initialize network private structure
+ *
+ * Returns non-zero for failure.
+ */
+STATIC int network_create(struct usb_network_private *npd)
+{
+        TRACE_MSG0(NTT,"entered");
+
+        // Set some fields to generic defaults and register the network device with the kernel networking code
+
+        memset(&npd->stats, 0, sizeof npd->stats);
+
+        ether_setup(npd->net_dev);
+        RETURN_EINVAL_IF (register_netdev(npd->net_dev));
+        npd->flags |= NETWORK_REGISTERED;
+
+        netif_stop_queue(npd->net_dev);
+        netif_carrier_off(npd->net_dev);
+        npd->net_dev->flags &= ~IFF_UP;
+
+        npd->flags |= NETWORK_CREATED;
+
+        npd->maxtransfer = MAXFRAMESIZE + 4 + 64;
+
+        TRACE_MSG0(NTT,"finis");
+        return 0;
+}
+
+/* network_destroy - destroy network private struture
+ *
+ * Destroys the network interface referenced by the global variable @c Network_net_device.
+ */
+STATIC void network_destroy(struct usb_network_private *npd)
+{
+        if (npd->flags & NETWORK_REGISTERED) {
+                netif_stop_queue(npd->net_dev);
+                netif_carrier_off(npd->net_dev);
+                unregister_netdev(npd->net_dev);
+        }
+        npd->flags = 0;
+}
+
+
+//______________________________________module_init and module_exit________________________________
+
+#ifdef CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG
+
+/*! network_proc_read_ip - implement proc file system read.
+ * Standard proc file system read function.
+ */
+static ssize_t network_proc_read_ip (struct file *file, char *buf, size_t count, loff_t * pos)
+{
+        unsigned long page;
+        int len = 0;
+        char *bp;
+        int index = (*pos)++;
+
+        RETURN_ZERO_IF(index);
+
+        // get a page, max 4095 bytes of data...
+        RETURN_ENOMEM_UNLESS ((page = GET_KERNEL_PAGE()));
+
+        bp = (char *) page;
+
+        len = sprintf(bp, "%d.%d.%d.%d\n", 
+                        (router_ip >> 24) & 0xff,
+                        (router_ip >> 16) & 0xff,
+                        (router_ip >> 8) & 0xff,
+                        (router_ip) & 0xff
+                        );
+
+        if (copy_to_user(buf, (char *) page, len)) 
+                len = -EFAULT;
+        
+        free_page (page);
+        return len;
+}
+
+static struct file_operations otg_message_proc_switch_functions = {
+      read: network_proc_read_ip,
+};
+
+#endif
+
+
+/* network_modinit - driver intialization
+ *
+ * Returns non-zero for failure.
+ */
+STATIC int network_modinit (void)
+{
+        // Pickup and link together the various global structs.
+        struct usb_network_private *npd = &Usb_network_private;
+        #ifdef CONFIG_PROC_FS
+        struct proc_dir_entry *p;
+        #endif /* CONFIG_PROC_FS */
+        npd->fd_ops = &net_fd_usb_ops;
+        npd->params = &params;
+        npd->net_dev = &Network_net_device;
+        npd->net_dev->priv = (void *) npd;
+#ifdef CONFIG_OTG_NETWORK_ALLOW_SETID
+        params.vendor_id = vendor_id;
+        params.product_id = product_id;
+#endif
+        params.local_mac_address_str = local_mac_address_str;
+        params.remote_mac_address_str = remote_mac_address_str;
+#ifdef CONFIG_OTG_NETWORK_EP0TEST
+        params.ep0test = ep0test;
+#endif
+        params.zeroconf = zeroconf;
+#if defined(CONFIG_OTG_NETWORK_CDC)
+        params.cdc = cdc;
+#endif
+#ifdef CONFIG_OTG_NETWORK_BASIC
+        params.basic = basic;
+#endif
+#ifdef CONFIG_OTG_NETWORK_BASIC2
+        params.basic2 = basic2;
+#endif
+#ifdef CONFIG_OTG_NETWORK_SAFE
+        params.safe = safe;
+#endif
+#ifdef CONFIG_OTG_NETWORK_BLAN
+        params.blan = blan;
+#endif
+        // That should be it for reference to globals except for network_modexit().
+
+        init_waitqueue_head(&usb_netif_wq);
+        PREPARE_WORK_ITEM(npd->notification_bh, notification_bh,npd);
+#ifdef CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG
+        PREPARE_WORK_ITEM(npd->config_bh, config_bh, npd);
+        #ifdef CONFIG_PROC_FS
+        if ((p = create_proc_entry ("network_ip", 0666, 0))) 
+                p->proc_fops = &otg_message_proc_switch_functions;
+        #endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG */
+#ifdef CONFIG_OTG_NETWORK_HOTPLUG
+        PREPARE_WORK_ITEM(npd->hotplug_bh, hotplug_bh, npd);
+#endif /* CONFIG_OTG_NETWORK_HOTPLUG */
+
+        if (0 != (*(npd->fd_ops->initialize_usb_part))(npd,"linux network_fd")) {
+                // If the usb part fails, there are no trace functions.
+                return -EINVAL;
+        }
+
+        memcpy(npd->net_dev->dev_addr, npd->local_dev_addr, ETH_ALEN);
+        /* QQSV - this is very strange, since npd->network type can have
+           a number of different values. setting zeroconf is not going to
+           be quite as obvious as it might at first seem. */
+        strncpy(npd->net_dev->name, ((npd->network_type == zeroconf) ? "usbz0" :
+                                     (network_blan ? "usbl0" : "usbb0")), 6);
+
+        if (network_create(npd)) {
+                (*(npd->fd_ops->terminate_usb_part))(npd);
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+//_____________________________________________________________________________
+
+/* network_modexit - driver exit
+ *
+ * Cleans up the module. Deregisters the function driver and destroys the network object.
+ */
+STATIC void network_modexit (void)
+{
+        struct usb_network_private *npd = &Usb_network_private;
+
+        #ifdef CONFIG_PROC_FS
+        remove_proc_entry("network_ip", NULL);
+        #endif /* CONFIG_PROC_FS */
+
+        while (PENDING_WORK_ITEM(npd->notification_bh)) {
+                // TRACE_MSG pointless here, module will be gon before we can look at it.
+                printk(KERN_ERR"%s: waiting for notificationhotplug bh\n", __FUNCTION__);
+                schedule_timeout(10 * HZ);
+        }
+#ifdef CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG
+        while (PENDING_WORK_ITEM(npd->config_bh)) {
+                printk(KERN_ERR"%s: waiting for config bh\n", __FUNCTION__);
+                schedule_timeout(10 * HZ);
+        }
+#endif /* CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG */
+
+#ifdef CONFIG_OTG_NETWORK_HOTPLUG
+        while (PENDING_WORK_ITEM(npd->hotplug_bh)) {
+                printk(KERN_ERR"%s: waiting for hotplug bh\n", __FUNCTION__);
+                schedule_timeout(10 * HZ);
+        }
+#endif
+        /* Which order to tear down the two parts?  No matter which goes first,
+           the other could still try to send data through the now-torn-down part,
+           so go with usb last, because it has the otg_trace cleanup. */
+        network_destroy(npd);
+        if (npd->fd_ops) 
+                (*(npd->fd_ops->terminate_usb_part))(npd);
+}
+
+//_________________________________________________________________________________________________
+
+module_init (network_modinit);
+module_exit (network_modexit);
+
diff -uNr linux/drivers/no-otg/functions/network/net-os.h linux/drivers/otg/functions/network/net-os.h
--- linux/drivers/no-otg/functions/network/net-os.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/net-os.h	2006-09-01 21:41:30.000000000 +0200
@@ -0,0 +1,107 @@
+/*
+ * otg/functions/network/net-os.h
+ *
+ *      Copyright (c) 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ */
+
+/*!
+ * @file otg/functions/network/net-os.h
+ * @brief Structures and function definitions required for implementation
+ * of the OS specific upper edge (network interface) for the Network
+ * Function Driver.
+ *
+ * A USB network driver is composed of two pieces:
+ *    1) An OS specific piece that handles creating and operating
+ *       a network device for the given OS.
+ *    2) A USB specific piece that interfaces either with the host
+ *       usbcore layer, or with the device usbdcore layer.
+ *
+ * If the USB piece interfaces with the host usbcore layer you get
+ * a network class driver.  If the USB piece interfaces with the usbdcore
+ * layer you get a network function driver.
+ *
+ * This file describes the functions exported by the various net-*-os.c
+ * files (implementing (1)) for use in net-fd.c (2).
+ *
+ *
+ * @ingroup NetworkFunction
+ */
+
+#ifndef NET_OS_H
+#define NET_OS_H 1
+
+/*
+ * net_os_mutex_enter - enter mutex region
+ */
+extern void net_os_mutex_enter(struct usb_network_private *npd);
+
+/*
+ * net_os_mutex_exit - exit mutex region
+ */
+extern void net_os_mutex_exit(struct usb_network_private *npd);
+
+/*
+ * net_os_send_notification_later - schedule a callback to the USB part to send
+ *                                  an INT notification.
+ */
+extern void net_os_send_notification_later(struct usb_network_private *npd);
+
+/*
+ * net_os_xmit_done - called from USB part when a transmit completes, good or bad.
+ *                    tx_rc is SEND_FINISHED_ERROR, SEND_CANCELLED or...
+ *                    buff_ctx is the pointer passed to fd_ops->start_xmit().
+ * Return non-zero only if network does not exist, ow 0.
+ */
+extern int net_os_xmit_done(struct usbd_function_instance *function, void *buff_ctx, int tx_rc);
+
+/*
+ *
+ */
+extern void *net_os_alloc_buff(struct usb_network_private *npd, u8 **cp, int n);
+
+/*
+ * net_os_recv_buff - forward a received URB, or clean up after a bad one.
+ *      buff_ctx == NULL --> just accumulate stats (count 1 bad buff)
+ *      crc_bad != 0     --> count a crc error and free buff_ctx/skb
+ *      trim             --> amount to trim from valid buffer (i.e. shorten
+ *                           from amount requested in net_os_alloc_buff(..... n).
+ *                    This will be called from interrupt context.
+ */
+extern void net_os_recv_buff(struct usb_network_private *npd, void *buff_ctx, int crc_bad, int trim);
+
+/*
+ * net_os_config - schedule a network hotplug event if the OS supports hotplug.
+ */
+extern void net_os_config(struct usb_network_private *npd);
+
+/*
+ * net_os_hotplug - schedule a network hotplug event if the OS supports hotplug.
+ */
+extern void net_os_hotplug(struct usb_network_private *npd);
+
+/*
+ *
+ */
+extern void net_os_enable(struct usbd_function_instance *function);
+
+/*
+ *
+ */
+extern void net_os_disable(struct usbd_function_instance *function);
+
+/*
+ *
+ */
+extern void net_os_carrier_on(struct usb_network_private *npd);
+
+/*
+ *
+ */
+extern void net_os_carrier_off(struct usb_network_private *npd);
+
+#endif
diff -uNr linux/drivers/no-otg/functions/network/network.h linux/drivers/otg/functions/network/network.h
--- linux/drivers/no-otg/functions/network/network.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/network.h	2006-09-01 21:41:30.000000000 +0200
@@ -0,0 +1,348 @@
+/*
+ * otg/functions/network/network.h - Network Function Driver
+ *
+ *      Copyright (c) 2002, 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Tom Rushworth <tbr@belcarra.com>
+ *      Chris Lynne <cl@belcarra.com>
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*!
+ * @defgroup NetworkFunction Network
+ * @ingroup functiongroup 
+ */
+/*!
+ * @file otg/functions/network/network.h
+ * @brief Network Function Driver private defines
+ *
+ * This defines the internal and private structures required
+ * by the Network Function Driver.
+ *
+ * @ingroup NetworkFunction
+ */
+
+/*! This is a test
+ */
+#ifndef NETWORK_FD_H
+#define NETWORK_FD_H 1
+
+#include <otg/otg-trace.h>
+
+extern otg_tag_t network_fd_trace_tag;
+
+// Some platforms need to get rid of "static" when using GDB or looking at ksyms
+//#define STATIC
+#define STATIC static
+
+typedef enum network_encapsulation {
+        simple_net, simple_crc, 
+} network_encapsulation_t;
+
+typedef enum network_config_status {
+        config_unkown,
+        config_attached,
+        config_detached
+} network_config_status_t;
+
+typedef enum network_hotplug_status {
+        hotplug_unkown,
+        hotplug_attached,
+        hotplug_detached
+} network_hotplug_status_t;
+
+typedef enum network_type {
+        network_unknown,
+        network_blan,
+        network_safe,
+        network_cdc,
+        network_basic,
+        network_basic2,
+        network_eem,
+} network_type_t;
+
+struct usb_network_params {
+        // enabling switchs
+        u32 cdc;
+        u32 basic;
+        u32 basic2;
+        u32 safe;
+        u32 blan;
+        // capability flags
+        u32 cdc_capable;
+        u32 basic_capable;
+        u32 basic2_capable;
+        u32 safe_capable;
+        u32 blan_capable;
+        // overrides
+        u32 vendor_id;
+        u32 product_id;
+        char *local_mac_address_str;
+        char *remote_mac_address_str;
+        // other switches
+        u32 ep0test;
+        u32 zeroconf;
+};
+
+#define CONFIG_OTG_NETWORK_ALLOW_SETID           1
+
+#define NETWORK_CREATED         0x01
+#define NETWORK_REGISTERED      0x02
+#define NETWORK_DESTROYING      0x04
+#define NETWORK_ENABLED         0x08
+#define NETWORK_ATTACHED        0x10 
+#define NETWORK_OPEN            0x20
+
+
+#define MCCI_ENABLE_CRC         0x03
+#define BELCARRA_GETMAC         0x04
+
+#define BELCARRA_SETTIME        0x04
+#define BELCARRA_SETIP          0x05
+#define BELCARRA_SETMSK         0x06
+#define BELCARRA_SETROUTER      0x07
+#define BELCARRA_SETDNS         0x08
+#define BELCARRA_PING           0x09
+#define BELCARRA_SETFERMAT      0x0a
+#define BELCARRA_HOSTNAME       0x0b
+
+
+// RFC868 - seconds from midnight on 1 Jan 1900 GMT to Midnight 1 Jan 1970 GMT
+#define RFC868_OFFSET_TO_EPOCH  0x83AA7E80
+
+struct usb_network_private {
+
+        struct net_device_stats stats;  /* network device statistics */
+
+        int flags;
+        struct net_device *net_dev;
+        struct usbd_function_instance *function;
+        struct usbd_function_driver *function_driver;
+        struct usb_network_params *params;
+        struct net_usb_services *fd_ops;
+        unsigned int maxtransfer;
+        rwlock_t rwlock;
+
+        network_config_status_t config_status;
+        network_hotplug_status_t hotplug_status;
+        network_type_t network_type;
+
+        int state;
+
+        int mtu; 
+        int crc;
+#if defined(CONFIG_OTG_NETWORK_BLAN_FERMAT)
+        int fermat;
+#endif
+
+        unsigned int stopped; 
+        unsigned int restarts;
+
+        unsigned int max_queue_entries;
+        unsigned int max_queue_bytes;
+
+        unsigned int queued_entries;
+        unsigned int queued_bytes;
+
+        time_t avg_queue_entries;
+
+        time_t jiffies;
+        unsigned long samples;
+
+        int have_interrupt;
+
+        int data_notify;
+
+        struct usbd_urb *int_urb;
+
+        network_encapsulation_t encapsulation;
+
+        struct WORK_ITEM notification_bh;
+#ifdef CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG
+        struct WORK_ITEM config_bh;
+#endif /* CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG */
+#ifdef CONFIG_HOTPLUG
+        struct WORK_ITEM hotplug_bh;
+#endif /* CONFIG_HOTPLUG */
+        __u8 local_dev_addr[ETH_ALEN];
+        __u8 remote_dev_addr[ETH_ALEN];
+};
+
+// XXX this needs to be co-ordinated with rndis.c maximum's
+#define MAXFRAMESIZE 2000
+
+#if !defined(CONFIG_OTG_MANUFACTURER)
+        #define CONFIG_OTG_MANUFACTURER                "Belcarra"
+#endif
+
+
+#if !defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        #define CONFIG_OTG_SERIAL_NUMBER_STR           ""
+#endif
+
+/*
+ * Lineo specific 
+ */
+
+#define VENDOR_SPECIFIC_CLASS           0xff
+#define VENDOR_SPECIFIC_SUBCLASS        0xff
+#define VENDOR_SPECIFIC_PROTOCOL        0xff
+
+/*
+ * Lineo Classes
+ */
+#define LINEO_CLASS                     0xff
+
+#define LINEO_SUBCLASS_BASIC_NET          0x01
+#define LINEO_SUBCLASS_BASIC_SERIAL       0x02
+
+/*
+ * Lineo Protocols
+ */
+#define LINEO_BASIC_NET_CRC             0x01
+#define LINEO_BASIC_NET_CRC_PADDED      0x02
+
+#define LINEO_BASIC_SERIAL_CRC          0x01
+#define LINEO_BASIC_SERIAL_CRC_PADDED   0x02
+
+
+/*
+ * endpoint and interface indexes
+ */
+#define BULK_OUT        0x00
+#define BULK_IN         0x01
+#define INT_IN          0x02
+#define ENDPOINTS       0x03
+
+#define COMM_INTF       0x00
+#define DATA_INTF       0x01
+
+
+/* bmDataCapabilities */
+#define BMDATA_CRC                      0x01
+#define BMDATA_PADBEFORE                0x02
+#define BMDATA_PADAFTER                 0x04
+#define BMDATA_FERMAT                   0x08
+#define BMDATA_HOSTNAME                 0x10
+
+/* bmNetworkCapabilities */
+#define BMNETWORK_SET_PACKET_OK         0x01
+#define BMNETWORK_NONBRIDGED            0x02
+#define BMNETWORK_DATA_NOTIFY_OK        0x04
+
+
+/*
+ * BLAN Data Plane
+ */
+//#define CONFIG_OTG_NETWORK_PADBYTES  8
+//#define CONFIG_OTG_NETWORK_PADAFTER  1
+//#undef CONFIG_OTG_NETWORK_PADBEFORE  
+//#define CONFIG_OTG_NETWORK_CRC       1
+
+
+extern __u8 network_requested_endpoints[ENDPOINTS+1];
+extern __u16 network_requested_transferSizes[ENDPOINTS+1];
+extern struct usb_network_private Usb_network_private;
+extern __u8 local_dev_addr[ETH_ALEN];
+extern __u8 remote_dev_addr[ETH_ALEN];
+
+extern struct usbd_function_operations net_fd_function_ops;
+
+struct usbd_class_safe_networking_mdlm_descriptor {
+        __u8 bFunctionLength;           // 0x06
+        __u8 bDescriptorType;           // 0x24
+        __u8 bDescriptorSubtype;        // 0x13
+        __u8 bGuidDescriptorType;       // 0x00
+        __u8 bmNetworkCapabilities;
+        __u8 bmDataCapabilities;
+} __attribute__ ((packed));
+
+struct usbd_class_blan_networking_mdlm_descriptor {
+        __u8 bFunctionLength;           // 0x07
+        __u8 bDescriptorType;           // 0x24
+        __u8 bDescriptorSubtype;        // 0x13
+        __u8 bGuidDescriptorType;       // 0x01
+        __u8 bmNetworkCapabilities;
+        __u8 bmDataCapabilities;
+        __u8 bPad;
+} __attribute__ ((packed));
+
+
+
+
+#define NETWORK_CREATED         0x01
+#define NETWORK_REGISTERED      0x02
+#define NETWORK_DESTROYING      0x04
+#define NETWORK_ENABLED         0x08
+#define NETWORK_ATTACHED        0x10
+#define NETWORK_OPEN            0x20
+
+
+#define MCCI_ENABLE_CRC         0x03
+#define BELCARRA_GETMAC         0x04
+
+#define BELCARRA_SETTIME        0x04
+#define BELCARRA_SETIP          0x05
+#define BELCARRA_SETMSK         0x06
+#define BELCARRA_SETROUTER      0x07
+#define BELCARRA_SETDNS         0x08
+#define BELCARRA_PING           0x09
+#define BELCARRA_SETFERMAT      0x0a
+#define BELCARRA_HOSTNAME       0x0b
+#define BELCARRA_DATA_NOTIFY    0x0c
+
+#define RFC868_OFFSET_TO_EPOCH  0x83AA7E80      // RFC868 - seconds from midnight on 1 Jan 1900 GMT to Midnight 1 Jan 1970 GMT
+
+
+extern __u32 *network_crc32_table;
+                        
+#define CRC32_INIT   0xffffffff      // Initial FCS value
+#define CRC32_GOOD   0xdebb20e3      // Good final FCS value
+
+#define CRC32_POLY   0xedb88320      // Polynomial for table generation
+        
+#define COMPUTE_FCS(val, c) (((val) >> 8) ^ network_crc32_table[((val) ^ (c)) & 0xff])
+
+
+#if 0
+#if !defined(CONFIG_OTG_NETWORK_CRC_DUFF4) && !defined(CONFIG_OTG_NETWORK_CRC_DUFF8)
+/**
+ * Copies a specified number of bytes, computing the 32-bit CRC FCS as it does so.
+ *
+ * dst   Pointer to the destination memory area.
+ * src   Pointer to the source memory area.
+ * len   Number of bytes to copy.
+ * val   Starting value for the CRC FCS.
+ *
+ * Returns      Final value of the CRC FCS.
+ *
+ * @sa crc32_pad
+ */
+static __u32 __inline__ crc32_copy (__u8 *dst, __u8 *src, int len, __u32 val)
+{
+        for (; len-- > 0; val = COMPUTE_FCS (val, *dst++ = *src++));
+        return val;
+}
+
+#endif /* DUFFn */
+#endif
+
+
+
+
+#endif /* NETWORK_FD_H */
diff -uNr linux/drivers/no-otg/functions/network/safe.c linux/drivers/otg/functions/network/safe.c
--- linux/drivers/no-otg/functions/network/safe.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/functions/network/safe.c	2006-09-01 21:41:30.000000000 +0200
@@ -0,0 +1,362 @@
+/*
+ * otg/functions/network/safe.c - Network Function Driver
+ *
+ *      Copyright (c) 2002, 2003, 2004 Belcarra
+ *
+ * By: 
+ *      Thomas Rushworth <tbr @belcarra.com>
+ *      Stuart Lynne <sl@belcarra.com>
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * The SAFE network driver implements the SAFE protocol descriptors.
+ *
+ * The SAFE protocol is suitable for infrastructure devices that
+ * are implementing a bridged or routed connection betwen an
+ * external network and the USB Host.
+ *
+ *
+ */
+/*!
+ * @file otg/functions/network/safe.c
+ * @brief This file implements the required descriptors to implement
+ * a SAFE network device with one interface.
+ *
+ * @ingroup NetworkFunction
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/utsname.h>
+#include <linux/netdevice.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+
+#include "network.h"
+
+#define NTT network_fd_trace_tag
+
+#ifdef CONFIG_OTG_NETWORK_SAFE
+/* USB SAFE  Configuration ********************************************************** */
+
+/*
+ * SAFE Ethernet Configuration
+ */
+
+/* Communication Interface Class descriptors
+ */
+
+/*! BULK OUT data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor safe_data_1 = {
+    bLength: 0x07,
+    bDescriptorType: USB_DT_ENDPOINT,
+    bEndpointAddress: USB_DIR_OUT,
+    bmAttributes: BULK,     
+    wMaxPacketSize: __constant_cpu_to_le16(0), 
+    bInterval: 0,
+};
+/*! BULK IN data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor safe_data_2 =
+{
+    bLength:sizeof(struct usbd_endpoint_descriptor),
+    bDescriptorType:USB_DT_ENDPOINT,
+    bEndpointAddress:USB_DIR_IN, 
+    bmAttributes: BULK,     
+    wMaxPacketSize: __constant_cpu_to_le16(0), 
+    bInterval: 0x0,
+};
+
+/*! INTERRUPT IN data endpoint descriptor
+ */
+static struct usbd_endpoint_descriptor safe_comm_1 = 
+{
+    bLength:sizeof(struct usbd_endpoint_descriptor),
+    bDescriptorType:USB_DT_ENDPOINT,
+    bEndpointAddress:USB_DIR_IN, 
+    bmAttributes: INTERRUPT,     
+    wMaxPacketSize: __constant_cpu_to_le16(0), 
+    bInterval: 0xa,
+};
+
+#if 0
+static  struct usbd_endpoint_descriptor  *basic_default[] = { &basic_data_1, 
+    &basic_data_2, 
+    &basic_comm_1, };
+u8 basic_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
+#endif
+	
+#if 0
+static u8 safe_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x10, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
+static u8 safe_class_2[] = { 0x15, CS_INTERFACE, USB_ST_MDLM, 0x00, 0x01, /* bcdVersion, bcdVersion */
+
+                0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,  /* bGUID */
+                0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,  /* bGUID */ };
+
+static u8 safe_class_3[] = { 0x06, CS_INTERFACE, USB_ST_MDLMD, 0x00, 0x00, 0x00,    /* bDetailData */ };
+
+static u8 safe_class_4[] = { 0x0d, CS_INTERFACE, USB_ST_ENF, 
+        0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x05, /* 1514 maximum frame size */
+        0x00, 0x00, 0x00 , };
+#else 
+static  struct usbd_class_header_function_descriptor safe_class_1 = { 
+     bFunctionLength:0x05, 
+     bDescriptorType: CS_INTERFACE, 
+     bDescriptorSubtype: USB_ST_HEADER, 
+     bcdCDC: __constant_cpu_to_le16(0x0110), //0x10, 0x01, 
+};
+
+static struct usbd_class_mdlm_descriptor safe_class_2 = { 
+     bFunctionLength: 0x15, 
+     bDescriptorType: CS_INTERFACE, 
+     bDescriptorSubtype: USB_ST_MDLM, 
+     bcdVersion: __constant_cpu_to_le16( 0x0100), //0x00, 0x01, 
+     bGUID:  {
+                0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,  /* bGUID */
+                0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,  /* bGUID */ },
+};
+
+static struct usbd_class_safe_descriptor safe_class_3 = { 
+     bFunctionLength: 0x06, 
+     bDescriptorType: CS_INTERFACE, 
+     bDescriptorSubtype: USB_ST_MDLMD, 
+     bGuidDescriptorType: 0x00, 
+     bmNetworkCapabilities: 0x00, 
+     bmDataCapabilities: 0x00,    /* bDetailData */ 
+};
+
+static struct usbd_class_ethernet_networking_descriptor safe_class_4 = { 
+     bFunctionLength: 0x0d, 
+     bDescriptorType: CS_INTERFACE, 
+     bDescriptorSubtype: USB_ST_ENF,
+     iMACAddress: 0x0,
+     bmEthernetStatistics: __constant_cpu_to_le32(0x00), 
+     wMaxSegmentSize: __constant_cpu_to_le16(0x5ea),
+     wNumberMCFilters: __constant_cpu_to_le16(0x00),
+     bNumberPowerFilters: 0,
+};
+
+#endif
+
+/*! Endpoint descriptor list
+ */
+static struct usbd_endpoint_descriptor  *safe_alt_endpoints[] = { 
+    &safe_data_1, &safe_data_2, &safe_comm_1, };
+
+static struct usbd_generic_class_descriptor  *safe_comm_class_descriptors[] = { 
+        (struct usbd_generic_class_descriptor *) &safe_class_1, 
+        (struct usbd_generic_class_descriptor *) &safe_class_2, 
+        (struct usbd_generic_class_descriptor *) &safe_class_3, 
+        (struct usbd_generic_class_descriptor *) &safe_class_4, };
+
+u8 safe_alt_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
+
+/*! Data Interface Descriptor
+ */
+static struct usbd_interface_descriptor safe_alternate_descriptor = {
+    bLength: 0x09,
+    bDescriptorType: USB_DT_INTERFACE,
+    bInterfaceNumber: 0x00,
+    bAlternateSetting: 0x00,
+    bNumEndpoints: sizeof(safe_alt_endpoints)/sizeof(struct usbd_endpoint_descriptor *),
+    bInterfaceClass: COMMUNICATIONS_INTERFACE_CLASS,
+    bInterfaceSubClass: COMMUNICATIONS_MDLM_SUBCLASS,
+    bInterfaceProtocol: COMMUNICATIONS_NO_PROTOCOL,
+    iInterface: 0x00,
+};
+
+/*! Data Alternate Interface Description List
+ */
+static struct usbd_alternate_description safe_alternate_descriptions[] = {
+    { 
+        iInterface: CONFIG_OTG_NETWORK_SAFE_INTF,
+        interface_descriptor: &safe_alternate_descriptor,
+        classes: sizeof (safe_comm_class_descriptors) / sizeof (struct usbd_generic_class_descriptor *),
+        class_list: safe_comm_class_descriptors,
+        endpoints:sizeof (safe_alt_endpoints) / sizeof(struct usbd_endpoint_descriptor *),
+        endpoint_list: safe_alt_endpoints,
+        endpoint_indexes: safe_alt_indexes,
+    },
+};
+
+/* Interface descriptions and descriptors
+ */
+/*! Interface Description List
+ */
+static struct usbd_interface_description safe_interfaces[] = {
+    { 
+        alternates:sizeof (safe_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+        alternate_list:safe_alternate_descriptions, },
+};
+
+
+/* Configuration descriptions and descriptors
+ */
+
+/*! Configuration Descriptor 
+ */
+static struct usbd_configuration_descriptor  safe_configuration_descriptor = {
+    bLength: 0x09, 
+    bDescriptorType: USB_DT_CONFIGURATION, 
+    wTotalLength: __constant_cpu_to_le16(0x0000), //0x00, 0x00, // wLength
+    bNumInterfaces:sizeof (safe_interfaces) / sizeof (struct usbd_interface_description),
+    bConfigurationValue:0x01, 
+    iConfiguration: 0x00, // bConfigurationValue, iConfiguration
+    bmAttributes: 0, 
+    bMaxPower:0,
+};
+
+/*! Configuration Description List 
+ */
+struct usbd_configuration_description safe_description[] = {
+    { 
+        iConfiguration: CONFIG_OTG_NETWORK_SAFE_DESC,
+        configuration_descriptor: &safe_configuration_descriptor,
+    },
+};
+
+/* Device Description
+ */
+/*! Device Descriptor 
+ */
+static struct usbd_device_descriptor safe_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+/*! High Speed Device Qualifier Descriptor 
+ */
+static struct usbd_device_qualifier_descriptor safe_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
+        bDeviceSubClass: 0x02,
+        bDeviceProtocol: 0x00,
+        bMaxPacketSize0: 0x00,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+/*! Endpoint Request List
+ */
+static struct usbd_endpoint_request safe_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512,  },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512,  },
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
+        { 0, },
+};
+
+/*! OTG Descriptor
+ */
+static struct usbd_otg_descriptor safe_otg_descriptor = {
+        bLength : sizeof(struct usbd_otg_descriptor),
+        bDescriptorType: USB_DT_OTG,
+        bmAttributes: 0,
+};
+
+/*! Device Description
+ */
+struct usbd_device_description safe_device_description = {
+        device_descriptor: &safe_device_descriptor,
+#ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &safe_device_qualifier_descriptor,
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &safe_otg_descriptor,
+        iManufacturer: CONFIG_OTG_NETWORK_MANUFACTURER,
+        iProduct: CONFIG_OTG_NETWORK_PRODUCT_NAME,
+#if !defined(CONFIG_OTG_NO_SERIAL_NUMBER) && defined(CONFIG_OTG_SERIAL_NUMBER_STR)
+        iSerialNumber:CONFIG_OTG_SERIAL_NUMBER_STR,
+#endif
+};
+
+/*! safe_init
+ * @param function The function instance
+ */
+void safe_init (struct usbd_function_instance *function)
+{
+        struct usbd_class_ethernet_networking_descriptor *ethernet;
+        int len = 0;
+        char buf[255];
+
+        buf[0] = 0;
+
+        safe_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 3 : 2;
+
+        // Update the iMACAddress field in the ethernet descriptor
+        {
+                char address_str[14];
+                snprintf(address_str, 13, "%02x%02x%02x%02x%02x%02x",
+                                remote_dev_addr[0], remote_dev_addr[1], remote_dev_addr[2], 
+                                remote_dev_addr[3], remote_dev_addr[4], remote_dev_addr[5]);
+                if ((ethernet = &safe_class_4)) {
+                        if (ethernet->iMACAddress) {
+                                usbd_free_string_descriptor(ethernet->iMACAddress);
+                        }
+                        ethernet->iMACAddress = usbd_alloc_string(address_str);
+                }
+        }
+
+#ifdef CONFIG_OTG_NETWORK_SAFE_PADBEFORE
+        safe_class_3.bmNetworkCapabilities |= BMDATA_PADBEFORE;
+        len += sprintf(buf + len, "PADBEFORE: %02x ", safe_class_3.bmNetworkCapabilities);
+#endif
+#ifdef CONFIG_OTG_NETWORK_SAFE_CRC
+        safe_class_3.bmNetworkCapabilities |= BMDATA_CRC;
+        len += sprintf(buf + len, "CRC: %02x ", safe_class_3.bmNetworkCapabilities);
+#endif
+#ifdef CONFIG_OTG_NETWORK_SAFE_NONBRIDGED
+        safe_class_3.bmNetworkCapabilities |= BMNETWORK_NONBRIDGED;
+        len += sprintf(buf + len, "NONBRIDGE: %02x ",safe_class_3.bmDataCapabilities);
+#endif
+        if (strlen(buf))
+                TRACE_MSG1(NTT,"%s", buf);
+
+}
+
+/*! function driver description
+ */
+struct usbd_function_driver safe_function_driver = {
+        name: "network-SAFE",
+        fops: &net_fd_function_ops,
+        device_description: &safe_device_description,
+        bNumConfigurations: sizeof (safe_description) / sizeof (struct usbd_configuration_description),
+        configuration_description: safe_description,
+        idVendor: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_VENDORID),
+        idProduct: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_PRODUCTID),
+        bcdDevice: __constant_cpu_to_le16(CONFIG_OTG_NETWORK_BCDDEVICE),
+        bNumInterfaces:sizeof (safe_interfaces) / sizeof (struct usbd_interface_description),
+        interface_list:safe_interfaces, 
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: safe_endpoint_requests,
+};
+#endif                  /* CONFIG_OTG_NETWORK_SAFE */
+
diff -uNr linux/drivers/no-otg/ocd/Config.in linux/drivers/otg/ocd/Config.in
--- linux/drivers/no-otg/ocd/Config.in	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/Config.in	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,15 @@
+
+#
+# Copyright (c) 2004 Belcarra
+#
+# 
+
+   mainmenu_option next_comment
+   comment 'OTG Host Controller Driver (HCD)'
+   dep_tristate '  USB Host Controller Driver' CONFIG_OTG_HCD $CONFIG_OTG_HOSTCORE
+   hex     'VendorID (hex value)'             CONFIG_OTG_ROOTHUB_VENDORID "15ec"
+   hex     'ProductID (hex value)'            CONFIG_OTG_ROOTHUB_PRODUCTID "f010"
+   hex     'ProductID (hex value)'            CONFIG_OTG_ROOTHUB_BCDDEVICE "0100"
+
+
+   endmenu
diff -uNr linux/drivers/no-otg/ocd/Makefile linux/drivers/otg/ocd/Makefile
--- linux/drivers/no-otg/ocd/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/Makefile	2006-09-01 21:41:30.000000000 +0200
@@ -0,0 +1,44 @@
+#
+# Belcarra OTG - On-The-Go 
+#
+# Copyright (c) 2004 Belcarra Technologies Corp
+
+TOPDIR ?= ../../../..
+
+subdir-y 	:= 
+subdir-m 	:=
+subdir-n 	:=
+subdir- 	:=
+
+# The target object and module list name.
+
+O_TARGET        := ocd_target.o
+
+subdir-$(CONFIG_OTG_AU1550) += au1x00
+subdir-$(CONFIG_OTG_AU1X00) += au1x00
+subdir-$(CONFIG_OTG_ISP1301_OMAP_H2) += isp1301
+subdir-$(CONFIG_OTG_ISP1301_MAINSTONE) += isp1301
+
+subdir-$(CONFIG_OTG_MAX3353E_DB1550) += max3353e
+
+# Object file lists.
+
+obj-y           :=
+obj-m           :=
+obj-n           :=
+obj-            :=
+
+# Bus Interface Drivers
+ocd-obj-$(CONFIG_OTG_AU1550) += au1x00/au1x00_pcd_drv.o
+ocd-obj-$(CONFIG_OTG_AU1X00) += au1x00/au1x00_pcd_drv.o
+
+# Platform 
+ocd-obj-$(CONFIG_OTG_ISP1301_OMAP_H2) += isp1301/isp1301_target.o
+ocd-obj-$(CONFIG_OTG_ISP1301_MAINSTONE) += isp1301/isp1301_target.o
+
+ocd-obj-$(CONFIG_OTG_MAX3353E_DB1550) += max3353e/max3353e_target.o
+
+obj-y += $(ocd-obj-y)  
+
+include $(TOPDIR)/Rules.make
+EXTRA_CFLAGS += -Wno-format -Wall
diff -uNr linux/drivers/no-otg/ocd/Makefile-l26 linux/drivers/otg/ocd/Makefile-l26
--- linux/drivers/no-otg/ocd/Makefile-l26	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/Makefile-l26	2006-09-01 21:41:30.000000000 +0200
@@ -0,0 +1,29 @@
+#
+# Belcarra OTG - On-The-Go 
+#
+# Copyright (c) 2004 Belcarra Technologies Corp
+
+EXTRA_CFLAGS += -Wno-format -Wall
+
+# Bus Interface Drivers
+#subdir-$(CONFIG_OTG_AU1X00) += au1x00
+#subdir-$(CONFIG_OTG_LH7A400) += lh7a400
+#subdir-$(CONFIG_OTG_MX1) += mx1
+#subdir-$(CONFIG_OTG_MX2) += mx2
+#subdir-$(CONFIG_OTG_NC2280) += nc2280
+#subdir-$(CONFIG_OTG_PXA) += pxa
+#subdir-$(CONFIG_OTG_SA1100) += sa1100
+#subdir-$(CONFIG_OTG_SMDK2500) += smdk2500
+#subdir-$(CONFIG_OTG_SUPERH) += superh
+#subdir-$(CONFIG_OTG_SX2) += sx2
+#subdir-$(CONFIG_OTG_WMMX) += wmmx
+
+obj-m += scma11-evb/
+obj-m += omap/
+obj-m += isp1301/
+
+obj-y += scma11-evb/
+obj-y += omap/
+obj-y += isp1301/
+
+
diff -uNr linux/drivers/no-otg/ocd/README linux/drivers/otg/ocd/README
--- linux/drivers/no-otg/ocd/README	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/README	2006-09-01 21:41:30.000000000 +0200
@@ -0,0 +1,54 @@
+otg/pcd
+
+
+Linux Build support:
+
+        Makefile
+        Makefile-l24
+        Makefile-l26
+
+        README
+
+PCD support files:
+
+        otg-pcd/pcd.c
+        otg-pcd/pcd-init-l24.c
+        otg-pcd/pcd-ocd-init-l24.c
+        otg-pcd/tr-init-l24.c
+
+TCD support files:
+
+        otg-tcd/tcd.c
+        otg-tcd/tcd-init-l24.c
+
+HCD support files;
+
+        otg-hcd/hcd-init-l24.c
+        otg-hcd/hcd-l26.c
+        otg-hcd/hcd-rh.c
+        otg-hcd/hcd.c
+
+Architecture Specific Drivers:
+
+        lh7a400
+        mx1
+        nc2280
+        pxa
+        sa1100
+        smdk2500
+        superh
+        sx2
+
+Device Specific Drivers:
+        
+        atlas
+        isp1301
+        max3353e
+
+Platform Specific Drivers
+
+        au1x00
+        bvd
+        mx2
+        omap
+
diff -uNr linux/drivers/no-otg/ocd/au1x00/Makefile linux/drivers/otg/ocd/au1x00/Makefile
--- linux/drivers/no-otg/ocd/au1x00/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/au1x00/Makefile	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,111 @@
+#
+# Makefile for the kernel USBD (device not host) drivers.
+#
+# Copyright (c) 2002 Belcarra
+
+# Subdirs.
+# This is a bit complex, because some subdirs are for
+# proprietary code, and are simply not present in a
+# general distribution.
+
+# The all-CAPS *_DIRS get nuked in the new versions
+# of Rules.make, so use only the subdir-* methods.
+subdir-y 	:=
+subdir-m 	:=
+subdir-n 	:=
+subdir- 	:=
+
+# The target object and module list name.
+
+O_TARGET	:= au1x00_pcd_drv.o
+
+# Objects that export symbols.
+
+export-objs	:= 
+
+# Multipart objects.
+
+#au1x00_otg-objs	:= au1x00.o usbd-bi.o trace.o
+db1550_tr-objs	:= tr-init-l24.o au1550.o pcd.o 
+db1550_dr-objs	:= tr-init-l24.o au1550.o pcd.o 
+#au1550_tr-objs	:= tr-init-l24.o au1550.o pcd.o 
+au1x00_tr-objs	:= tr-init-l24.o au1x00.o pcd.o 
+
+# Optional parts of multipart objects.
+
+# Object file lists.
+
+#obj-y		:= usbd-bi.o 
+obj-y		:=
+obj-m		:=
+obj-n		:=
+obj-		:=
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_OTG_AU1550_DB1500_TR)	+= db1550_tr.o
+obj-$(CONFIG_OTG_AU1550_DB1550_TR)	+= db1550_tr.o
+obj-$(CONFIG_OTG_AU1550_DB1500_DR)	+= db1550_dr.o
+
+#obj-$(CONFIG_OTG_AU1550)		+= au1550_tr.o
+obj-$(CONFIG_OTG_AU1X00)		+= au1x00_tr.o
+
+# Object files in subdirectories
+
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+int-m		:= $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
+OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
+
+OTG=$(TOPDIR)/drivers/otg
+OCD_DIR=$(OTG)/ocd
+INCLUDE_DIRS =          -I$(OTG) 
+EXTRA_CFLAGS +=          -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
+EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
+
+I2C=$(OTG)/ocd/otg-i2c
+PCD=$(OTG)/ocd/otg-pcd
+vpath %.c $(USBDCORE_DIR) $(OCD_DIR) $(PCD) $(I2C)
+
+
+# Link rules for multi-part drivers.
+
+db1550_tr.o: $(db1550_tr-objs)
+	$(LD) -r -o $@ $(db1550_tr-objs)
+
+db1550_dr.o: $(db1550_tr-objs)
+	$(LD) -r -o $@ $(au1550_tr-objs)
+
+#au1550_tr.o: $(au1550_tr-objs)
+#	$(LD) -r -o $@ $(au1550_tr-objs)
+
+au1x00_tr.o: $(au1x00_tr-objs)
+	$(LD) -r -o $@ $(au1x00_tr-objs)
+
+# dependencies:
+
+# local
+
+
diff -uNr linux/drivers/no-otg/ocd/au1x00/NOTES.txt linux/drivers/otg/ocd/au1x00/NOTES.txt
--- linux/drivers/no-otg/ocd/au1x00/NOTES.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/au1x00/NOTES.txt	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,62 @@
+
+Notes
+
+1. EP0 - packetsize of 8 does not work, this means that PIO cannot be used for IN (transmit).
+DMA must be used. Only 16, 32 and 64 are usable.
+
+Update: even though we couldn't program the endpoint size to 8, we just set it to 8 in the
+device descriptor and things work ok. This works and we don't need or use DMA for either
+direction for EP0.
+
+2. For each BULK transfer the first N packets must be sent with the full packetsize and the
+last must be sent as a short packet. The packetsize must be set before enabling the DMA.
+
+3. For IN endpoints an interrupt will be generated for EVERY IN packet including ones that
+will be NAK'd. To reduce overhead the interrupt should only be enabled when there is data
+being sent and we need to know when it has been sent.
+
+Update: for new silicon this is not true, the UDC will interrupt less often and will NAK
+until the interrupt is cleared.
+
+4. The AU1x00 auto-acks many setup commands and is very sensitive to latency of the irq
+handler processing the interrupt and clearing the ep0 fifo. Like the pxa we need to spool the
+requests and process later when we receive a request for data.  There is a special test in
+the bulk data receive handler to check if there are spooled requests to process.
+
+Update: this has been mostly mitigated by reducing all upper layer processing in recv_setup,
+event_irq etc so that they complete in less than a milli-second. This simplifies things and
+we can now pass UUT tests.
+
+5. There is a time sensitive problem in au_in_epn(). Without a udelay(8) sending large
+packets will eventually stall interrupts.
+
+Update: this is not required for new silicon.
+
+6. When receiving data (Bulk OUT) the UDC will not start NAKing until and unless the receive
+FIFO is full. This means that there is no reliable way to determine the end of one packet and
+the beginning of the next if there is any undue latency in handling the interrupt for the
+first packet.
+
+The Belcarra Windows and Macintosh network class drivers have an option that can be used
+to pad all outgoing packets to a multiple of 8 bytes. This helps eliminate this problem.
+
+Update: this is not a problem with new silicon, it NAK's until the interrupt is cleared.
+
+8. The original AU1x00 UDC generated an interrupt for EVERY IN packet. If we do not have
+any data we need to disable the interrupt for the endpoint to eliminate the overhead
+for processing them. The interrupt must be re-enabled when DMA is finished and we
+actually want to know that the endpoint has finished.
+
+Leaving the interrupt enabled also interfers with the DMA process. It is not apparant
+why.
+
+Update: This has been fixed on the new silicon but it doesn't hurt to continue to do this.
+
+9. The DMA functions replace the equivalent routines in au1100_dma.h except that they pass
+the actual struct dma_chan pointer instead of the channel number.  The bounds checking and
+table lookup to derive this information amounts to a substantial increase in code size and
+latency which can simply be avoided by using the structure address directly and/or doing the
+equivalent i/o directly.
+
+10. The Au1x00 does not support REMOTE WAKEUP
+
diff -uNr linux/drivers/no-otg/ocd/au1x00/au1550.c linux/drivers/otg/ocd/au1x00/au1550.c
--- linux/drivers/no-otg/ocd/au1x00/au1550.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/au1x00/au1550.c	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,1451 @@
+/*
+ * otg/ocd/au1x00/au1x00.c -- USB Device Controller driver. 
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *
+ */
+/*!
+ * @file otg/ocd/au1x00/au1550.c
+ * @brief AU1X00 Header
+ *
+ * This file contains the private defines and structures for the AU1X00  
+ * Drivers. 
+ *
+ * @ingroup AU1X00
+ */
+
+
+#include <otg/pcd-include.h>
+#include "au1x00.h"
+
+#include <asm/io.h>
+#include <asm/au1000.h>
+#include <asm/au1000_dma.h>
+
+#if defined(CONFIG_SOC_AU1550)
+#include <asm/au1xxx_dbdma.h>
+#else
+#error "Wrong AU1X00_MDA"
+#endif
+
+#include <asm/mipsregs.h>
+
+#ifdef CONFIG_MIPS_FREEHAND
+#include <linux/i2c.h>
+#include <linux/sensors.h>      /* for reading serial number */
+#endif
+
+
+#undef CHECK_LATENCY
+#undef RECORD_LATENCY
+#undef MAX_INTR_LOOP_STATS   //10
+#if defined(MAX_INTR_LOOP_STATS)
+static u32 interrupt_loop_stats[MAX_INTR_LOOP_STATS+1];
+#endif
+#ifdef  RECORD_LATENCY
+#define CP0_COUNTS 50
+u32 cp0_counts[CP0_COUNTS];
+u32 cp0_record;
+#endif
+u32 cp0_count;
+unsigned int udc_saw_bus_activity;
+int au_halt_dma_expired;
+u32 au1x00_inten;
+
+u8 au1x00_config_bulk[25] = {
+        0x04, (USB_ENDPOINT_CONTROL << 4) | (EP0_PACKETSIZE & 0x380) >> 7,                            // 1
+        (EP0_PACKETSIZE & 0x7F) << 1, 0x00, 0x00,
+        0x24, (USB_ENDPOINT_BULK << 4) | USB_DIR_IN | (MAX_EPN_PACKET_SIZE & 0x380) >> 7,             // 6
+        (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x02, 
+        0x34, (USB_ENDPOINT_BULK << 4) | USB_DIR_IN | (MAX_EPN_PACKET_SIZE & 0x380) >> 7,             // 11
+        (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x03, 
+        0x44, (USB_ENDPOINT_BULK << 4) | USB_DIR_OUT | (MAX_EPN_PACKET_SIZE & 0x380) >> 7,            // 16
+        (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x04,
+        0x54, (USB_ENDPOINT_BULK << 4) | USB_DIR_OUT | (MAX_EPN_PACKET_SIZE & 0x380) >> 7,            // 21
+        (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x05,
+};
+
+/* ********************************************************************************************* */
+/* Note - The endpoints names are confusing. To simplify mapping of the interrupt request lines
+ * we use a numbering of the physical endpoints of 0-5, which also matches the fifo numbering
+ * (see the config block).
+ *
+ *   Physical  FIFO    Name    Direction   Logical
+ *      0       0       EP0     OUT         0
+ *      1       1       EP0     IN          0
+ *      2       2       EP1     IN          81
+ *      3       3       EP2     IN          82
+ *      4       4       EP3     OUT         3
+ *      5       5       EP4     OUT         4
+ *
+ * The ep_regs array maps a physical endpoint number to the registers required to access the udc
+ * for that endpoint. Note that ep0 is always accessed via 0.  The epl2p array maps the logical
+ * addresses back to the physical number.  The epp2l array maps the physical number to the
+ * logical endpoint address
+ */
+struct ep_regs ep_regs[6] = {
+
+        { rd: USBD_EP0RD, rds: USBD_EP0RDSTAT, /*rx_id: DMA_ID_USBDEV_EP0_RX,*/ cs: USBD_EP0CS, rx_str: "EP0 OUT RD",
+          wr: USBD_EP0WR, wrs: USBD_EP0WRSTAT, tx_id: DSCR_CMD0_USBDEV_TX0,                 tx_str: "EP0 IN WR",},
+
+        { rds: 0, wrs: 0, indma: -1, outdma: -1, },     // ep0
+        { wr: NUSBD_EP1WR, wrs: NUSBD_EP1WRSTAT, tx_id: DSCR_CMD0_USBDEV_TX1, cs: NUSBD_EP1CS, tx_str: "EP1 IN WR",},
+        { wr: NUSBD_EP2WR, wrs: NUSBD_EP2WRSTAT, tx_id: DSCR_CMD0_USBDEV_TX2, cs: NUSBD_EP2CS, tx_str: "EP2 IN WR",},
+
+        { rd: NUSBD_EP3RD, rds: NUSBD_EP3RDSTAT, rx_id: DSCR_CMD0_USBDEV_RX3, cs: NUSBD_EP3CS, rx_str: "EP3 OUT RD",},
+        { rd: NUSBD_EP4RD, rds: NUSBD_EP4RDSTAT, rx_id: DSCR_CMD0_USBDEV_RX4, cs: NUSBD_EP4CS, rx_str: "EP4 OUT RD",},
+};
+u8 epl2p[6] = { 0x00, 0x02, 0x03, 0x04, 0x05, 0x00, };        // map logical to physical
+u8 epp2l[6] = { 0x00, 0x00, 0x81, 0x82, 0x03, 0x04, };        // map physical to logical
+
+static __inline__ void au_fifo_read(struct ep_regs *ep, unsigned char * cp, int bytes)
+{
+        u32 rd = ep->rd;
+        for (; bytes--; *cp++ = au_readl(rd));
+}
+
+static __inline__ void au_fifo_write(int ep, unsigned char * cp, int bytes)
+{
+        u32 wr = ep_regs[ep].wr;
+        for (; bytes--; au_writel(*cp++, wr));
+        ep_regs[ep].last = bytes;
+}
+
+void __inline__ au_inten(u32 inten, char *msg)
+{
+        TRACE_MSG2(PCD, "%s %08x", msg, inten);
+        au1x00_inten = inten;
+        au_writel(au1x00_inten, USBD_INTEN);
+}
+
+void __inline__ au_epn_interrupt_enable(int epn)
+{
+        au_inten(au1x00_inten | (1 << epn), "epn enable");
+}
+
+void __inline__ au_epn_interrupt_disable(int epn)
+{
+        au_inten(au1x00_inten & ~(1 << epn), "epn disable");
+        au_writel((1 << epn) , USBD_INTSTAT);
+}
+
+static void __inline__ send_zlp(unsigned char epn)
+{
+        au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep_regs[epn].wrs);
+        au_writel(0 << 1, ep_regs[epn].cs);
+        au_writel(0, ep_regs[epn].wr);
+}
+/* ********************************************************************************************* */
+#define AU_DMA_HALT_POLL 0x1000
+
+#define         DDMA_DESCCMD_ARB                        (1<<15)
+#define         DDMA_DESCCMD_DW                         (16)
+#define         DDMA_DESCCMD_DW_N(n)            ((n&3)<<DDMA_DESCCMD_DW)
+ #define                DDMA_DESCCMD_DW_BYTE    DDMA_DESCCMD_DW_N(0)
+ #define                DDMA_DESCCMD_DW_HWORD   DDMA_DESCCMD_DW_N(1)
+ #define                DDMA_DESCCMD_DW_WORD    DDMA_DESCCMD_DW_N(2)
+#define         DDMA_DESCCMD_SW                         (18)
+#define         DDMA_DESCCMD_SW_N(n)            ((n&3)<<DDMA_DESCCMD_SW)
+ #define                DDMA_DESCCMD_SW_BYTE    DDMA_DESCCMD_SW_N(0)
+ #define                DDMA_DESCCMD_SW_HWORD   DDMA_DESCCMD_SW_N(1)
+ #define                DDMA_DESCCMD_SW_WORD    DDMA_DESCCMD_SW_N(2)
+
+#define         DDMA_DESCCMD_DID                        (20)
+#define         DDMA_DESCCMD_DID_N(n)           ((n&0x1F)<<DDMA_DESCCMD_DID)
+#define         DDMA_DESCCMD_SID                        (25)
+#define         DDMA_DESCCMD_SID_N(n)           ((n&0x1F)<<DDMA_DESCCMD_SID)
+
+/*      
+ *      Bit definitions for source stride/block 1 dimensional
+ */
+#define         DDMA_DESCSRC_STRIDE_SS                          (0)
+#define         DDMA_DESCSRC_STRIDE_SS_N(n)                     ((n&0x3fff)<<DDMA_DESCSRC_STRIDE_SS)
+#define         DDMA_DESCSRC_STRIDE_SB                          (14)
+#define         DDMA_DESCSRC_STRIDE_SB_N(n)                     ((n&0x3Fff)<<DDMA_DESCSRC_STRIDE_SB)
+#define         DDMA_DESCSRC_STRIDE_SAM                         (28)
+#define         DDMA_DESCSRC_STRIDE_SAM_N(n)            ((n&3)<<DDMA_DESCSRC_STRIDE_SAM)
+ #define                DDMA_DESCSRC_STRIDE_SAM_INC             DDMA_DESCSRC_STRIDE_SAM_N(0)
+ #define        DDMA_DESCSRC_STRIDE_SAM_DEC             DDMA_DESCSRC_STRIDE_SAM_N(1)
+ #define                DDMA_DESCSRC_STRIDE_SAM_STATIC  DDMA_DESCSRC_STRIDE_SAM_N(2)
+ #define                DDMA_DESCSRC_STRIDE_SAM_BURST   DDMA_DESCSRC_STRIDE_SAM_N(3)
+#define         DDMA_DESCSRC_STRIDE_STS                         (30)
+#define         DDMA_DESCSRC_STRIDE_STS_N(n)            ((n&3)<<DDMA_DESCSRC_STRIDE_STS)
+ #define                DDMA_DESCSRC_STRIDE_STS_1               DDMA_DESCSRC_STRIDE_STS_N(0)
+ #define                DDMA_DESCSRC_STRIDE_STS_2               DDMA_DESCSRC_STRIDE_STS_N(1)
+ #define                DDMA_DESCSRC_STRIDE_STS_4               DDMA_DESCSRC_STRIDE_STS_N(2)
+ #define                DDMA_DESCSRC_STRIDE_STS_8               DDMA_DESCSRC_STRIDE_STS_N(3)
+                                        
+
+/*
+ *      Bit definitions for dest         stride/block 1 dimensional 
+ */
+#define         DDMA_DESCDST_STRIDE_DS                          (0)
+#define         DDMA_DESCDST_STRIDE_DS_N(n)                     ((n&0x3fff)<<DDMA_DESCDST_STRIDE_DS)
+#define         DDMA_DESCDST_STRIDE_DB                          (14)
+#define         DDMA_DESCDST_STRIDE_DB_N(n)                     ((n&0x3Fff)<<DDMA_DESCDST_STRIDE_DB)
+#define         DDMA_DESCDST_STRIDE_DAM                         (28)
+#define         DDMA_DESCDST_STRIDE_DAM_N(n)            ((n&3)<<DDMA_DESCDST_STRIDE_DAM)
+ #define                DDMA_DESCDST_STRIDE_DAM_INC             DDMA_DESCDST_STRIDE_DAM_N(0)
+ #define        DDMA_DESCDST_STRIDE_DAM_DEC             DDMA_DESCDST_STRIDE_DAM_N(1)                                               #define                DDMA_DESCDST_STRIDE_DAM_STATIC  DDMA_DESCDST_STRIDE_DAM_N(2)
+ #define                DDMA_DESCDST_STRIDE_DAM_BURST   DDMA_DESCDST_STRIDE_DAM_N(3)
+#define         DDMA_DESCDST_STRIDE_DTS                         (30)
+#define         DDMA_DESCDST_STRIDE_DTS_N(n)            ((n&3)<<DDMA_DESCDST_STRIDE_DTS)
+ #define                DDMA_DESCDST_STRIDE_DTS_1               DDMA_DESCDST_STRIDE_DTS_N(0)
+ #define                DDMA_DESCDST_STRIDE_DTS_2               DDMA_DESCDST_STRIDE_DTS_N(1)
+ #define                DDMA_DESCDST_STRIDE_DTS_4               DDMA_DESCDST_STRIDE_DTS_N(2)
+ #define                DDMA_DESCDST_STRIDE_DTS_8               DDMA_DESCDST_STRIDE_DTS_N(3)
+
+#ifndef CONFIG_MIPS_MTX2
+typedef struct dbdma_device_table {
+        u32             dev_flags;
+        u32             dev_tsize;
+        u32             dev_devwidth;
+        u32             dev_physaddr;           /* If FIFO */
+        u32             dev_intlevel;
+        u32             dev_intpolarity;
+} dbdev_tab_t;
+
+typedef struct dbdma_chan_config {
+        u32                     chan_flags;
+        u32                     chan_index;
+        dbdev_tab_t             *chan_src;
+        dbdev_tab_t             *chan_dest;
+        au1x_dma_chan_t         *chan_ptr;
+        au1x_ddma_desc_t        *chan_desc_base;
+        au1x_ddma_desc_t        *get_ptr, *put_ptr, *cur_ptr;
+        void                    *chan_callparam;
+        void (*chan_callback)(int, void *, struct pt_regs *);
+} chan_tab_t;
+#endif
+static void __inline__ au_halt_dma(u32 chan)
+{
+        chan_tab_t                      *ctp = *((chan_tab_t **)chan);
+        volatile au1x_dma_chan_t        *cp = ctp->chan_ptr;;
+        au1x_ddma_desc_t                *dp;
+
+	au1xxx_dbdma_stop(chan);  
+        au_halt_dma_expired++;
+
+        dp = ctp->cur_ptr;              // ensure that descriptor is stopped
+        dp->dscr_cmd0 &= ~DSCR_CMD0_V;
+
+}
+
+static void __inline__ au_start_dma_in(int indma, u32 tx_id, __u8 *bp, int len)
+{
+        chan_tab_t                      *ctp = *((chan_tab_t **)indma);
+        au1x_ddma_desc_t                *dp = ctp->cur_ptr; 
+        volatile au1x_dma_chan_t        *cp = ctp->chan_ptr;;
+
+        TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %08x dst: %08x %08x MEM2USB", 
+                        indma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
+                        dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
+
+        dp->dscr_source0 = virt_to_phys(bp);
+        dp->dscr_source1 = DDMA_DESCSRC_STRIDE_STS_4 | DDMA_DESCSRC_STRIDE_SAM_INC;
+
+        dp->dscr_cmd1 = len;
+        dp->dscr_cmd0  = 
+                DSCR_CMD0_SID(DSCR_CMD0_ALWAYS) |
+                DSCR_CMD0_DID(indma) 
+                ;
+        TRACE_MSG1(PCD, "cmd0: %08x SID/DID", dp->dscr_cmd0);
+
+        dp->dscr_cmd0  |= 
+                DDMA_DESCCMD_SW_BYTE |
+                DDMA_DESCCMD_DW_BYTE 
+                ;
+        TRACE_MSG1(PCD, "cmd0: %08x SW/DW", dp->dscr_cmd0);
+
+        dp->dscr_cmd0  = DSCR_CMD0_V |
+                DSCR_CMD0_SID(DSCR_CMD0_ALWAYS) |
+                DSCR_CMD0_DID(tx_id) |
+                DDMA_DESCCMD_SW_BYTE |
+                DDMA_DESCCMD_DW_BYTE |
+                DSCR_CMD0_ARB |
+                DSCR_CMD0_DN |
+                DSCR_CMD0_CV 
+                ;
+
+        dp->dscr_dest1 = DDMA_DESCDST_STRIDE_DTS_4 | DDMA_DESCSRC_STRIDE_SAM_STATIC;
+                
+        ctp->cur_ptr = dp;
+        cp->ddma_desptr = virt_to_phys(ctp->cur_ptr);
+        cp->ddma_cfg |= DDMA_CFG_EN;    /* Enable channel */
+        au_sync();
+        cp->ddma_dbell = 0xffffffff;    /* Make it go */
+        au_sync();
+
+        TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %08x dst: %08x %08x MEM2USB start", 
+                        indma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
+                        dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
+}
+
+static void __inline__ au_start_dma_out(unsigned int outdma, u32 rx_id, __u8 *bp, int wMaxPacketSize)
+{
+        chan_tab_t                      *ctp = *((chan_tab_t **)outdma);
+        au1x_ddma_desc_t                *dp = ctp->cur_ptr; 
+        volatile au1x_dma_chan_t        *cp = ctp->chan_ptr;;
+
+        
+        dma_cache_inv((unsigned long) bp, wMaxPacketSize);
+
+        TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %08x dst: %08x %08x USB2MEM", 
+                        outdma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
+                        dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
+
+        // if (!au1xxx_dbdma_put_dest(outdma, bp, wMaxPacketSize)) 
+        
+        dp->dscr_dest0 = virt_to_phys(bp);
+        dp->dscr_dest1 = DDMA_DESCDST_STRIDE_DTS_4 | DDMA_DESCDST_STRIDE_DAM_INC;
+
+        dp->dscr_cmd1 = wMaxPacketSize;
+        dp->dscr_cmd0  = DSCR_CMD0_V |
+                DSCR_CMD0_SID(rx_id) |
+                DSCR_CMD0_DID(DSCR_CMD0_ALWAYS) |
+                DDMA_DESCCMD_SW_BYTE |
+                DDMA_DESCCMD_DW_BYTE |
+                DSCR_CMD0_ARB |
+                DSCR_CMD0_SN |
+                DSCR_CMD0_CV 
+                ;
+
+        dp->dscr_source1 = DDMA_DESCSRC_STRIDE_STS_4 | DDMA_DESCSRC_STRIDE_SAM_STATIC;
+
+        ctp->cur_ptr = dp;
+        cp->ddma_desptr = virt_to_phys(ctp->cur_ptr);
+        cp->ddma_cfg |= DDMA_CFG_EN;    /* Enable channel */
+        au_sync();
+        cp->ddma_dbell = 0xffffffff;    /* Make it go */
+        au_sync();
+
+        TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %08x dst: %08x %08x USB2MEM start", 
+                        outdma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
+                        dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
+}
+
+/* ********************************************************************************************* */
+static struct usbd_urb *au_rcv_complete_ep0_irq(struct usbd_endpoint_instance *endpoint, int len, int urb_bad)
+{
+        struct usbd_urb *rcv_urb = endpoint->rcv_urb;
+        if (rcv_urb && !urb_bad) {
+                int i;
+                u8 *cp = rcv_urb->buffer + rcv_urb->actual_length;
+                for (i = 0 ; i < len; i+= 8)
+                        TRACE_MSG8(PCD, "ARCV  %02x %02x %02x %02x %02x %02x %02x %02x",
+                                        cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
+                                        cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
+                                  );
+
+        }
+        return pcd_rcv_complete_irq(endpoint, len, urb_bad);
+}
+
+/* au_start_in_ep0 - start transmit
+ */
+static void au_start_in_ep0 (struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+	struct usbd_urb *urb = endpoint->tx_urb;
+        int last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
+        TRACE_MSG2(PCD, "START IN EP0 SENT: %d SENDING: %d", endpoint->sent, last);
+        RETURN_IF ((urb->actual_length - endpoint->sent) <= 0);
+        au_writel(last << 1, ep->cs); // XXX
+        au_fifo_write(0, urb->buffer + endpoint->sent, last);
+        endpoint->last = last;
+}
+
+/* au_in_ep0 - called to service an endpoint zero IN interrupt, data sent
+ */
+static void au_in_ep0(struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+        u32 cs;
+        struct usbd_urb *tx_urb;
+        int last;
+        TRACE_MSG1(PCD, "EP0 IN: tx_urb: %p", (int)endpoint->tx_urb);
+        if ((cs = au_readl(ep->cs)) & USBDEV_CS_STALL) {                // clear stall if present
+                TRACE_MSG1(PCD, "CLEAR STALL %d", 0);
+                cs &= ~USBDEV_CS_STALL;
+                au_writel(cs, ep->cs);
+                return;
+        }
+        if (!(tx_urb = pcd_tx_complete_irq(endpoint, 0))) {               // wait for setup if no more data
+                endpoint->state = WAIT_FOR_SETUP;
+                return;
+        }
+        TRACE_MSG4(PCD, "EP0 IN actual: %d last: %d sent: %d flags: %x", endpoint->tx_urb->actual_length, 
+                        endpoint->last, endpoint->sent, endpoint->tx_urb->flags);
+        if (pcd_tx_sendzlp(endpoint)) {                          // check if tx_urb we have is finished
+                TRACE_MSG0(PCD, "EP0 IN BULK - sending ZLP");
+                tx_urb->flags &= ~USBD_URB_SENDZLP;
+                send_zlp(0);
+                pcd_tx_complete_irq(endpoint, 0);
+                return;
+        }
+        if (tx_urb->actual_length > endpoint->sent) {
+                if ((tx_urb->actual_length - endpoint->sent) < endpoint->wMaxPacketSize) 
+                        TRACE_MSG1(PCD, "EP0 IN starting short packet %d", tx_urb->actual_length - endpoint->sent);
+                else 
+                        TRACE_MSG1(PCD, "EP0 IN LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
+                au_start_in_ep0(endpoint, ep);
+        }
+}
+
+/* au_out_ep0 - called to service an endpoint zero OUT interrupt, data received
+ */
+static void au_out_ep0(struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+        struct usbd_device_request request;
+        int i;
+        u32 cs;
+        u32 bytes;
+        TRACE_MSG0(PCD, "EP0 OUT");
+        cs = au_readl(ep->cs);                                  // check if host aborted transfer and flush the write fifo
+        bytes = au_readl(ep->rds) & USBDEV_FSTAT_FCNT_MASK;
+        if (endpoint->state == DATA_STATE_RECV) {
+                struct usbd_urb *rcv_urb = pcd_rcv_next_irq(endpoint);
+                TRACE_MSG1(PCD, "EP0 OUT: RECV: rcv_urb: %x", (int) rcv_urb);
+                if (rcv_urb) {
+                        au_fifo_read(ep, rcv_urb->buffer + rcv_urb->actual_length, bytes);
+                        if (au_rcv_complete_ep0_irq(endpoint, bytes, 0)) 
+                                return;
+                        au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+                        endpoint->state = WAIT_FOR_SETUP;
+                        send_zlp(0);
+                        return;
+                }
+                endpoint->state = WAIT_FOR_SETUP;
+        }
+        pcd_tx_cancelled_irq(endpoint);
+        pcd_rcv_cancelled_irq(endpoint);
+        au_fifo_read(ep, (u8 *)&request, bytes);
+        au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs);
+        if (bytes != 8) {
+                TRACE_MSG1(PCD, "ERROR SETUP SET not eight bytes: %d", bytes);
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs);
+                return;
+        }
+        TRACE_MSG4(PCD, "SETUP bmRequestType: %02x bRequest %02x state: %d status: %d", request.bmRequestType, 
+                        request.bRequest, pcd_instance->bus->device_state, pcd_instance->bus->status);
+        switch (request.bRequest) {                     // we need to simply ignore any of these
+        case USB_REQ_SET_ADDRESS:                       // Fake a bus reset IFF not state default and then process normally
+                BREAK_IF (pcd_instance->bus->device_state == STATE_DEFAULT);
+                udc_saw_bus_activity = 0;
+                usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_RESET, 0);
+                //usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_ADDRESS_ASSIGNED, 0);
+                break;
+        case USB_REQ_GET_DESCRIPTOR:                    // Fake a bus reset IFF suspended and then process normally
+                BREAK_IF (STATE_SUSPENDED != pcd_instance->bus->device_state);
+                udc_saw_bus_activity = 0;
+                usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_RESET, 0);
+                //usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_ADDRESS_ASSIGNED, 0);
+                break;
+        }
+        if (pcd_recv_setup_irq(pcd_instance, &request)) {
+                TRACE_MSG1(PCD, "ep0 STALL %d", cs);
+                au_writel(USBDEV_CS_STALL, USBD_EP0CS);
+                return;
+        }
+        if (((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) && le16_to_cpu (request.wLength)) {
+                TRACE_MSG1(PCD, "ep0 Class H2D request %04x", le16_to_cpu(request.wLength));
+                endpoint->state = DATA_STATE_RECV;
+                return;
+        }                               
+        if ((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
+                TRACE_MSG1(PCD, "ep0 Class H2D request %04x", le16_to_cpu(request.wLength));
+                if ((request.bmRequestType & ~USB_REQ_DIRECTION_MASK)) {
+                        TRACE_MSG1(PCD, "ep0 Class or Vendor, send ZLP %d", cs);
+                        send_zlp(0);
+                        return;
+                }
+        }
+        TRACE_MSG1(PCD, "ep0 Class D2H request %04x", le16_to_cpu(request.wLength));
+}
+/* ********************************************************************************************* */
+/* au_start_in_bulk - start transmit
+ * The au1x00 will start to send when the first byte is loaded into the FIFO, either by
+ * DMA or PIO. The packetsize must be set first.
+ */
+static void au_start_in_bulk (unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+        struct usbd_urb *urb = endpoint->tx_urb;
+        u8 *bp = urb->buffer + endpoint->sent;
+        int last;
+        int i;
+        u32 *lp;
+        TRACE_MSG1(PCD, "START IN BULK %d", epn);
+        RETURN_IF (!urb || (( (urb->actual_length - endpoint->sent) == 0) && !(urb->flags & USBD_URB_SENDZLP)));
+        last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
+        TRACE_MSG2(PCD, "START IN BULK sent: %d last:%d", endpoint->sent, last);
+        au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // XXX
+        if (!last) {
+                if (endpoint->tx_urb->flags & USBD_URB_SENDZLP) {
+                        TRACE_MSG0(PCD, "START IN BULK - zending ZLP");
+                        send_zlp(epn);
+                        endpoint->tx_urb->flags &= ~USBD_URB_SENDZLP;
+                }
+                return;
+        }
+        else if (8 >= last) {
+                au_writel(last << 1, ep->cs);
+                au_fifo_write(epn, bp, last);
+                return;
+        }
+
+        dma_cache_wback_inv((unsigned long) bp, last); 
+        //au_writel(last << 1, ep->cs);
+        au_start_dma_in(ep->indma, ep->tx_id, bp, last);
+        au_writel(last << 1, ep->cs);
+}
+
+static void au_in_bulk(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *tx_urb;
+        int rc = 0;
+        u32 cs = au_readl(ep->cs);
+        u32 wrs = au_readl(ep->wrs);
+        u32 residue = au1xxx_get_dma_residue(ep->indma);
+        TRACE_MSG3(PCD, "BULK IN EPN - cs: %x wrs: %x residue:%d", cs, wrs, residue);
+        if (wrs) {                                                              // check for underflow or overflow
+                rc = 1;
+                if (wrs & USBDEV_FSTAT_UF) {
+                        TRACE_MSG2(PCD, "BULK IN EPN - UF epn %d wrs: %x", epn, wrs);
+                        rc = 1;                                                 // set rc to indicate an error
+                }
+                if (wrs & USBDEV_FSTAT_OF) 
+                        TRACE_MSG2(PCD, "BULK IN EPN - OF epn %d wrs: %x", epn, wrs);
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs);     // flush the fifo 
+        }
+        if (cs & USBDEV_CS_NAK) {
+                RETURN_IF (ep->last && ((wrs&0x1f) == ep->last));
+                rc = 1;
+        }
+        if (cs & USBDEV_CS_STALL) {                                             // clear stall if present
+                TRACE_MSG1(PCD, "BULK IN EPN - CLEAR STALL %d", epn);
+                cs &= ~USBDEV_CS_STALL;
+                au_writel(cs, ep->cs);
+                return;
+        }
+        TRACE_MSG4(PCD, "BULK IN EPN epn: %d rc: %d last: %d sent: %d", epn, rc, endpoint->last, endpoint->sent);
+
+        if ((tx_urb = pcd_tx_complete_irq(endpoint, rc))) {
+                if ((tx_urb->actual_length > endpoint->sent) || (endpoint->tx_urb->flags & USBD_URB_SENDZLP)) {
+                        au_start_in_bulk(epl2p[endpoint->bEndpointAddress&0xf], endpoint, ep);
+                        TRACE_MSG1(PCD, "BULK IN EPN - LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
+                        return;
+                }
+        }
+        au_epn_interrupt_disable(epn);                                         // disable interrupts
+}
+
+/* au_start_in_iso - start transmit
+ * The au1x00 will start to send when the first byte is loaded into the FIFO, either by DMA or
+ * PIO. The packetsize must be set first.
+ */
+static void au_start_in_iso (unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+        struct usbd_urb *urb = endpoint->tx_urb;
+        unsigned char *bp = urb->buffer + endpoint->sent;
+        int last;
+        TRACE_MSG2(PCD, "START IN ISO actual: %d sent: %d", urb->actual_length, endpoint->sent);
+        RETURN_IF ((urb->actual_length - endpoint->sent) == 0);
+        last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
+        TRACE_MSG2(PCD, "START IN ISO last: %d packetSize: %d", last, endpoint->wMaxPacketSize);
+        au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // XXX
+        au_epn_interrupt_enable (epn);
+        dma_cache_wback_inv((unsigned long) bp, last);
+        au_writel(last << 1, ep->cs);
+        au_start_dma_in(ep->indma, ep->tx_id, bp, last);
+}
+
+static void au_in_iso(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *tx_urb = pcd_tx_complete_irq(endpoint, 0);
+        u32 cs = au_readl(ep->cs);
+        u32 wrs = au_readl(ep->wrs);
+        TRACE_MSG2(PCD, "ISO IN EPN - cs: %x wrs: %x", cs, wrs);
+        TRACE_MSG4(PCD, "ISO IN EPN epn: %d last: %d sent: %d", epn, endpoint->last, endpoint->sent, 0);
+        ep->last = 0;
+        if ((tx_urb = endpoint->tx_urb) && (tx_urb->actual_length > endpoint->sent)) {
+                au_start_in_iso(epl2p[endpoint->bEndpointAddress&0xf], endpoint, ep);
+                /* XXX magic delay - without this large packets will eventually stall the transmit
+                 * XXX and all traffic in both directions will stop. 
+                 */
+                TRACE_MSG1(PCD, "ISO IN EPN - LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
+                return;
+        }
+
+        TRACE_MSG0(PCD, "ISO IN EPN - nothing to send");
+        au_epn_interrupt_disable(epn);                                 // disable interrupts
+}
+/* ********************************************************************************************* */
+
+static struct usbd_urb *au_rcv_complete_epn_irq(struct usbd_endpoint_instance *endpoint, int len, int urb_bad)
+{
+        return pcd_rcv_complete_irq(endpoint, len, urb_bad);
+}
+
+
+static void au_start_out_bulk(unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+        TRACE_MSG2(PCD, "START OUT BULK %d actual: %d pcktSize: %d", epn, endpoint->wMaxPacketSize);
+        if (!endpoint->rcv_urb) {
+                TRACE_MSG0(PCD, "START OUT BULK DISABLE");
+                au_epn_interrupt_disable(epn);
+                return;
+        }
+        if (endpoint->rcv_error) {
+                TRACE_MSG0(PCD, "START OUT BULK reseting rcv_error");
+                endpoint->rcv_error = 0;
+        }
+        au_start_dma_out(ep->outdma, ep->rx_id, 
+                        endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length, endpoint->wMaxPacketSize);
+}
+
+static void au_out_bulk(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
+{
+        int bytes = 0;
+        int residue = 0;
+        u32 *lp = NULL;
+
+        struct usbd_urb *urb;
+        struct usbd_urb *completed_urb = NULL;
+        u32 cs;
+        u32 rds;
+        u32 nrds;
+        int i;
+
+        cs = au_readl(ep->cs);
+        rds = au_readl(ep->rds);
+
+        // XXX it appears that this is zero if 64 bytes where received!!!
+        
+        // get dest ring buffer
+        au1xxx_dbdma_get_dest(ep->outdma, (void **)&lp, &bytes);
+
+        au_halt_dma(ep->outdma);
+        residue = endpoint->wMaxPacketSize - au1xxx_get_dma_residue(ep->outdma);
+
+        TRACE_MSG5(PCD, "BULK OUT CS: %04x RD: %04x bytes: %d residue: %d DMA %s", 
+                        cs, rds, bytes, residue, lp ? "FINISHED" : "ACTIVE");
+
+        /* check for NAK
+         */
+        if (cs & USBDEV_CS_NAK) {
+                TRACE_MSG0(PCD, "NAK bytes: 0");
+                bytes = 0;
+        }
+
+        /* with dbdma residue will either be zero or non-zero and less than packetsize, if
+         * zero then a complete transfer of packetsize was performed.
+         */
+        else if (!residue && !rds) {
+                TRACE_MSG0(PCD, "BULK OUT CS: forcing bytes: 64");
+                bytes = endpoint->wMaxPacketSize;
+        }
+        else {
+                TRACE_MSG0(PCD, "BULK OUT CS: using residue bytes: 64");
+                bytes = residue;
+        }
+
+
+        if (!(urb = pcd_rcv_next_irq(endpoint))) {
+                TRACE_MSG0(PCD, "BULK OUT EPN - no rcv_urb");
+                au_epn_interrupt_disable(epn);
+                return;
+        }
+
+        TRACE_MSG4(PCD, "BULK OUT CS: %04x RD: %04x actual: %d DMA bytes: %d", cs, rds, urb->actual_length, bytes);
+
+        if (bytes)
+                dma_cache_inv((u32) urb->buffer + urb->actual_length, bytes);
+
+        /* The original AU1X00 UDC design will continue to receive data as long as there is room
+         * in the FIFO. We cannot tell when we are at the end of a packet and/or have the start
+         * of a new one.
+         *
+         * There are only two scenarios that are guaranteed (almost) to be correct:
+         *
+         *      64 bytes of data from DMA, empty fifo, continue Bulk OUT < 60 bytes of data and
+         *      < 4 bytes in fifo, end Bulk OUT.
+         *
+         * There may be a third scenario that is ok:
+         *
+         *      0 bytes dma, 0 bytes in fifo, NAK
+         *
+         * Everything else is an error. In all cases we assume that it is safer to drop data
+         * than to accept it in error. This allows CRC or size protected encapsulations to
+         * notice bulk transfers received with errors.
+         *
+         * In general none of the policies or strategies are able to cope with all errors
+         * without missing errors and dropping good data.  The intent is to minimize the amount
+         * of potentially bad data getting to the function driver while minimizing the amount of
+         * good data that is dropped.
+         *
+         * The new silicon mitigates this problem for non control endpoints because it will NAK
+         * additional data until the interrupt service flag is reset.
+         * 
+         * Start with generic error tests, OF, UF or NAK indicate an error we cannot recover
+         * from, start flushing until end of current bulk transfer (wait for a short packet)
+         *
+         * XXX The following needs to be tested and streamlined for au1550, much of the extra
+         * testing done for older silicon cab probably be eliminated. For example the extra read 
+         * of nrds to check for overrun in the FIFO should not be required.
+         *
+         */
+        if (rds & (USBDEV_FSTAT_OF | USBDEV_FSTAT_UF)) {
+                TRACE_MSG2(PCD, "BULK OUT FLUSHING %d length: %d", bytes, urb->actual_length);
+                THROW(start_flushing);
+        }
+        rds = rds & USBDEV_FSTAT_FCNT_MASK;
+        nrds = au_readl(ep->rds);
+
+        /* full size packet received, check that we are not flushing and that the FIFO
+         * does not have any data. If there is data in the FIFO we may not be able to
+         * restart DMA in time, so start flushing 
+         */
+        if (endpoint->wMaxPacketSize == bytes) {
+                TRACE_MSG2(PCD, "BULK OUT 64 BYTES %d length: %d", bytes, urb->actual_length);
+                if (endpoint->rcv_error) {
+                        TRACE_MSG4(PCD, "FULL PACKET bytes: %d rds: %d nrds: %d cp0: %d CONTINUE FLUSHING", 
+                                        bytes, rds, nrds, cp0_count);
+                        THROW(start_flushing);
+                }
+                if ((nrds > 6)  && (nrds < 8) ) {
+                        TRACE_MSG4(PCD, "FIFO not empty bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING nrds > 6 < 8", 
+                                        bytes, rds, nrds, cp0_count);
+                        THROW(start_flushing);
+                }
+                if (!urb->actual_length) 
+                        TRACE_MSG4(PCD, "PACKET ok bytes: %d rds: %d nrds: %d cp0: %d ACCEPTING 64 bytes", 
+                                        bytes, rds, nrds, cp0_count);
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+                au_rcv_complete_epn_irq(endpoint, endpoint->wMaxPacketSize, 0);
+                if (cs & USBDEV_CS_NAK) 
+                        if (nrds && (nrds < 8) ) {
+                                TRACE_MSG4(PCD, "NAK bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING CS_NAK", 
+                                                bytes, rds, nrds, cp0_count);
+                                THROW(start_flushing);
+                        }
+        }
+        /* a nak'd packet may be ok to ignore IFF the FIFO is empty(?) or completely full.
+         */
+        else if ((cs & USBDEV_CS_NAK) && (!nrds || (nrds == 8)) ) {
+                TRACE_MSG2(PCD, "BULK OUT  NAK BYTES %d length: %d", bytes, urb->actual_length);
+                if (endpoint->rcv_error) {
+                        TRACE_MSG4(PCD, "NAK bytes: %d rds: %d nrds: %d cp0: %d CONTINUE FLUSHING", 
+                                        bytes, rds, nrds, cp0_count);
+                        THROW(start_flushing);
+                }
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+        }
+        /* short packet by DMA, additional data for this packet in FIFO, more than 3
+         * bytes is probably an error.
+         */
+        else {
+                TRACE_MSG2(PCD, "BULK OUT < 64 BYTES %d length: %d", bytes, urb->actual_length);
+                if ((cs & USBDEV_CS_NAK) && nrds && (nrds < 8) ) {
+                        TRACE_MSG4(PCD, "BULK OUT NAK bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING", 
+                                        bytes, rds, nrds, cp0_count);
+                        THROW(start_flushing);
+                }
+                if (nrds > 4) {
+                        TRACE_MSG4(PCD, "BULK OUT SHORT PACKET by DMA full FIFO bytes: %d rds: %d nrds: %d cp0: %d START FLUSH", 
+                                        bytes, rds, nrds, cp0_count);
+                        THROW(start_flushing);
+                }
+                TRACE_MSG4(PCD, "BULK OUT SHORT bytes: %d rds: %d nrds: %d cp0: %d reading fifo", bytes, rds, nrds, cp0_count);
+                au_fifo_read(ep, urb->buffer + urb->actual_length + bytes, nrds);
+                bytes += nrds;
+                TRACE_MSG1(PCD, "BULK OUT < 64 BYTES %d", bytes);
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+                if (!endpoint->rcv_error) {
+                        TRACE_MSG0(PCD, "BULK OUT COMPLETED URB");
+                        au_rcv_complete_epn_irq(endpoint, bytes, 0);
+                }
+                else {
+                        TRACE_MSG0(PCD, "BULK OUT - FLUSHING URB - reseting rcv_error");
+                        endpoint->rcv_error = 0;
+                }
+        }
+        CATCH(start_flushing) {
+                TRACE_MSG0(PCD, "BULK OUT - START FLUSHING URB");
+                endpoint->rcv_error = 1;
+                endpoint->rcv_urb->actual_length = 0;
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+                bytes = 0;
+        }
+        TRACE_MSG0(PCD, "BULK OUT - RESTARTING");
+        au_start_out_bulk(epn, endpoint, ep);
+}
+
+static void au_start_out_iso(unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+        RETURN_IF(!endpoint->rcv_urb);
+        au_start_dma_out(ep->outdma, ep->rx_id, 
+                        endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length, endpoint->wMaxPacketSize);
+}
+
+static void au_out_iso(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
+{
+        int bytes = 0;
+        struct usbd_urb *urb;
+        u32 cs;
+        u32 rds;
+        au_halt_dma(ep->outdma);
+        cs = au_readl(ep->cs);
+        rds = au_readl(ep->rds);
+        if (!endpoint) {
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+                return;
+        }
+        if (!(urb = endpoint->rcv_urb)) {
+                TRACE_MSG2(PCD, "ISO OUT EPN - rcv_urb was NULL bytes: %d rds: %d", bytes, rds);
+                au_rcv_complete_epn_irq(endpoint, bytes, 1);
+                TRACE_MSG0(PCD, "ISO OUT setting rcv_error");
+        }
+        bytes = endpoint->wMaxPacketSize - au1xxx_get_dma_residue(ep->outdma);
+        rds = rds & USBDEV_FSTAT_FCNT_MASK;
+        au_fifo_read(ep, urb->buffer + urb->actual_length + bytes, rds);
+        bytes += rds;
+        au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+        au_rcv_complete_epn_irq(endpoint, bytes, 0);
+        au_start_out_iso(epn, endpoint, ep);
+}
+/* ********************************************************************************************* */
+/* au_tx_dma_done - TX DMA interrupt handler
+ */
+static void au_tx_dma_done(int irq, void *dev_id, struct pt_regs *regs)
+{
+        int epn = (int) dev_id;
+        struct usbd_endpoint_instance *endpoint = pcd_instance->bus->endpoint_array + epn;
+        struct ep_regs *ep = &ep_regs[epn];
+        int residue;
+        ocd_ops.interrupts++;
+        RETURN_IF (!epn);
+        au_halt_dma(ep->indma);
+        ep->last = 0;
+}
+
+/* au_int_req - usb interrupt handler
+ */
+static void au_int_req (int irq, void *dev_id, struct pt_regs *regs)
+{
+        u32 intstat;
+        struct ep_regs *ep;
+#if defined(MAX_INTR_LOOP_STATS)
+        u32 loopcount = 0;
+#endif
+#ifdef  RECORD_LATENCY
+        cp0_count = (read_c0_count(CP0_COUNT) - cp0_record) >> 9;
+        if (cp0_count < CP0_COUNTS) 
+                cp0_counts[cp0_count]++;
+#endif
+#ifdef  CHECK_LATENCY
+        u32 cp0_count = read_c0_count(CP0_COUNT);
+#endif
+        ocd_ops.interrupts++;
+        TRACE_MSG2(PCD, "INT - device: %d status: %d", pcd_instance->bus->device_state, pcd_instance->bus->status);
+#if 0
+        if (ocd_ops.interrupts > 2000) {
+                TRACE_MSG0(PCD, "UDC_INT call udc_disable_interrupts");
+                au_inten(0, "DISABLING");
+                return;
+        }
+#endif
+        while (( intstat = au_readl(USBD_INTSTAT) & au1x00_inten)) {    // read and reset interrupt status register
+
+                int epn;
+#if 1                
+                for (epn = 2; epn < 6; epn++) {
+                        CONTINUE_IF (!(intstat & (1 << epn)));
+#else
+                // NOT TESTED
+                u32 local_intstat = intstat;
+                TRACE_MSG2(PCD, "INTSTAT: %04x %04x", intstat, au_readl(USBD_INTEN));
+                while (local_intstat & 0x3f) {
+                        int epn = 31 - au_clz(local_intstat);
+                        local_intstat &= ~(1<<epn);
+#endif
+                        if (udc_saw_bus_activity) {
+                                udc_saw_bus_activity = 0;
+                                usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_BUS_ACTIVITY, 0);
+                                au_inten(0x0033/*|USBDEV_INT_SOF*/, "int SOF");                    
+                        }
+                        ep = &ep_regs[epn];
+                        switch(ep->eptype) {
+                        case USB_DIR_IN | USB_ENDPOINT_BULK:
+                        case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
+                                //TRACE_MSG2(PCD, "BULK IN %d %02x", epn, ep->eptype);
+                                au_in_bulk(epn, ep, pcd_instance->bus->endpoint_array + epn);
+                                break;
+                        case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
+                                //TRACE_MSG2(PCD, "ISO IN %d %02x", epn, ep->eptype);
+                                au_in_iso(epn, ep, pcd_instance->bus->endpoint_array + epn);
+                                break;
+                        case USB_DIR_OUT | USB_ENDPOINT_BULK:
+                        case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
+                                //TRACE_MSG2(PCD, "BULK OUT %d %02x", epn, ep->eptype);
+                                au_out_bulk(epn, ep, pcd_instance->bus->endpoint_array + epn);
+                                break;
+                        case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
+                                //TRACE_MSG2(PCD, "ISO OUT %d %04d", epn, au_readl(NUSBD_FRAMENUM));
+                                au_out_iso(epn, ep, pcd_instance->bus->endpoint_array + epn);
+                                break;
+                        }
+                }
+                au_writel(intstat, USBD_INTSTAT);               // Only clear the interrupt(s) AFTER servicing OUT
+                /* even though we disable the bulk-in interrupt (endpoint 2) prior to enabling
+                 * DMA we always see one additional interrupt that is a NAK on that endpoint.
+                 */
+                CONTINUE_IF(!(intstat & au1x00_inten));
+                /* handle control endpoint and suspend interrupt
+                 */
+                if (intstat & ( ((1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | USBDEV_INT_SOF))) {
+                        if (intstat & (1 << 0)) 
+                                au_out_ep0(pcd_instance->bus->endpoint_array + 0, &ep_regs[0]);
+                        if (intstat & (1 << 1)) 
+                                au_in_ep0(pcd_instance->bus->endpoint_array + 0, &ep_regs[0]);
+                        if (intstat & USBDEV_INT_SOF) 
+                                if (USBD_SUSPENDED == pcd_instance->bus->status) {
+                                        TRACE_MSG0(PCD, "SUS - ACTIVITY");
+                                        udc_saw_bus_activity++;
+                                }
+                }
+#if defined(MAX_INTR_LOOP_STATS)
+                loopcount += 1;                         // Gather stats on how many times this loop is performed. 
+#endif
+        }
+#if defined(MAX_INTR_LOOP_STATS)
+        interrupt_loop_stats[MIN(loopcount, MAX_INTR_LOOP_STATS)]++;
+#endif
+#if defined(CHECK_LATENCY)
+        TRACE_MSG1(PCD, "USB IRQ - %d", read_c0_count(CP0_COUNT) - cp0_count);
+#endif
+#if defined(RECORD_LATENCY)
+        cp0_record = read_c0_count(CP0_COUNT);
+#endif
+}
+
+/* au_int_sus -suspend interrupt handler
+ */
+static void au_int_sus (int irq, void *dev_id, struct pt_regs *regs)
+{
+        ocd_ops.interrupts++;
+        TRACE_MSG2(PCD, "SUS - INACTIVE device: %d status: %d", pcd_instance->bus->device_state, pcd_instance->bus->status);
+        switch(pcd_instance->bus->status) {
+        case USBD_OPENING:
+        case USBD_OK:
+                au_inten(0x0033, "suspend");
+                usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_BUS_INACTIVE, 0);
+                break;
+        default:
+                break;
+        }
+}
+/* ********************************************************************************************* */
+/* 
+ * au_connect - enable pullup resistor
+ * Turn on the USB connection by enabling the pullup resistor.
+ *
+ * au_disconnect - disable pullup resistor
+ * Turn off the USB connection by disabling the pullup resistor.
+ */
+
+#if defined(CONFIG_MIPS_FREEHAND_NATIVE)
+#warning "Old code for Freehand"
+void au_connect (struct pcd_instance *pcd)
+{
+        au1000gpio_set(GPIO01);
+}
+
+void au_disconnect (struct pcd_instance *pcd)
+{               
+        au1000gpio_clear(GPIO01);
+}
+#elif defined(CONFIG_AMX_MORDOR)
+void au_connect (struct pcd_instance *pcd)
+{
+        au_writel(0x00000008, SYS_OUTPUTSET);
+}
+
+void au_disconnect (struct pcd_instance *pcd)
+{               
+        au_writel(0x00000008, SYS_OUTPUTCLR);
+}
+#elif defined(CONFIG_MIPS_DB1550) || defined(CONFIG_MIPS_MTX2)
+void au_connect (struct pcd_instance *pcd)
+{
+	au_writel(au_readl(GPIO2_DIR) | 0x100, GPIO2_DIR);
+	au_writel(0x01000100, GPIO2_OUTPUT);
+	au_sync();
+}
+void au_disconnect (struct pcd_instance *pcd)
+{
+	au_writel(au_readl(GPIO2_DIR) | 0x100, GPIO2_DIR);
+	au_writel(0x01000000, GPIO2_OUTPUT);
+	au_sync();
+}
+#else
+#warning "Please define au_connect / au_disconnect"
+void au_connect (struct pcd_instance *pcd)
+{
+}
+void au_disconnect (struct pcd_instance *pcd)
+{
+}
+#endif
+
+#undef read_c0_COUNT
+#ifndef read_c0_count
+#define read_c0_count()  read_32bit_cp0_register(CP0_COUNT)
+#endif
+/* ********************************************************************************************* */
+/* au_ticks - get current ticks
+* */
+u64 au_ticks (void)
+{       
+        return read_c0_count();
+}       
+
+/* au_elapsed - return micro-seconds between two tick values
+ */
+u64 au_elapsed(u64 *t1, u64 *t2)
+{
+        u64 ticks = (*t1 > *t2) ? (*t1 - *t2) : (*t2 - *t1);
+        ticks = (u32)((u32) ticks / (u32) CONFIG_OTG_AU1X00_SCLOCK);
+        return ticks;
+}
+
+/* au_framenum - get current framenum
+ */             
+u16 au_framenum (void)
+{               
+        return au_readl(NUSBD_FRAMENUM);
+}               
+
+
+/* ********************************************************************************************* */
+/* au_start_endpoint_in - start transmit
+ */
+void au_start_endpoint_in(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
+{
+        int epn = epl2p[endpoint->bEndpointAddress&0xf];
+        struct ep_regs *ep = &ep_regs[epn];
+        switch(endpoint->bmAttributes & USB_ENDPOINT_MASK) {
+        case USB_ENDPOINT_CONTROL:
+                au_in_ep0(endpoint, ep);
+                break;
+        case USB_ENDPOINT_BULK:
+        case USB_ENDPOINT_INTERRUPT:
+                au_start_in_bulk(epn, endpoint, ep);
+                break;
+        case USB_ENDPOINT_ISOCHRONOUS:
+                au_start_in_iso(epn, endpoint, ep);
+                break;
+        }
+        au_epn_interrupt_enable(epn);
+}
+
+/* au_start_endpoint_out - start receive
+ */
+void au_start_endpoint_out(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
+{
+        int epn = epl2p[endpoint->bEndpointAddress&0xf];
+        struct ep_regs *ep = &ep_regs[epn];
+        switch(endpoint->bmAttributes & USB_ENDPOINT_MASK) {
+        case USB_ENDPOINT_CONTROL:
+                break;
+        case USB_ENDPOINT_BULK:
+        case USB_ENDPOINT_INTERRUPT:
+                au_start_out_bulk(epn, endpoint, ep);
+                au_epn_interrupt_enable(epn);
+                break;
+        case USB_ENDPOINT_ISOCHRONOUS:
+                au_start_out_iso(epn, endpoint, ep);
+                break;
+        }
+}
+
+/* 
+ * au_pcd_endpoint_halted() - is endpoint halted
+ */
+static int
+au_pcd_endpoint_halted (struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
+{
+int cs;
+        int epn = epl2p[endpoint->bEndpointAddress&0xf];
+        int dir = (endpoint->bEndpointAddress & 0x80) ? 1 : 0;
+        struct ep_regs *ep = &ep_regs[epn];
+
+        TRACE_MSG2(PCD, "epn: %02x dir: %x", epn, dir);
+        return ((cs = au_readl(ep->cs)) & USBDEV_CS_STALL) ? TRUE : FALSE;
+}
+
+/* au_pcd_halt_endpoint - halt endpoint
+ */     
+int au_pcd_halt_endpoint(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint, int flag)
+{
+        int epn = epl2p[endpoint->bEndpointAddress&0xf];
+        int dir = (endpoint->bEndpointAddress & 0x80) ? 1 : 0;
+        struct ep_regs *ep = &ep_regs[epn];
+
+        TRACE_MSG3(PCD, "epn: %02x dir: %x flag: %d", epn, dir, flag);
+
+        au_writel(au_readl(ep->cs) & USBDEV_CS_STALL, ep->cs);
+        return 0;
+}       
+
+
+
+void au_cancel_in_irq(struct pcd_instance *pcd, struct usbd_urb *urb)
+{
+        int epn = epl2p[urb->endpoint->bEndpointAddress&0xf];
+        struct ep_regs *ep = &ep_regs[epn];
+        au_in_bulk(epn, ep, urb->endpoint);
+}
+
+void au_cancel_out_irq(struct pcd_instance *pcd, struct usbd_urb *urb)
+{
+        int epn = epl2p[urb->endpoint->bEndpointAddress&0xf];
+        struct ep_regs *ep = &ep_regs[epn];
+        au_out_bulk(epn, ep, urb->endpoint);
+}
+
+/* au_serial_init - set a serial number if available
+ */
+int au_serial_init (struct pcd_instance *pcd)
+{
+#if defined(CONFIG_MIPS_FREEHAND)
+        int length;
+        long data[16];          /* yeah a hack, but we KNOW it's 16 */
+        struct i2c_client *client;
+        char chData[16];
+        int i;
+
+        if (!(client = getFreeHandEepromClient())) {
+                printk(KERN_INFO"eeprom not ready when au_serial_init called\n");
+                return -EINVAL;
+        }
+        eeprom_contents(client, SENSORS_PROC_REAL_READ, EEPROM_SYSCTL1, &length, (long *)data);
+
+        /* serial number is first 9 longs. But each long is just an ASCII char
+         * convert this to a string and then extract a 4 byte value from it
+         */
+        for (i = 0; i < 9; chData[i] = (char)data[i], i++);     /* trunc, is ok */
+        chData[9] = 0;                                          /* terminate string */
+        printk(KERN_INFO"%s: %s\n", __FUNCTION__, chData);
+        pcd_instance->bus->serial_number_str = lstrdup(chData);
+        return 0;
+#else
+        return -EINVAL;
+#endif
+}
+
+
+/* au_start - start session
+ */
+void au_start (struct pcd_instance *pcd)
+{
+        au_inten(0x0033/*|USBDEV_INT_SOF*/, "START");                                // Only enable receive interrupts. 
+}
+
+/* au_stop - stop session
+ */
+void au_stop (struct pcd_instance *pcd)
+{
+        //au_inten(0, "STOP");
+}
+
+int au_assign_endpoint( u8 physicalEndpoint, int used[6], struct usbd_endpoint_map *endpoint_map, u8 bmAttributes,
+                u16 wMaxPacketSize, u16 transferSize) 
+{
+        struct ep_regs *ep = &ep_regs[physicalEndpoint]; 
+        RETURN_EINVAL_IF(used[physicalEndpoint]);
+        endpoint_map->bEndpointAddress[0] = epp2l[physicalEndpoint];
+        endpoint_map->physicalEndpoint[0] = physicalEndpoint;
+        endpoint_map->wMaxPacketSize[0] = wMaxPacketSize;
+        endpoint_map->transferSize[0] = transferSize;
+        endpoint_map->bmAttributes[0] = bmAttributes;
+        used[physicalEndpoint]++;
+        ep->eptype = bmAttributes & 0x83;
+        return 0;
+}
+
+int au_request_endpoints(struct pcd_instance *pcd, struct usbd_endpoint_map *endpoint_map_array, int endpointsRequested, 
+                struct usbd_endpoint_request *requestedEndpoints)
+{
+        struct usbd_device_description *device_description;
+        int i, j;
+        int used[UDC_MAX_ENDPOINTS];
+        memset(used, 0, sizeof(used));
+        for (j = 0, i = 0; i < endpointsRequested; i++, j++) {
+                struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
+                u8 bmAttributes = requestedEndpoints[i].bmAttributes;
+                u16 transferSize = requestedEndpoints[i].fs_requestedTransferSize;
+                RETURN_EINVAL_UNLESS(j < UDC_MAX_ENDPOINTS);
+                switch(bmAttributes) {
+                case USB_DIR_OUT | USB_ENDPOINT_BULK:
+                case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
+                case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
+                        CONTINUE_IF(!au_assign_endpoint(4, used, endpoint_map, bmAttributes, 0x40, transferSize));
+                        CONTINUE_IF(!au_assign_endpoint(5, used, endpoint_map, bmAttributes, 0x40, transferSize));
+                        break;
+                case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
+                        CONTINUE_IF(!au_assign_endpoint(4, used, endpoint_map, bmAttributes, transferSize, transferSize));
+                        CONTINUE_IF(!au_assign_endpoint(5, used, endpoint_map, bmAttributes, transferSize, transferSize));
+                        break;
+                case USB_DIR_IN | USB_ENDPOINT_BULK:
+                case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
+                case USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
+                        CONTINUE_IF(!au_assign_endpoint(2, used, endpoint_map, bmAttributes, 0x40, transferSize));
+                        CONTINUE_IF(!au_assign_endpoint(3, used, endpoint_map, bmAttributes, 0x40, transferSize));
+                        break;
+                case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
+                        CONTINUE_IF(!au_assign_endpoint(2, used, endpoint_map, bmAttributes, transferSize, transferSize));
+                        CONTINUE_IF(!au_assign_endpoint(3, used, endpoint_map, bmAttributes, transferSize, transferSize));
+                        break;
+                }
+                CONTINUE_IF(bmAttributes & USB_ENDPOINT_OPT);
+                return -EINVAL;
+        }
+        return 0;
+}
+
+struct usbd_endpoint_map *au_endpoint_map_array;
+int au_endpointsRequested;
+
+int au_set_endpoints2(struct pcd_instance *pcd, int endpointsRequested, struct usbd_endpoint_map *endpoint_map_array);
+int au_set_endpoints(struct pcd_instance *pcd, int endpointsRequested, struct usbd_endpoint_map *endpoint_map_array)
+{
+	au_endpointsRequested = endpointsRequested;
+	au_endpoint_map_array = endpoint_map_array;
+	return au_set_endpoints2(pcd, au_endpointsRequested, au_endpoint_map_array);
+}
+
+int au_set_endpoints2(struct pcd_instance *pcd, int endpointsRequested, struct usbd_endpoint_map *endpoint_map_array)
+{
+        int i, j;
+        u8 config[25];
+        u8 *cp;
+        memcpy(config, au1x00_config_bulk, sizeof(config));
+        for (i = 0; i < endpointsRequested; i++) {
+                struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
+                int epreq = endpoint_map->bmAttributes[0];
+                int eptype = epreq & USB_ENDPOINT_MASK;
+                int epdir = epreq & USB_ENDPOINT_DIR_MASK ? 0x8 : 0;
+                int epsize = endpoint_map->wMaxPacketSize[0];
+                int epaddr = epp2l[endpoint_map->physicalEndpoint[0]];
+                CONTINUE_IF(!endpoint_map->physicalEndpoint[0] || (endpoint_map->physicalEndpoint[0] > 5));
+                cp = config + ((endpoint_map->physicalEndpoint[0] - 1) * 5);
+                cp[0] = (epaddr & 0xf) << 4 | 0x4;
+                cp[1] = (eptype << 4) | epdir | (epsize & 0x380) >> 7;
+                cp[2] = (epsize & 0x7F) << 1;
+        } 
+        TRACE_MSG0(PCD, "Disable interrupts");
+        au_inten(0, "SET ENDPOINTS");                                                            // disable interrupts
+        au_writel(0x0002, USBD_ENABLE);                                         // reset controller
+        udelay(100);
+        au_writel(0x0003, USBD_ENABLE);                                         // enable controller
+        udelay(100);
+        for (cp = config, i = 0; i < 25; i++, au_writel(*cp++, USBD_CONFIG));   // feed the config into the UDC
+        return 0;
+}
+
+/* au_loc_conn - used to enable or disable peripheral connecting to bus
+ *
+ */
+void au_loc_conn(struct otg_instance *otg, u8 flag)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)otg->pcd;
+        TRACE_MSG0(PCD, "--");
+        TRACE_MSG1(PCD, "PCD: %x", (int)pcd);
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_SET - Enable DP PULLUP");
+		au_set_endpoints2(pcd, au_endpointsRequested, au_endpoint_map_array);
+		au_inten(0x0033/*|USBDEV_INT_SOF*/, "START");                    // Only enable receive interrupts. 
+                au_connect(pcd);
+                break;
+
+        case RESET:
+                TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_RESET - Disable DP PULLUP");
+                au_disconnect(pcd);
+		au_inten(0, "RESET ENDPOINTS");                                         // disable interrupts
+		au_writel(0x0000, USBD_ENABLE);                                         // reset controller
+                break;
+        }
+}
+
+
+/* ********************************************************************************************* */
+
+
+static u32 request_dma(int ep, int src, int dest, char *str, void dma_done(int , void *, struct pt_regs *))
+{
+        u32 dma;
+        
+        chan_tab_t              *ctp;
+        volatile au1x_dma_chan_t *cp;
+        au1x_ddma_desc_t        *dp;
+
+
+	if ((dma = au1xxx_dbdma_chan_alloc(src, dest, dma_done, (void *)ep)) < 0) {
+                printk(KERN_INFO"request_io[%d] dma: %x src: %d dest: %d %s FAILED\n", ep, dma, src, dest, str);
+                return -1;
+        }
+
+        if(au1xxx_dbdma_ring_alloc(dma, 1) == 0) {
+                printk(KERN_INFO"request_io[%d] Ring Buffer Allocation for  dma: %x src: %d dest: %d %s FAILED\n", 
+                                ep, dma, src, dest, str);
+                return -1;
+	}
+
+        ctp = *((chan_tab_t **)dma);
+        cp = ctp->chan_ptr;;
+        dp = ctp->put_ptr; 
+        dp->dscr_cmd0 &= ~DSCR_CMD0_V;
+
+        TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %04x dst: %08x %08x DBDMA", 
+                        dma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
+                        dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
+
+#if 0
+        // XXX copy static components from au_start_out
+        // transmit - mem to usb
+        if (src == DBDMA_MEM_CHAN) {
+                TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %04x dst: %08x %08x MEM2USB", 
+                                dma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
+                                dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
+        }
+#endif
+#if 0
+        // XXX copy static components from au_start_in
+        // receive - usb to mem
+        if (dest == DBDMA_MEM_CHAN) {
+                TRACE_MSG8(PCD, "%08x %08x cmd: %08x %04x src: %08x %08x dst: %08x %08x USB2MEM", 
+                                dma, dp, dp->dscr_cmd0, dp->dscr_cmd1,
+                                dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
+        }
+#endif
+        TRACE_MSG5(PCD, "request_io[%d] dma: %x src: %d dest: %d %s SUCCEDED", ep, dma, src, dest, str);
+        return dma;
+}
+
+/* au_mod_init 
+ */
+int au_mod_init (void)
+{
+        int dev = request_irq (AU1000_USB_DEV_REQ_INT, au_int_req, SA_INTERRUPT, UDC_NAME "UDC Req", NULL);
+        int sus = request_irq (AU1000_USB_DEV_SUS_INT, au_int_sus, SA_INTERRUPT, UDC_NAME "UDC Sus", NULL);
+        u32 cp0_prid = read_c0_prid();
+        int i;
+
+
+        if (dev || sus) {                                               // check if either request irq failed
+                if (!dev) free_irq (AU1000_USB_DEV_REQ_INT, NULL);      // free irqs that might have
+                if (!sus) free_irq (AU1000_USB_DEV_SUS_INT, NULL);      // been successfully allocated
+                return -EINVAL;
+        }
+        for (i = 0; i < 6; i++) {
+                ep_regs[i].indma = ep_regs[i].tx_id ? 
+                        request_dma(i, DBDMA_MEM_CHAN, ep_regs[i].tx_id, ep_regs[i].tx_str, au_tx_dma_done) : -1;
+                ep_regs[i].outdma = ep_regs[i].rx_id ? 
+                        request_dma(i, ep_regs[i].rx_id, DBDMA_MEM_CHAN, ep_regs[i].rx_str, NULL) : -1;
+        }
+        switch (cp0_prid & CP0_PRID_SOC_MASK) {
+        case CP0_PRID_AU1000:
+        case CP0_PRID_AU1100:
+        case CP0_PRID_AU1500:
+                return -EINVAL;
+        case CP0_PRID_AU1550:
+                TRACE_MSG1(PCD, "AU1550 cp0_prid: %08x\n", cp0_prid);
+                printk(KERN_INFO"%s: AU1550 cp0_prid: %08x\n", __FUNCTION__, cp0_prid);
+                break;
+        default:
+                printk(KERN_INFO"%s: UNKNOWN CPU cp0_prid: %08x UNKNOWN UDC\n", __FUNCTION__, cp0_prid);
+                break;
+        }
+        return 0;
+}
+
+/* au_mod_exit  
+ */
+void au_mod_exit (void)
+{
+        int j;
+        au_writel(0x0000, USBD_ENABLE);
+        for (j = 0; j < 6; j++) {
+                struct ep_regs *ep = &ep_regs[j]; 
+                if (ep->indma != -1) {
+                        au1xxx_dbdma_chan_free(ep->indma);
+                        ep->indma = -1;
+                }
+                if (ep->outdma != -1) {
+                        au1xxx_dbdma_chan_free(ep->outdma);
+                        ep->outdma = -1;
+                }
+        }
+        free_irq (AU1000_USB_DEV_REQ_INT, NULL);
+        free_irq (AU1000_USB_DEV_SUS_INT, NULL);
+#if defined(MAX_INTR_LOOP_STATS)
+        {
+                u32 lc;
+                for (lc = 0; lc <= MAX_INTR_LOOP_STATS; lc++) 
+                        if (interrupt_loop_stats[lc]) 
+                                printk(KERN_ERR "%s: interrupt loopcount[%02u] %9u\n", __FUNCTION__, lc,interrupt_loop_stats[lc]);
+                printk(KERN_INFO"%s: halt_dma_expired: %d\n", __FUNCTION__, au_halt_dma_expired);
+        }
+#endif
+#ifdef RECORD_LATENCY
+        {
+                int i;
+                for (i = 0; i < CP0_COUNTS; i++) 
+                        if (cp0_counts[i]) 
+                                printk(KERN_INFO"%s: cp0_counts[%d] %d\n", __FUNCTION__, i, cp0_counts[i]);
+        }
+#endif
+}
+
+/* ********************************************************************************************* */
+struct usbd_pcd_ops usbd_pcd_ops = {
+        max_endpoints:  UDC_MAX_ENDPOINTS,
+        ep0_packetsize:  EP0_PACKETSIZE,
+        name:  UDC_NAME,
+        start: au_start,
+        stop: au_stop,
+        start_endpoint_in: au_start_endpoint_in,
+        start_endpoint_out: au_start_endpoint_out,
+        request_endpoints: au_request_endpoints,
+        set_endpoints: au_set_endpoints,
+        cancel_in_irq: au_cancel_in_irq,
+        cancel_out_irq: au_cancel_out_irq,
+        serial_init: au_serial_init,
+        halt_endpoint: au_pcd_halt_endpoint,
+        endpoint_halted: au_pcd_endpoint_halted,
+};
+
+struct pcd_ops pcd_ops = {
+        pcd_en_func: pcd_en_func,
+        mod_init: au_mod_init,
+        mod_exit: au_mod_exit,
+        framenum: au_framenum,
+};
+
+struct ocd_ops ocd_ops = {
+	#if defined(CONFIG_OTG_TR_AUTO)
+        capabilities: OCD_CAPABILITIES_TR | OCD_CAPABILITIES_AUTO,
+	#else 
+        capabilities: OCD_CAPABILITIES_TR,
+        #endif
+        ticks: au_ticks,
+        elapsed: au_elapsed,
+};
+
+struct tcd_ops tcd_ops = {
+	dp_pullup_func: au_loc_conn,
+};
+
diff -uNr linux/drivers/no-otg/ocd/au1x00/au1x00.c linux/drivers/otg/ocd/au1x00/au1x00.c
--- linux/drivers/no-otg/ocd/au1x00/au1x00.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/au1x00/au1x00.c	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,1293 @@
+/*
+ * otg/ocd/au1x00/au1x00.c -- USB Device Controller driver. 
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *
+ */
+/*!
+ * @file otg/ocd/au1x00/au1x00.c
+ * @brief AU1X00 Header
+ *
+ * This file contains the private defines and structures for the AU1X00  
+ * Drivers. 
+ *
+ * @ingroup AU1X00
+ */
+
+
+#include <otg/pcd-include.h>
+#include "au1x00.h"
+
+#include <asm/io.h>
+#include <asm/au1000.h>
+#include <asm/au1000_dma.h>
+
+#if defined(CONFIG_SOC_AU1550)
+#define DBDMA 
+#endif
+#ifdef DBDMA
+#warning "Using AU1XXX_DBMDA"
+#include <asm/au1xxx_dbdma.h>
+#else /* DBDMA */
+#warning "Using AU1X00_MDA"
+#endif /* DBDMA */
+
+#include <asm/mipsregs.h>
+
+
+#ifdef CONFIG_MIPS_FREEHAND
+#include <linux/i2c.h>
+#include <linux/sensors.h>      /* for reading serial number */
+#endif
+
+
+#undef CHECK_LATENCY
+#undef RECORD_LATENCY
+#undef MAX_INTR_LOOP_STATS   //10
+#if defined(MAX_INTR_LOOP_STATS)
+static u32 interrupt_loop_stats[MAX_INTR_LOOP_STATS+1];
+#endif
+#ifdef  RECORD_LATENCY
+#define CP0_COUNTS 50
+u32 cp0_counts[CP0_COUNTS];
+u32 cp0_record;
+#endif
+u32 cp0_count;
+unsigned int udc_saw_bus_activity;
+int au_halt_dma_expired;
+u32 au1x00_new_silicon;
+u32 au1x00_inten;
+
+u8 au1x00_config_bulk[25] = {
+        0x04, (USB_ENDPOINT_CONTROL << 4) | (EP0_PACKETSIZE & 0x380) >> 7,                            // 1
+        (EP0_PACKETSIZE & 0x7F) << 1, 0x00, 0x00,
+        0x24, (USB_ENDPOINT_BULK << 4) | USB_DIR_IN | (MAX_EPN_PACKET_SIZE & 0x380) >> 7,             // 6
+        (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x02, 
+        0x34, (USB_ENDPOINT_BULK << 4) | USB_DIR_IN | (MAX_EPN_PACKET_SIZE & 0x380) >> 7,             // 11
+        (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x03, 
+        0x44, (USB_ENDPOINT_BULK << 4) | USB_DIR_OUT | (MAX_EPN_PACKET_SIZE & 0x380) >> 7,            // 16
+        (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x04,
+        0x54, (USB_ENDPOINT_BULK << 4) | USB_DIR_OUT | (MAX_EPN_PACKET_SIZE & 0x380) >> 7,            // 21
+        (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x05,
+};
+
+/* ********************************************************************************************* */
+/* Note - The endpoints names are confusing. To simplify mapping of the interrupt request lines
+ * we use a numbering of the physical endpoints of 0-5, which also matches the fifo numbering
+ * (see the config block).
+ *
+ *   Physical  FIFO    Name    Direction   Logical
+ *      0       0       EP0     OUT         0
+ *      1       1       EP0     IN          0
+ *      2       2       EP1     IN          81
+ *      3       3       EP2     IN          82
+ *      4       4       EP3     OUT         3
+ *      5       5       EP4     OUT         4
+ *
+ * The ep_regs array maps a physical endpoint number to the registers required to access the udc
+ * for that endpoint. Note that ep0 is always accessed via 0.  The epl2p array maps the logical
+ * addresses back to the physical number.  The epp2l array maps the physical number to the
+ * logical endpoint address
+ */
+#ifdef DBDMA
+struct ep_regs ep_regs[6] = {
+
+        { rd: USBD_EP0RD, rds: USBD_EP0RDSTAT, /*rx_id: DMA_ID_USBDEV_EP0_RX,*/ cs: USBD_EP0CS, rx_str: "EP0 OUT RD",
+          wr: USBD_EP0WR, wrs: USBD_EP0WRSTAT, tx_id: DSCR_CMD0_USBDEV_TX0,                 tx_str: "EP0 IN WR",},
+
+        { rds: 0, wrs: 0, indma: -1, outdma: -1, },
+        { wr: NUSBD_EP1WR, wrs: NUSBD_EP1WRSTAT, tx_id: DSCR_CMD0_USBDEV_TX1, cs: NUSBD_EP1CS, tx_str: "EP1 IN WR",},
+        { wr: NUSBD_EP2WR, wrs: NUSBD_EP2WRSTAT, tx_id: DSCR_CMD0_USBDEV_TX2, cs: NUSBD_EP2CS, tx_str: "EP2 IN WR",},
+
+        { rd: NUSBD_EP3RD, rds: NUSBD_EP3RDSTAT, rx_id: DSCR_CMD0_USBDEV_RX3, cs: NUSBD_EP3CS, rx_str: "EP3 OUT RD",},
+        { rd: NUSBD_EP4RD, rds: NUSBD_EP4RDSTAT, rx_id: DSCR_CMD0_USBDEV_RX4, cs: NUSBD_EP4CS, rx_str: "EP4 OUT RD",},
+};
+#else /*DBMA */
+struct ep_regs ep_regs[6] = {
+        { rd: USBD_EP0RD, rds: USBD_EP0RDSTAT, /*rx_id: DMA_ID_USBDEV_EP0_RX,*/ cs: USBD_EP0CS, rx_str: "EP0 OUT RD", 
+          wr: USBD_EP0WR, wrs: USBD_EP0WRSTAT, tx_id: DMA_ID_USBDEV_EP0_TX,                 tx_str: "EP0 IN WR",},  
+        { rds: 0, wrs: 0, indma: -1, outdma: -1, },
+        { wr: NUSBD_EP1WR, wrs: NUSBD_EP1WRSTAT, tx_id: NDMA_ID_USBDEV_EP1_TX, cs: NUSBD_EP1CS, tx_str: "EP1 IN WR",}, 
+        { wr: NUSBD_EP2WR, wrs: NUSBD_EP2WRSTAT, tx_id: NDMA_ID_USBDEV_EP2_TX, cs: NUSBD_EP2CS, tx_str: "EP2 IN WR",}, 
+
+        { rd: NUSBD_EP3RD, rds: NUSBD_EP3RDSTAT, rx_id: NDMA_ID_USBDEV_EP3_RX, cs: NUSBD_EP3CS, rx_str: "EP3 OUT RD",},
+        { rd: NUSBD_EP4RD, rds: NUSBD_EP4RDSTAT, rx_id: NDMA_ID_USBDEV_EP4_RX, cs: NUSBD_EP4CS, rx_str: "EP4 OUT RD",},
+};
+#endif /*DBMA */
+u8 epl2p[6] = { 0x00, 0x02, 0x03, 0x04, 0x05, 0x00, };        // map logical to physical
+u8 epp2l[6] = { 0x00, 0x00, 0x81, 0x82, 0x03, 0x04, };        // map physical to logical
+
+static __inline__ void au_fifo_read(struct ep_regs *ep, unsigned char * cp, int bytes)
+{
+        u32 rd = ep->rd;
+        for (; bytes--; *cp++ = au_readl(rd));
+}
+
+static __inline__ void au_fifo_write(int ep, unsigned char * cp, int bytes)
+{
+        u32 wr = ep_regs[ep].wr;
+        for (; bytes--; au_writel(*cp++, wr));
+        ep_regs[ep].last = bytes;
+}
+
+void __inline__ au_inten(u32 inten)
+{
+        au1x00_inten = inten;
+        au_writel(au1x00_inten, USBD_INTEN);
+}
+
+void __inline__ au_epn_interrupt_enable(int epn)
+{
+        au_inten(au1x00_inten | (1 << epn));
+}
+
+void __inline__ au_epn_interrupt_disable(int epn)
+{
+        au_inten(au1x00_inten & ~(1 << epn));
+        au_writel((1 << epn) , USBD_INTSTAT);
+}
+
+static void __inline__ send_zlp(unsigned char epn)
+{
+        au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep_regs[epn].wrs);
+        au_writel(0 << 1, ep_regs[epn].cs);
+        au_writel(0, ep_regs[epn].wr);
+}
+/* ********************************************************************************************* */
+#define AU_DMA_HALT_POLL 0x1000
+#ifdef DBDMA
+static void __inline__ au_halt_dma(int chan)
+{
+	au1xxx_dbdma_stop(chan);  
+        au_halt_dma_expired++;
+}
+
+static int __inline__ au_get_dma_residue(int chan)
+{
+	return au1xxx_get_dma_residue(chan);
+}
+
+static void __inline__ au_start_dma_in(int indma, __u8 *bp, int len)
+{
+        //printk("\n----------------------STARTING DMA IN dma:%X buffer:%p len:%d---------------\n", indma, bp, len);
+        //		au1xxx_dbdma_stop(indma);
+        au1xxx_dbdma_put_source(indma, bp, len);
+        au1xxx_dbdma_start(indma);
+}
+
+static void __inline__ au_start_dma_out(unsigned int outdma, __u8 *bp, int packetSize)
+{
+        //printk("\n----------------------STARTING DMA OUT dma:%X buffer:%p len:%d---------------\n", outdma, bp, packetSize);
+        au1xxx_dbdma_put_dest(outdma, bp, packetSize);
+        au1xxx_dbdma_start(outdma);
+}
+
+static u32 __inline__ au_get_dma_chan(u32 dma)
+{
+        return dma;
+}
+#else /* DBDMA */
+static void __inline__ au_halt_dma(struct dma_chan *chan)
+{
+        int i;
+        au_writel(DMA_GO, chan->io + DMA_MODE_CLEAR);
+        for (i = 0; i < AU_DMA_HALT_POLL; i++) 
+                RETURN_IF (au_readl(chan->io + DMA_MODE_READ) & DMA_HALT);
+        au_halt_dma_expired++;
+}
+
+static int __inline__ au_get_dma_residue(struct dma_chan *chan)
+{
+        int curBufCntReg = (au_readl(chan->io + DMA_MODE_READ) & DMA_AB) ? DMA_BUFFER1_COUNT : DMA_BUFFER0_COUNT;
+        return au_readl(chan->io + curBufCntReg) & DMA_COUNT_MASK;
+}
+
+static void __inline__ au_start_dma(struct dma_chan *chan, u8 *bp, int len)
+{
+        if (au_readl(chan->io + DMA_MODE_READ) & DMA_AB) {
+                au_writel(DMA_D1, chan->io + DMA_MODE_CLEAR);
+                au_writel(len & DMA_COUNT_MASK, chan->io + DMA_BUFFER1_COUNT);
+                au_writel(0, chan->io + DMA_BUFFER0_COUNT);
+                au_writel(virt_to_phys(bp), chan->io + DMA_BUFFER1_START);
+                au_writel(DMA_BE1, chan->io + DMA_MODE_SET);
+        }
+        else {
+                au_writel(DMA_D0, chan->io + DMA_MODE_CLEAR);
+                au_writel(len & DMA_COUNT_MASK, chan->io + DMA_BUFFER0_COUNT);
+                au_writel(0, chan->io + DMA_BUFFER1_COUNT);
+                au_writel(virt_to_phys(bp), chan->io + DMA_BUFFER0_START);
+                au_writel(DMA_BE0, chan->io + DMA_MODE_SET);
+        }
+        au_writel(DMA_GO, chan->io + DMA_MODE_SET);
+}
+
+static void __inline__ au_start_dma_in(int indma, u8 *bp, int len)
+{
+        au_start_dma(get_dma_chan(indma), bp, len);
+}
+
+static void __inline__ au_start_dma_out(int outdma, u8 *bp, int wMaxPacketSize)
+{
+        dma_cache_inv((unsigned long) bp, wMaxPacketSize);
+        au_start_dma(get_dma_chan(outdma), bp, wMaxPacketSize);
+}
+
+static __inline__ struct dma_chan * au_get_dma_chan(u32 dma)
+{
+        return get_dma_chan(dma);
+}
+#endif /* DBDMA */
+static struct usbd_urb *au_rcv_complete_irq(struct usbd_endpoint_instance *endpoint, int len, int urb_bad)
+{
+        return pcd_rcv_complete_irq(endpoint, len, urb_bad);
+}
+/* ********************************************************************************************* */
+/* au_start_in_ep0 - start transmit
+ */
+static void au_start_in_ep0 (struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+	struct usbd_urb *urb = endpoint->tx_urb;
+        int last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
+        TRACE_MSG2(PCD, "START IN EP0 SENT: %d SENDING: %d", endpoint->sent, last);
+        RETURN_IF ((urb->actual_length - endpoint->sent) <= 0);
+        au_writel(last << 1, ep->cs); // XXX
+        au_fifo_write(0, urb->buffer + endpoint->sent, last);
+        endpoint->last = last;
+}
+
+/* au_in_ep0 - called to service an endpoint zero IN interrupt, data sent
+ */
+static void au_in_ep0(struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+        u32 cs;
+        struct usbd_urb *tx_urb;
+        int last;
+        TRACE_MSG1(PCD, "EP0 IN: tx_urb: %p", (int)endpoint->tx_urb);
+        if ((cs = au_readl(ep->cs)) & USBDEV_CS_STALL) {                // clear stall if present
+                TRACE_MSG1(PCD, "CLEAR STALL %d", 0);
+                cs &= ~USBDEV_CS_STALL;
+                au_writel(cs, ep->cs);
+                return;
+        }
+        if (!(tx_urb = pcd_tx_complete_irq(endpoint, 0))) {               // wait for setup if no more data
+                endpoint->state = WAIT_FOR_SETUP;
+                return;
+        }
+        TRACE_MSG4(PCD, "EP0 IN actual: %d last: %d sent: %d flags: %x", endpoint->tx_urb->actual_length, 
+                        endpoint->last, endpoint->sent, endpoint->tx_urb->flags);
+        if (pcd_tx_sendzlp(endpoint)) {                          // check if tx_urb we have is finished
+                TRACE_MSG0(PCD, "EP0 IN BULK - sending ZLP");
+                tx_urb->flags &= ~USBD_URB_SENDZLP;
+                send_zlp(0);
+                pcd_tx_complete_irq(endpoint, 0);
+                return;
+        }
+        if (tx_urb->actual_length > endpoint->sent) {
+                if ((tx_urb->actual_length - endpoint->sent) < endpoint->wMaxPacketSize) 
+                        TRACE_MSG1(PCD, "EP0 IN starting short packet %d", tx_urb->actual_length - endpoint->sent);
+                else 
+                        TRACE_MSG1(PCD, "EP0 IN LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
+                au_start_in_ep0(endpoint, ep);
+        }
+}
+
+/* au_out_ep0 - called to service an endpoint zero OUT interrupt, data received
+ */
+static void au_out_ep0(struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+        struct usbd_device_request request;
+        int i;
+        u32 cs;
+        u32 bytes;
+        TRACE_MSG0(PCD, "EP0 OUT");
+        cs = au_readl(ep->cs);                                  // check if host aborted transfer and flush the write fifo
+        bytes = au_readl(ep->rds) & USBDEV_FSTAT_FCNT_MASK;
+        if (endpoint->state == DATA_STATE_RECV) {
+                struct usbd_urb *rcv_urb = pcd_rcv_next_irq(endpoint);
+                TRACE_MSG1(PCD, "EP0 OUT: RECV: rcv_urb: %x", (int) rcv_urb);
+                if (rcv_urb) {
+                        au_fifo_read(ep, rcv_urb->buffer + rcv_urb->actual_length, bytes);
+                        if (au_rcv_complete_irq(endpoint, bytes, 0)) 
+                                return;
+                        au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+                        endpoint->state = WAIT_FOR_SETUP;
+                        send_zlp(0);
+                        return;
+                }
+                endpoint->state = WAIT_FOR_SETUP;
+        }
+        pcd_tx_cancelled_irq(endpoint);
+        pcd_rcv_cancelled_irq(endpoint);
+        au_fifo_read(ep, (u8 *)&request, bytes);
+        au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs);
+        if (bytes != 8) {
+                TRACE_MSG1(PCD, "ERROR SETUP SET not eight bytes: %d", bytes);
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs);
+                return;
+        }
+        TRACE_MSG4(PCD, "SETUP bmRequestType: %02x bRequest %02x state: %d status: %d", request.bmRequestType, 
+                        request.bRequest, pcd_instance->bus->device_state, pcd_instance->bus->status);
+        switch (request.bRequest) {                     // we need to simply ignore any of these
+        case USB_REQ_SET_ADDRESS:                       // Fake a bus reset IFF not state default and then process normally
+                BREAK_IF (pcd_instance->bus->device_state == STATE_DEFAULT);
+                udc_saw_bus_activity = 0;
+                usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_RESET, 0);
+                usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_ADDRESS_ASSIGNED, 0);
+                break;
+        case USB_REQ_GET_DESCRIPTOR:                    // Fake a bus reset IFF suspended and then process normally
+                BREAK_IF (STATE_SUSPENDED != pcd_instance->bus->device_state);
+                udc_saw_bus_activity = 0;
+                usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_RESET, 0);
+                usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_ADDRESS_ASSIGNED, 0);
+                break;
+        }
+        if (pcd_recv_setup_irq(pcd_instance, &request)) {
+                TRACE_MSG1(PCD, "ep0 STALL %d", cs);
+                au_writel(USBDEV_CS_STALL, USBD_EP0CS);
+                return;
+        }
+        if (((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) && le16_to_cpu (request.wLength)) {
+                TRACE_MSG1(PCD, "ep0 Class H2D request %04x", le16_to_cpu(request.wLength));
+                endpoint->state = DATA_STATE_RECV;
+                return;
+        }                               
+        if ((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
+                TRACE_MSG1(PCD, "ep0 Class H2D request %04x", le16_to_cpu(request.wLength));
+                if ((request.bmRequestType & ~USB_REQ_DIRECTION_MASK)) {
+                        TRACE_MSG1(PCD, "ep0 Class or Vendor, send ZLP %d", cs);
+                        send_zlp(0);
+                        return;
+                }
+        }
+        TRACE_MSG1(PCD, "ep0 Class D2H request %04x", le16_to_cpu(request.wLength));
+}
+/* ********************************************************************************************* */
+/* au_start_in_bulk - start transmit
+ * The au1x00 will start to send when the first byte is loaded into the FIFO, either by
+ * DMA or PIO. The packetsize must be set first.
+ */
+static void au_start_in_bulk (unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+        struct usbd_urb *urb = endpoint->tx_urb;
+        unsigned char *bp = urb->buffer + endpoint->sent;
+        int last;
+        TRACE_MSG1(PCD, "START IN BULK %d", epn);
+        RETURN_IF (!urb || (( (urb->actual_length - endpoint->sent) == 0) && !(urb->flags & USBD_URB_SENDZLP)));
+        last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
+        TRACE_MSG2(PCD, "START IN BULK sent: %d last:%d", endpoint->sent, last);
+        au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // XXX
+        if (!last) {
+                if (endpoint->tx_urb->flags & USBD_URB_SENDZLP) {
+                        TRACE_MSG0(PCD, "START IN BULK - zending ZLP");
+                        send_zlp(epn);
+                        endpoint->tx_urb->flags &= ~USBD_URB_SENDZLP;
+                }
+                return;
+        }
+        else if (au1x00_new_silicon  && (8 >= last)) {
+                au_writel(last << 1, ep->cs);
+                au_fifo_write(epn, bp, last);
+                return;
+        }
+        if (!au1x00_new_silicon) 
+                au_epn_interrupt_disable(epn);
+        dma_cache_wback_inv((unsigned long) bp, last); 
+        au_writel(last << 1, ep->cs);
+        au_start_dma_in(ep->indma, bp, last);
+}
+
+static void au_in_bulk(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *tx_urb;
+        int rc = 0;
+        u32 cs = au_readl(ep->cs);
+        u32 wrs = au_readl(ep->wrs);
+        TRACE_MSG2(PCD, "BULK IN EPN - cs: %x wrs: %x", cs, wrs);
+        if (!au1x00_new_silicon) 
+                if (epn && (ep->last > 8)) {
+                        TRACE_MSG2(PCD, "BULK IN EPN - DMA ACTIVE epn %d last %d", epn, ep->last);
+                        au_epn_interrupt_disable(epn);
+                        return;
+                }
+        if (wrs) {                                                              // check for underflow or overflow
+                rc = 1;
+                if (wrs & USBDEV_FSTAT_UF) {
+                        TRACE_MSG2(PCD, "BULK IN EPN - UF epn %d wrs: %x", epn, wrs);
+                        rc = 1;                                                 // set rc to indicate an error
+                }
+                if (wrs & USBDEV_FSTAT_OF) 
+                        TRACE_MSG2(PCD, "BULK IN EPN - OF epn %d wrs: %x", epn, wrs);
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs);     // flush the fifo 
+        }
+        if (cs & USBDEV_CS_NAK) {
+                RETURN_IF (ep->last && ((wrs&0x1f) == ep->last));
+                rc = 1;
+        }
+        if (cs & USBDEV_CS_STALL) {                                             // clear stall if present
+                TRACE_MSG1(PCD, "BULK IN EPN - CLEAR STALL %d", epn);
+                cs &= ~USBDEV_CS_STALL;
+                au_writel(cs, ep->cs);
+                return;
+        }
+        TRACE_MSG4(PCD, "BULK IN EPN epn: %d rc: %d last: %d sent: %d", epn, rc, endpoint->last, endpoint->sent);
+        if ((tx_urb = pcd_tx_complete_irq(endpoint, rc))) {
+                if ((tx_urb->actual_length > endpoint->sent) || (endpoint->tx_urb->flags & USBD_URB_SENDZLP)) {
+                        au_start_in_bulk(epl2p[endpoint->bEndpointAddress&0xf], endpoint, ep);
+                        /* XXX magic delay - without this large packets will eventually stall the transmit
+                         * XXX and all traffic in both directions will stop. 
+                         */
+                        if (!au1x00_new_silicon) 
+                                udelay(8);
+                        TRACE_MSG1(PCD, "BULK IN EPN - LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
+                        return;
+                }
+        }
+        au_epn_interrupt_disable(epn);                                         // disable interrupts
+}
+
+/* au_start_in_iso - start transmit
+ * The au1x00 will start to send when the first byte is loaded into the FIFO, either by DMA or
+ * PIO. The packetsize must be set first.
+ */
+static void au_start_in_iso (unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+        struct usbd_urb *urb = endpoint->tx_urb;
+        unsigned char *bp = urb->buffer + endpoint->sent;
+        int last;
+        TRACE_MSG2(PCD, "START IN ISO actual: %d sent: %d", urb->actual_length, endpoint->sent);
+        RETURN_IF ((urb->actual_length - endpoint->sent) == 0);
+        last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
+        TRACE_MSG2(PCD, "START IN ISO last: %d packetSize: %d", last, endpoint->wMaxPacketSize);
+        au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // XXX
+        au1x00_new_silicon ? au_epn_interrupt_enable : au_epn_interrupt_disable (epn);
+        dma_cache_wback_inv((unsigned long) bp, last);
+        au_writel(last << 1, ep->cs);
+        au_start_dma_in(ep->indma, bp, last);
+}
+
+static void au_in_iso(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *tx_urb = pcd_tx_complete_irq(endpoint, 0);
+        u32 cs = au_readl(ep->cs);
+        u32 wrs = au_readl(ep->wrs);
+        TRACE_MSG2(PCD, "ISO IN EPN - cs: %x wrs: %x", cs, wrs);
+        if (!au1x00_new_silicon) 
+                if (epn && (ep->last > 8)) {
+                        au_epn_interrupt_disable(epn);
+                        return;
+                }
+        TRACE_MSG4(PCD, "ISO IN EPN epn: %d last: %d sent: %d", epn, endpoint->last, endpoint->sent, 0);
+        ep->last = 0;
+        if ((tx_urb = endpoint->tx_urb) && (tx_urb->actual_length > endpoint->sent)) {
+                au_start_in_iso(epl2p[endpoint->bEndpointAddress&0xf], endpoint, ep);
+                /* XXX magic delay - without this large packets will eventually stall the transmit
+                 * XXX and all traffic in both directions will stop. 
+                 */
+                if (!au1x00_new_silicon) 
+                        udelay(8);
+                TRACE_MSG1(PCD, "ISO IN EPN - LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
+                return;
+        }
+        else 
+                TRACE_MSG0(PCD, "ISO IN EPN - nothing to send");
+        au_epn_interrupt_disable(epn);                                 // disable interrupts
+}
+/* ********************************************************************************************* */
+
+static void au_start_out_bulk(unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+        TRACE_MSG2(PCD, "START OUT BULK %d %d", epn, endpoint->wMaxPacketSize);
+        if (!endpoint->rcv_urb) {
+                TRACE_MSG0(PCD, "START OUT BULK DISABLE");
+                au_epn_interrupt_disable(epn);
+                return;
+        }
+        if (endpoint->rcv_error) {
+                TRACE_MSG0(PCD, "START OUT BULK reseting rcv_error");
+                endpoint->rcv_error = 0;
+        }
+        au_start_dma_out(ep->outdma, endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length, endpoint->wMaxPacketSize);
+}
+
+static void au_out_bulk(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
+{
+        int bytes = 0;
+        struct usbd_urb *urb;
+        struct usbd_urb *completed_urb = NULL;
+        u32 cs;
+        u32 rds;
+        u32 nrds;
+        au_halt_dma(au_get_dma_chan(ep->outdma));
+        cs = au_readl(ep->cs);
+        rds = au_readl(ep->rds);
+        TRACE_MSG2(PCD, "BULK OUT CS: %04x RD: %04x", cs, rds);
+        bytes = endpoint->wMaxPacketSize - au_get_dma_residue(au_get_dma_chan(ep->outdma));
+        if (!(urb = pcd_rcv_next_irq(endpoint))) {
+                TRACE_MSG0(PCD, "BULK OUT EPN - no rcv_urb");
+                au_epn_interrupt_disable(epn);
+                return;
+        }
+        /* The original AU1X00 UDC design will continue to receive data as long as there is room
+         * in the FIFO. We cannot tell when we are at the end of a packet and/or have the start
+         * of a new one.
+         *
+         * There are only two scenarios that are guaranteed (almost) to be correct:
+         *
+         *      64 bytes of data from DMA, empty fifo, continue Bulk OUT < 60 bytes of data and
+         *      < 4 bytes in fifo, end Bulk OUT.
+         *
+         * There may be a third scenario that is ok:
+         *
+         *      0 bytes dma, 0 bytes in fifo, NAK
+         *
+         * Everything else is an error. In all cases we assume that it is safer to drop data
+         * than to accept it in error. This allows CRC or size protected encapsulations to
+         * notice bulk transfers received with errors.
+         *
+         * In general none of the policies or strategies are able to cope with all errors
+         * without missing errors and dropping good data.  The intent is to minimize the amount
+         * of potentially bad data getting to the function driver while minimizing the amount of
+         * good data that is dropped.
+         *
+         * The new silicon mitigates this problem for non control endpoints because it will NAK
+         * additional data until the interrupt service flag is reset.
+         * 
+         * Start with generic error tests, OF, UF or NAK indicate an error we cannot recover
+         * from, start flushing until end of current bulk transfer (wait for a short packet)
+         *
+         */
+        if (rds & (USBDEV_FSTAT_OF | USBDEV_FSTAT_UF)) {
+                TRACE_MSG2(PCD, "BULK OUT FLUSHING %d length: %d", bytes, urb->actual_length);
+                THROW(start_flushing);
+        }
+        rds = rds & USBDEV_FSTAT_FCNT_MASK;
+        nrds = au_readl(ep->rds);
+        if (64 == bytes) {
+                TRACE_MSG2(PCD, "BULK OUT 64 BYTES %d length: %d", bytes, urb->actual_length);
+                /* full size packet received, check that we are not flushing and that the FIFO
+                 * does not have any data. If there is data in the FIFO we may not be able to
+                 * restart DMA in time, so start flushing 
+                 */
+                if (endpoint->rcv_error) {
+                        TRACE_MSG4(PCD, "FULL PACKET bytes: %d rds: %d nrds: %d cp0: %d CONTINUE FLUSHING", 
+                                        bytes, rds, nrds, cp0_count);
+                        THROW(start_flushing);
+                }
+                if ((nrds > 6)  && (nrds < 8) ) {
+                        TRACE_MSG4(PCD, "FIFO not empty bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING nrds > 6 < 8", 
+                                        bytes, rds, nrds, cp0_count);
+                        THROW(start_flushing);
+                }
+                if (!urb->actual_length) 
+                        TRACE_MSG4(PCD, "PACKET ok bytes: %d rds: %d nrds: %d cp0: %d ACCEPTING 64 bytes", 
+                                        bytes, rds, nrds, cp0_count);
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+                au_rcv_complete_irq(endpoint, 64, 0);
+                if (cs & USBDEV_CS_NAK) 
+                        if (nrds && (nrds < 8) ) {
+                                TRACE_MSG4(PCD, "NAK bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING CS_NAK", 
+                                                bytes, rds, nrds, cp0_count);
+                                THROW(start_flushing);
+                        }
+        }
+        else if ((cs & USBDEV_CS_NAK) && (!nrds || (nrds == 8)) ) {
+                TRACE_MSG2(PCD, "BULK OUT  NAK BYTES %d length: %d", bytes, urb->actual_length);
+                /* a nak'd packet may be ok to ignore IFF the FIFO is empty(?) or completely full.
+                 */
+                if (endpoint->rcv_error) {
+                        TRACE_MSG4(PCD, "NAK bytes: %d rds: %d nrds: %d cp0: %d CONTINUE FLUSHING", 
+                                        bytes, rds, nrds, cp0_count);
+                        THROW(start_flushing);
+                }
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+        }
+        else {
+                TRACE_MSG2(PCD, "BULK OUT < 64 BYTES %d length: %d", bytes, urb->actual_length);
+                /* short packet by DMA, additional data for this packet in FIFO, more than 3
+                 * bytes is probably an error.
+                 */
+                if ((cs & USBDEV_CS_NAK) && nrds && (nrds < 8) ) {
+                        TRACE_MSG4(PCD, "BULK OUT NAK bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING", 
+                                        bytes, rds, nrds, cp0_count);
+                        THROW(start_flushing);
+                }
+                if (nrds > 4) {
+                        TRACE_MSG4(PCD, "BULK OUT SHORT PACKET by DMA full FIFO bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING", 
+                                        bytes, rds, nrds, cp0_count);
+                        THROW(start_flushing);
+                }
+                TRACE_MSG4(PCD, "BULK OUT SHORT bytes: %d rds: %d nrds: %d cp0: %d reading fifo", bytes, rds, nrds, cp0_count);
+                au_fifo_read(ep, urb->buffer + urb->actual_length + bytes, nrds);
+                bytes += nrds;
+                TRACE_MSG1(PCD, "BULK OUT < 64 BYTES %d", bytes);
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+                if (!endpoint->rcv_error) {
+                        TRACE_MSG0(PCD, "BULK OUT COMPLETED URB");
+                        au_rcv_complete_irq(endpoint, bytes, 0);
+                }
+                else {
+                        TRACE_MSG0(PCD, "BULK OUT - FLUSHING URB - reseting rcv_error");
+                        endpoint->rcv_error = 0;
+                }
+        }
+        CATCH(start_flushing) {
+                TRACE_MSG0(PCD, "BULK OUT - START FLUSHING URB");
+                endpoint->rcv_error = 1;
+                endpoint->rcv_urb->actual_length = 0;
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+                bytes = 0;
+        }
+        TRACE_MSG0(PCD, "BULK OUT - RESTARTING");
+        au_start_out_bulk(epn, endpoint, ep);
+}
+
+static void au_start_out_iso(unsigned int epn, struct usbd_endpoint_instance *endpoint, struct ep_regs *ep)
+{
+        int outdma = ep->outdma;
+        RETURN_IF(!endpoint->rcv_urb);
+        au_start_dma_out(outdma, endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length, endpoint->wMaxPacketSize);
+}
+
+static void au_out_iso(unsigned int epn, struct ep_regs *ep, struct usbd_endpoint_instance *endpoint)
+{
+        int bytes = 0;
+        struct usbd_urb *urb;
+        u32 cs;
+        u32 rds;
+        au_halt_dma(au_get_dma_chan(ep->outdma));
+        cs = au_readl(ep->cs);
+        rds = au_readl(ep->rds);
+        if (!endpoint) {
+                au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+                return;
+        }
+        if (!(urb = endpoint->rcv_urb)) {
+                TRACE_MSG2(PCD, "ISO OUT EPN - rcv_urb was NULL bytes: %d rds: %d", bytes, rds);
+                au_rcv_complete_irq(endpoint, bytes, 1);
+                TRACE_MSG0(PCD, "ISO OUT setting rcv_error");
+        }
+        bytes = endpoint->wMaxPacketSize - au_get_dma_residue(au_get_dma_chan(ep->outdma));
+        rds = rds & USBDEV_FSTAT_FCNT_MASK;
+        au_fifo_read(ep, urb->buffer + urb->actual_length + bytes, rds);
+        bytes += rds;
+        au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
+        au_rcv_complete_irq(endpoint, bytes, 0);
+        au_start_out_iso(epn, endpoint, ep);
+}
+/* ********************************************************************************************* */
+/* au_tx_dma_done - TX DMA interrupt handler
+ */
+static void au_tx_dma_done(int irq, void *dev_id, struct pt_regs *regs)
+{
+        int epn = (int) dev_id;
+        struct usbd_endpoint_instance *endpoint = pcd_instance->bus->endpoint_array + epn;
+        struct ep_regs *ep = &ep_regs[epn];
+        int residue;
+#if 0
+        int indma = irq - 6;
+        struct dma_chan *chan = get_dma_chan(indma);
+#endif
+#ifdef DBDMA
+#else /* DBDMA */
+        struct dma_chan *chan = get_dma_chan(ep->indma);
+        u32 mode = au_readl(chan->io + DMA_MODE_READ);
+        TRACE_MSG1(PCD, "TX DMA done: mode: %x", mode);
+        if (mode & DMA_D0) 
+                au_writel(DMA_D0, chan->io + DMA_MODE_CLEAR);
+        if (mode & DMA_D1) 
+                au_writel(DMA_D1, chan->io + DMA_MODE_CLEAR);
+#endif /* DBDMA */
+        ocd_ops.interrupts++;
+        RETURN_IF (!epn);
+        au_halt_dma(au_get_dma_chan(ep->indma));
+        residue = au_get_dma_residue(au_get_dma_chan(ep->indma));
+        TRACE_MSG2(PCD, "TX DMA IRQ - epn %d residue %d", epn, residue);
+        if (!au1x00_new_silicon) {
+                /* XXX magic delay - without this large packets will eventually stall the transmit
+                 * XXX and all traffic in both directions will stop. 
+                 */
+                udelay(8);
+                pcd_tx_complete_irq (endpoint, residue?1:0);
+                au_epn_interrupt_enable(epl2p[endpoint->bEndpointAddress&0xf]);
+        }
+        ep->last = 0;
+}
+
+/* au_int_req - usb interrupt handler
+ */
+static void au_int_req (int irq, void *dev_id, struct pt_regs *regs)
+{
+        u32 intstat;
+        struct ep_regs *ep;
+#if defined(MAX_INTR_LOOP_STATS)
+        u32 loopcount = 0;
+#endif
+#ifdef  RECORD_LATENCY
+        cp0_count = (read_c0_count(CP0_COUNT) - cp0_record) >> 9;
+        if (cp0_count < CP0_COUNTS) 
+                cp0_counts[cp0_count]++;
+#endif
+#ifdef  CHECK_LATENCY
+        u32 cp0_count = read_c0_count(CP0_COUNT);
+#endif
+        ocd_ops.interrupts++;
+#if 0
+        if (ocd_ops.interrupts > 2000) {
+                TRACE_MSG0(PCD, "UDC_INT call udc_disable_interrupts");
+                au_inten(0);
+                return;
+        }
+#endif
+        while (( intstat = au_readl(USBD_INTSTAT) & au1x00_inten)) {    // read and reset interrupt status register
+
+                int epn;
+#if 1                
+                for (epn = 2; epn < 6; epn++) {
+                        CONTINUE_IF (!(intstat & (1 << epn)));
+#else
+                // NOT TESTED
+                u32 local_intstat = intstat;
+                TRACE_MSG2(PCD, "INTSTAT: %04x %04x", intstat, au_readl(USBD_INTEN));
+                while (local_intstat & 0x3f) {
+                        int epn = 31 - au_clz(local_intstat);
+                        local_intstat &= ~(1<<epn);
+#endif
+                        if (udc_saw_bus_activity) {
+                                udc_saw_bus_activity = 0;
+                                usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_BUS_ACTIVITY, 0);
+                                au_inten(0x0033|USBDEV_INT_SOF);                    
+                        }
+                        ep = &ep_regs[epn];
+                        switch(ep->eptype) {
+                        case USB_DIR_IN | USB_ENDPOINT_BULK:
+                        case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
+                                //TRACE_MSG2(PCD, "BULK IN %d %02x", epn, ep->eptype);
+                                au_in_bulk(epn, ep, pcd_instance->bus->endpoint_array + epn);
+                                break;
+                        case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
+                                //TRACE_MSG2(PCD, "ISO IN %d %02x", epn, ep->eptype);
+                                au_in_iso(epn, ep, pcd_instance->bus->endpoint_array + epn);
+                                break;
+                        case USB_DIR_OUT | USB_ENDPOINT_BULK:
+                        case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
+                                //TRACE_MSG2(PCD, "BULK OUT %d %02x", epn, ep->eptype);
+                                au_out_bulk(epn, ep, pcd_instance->bus->endpoint_array + epn);
+                                break;
+                        case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
+                                //TRACE_MSG2(PCD, "ISO OUT %d %04d", epn, au_readl(NUSBD_FRAMENUM));
+                                au_out_iso(epn, ep, pcd_instance->bus->endpoint_array + epn);
+                                break;
+                        }
+                }
+                au_writel(intstat, USBD_INTSTAT);               // Only clear the interrupt(s) AFTER servicing OUT
+                /* even though we disable the bulk-in interrupt (endpoint 2) prior to enabling
+                 * DMA we always see one additional interrupt that is a NAK on that endpoint.
+                 */
+                CONTINUE_IF(!(intstat & au1x00_inten));
+                /* handle control endpoint and suspend interrupt
+                 */
+                if (intstat & ( ((1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | USBDEV_INT_SOF))) {
+                        if (intstat & (1 << 0)) 
+                                au_out_ep0(pcd_instance->bus->endpoint_array + 0, &ep_regs[0]);
+                        if (intstat & (1 << 1)) 
+                                au_in_ep0(pcd_instance->bus->endpoint_array + 0, &ep_regs[0]);
+                        if (intstat & USBDEV_INT_SOF) 
+                                if (USBD_SUSPENDED == pcd_instance->bus->status) {
+                                        TRACE_MSG0(PCD, "SUS - ACTIVITY");
+                                        udc_saw_bus_activity++;
+                                }
+                }
+#if defined(MAX_INTR_LOOP_STATS)
+                loopcount += 1;                         // Gather stats on how many times this loop is performed. 
+#endif
+        }
+#if defined(MAX_INTR_LOOP_STATS)
+        interrupt_loop_stats[MIN(loopcount, MAX_INTR_LOOP_STATS)]++;
+#endif
+#if defined(CHECK_LATENCY)
+        TRACE_MSG1(PCD, "USB IRQ - %d", read_c0_count(CP0_COUNT) - cp0_count);
+#endif
+#if defined(RECORD_LATENCY)
+        cp0_record = read_c0_count(CP0_COUNT);
+#endif
+}
+
+/* au_int_sus -suspend interrupt handler
+ */
+static void au_int_sus (int irq, void *dev_id, struct pt_regs *regs)
+{
+        ocd_ops.interrupts++;
+        TRACE_MSG2(PCD, "SUS - INACTIVE device: %d status: %d", pcd_instance->bus->device_state, pcd_instance->bus->status);
+        switch(pcd_instance->bus->status) {
+        case USBD_OPENING:
+        case USBD_OK:
+                au_inten(0x0033);
+                usbd_bus_event_handler_irq (pcd_instance->bus, DEVICE_BUS_INACTIVE, 0);
+                break;
+        default:
+                break;
+        }
+}
+/* ********************************************************************************************* */
+/* 
+ * au_connect - enable pullup resistor
+ * Turn on the USB connection by enabling the pullup resistor.
+ *
+ * au_disconnect - disable pullup resistor
+ * Turn off the USB connection by disabling the pullup resistor.
+ */
+
+#if defined(CONFIG_MIPS_PICOENGINE_MVCI)
+void au_connect (struct pcd_instance *pcd)
+{
+        extern void pico_mvci_set_usb_pullup(int);
+        pico_mvci_set_usb_pullup(1);
+}
+
+void au_disconnect (struct pcd_instance *pcd)
+{               
+        extern void pico_mvci_set_usb_pullup(int);
+        pico_mvci_set_usb_pullup(0);
+}
+
+#elif defined(CONFIG_MIPS_FREEHAND_NATIVE)
+void au_connect (struct pcd_instance *pcd)
+{
+        au1000gpio_set(GPIO01);
+}
+
+void au_disconnect (struct pcd_instance *pcd)
+{               
+        au1000gpio_clear(GPIO01);
+}
+#elif defined(CONFIG_AMX_MORDOR)
+void au_connect (struct pcd_instance *pcd)
+{
+        au_writel(0x00000008, SYS_OUTPUTSET);
+}
+
+void au_disconnect (struct pcd_instance *pcd)
+{               
+        au_writel(0x00000008, SYS_OUTPUTCLR);
+}
+#else
+void au_connect (struct pcd_instance *pcd)
+{
+}
+void au_disconnect (struct pcd_instance *pcd)
+{
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
+#undef read_c0_prid
+#define read_c0_prid()  read_32bit_cp0_register(CP0_PRID)
+#endif
+#undef read_c0_COUNT
+#ifndef read_c0_count
+#define read_c0_count()  read_32bit_cp0_register(CP0_COUNT)
+#endif
+/* au_loc_conn - used to enable or disable peripheral connecting to bus
+ *
+ */
+void au_loc_conn(struct otg_instance *otg, u8 flag)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)otg->pcd;
+        TRACE_MSG0(PCD, "--");
+        TRACE_MSG1(PCD, "PCD: %x", (int)pcd);
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_SET");
+                TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_RESET - Enable DP PULLUP");
+                au_connect(pcd);
+                break;
+
+        case RESET:
+                TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_RESET");
+                TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_RESET - Disable DP PULLUP");
+                au_disconnect(pcd);
+                break;
+
+        case PULSE:
+                TRACE_MSG0(PCD, "OUTPUT: OCD_LOC_CONN_PULSE");
+                break;
+        }
+}
+
+/* ********************************************************************************************* */
+/* au_ticks - get current ticks
+* */
+u64 au_ticks (void)
+{       
+        return read_c0_count();
+}       
+
+/* au_elapsed - return micro-seconds between two tick values
+ */
+u64 au_elapsed(u64 *t1, u64 *t2)
+{
+        u64 ticks = (*t1 > *t2) ? (*t1 - *t2) : (*t2 - *t1);
+        ticks = (u32)((u32) ticks / (u32) CONFIG_OTG_AU1X00_SCLOCK);
+        return ticks;
+}
+
+/* au_framenum - get current framenum
+ */             
+u16 au_framenum (void)
+{               
+        return au_readl(NUSBD_FRAMENUM);
+}               
+
+
+/* ********************************************************************************************* */
+/* au_start_endpoint_in - start transmit
+ */
+void au_start_endpoint_in(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
+{
+        int epn = epl2p[endpoint->bEndpointAddress&0xf];
+        struct ep_regs *ep = &ep_regs[epn];
+        switch(endpoint->bmAttributes & USB_ENDPOINT_MASK) {
+        case USB_ENDPOINT_CONTROL:
+                au_in_ep0(endpoint, ep);
+                break;
+        case USB_ENDPOINT_BULK:
+        case USB_ENDPOINT_INTERRUPT:
+                au_start_in_bulk(epn, endpoint, ep);
+                break;
+        case USB_ENDPOINT_ISOCHRONOUS:
+                au_start_in_iso(epn, endpoint, ep);
+                break;
+        }
+        if (au1x00_new_silicon) 
+                au_epn_interrupt_enable(epn);
+}
+
+/* au_start_endpoint_out - start receive
+ */
+void au_start_endpoint_out(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
+{
+        int epn = epl2p[endpoint->bEndpointAddress&0xf];
+        struct ep_regs *ep = &ep_regs[epn];
+        switch(endpoint->bmAttributes & USB_ENDPOINT_MASK) {
+        case USB_ENDPOINT_CONTROL:
+                break;
+        case USB_ENDPOINT_BULK:
+        case USB_ENDPOINT_INTERRUPT:
+                au_start_out_bulk(epn, endpoint, ep);
+                au_epn_interrupt_enable(epn);
+                break;
+        case USB_ENDPOINT_ISOCHRONOUS:
+                au_start_out_iso(epn, endpoint, ep);
+                break;
+        }
+}
+
+void au_cancel_in_irq(struct pcd_instance *pcd, struct usbd_urb *urb)
+{
+        int epn = epl2p[urb->endpoint->bEndpointAddress&0xf];
+        struct ep_regs *ep = &ep_regs[epn];
+        au_in_bulk(epn, ep, urb->endpoint);
+}
+
+void au_cancel_out_irq(struct pcd_instance *pcd, struct usbd_urb *urb)
+{
+        int epn = epl2p[urb->endpoint->bEndpointAddress&0xf];
+        struct ep_regs *ep = &ep_regs[epn];
+        au_out_bulk(epn, ep, urb->endpoint);
+}
+
+/* au_serial_init - set a serial number if available
+ */
+int au_serial_init (struct pcd_instance *pcd)
+{
+#if defined(CONFIG_MIPS_FREEHAND)
+        int length;
+        long data[16];          /* yeah a hack, but we KNOW it's 16 */
+        struct i2c_client *client;
+        char chData[16];
+        int i;
+
+        if (!(client = getFreeHandEepromClient())) {
+                printk(KERN_INFO"eeprom not ready when au_serial_init called\n");
+                return -EINVAL;
+        }
+        eeprom_contents(client, SENSORS_PROC_REAL_READ, EEPROM_SYSCTL1, &length, (long *)data);
+
+        /* serial number is first 9 longs. But each long is just an ASCII char
+         * convert this to a string and then extract a 4 byte value from it
+         */
+        for (i = 0; i < 9; chData[i] = (char)data[i], i++);     /* trunc, is ok */
+        chData[9] = 0;                                          /* terminate string */
+        printk(KERN_INFO"%s: %s\n", __FUNCTION__, chData);
+        pcd_instance->bus->serial_number_str = lstrdup(chData);
+        return 0;
+#else
+        return -EINVAL;
+#endif
+}
+
+
+#ifdef DBDMA
+static int request_dma(int ep, int src, int dest, char *str, void dma_done(int , void *, struct pt_regs *))
+{
+        unsigned int dma;
+
+        if ((dma = au1xxx_dbdma_chan_alloc(src, dest, dma_done, (void *)ep)) < 0) {
+                printk(KERN_INFO"request_io[%d] dma: %X src: %x dest: %x %s FAILED\n", ep, dma, src, dest, str);
+                return -1;
+        }
+
+        au1xxx_dbdma_set_devwidth(dma, 16);
+
+        if(au1xxx_dbdma_ring_alloc(dma, 4) == 0) {
+                printk(KERN_INFO"Ring Buffer Allocation for  dma: %X src: %x dest: %x %s FAILED\n", ep, dma, src, dest, str);
+                return -1;
+	}
+        printk(KERN_INFO"request_io[%d] dma: %X src: %x dest: %x %s SUCCEDED\n", ep, dma, src, dest, str);
+        return dma;
+}
+#else /* DBDMA */
+static int request_dma(int ep, int id, char *str, void dma_done(int , void *, struct pt_regs *))
+{
+        int dma = request_au1000_dma(id, str, dma_done, SA_INTERRUPT, (void *)ep);
+        if (dma >= 0) return dma;
+        printk(KERN_INFO"request_io[%d] dma: %d id: %x %s FAILED\n", ep, dma, id, str);
+        return -1;
+}
+#endif /* DBDMA */
+
+/* au_start - start session
+ */
+void au_start (struct pcd_instance *pcd)
+{
+        au_inten(0x0033|USBDEV_INT_SOF);                                // Only enable receive interrupts. 
+}
+
+/* au_stop - stop session
+ */
+void au_stop (struct pcd_instance *pcd)
+{
+        au_inten(0);
+}
+
+int au_assign_endpoint( u8 physicalEndpoint, int used[6], struct usbd_endpoint_map *endpoint_map, u8 bmAttributes,
+                u16 wMaxPacketSize, u16 transferSize) 
+{
+        struct ep_regs *ep = &ep_regs[physicalEndpoint]; 
+        RETURN_EINVAL_IF(used[physicalEndpoint]);
+        endpoint_map->bEndpointAddress[0] = epp2l[physicalEndpoint];
+        endpoint_map->physicalEndpoint[0] = physicalEndpoint;
+        endpoint_map->wMaxPacketSize[0] = wMaxPacketSize;
+        endpoint_map->transferSize[0] = transferSize;
+        endpoint_map->bmAttributes[0] = bmAttributes;
+        used[physicalEndpoint]++;
+        ep->eptype = bmAttributes & 0x83;
+        return 0;
+}
+
+int au_request_endpoints(struct pcd_instance *pcd, struct usbd_endpoint_map *endpoint_map_array, int endpointsRequested, 
+                struct usbd_endpoint_request *requestedEndpoints)
+{
+        struct usbd_device_description *device_description;
+        int i, j;
+        int used[UDC_MAX_ENDPOINTS];
+        memset(used, 0, sizeof(used));
+        for (j = 0, i = 0; i < endpointsRequested; i++, j++) {
+                struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
+                u8 bmAttributes = requestedEndpoints[i].bmAttributes;
+                u16 transferSize = requestedEndpoints[i].fs_requestedTransferSize;
+                RETURN_EINVAL_UNLESS(j < UDC_MAX_ENDPOINTS);
+                switch(bmAttributes) {
+                case USB_DIR_OUT | USB_ENDPOINT_BULK:
+                case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
+                case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
+                        CONTINUE_IF(!au_assign_endpoint(4, used, endpoint_map, bmAttributes, 0x40, transferSize));
+                        CONTINUE_IF(!au_assign_endpoint(5, used, endpoint_map, bmAttributes, 0x40, transferSize));
+                        break;
+                case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
+                        CONTINUE_IF(!au_assign_endpoint(4, used, endpoint_map, bmAttributes, transferSize, transferSize));
+                        CONTINUE_IF(!au_assign_endpoint(5, used, endpoint_map, bmAttributes, transferSize, transferSize));
+                        break;
+                case USB_DIR_IN | USB_ENDPOINT_BULK:
+                case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
+                case USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
+                        CONTINUE_IF(!au_assign_endpoint(2, used, endpoint_map, bmAttributes, 0x40, transferSize));
+                        CONTINUE_IF(!au_assign_endpoint(3, used, endpoint_map, bmAttributes, 0x40, transferSize));
+                        break;
+                case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
+                        CONTINUE_IF(!au_assign_endpoint(2, used, endpoint_map, bmAttributes, transferSize, transferSize));
+                        CONTINUE_IF(!au_assign_endpoint(3, used, endpoint_map, bmAttributes, transferSize, transferSize));
+                        break;
+                }
+                CONTINUE_IF(bmAttributes & USB_ENDPOINT_OPT);
+                return -EINVAL;
+        }
+        return 0;
+}
+
+int au_set_endpoints(struct pcd_instance *pcd, int endpointsRequested, struct usbd_endpoint_map *endpoint_map_array)
+{
+        int i, j;
+        u8 config[25];
+        u8 *cp;
+        memcpy(config, au1x00_config_bulk, sizeof(config));
+        for (i = 0; i < endpointsRequested; i++) {
+                struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
+                int epreq = endpoint_map->bmAttributes[0];
+                int eptype = epreq & USB_ENDPOINT_MASK;
+                int epdir = epreq & USB_ENDPOINT_DIR_MASK ? 0x8 : 0;
+                int epsize = endpoint_map->wMaxPacketSize[0];
+                int epaddr = epp2l[endpoint_map->physicalEndpoint[0]];
+                CONTINUE_IF(!endpoint_map->physicalEndpoint[0] || (endpoint_map->physicalEndpoint[0] > 5));
+                cp = config + ((endpoint_map->physicalEndpoint[0] - 1) * 5);
+                cp[0] = (epaddr & 0xf) << 4 | 0x4;
+                cp[1] = (eptype << 4) | epdir | (epsize & 0x380) >> 7;
+                cp[2] = (epsize & 0x7F) << 1;
+        } 
+        au_inten(0);                                                            // disable interrupts
+        au_writel(0x0002, USBD_ENABLE);                                         // reset controller
+        udelay(100);
+        au_writel(0x0003, USBD_ENABLE);                                         // enable controller
+        udelay(100);
+        for (cp = config, i = 0; i < 25; i++, au_writel(*cp++, USBD_CONFIG));   // feed the config into the UDC
+        return 0;
+}
+/* ********************************************************************************************* */
+/* au_mod_init 
+ */
+int au_mod_init (void)
+{
+        int dev = request_irq (AU1000_USB_DEV_REQ_INT, au_int_req, SA_INTERRUPT, UDC_NAME "UDC Req", NULL);
+        int sus = request_irq (AU1000_USB_DEV_SUS_INT, au_int_sus, SA_INTERRUPT, UDC_NAME "UDC Sus", NULL);
+        u32 cp0_prid = read_c0_prid();
+        int i;
+
+
+        if (dev || sus) {                                               // check if either request irq failed
+                if (!dev) free_irq (AU1000_USB_DEV_REQ_INT, NULL);      // free irqs that might have
+                if (!sus) free_irq (AU1000_USB_DEV_SUS_INT, NULL);      // been successfully allocated
+                return -EINVAL;
+        }
+#ifdef DBDMA
+        for (i = 0; i < 6; i++) {
+                ep_regs[i].indma = ep_regs[i].tx_id ? 
+                        request_dma(i, DBDMA_MEM_CHAN, ep_regs[i].tx_id, ep_regs[i].tx_str, au_tx_dma_done) : -1;
+                ep_regs[i].outdma = ep_regs[i].rx_id ? 
+                        request_dma(i, ep_regs[i].rx_id, DBDMA_MEM_CHAN, ep_regs[i].rx_str, NULL) : -1;
+        }
+#else /*DBMA */
+        for (i = 0; i < 6; i++) {
+                ep_regs[i].indma = ep_regs[i].tx_id ?  request_dma(i, ep_regs[i].tx_id, ep_regs[i].tx_str, au_tx_dma_done) : -1;
+                ep_regs[i].outdma = ep_regs[i].rx_id ?  request_dma(i, ep_regs[i].rx_id, ep_regs[i].rx_str, NULL) : -1;
+        }
+#endif /*DBMA */
+        switch (cp0_prid & CP0_PRID_SOC_MASK) {
+        case CP0_PRID_AU1000:
+        case CP0_PRID_AU1100:
+                au1x00_new_silicon = (cp0_prid & CP0_PRID_REV_MASK) >= 4;
+                printk(KERN_INFO"%s: AU1100 cp0_prid: new: %d\n", __FUNCTION__, au1x00_new_silicon);
+                break;
+        case CP0_PRID_AU1500:
+                au1x00_new_silicon = (cp0_prid & CP0_PRID_REV_MASK) >= 2;
+                printk(KERN_INFO"%s: AU1500 cp0_prid: new: %d\n", __FUNCTION__, au1x00_new_silicon);
+                break;
+        case CP0_PRID_AU1550:
+                au1x00_new_silicon = (cp0_prid & CP0_PRID_REV_MASK) >= 0;
+                printk(KERN_INFO"%s: AU1550 cp0_prid: new: %d\n", __FUNCTION__, au1x00_new_silicon);
+                break;
+        default:
+                printk(KERN_INFO"%s: UNKNOWN CPU cp0_prid: %08x UNKNOWN UDC\n", __FUNCTION__, cp0_prid);
+                break;
+        }
+        return 0;
+}
+
+/* au_mod_exit  
+ */
+void au_mod_exit (void)
+{
+        int j;
+        au_writel(0x0000, USBD_ENABLE);
+        for (j = 0; j < 6; j++) {
+                struct ep_regs *ep = &ep_regs[j]; 
+#ifdef DBDMA
+                if (ep->indma != -1) {
+                        au1xxx_dbdma_chan_free(ep->indma);
+                        ep->indma = -1;
+                }
+                if (ep->outdma != -1) {
+                        au1xxx_dbdma_chan_free(ep->outdma);
+                        ep->outdma = -1;
+                }
+#else /*DBMA */
+                if (ep->indma != -1) {
+                        free_au1000_dma(ep->indma);
+                        ep->indma = -1;
+                }
+                if (ep->outdma != -1) {
+                        free_au1000_dma(ep->outdma);
+                        ep->outdma = -1;
+                }
+#endif /*DBMA */
+        }
+        free_irq (AU1000_USB_DEV_REQ_INT, NULL);
+        free_irq (AU1000_USB_DEV_SUS_INT, NULL);
+#if defined(MAX_INTR_LOOP_STATS)
+        {
+                u32 lc;
+                for (lc = 0; lc <= MAX_INTR_LOOP_STATS; lc++) 
+                        if (interrupt_loop_stats[lc]) 
+                                printk(KERN_ERR "%s: interrupt loopcount[%02u] %9u\n", __FUNCTION__, lc,interrupt_loop_stats[lc]);
+                printk(KERN_INFO"%s: halt_dma_expired: %d\n", __FUNCTION__, au_halt_dma_expired);
+        }
+#endif
+#ifdef RECORD_LATENCY
+        {
+                int i;
+                for (i = 0; i < CP0_COUNTS; i++) 
+                        if (cp0_counts[i]) 
+                                printk(KERN_INFO"%s: cp0_counts[%d] %d\n", __FUNCTION__, i, cp0_counts[i]);
+        }
+#endif
+}
+
+/* ********************************************************************************************* */
+struct usbd_pcd_ops usbd_pcd_ops = {
+        max_endpoints:  UDC_MAX_ENDPOINTS,
+        ep0_packetsize:  EP0_PACKETSIZE,
+        name:  UDC_NAME,
+        start: au_start,
+        stop: au_stop,
+        start_endpoint_in: au_start_endpoint_in,
+        start_endpoint_out: au_start_endpoint_out,
+        request_endpoints: au_request_endpoints,
+        set_endpoints: au_set_endpoints,
+        cancel_in_irq: au_cancel_in_irq,
+        cancel_out_irq: au_cancel_out_irq,
+        serial_init: au_serial_init,
+};
+
+struct pcd_ops pcd_ops = {
+        pcd_en_func: pcd_en_func,
+        mod_init: au_mod_init,
+        mod_exit: au_mod_exit,
+};
+
+struct ocd_ops ocd_ops = {
+	#if defined(CONFIG_OTG_TR_AUTO)
+        capabilities: OCD_CAPABILITIES_TR | OCD_CAPABILITIES_AUTO,
+	#else 
+        capabilities: OCD_CAPABILITIES_TR,
+        #endif
+        ticks: au_ticks,
+        elapsed: au_elapsed,
+};
+
+struct tcd_ops tcd_ops = {
+	dp_pullup_func: au_loc_conn,
+};
+
diff -uNr linux/drivers/no-otg/ocd/au1x00/au1x00.h linux/drivers/otg/ocd/au1x00/au1x00.h
--- linux/drivers/no-otg/ocd/au1x00/au1x00.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/au1x00/au1x00.h	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,112 @@
+/*
+ * otg/ocd/au1x00/au1100.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ */
+ /*!
+ * @defgroup AU1X00 AMD AU1X00
+ * @ingroup pcdgroup
+ */
+ 
+/*!
+ * @file otg/ocd/au1x00/au1x00.h
+ * @brief AU1X00 Header
+ *
+ * This file contains the private defines and structures for the AU1X00  
+ * Drivers. 
+ *
+ * @ingroup AU1X00
+ */
+
+
+
+/*
+ *
+ * au1100 
+ *
+ * The au1100 does not seem to work properly with an 8 byte
+ * packetsize. So 16, 32 or 64 are the only valid values.
+ *
+ * Unfortunately this means that a DMA channel is required for
+ * EP0 transmit.
+ */
+
+#define EP0_PACKETSIZE  0x8
+
+#define UDC_MAX_ENDPOINTS       6
+
+#define UDC_NAME        "AU1100"
+
+#define NUSBD_EP0RD                0xB0200000
+#define NUSBD_EP0WR                0xB0200004
+#define NUSBD_EP1WR                0xB0200008
+#define NUSBD_EP2WR                0xB020000C
+#define NUSBD_EP3RD                0xB0200010
+#define NUSBD_EP4RD                0xB0200014
+
+#define NUSBD_EP0CS                0xB0200024
+#define NUSBD_EP1CS                0xB0200028
+#define NUSBD_EP2CS                0xB020002C
+#define NUSBD_EP3CS                0xB0200030
+#define NUSBD_EP4CS                0xB0200034
+
+#define NUSBD_EP0RDSTAT            0xB0200040
+#define NUSBD_EP0WRSTAT            0xB0200044
+#define NUSBD_EP1WRSTAT            0xB0200048
+#define NUSBD_EP2WRSTAT            0xB020004C
+#define NUSBD_EP3RDSTAT            0xB0200050
+#define NUSBD_EP4RDSTAT            0xB0200054
+
+#define NUSBD_FRAMENUM             0xB0200038
+
+enum {
+        NDMA_ID_UART0_TX = 0,
+        NDMA_ID_UART0_RX,
+        NDMA_ID_GP04,
+        NDMA_ID_GP05,
+        NDMA_ID_AC97C_TX,
+        NDMA_ID_AC97C_RX,
+        NDMA_ID_UART3_TX,
+        NDMA_ID_UART3_RX,
+        NDMA_ID_USBDEV_EP0_RX,
+        NDMA_ID_USBDEV_EP0_TX,
+        NDMA_ID_USBDEV_EP1_TX,
+        NDMA_ID_USBDEV_EP2_TX,
+        NDMA_ID_USBDEV_EP3_RX,
+        NDMA_ID_USBDEV_EP4_RX,
+        NDMA_ID_I2S_TX,
+        NDMA_ID_I2S_RX,
+        NDMA_NUM_DEV
+};
+
+typedef struct ep_regs {
+        int rd;
+        int wr;
+        int cs;
+        int rds;
+        int wrs;
+        int rx_id;
+        int tx_id;
+        char * rx_str;
+        char * tx_str;
+        u32 indma;    
+        u32 outdma;
+        int last;
+        int eptype;
+} ep_regs_t;
+
+#define MAX_EPN_PACKET_SIZE 64
+#define CP0_PRID_SOC_MASK       0xff000000
+#define CP0_PRID_AU1000         0x00000000
+#define CP0_PRID_AU1500         0x01000000
+#define CP0_PRID_AU1100         0x02000000
+#define CP0_PRID_AU1550         0x03000000  /* AMX */
+
+#define CP0_PRID_REV_MASK       0x000000ff
+
diff -uNr linux/drivers/no-otg/ocd/fsotg/fs-hcd.c linux/drivers/otg/ocd/fsotg/fs-hcd.c
--- linux/drivers/no-otg/ocd/fsotg/fs-hcd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/fsotg/fs-hcd.c	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,1527 @@
+/*
+ * otg/hcd/fsotg/fs-hcd.c - Freescale USBOTG aware Host Controller Driver (HCD)
+ *
+ *      Copyright (c) 2004 Belcarra Technologies
+ *
+ * By:
+ *      Stuart Lynne <sl@belcara.com>,
+ *      Tom Rushworth <tbr@belcara.com>,
+ *      Bruce Balden <balden@belcara.com>
+ */
+/*!
+ * @file otg/ocd/fsotg/fs-hcd.c
+ * @brief Freescale USB Host Controller Driver
+ *
+ * This is the hardware specific component of the HCD.  It knows nothing
+ * about URBs, and deals with "transfers".  This is not because it shouldn't
+ * know about them, but because URBs are generic, and so it seems reasonable
+ * to keep as much generic code in the hardware independent portion as
+ * possible.  As a result, the parameter list to hcd_hw_start_transfer()
+ * is really fat.
+ *
+ * This is not compiled as a self contained module, but is linked with
+ * the generic component hc_xfer.o.
+ *
+ * There is some processor specific code here to support the alternate processors
+ * that implement this type of USB support.
+ *
+ * There is no board or platform level code here.
+ *
+ * @ingroup FSOTG
+ * @{
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>    // For DMA directions
+//#include <linux/slab.h>
+#include <linux/errno.h>
+
+#include <linux/usb.h>
+#include <linux/delay.h>
+#include <asm/arch/mx2.h>
+
+#include <otg/otg-compat.h>
+
+#include "../core/hcd.h"
+
+#include <otg/usbp-chap9.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-utils.h>
+
+#include <otg/otg-hcd.h>
+#include <otg/hcd-l26.h>
+#include <otg/hcd-rh.h>
+#include <otg/hcd-hw.h>
+
+#include <otghw/fsotg-hardware.h>
+
+#ifndef CONFIG_OTG_ROOTHUB_VENDORID
+#define CONFIG_OTG_ROOTHUB_VENDORID 0x15ec
+#endif
+#ifndef CONFIG_OTG_ROOTHUB_PRODUCTID
+#define CONFIG_OTG_ROOTHUB_PRODUCTID 0xf010
+#endif
+#ifndef CONFIG_OTG_ROOTHUB_BCDDEVICE
+#define CONFIG_OTG_ROOTHUB_BCDDEVICE 0x0100
+#endif
+
+
+#define STATIC static
+extern void hcd_trace_mem(otg_tag_t tag, char *fn, char *msg, int len, volatile void *data);
+
+// Start of hardware specific components....
+
+/* ********************************************************************************************* */
+
+// Globals for debug
+static u32 monitoring_etd_mask = 0;  // 0 == no monitoring
+static u32 monitoring_etd_num;
+#define MAX_ETD_FRAMES 3
+static u32 current_etd_frame;
+static u32 done_flags[1+MAX_ETD_FRAMES];
+static u32 done_status[1+MAX_ETD_FRAMES];
+static endpoint_transfer_descriptor mon_etd[1+MAX_ETD_FRAMES];
+
+
+
+/*!
+ * @struct cc_name
+ * @brief Map CC values to names
+ */
+static char *cc_name[] = {
+        "no error", "CRC error", "bitstuff error", "data toggle error",
+        "stall", "device not responding", "PID failure" "reserved",
+        "data overrun", "data underrun", "ACK", "NAK", "buffer overrun",
+        "buffer underrun", "schedule overrun" "not accessed"
+};
+
+
+/*!
+ * comp_code_to_status() - map condition cod3 to errno value
+ * @param cc condition code
+ * @return errno value
+ */
+STATIC int comp_code_to_status(int cc)
+{
+        //
+        if (cc)
+                TRACE_MSG2(HCD,"NON-ZERO CC=%d %s", cc,cc_name[cc]);
+
+        switch (cc) {
+        case ETD_CC_NOERROR:           return 0;
+        case ETD_CC_CRCERR:            return -EILSEQ;
+        case ETD_CC_BITSTUFFERR:       return -EPROTO;
+        case ETD_CC_DATATOGERR:        return -EPROTO;  // I guess, nothing else looks better.
+        case ETD_CC_STALL:             return -EPIPE;
+        case ETD_CC_DEVNOTRESPONDING:  return -ETIMEDOUT;
+        case ETD_CC_PIDFAILURE:        return -EPROTO;
+        case ETD_CC_DATAOVERRUN:       return -EOVERFLOW;
+        case ETD_CC_DATAUNDERRUN:      return -EREMOTEIO;
+        case ETD_CC_ACK:               return -EPROTO;  // For lack of anything better
+        case ETD_CC_NAK:               return -EPROTO;  // For lack of anything better
+        case ETD_CC_BUFFEROVERRUN:     return -ECOMM;
+        case ETD_CC_BUFFERUNDERRUN:    return -ENOSR;
+        case ETD_CC_SCHEDOVERRUN:      return -ENOSPC;
+        case ETD_CC_NOTACCESSED:       return -EPROTO;  // For lack of anything better
+        default:                       return -EINVAL;
+        }
+}
+
+/*!
+ * rel_etd() - release etd
+ * {get,rel}_etd maintain a free list of ETDs by saving the index of the next free ETD in the
+ * etd->xbufsrtad field.  The list is terminated by 0x0000ffff.  List manipulation needs to be
+ * protected by irq_lock, since ETDs are released in the interrupt handler, but allocated at
+ * regular priority.
+ * @param fs_hcpriv
+ * @param etdn
+ */
+STATIC void rel_etd(fs_hcpriv *fs_hcpriv, int etdn)
+{
+        fs_wl(etd_word(etdn, 0), 0);
+        fs_wl(etd_word(etdn, 2), 0);
+        fs_wl(etd_word(etdn, 3), 0);
+        fs_wl(etd_word(etdn, 1), fs_hcpriv->free_etds);
+        fs_hcpriv->free_etds = etdn;
+}
+
+/*!
+ * get_etd() - get etd
+ * {get,rel}_etd maintain a free list of ETDs by saving the index of the next free ETD in the 
+ * etd->xbufsrtad field.  The list is terminated by 0x0000ffff.  List manipulation needs to be
+ * protected by irq_lock, since ETDs are released in the interrupt handler, but allocated at
+ * regular priority.
+ * @param fs_hcpriv
+ * @return int 
+ */
+STATIC int get_etd(fs_hcpriv *fs_hcpriv)
+{
+        // Return the index of an available ETD, or -1 if none are available.
+        unsigned long flags;
+        int etdn = -1;
+        local_irq_save(flags);
+        // Is list is empty?
+        if (0x0000ffff != (etdn = fs_hcpriv->free_etds)) 
+                fs_hcpriv->free_etds = fs_rl(etd_word(etdn, 1));
+        local_irq_restore(flags);
+        return etdn;
+}
+
+/* ********************************************************************************************* */
+/*
+ * For the generic transfer aware framework.
+ */
+
+// For debugging...
+static int num_urbs_started = 0;
+#define MAX_URBS_STARTED      0
+static char *dirpid_name[4] = {"SETUP","OUT","IN","WRONG"};
+//static char *direct_name[4] = {"TD00","OUT","IN","TD11"};
+static char *etd_urb_state_name[] = {"COMPLETED","SETUP_STATUS","SETUP_DATA","SETUP_PKT","BULK","INTERRUPT","ISOC","WRONG"};
+static char *format_name[4] = { "CONTROL", "ISO", "BULK", "INT", };
+
+
+/*!
+ * start_etd() - start an etd
+ * @param etdn
+ * @param len
+ * @param data
+ * @param out
+ */
+STATIC void start_etd(int etdn, int len, void *data, int out)
+{
+        if (len) {
+                consistent_sync(data,len, (out ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE));
+                fs_wl(OTG_DMA_ETD_MSA(etdn), virt_to_bus(data));
+        }
+        if (len || out) 
+                fs_wl(OTG_DMA_ETD_EN, ETD_MASK(etdn));
+        
+        fs_orl(OTG_HOST_IINT, ETD_MASK(etdn));                       // Don't wait until SOF, interrupt ASAP.
+        fs_orl(OTG_HOST_ETD_DONE, ETD_MASK(etdn));                   // Interrupt on ETD done (forget DMA interrupt).
+        fs_wl(OTG_HOST_ETD_EN, ETD_MASK(etdn));
+}
+
+/*!
+ * hcd_hw_start_transfer() - start a transfer
+ * Return 0..MAX_ACTIVE_XFERS-1 if the transfer is successfully started,
+ *       -1 if there is something wrong with the requested transfer,
+ *       -2 if there are no resources available at this time, but resubmission is OK. 
+ *
+ * @param bus_hcpriv    
+ * @param len           length of data region
+ * @param data          virtual address of data region
+ * @param toggle        toggle value to start the xfer with
+ * @param maxps         max packet size of endpoint
+ * @param slow          1 ==> slow speed, 0 ==> full speed  QQSV verify: (((urb->pipe) >> 26) & 1)
+ * @param endpoint      endpoint number
+ * @param address       USB device address
+ * @param pid           USB_PID_{OUT,IN,SETUP}
+ * @param format        PIPE_{CONTROL,BULK,INTERRUPT,ISOCHRONOUS}
+ * @param other         value depending on format
+ *
+ * PIPE_CONTROL:   other == address of setup packet.
+ * PIPE_BULK:      other == ZLP at end (T/F),
+ * PIPE_INTERRUPT: other == poll interval
+ */
+int hcd_hw_start_transfer(struct bus_hcpriv *bus_hcpriv, int len, void *data, int toggle, int maxps, 
+                int slow, int endpoint, int address, int pid, int format, u32 other)   
+{
+        fs_hcpriv *fs_hcpriv = (struct fs_hcpriv *) (bus_hcpriv->hw_hci);
+        fs_data_buff *x = NULL;
+        fs_data_buff *y = NULL;
+        int fmt = 0;
+        int out;
+        int etdn;
+        //int rc = 0;
+        int dir = 0;
+        endpoint_transfer_descriptor *sdp = NULL;
+        transfer_descriptor td;
+        int sdp_out = FALSE;
+
+        //TRACE_MSG8(HCD, "len: %d toggle: %d endpoint: %02x pid: %d format: %d address: %d %s %s",
+        //                len, toggle, endpoint, pid, format, address, dirpid_name[pid], format_name[format]);
+
+        // data address needs to be on a 32-bit boundary.
+        if (0x3 & (u32)data) {
+                printk(KERN_ERR "%s: invalid data alignment for urb, urb rejected.\n",__FUNCTION__);
+                TRACE_MSG1(HCD, "invalid data alignment for urb (%08x), urb rejected.",(u32)data);
+                return -1;
+        }
+        num_urbs_started += 1;
+        if ((MAX_URBS_STARTED > 0) && (num_urbs_started > MAX_URBS_STARTED)) {
+                // Can the urb, don't touch the HW
+                printk(KERN_ERR "%s: ignoring urb %d\n",__FUNCTION__,num_urbs_started);
+                return -1;
+        }
+        
+        /* Check pid, setup pid and out flags
+         */
+        switch (pid) {
+        case USB_PID_SETUP:
+                pid = ETD_DIRPID_SETUP;
+                out = TRUE;
+                break;
+        case USB_PID_OUT:
+                pid = ETD_DIRPID_OUT;
+                out = TRUE;
+                break;
+        case USB_PID_IN:
+                pid = ETD_DIRPID_IN;
+                out = FALSE;
+                break;
+        default:
+                TRACE_MSG1(HCD,"invalid PID %x",pid);
+                return -1;
+        }
+        switch (format) {
+        case PIPE_CONTROL:
+        case PIPE_BULK:
+        case PIPE_INTERRUPT:
+                td.w3.val = (ETD_SET_BUFSIZE(sizeof(fs_data_buff)-1) | ETD_SET_TOTBYECNT(len));
+                break;
+        default:
+                return -1;
+        }
+
+        /*
+         * 1. Allocate resources:
+         *    a. X,Y buffers
+         *    b. ETD (& matching DMA)
+         * 2. Set the registers
+         */
+        UNLESS ((x = get_data_buff(fs_hcpriv)) && (y = get_data_buff(fs_hcpriv)) && (0 <= (etdn = get_etd(fs_hcpriv)))) {
+                // Resource allocation failure, retry later is OK.
+                TRACE_MSG0(HCD,"resource allocation failure -> resubmit OK");
+                y = rel_data_buff(fs_hcpriv,y);
+                x = rel_data_buff(fs_hcpriv,x);
+                return -2;
+        }
+
+        // OK, we've got all we need.
+        td.w1.bufsrtad.y = data_buff_boff(y);
+        td.w1.bufsrtad.x = data_buff_boff(x);
+        
+        switch (format) {
+        case PIPE_CONTROL:
+                fmt = ETD_FORMAT_CONTROL;
+                dir = ETD_DIRECT_TD00;
+
+                /* build setup data/status phase ETD for use after completion of 8 byte setup packet
+                 */
+                fs_hcpriv->sdp_data[etdn] = data; // address of data phase buffer.
+                data = (void *) other;   // address of setup packet.
+                sdp = &fs_hcpriv->sdp_etd[etdn];
+                memset((void*)sdp, 0, sizeof(endpoint_transfer_descriptor));
+
+                /* toggle is constant 0 for setup packet, and 1 for data and status phases,
+                 * so toggle was overloaded to handle data phase direction.  If len == 0, there
+                 * is no data phase, so direction is IN. 
+                 */
+                sdp_out = (toggle && len > 0);
+                sdp->td.w1.val = td.w1.val;
+                sdp->td.w2.cb.flags = ETD_SET_DATATOGL((0x2|1)) |  // toggle is always 1, for data or status phases.
+                        ETD_SET_DELAYINT(0) |           // when done, interrupt ASAP (wait for 0 frames)
+                        ETD_SET_BUFROUND(1) |           // Allow short recv xfers
+                        ETD_SET_DIRPID((sdp_out?ETD_DIRPID_OUT:ETD_DIRPID_IN));
+                sdp->td.w2.cb.reserved = 0;
+                sdp->td.w2.cb.rtrydelay = 1;            // Number of frames to wait before retry on failure.
+                sdp->td.w3.val = ETD_SET_BUFSIZE(sizeof(fs_data_buff)-1) | ETD_SET_TOTBYECNT(len);
+
+                /* build SETUP ETD for initial 8 byte setup packet
+                 */
+                len = 8;
+                td.w2.cb.flags = ETD_SET_DATATOGL((0x2|0)) |  // starting toggle is here, not TOGCRY, and is always 0.
+                        ETD_SET_DELAYINT(0) |           // when done, interrupt ASAP (wait for 0 frames)
+                        ETD_SET_BUFROUND(1) |           // Allow short recv xfers
+                        ETD_SET_DIRPID(pid);
+                td.w2.cb.reserved = 0;
+                td.w2.cb.rtrydelay = 1;                 // Number of frames to wait before retry on failure.
+                td.w3.val = (ETD_SET_BUFSIZE(sizeof(fs_data_buff)-1) | ETD_SET_TOTBYECNT(len));
+
+                fs_hcpriv->etd_urb_state[etdn] = ETD_URB_SETUP_START;
+        
+                //TRACE_MSG3(HCD,"SETUP pkt, len=%d : %08x : %08x",len,*((u32*)(void*)data),*(1+(u32*)(void*)data));
+                
+                /* Complete the setup data phase ETD.
+                 */
+                sdp->epd = ETD_SET_MAXPKTSIZ(maxps) |
+                        ETD_SET_TOGCRY(0) |
+                        ETD_SET_FORMAT(ETD_FORMAT_BULK) |
+                        ETD_SET_SPEED((slow?ETD_SPEED_LOW:ETD_SPEED_FULL)) |
+                        ETD_SET_DIRECT(ETD_DIRECT_TD00) |
+                        ETD_SET_ENDPNT(endpoint) |
+                        ETD_SET_ADDRESS(address);
+       
+                break;
+
+        case PIPE_BULK:
+                fmt = ETD_FORMAT_BULK;
+                dir = ETD_DIRECT_TD00;
+
+                //TRACE_MSG1(HCD,"BULK, starting toggle %x",toggle);
+                td.w2.cb.flags = ETD_SET_DATATOGL((0x2|toggle)) |  // starting toggle is here, not TOGCRY
+                        ETD_SET_DELAYINT(0) |           // when done, interrupt ASAP (wait for 0 frames)
+                        ETD_SET_BUFROUND(1) |           // Allow short recv xfers
+                        ETD_SET_DIRPID(pid);
+                td.w2.cb.reserved = 0;
+                td.w2.cb.rtrydelay = 0;                 // Number of frames to wait before retry on failure.
+
+                /* Set the state to indicate if a trailing ZLP is required.
+                 */
+                fs_hcpriv->etd_urb_state[etdn] = ((other && out && 0 == 
+                                        (len % maxps)) ? ETD_URB_BULKWZLP_START : ETD_URB_BULK_START);
+                break;
+
+        case PIPE_INTERRUPT:
+                fmt = ETD_FORMAT_INTERRUPT;
+                dir = ETD_DIRECT_TD00;
+
+                //TRACE_MSG1(HCD,"INTERRUPT, starting toggle %x",toggle);
+                td.w2.intr.flags = ETD_SET_DATATOGL((0x2|toggle)) |  // starting toggle is here, not TOGCRY
+                        ETD_SET_DELAYINT(0) |           // when done, interrupt ASAP (wait for 0 frames)
+                        ETD_SET_BUFROUND(1) |           // Allow short recv xfers
+                        ETD_SET_DIRPID(pid);
+
+                td.w2.intr.relpolpos = (fs_rl(OTG_HOST_FRM_NUM) + 1) & 0xff;  // Start next frame
+
+                td.w2.intr.polinterv = other & 0xff;
+                fs_hcpriv->etd_urb_state[etdn] = ETD_URB_INTERRUPT_START;
+                break;
+
+        case PIPE_ISOCHRONOUS:
+                fmt = ETD_FORMAT_ISOC;
+                dir = out ? ETD_DIRECT_OUT : ETD_DIRECT_IN;
+                td.w2.isoc.startfrm = (fs_rl(OTG_HOST_FRM_NUM) + 1) & 0xffff;  // next frame
+                if (len > 1023) {
+                        // Two frames needed, send 1023 in the first, remainder in the second.
+                        td.w2.isoc.flags = ETD_SET_DELAYINT(0) | ETD_SET_AUTOISO(0) | ETD_SET_FRAMECNT(1);
+                        td.w3.isoc.pkt0 = ETD_SET_PKTLEN(1023);
+                        td.w3.isoc.pkt1 = ETD_SET_PKTLEN(len-1023);
+                } 
+                else {
+                        // Only one frame needed, send it all at once.
+                        td.w2.isoc.flags = ETD_SET_DELAYINT(0) | ETD_SET_AUTOISO(0) | ETD_SET_FRAMECNT(0);
+                        td.w3.isoc.pkt0 = ETD_SET_PKTLEN(len);
+                        td.w3.isoc.pkt1 = 0;
+                }
+                fs_hcpriv->etd_urb_state[etdn] = ETD_URB_ISOC_START;
+                break;
+        }
+
+        fs_wl(etd_word(etdn, 0), ETD_SET_MAXPKTSIZ(maxps) | ETD_SET_TOGCRY(0) | ETD_SET_FORMAT(fmt) |
+                        ETD_SET_SPEED((slow ? ETD_SPEED_LOW : ETD_SPEED_FULL)) |
+                        ETD_SET_DIRECT(dir) | ETD_SET_ENDPNT(endpoint) | ETD_SET_ADDRESS(address));
+
+        fs_wl(etd_word(etdn, 1), td.w1.val);
+        fs_wl(etd_word(etdn, 2), td.w2.val);
+        fs_wl(etd_word(etdn, 3), td.w3.val);
+
+        //TRACE_MSG5(HCD, "ETD[%02d] %08x %08x %08x %08x", etdn,
+        //                fs_rl(etd_word(etdn, 0)), fs_rl(etd_word(etdn, 1)),
+        //                fs_rl(etd_word(etdn, 2)), fs_rl(etd_word(etdn, 3)));
+
+        start_etd(etdn, len, data, out);
+        return etdn;
+}
+
+/*!
+ * finish_urb_irq() - called to complete transfer
+ * @param fs_hcpriv
+ * @param etdn
+ * @param killed
+ */
+STATIC void finish_urb_irq(fs_hcpriv *fs_hcpriv, int etdn, int killed)
+{
+        int cc = 0;
+        int next_toggle = 0;
+        int format = 0;
+        u32 remaining = 0;
+        fs_data_buff *x,*y;
+        endpoint_transfer_descriptor res;
+
+        TRACE_MSG5(HCD, "etdn=%d state=%d %s nus=%u %s", etdn, fs_hcpriv->etd_urb_state[etdn], 
+                        etd_urb_state_name[fs_hcpriv->etd_urb_state[etdn]], num_urbs_started, (killed?"KILLED":""));
+        
+        if (monitoring_etd_mask == ETD_MASK(etdn)) 
+                monitoring_etd_mask = 0;
+        
+
+        /* Disable/Abort DMA.  R1: sec 23.13.16 pg 23-103
+         * (supposed to auto-clear on DMA completion, but this shouldn't hurt). 
+         */
+        fs_wl(OTG_DMA_ETD_CH_CLR, ETD_MASK(etdn));
+
+        if (fs_rl(OTG_HOST_ETD_EN) & ETD_MASK(etdn)) 
+                fs_andl(OTG_HOST_ETD_EN, ~ETD_MASK(etdn));                // This register IS write 0 to disable.  Really.
+
+        if ( fs_rl(OTG_HOST_ETD_DONE) & ETD_MASK(etdn)) 
+                fs_andl(OTG_HOST_ETD_DONE, ~ETD_MASK(etdn));              // This register IS write 0 to disable.  Really.
+        
+                                                        // Hardware should have disabled ETD, but it doesn't hurt to check.
+        if (fs_rl(OTG_HOST_ETD_EN) & ETD_MASK(etdn)) 
+                fs_wl(OTG_HOST_ETD_EN, ETD_MASK(etdn));                   // This register IS write 1 to clear.  Really.
+
+        if (fs_rl(OTG_HOST_XINT_STAT) & ETD_MASK(etdn)) 
+                fs_wl(OTG_HOST_XINT_STAT, ETD_MASK(etdn));                // This register IS write 1 to clear.  Really.
+        
+        if (fs_rl(OTG_HOST_YINT_STAT) & ETD_MASK(etdn)) 
+                fs_wl(OTG_HOST_YINT_STAT, ETD_MASK(etdn));                // This register should be write 1 to clear.
+        
+
+        if (fs_rl(OTG_HOST_XYINT_STEN) & ETD_MASK(etdn)) 
+                fs_andl(OTG_HOST_XYINT_STEN, ~ETD_MASK(etdn));            // This register should be write 0 to disable.
+        
+        if (fs_rl(OTG_HOST_XFILL_STAT) & ETD_MASK(etdn)) 
+                fs_wl(OTG_HOST_XFILL_STAT, ETD_MASK(etdn));               // This register IS write 1 to clear.  Really.
+        
+        if (fs_rl(OTG_HOST_YFILL_STAT) & ETD_MASK(etdn)) 
+                fs_wl(OTG_HOST_YFILL_STAT, ETD_MASK(etdn));               // This register should be write 1 to clear.
+        
+
+        // Extract results
+        res.epd = fs_rl(etd_word(etdn, 0));
+        res.td.w1.val = fs_rl(etd_word(etdn, 1));
+        res.td.w2.val = fs_rl(etd_word(etdn, 2));
+        res.td.w3.val = fs_rl(etd_word(etdn, 3));
+
+        fs_wl(OTG_HOST_EP_DSTAT, ETD_MASK(etdn));
+
+        //TRACE_MSG1(HCD,"OTG_HOST_ETD_DONE: %08x", fs_rl(OTG_HOST_ETD_DONE));
+        
+        if ((ETD_URB_BULK_START == fs_hcpriv->etd_urb_state[etdn] || 
+                                (ETD_URB_BULKWZLP_START == fs_hcpriv->etd_urb_state[etdn])) &&
+                        (ETD_GET_DIRPID(res.td.w2.cb.flags) != ETD_DIRPID_IN)
+            ) 
+                TRACE_MSG4(HCD,"RES: epd: %08x w1: %08x w2: %08x w3: %08x", res.epd,res.td.w1.val,res.td.w2.val,res.td.w3.val);
+        
+        if (ETD_GET_HALTED(res.epd)) 
+                TRACE_MSG0(HCD,"endpoint HALTED");
+        
+        format = ETD_GET_FORMAT(res.epd);
+
+        switch (fs_hcpriv->etd_urb_state[etdn]) {
+        case ETD_URB_SETUP_START:
+                /* Just finished the setup packet.
+                 * Go to data or status phase of setup packet while we still have the ETD and data buffers allocated.
+                 */
+                if (!killed && ETD_CC_NOERROR == (cc = ETD_GET_COMPCODE(res.td.w2.cb.flags))) {
+
+                        endpoint_transfer_descriptor *sdp = &fs_hcpriv->sdp_etd[etdn];
+                        int len = ETD_GET_TOTBYECNT(sdp->td.w3.val);
+                        void *data = fs_hcpriv->sdp_data[etdn];
+                        fs_hcpriv->etd_urb_state[etdn] = ((len > 0) ? ETD_URB_SETUP_DATA : ETD_URB_SETUP_STATUS);
+
+                        // Copy into the active ETD and start it.
+                        fs_wl(etd_word(etdn, 0), sdp->epd);
+                        fs_wl(etd_word(etdn, 1), sdp->td.w1.val);
+                        fs_wl(etd_word(etdn, 2), sdp->td.w2.val);
+                        fs_wl(etd_word(etdn, 3), sdp->td.w3.val);
+                                                                                        // watch out for ETD_DIRPID_SETUP
+                        start_etd(etdn, len,data,(ETD_GET_DIRPID(sdp->td.w2.cb.flags)!=ETD_DIRPID_IN)); 
+                        TRACE_MSG1(HCD,"SETUP %s Phase started",((len > 0) ? "DATA" : "STATUS"));
+                        return;
+                }
+                /* Something is wrong, finish the URB as is.
+                 */
+                remaining = ETD_GET_TOTBYECNT(fs_rl(etd_word(etdn, 3)));
+                format = PIPE_CONTROL;
+                break;
+        
+        case ETD_URB_SETUP_DATA:
+                /* Go to status phase of setup packet while we still have the ETD and data buffers allocated.
+                 * Save the data phase length for after status.
+                 */
+                if (!killed && ETD_CC_NOERROR == (cc = ETD_GET_COMPCODE(res.td.w2.cb.flags))) {
+                        endpoint_transfer_descriptor *sdp = &fs_hcpriv->sdp_etd[etdn];
+                        fs_hcpriv->sdp_data[etdn] = (void *) ETD_GET_TOTBYECNT(res.td.w3.val); 
+                        fs_hcpriv->etd_urb_state[etdn] = ETD_URB_SETUP_STATUS;
+
+                        /* Rebuild data phase sdp for status phase with opposite direction, and 0 length. 
+                         */
+                        
+                        sdp->td.w2.cb.flags = ETD_FLIP_DIRPID(sdp->td.w2.cb.flags);
+                        sdp->td.w3.val = (ETD_SET_BUFSIZE(sizeof(fs_data_buff)-1) | ETD_SET_TOTBYECNT(0));
+
+                        /* Copy into the active ETD and start it.
+                         */
+                        fs_wl(etd_word(etdn, 0), sdp->epd);
+                        fs_wl(etd_word(etdn, 1), sdp->td.w1.val);
+                        fs_wl(etd_word(etdn, 2), sdp->td.w2.val);
+                        fs_wl(etd_word(etdn, 3), sdp->td.w3.val);
+                        start_etd(etdn, 0,NULL,(ETD_GET_DIRPID(sdp->td.w2.cb.flags)!=ETD_DIRPID_IN));
+                        TRACE_MSG0(HCD,"SETUP STATUS Phase started");
+                        return;
+                }
+                // Something is wrong, finish the URB as is.
+                remaining = ETD_GET_TOTBYECNT(res.td.w3.val);
+                format = PIPE_CONTROL;
+                break;
+
+        case ETD_URB_SETUP_STATUS:
+                cc = ETD_GET_COMPCODE(res.td.w2.cb.flags);
+                // Fetch saved length.
+                remaining = (u32) fs_hcpriv->sdp_data[etdn];
+                format = PIPE_CONTROL;
+                break;
+
+        case ETD_URB_BULKWZLP_START:
+                // Need a trailing ZLP.
+                next_toggle = ETD_GET_TOGCRY(res.epd);
+                if (!killed && ETD_CC_NOERROR == ETD_GET_COMPCODE(res.td.w2.cb.flags)) {
+                        // Since TOTBYECNT should be 0, re-enabling the same ETD ought to give a ZLP.
+                        fs_hcpriv->etd_urb_state[etdn] = ETD_URB_BULKWZLP;
+                                                                                // Save the data phase length for after ZLP.
+                        // fs_hcpriv->sdp_data[etdn] = (void *) ETD_GET_TOTBYECNT(res.td.w3.val); 
+                        // FIXME - verify toggle OK
+                        
+                        start_etd(etdn, 0,NULL,TRUE/*always OUT*/);
+
+                        TRACE_MSG0(HCD,"ZLP started");
+                        return;
+                }
+                // Something is wrong, finish the URB as is.
+                remaining = ETD_GET_TOTBYECNT(res.td.w3.val);
+                format = PIPE_BULK;
+                break;
+
+        case ETD_URB_BULKWZLP:
+                // Trailing ZLP now finished.
+                cc = ETD_GET_COMPCODE(res.td.w2.cb.flags);
+                next_toggle = ETD_GET_TOGCRY(res.epd);
+                // Fetch saved length (it was zero, or we wouldn't be here).
+                remaining = 0;
+                format = PIPE_BULK;
+                break;
+
+        case ETD_URB_BULK_START:
+                cc = ETD_GET_COMPCODE(res.td.w2.cb.flags);
+                next_toggle = ETD_GET_TOGCRY(res.epd);
+                remaining = ETD_GET_TOTBYECNT(res.td.w3.val);
+                format = PIPE_BULK;
+                break;
+
+        case ETD_URB_INTERRUPT_START:
+                cc = ETD_GET_COMPCODE(res.td.w2.intr.flags);
+                remaining = ETD_GET_TOTBYECNT(res.td.w3.val);
+                format = PIPE_INTERRUPT;
+                break;
+
+        case ETD_URB_ISOC_START:
+                // This probably needs more work, best guess only here.
+                remaining = ETD_GET_PKTLEN(res.td.w3.isoc.pkt0);
+                cc = ETD_GET_COMPCODE(res.td.w3.isoc.pkt0);
+                if (ETD_GET_FRAMECNT(res.td.w2.isoc.flags)) {
+                        // There were two packets in this transfer
+                        remaining += ETD_GET_PKTLEN(res.td.w3.isoc.pkt1);
+                }
+                format = PIPE_ISOCHRONOUS;
+        }
+
+        fs_hcpriv->etd_urb_state[etdn] = ETD_URB_COMPLETED;
+
+        /* Convert completion code to HW independent value.
+         */
+        if (killed) {
+                cc = -ENOENT;
+                remaining = 0;
+        }
+        else 
+                cc = comp_code_to_status(cc);
+        
+        /* Return ETD and X,Y buffers to free list.
+         */
+        y = data_buff_addr(res.td.w1.bufsrtad.y);
+        x = data_buff_addr(res.td.w1.bufsrtad.x);
+        y = rel_data_buff(fs_hcpriv,y);
+        x = rel_data_buff(fs_hcpriv,x);
+        rel_etd(fs_hcpriv, etdn);
+
+        /* Forward results to the layers above.
+         */
+        //TRACE_MSG4(HCD,"completing urb on ETD %d cc=%d remaining=%d next_toggle=%d", etdn, cc, remaining,next_toggle);
+        hcd_transfer_complete(fs_hcpriv->bus_hcpriv, etdn, format, cc, remaining, next_toggle);
+}
+
+/*!
+ * hcd_hw_unlink_urb() - unlink urb
+ * Called in irq_lock
+ * @param bus_hcpriv
+ * @param u
+ */
+int hcd_hw_unlink_urb(struct bus_hcpriv *bus_hcpriv, int u)
+{
+        unsigned long flags;
+        struct fs_hcpriv *fs_hcpriv;
+        RETURN_EINVAL_UNLESS ((fs_hcpriv = (struct fs_hcpriv *) bus_hcpriv->hw_hci));
+        local_irq_save(flags);
+        finish_urb_irq(fs_hcpriv, u, TRUE);
+        local_irq_restore(flags);
+        return 0;
+}
+
+/*!
+ * hcd_hw_frame_number() - return current frame number
+ * @param bus_hcpriv
+ * @return u32 ???
+ */
+u32 hcd_hw_frame_number(struct bus_hcpriv *bus_hcpriv)
+{
+        return(fs_rl(OTG_HOST_FRM_NUM));
+}
+
+/* ********************************************************************************************* */
+
+/*!
+ * MX21_PORT_CHANGED() - send otg event information to state machine
+ * @param name
+ * @param cs
+ * @param changed
+ * @param status
+ * @param set
+ * @param reset
+ */
+void MX21_PORT_CHANGED(char *name, u32 cs, u32 changed, u32 status, u64 set, u64 reset)
+{
+        RETURN_UNLESS(cs & changed);
+        TRACE_MSG2(HCD, "%s%s", name, (cs & (1 << status)) ? "" : "/");
+        if (cs & (1 << status) && set)
+                otg_event(hcd_instance->otg, set, HCD, name);
+        if (!(cs & (1 << status)) && reset)
+                otg_event(hcd_instance->otg, reset, HCD, name);
+}
+
+/*!
+ * update_shadow_rh() - Update shadow _status_ info (change info already updated).
+ * @param bus_hcpriv
+ * @param port_num - 1-N based port number
+ * @param cs
+ *
+ */
+STATIC void update_shadow_rh(struct bus_hcpriv *bus_hcpriv, int port_num, u32 cs)
+{
+        u32 msk_and = 0;  // bits to turn off
+        u32 msk_or = 0;   // bits to turn on
+
+        TRACE_MSG2(HCD,"port: %d cs: %08x", port_num, cs);
+
+        /* PORT_STATUS_PRTRSTSC (20) - PORT_RESET (4) changed
+         * PORT_RESET (4) status change, end of reset, PORT_ENABLE may (should) be on.
+         */
+        MX21_PORT_CHANGED("PORT_RESET", cs, PORT_STATUS_PRTRSTSC, PORT_RESET, 
+                        BUS_RESET, BUS_RESET_);
+
+        if (cs & (1 << C_PORT_RESET)) {
+                TRACE_MSG1(HCD,"port: %d PORT_RESET complete (s.b. enabled)", port_num);
+                if (cs & (1 << PORT_ENABLE)) {
+                        TRACE_MSG1(HCD,"port: %d enabled", port_num);
+                        //otg_write_info_message("port update C_PORT_RESET");
+                        msk_or |= (1 << PORT_ENABLE);
+                }
+                else {
+                        TRACE_MSG1(HCD,"port: %d NOT enabled!!!", port_num);
+                        //otg_write_info_message("update C_PORT_RESET/");
+                }
+
+                /* Clear the PORT_RESET bit too, since it's over.
+                 */
+                msk_and |= (1 << PORT_RESET);
+                bus_hcpriv->rh_hcpriv->hub_port_change_status |= (1 << port_num);
+        }
+
+        /* PORT_OVER_CURRENT (3) bit has changed (either direction).
+         * PORT_STATUS_OVRCURIC (19) - PORT_OVER_CURRENT (3) changed
+         */
+        MX21_PORT_CHANGED("PORT_OVER_CURRENT", cs, PORT_STATUS_OVRCURIC, PORT_OVER_CURRENT, (u64) 0, (u64) 0);
+        if (cs & (1 << C_PORT_OVER_CURRENT)) {
+                /* OVER_CURRENT has come on.
+                 */
+                if (cs & (1 << PORT_OVER_CURRENT)) {
+                        TRACE_MSG1(HCD,"port: %d over current ON", port_num);
+                        msk_or |= (1 << PORT_OVER_CURRENT);
+                } 
+                /* OVER_CURRENT has gone away.
+                 */
+                else {
+                        TRACE_MSG1(HCD,"port: %d over current OFF", port_num);
+                        msk_and |= (1 << PORT_OVER_CURRENT);
+                }
+                bus_hcpriv->rh_hcpriv->hub_port_change_status |= (1 << port_num);
+        }
+
+        /* PORT_SUSPEND (2) Resume sequence has completed....
+         * PORT_STATUS_PRTSTATSC (18) - PORT_SUSPEND (2) changed
+         */
+        MX21_PORT_CHANGED("PORT_SUSPEND", cs, PORT_STATUS_PRTSTATSC, PORT_SUSPEND, 
+                        BUS_SUSPENDED, BUS_SUSPENDED_);
+
+        if (cs & (1 << C_PORT_SUSPEND)) {
+                // FIXME - figure this out when we get to suspend/resume....
+
+        }
+
+
+        /* PORT_ENABLE (1) has been __cleared__ by some HW event
+         * PORT_STATUS_PRTENBLSC (17) - PORT_ENABLE (1) changed
+         */
+        MX21_PORT_CHANGED("PORT_ENABLE", cs, PORT_STATUS_PRTENBLSC, PORT_ENABLE, (u64) 0, (u64) 0);
+        if (cs & (1 << C_PORT_ENABLE)) {
+                //otg_write_info_message("update C_PORT_ENABLE");
+                TRACE_MSG1(HCD,"port: %d disabled (by HW)", port_num);
+                if (!(cs & (1 << PORT_ENABLE))) 
+                        msk_and |= ( 1 << PORT_ENABLE);
+                bus_hcpriv->rh_hcpriv->hub_port_change_status |= (1 << port_num);
+        }
+
+        /* PORT_CONNECTION (0) bit has changed (either direction).
+         * PORT_STATUS_CONNECTSC (16) - PORT_CONNECTION (0) changed
+         */
+        MX21_PORT_CHANGED("PORT_CONNECTION", cs, PORT_STATUS_CONNECTSC, PORT_CONNECTION, 
+                        HUB_PORT_CONNECT, HUB_PORT_CONNECT_ );
+
+        if (cs & (1 << C_PORT_CONNECTION)) {
+                /* CONNECT has come on.
+                 */
+                if (cs & (1 << PORT_CONNECTION)) {
+                        TRACE_MSG1(HCD,"port: %d new connection", port_num);
+                        msk_or |= (1 << PORT_CONNECTION);
+                        if (cs & (1 << PORT_LOW_SPEED)) {
+                                TRACE_MSG1(HCD,"port: %d low speed device", port_num);
+                                msk_or |= (1 << PORT_LOW_SPEED);
+                        }
+                        //otg_write_info_message("update PORT_CONNECTION");
+                        //printk(KERN_INFO"%s: AAA\n", __FUNCTION__);
+                        //otg_event(hcd_instance->otg, HUB_PORT_CONNECT, HCD, "HUB_PORT_CONNECT (mx21 hw)");
+                        //printk(KERN_INFO"%s: BBB\n", __FUNCTION__);
+                } 
+                /* CONNECT has gone away.
+                 */
+                else {
+                        TRACE_MSG1(HCD,"port: %d disconnection", port_num);
+                        //otg_write_info_message("update PORT_CONNECTION/");
+                        msk_and |= (1 << PORT_CONNECTION) | (1 << PORT_LOW_SPEED);
+                        //otg_event(hcd_instance->otg, HUB_PORT_CONNECT_, HCD, "HUB_PORT_CONNECT/ (mx21 hw)");
+                }
+                bus_hcpriv->rh_hcpriv->hub_port_change_status |= (1 << port_num);
+                //printk(KERN_INFO"%s: CCC\n", __FUNCTION__);
+        }
+
+        TRACE_MSG5(HCD, "port: %d shadow port_change_status: ((%08x & ~%04x) | %04x) hpcs: %04x",
+                        port_num, bus_hcpriv->rh_hcpriv->port_change_status[port_num - 1], 
+                        msk_and, msk_or, bus_hcpriv->rh_hcpriv->hub_port_change_status);
+}
+
+/* ********************************************************************************************* */
+static int num_host_interrupts = 0;
+#define MAX_HOST_INTERRUPTS  0
+static int num_psc_interrupts = 0;
+#define MAX_PSC_INTERRUPTS  0
+
+extern struct bus_hcpriv fs_bus_hcpriv;
+
+/*!
+ * hcd_hw_int_hndlr() - interrupt handler for hcd controller
+ * @param irq
+ * @param dev_id
+ * @param regs
+ */
+irqreturn_t hcd_hw_int_hndlr(int irq, void *dev_id, struct pt_regs *regs)
+{
+        struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *) &fs_bus_hcpriv;
+        struct fs_hcpriv *fs_hcpriv = (struct fs_hcpriv *) bus_hcpriv->hw_hci;
+        u32 host_sint;                                  // C.f. 23.11.11 Host Interrupt Register
+
+        if (OTG_USBDMA == irq) {
+                // HOST DMA error interrupt
+                u32 err_stat = fs_rl(OTG_DMA_ETD_ERR);
+                TRACE_MSG1(HCD,"host DMA interrupt, error status %08x",err_stat);
+                if (0 != err_stat) {
+                        // Disable the matching DMA channels and clear the interrupt
+                        fs_wl(OTG_DMA_ETD_CH_CLR, err_stat);
+                        fs_wl(OTG_DMA_ETD_ERR, err_stat);
+                }
+                // local_irq_restore(flags);
+                return IRQ_HANDLED;
+        }
+
+        /* FIXME - should check fs_hcpriv->mm->otg.OTG_Module_Interrupt_Status & (0x1 << 3) | 0x1;
+         * for Host (async + regular) Interrupt - enable clock on async. 
+         */
+
+        num_host_interrupts += 1;
+        if (MAX_HOST_INTERRUPTS > 0 && num_host_interrupts > MAX_HOST_INTERRUPTS) {
+                // Host (async + regular) Interrupt Disable
+                
+                fs_wl(OTG_HOST_SINT_STEN, 0);
+                fs_andl(OTG_CORE_CINT_STEN, ~(/*(0x1 << 3) |*/ 0x1));  
+        }
+
+        while ((host_sint = fs_rl(OTG_HOST_SINT_STAT))) {
+
+                while (HOST_DONEINT & host_sint) {
+                        u32 etds_done;
+
+                        TRACE_MSG1(HCD,"HOST_DONEINT: %08x", fs_rl(OTG_HOST_EP_DSTAT));
+                        fs_wl(OTG_HOST_SINT_STAT, HOST_DONEINT);
+                        host_sint = fs_rl(OTG_HOST_SINT_STAT);
+                        while ((etds_done = fs_rl(OTG_HOST_EP_DSTAT))) 
+                                finish_urb_irq(fs_hcpriv, fls(etds_done) - 1, FALSE);
+                }
+
+                host_sint = fs_rl(OTG_HOST_SINT_STAT);
+
+                /* Start Of Frame.
+                 * Note: this interrupt seems to happen even if disabled when there is a frame number overflow.
+                 */
+                if (host_sint & HOST_SOFINT) {
+                        if (0 == (fs_hcpriv->sof_count & (4096 - 1))) {
+                                TRACE_MSG1(HCD,"SOF %08lx",fs_hcpriv->sof_count);
+                        }
+                        fs_hcpriv->sof_count += 1;
+                        if (monitoring_etd_mask != 0) {
+                                // This ETD needs to be watched....
+                                current_etd_frame += 1;
+                                
+                                done_flags[current_etd_frame] = fs_rl(OTG_HOST_ETD_EN);
+                                done_status[current_etd_frame] = fs_rl(OTG_HOST_EP_DSTAT);
+
+                                mon_etd[current_etd_frame].epd = fs_rl(etd_word(monitoring_etd_num, 0));
+                                mon_etd[current_etd_frame].td.w1.val = fs_rl(etd_word(monitoring_etd_num, 1));
+                                mon_etd[current_etd_frame].td.w2.val = fs_rl(etd_word(monitoring_etd_num, 2));
+                                mon_etd[current_etd_frame].td.w3.val = fs_rl(etd_word(monitoring_etd_num, 3));
+
+                                if (current_etd_frame >= MAX_ETD_FRAMES) {
+                                        // This has taken too long!
+                                        int i,u;
+                                        u = ((mon_etd[0].td.w3.val == mon_etd[1].td.w3.val) &&
+                                             (mon_etd[1].td.w3.val == mon_etd[2].td.w3.val) &&
+                                             (mon_etd[2].td.w3.val == mon_etd[3].td.w3.val));
+
+                                        TRACE_MSG5(HCD,"SOF: OUT urb TIMEOUT at %d/%d frames, mask: %08x num=%u u=%d",
+                                                  current_etd_frame,MAX_ETD_FRAMES,monitoring_etd_mask,monitoring_etd_num,u);
+
+                                        for (i = 0; i <= MAX_ETD_FRAMES; i++) 
+                                                TRACE_MSG7(HCD,"SOF: %d epd: %08x w1: %08x w2: %08x w3: %08x ef: %08x st: %08x",
+                                                                i, mon_etd[i]. epd, mon_etd[i]. td.w1.val, mon_etd[i].td.w2.val,
+                                                                mon_etd[i].td.w3.val, done_flags[i], done_status[i]);
+                                        // Disable monitoring by killing the urb.  FUTURE, look into restarting it.
+                                        finish_urb_irq(fs_hcpriv, monitoring_etd_num,TRUE);
+                                }
+                        }
+                }
+
+                /* Frame Number Overflow.
+                 */
+                if (host_sint & HOST_FMOFINT) {
+                        //TRACE_MSG0(HCD,"Frame Number Overflow");
+                        //printk(KERN_ERR "%s: Frame Number Overflow\n",__FUNCTION__);
+                }
+
+                /* Port Status Change.
+                 */
+                if (host_sint & HOST_PSCINT) {
+                        int port_num;
+                        num_psc_interrupts += 1;
+
+                        /* Clear the interrupt by clearing the port(s) in question.
+                         * Reflect any changes in the shadow values. 
+                         */
+                        for (port_num = 1; port_num <= bus_hcpriv->num_ports; port_num++) {
+
+                                u32 cs = fs_rl(fs_host_port_stat(port_num));  
+                                u32 cm = cs & 0xFFFF0000;
+
+                                CONTINUE_UNLESS (cm);
+                                fs_wl(fs_host_port_stat(port_num), cm);
+                                bus_hcpriv->rh_hcpriv->port_change_status[port_num - 1] |= cm;
+                                update_shadow_rh(bus_hcpriv, port_num, cs);
+                        }
+
+                        /* Tell the RH to scan for changes in shadow data. (schedule bottom half handler)
+                         */
+                        hcd_rh_int_hndlr(irq,bus_hcpriv,NULL);
+                }
+
+                /* Overrun
+                 */
+                if (host_sint & (HOST_SORINT | HOST_HERRINT)) {
+                        if (host_sint & HOST_SORINT) {
+                                TRACE_MSG0(HCD,"Scheduling Overrun");
+                                printk(KERN_ERR "%s: Scheduling Overrun\n",__FUNCTION__);
+                        }
+                        if (host_sint & HOST_HERRINT) {
+                                TRACE_MSG0(HCD,"Host Scheduling Error");
+                                printk(KERN_ERR "%s: Host Scheduling Error\n",__FUNCTION__);
+                        }
+                }
+                /* Resume Detected.
+                 */
+                if (host_sint & HOST_RESDETINT) {
+                        TRACE_MSG0(HCD,"Resume Detected");
+                }
+                /* Clear by writing back the ones we've checked for since the last read.
+                 */
+                fs_wl(OTG_HOST_SINT_STAT, host_sint & (HOST_RESDETINT | HOST_FMOFINT | HOST_SORINT | 
+                                HOST_HERRINT | HOST_PSCINT | HOST_SOFINT));
+        }
+        return IRQ_HANDLED;
+}
+
+/* ********************************************************************************************* */
+
+
+/*!
+ * hcd_hw_rh_hub_attributes() - get root hub attributes
+ * These provide access to the real root hub.
+ * @param bus_hcpriv
+ */
+u16 hcd_hw_rh_hub_attributes(struct bus_hcpriv *bus_hcpriv)
+{
+        // R1: sec 23.11.27
+        return 0xFFFF & (fs_rl(OTG_HOST_ROOTHUB_DESCA) >> 8);
+}
+
+/*!
+ * hcd_hw_rh_power_delay() - get power delay attributes
+ * These provide access to the real root hub.
+ * @param bus_hcpriv
+ */
+u8 hcd_hw_rh_power_delay(struct bus_hcpriv *bus_hcpriv)
+{
+        // R1: sec 23.11.27
+        return fs_rl(OTG_HOST_ROOTHUB_DESCA) >> 24;
+}
+
+/*!
+ * hcd_hw_rh_contr_current() - get contr current attributes
+ * These provide access to the real root hub.
+ * @param bus_hcpriv
+ */
+u8 hcd_hw_rh_hub_contr_current(struct bus_hcpriv *bus_hcpriv)
+{
+        return 0x0;
+}
+
+/*!
+ * hcd_hw_rh_DeviceRemovalbe() - get DeviceRemovalbe attributes
+ * These provide access to the real root hub.
+ * @param bus_hcpriv
+ */
+u8 hcd_hw_rh_DeviceRemovable(struct bus_hcpriv *bus_hcpriv)
+{
+        // USB2.0 pg 418 ==> bit 0 reserved, 1..7 for ports
+        // R1: sec 23.11.28
+        return 0xFF & fs_rl(OTG_HOST_ROOTHUB_DESCB);
+}
+
+/*!
+ * hcd_hw_rh_PortPwrCtrlMask() - get DeviceRemovalbe attributes
+ * These provide access to the real root hub.
+ * @param bus_hcpriv
+ */
+u8 hcd_hw_rh_PortPwrCtrlMask(struct bus_hcpriv *bus_hcpriv)
+{
+        // USB2.0 pg 418 ==> all 1s???  QQSV
+        // R1: sec 23.11.28
+        return 0xFF & fs_rl(OTG_HOST_ROOTHUB_DESCB);
+}
+
+
+/*!
+ * hcd_hw_rh_get_hub_change_status() - get change status
+ * These provide access to the real root hub.
+ * @param bus_hcpriv
+ */
+u32 hcd_hw_rh_get_hub_change_status(struct bus_hcpriv *bus_hcpriv)
+{
+        // R1: sec 23.11.29 pg 23-62, USB2.0 11.24.2.6 pg 425
+        return fs_rl(OTG_HOST_ROOTHUB_STATUS & (ROOTHUB_STATUS_LOCPWRSC | ROOTHUB_STATUS_DEVCONWUE |
+                                      ROOTHUB_STATUS_OVRCURI | ROOTHUB_STATUS_LOCPWRS));
+}
+
+/*!
+ * hcd_hw_rh_hub_feature() - get hub feature
+ * These provide access to the real root hub.
+ * @param bus_hcpriv
+ * @param feat_selector
+ * @param set_flag
+ */
+void hcd_hw_rh_hub_feature(struct bus_hcpriv *bus_hcpriv, int feat_selector, int set_flag)
+{
+        if (set_flag) {
+                // SET feature USB2.0 11.24.2.12 pg 434 and USB2.0 11.24.2 tbl 11-17 pg 421
+                // R1: sec 23.11.29 pg 23-62
+                switch (feat_selector) {
+                // case C_HUB_OVER_CURRENT: MX21 doesn't support SW setting the over current feature
+                // case C_HUB_LOCAL_POWER: MX21 doesn't support local power
+                default:
+                        // Error, but ignore.
+                        TRACE_MSG1(HCD,"SET invalid feature %d",feat_selector);
+                        break;
+                }
+        } 
+        else {
+                // CLEAR feature USB2.0 11.24.2.1 pg 422 and USB2.0 11.24.2 tbl 11-17 pg 421
+                // R1: sec 23.11.29 pg 23-62
+                switch (feat_selector) {
+                case C_HUB_OVER_CURRENT:
+                        fs_wl(OTG_HOST_ROOTHUB_STATUS, ROOTHUB_STATUS_OVRCURCHG);
+                        break;
+
+                // case C_HUB_LOCAL_POWER: MX21 doesn't support local power
+                default:
+                        // Error, but ignore.
+                        TRACE_MSG1(HCD,"CLEAR invalid feature %d",feat_selector);
+                        break;
+                }
+        }
+}
+
+/*!
+ * hcd_hw_rh_get_port_change_status() - get port change status
+ * R1: High 16 bits == change, low 16 == status 
+ * Change & Status bits in register match USB2.0 spec on (read).
+ * @param bus_hcpriv
+ * @param wIndex is 1-origin
+ */
+u32 hcd_hw_rh_get_port_change_status(struct bus_hcpriv *bus_hcpriv, int wIndex)
+{
+        u32 port_status = fs_rl(fs_host_port_stat(wIndex));
+
+        TRACE_MSG8(HCD,"port %d cs: %08lx %s %s %s %s %s %s", 
+                        wIndex, port_status,
+                        port_status & PORT_STATUS_CONNECTSC ? "CHANGE" : "", 
+                        port_status & PORT_STATUS_PRTPWRST ? "POWER" : "", 
+                        port_status & PORT_STATUS_PRTRSTST ? "RESET" : "", 
+                        port_status & PORT_STATUS_PRTSUSPST ? "SUSPEND" : "", 
+                        port_status & PORT_STATUS_PRTENABST ? "ENABLE" : "", 
+                        port_status & PORT_STATUS_CURCONST ? "CONNECT" : ""
+                        );
+
+        return fs_rl(fs_host_port_stat(wIndex));
+}
+
+extern char *port_feature_name[];
+
+/*!
+ * hcd_hw_rh_port_feature() - get rh port feature
+ * @param bus_hcpriv
+ * @param wValue is feature selector
+ * @param wIndex is port number (1-N)
+ * @param set_flag
+ */
+void hcd_hw_rh_port_feature(struct bus_hcpriv *bus_hcpriv, u16 wValue, u16 wIndex, int set_flag)
+{
+        char buf[64];
+        sprintf(buf, "port feature %s %s", port_feature_name[wValue], set_flag ? "SET" : "RESET");
+        //otg_write_info_message(buf);
+
+        TRACE_MSG4(HCD, "mx21 %s (%d) %s port_stat: %8x", port_feature_name[wValue], wValue, set_flag ? "SET" : "RESET",
+                        fs_rl(fs_host_port_stat(wIndex)));
+        if (set_flag) {
+                // SET feature
+                switch (wValue) {
+                case PORT_SUSPEND:
+                        otg_event(hcd_instance->otg, BUS_SUSPENDED, HCD, "HUB_PORT_SUSPEND (mx21 hw)");
+                        fs_wl(fs_host_port_stat(wIndex), 1 << wValue);
+                        break;
+                case PORT_RESET:
+                case PORT_POWER:
+                        fs_wl(fs_host_port_stat(wIndex), 1 << wValue);
+                        break;
+                default:
+                        // Error, but ignore.
+                        TRACE_MSG2(HCD,"SET port %d invalid feature %d", wIndex, wValue);
+                        break;
+                }
+        } 
+        else {
+                // CLEAR feature (valid features from USB2.0 11.24.2.2 pg 423).
+                switch (wValue) {
+                case PORT_SUSPEND:              // Cause a Host initiated resume, or no-op if already active.
+                        wValue++;               // yes, really. this clears PORT_SUSPEND 
+                        fs_wl(fs_host_port_stat(wIndex), 1 << wValue);
+                        otg_event(hcd_instance->otg, BUS_SUSPENDED_, HCD, "HUB_PORT_SUSPEND/ (mx21 hw)");
+                        break;
+
+                case PORT_POWER:                // Put port in powered-off state.
+                        wValue++;               // yes, really. this clears PORT_POWER 
+                        fs_wl(fs_host_port_stat(wIndex), 1 << wValue);
+                        break;
+
+                case PORT_ENABLE:               // Disable port.
+                        //wValue--;
+                        break;
+                default:
+                        break;
+                }
+                switch (wValue) {
+                case PORT_POWER:                // Put port in powered-off state.
+                case PORT_SUSPEND:              // Cause a Host initiated resume, or no-op if already active.
+                case PORT_ENABLE:               // Disable port.
+                case PORT_INDICATOR:            // ind_selector gives which indicator to clear
+                case C_PORT_SUSPEND:            // clear the PORT_SUSPEND change bit
+                case C_PORT_CONNECTION:         // clear the PORT_CONNECTION change bit
+                case C_PORT_RESET:              // clear the PORT_RESET change bit
+                case C_PORT_ENABLE:             // clear the PORT_ENABLE change bit
+                case C_PORT_OVER_CURRENT:       // clear the PORT_OVERCURRENT change bit
+                        fs_wl(fs_host_port_stat(wIndex), 1 << wValue);
+                        break;
+                default:
+                        // Error, but ignore.
+                        TRACE_MSG2(HCD,"CLEAR port %d invalid feature %d", wIndex, wValue);
+                        break;
+                }
+        }
+
+        TRACE_MSG3(HCD, "mx21 %s %s port_stat: %8x", port_feature_name[wValue], set_flag ? "SET" : "RESET",
+                        fs_rl(fs_host_port_stat(wIndex)));
+}
+
+/* ********************************************************************************************* */
+/* Hardware Initialization - this is used by the OTG state machine to 
+ * enable and disable the host controller hardware
+ */
+void rh_hcd_en_func(struct otg_instance *otg, u8 flag);
+
+extern void fs_host_clock_on(void);
+extern void fs_host_clock_off(void);
+
+/*!
+ * fs_hcd_en_func() - otg hcd enable output function
+ * @param otg
+ * @param flag
+ */
+void fs_hcd_en_func(struct otg_instance *otg, u8 flag)
+{
+        struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *)(((struct hcd_instance *)(otg->hcd))->privdata);
+        fs_hcpriv *fs_hcpriv = bus_hcpriv->hw_hci;
+        int i;
+        u32 hwmode = fs_rl(OTG_CORE_HWMODE);
+        unsigned long flags;
+
+        /* puts OTG capable port into a state where host is enabled */
+
+        fs_andl(OTG_CORE_HWMODE, 0xffffff0f);                  // clear
+
+        switch (flag) {
+        case SET:
+                local_irq_save(flags);
+                printk(KERN_INFO"%s: SET\n", __FUNCTION__);
+                if (hwmode & MODULE_CRECFG_HOST) {
+                        printk(KERN_INFO"%s: warning FUNC STILL SET\n", __FUNCTION__);
+                }
+                //printk(KERN_INFO"%s: SET\n", __FUNCTION__);
+                fs_orl(OTG_CORE_HWMODE, MODULE_CRECFG_HOST);           // set to software hnp
+                local_irq_restore(flags);
+                break;
+        case RESET:
+                local_irq_save(flags);
+                printk(KERN_INFO"%s: RESET\n", __FUNCTION__);
+                fs_andl(OTG_CORE_HWMODE, ~MODULE_CRECFG_HOST);           // set to software hnp
+                local_irq_restore(flags);
+                break;
+        }
+
+        TRACE_MSG1(HCD, "HWMODE: %08x", fs_rl(OTG_CORE_HWMODE));
+}
+
+
+void rh_loc_sof_func(struct otg_instance *otg, u8 flag);
+void rh_loc_suspend_func(struct otg_instance *otg, u8 flag);
+
+/*!
+ * fs_loc_suspend() - otg loc suspend output function
+ * @param otg
+ * @param flag
+ */
+void fs_loc_suspend_func(struct otg_instance *otg, u8 flag)
+{
+        unsigned long flags;
+        switch (flag) {
+        case SET:
+                
+                fs_orl(OTG_HOST_CONTROL, HOST_CONTROL_HCUSBSTE_SUSPEND);
+                break;
+
+        case RESET:
+                break;
+        }
+
+        rh_loc_suspend_func(otg, flag);
+
+        switch (flag) {
+        case SET:
+                break;
+
+        case RESET:
+                local_irq_save(flags);
+                fs_andl(OTG_HOST_CONTROL, ~HOST_CONTROL_HCUSBSTE_SUSPEND);
+                fs_orl(OTG_HOST_CONTROL, HOST_CONTROL_HCUSBSTE_OPERATIONAL);
+                local_irq_restore(flags);
+                break;
+        }
+}
+
+/*!
+ * fs_loc_sof_func() - otg loc sof output function
+ * @param otg
+ * @param flag
+ */
+void fs_loc_sof_func(struct otg_instance *otg, u8 flag)
+{
+        struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *)(((struct hcd_instance *)(otg->hcd))->privdata);
+        fs_hcpriv *fs_hcpriv = bus_hcpriv->hw_hci;
+        int i;  
+        u32 mask;
+        unsigned long flags;
+
+        switch (flag) {   
+        case SET:
+                //printk(KERN_INFO"%s: SET\n", __FUNCTION__);
+                //TRACE_MSG0(HCD, "-----------------------------------------");
+
+                local_irq_save(flags);
+
+		/* reset the host core
+		 */
+                fs_wl_clr(HCD, OTG_CORE_RST_CTRL, MODULE_RSTRH | MODULE_RSTHSIE | MODULE_RSTHC);
+                while (fs_rl(OTG_CORE_RST_CTRL));
+		
+                fs_host_clock_on();
+
+                for (i = 0; i < NUM_DATA_BUFFS; i++) 
+                        (void) rel_data_buff(fs_hcpriv, ((fs_data_buff *)OTG_DATA_BASE)+i);
+
+                for (i = 0; i < NUM_ETDS; i++) 
+                        rel_etd(fs_hcpriv,i);
+
+                fs_wl(OTG_HOST_CONTROL, HOST_CONTROL_HCRESET | HOST_CONTROL_RMTWUEN | 
+                                HOST_CONTROL_HCUSBSTE_RESET | HOST_CONTROL_CTLBLKSR_11);
+
+
+                //TRACE_MSG0(HCD, "HW HCD_ENABLE_SET");
+                fs_andl(OTG_CORE_HNP_CSTAT, ~(MODULE_MASTER | MODULE_SLAVE | MODULE_CMPEN | 
+                                        MODULE_BGEN | MODULE_SWAUTORST | MODULE_ABBUSREQ));
+                fs_rl(OTG_CORE_HNP_CSTAT); 
+
+                fs_orl(OTG_CORE_HNP_CSTAT, MODULE_MASTER | MODULE_CMPEN | MODULE_BGEN | MODULE_ABBUSREQ);
+                fs_orl(OTG_CORE_HNP_CSTAT, MODULE_ARMTHNPE | MODULE_BHNPEN); // XXX
+
+                fs_wl(OTG_HOST_CONTROL, HOST_CONTROL_HCUSBSTE_OPERATIONAL);
+
+                //hcd_hw_enable_interrupts(bus_hcpriv);
+
+                mask = (HOST_PSCINT_EN | HOST_FMOFINT_EN | HOST_HERRINT_EN | 
+                                HOST_RESDETINT_EN | /* HOST_SOFINT_EN | */ HOST_DONEINT_EN | HOST_SORINT_EN);
+
+                // R1: sec 23.11.15 pg 23-54
+                fs_rl(OTG_CORE_HNP_CSTAT); 
+                fs_rl(OTG_HOST_CONTROL);
+                fs_rl(OTG_HOST_ROOTHUB_STATUS);
+                fs_rl(OTG_HOST_PORT_STATUS_1);
+                fs_rl(OTG_HOST_PORT_STATUS_2);
+                fs_rl(OTG_HOST_PORT_STATUS_3);
+
+                fs_wl(OTG_HOST_SINT_STEN, mask);
+                fs_rl(OTG_HOST_SINT_STEN);
+                local_irq_restore(flags);
+        }
+
+        rh_loc_sof_func(otg, flag);
+
+        switch (flag) {   
+        case RESET:
+                local_irq_save(flags);
+
+                //printk(KERN_INFO"%s: RESET\n", __FUNCTION__);
+                //TRACE_MSG0(HCD, "HW HCD_ENABLE_RESET");
+
+                //hcd_hw_disable_interrupts(bus_hcpriv);
+                // R1: sec 23.11.15 pg 23-54
+                fs_wl(OTG_HOST_SINT_STAT, 0);
+
+                fs_andl(OTG_HOST_CONTROL, ~HOST_CONTROL_HCUSBSTE_OPERATIONAL);
+
+                // Shut down hardware if not already shut down....
+                //hcd_hw_disable_interrupts(bus_hcpriv);
+
+                fs_host_clock_off();
+                local_irq_restore(flags);
+                break;
+        }
+}
+/* ********************************************************************************************* */
+/* Module init
+ *
+ * Define the global data structures and call the initialization functions required
+ * to start the generic hcd layer and register with the otg core.
+ *
+ */
+
+void rh_suspend_func(struct otg_instance *otg, u8 on);
+void hcd_init_func (struct otg_instance *otg, u8 flag);
+int hcd_probe(struct usb_interface *intf, const struct usb_device_id *id);
+void hcd_disconnect(struct usb_interface *intf);
+
+int fs_mod_init(void);
+#ifdef MODULE
+void fs_mod_exit(void);
+#endif
+
+#if !defined(OTG_C99)
+
+static struct usb_driver mx2_usb_driver;
+fs_hcpriv priv_mx21;
+struct bus_hcpriv fs_bus_hcpriv;
+struct hcd_ops hcd_ops;
+
+
+/*!
+ * fs_hcd_global_init() - initialize global vars for non C99 systems
+ */
+void fs_hcd_global_init(void)
+{
+        ZERO(mx2_usb_driver);
+        mx2_usb_driver.owner = THIS_MODULE;
+        mx2_usb_driver.name = "MX21_HCD";
+        mx2_usb_driver.probe = hcd_probe;
+        mx2_usb_driver.disconnect = hcd_disconnect;
+
+        ZERO(priv_mx21);
+        priv_mx21.free_buffs = 0xffff;
+        priv_mx21.free_etds = 0x0000ffff;
+        priv_mx21.bus_hcpriv = &fs_bus_hcpriv;
+
+        ZERO(fs_bus_hcpriv);
+        fs_bus_hcpriv.hw_hci = &priv_mx21;
+        fs_bus_hcpriv.usb_driver = &mx2_usb_driver;
+        fs_bus_hcpriv.bus_device.driver = &mx2_usb_driver.driver;
+        fs_bus_hcpriv.bus_device.parent = NULL;
+        fs_bus_hcpriv.bus_device.bus = &usb_bus_type;    // struct bus_type *
+#if 0
+        strncpy(fs_bus_hcpriv.bus_device.name, "MX21 HOST", sizeof(fs_bus_hcpriv.bus_device.name));
+#endif
+        fs_bus_hcpriv.num_ports = 1;
+        fs_bus_hcpriv.otg_port = 1;
+        fs_bus_hcpriv.otg_capable_mask = (1 << 1);
+        fs_bus_hcpriv.rh_serial = "000001";
+        fs_bus_hcpriv.rh_product = "Virtual Root Hub";
+        fs_bus_hcpriv.rh_manufacturer = "Belcarra Technologies";
+        fs_bus_hcpriv.rh_vendorid = CONFIG_OTG_ROOTHUB_VENDORID;
+        fs_bus_hcpriv.rh_productid = CONFIG_OTG_ROOTHUB_PRODUCTID;
+        fs_bus_hcpriv.rh_bcddevice = CONFIG_OTG_ROOTHUB_BCDDEVICE;
+        fs_bus_hcpriv.rh_bmAttributes = 0x0;
+        fs_bus_hcpriv.rh_bMaxPower = 0;
+
+        fs_bus_hcpriv.max_active_transfers = NUM_ETDS;
+        fs_bus_hcpriv.max_active_urbs = NUM_ETDS;
+
+        ZERO(hcd_ops);
+        hcd_ops.name = "MX21 HCD";
+        hcd_ops.max_ports = 1;
+        hcd_ops.capabilities = 0;
+                                                        // module
+        hcd_ops.mod_init = fs_mod_init;               // called for module init
+#ifdef MODULE
+        hcd_ops.mod_exit = fs_mod_exit;               // called for module exit
+#endif
+                                                        // otg state machine
+        hcd_ops.hcd_init_func = hcd_init_func;         // initialize when otg enabled
+        hcd_ops.hcd_en_func = fs_hcd_en_func;         // setup hardware as host
+        hcd_ops.loc_suspend_func = rh_loc_suspend_func;        // enable port on hub
+        hcd_ops.loc_sof_func = fs_loc_sof_func;       // enable port on hub
+};
+
+#else /* !defined(OTG_C99) */
+
+static struct usb_driver mx2_usb_driver = {
+        .owner = THIS_MODULE,
+        .name = "MX21_HCD",
+        .probe = hcd_probe,
+        .disconnect = hcd_disconnect,
+};
+
+extern struct bus_hcpriv fs_bus_hcpriv;
+fs_hcpriv priv_mx21 = {
+        .free_buffs = 0xffff,
+        .free_etds = 0x0000ffff,
+        .bus_hcpriv = &fs_bus_hcpriv,
+};
+
+struct bus_hcpriv fs_bus_hcpriv = {
+
+        .hw_hci = &priv_mx21,
+        .usb_driver = &mx2_usb_driver,
+        .bus_device.driver = &mx2_usb_driver.driver,
+        .bus_device.parent = NULL,
+        .bus_device.bus = &usb_bus_type,    // struct bus_type *
+        .bus_device.name = "MX21 HOST",
+
+        .num_ports = 1,
+        .otg_port = 1,
+        .otg_capable_mask = (1 << 1),
+        .rh_serial = "000001",
+        .rh_product = "Virtual Root Hub",
+        .rh_manufacturer = "Belcarra Technologies",
+        .rh_vendorid = CONFIG_OTG_ROOTHUB_VENDORID,
+        .rh_productid = CONFIG_OTG_ROOTHUB_PRODUCTID,
+        .rh_bcddevice = CONFIG_OTG_ROOTHUB_BCDDEVICE,
+        .rh_bmAttributes = 0x0,
+        .rh_bMaxPower = 0,
+
+        .max_active_transfers = NUM_ETDS,
+        .max_active_urbs = NUM_ETDS,
+};
+
+struct hcd_ops hcd_ops = {
+
+        .name = "MX21 HCD",
+        .max_ports = 1,
+        .capabilities = 0,
+                                                // module
+        .mod_init = fs_mod_init,               // called for module init
+#ifdef MODULE
+        .mod_exit = fs_mod_exit,               // called for module exit
+#endif
+        .hcd_init_func = hcd_init_func,         // initialize when otg enabled
+        .hcd_en_func = fs_hcd_en_func,         // setup hardware as host
+        .loc_suspend_func = rh_loc_suspend_func,        // enable port on hub
+        .loc_sof_func = fs_loc_sof_func,        // enable port on hub
+};
+#endif /* !defined(OTG_C99) */
+
+
+extern int hcd_init(struct bus_hcpriv *bus_hcpriv, struct usb_driver *usb_driver);
+extern void hcd_exit(struct bus_hcpriv *bus_hcpriv, struct usb_driver *usb_driver);
+
+/*! 
+ * fs_mod_init() - initialize mx2 hcd
+ *
+ * This calls hcd_init() with the mx2 data structures.
+ */
+int fs_mod_init(void)
+{
+        RETURN_ENOMEM_IF(hcd_init(&fs_bus_hcpriv, &mx2_usb_driver));
+
+        hcd_instance->privdata = &fs_bus_hcpriv;
+        return 0;
+}
+
+#ifdef MODULE
+/*! 
+ * fs_mod_exit() - de-initialize mx2 hcd
+ *
+ * This calls hcd_exit() with the mx2 data structures.
+ */
+void fs_mod_exit(void)
+{
+        hcd_exit(&fs_bus_hcpriv, &mx2_usb_driver);
+}
+#endif
+
+/* @} */
+
diff -uNr linux/drivers/no-otg/ocd/fsotg/fs-ocd.c linux/drivers/otg/ocd/fsotg/fs-ocd.c
--- linux/drivers/no-otg/ocd/fsotg/fs-ocd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/fsotg/fs-ocd.c	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,263 @@
+/*
+ * otg/ocd/fsotg/fs-ocd.c -- USB Device Controller driver 
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/fsotg/fs-ocd.c
+ * @brief Freescale USB OTG Controller Driver
+ * This is the OTG Controller Driver. 
+ *
+ * This implements overall configuration and control of the Freescale OTG hardware
+ * and implements the main interrupt handler.
+ *
+ * There is some processor specific code here to support the alternate processors
+ * that implement this type of USB support.
+ *
+ * There is no board or platform level code here.
+ *
+ * @ingroup FSOTG
+ *
+ * @{
+ */
+
+#include <otg/pcd-include.h>
+#include <linux/pci.h>
+#include <asm/arch/mx2.h>
+#undef GPT_BASE_ADDR
+#include <asm/arch/gpt.h>
+#include <asm/arch/clk.h>
+
+#include <otghw/fsotg-hardware.h>
+
+
+/* ********************************************************************************************* */
+#define TIMEOUT_VALUE 1000
+/*!
+ * fs_func_clock_on() - enable function controller clock
+ */
+void fs_func_clock_on(void)
+{
+        u32 timeout = TIMEOUT_VALUE;
+        //TRACE_MSG0(OCD, "FUNC CLOCK ON:");
+        fs_orl(OTG_CORE_CLK_CTRL, MODULE_FUNC_CLK);
+        while(!( fs_rl(OTG_CORE_CLK_CTRL) & MODULE_FUNC_CLK)) { timeout--; if (!timeout) break; }
+
+        //fs_orl(OTG_CORE_CINT_STEN, MODULE_ASFCINT_EN |MODULE_FCINT_EN);
+}       
+
+/*!
+ * fs_host_clock_on() - enable host controller clock
+ */
+void fs_host_clock_on(void)
+{
+        u32 timeout = TIMEOUT_VALUE;
+        //TRACE_MSG0(OCD, "HOST CLOCK ON");
+        fs_orl(OTG_CORE_CLK_CTRL, MODULE_HOST_CLK);
+        while(!( fs_rl(OTG_CORE_CLK_CTRL) & MODULE_HOST_CLK)) { timeout--; if (!timeout) break; }
+}       
+
+/*!
+ * fs_func_clock_off() - disable function controller clock
+ */
+void fs_func_clock_off(void)
+{       
+        u32 timeout = TIMEOUT_VALUE;
+        //TRACE_MSG0(OCD, "FUNC CLOCK OFF");
+        fs_andl(OTG_CORE_CLK_CTRL, 0x0);
+        while((fs_rl(OTG_CORE_CLK_CTRL) & (MODULE_FUNC_CLK | MODULE_MAIN_CLK))) { timeout--; if (!timeout) break; }
+}       
+
+/*!
+ * fs_host_clock_off() - disable host controller clock
+ */
+void fs_host_clock_off(void)
+{       
+        u32 timeout = TIMEOUT_VALUE;
+        //TRACE_MSG0(OCD, "HOST CLOCK OFF");
+        fs_andl(OTG_CORE_CLK_CTRL, 0x0);
+        while((fs_rl(OTG_CORE_CLK_CTRL) & (MODULE_HOST_CLK | MODULE_MAIN_CLK))) { timeout--; if (!timeout) break; }
+}       
+
+/*!
+ * fs_main_clock_on() - enable main clock
+ */
+void fs_main_clock_on(void)
+{
+        u32 timeout = TIMEOUT_VALUE;
+        //TRACE_MSG0(OCD, "MAINFUNC CLOCK ON");
+        fs_orl(OTG_CORE_CLK_CTRL, MODULE_MAIN_CLK);
+        while(!( fs_rl(OTG_CORE_CLK_CTRL) & MODULE_MAIN_CLK)) { timeout--; if (!timeout) break; }
+}
+
+/*!
+ * fs_main_clock_off() - disable main clock
+ */
+void fs_main_clock_off(void)
+{
+        u32 timeout = TIMEOUT_VALUE;
+        //TRACE_MSG0(OCD, "MAIN CLOCK OFF");
+        fs_wl_set(OCD, OTG_CORE_CLK_CTRL, 0);
+        while((fs_rl(OTG_CORE_CLK_CTRL) & MODULE_MAIN_CLK)) { timeout--; if (!timeout) break; }
+}
+
+/* ********************************************************************************************* */
+
+/*!
+ * fs_disable_interrupts() - disable interrupts
+ */
+void fs_disable_interrupts (void)
+{
+        fs_wl(OTG_CORE_CINT_STEN, 0 );
+        fs_wl(OTG_CORE_HINT_STEN, 0 );
+        fs_wl(OTG_HOST_SINT_STEN, 0 );
+        fs_wl(OTG_HOST_XYINT_STEN, 0 );
+        fs_wl(OTG_HOST_ETD_EN, 0);
+        fs_wl(OTG_HOST_ETD_DONE, 0 );
+        fs_wl(OTG_FUNC_SINT_STEN, 0 );
+        fs_wl(OTG_FUNC_XYINT_STEN, 0 );
+        fs_wl(OTG_FUNC_EP_EN, 0 );
+        fs_wl(OTG_FUNC_EP_DEN, 0 );
+}
+
+/* ********************************************************************************************* */
+
+/* ********************************************************************************************* */
+/*!
+ * fs_init() - initial tcd setup
+ * Allocate interrupts and setup hardware.
+ */
+void fs_init (void)
+{
+        int timeout; 
+        unsigned long flags;
+
+        TRACE_MSG0(OCD, "MX2_MOD_OCD_INIT");
+        local_irq_save (flags);
+
+        fs_wl(OTG_SYS_CTRL, 0x0);
+
+        /* 2. Ensure hardware is reset and cleared
+         */
+        fs_clear_words((volatile u32 *)MX2_IO_ADDRESS(OTG_DMA_BASE), (32*16/4));
+        //fs_clear((void *)MX2_IO_ADDRESS(OTG_FUNC_BASE), 0x200);
+        fs_main_clock_off();
+
+        fs_wl_clr(OCD, OTG_CORE_RST_CTRL, MODULE_RSTI2C | 0x3f);
+        while (fs_rl(OTG_CORE_RST_CTRL));
+
+        /* 3. OTG Hardware Mode and clocks
+         * set to diff, diff and Configure the OTG to behave as function
+         */
+        TRACE_MSG0(OCD, "3. OTG Software Mode and clock");
+        fs_andl(OTG_CORE_HWMODE, 0xffffff0f);                  // clear
+        fs_orl(OTG_CORE_HWMODE, MODULE_CRECFG_SHNP);           // set to software hnp
+        fs_rl(OTG_CORE_HWMODE);
+
+        fs_andl(OTG_CORE_HNP_CSTAT, ~0x00000800);
+        fs_rl(OTG_CORE_HNP_CSTAT);
+
+        fs_wl_set(OCD, OTG_CORE_HNP_T3PCR, 0x00000000);
+        fs_rl(OTG_CORE_HNP_T3PCR);
+
+        TRACE_MSG0(OCD, "6. Enable ");
+        TRACE_MSG0(OCD, "enable core interrupts");
+
+        fs_wl(OTG_CORE_CINT_STEN, 0);
+        
+        fs_wl(OTG_CORE_CINT_STEN, MODULE_ASHNPINT_EN | 
+                MODULE_ASHCINT_EN | MODULE_HNPINT_EN | MODULE_HCINT);
+        
+        
+        TRACE_MSG0(OCD, "enable host interrupts");
+        fs_wl(OTG_CORE_HINT_STEN, HNP_I2COTGINT_EN | HNP_AWAITBTO_EN |  
+                HNP_AIDLEBDTO_EN | HNP_SRPSUCFAIL_EN | HNP_SRPINT_EN | HNP_VBUSERROR_EN |
+                HNP_ABSEVAILD_EN | HNP_ABUSVALID_EN | HNP_MASSLVCHG_EN | HNP_IDCHANGE_EN); 
+
+        TRACE_MSG0(OCD, "disable various host interrupts");
+        fs_wl(OTG_HOST_XYINT_STEN, 0);
+        fs_wl(OTG_HOST_ETD_EN, 0);
+        fs_wl(OTG_HOST_ETD_DONE, 0);
+        fs_wl(OTG_HOST_SINT_STEN, 0);
+
+        TRACE_MSG0(OCD, "disable various function interrupts");
+        fs_wl(OTG_FUNC_XYINT_STEN, 0); 
+        fs_wl(OTG_FUNC_EP_EN, 0); 
+        fs_wl(OTG_FUNC_EP_DEN, 0);
+
+        fs_wl(OTG_DMA_DINT_STEN, 0x3);
+        //fs_wb(I2C_MASTER_INT_REG_ADD, 0xf0);
+        //fs_wb(I2C_MASTER_INT_REG_ADD, 0x00);
+
+        // XXX note that newer designs than the mx21 will also need to check
+        // and/or set OTG_CORE_INTERRUPT_STEN
+
+
+        TRACE_MSG0(OCD, "--");
+        TRACE_MSG0(OCD, "8. Ready ");
+        TRACE_MSG0(OCD, "--");
+
+        local_irq_restore (flags);
+}
+
+extern void fs_stop_ep(int epn, int dir);
+
+/*!
+ * fs_exit() - de-initialize
+ */
+void fs_exit(void)
+{
+        int i;
+        unsigned long flags;
+        TRACE_MSG0(OCD, "MX2_MOD_OCD_EXIT");
+
+        fs_disable_interrupts();
+        //_reg_CRM_PCCR1 &= ~(1<<27);                                             // disable GPT3
+
+        local_irq_save (flags);
+        for (i = 0; i < 16; i++) {
+                fs_stop_ep(i, USB_DIR_IN);
+                fs_stop_ep(i, USB_DIR_OUT);
+        }
+        fs_clear_words((volatile u32 *)MX2_IO_ADDRESS(OTG_EP_BASE), (32*16/4));
+        //fs_clear((void *)MX2_IO_ADDRESS(OTG_EP_BASE), 0x200);
+        //fs_clear((volatile u32 *)MX2_IO_ADDRESS(OTG_DMA_BASE), 32*16);
+        //fs_clear((void *)MX2_IO_ADDRESS(OTG_FUNC_BASE), 0x200);
+        fs_wl( OTG_CORE_HWMODE, 0xa3);
+        fs_main_clock_off();
+        local_irq_restore (flags);
+}
+
+
+/*!
+ * fs_ocd_init() - used to initialize/enable or disable the tcd driver
+ * @param otg
+ * @param flag
+ */
+void fs_ocd_init(struct otg_instance *otg, u8 flag)
+{
+        TRACE_MSG0(OCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(OCD, "MX2_OCD_EN SET");
+                fs_init();
+                otg_event(otg, TCD_OK | ID_FLOAT, OCD, "OCD_OK");
+                break;
+        case RESET:
+                fs_exit();
+                TRACE_MSG0(OCD, "MX2_OCD_EN RESET");
+                otg_event(otg, TCD_OK | ID_FLOAT, OCD, "OCD_OK");
+                break;
+        }
+}
+
+/* ********************************************************************************************* */
+
+/* @} */
+
diff -uNr linux/drivers/no-otg/ocd/fsotg/fs-pcd.c linux/drivers/otg/ocd/fsotg/fs-pcd.c
--- linux/drivers/no-otg/ocd/fsotg/fs-pcd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/fsotg/fs-pcd.c	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,793 @@
+/*
+ * otg/ocd/fsotg/fs-pcd.c -- Freescale USBOTG Peripheral Controller driver
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By:
+ *      Stuart Lynne <sl@lbelcarra.com>,
+ *      Tom Rushworth <tbr@belcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/fsotg/fs-pcd.c
+ * @brief Freescale USB Peripheral Controller Driver
+ * This implements the Freescale USBOTG Peripheral Controller Driver.
+ *
+ * There is some processor specific code here to support the alternate processors
+ * that implement this type of USB support.
+ *
+ * There is no board or platform level code here.
+ *
+ * @ingroup FSOTG
+ *
+ * @{
+ */
+
+#include <otg/pcd-include.h>
+#include <linux/pci.h>
+#include <asm/arch/mx2.h>
+
+#include <otghw/fsotg-hardware.h>
+
+void fs_func_clock_on(void);                   /* defined in mx2-ocd.c */
+void fs_func_clock_off(void);                  /* defined in mx2-ocd.c */
+
+u8 fs_new_address, fs_usb_address;            /* used to save and set USB address */
+
+/* ********************************************************************************************* */
+/*!
+ * fs_ep_config() - configure and enable an endpoint to send or receive data
+ * First setup the endpoint descriptor words, and then enable the endpoint and done interrupt
+ * @param epn - endpoint number
+ * @param dir - direction IN or OUT
+ * @param ep_num -
+ * @param wMaxPacketSize
+ * @param format
+ * @param ttlbtecnt
+ * @param stall
+ */
+static void inline
+fs_ep_config(int epn, int dir, u32 ep_num, int wMaxPacketSize, int format, int ttlbtecnt, int stall)
+{
+        TRACE_MSG6(PCD, "epn: %02x dir: %02x sz: %d fmt: %x cnt: %d stall: %d",
+                        epn, dir, wMaxPacketSize, format, ttlbtecnt, stall);
+
+        fs_wl(ep_word(epn, dir, 0), ((stall ? 1 : 0) << 31) | (wMaxPacketSize << 16) | ((format & 3) << 14));
+        fs_wl(ep_word(epn, dir, 1), ttlbtecnt ?  (data_y_buf(epn, dir) << 16) | data_x_buf(epn, dir): 0);
+        fs_wl(ep_word(epn, dir, 3), ((wMaxPacketSize-1) << 21) | ttlbtecnt);
+        fs_orl(OTG_FUNC_IINT, ep_num);              // issue done status interrupts immediately
+        fs_orl(OTG_FUNC_EP_DEN, ep_num);            // enable endpoint done interrupt
+        fs_orl(OTG_FUNC_EP_EN, ep_num);             // enable the interrupt
+}
+
+/*!
+ * fs_ep_config_dma() - configure and enable an endpoint to send or receive data
+ * Check the RDY bit and clear if necessary, setup dma, do common setup and then set RDY.
+ * @param epn - endpoint number
+ * @param dir - direction IN or OUT
+ * @param wMaxPacketSize
+ * @param format
+ * @param ttlbtecnt
+ * @param bp
+ */
+static void inline
+fs_ep_config_dma(int epn, int dir, int wMaxPacketSize, int format, int ttlbtecnt, u8 *bp)
+{
+        u32 ep_num = ep_num_dir(epn, dir);
+        u32 dma_num = dma_num_dir(epn, dir);
+        TRACE_MSG2(PCD, "EP CONFIG DMA: epn: %02x num: %02x", epn, ep_num);
+        if (fs_rl(OTG_FUNC_EP_RDY) & ep_num) fs_wl_set(PCD, OTG_FUNC_EP_RDY, ep_num);
+        fs_wl(OTG_DMA_EPN_MSA(dma_num), (int)bp);
+        fs_wl_set(PCD, OTG_DMA_EP_EN, ep_num);
+        fs_ep_config(epn, dir, ep_num, wMaxPacketSize, format, ttlbtecnt, 0);
+        fs_wl_set(PCD, OTG_FUNC_EP_RDY, ep_num);           // toggle ready bit
+}
+
+/*!
+ * fs_ep_config_nodma() - configure and enable an endpoint to send or receive data
+ * Non-DMA setup, optional stall, ready etc.
+ * @param epn - endpoint number
+ * @param dir
+ * @param stall - stall endpoint
+ * @param wMaxPacketSize
+ * @param format
+ * @param ttlbtecnt
+ * @param rdy1
+ * @param rdy2
+ */
+static void
+fs_ep_config_nodma(int epn, int dir, int stall, int wMaxPacketSize, int format, int ttlbtecnt, int rdy1, int rdy2)
+{
+        u32 ep_num = ep_num_dir(epn, dir);
+        TRACE_MSG5(PCD, "EP CONFIG NODMA: epn: %02x num: %02x stall: %d r1: %d r2: %d", epn, ep_num, stall, rdy1, rdy2);
+        #if 1
+        // XXX This should work, but enumeratation fails after disable/enable
+        if (rdy1) {
+                TRACE_MSG3(PCD, "EP CONFIG NODMA: epn: %02x num: %02x checking RDY: %02x",
+                                epn, ep_num, rdy1 && fs_rl(OTG_FUNC_EP_RDY) & ep_num);
+                RETURN_IF (rdy1 && (fs_rl(OTG_FUNC_EP_RDY) & ep_num));
+        }
+        #endif
+        UNLESS(epn)
+                fs_orl(OTG_FUNC_XYINT_STEN, ep_num);        // enable x or y buffer interrupt
+
+        fs_ep_config(epn, dir, ep_num, wMaxPacketSize, format, ttlbtecnt, stall);
+        RETURN_UNLESS(rdy2);
+        UNLESS (fs_rl(OTG_FUNC_EP_RDY) & ep_num) fs_wl_set(PCD, OTG_FUNC_EP_RDY, ep_num);           // toggle ready bit
+}
+
+/*!
+ * fs_sendzlp() - start sending a buffer on a specified endpoint
+ * Toggle XFILL_STAT or YFILL_STAT bit, then call fs_ep_config_nodma().
+ * @param epn - endpoint number
+ * @param endpoint - endpoint instance
+ * @param wMaxPacketSize
+ */
+static void inline
+fs_sendzlp (int epn, struct usbd_endpoint_instance *endpoint, int wMaxPacketSize)
+{
+        u32 ep_num_in = ep_num_in(epn);
+        TRACE_MSG0(PCD, "ZLP");
+        if (!(fs_rl(OTG_FUNC_XFILL_STAT) & ep_num_in)) {
+                //TRACE_MSG0(PCD, "EMPTY Y BUFFER: ZLP");
+                fs_wl_set(PCD, OTG_FUNC_XFILL_STAT, ep_num_in);
+        }
+        else if (!(fs_rl(OTG_FUNC_YFILL_STAT) & ep_num_in)) {
+                //TRACE_MSG0(PCD, "EMPTY Y BUFFER: ZLP");
+                fs_wl_set(PCD, OTG_FUNC_YFILL_STAT, ep_num_in);
+        }
+        fs_ep_config_nodma(epn, USB_DIR_IN, 0, endpoint->wMaxPacketSize, endpoint->bmAttributes & 0x3, 0, 1, 1);
+}
+
+/*!
+ * fs_stop_ep() - stop endpoint
+ * @param epn - endpoint number
+ * @param dir - direction IN or OUT
+ */
+static void fs_stop_ep(int epn, int dir)
+{
+        int ep_num = ep_num_dir(epn, dir);
+
+        TRACE_MSG3(PCD, "STOP EP: %08x dir: %02x [%08x]", ep_num, dir, fs_rl(ep_word(epn, dir, 0)));
+
+        //fs_wl(ep_word(epn, dir, 0), ((stall ? 1 : 0) << 31) | (wMaxPacketSize << 16) | ((format & 3) << 14));
+
+        if (fs_rl(OTG_FUNC_EP_RDY) & ep_num)
+                fs_wl_clr(PCD, OTG_FUNC_EP_RDY, ep_num);
+        fs_andl(OTG_FUNC_XYINT_STEN, ~ep_num);
+        fs_andl(OTG_FUNC_IINT, ~ep_num);
+        if (fs_rl(OTG_FUNC_XINT_STAT) & ep_num) {
+                fs_wl_clr(PCD, OTG_FUNC_XINT_STAT, ep_num);
+                fs_wl_clr(PCD, OTG_FUNC_XFILL_STAT, ep_num);
+        }
+        else if (fs_rl(OTG_FUNC_YINT_STAT) & ep_num) {
+                fs_wl_clr(PCD, OTG_FUNC_YINT_STAT, ep_num);
+                fs_wl_clr(PCD, OTG_FUNC_YFILL_STAT, ep_num);
+        }
+}
+
+/* ********************************************************************************************* */
+/*!
+ * fs_pcd_setup_ep() - setup endpoint
+ * @param pcd - pcd instance
+ * @param epn - endpoint number
+ * @param endpoint - endpoint instance
+ */
+static void inline
+fs_pcd_setup_ep (struct pcd_instance *pcd, unsigned int epn, struct usbd_endpoint_instance *endpoint)
+{
+        TRACE_MSG2(PCD, "START EPN: config %d %02x", epn, endpoint->bEndpointAddress);
+        if (epn && endpoint->bEndpointAddress)
+                fs_ep_config_nodma(endpoint->bEndpointAddress & 0x7f, endpoint->bEndpointAddress & USB_DIR_IN, 0,
+                                endpoint->wMaxPacketSize, endpoint->bmAttributes&0x3, 0, 0, 0);
+}
+
+/*!
+ * fs_pcd_start_ep0_setup() - enable ep0 for receiving SETUP request
+ * Unless already ready, configure ep0 to receive.
+ * @param endpoint - endpoint instance
+ */
+static void inline
+fs_pcd_start_ep0_setup (struct usbd_endpoint_instance *endpoint)
+{
+        TRACE_MSG0(PCD, "START EP0: config");
+        fs_ep_config_nodma(0, USB_DIR_OUT, 0, endpoint->wMaxPacketSize, endpoint->bmAttributes&0x3,
+                        endpoint->wMaxPacketSize, 0, 1); // XXX rdy1 must be zero
+}
+/* ********************************************************************************************* */
+/*!
+ * fs_pcd_start_endpoint_out() - start receive
+ * @param pcd - pcd instance
+ * @param endpoint - endpoint number
+ */
+static void
+fs_pcd_start_endpoint_out(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *rcv_urb = pcd_rcv_next_irq(endpoint);
+        int epn = endpoint->bEndpointAddress & 0x7f;
+        UNLESS (rcv_urb) {
+                UNLESS (!epn) fs_pcd_start_ep0_setup(endpoint);  // if EP0 then restart for receive setup
+                return;
+        }
+        rcv_urb->pcimap = (void *)pci_map_single (NULL, (void *) rcv_urb->buffer, rcv_urb->buffer_length, PCI_DMA_FROMDEVICE);
+        fs_ep_config_dma(epn, USB_DIR_OUT, endpoint->wMaxPacketSize, endpoint->bmAttributes & 0x3,
+                        rcv_urb->buffer_length, rcv_urb->pcimap);
+        TRACE_MSG3(PCD, "START OUT: %02x rcv_urb: %x length: %d", endpoint->bEndpointAddress, rcv_urb, rcv_urb->actual_length);
+}
+
+/*!
+ * fs_pcd_stop_out() - process interrupt for received buffer
+ * @param pcd - pcd instance
+ * @param epn - endpoint number
+ * @param endpoint - endpoint instance
+ */
+static void
+fs_pcd_stop_out (struct pcd_instance *pcd, int epn, struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *rcv_urb = pcd_rcv_next_irq(endpoint);
+        u32 ep3 = fs_rl(ep_word(epn, USB_DIR_OUT, 3));
+        u32 ep_num_out = ep_num_out(epn);
+        fs_stop_ep(epn, USB_DIR_OUT);
+        RETURN_UNLESS (rcv_urb);
+        pcd_rcv_finished_irq (endpoint,rcv_urb->buffer_length - (ep3 & 0xffff), 0);      // XXX fix mask
+        if (!epn)
+                fs_sendzlp(epn, endpoint, endpoint->wMaxPacketSize);        // ZLP
+        else
+                fs_pcd_start_endpoint_out(pcd, endpoint);                        // restart
+}
+/* fs_pcd_cancel_out_irq - cancel OUT urb
+ */
+static void
+fs_pcd_cancel_out_irq (struct pcd_instance *pcd,struct usbd_urb *urb)
+{
+        struct usbd_endpoint_instance *endpoint = urb->endpoint;
+        int epn = endpoint->bEndpointAddress & 0x7f;
+        TRACE_MSG3(PCD, "urb: %x endpoint: %x epn: %d", urb, endpoint, epn);
+        fs_pcd_stop_out (pcd, epn, endpoint);
+}
+/* ********************************************************************************************* */
+/*!
+ * fs_pcd_start_endpoint_in() - start transmit
+ * Get next tx_urb (completing old one if there is one) and start sending it.
+ * @param pcd - pcd instance
+ * @param endpoint - endpoint instance
+ */
+static void
+fs_pcd_start_endpoint_in(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *tx_urb = pcd_tx_complete_irq(endpoint, 0);
+        int epn = endpoint->bEndpointAddress & 0x7f;
+
+        UNLESS (tx_urb) {
+                TRACE_MSG1(PCD, "START IN: %02x finished", endpoint->bEndpointAddress);
+                UNLESS (epn) {                                  // if not EP0 we are done
+                        if (fs_new_address != fs_usb_address) {
+                                fs_usb_address = fs_new_address;
+                                //TRACE_MSG1(PCD, "START IN: SETTING ADDRESS %x", fs_usb_address);
+                                fs_wl(OTG_FUNC_DEV_ADDR, fs_usb_address);
+                        }
+                        fs_pcd_start_ep0_setup(endpoint);          // if EP0 then restart for receive setup
+                }
+                return;
+        }
+
+        if (pcd_tx_sendzlp(endpoint)) {                                                  // check if we need to send ZLP
+                TRACE_MSG1(PCD, "START IN: ZLP tx_urb: %x", tx_urb);
+                fs_sendzlp(epn, endpoint, endpoint->wMaxPacketSize);        // ZLP
+                return;
+        }
+        endpoint->last = tx_urb->actual_length;
+        consistent_sync (tx_urb->buffer, tx_urb->actual_length, PCI_DMA_BIDIRECTIONAL);
+        fs_ep_config_dma(epn, USB_DIR_IN, endpoint->wMaxPacketSize, endpoint->bmAttributes & 0x3,
+                        tx_urb->actual_length, tx_urb->buffer);
+
+        TRACE_MSG4(PCD, "START IN: %02x tx_urb: %x length: %d %s", 
+                        endpoint->bEndpointAddress, tx_urb, tx_urb->actual_length, 
+                        (tx_urb->flags & USBD_URB_SENDZLP) ? "ZLP": "");
+}
+
+/*!
+ * fs_pcd_stop_in() - process interrupt for transmitted buffer
+ * @param pcd - pcd instance
+ * @param epn -endpoint number
+ * @param endpoint - endpoint instance
+ */
+static void inline
+fs_pcd_stop_in (struct pcd_instance *pcd, int epn, struct usbd_endpoint_instance *endpoint)
+{
+        fs_stop_ep(epn, USB_DIR_IN);
+        fs_pcd_start_endpoint_in(pcd, endpoint);
+}
+/*!
+ * fs_pcd_cancel_in_irq() - cancel IN urb
+ */
+static void inline 
+fs_pcd_cancel_in_irq (struct pcd_instance *pcd,struct usbd_urb *urb)
+{
+        struct usbd_endpoint_instance *endpoint = urb->endpoint;
+        int epn = endpoint->bEndpointAddress & 0x7f;
+        TRACE_MSG3(PCD, "urb: %x endpoint: %x epn: %d", urb, endpoint, epn);
+        fs_pcd_stop_in (pcd, epn, endpoint);
+}
+
+/* ********************************************************************************************* */
+/*! 
+ * fs_pcd_stop_ep0_setup() - setup endpoint zero
+ * @param pcd - pcd instance
+ * @param endpoint - endpoint instance
+ */
+static void 
+fs_pcd_stop_ep0_setup (struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
+{
+        static struct usbd_device_request request;
+        u8 *cp = (u8 *) &request;
+        u32 ep0 = fs_rl(ep_word(0, USB_DIR_OUT, 0));
+        u32 ep3 = fs_rl(ep_word(0, USB_DIR_OUT, 3));
+        
+        fs_andl(OTG_FUNC_XYINT_STEN, ~ep_num_both(0));
+        fs_andl(OTG_FUNC_IINT, ~ep_num_both(0));
+        UNLESS (ep0 & EP0_SETUP) {                                      // check if SETUP flag set
+                fs_pcd_stop_out(pcd, 0, endpoint);
+                return;
+        }
+        TRACE_MSG1(PCD, "EP0 - SETUP: size: %x", ep3 & 0xffff);
+        pcd_tx_cancelled_irq(endpoint);
+        pcd_rcv_cancelled_irq(endpoint);
+        fs_orl(OTG_FUNC_EP_TOGGLE, 0x2);                             // XXX is this required?
+
+        /* get request from x or y buffer
+         */
+        if (fs_rl(OTG_FUNC_XINT_STAT) & ep_num_out(0)) {
+                TRACE_MSG0(PCD, "READ X SETUP");
+                fs_memcpy((u8 *)&request, (u8 *)data_x_address(0, USB_DIR_OUT), 8);
+                fs_wl_clr(PCD, OTG_FUNC_XINT_STAT, ep_num_out(0));
+                fs_wl_clr(PCD, OTG_FUNC_XFILL_STAT, ep_num_out(0));
+                fs_rl(OTG_FUNC_XFILL_STAT);
+        }
+        else if (fs_rl(OTG_FUNC_YINT_STAT) & ep_num_out(0)) {
+                TRACE_MSG0(PCD, "READ Y SETUP");
+                fs_memcpy((u8 *)&request, (u8 *)data_y_address(0, USB_DIR_OUT), 8);
+                fs_wl_clr(PCD, OTG_FUNC_YINT_STAT, ep_num_out(0));
+                fs_wl_clr(PCD, OTG_FUNC_YFILL_STAT, ep_num_out(0));
+                fs_rl(OTG_FUNC_YFILL_STAT);
+        }
+        else
+                TRACE_MSG0(PCD, "READ NO SETUP");                             // XXX what should we do here?
+        if (pcd_recv_setup_irq(pcd, &request)) {                              // process setup packet
+                TRACE_MSG0(PCD, "pcd_ep0: STALLING");
+                fs_rl(OTG_FUNC_XINT_STAT);
+                fs_ep_config_nodma(0, USB_DIR_IN, 1, endpoint->wMaxPacketSize, endpoint->bmAttributes & 0x3, 0, 1, 1);
+                return;
+        }
+        RETURN_IF (request.wLength);                            // fs_pcd_start_endpoint_in() will start xfer
+        if ((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
+                //RETURN_IF (request.wLength);                            // fs_pcd_start_endpoint_in() will start xfer
+                fs_sendzlp(0, endpoint, endpoint->wMaxPacketSize);     // wLength zero, so send ZLP
+                return;
+        }
+        fs_pcd_start_ep0_setup(endpoint);                                  // restart endpoint 
+}
+/* ********************************************************************************************* */
+static int pcd_resetdet_count;
+/*! 
+ * fs_pcd_int_hndlr() - interrupt handler
+ * @param irq
+ * @param dev_id
+ * @param regs
+ * @return interrupt handled status
+ */
+static irqreturn_t 
+fs_pcd_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pcd_instance *pcd = pcd_instance;
+        u32 cmd_stat, sint_stat, ep_dstat, ep_stats, mask;
+
+        /* Reset and process any System interrupts
+         */
+        if ((sint_stat = fs_rl(OTG_FUNC_SINT_STAT))) 
+                fs_wl_clr(PCD, OTG_FUNC_SINT_STAT, sint_stat);
+
+        cmd_stat = fs_rl(OTG_FUNC_CMD_STAT);
+
+        TRACE_MSG2(PCD, "FUNC INT sint: %08x cmd: %08x", sint_stat, cmd_stat); 
+
+        if ((cmd_stat & COMMAND_RESETDET) || (sint_stat & SYSTEM_RESETINT)) {
+                TRACE_MSG1(PCD, "RESETDET: %08x", sint_stat);
+                usbd_bus_event_handler_irq (pcd->bus, DEVICE_RESET, 0);
+                fs_wl(OTG_FUNC_DEV_ADDR, 0);
+                fs_new_address = fs_usb_address = 0;
+                fs_wl(OTG_FUNC_XYINT_STEN, 0);
+                fs_wl(OTG_FUNC_IINT, 0);
+                //fs_wl(OTG_FUNC_EP_DEN, 0);  // XXX this fails, 
+                fs_wl(OTG_FUNC_EP_TOGGLE, 0);
+                fs_wl_clr(PCD, OTG_FUNC_EP_RDY, fs_rl(OTG_FUNC_EP_RDY));
+                fs_wl_clr(PCD, OTG_FUNC_EP_DSTAT, fs_rl(OTG_FUNC_EP_DSTAT));
+                fs_wl_clr(PCD, OTG_FUNC_XINT_STAT, fs_rl(OTG_FUNC_XINT_STAT));
+                fs_wl_clr(PCD, OTG_FUNC_YINT_STAT, fs_rl(OTG_FUNC_YINT_STAT));
+                if (pcd_resetdet_count++ > 10) {
+
+                        //printk(KERN_INFO"%s: SINT: %08x %08x CINT: %08x\n", __FUNCTION__,
+                        //                sint_stat, fs_rl(OTG_FUNC_SINT_STEN), fs_rl(OTG_CORE_CINT_STEN));
+                        fs_func_clock_on();
+                        fs_wl(OTG_FUNC_SINT_STEN, 0);
+                        fs_wl(OTG_CORE_CINT_STEN, 0);
+                        fs_wl(OTG_FUNC_XYINT_STEN, 0); 
+                        fs_wl(OTG_FUNC_EP_EN, 0); 
+                        fs_wl(OTG_FUNC_EP_DEN, 0);
+                        fs_func_clock_off();
+                        //printk(KERN_INFO"%s: SINT: %08x %08x CINT: %08x RESET\n", __FUNCTION__,
+                        //                sint_stat, fs_rl(OTG_FUNC_SINT_STEN), fs_rl(OTG_CORE_CINT_STEN));
+                }
+        }
+        if ((cmd_stat & COMMAND_RSMINPROG) || (sint_stat & SYSTEM_RSMFININT)) {
+                TRACE_MSG1(PCD, "RSMINPRO: %08x", sint_stat);
+                fs_wl_set(PCD, OTG_FUNC_SINT_STAT,SYSTEM_RSMFININT);
+                fs_func_clock_on();
+                usbd_bus_event_handler_irq (pcd->bus, DEVICE_BUS_ACTIVITY, 0);
+        }
+        if ((cmd_stat & COMMAND_SUPDET) || (sint_stat & SYSTEM_SUSPDETINT)) {
+                int timeout = 0;
+                TRACE_MSG1(PCD, "SUSPENDDET: %08x", sint_stat);
+                fs_wl_set(PCD, OTG_FUNC_SINT_STAT,SYSTEM_SUSPDETINT);
+                fs_func_clock_off();
+                usbd_bus_event_handler_irq (pcd->bus, DEVICE_BUS_INACTIVE, 0);
+        }
+        ep_dstat = fs_rl(OTG_FUNC_EP_DSTAT);
+        ep_stats = ep_dstat | fs_rl(OTG_FUNC_XINT_STAT) | fs_rl(OTG_FUNC_YINT_STAT);
+        if (ep_stats) {
+                int i;
+
+                pcd_resetdet_count = 0;
+
+                /* clear the done status flags
+                 */
+                TRACE_MSG1(PCD, "EP STATS: %08x", ep_stats);
+                fs_wl_clr(PCD, OTG_FUNC_EP_DSTAT, ep_dstat);
+
+                /* check ep0 first - special handling for control endpoint, need to check dstat, y/x stats
+                 */
+                if (ep_stats & EP_OUT) fs_pcd_stop_ep0_setup(pcd, pcd->bus->endpoint_array);
+                if (ep_stats & EP_IN) fs_pcd_stop_in(pcd, 0, pcd->bus->endpoint_array);
+
+                /* now check all of the data endpoints, only if in dstat
+                 */
+                for (i = 1, ep_dstat >>= 2; ep_dstat && (i < 16); i++, ep_dstat >>= 2) {
+                        if (ep_dstat & EP_OUT) fs_pcd_stop_out(pcd, i, pcd->bus->endpoint_array + (2 * i));
+                        if (ep_dstat & EP_IN) fs_pcd_stop_in(pcd, i, pcd->bus->endpoint_array + (2 * i) + 1);
+                }
+        }
+        return IRQ_HANDLED;
+}
+
+/* ********************************************************************************************* */
+/*!
+ * fs_pcd_set_address() - set the USB address for this device
+ * @param pcd
+ * @param address
+ */
+static void inline
+fs_pcd_set_address (struct pcd_instance *pcd, u8 address)
+{
+        fs_usb_address = 0;
+        fs_new_address = address;      /* this will be used in the interrupt handler */
+}
+
+/* ********************************************************************************************* */
+/*! 
+ * fs_pcd_en_func() - enable
+ * This is called to enable / disable the PCD and USBD stack.
+ * @param otg - otg instance
+ * @param flag - SET or RESET
+ */
+static void 
+fs_pcd_en_func (struct otg_instance *otg, u8 flag)
+{
+        unsigned long flags;
+        struct pcd_instance *pcd = otg->pcd;
+        struct usbd_bus_instance *bus = pcd->bus;
+        u32 hwmode = fs_rl(OTG_CORE_HWMODE);
+
+
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(PCD, "PCD_EN: SET");
+                local_irq_save (flags);
+                fs_andl(OTG_CORE_HWMODE, 0xffffff0f);                  // clear
+
+                //printk(KERN_INFO"%s: SET\n", __FUNCTION__);
+                if (hwmode & MODULE_CRECFG_HOST) {
+                        printk(KERN_INFO"%s: warning HOST STILL SET\n", __FUNCTION__);
+                }
+                fs_orl(OTG_CORE_HWMODE, MODULE_CRECFG_FUNC);           // set to software hnp
+
+		/* reset the function core
+		 */
+                //fs_wl_clr(PCD, OTG_CORE_RST_CTRL, MODULE_RSTFSIE | MODULE_RSTFC);
+                //while (fs_rl(OTG_CORE_RST_CTRL));
+		
+                fs_func_clock_on();
+
+                fs_pcd_start_ep0_setup(pcd->bus->endpoint_array);
+
+                /* C.f. L3 12.1 - enable Slave, Band Gap enable, and Comparator enable.
+                 * C.f. SCM-11 version of the USBOTG specification, ABBusReq enables the charge pump
+                 */
+                fs_andl(OTG_CORE_HNP_CSTAT, ~(MODULE_MASTER | MODULE_SLAVE | 
+                                        MODULE_CMPEN | MODULE_BGEN | MODULE_SWAUTORST | MODULE_ABBUSREQ));
+
+                fs_orl(OTG_CORE_HNP_CSTAT, MODULE_SLAVE | MODULE_CMPEN | MODULE_BGEN | MODULE_SWAUTORST | MODULE_ABBUSREQ);
+                fs_rl(OTG_CORE_HNP_CSTAT);
+
+                fs_orl(OTG_FUNC_SINT_STEN, ( /*SYSTEM_DONEREGINTDS_EN | *//*SYSTEM_SOFDETINT_EN |*/ SYSTEM_DONEREGINT_EN |
+                                        SYSTEM_SUSPDETINT_EN | SYSTEM_RSMFININT_EN | SYSTEM_RESETINT_EN));
+
+                fs_orl(OTG_CORE_CINT_STEN, MODULE_FCINT_EN | MODULE_ASFCINT_EN);
+                //printk(KERN_INFO"%s: SINT: %08x CINT: %08x SET\n", __FUNCTION__,
+                //                fs_rl(OTG_FUNC_SINT_STEN), fs_rl(OTG_CORE_CINT_STEN));
+                local_irq_restore (flags);
+        
+                break;
+
+        case RESET:
+                TRACE_MSG0(PCD, "PCD_EN: RESET");
+                //printk(KERN_INFO"%s: RESET\n", __FUNCTION__);
+
+                //fs_andl(OTG_FUNC_SINT_STEN, ~( /*SYSTEM_DONEREGINTDS_EN | *//*SYSTEM_SOFDETINT_EN |*/ SYSTEM_DONEREGINT_EN |
+                //                        SYSTEM_SUSPDETINT_EN | SYSTEM_RSMFININT_EN | SYSTEM_RESETINT_EN));
+                
+                local_irq_save (flags);
+                fs_func_clock_on();
+                fs_andl(OTG_FUNC_SINT_STEN, 0);
+                fs_andl(OTG_CORE_CINT_STEN, ~(MODULE_FCINT_EN | MODULE_ASFCINT_EN));
+
+                fs_func_clock_off();
+                //printk(KERN_INFO"%s: SINT: %08x CINT: %08x RESET\n", __FUNCTION__,
+                //                fs_rl(OTG_FUNC_SINT_STEN), fs_rl(OTG_CORE_CINT_STEN));
+
+                /* reset the function core
+                 */
+                fs_wl_clr(PCD, OTG_CORE_RST_CTRL, MODULE_RSTFSIE | MODULE_RSTFC);
+                while (fs_rl(OTG_CORE_RST_CTRL));
+                fs_andl(OTG_CORE_HWMODE, ~MODULE_CRECFG_FUNC);           // set to software hnp
+                local_irq_restore (flags);
+
+                usbd_bus_event_handler_irq (bus, DEVICE_RESET, 0);
+                usbd_bus_event_handler_irq (bus, DEVICE_DESTROY, 0);
+
+                break;
+        }
+        TRACE_MSG1(PCD, "HWMODE: %08x", fs_rl(OTG_CORE_HWMODE));
+}
+
+/*! 
+ * fs_remote_wakeup() - perform remote wakeup.
+ * Initiate a remote wakeup to the host.
+ * @param otg - otg instance
+ * @param flag - SET or RESET
+ */
+static void 
+fs_remote_wakeup(struct otg_instance *otg, u8 flag)
+{
+        unsigned long flags;
+        TRACE_MSG0(PCD, "MX2_REMOTE_WAKEUP: ");
+        local_irq_save (flags);
+        fs_wl_set(PCD, OTG_FUNC_CMD_STAT, COMMAND_RSMINPROG);
+        fs_wl(OTG_FUNC_CMD_STAT, COMMAND_RSMINPROG);
+        local_irq_restore (flags);
+}               
+
+/* ********************************************************************************************* */
+/*! 
+ * fs_pcd_start() - start the UDC
+ * @param pcd
+ */
+static void 
+fs_pcd_start (struct pcd_instance *pcd)
+{
+        //TRACE_MSG0(PCD, "UDC START");
+        fs_rl(OTG_FUNC_SINT_STEN);
+        //fs_pcd_start_ep0_setup(pcd_instance->bus->endpoint_array);
+}
+
+/*! 
+ * fs_pcd_stop() - stop the UDC
+ * @param pcd
+ */
+static void 
+fs_pcd_stop (struct pcd_instance *pcd)
+{
+        TRACE_MSG0(PCD, "UDC STOP");
+}
+
+/*!
+ * pcd_assign_endpoint()
+ */
+static int 
+pcd_assign_endpoint(u8 physicalEndpoint, int used[UDC_MAX_ENDPOINTS], 
+                struct usbd_endpoint_map *endpoint_map, u8 bmAttributes, u16 wMaxPacketSize, u16 transferSize) 
+{
+        RETURN_EINVAL_IF( used[physicalEndpoint] );
+        endpoint_map->bEndpointAddress[0] = physicalEndpoint | (USB_DIR_IN & bmAttributes);
+        endpoint_map->physicalEndpoint[0] = (physicalEndpoint * 2) + ((USB_DIR_IN & bmAttributes) ? 1 : 0);
+        endpoint_map->wMaxPacketSize[0] = wMaxPacketSize;
+        endpoint_map->transferSize[0] = transferSize;
+        endpoint_map->bmAttributes[0] = bmAttributes;
+        used[physicalEndpoint]++;
+        TRACE_MSG4(PCD, "ASSIGN: index: %02x phys: %02x addr: %02x", physicalEndpoint, 
+                         endpoint_map->physicalEndpoint[0], endpoint_map->bEndpointAddress[0], 0);
+        return 0;
+}
+
+/*!
+ * fs_pcd_request_endpoints()
+ * @param pcd
+ * @param endpoint_map_array
+ * @param endpointsRequested
+ * @param requestedEndpoints
+ */
+static int 
+fs_pcd_request_endpoints(struct pcd_instance *pcd, struct usbd_endpoint_map *endpoint_map_array, int endpointsRequested, 
+                struct usbd_endpoint_request *requestedEndpoints)
+{
+        struct usbd_device_description *device_description;
+        int i, in, out;
+        int in_used[UDC_MAX_ENDPOINTS];
+        int out_used[UDC_MAX_ENDPOINTS];
+        memset(in_used, 0, sizeof(in_used));
+        memset(out_used, 0, sizeof(out_used));
+        TRACE_MSG1(PCD, "REQUEST ENDPOINTS: %d", endpointsRequested);
+        for (in = out = 1, i = 0; i < endpointsRequested; i++) {
+                struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
+                u8 bmAttributes = requestedEndpoints[i].bmAttributes;
+                u16 transferSize = requestedEndpoints[i].fs_requestedTransferSize;
+                switch(bmAttributes) {
+                case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
+                case USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
+                case USB_DIR_IN | USB_ENDPOINT_BULK:
+                        CONTINUE_IF(!pcd_assign_endpoint(in++, in_used, endpoint_map, bmAttributes, 0x40, transferSize));
+                        THROW(error);
+
+                case USB_DIR_OUT | USB_ENDPOINT_BULK:
+                case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
+                case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
+                        CONTINUE_IF(!pcd_assign_endpoint(out++, out_used, endpoint_map, bmAttributes, 0x40, transferSize));
+                        //CONTINUE_IF(!pcd_assign_endpoint(in++, out_used, endpoint_map, bmAttributes, 0x40, transferSize));
+                        THROW(error);
+
+                case USB_ENDPOINT_CONTROL:
+                        continue;
+                case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
+                case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
+                        THROW(error);
+                }
+                THROW(error);
+                CATCH(error) {
+                        printk(KERN_ERR"%s: FAILED num: %d bmAttributes: %02x transferSize: %02x\n", 
+                                        __FUNCTION__, i, bmAttributes, transferSize);
+                        return -EINVAL;
+                }
+        }
+        return 0;
+}
+
+/*! 
+ * fs_pcd_set_endpoints() - setup the physical endpoints for the endpoint map
+ * @param pcd
+ * @param endpointsRequested
+ * @param endpoint_map_array
+ */
+static int 
+fs_pcd_set_endpoints (struct pcd_instance *pcd, int endpointsRequested, struct usbd_endpoint_map *endpoint_map_array)
+{
+        fs_clear_words((volatile u32 *)MX2_IO_ADDRESS(OTG_EP_BASE), (32*16/4));
+        //fs_clear((void *)MX2_IO_ADDRESS(OTG_EP_BASE), 0x200);
+        TRACE_MSG0(PCD, "Enable system control interrupts");
+        fs_wl(OTG_SYS_CTRL, SYS_CTRL_I2C_WU_INT_EN | SYS_CTRL_OTG_WU_INT_EN | SYS_CTRL_HOST_WU_INT_EN | SYS_CTRL_FNT_WU_INT_EN);
+        return 0;
+}
+
+/*! 
+ * fs_pcd_framenum() - get current framenum
+ */             
+static u16 
+fs_pcd_framenum (void)
+{               
+        return fs_rl(OTG_FUNC_FRM_NUM);
+}               
+
+/* 
+ * fs_endpoint_halted() - is endpoint halted
+ */
+static int 
+fs_endpoint_halted (struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint)
+{
+        int epn = endpoint->bEndpointAddress & 0x7f;
+        int dir = (endpoint->bEndpointAddress & 0x80) ? 1 : 0;
+
+        TRACE_MSG2(PCD, "epn: %02x dir: %x", epn, dir);
+        return fs_rl(ep_word(epn, dir, 0))  & (1 << 31) ? TRUE : FALSE;
+}
+
+/* fs_halt_endpoint - halt endpoint
+ */
+int fs_halt_endpoint(struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint, int flag)
+{
+        int epn = endpoint->bEndpointAddress & 0x7f;
+        int dir = (endpoint->bEndpointAddress & 0x80) ? 1 : 0;
+        TRACE_MSG3(PCD, "epn: %02x dir: %x flag: %d", epn, dir, flag);
+        fs_ep_config_nodma(epn, USB_DIR_IN, flag, endpoint->wMaxPacketSize, endpoint->bmAttributes & 0x3, 0, 0, 1);
+        return 0;
+}
+
+/* ********************************************************************************************* */
+
+#if !defined(OTG_C99)
+struct usbd_pcd_ops usbd_pcd_ops;
+struct pcd_ops pcd_ops;
+
+/*!
+ * fs_pcd_global_init() - initialize globals
+ */
+static void 
+fs_pcd_global_init(void)
+{
+        ZERO(usbd_pcd_ops);
+        usbd_pcd_ops.bmAttributes = USB_OTG_HNP_SUPPORTED | USB_OTG_SRP_SUPPORTED;
+        usbd_pcd_ops.max_endpoints =  UDC_MAX_ENDPOINTS;
+        usbd_pcd_ops.ep0_packetsize =  EP0_PACKETSIZE;
+        usbd_pcd_ops.capabilities = REMOTE_WAKEUP_SUPPORTED;
+        usbd_pcd_ops.name =  UDC_NAME;
+        usbd_pcd_ops.start = fs_pcd_start;
+        usbd_pcd_ops.stop = fs_pcd_stop;
+        usbd_pcd_ops.start_endpoint_in = fs_pcd_start_endpoint_in;
+        usbd_pcd_ops.start_endpoint_out = fs_pcd_start_endpoint_out;
+        usbd_pcd_ops.request_endpoints = fs_pcd_request_endpoints;
+        usbd_pcd_ops.set_endpoints = fs_pcd_set_endpoints;
+        usbd_pcd_ops.set_address = fs_pcd_set_address;
+        usbd_pcd_ops.setup_ep = fs_pcd_setup_ep;
+        usbd_pcd_ops.halt_endpoint = fs_halt_endpoint;
+        usbd_pcd_ops.endpoint_halted = fs_endpoint_halted;
+
+        usbd_pcd_ops.cancel_in_irq = fs_pcd_cancel_in_irq;
+        usbd_pcd_ops.cancel_out_irq = fs_pcd_cancel_out_irq;
+
+        ZERO(pcd_ops);
+        pcd_ops.pcd_en_func = fs_pcd_en_func;
+        pcd_ops.pcd_init_func = pcd_init_func;
+	pcd_ops.remote_wakeup_func = fs_remote_wakeup;
+	pcd_ops.framenum = fs_pcd_framenum;
+}
+#else /* !defined(OTG_C99) */
+static struct 
+usbd_pcd_ops usbd_pcd_ops = {
+        .bmAttributes = USB_OTG_HNP_SUPPORTED | USB_OTG_SRP_SUPPORTED,
+        .max_endpoints =  UDC_MAX_ENDPOINTS,
+        .ep0_packetsize =  EP0_PACKETSIZE,
+        .capabilities = REMOTE_WAKEUP_SUPPORTED,
+        .name =  UDC_NAME,
+        .start = fs_pcd_start,
+        .stop = fs_pcd_stop,
+        .start_endpoint_in = fs_pcd_start_endpoint_in,
+        .start_endpoint_out = fs_pcd_start_endpoint_out,
+        .request_endpoints = fs_pcd_request_endpoints,
+        .set_endpoints = fs_pcd_set_endpoints,
+        .set_address = fs_pcd_set_address,
+        .setup_ep = fs_pcd_setup_ep,
+        .halt_endpoint = fs_halt_endpoint,
+        .endpoint_halted = fs_endpoint_halted,
+
+        .cancel_in_irq = fs_pcd_cancel_in_irq,
+        .cancel_out_irq = fs_pcd_cancel_out_irq,
+};
+
+struct pcd_ops pcd_ops = {
+        .pcd_en_func = fs_pcd_en_func,
+        .pcd_init_func = pcd_init_func,
+	.remote_wakeup_func = fs_remote_wakeup,
+	.framenum = fs_pcd_framenum,
+};
+#endif /* !defined(OTG_C99) */
+
+/* @} */
+
diff -uNr linux/drivers/no-otg/ocd/gen/gen.c linux/drivers/otg/ocd/gen/gen.c
--- linux/drivers/no-otg/ocd/gen/gen.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/gen/gen.c	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,268 @@
+/*
+ * otg/ocd/gen/gen.c -- USB Device Controller driver 
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/gen/gen.c
+ * @brief Sample driver
+ *
+ *
+ * @ingroup USBP
+ */
+
+#include <udc.h>
+#include <asm/hardware.h>
+#include "gen.h"
+
+
+static unsigned char usb_address;
+
+/* ********************************************************************************************* */
+/* udc_write_buffer - write a buffer to the udc fifo
+ */
+static void udc_write_buffer (unsigned char ep, unsigned char *b, unsigned char size)
+{
+}
+
+/* udc_read_buffer - fill a buffer from the udc fifo
+ */
+static void udc_read_buffer (unsigned char ep, unsigned char *b, unsigned char size)
+{
+}
+
+/* udc_out - process an OUT interrupt
+ */
+static void udc_out (struct usbd_endpoint_instance *endpoint)
+{
+}
+
+/* udc_in  - process an IN interrupt
+ */
+static void udc_in (struct usbd_endpoint_instance *endpoint)
+{
+}
+
+/* ********************************************************************************************* */
+/* udc_in_ep0 - start transmit of ep0 Control Read data
+ */
+static void udc_in_ep0 (struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *tx_urb = pcd_tx_complete_irq (endpoint, 0);
+        if (!tx_urb || pcd_tx_sendzlp (endpoint)) {
+                udc_write_buffer (0, NULL, 0);
+                return;
+        }
+        TRACE_MSG16("EP0 IN: actual: %d sent: %d", endpoint->tx_urb->actual_length, endpoint->sent);
+        endpoint->last = MIN (tx_urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
+        udc_write_buffer (0, tx_urb->buffer + endpoint->sent, endpoint->last);
+}
+
+/* udc_out_ep0 - start receive of ep0 Control Write data
+ */
+static void udc_out_ep0 (struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *rcv_urb = pcd_rcv_next_irq (endpoint);
+        int size = 0; 
+        RETURN_IF(!rcv_urb);
+        TRACE_MSG8("OUT EP0: actual: %d buffer_length: %d size: %d", rcv_urb->actual_length, rcv_urb->buffer_length, size, 0);
+        udc_read_buffer (0, rcv_urb->buffer + rcv_urb->actual_length, size);
+        if (!pcd_rcv_complete_irq (endpoint, size, 0)) 
+                endpoint->state = WAIT_FOR_SETUP;
+}
+
+/* udc_ep0_setup - process a Control Setup command
+ */
+static void udc_ep0_setup (struct usbd_endpoint_instance *endpoint)
+{
+        static struct usbd_device_request request;
+        u8 *cp = (u8 *) &request;
+        int i;
+        TRACE_MSG32("EP0 SETUP: tx_urb: %p", (int)endpoint->tx_urb);
+        pcd_tx_cancelled_irq (endpoint);
+        pcd_rcv_cancelled_irq (endpoint);
+        if (pcd_recv_setup_irq (&request)) {              // process setup packet
+                TRACE_MSG("udc_ep0: setup failed");
+                //udc_stall_ep (0);
+                endpoint->state = WAIT_FOR_SETUP;
+                return;
+        }
+        if ((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
+                TRACE_MSG32("udc_ep0: send zlp %d", le16_to_cpu (request.wLength));     // XXX 
+                //ctrl_outb (EP0s_RDFN, USBTRG);
+                RETURN_IF(pcd_rcv_next_irq (endpoint));
+                //and_b (~EP0o_TS, USBIER0);
+                return;
+        }
+}
+/* ********************************************************************************************* */
+/* udc_int_hndlr - interrupt handler
+ */
+static void udc_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
+{
+        trace_ops.interrupts++;
+#if 0
+        if (trace_ops.interrupts > 1000) { udc_disable_interrupts (); udc_disable (); TRACE_MSG("UDC DISABLE"); return; }
+#endif
+}
+/* ********************************************************************************************* */
+/* udc_start_endpoint_in - start transmit
+ */
+void udc_start_endpoint_in (struct usbd_endpoint_instance *endpoint)
+{               
+}
+
+/* udc_start_endpoint_out - start receive
+ */
+void udc_start_endpoint_out (struct usbd_endpoint_instance *endpoint)
+{
+}
+/* ********************************************************************************************* */
+/* udc_attached - is the USB cable attached
+ * Return non-zero if cable is attached.
+ */
+int udc_attached (void)
+{
+        return 0;
+}
+
+static int udc_connect_status;
+
+/* udc_connected - is the USB pullup enabled
+ * Return non-zero if pullup is enabled.
+ */
+int udc_connected (void)
+{
+        return udc_connect_status;
+}
+
+/* udc_connect - enable pullup resistor
+ */
+void udc_connect (void)
+{
+        udc_connect_status = 1;
+}
+
+/* udc_disconnect - disable pullup resistor
+ */
+void udc_disconnect (void)
+{
+        udc_connect_status = 0;
+}
+
+/* udc_start - start session
+ */
+void udc_start (void)
+{
+        // udc_enable_interrupts ();
+}
+
+/* udc_stop - stop session
+ */
+void udc_stop (void)
+{
+        // udc_disable_interrupts ();
+}
+
+/* udc_enable - enable the UDC
+ */
+void udc_enable (void)
+{
+}
+
+/* udc_disable - disable the UDC
+ */
+void udc_disable (void)
+{
+}
+
+/* udc_init - initialize
+ * Return non-zero if we cannot see device.
+ */
+int udc_init (void)
+{
+        return 0;
+}
+
+/* udc_exit - disable the UDC
+ */
+void udc_exit (void)
+{
+}
+
+/* ********************************************************************************************* */
+/* udc_assign_endpoint
+ */
+int udc_assign_endpoint (u8 physicalEndpoint, int used[6], struct usbd_endpoint_map *endpoint_map, u8 bmAttributes,
+                u16 wMaxPacketSize, u16 transferSize) 
+{
+        RETURN_EINVAL_IF(used[physicalEndpoint]);
+        endpoint_map->bEndpointAddress[0] = physicalEndpoint | (bmAttributes & USB_IN_DIR);
+        endpoint_map->physicalEndpoint[0] = physicalEndpoint;
+        endpoint_map->wMaxPacketSize[0] = wMaxPacketSize;
+        endpoint_map->transferSize[0] = transferSize;
+        endpoint_map->bmAttributes[0] = bmAttributes;
+        used[physicalEndpoint]++;
+        return 0;
+}
+
+/* udc_request_endpoints - process endpoint request list
+ */
+int udc_request_endpoints (struct usbd_endpoint_map *endpoint_map_array, int endpointsRequested, 
+                struct usbd_endpoint_request *requestedEndpoints)
+{
+        struct usbd_device_description *device_description;
+        int i, j;
+        int used[UDC_MAX_ENDPOINTS];
+        memset (used, 0, sizeof (used));
+        for (j = 0, i = 0; i < endpointsRequested; i++) {
+                struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
+                u8 bmAttributes = requestedEndpoints[i].bmAttributes;
+                u16 transferSize = requestedEndpoints[i].fs_requestedTransferSize;
+                switch (bmAttributes) {
+                case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
+                case USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
+                case USB_DIR_IN | USB_ENDPOINT_BULK:
+                case USB_DIR_OUT | USB_ENDPOINT_BULK:
+                        BREAK_IF(!udc_assign_endpoint (j++, used, endpoint_map, bmAttributes, 0x40, transferSize));
+                        return -EINVAL;
+                case USB_ENDPOINT_CONTROL:
+                        continue;
+                case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
+                case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
+                case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
+                case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
+                        return -EINVAL;
+                }
+                return -EINVAL;
+                }
+                RETURN_EINVAL_UNLESS (j < UDC_MAX_ENDPOINTS);
+        }
+        return 0;
+}
+/* ********************************************************************************************* */
+struct udc_ops udc_ops = {
+        max_endpoints:  UDC_MAX_ENDPOINTS,
+        ep0_packetsize:  EP0_PACKETSIZE,
+        name:  UDC_NAME,
+        init: udc_init,
+        exit: udc_exit,
+        enable: udc_enable,
+        disable: udc_disable,
+        start: udc_start,
+        stop: udc_stop,
+        start_endpoint_in: udc_start_endpoint_in,
+        start_endpoint_out: udc_start_endpoint_out,
+        request_endpoints: udc_request_endpoints,
+        attached: udc_attached,
+        connected: udc_connected,
+        connect: udc_connect,
+        disconnect: udc_disconnect,
+};
+
diff -uNr linux/drivers/no-otg/ocd/gen/gen.h linux/drivers/otg/ocd/gen/gen.h
--- linux/drivers/no-otg/ocd/gen/gen.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/gen/gen.h	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,29 @@
+/*
+ * otg/ocd/gen/gen.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+/*!
+ * @file otg/ocd/gen/gen.h
+ * @brief Private structures and defines for Intel PXA-270
+ *
+ * Notes
+ *
+ * 1. This is a minmal outline for a simple UDC driver.
+ *
+ *
+ * @ingroup BVD
+ */
+
+
+#define UDC_NAME                "GEN"
+#define UDC_MAX_ENDPOINTS       3
+#define EP0_PACKETSIZE          8
+
diff -uNr linux/drivers/no-otg/ocd/isp1301/Config.in linux/drivers/otg/ocd/isp1301/Config.in
--- linux/drivers/no-otg/ocd/isp1301/Config.in	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/isp1301/Config.in	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,17 @@
+
+#
+# Copyright (c) 2004 Belcarra
+#
+# ISP 1301 TCD
+
+if [ "$CONFIG_OTG_ISP1301" = "y" ]; then
+    mainmenu_option next_comment
+
+    comment 'ISP 1301 (i2c)'
+   
+        dep_bool 'Proc FS debug' CONFIG_OTG_ISP1301_PROCFS $CONFIG_OTG_ISP1301
+
+    endmenu
+else
+    define_bool CONFIG_OTG_ISP1301_PROCFS n
+fi
diff -uNr linux/drivers/no-otg/ocd/isp1301/Kconfig linux/drivers/otg/ocd/isp1301/Kconfig
--- linux/drivers/no-otg/ocd/isp1301/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/isp1301/Kconfig	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,15 @@
+
+#
+# Copyright (c) 2004 Belcarra
+#
+
+# OMAP 1610 H2 development board
+#
+config OTG_ISP1301_OMAP_H2
+	tristate "OMAP 1610 H2 Development board - ISP 1301 (i2c)"
+	depends on I2C && OTG && ARCH_OMAP && OMAP_H2
+
+config OTG_ISP1301_MX2ADS
+	tristate "MX2ADS Development board - ISP 1301 (i2c)"
+	depends on I2C && OTG && ARCH_MX2ADS 
+
diff -uNr linux/drivers/no-otg/ocd/isp1301/Makefile linux/drivers/otg/ocd/isp1301/Makefile
--- linux/drivers/no-otg/ocd/isp1301/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/isp1301/Makefile	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,96 @@
+#
+# Makefile for the kernel USBD (device not host) drivers.
+#
+# Copyright (c) 2004 Belcarra
+
+# Subdirs.
+# This is a bit complex, because some subdirs are for
+# proprietary code, and are simply not present in a
+# general distribution.
+
+# The all-CAPS *_DIRS get nuked in the new versions
+# of Rules.make, so use only the subdir-* methods.
+subdir-y 	:=
+subdir-m 	:=
+subdir-n 	:=
+subdir- 	:=
+
+# The target object and module list name.
+
+O_TARGET	:= isp1301_target.o
+list-multi      := isp1301_tcd.o
+
+# Objects that export symbols.
+
+# Multipart objects.
+
+omap_h2_tcd-objs	:= tcd-init-l24.o tcd-omap-h2.o isp1301.o i2c-l26.o tcd.o isp1301-procfs.o
+mainstone_tcd-objs	:= tcd-init-l24.o tcd-mainstone.o tcd.o i2c-l26.o isp1301.o isp1301-procfs.o thread-l24.o
+
+# Optional parts of multipart objects.
+
+# Object file lists.
+
+obj-y		:=
+obj-m		:=
+obj-n		:=
+obj-		:=
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_OTG_ISP1301_OMAP_H2)	+= omap_h2_tcd.o
+obj-$(CONFIG_OTG_ISP1301_MAINSTONE)	+= mainstone_tcd.o
+
+# Object files in subdirectories
+
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+int-m		:= $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
+OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+
+# The global Rules.make.
+
+DOT_DIR=$(TCD_DIR)/isp1301
+
+include $(TOPDIR)/Rules.make
+OTG=$(TOPDIR)/drivers/otg
+OCD_DIR=$(OTG)/ocd
+INCLUDE_DIRS =          -I$(OTG) 
+EXTRA_CFLAGS +=          -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
+EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
+
+PCD=$(OTG)/ocd/otg-pcd
+vpath %.c $(USBDCORE_DIR) $(OCD_DIR) $(PCD)
+
+
+# Link rules for multi-part drivers.
+
+omap_h2_tcd.o: $(omap_h2_tcd-objs)
+	$(LD) -r -o $@ $(iomap_h2_tcd-objs)
+
+mainstone_tcd.o: $(mainstone_tcd-objs)
+	$(LD) -r -o $@ $(mainstone_tcd-objs)
+
+# dependencies:
+
+# local
+
+
diff -uNr linux/drivers/no-otg/ocd/isp1301/Makefile-l26 linux/drivers/otg/ocd/isp1301/Makefile-l26
--- linux/drivers/no-otg/ocd/isp1301/Makefile-l26	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/isp1301/Makefile-l26	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,26 @@
+#
+# Makefile for the kernel USBD (device not host) drivers.
+#
+# Copyright (c) 2004 Belcarra Technologies Corp
+
+DOT_DIR=$(TCD_DIR)/isp1301
+
+OTG=$(TOPDIR)/drivers/otg
+HCD_DIR=$(OTG)/hcd
+TCD_DIR=$(OTG)/tcd
+USBDCORE_DIR=$(OTG)/usbdcore
+OTGCORE_DIR=$(OTG)/otgcore
+INCLUDE_DIRS =          -I$(OTG) 
+EXTRA_CFLAGS +=          -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
+EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
+
+vpath %.c $(USBDCORE_DIR) $(OCD_DIR) 
+
+
+# Link rules for multi-part drivers.
+
+omap_h2_tcd-objs	:= ../tcd-init-l24.o tcd-omap-h2.o isp1301.o i2c-l26.o ../tcd.o 
+obj-$(CONFIG_OTG_ISP1301_OMAP_H2)	+= omap_h2_tcd.o
+
+
+
diff -uNr linux/drivers/no-otg/ocd/isp1301/isp1301-procfs.c linux/drivers/otg/ocd/isp1301/isp1301-procfs.c
--- linux/drivers/no-otg/ocd/isp1301/isp1301-procfs.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/isp1301/isp1301-procfs.c	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,385 @@
+/*
+ * otg/ocd/isp1301/isp1301-procfs.c - USB Device Core Layer
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ */
+/*!
+ * @file otg/ocd/isp1301/isp1301-procfs.c
+ * @brief Implement /proc/isp1301 to dump ISP1301 registers.
+ *
+ *
+ * @ingroup ISP1301TCD
+ */
+
+
+#include <otg/pcd-include.h>
+#include "otghw/isp1301-hardware.h"
+#include <otghw/isp1301.h>
+
+#ifdef CONFIG_ARCH_MX2ADS
+#include <asm/arch/mx2.h>
+#define MX2_OTG_XCVR_DEVAD                      0x18
+#define MX2_SEQ_OP_REG                          0x19
+#define MX2_SEQ_RD_STARTAD                      0x1a
+#define MX2_I2C_OP_CTRL_REG                     0x1b
+#define MX2_SCLK_TO_SCL_HPER                    0x1e
+#define MX2_I2C_INTERRUPT_AND_CTRL              0x1f
+
+#define OTG_BASE_ADDR                           0x10024000
+//#define OTG_I2C_BASE                            (OTG_BASE_ADDR+0x100)
+
+#endif /* CONFIG_ARCH_MX2ADS */
+
+#ifdef CONFIG_OTG_ISP1301_PROCFS
+/* Proc Filesystem *************************************************************************** */
+
+extern struct isp1301_private isp1301_private;
+
+#define MAX_HISTORY     6
+struct reg_list {
+        u8 reg;
+        u8 size;
+        char *name;
+        u32 values[MAX_HISTORY];
+};
+
+#define REG(r, s)  {r, s, #r, }
+
+struct reg_list isp1301_prod_list[] = {
+        REG(ISP1301_VENDOR_ID, 2),
+        REG(ISP1301_PRODUCT_ID, 2),
+        REG(ISP1301_VERSION_ID, 2),
+        { 0, 1, NULL,}, 
+};
+struct reg_list isp1301_reg_list[] = {
+        REG(ISP1301_OTG_CONTROL_SET, 1),
+        REG(ISP1301_INTERRUPT_SOURCE, 1),
+        REG(ISP1301_INTERRUPT_LATCH_SET, 1),
+        REG(ISP1301_INTERRUPT_ENABLE_LOW_SET, 1),
+        REG(ISP1301_INTERRUPT_ENABLE_HIGH_SET, 1),
+        REG(ISP1301_MODE_CONTROL_1_SET, 1),
+        { 0, 1, NULL,}, 
+};
+struct reg_list isp1301_spec_list[] = {
+        REG(ISP1301_MODE_CONTROL_2_SET, 1),
+        REG(ISP1301_OTG_STATUS, 1),
+        { 0, 1, NULL,}, 
+};
+struct reg_list max3301e_spec_list[] = {
+        REG(MAX3301E_SPECIAL_FUNCTION_1_SET, 1),
+        REG(MAX3301E_SPECIAL_FUNCTION_2_SET, 1),
+        { 0, 1, NULL,}, 
+};
+#ifdef CONFIG_ARCH_MX2ADS
+struct reg_list mx21_spec_list[] = {
+        REG(MX2_OTG_XCVR_DEVAD, 1),
+        REG(MX2_SEQ_OP_REG, 1),
+        REG(MX2_SEQ_RD_STARTAD, 1),
+        REG(MX2_I2C_OP_CTRL_REG, 1),
+        REG(MX2_SCLK_TO_SCL_HPER, 1),
+        REG(MX2_I2C_INTERRUPT_AND_CTRL, 1),
+        { 0, 1, NULL,}, 
+};
+#endif /* CONFIG_ARCH_MX2ADS */
+
+void isp1301_update(struct reg_list *list)
+{
+        for (; list && list->name; list++) {
+                TRACE_MSG1(TCD, "list: %s", list->name);
+                memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32));
+                switch(list->size) {
+                case 1: 
+                        list->values[0] = i2c_readb(list->reg); 
+                        break;
+                case 2: 
+                        list->values[0] = i2c_readw(list->reg); 
+                        break;
+                case 4: 
+                        list->values[0] = i2c_readl(list->reg); 
+                        break;
+                }
+        }
+}
+
+#ifdef CONFIG_ARCH_MX2ADS
+static u8 __inline__ mx2_rb(u32 port)
+{
+        return *(volatile u8 *) (MX2_IO_ADDRESS(port + OTG_I2C_BASE));
+}
+
+
+void mx21_update(struct reg_list *list)
+{
+        for (; list && list->name; list++) {
+                memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32));
+                list->values[0] = mx2_rb(list->reg); 
+        }
+}
+
+#endif /* CONFIG_ARCH_MX2ADS */
+
+void isp1301_update_all(void)
+{
+        isp1301_update(isp1301_reg_list);
+        switch (isp1301_private.transceiver_map->transceiver_type) {
+        case isp1301:
+                isp1301_update(isp1301_spec_list);
+                break;
+        case max3301e:
+                isp1301_update(max3301e_spec_list);
+                break;
+        default:
+                break;
+        }
+#ifdef CONFIG_ARCH_MX2ADS
+        mx21_update(mx21_spec_list);
+#endif /* CONFIG_ARCH_MX2ADS */
+
+}
+
+
+
+/*
+ * dohex
+ *
+ */
+static void dohexdigit (char *cp, unsigned char val)
+{
+        if (val < 0xa) 
+                *cp = val + '0';
+        else if ((val >= 0x0a) && (val <= 0x0f)) 
+                *cp = val - 0x0a + 'a';
+}
+
+/*
+ * dohex
+ *
+ */
+static void dohexval (char *cp, unsigned char val)
+{
+        dohexdigit (cp++, val >> 4);
+        dohexdigit (cp++, val & 0xf);
+}
+
+int isp1301_dump(char *buf, char *name, char *fmt, struct reg_list *reg)
+{
+        int len = 0, i;
+        len += sprintf (buf + len, "%-20s  %-34s [%03x]:  ", name, reg->name, reg->reg);
+        len += sprintf (buf + len, fmt, reg->values[0]);
+        for (i = 1; i < MAX_HISTORY; i++) 
+                if (reg->values[i - 1] == reg->values[i]) 
+                        len += sprintf (buf + len, "         ");
+                else 
+                        len += sprintf (buf + len, fmt, reg->values[i]);
+        len += sprintf (buf + len, "\n");
+        return len;
+}
+
+int isp1301_dump_list(char * buf, char *name, struct reg_list *list)
+{
+        int len = 0;
+        for (; list && list->name; list++) 
+                switch(list->size) {
+                case 1: len += isp1301_dump(buf + len, name, "       %02x", list); break;
+                case 2: len += isp1301_dump(buf + len, name, "     %04x", list); break;
+                case 4: len += isp1301_dump(buf + len, name, " %08x", list); break;
+                }
+        return len;
+}
+
+char *isp1301_otg_control[8] = {
+        "DP_PULLUP",
+        "DM_PULLUP",
+        "DP_PULLDOWN",
+        "DM_PULLDOWN",
+        "ID_PULLDOWN",
+        "VBUS_DRV",
+        "VBUS_DISCHRG",
+        "VBUS_CHRG",
+};
+char *isp1301_interrupt_source[8] = {
+        "VBUS_VLD",
+        "SESS_VLD",
+        "DP_HI",
+        "ID_GND",
+        "DM_HI",
+        "ID_FLOAT",
+        "BDIS_ACON",
+        "CR_INT",
+};
+
+char *isp1301_mode_control_1[8] = {
+        "SPEED_REG",
+        "SUSPEND_REG",
+        "DAT_SE0",
+        "TRANSP_EN",
+        "BDIS_ACON_EN",
+        "OE_INT_EN",
+        "UART_EN",
+        NULL,
+};
+
+char *isp1301_otg_status[8] = {
+        NULL, NULL, NULL, NULL, NULL, NULL,
+        "B_SESS_END",
+        "B_SESS_VLD",
+};
+
+int isp1301_detailed(char *buf, char *name, u8 reg, char **detail)
+{
+        u8 val;
+        int i;
+        int len = 0;
+
+        val = i2c_readb(reg); 
+        for (i = 7; i >= 0; i--) {
+                
+                if (3 == (i % 4)) 
+                        len += sprintf (buf + len, "\n%-20s [%02d] ", name, reg);
+
+                if (detail[i])
+                        len += sprintf (buf + len, "%14s%s ", detail[i], (val & (1 << i)) ? " " : "/");
+                else
+                        len += sprintf (buf + len, "%14s%s ", "",  " ");
+        }
+        len += sprintf (buf + len, "\n", name);
+
+        return len;
+}
+
+int isp1301_dump_all(char *buf)
+{
+        int len = 0;
+        len += isp1301_dump_list(buf + len, "ISP1301 Standard", isp1301_reg_list);
+        switch (isp1301_private.transceiver_map->transceiver_type) {
+        case isp1301:
+                len += isp1301_dump_list(buf + len, "ISP1301 Extra", isp1301_spec_list);
+                break;
+        case max3301e:
+                len += isp1301_dump_list(buf + len, "MAX3301E Extra", max3301e_spec_list);
+                break;
+        default:
+                break;
+        }
+#ifdef CONFIG_ARCH_MX2ADS
+        len += isp1301_dump_list(buf + len, "MX21 ADS Extra", mx21_spec_list);
+#endif /* CONFIG_ARCH_MX2ADS */
+        return len;
+}
+
+int isp1301_dump_detail(char *buf)
+{
+        int len = 0;
+
+        len += isp1301_detailed(buf + len, "MODE CONTROL 1", ISP1301_MODE_CONTROL_1, isp1301_mode_control_1);
+        len += isp1301_detailed(buf + len, "INTERRUPT ENABLE", ISP1301_INTERRUPT_ENABLE_HIGH, isp1301_interrupt_source);
+
+        len += isp1301_detailed(buf + len, "OTG CONTROL", ISP1301_OTG_CONTROL_SET, isp1301_otg_control);
+        len += isp1301_detailed(buf + len, "INTERRUPT SOURCE", ISP1301_INTERRUPT_SOURCE, isp1301_interrupt_source);
+        len += isp1301_detailed(buf + len, "OTG STATUS", ISP1301_OTG_STATUS, isp1301_otg_status);
+        return len;
+}
+
+
+/*!
+ * isp1301_device_proc_read - implement proc file system read.
+ *
+ * Standard proc file system read function.
+ *
+ * We let upper layers iterate for us, *pos will indicate which device to return
+ * statistics for.
+ */
+static ssize_t isp1301_device_proc_read_functions (struct file *file, char *buf, size_t count, loff_t * pos)
+{
+        unsigned long page;
+        int len = 0;
+        int index;
+        int i;
+        u32 r;
+
+        int config_size;
+
+        // get a page, max 4095 bytes of data...
+        RETURN_EINVAL_UNLESS ((page = get_free_page (GFP_KERNEL)));
+
+        len = 0;
+        index = (*pos)++;
+
+        //printk(KERN_INFO"%s: index: %d\n", __FUNCTION__, index);
+        switch(index) {
+        case 0:
+                len += sprintf ((char *) page + len, "ISP1301 Transceiver Registers\n");
+
+                TRACE_MSG0(TCD, "UPDATING");
+                isp1301_update_all();
+                TRACE_MSG0(TCD, "UPDATE FINISHED");
+                len += sprintf ((char *) page + len , "Vendor: %04x Product: %04x Revision: %04x %s\n", 
+                                isp1301_private.vendor, isp1301_private.product,
+                                isp1301_private.revision, isp1301_private.transceiver_map->name
+                                );
+
+                len += isp1301_dump_all((char *) page + len);
+                len += sprintf ((char *) page + len, "\n");
+
+                break;
+
+        case 1:
+                len += sprintf ((char *) page + len, "\n--\n");
+                len += isp1301_dump_detail((char *) page + len);
+                len += sprintf ((char *) page + len, "\n");
+                break;
+
+        default:
+                break;
+
+        }
+
+        //printk(KERN_INFO"%s: len: %d\n", __FUNCTION__, len);
+
+        if (len > count) 
+                len = -EINVAL;
+        
+        else if ((len > 0) && copy_to_user (buf, (char *) page, len)) 
+                len = -EFAULT;
+        
+        //printk(KERN_INFO"%s: len: %d\n", __FUNCTION__, len);
+        free_page (page);
+        return len;
+}
+
+static struct file_operations isp1301_device_proc_operations_functions = {
+        read:isp1301_device_proc_read_functions,
+};
+
+/* Module init ******************************************************************************* */
+
+static int isp1301_procfs_init (void)
+{
+        struct proc_dir_entry *p;
+
+        // create proc filesystem entries
+        if ((p = create_proc_entry ("isp1301", 0, 0)) == NULL)
+                return -ENOMEM;
+
+        p->proc_fops = &isp1301_device_proc_operations_functions;
+
+        isp1301_update_all();
+
+        return 0;
+}
+static void isp1301_procfs_exit (void)
+{
+        remove_proc_entry ("isp1301", NULL);
+}
+#else
+static int isp1301_procfs_init (void) { return 0;
+}
+static void isp1301_procfs_exit (void) { }
+#endif
diff -uNr linux/drivers/no-otg/ocd/isp1301/isp1301.c linux/drivers/otg/ocd/isp1301/isp1301.c
--- linux/drivers/no-otg/ocd/isp1301/isp1301.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/isp1301/isp1301.c	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,923 @@
+/*
+ * otg/ocd/isp1301/isp1301.c -- USB Transceiver Controller driver
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By:
+ *      Stuart Lynne <sl@lbelcarra.com>,
+ *      Tom Rushworth <tbr@belcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/isp1301/isp1301.c
+ * @brief ISP1301 OTG Transceiver Driver.
+ *
+ * This is the generic ISP1301 TCD core support.
+ *
+ * Notes:
+ *
+ * 1. The ISP1301 can control the speed and suspend directly, would it be
+ * appropriate to allow state machine to control this.
+ *
+ * 2. The ISP1301 has auto connect feature, can this be used without change
+ * to state machine.
+ *
+ * 3. The ISP1301 can control the ADR/PSW pin to enable / disable external
+ * charge pump.
+ *
+ * @ingroup ISP1301TCD
+ */
+
+#include <otg/otg-compat.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/i2c.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-ocd.h>
+#include <otg/otg-pcd.h>
+
+#include <otghw/isp1301-hardware.h>
+#include <otghw/isp1301.h>
+
+#ifdef CONFIG_OMAP_H2
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#endif /* CONFIG_OMAP_H2 */
+
+struct otg_transceiver_map isp1301_transceiver_map[] = {
+        { isp1301, 0x4cc, 0x1301, 0x00, "Phillips ISP1301", },
+        { max3301e, 0x6a0b, 0x0133, 0x00, "Maxim MAX3301E", },
+        { 0, 0, 0, 0, "Unknown Transceiver", },
+};
+
+struct isp1301_private isp1301_private;
+
+
+
+/* ********************************************************************************************* */
+#define TRACE_I2CB(t,r) TRACE_MSG3(t, "%-40s[%02x] %02x", #r, r, i2c_readb(r))
+#define TRACE_I2CW(t,r) TRACE_MSG3(t, "%-40s[%02x] %04x", #r, r, i2c_readw(r))
+#define TRACE_GPIO(t,b,r) TRACE_MSG2(t, "%-40s %04x", #r, readw(b + r))
+#define TRACE_REGL(t,r) TRACE_MSG2(t, "%-40s %08x", #r, readl(r))
+
+
+
+/*! isp1301_int_src - update interrupt source test mask
+ *
+ * This sets the current mask and updates the interrupt registers to match.
+ */
+void isp1301_int_src(u8 int_src)
+{
+        TRACE_MSG1(TCD, "setting int_src %02x", int_src);
+        isp1301_private.int_src = int_src;
+        i2c_writeb(ISP1301_INTERRUPT_ENABLE_LOW_CLR, ~int_src);
+        i2c_writeb(ISP1301_INTERRUPT_ENABLE_HIGH_CLR, ~int_src);
+        i2c_writeb(ISP1301_INTERRUPT_ENABLE_LOW_SET, int_src);
+        i2c_writeb(ISP1301_INTERRUPT_ENABLE_HIGH_SET, int_src);
+        i2c_writeb(ISP1301_INTERRUPT_LATCH_CLR, int_src);
+}
+
+/*! isp1301_int_src_set - add to the interrupt source mask
+ *
+ */
+void isp1301_int_src_set(u8 int_src)
+{
+        isp1301_int_src(int_src |= isp1301_private.int_src);
+}
+
+/*! isp1301_int_src_clr - remove from the interrup source mask
+ */
+void isp1301_int_src_clr(u8 int_src)
+{
+        isp1301_int_src(int_src = isp1301_private.int_src & ~int_src);
+}
+
+/* ********************************************************************************************* */
+
+typedef struct isp1301_test {
+        u32     input;
+        char   *name;
+        u8      mask;
+} isp1301_test_t;
+
+#define OV(i, m) {i, #i, m}
+
+struct isp1301_test isp1301_int_src_tests[9] = {
+
+        OV(VBUS_VLD, ISP1301_VBUS_VLD),
+        OV(A_SESS_VLD, ISP1301_SESS_VLD),
+        OV(DP_HIGH, ISP1301_DP_HI),
+        OV(ID_GND, ISP1301_ID_GND),
+        OV(DM_HIGH, ISP1301_DM_HI),
+        OV(ID_FLOAT, ISP1301_ID_FLOAT),
+        OV(BDIS_ACON, ISP1301_BDIS_ACON),
+        OV(CR_INT_DET, ISP1301_CR_INT),
+        {0, NULL, 0},
+};
+
+struct isp1301_test isp1301_otg_status_tests[3] = {
+
+        OV(B_SESS_END, ISP1301_B_SESS_END),
+        OV(B_SESS_VLD, ISP1301_B_SESS_VLD),
+        {0, NULL, 0},
+};
+
+/*! isp1301_event() - set input bit based on current settings and interrupt mask
+ */
+u64 isp1301_event(struct otg_instance *otg, struct isp1301_test *tests, int val, int testmask, char *msg)
+{
+        int i;
+        u64 inputs = 0;
+        TRACE_MSG3(TCD, "val: %02x mask: %02x %s", val, testmask, msg);
+        for (i = 0; tests[i].mask; i++) {
+                u64 input = tests[i].input;
+                u8 mask = tests[i].mask;
+                CONTINUE_UNLESS(mask & testmask);
+                inputs |= (val & mask) ? input : _NOT(input);
+                TRACE_MSG6(TCD, "%s%s %02x %08x inputs: %08x %08x", 
+                                tests[i].name, (val & mask) ? "" : "/", tests[i].mask, tests[i].input,
+                                (u32) (inputs >> 32), (u32)(inputs & 0xffffffff)
+                                );
+        }
+        return inputs;
+}
+
+
+
+int isp1301_bh_first;
+int isp1301_debounce;
+u64 isp1301_ticks;
+
+void isp1301_info(char *msg, u8 value)
+{
+        u64 new_ticks = otg_tmr_ticks();
+        u64 ticks = otg_tmr_elapsed(&new_ticks, &isp1301_ticks);
+
+        if (ticks < 10000)
+                TRACE_MSG3(PCD, "ISP1301 %d uS %s: %02x", (u32)(ticks & 0xffffffff), msg, value);
+        else if (ticks < 10000000)
+                TRACE_MSG3(PCD, "ISP1301 %d mS %s: %02x", (u32)((ticks >> 10) & 0xffffffff), msg, value);
+        else
+                TRACE_MSG3(PCD, "ISP1301 %d S  %s: %02x", (u32)((ticks >> 20) & 0xffffffff), msg, value);
+
+        isp1301_ticks = new_ticks;
+}
+
+
+void isp1301_trace(u8 int_src, u8 int_changed, char *msg)
+{
+
+        u64 new_ticks = otg_tmr_ticks();
+        u64 ticks = otg_tmr_elapsed(&new_ticks, &isp1301_ticks);
+
+        if (ticks < 10000)
+                TRACE_MSG4(PCD, "ISP1301 %d uS %s: src: %02x chng: %02x", 
+                                (u32)(ticks & 0xffffffff), msg, int_src, int_changed);
+        else if (ticks < 10000000)
+                TRACE_MSG4(PCD, "ISP1301 %d mS %s src: %02x chng: %02x", 
+                                (u32)((ticks >> 10) & 0xffffffff), msg, int_src, int_changed);
+        else
+                TRACE_MSG4(PCD, "ISP1301 %d S  %s src: %02x chng: %02x ", 
+                                (u32)((ticks >> 20) & 0xffffffff), msg, int_src, int_changed);
+
+        isp1301_ticks = new_ticks;
+}
+
+/*! isp1301_bh   
+ */             
+void isp1301_bh(void *arg)
+{               
+        u64 inputs = 0;
+        u8 int_lat, int_src1 = 0, int_src2 = 0, otg_status = 0, special_function_22 = 0;
+        static u8 int_src_saved, otg_status_saved, special_function_22_saved;
+
+        //TRACE_MSG0(TCD, "--");
+        /* read the interrupt latch and and clear latch and update otg  
+         */
+        if ((int_lat = i2c_readb(ISP1301_INTERRUPT_LATCH_SET))) {
+                //TRACE_MSG1(TCD, "CLEARING INT LAT: %02x", int_lat);
+                isp1301_info("INT LAT", int_lat);
+                i2c_writeb(ISP1301_INTERRUPT_LATCH_CLR, int_lat);
+        }
+
+        isp1301_info("INT_LAT", int_lat);
+
+        /* If int_lat shows a change or we are forcing an update, read interrupt source.
+         * Note that we mask DP_HI and DM_HI when LOC_CONN is set, we don't want them 
+         * when USB Bus is in use.
+         *
+         * Mask with bits we are currently interested in.
+         *
+         * Ensure that we have two matching reads to ensure that value is stable.
+         * Also ensure that interrupt source is non-zero.
+         */
+
+        int_src1 = i2c_readb(ISP1301_INTERRUPT_SOURCE);
+        isp1301_trace(int_src1, int_src_saved ^ int_src1, "INT_SRC_1");
+       
+        do {
+                int_src2 = i2c_readb(ISP1301_INTERRUPT_SOURCE);         // re-read interrupt source
+                BREAK_IF(int_src1 && (int_src1 & (ISP1301_ID_GND | ISP1301_ID_FLOAT)) && 
+                                (int_src1 == int_src2));           // finished if non-zero and same
+                isp1301_trace(int_src2, int_src_saved ^ int_src2, "INT_SRC_2");
+                int_src1 = int_src2;                                    // save most recent read value
+        } while (1);
+
+
+        #if 0
+        while ( (int_src1 != (int_src2 = i2c_readb(ISP1301_INTERRUPT_SOURCE) & isp1301_private.int_src))) {
+                isp1301_trace(int_src2, int_src_saved ^ int_src2, "INT_SRC_2");
+                int_src1 = int_src2;
+        } 
+        #endif
+
+        if (isp1301_bh_first || int_src_saved ^ (int_src1 & isp1301_private.int_src)) {
+                int_src_saved = int_src1;
+                inputs |= isp1301_event(tcd_instance->otg, isp1301_int_src_tests, int_src1, 
+                                isp1301_private.int_src, "ISP1301 INT SRC");
+                if (int_src1 & ISP1301_VBUS_VLD) {
+                        TRACE_MSG0(TCD, "VBUS_VLD, setting B_SESS_VLD");
+                        inputs |= B_SESS_VLD;
+                }
+                else if (!(int_src1 & ISP1301_SESS_VLD)) {
+                        TRACE_MSG0(TCD, "A_SESS_VLD/, setting B_SESS_VLD/");
+                        inputs |= B_SESS_VLD_;
+                }
+        }
+
+        /* further work if B-Device 
+         */
+        if ( !(int_src1 & ISP1301_ID_GND) || !(int_src_saved & ISP1301_ID_GND) ) {
+                /* read the otg_status register and update otg state machine
+                 *
+                 * XXX this needs to be conditional on Transceiver type. The
+                 * MAX3301E for example supports sess_end in a separate register.
+                 */
+                switch (isp1301_private.transceiver_map->transceiver_type) {
+                case isp1301:
+                        otg_status = i2c_readb(ISP1301_OTG_STATUS);
+                        isp1301_trace(otg_status, int_src_saved ^ int_src1, "OTG_STATUS");
+                        TRACE_MSG3(TCD, "otg_status_saved: %02x otg_status: %02x chng: %02x", 
+                                        otg_status_saved, otg_status, otg_status_saved ^ otg_status);
+
+                        if (isp1301_bh_first || (otg_status_saved ^ otg_status)) {
+                                inputs |= isp1301_event(tcd_instance->otg, isp1301_otg_status_tests, otg_status, 0xff,
+                                                "ISP1301 OTG STATUS");
+                                otg_status_saved = otg_status;
+                        }
+
+                        #if 0
+                        isp1301_info("OTG STATUS", otg_status);
+                        if (isp1301_bh_first) 
+                                otg_status_saved = ~otg_status;
+
+                        otg_status_saved = isp1301_update_otg_status( tcd_instance->otg, otg_status,
+                                        otg_status_saved ^ otg_status);
+                        #endif
+                        break;
+
+                        // XXX
+                case max3301e:
+                        special_function_22 = i2c_readb(MAX3301E_SPECIAL_FUNCTION_2_SET);
+                        break;
+                case unknown_transceiver:
+                        break;
+                }
+        }
+        if (inputs) otg_event(tcd_instance->otg, inputs, TCD, "ISP1301");
+        isp1301_bh_first = 0;
+}
+
+
+/*! isp1301_bh_wakeup - wakeup the isp1301 bottom half
+ */
+void isp1301_bh_wakeup(int first)
+{
+        //TRACE_MSG0(TCD, "--");
+        isp1301_bh_first |= first;
+        SCHEDULE_WORK(isp1301_private.bh);
+}
+
+
+/* ********************************************************************************************** */
+/*! isp1301_vbus - Do we have Vbus (cable attached?)
+ * Return non-zero if Vbus is detected.
+ *
+ */
+int isp1301_vbus (struct otg_instance *otg)
+{
+        return 0;
+}
+
+/*! isp1301_id - Do we have Vbus (cable attached?)
+ * Return non-zero if Vbus is detected.
+ *
+ */
+int isp1301_idvbus (struct otg_instance *otg)
+{
+        return 0;
+}
+
+
+/* ********************************************************************************************* */
+/*! isp1301_tcd_en() - used to enable 
+ *
+ */
+void isp1301_tcd_en(struct otg_instance *otg, u8 flag)
+{
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "SET");
+                break;
+        case PULSE:
+                TRACE_MSG0(TCD, "PULSE");
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "RESET");
+                break;
+        }
+        isp1301_bh_wakeup(TRUE);
+}
+
+
+/*! isp1301_chrg_vbus - used to enable or disable B-device Vbus charging
+ */
+void isp1301_chrg_vbus(struct otg_instance *otg, u8 flag)
+{
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "CHRG_VBUS_SET");
+                i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_VBUS_CHRG);
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "CHRG_VBUS_RESET");
+                i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_VBUS_RESET);
+                break;
+        case PULSE:
+                break;
+        }
+}
+
+/*! isp1301_drv_vbus - used to enable or disable A-device driving Vbus 
+ */
+void isp1301_drv_vbus(struct otg_instance *otg, u8 flag)
+{
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "DRV_VBUS_SET");
+                i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_VBUS_DRV);
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "DRV_VBUS_RESET");
+                i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_VBUS_RESET);
+                break;
+        }
+}
+
+/*! isp1301_dischrg_vbus - used to enable Vbus discharge
+ */
+void isp1301_dischrg_vbus(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "OUTPUT: TCD_DISCHRG_VBUS_SET");
+                i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_VBUS_DISCHRG);
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "OUTPUT: TCD_DISCHRG_VBUS_RESET");
+                i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_VBUS_RESET);
+                break;
+        }
+}
+
+/*! isp1301_mx21_vbus_drain - used to enable Vbus discharge
+ */
+void isp1301_mx21_vbus_drain_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "OUTPUT: TCD_DISCHRG_VBUS_SET");
+                i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_VBUS_DISCHRG);
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "OUTPUT: TCD_DISCHRG_VBUS_RESET");
+                i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_VBUS_RESET);
+                break;
+        }
+}
+
+/*! isp1301_dp_pullup_func - used to enable or disable peripheral connecting to bus
+ *
+ * C.f. 5.1.6, 5.1.7, 5.2.4 and 5.2.5
+ *
+ *                              host    peripheral
+ *              d+ pull-up      clr     set
+ *              d+ pull-down    set     clr
+ *
+ *              d- pull-up      clr     clr
+ *              d- pull-down    set     set
+ *
+ */
+void isp1301_dp_pullup_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                isp1301_private.flags |= ISP1301_LOC_CONN;
+                TRACE_MSG0(TCD, "ISP1301_LOC_CONN SET - Set DP PULLUP");
+                i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DP_PULLUP);
+                break;
+
+        case RESET:
+                isp1301_private.flags &= ~ISP1301_LOC_CONN;
+                TRACE_MSG0(TCD, "ISP1301_LOC_CONN RESET - Clr DP PULLUP");
+                i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_DP_PULLUP);
+                break;
+        }
+}
+
+/*! isp1301_dm_pullup_func - used to enable or disable peripheral connecting to bus
+ *
+ */
+void isp1301_dm_pullup_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                isp1301_private.flags |= ISP1301_LOC_CONN;
+                TRACE_MSG0(TCD, "ISP1301_LOC_CONN SET - Set DM PULLUP");
+                i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DM_PULLUP);
+                break;
+
+        case RESET:
+                isp1301_private.flags &= ~ISP1301_LOC_CONN;
+                TRACE_MSG0(TCD, "ISP1301_LOC_CONN RESET - Clr DM PULLUP");
+                i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_DM_PULLUP);
+                break;
+        }
+}
+
+/*! isp1301_dp_pulldown_func - used to enable or disable peripheral connecting to bus
+ *
+ * C.f. 5.1.6, 5.1.7, 5.2.4 and 5.2.5
+ *
+ *                              host    peripheral
+ *              d+ pull-up      clr     set
+ *              d+ pull-down    set     clr
+ *
+ *              d- pull-up      clr     clr
+ *              d- pull-down    set     set
+ *
+ */
+void isp1301_dp_pulldown_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                isp1301_private.flags |= ISP1301_LOC_CONN;
+                TRACE_MSG0(TCD, "ISP1301_LOC_CONN SET - Set DP PULLUP");
+                i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DP_PULLDOWN);
+                break;
+
+        case RESET:
+                isp1301_private.flags &= ~ISP1301_LOC_CONN;
+                TRACE_MSG0(TCD, "ISP1301_LOC_CONN RESET - Clr DP PULLUP");
+                i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_DP_PULLDOWN);
+                break;
+        }
+}
+
+/*! isp1301_dm_pulldown_func - used to enable or disable peripheral connecting to bus
+ *
+ */
+void isp1301_dm_pulldown_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                isp1301_private.flags |= ISP1301_LOC_CONN;
+                TRACE_MSG0(TCD, "ISP1301_LOC_CONN SET - Set DM PULLUP");
+                i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DM_PULLDOWN);
+                break;
+
+        case RESET:
+                isp1301_private.flags &= ~ISP1301_LOC_CONN;
+                TRACE_MSG0(TCD, "ISP1301_LOC_CONN RESET - Clr DM PULLUP");
+                i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_DM_PULLDOWN);
+                break;
+        }
+}
+
+/*! isp1301_peripheral_host_func - used to enable or disable peripheral connecting to bus
+ *
+ * A-Device             D+ pulldown     D- pulldown
+ *      idle            set             set
+ *      host            set             set
+ *      peripheral      reset           set
+ *
+ * B-Device
+ *      idle            set             set
+ *      host            set             set
+ *      peripheral      reset           set
+ */
+void isp1301_peripheral_host_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:       // peripheral
+                TRACE_MSG0(TCD, "SET - CLR DP PULLDOWN");
+                i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_DP_PULLDOWN);
+                break;
+
+        case RESET:     // host
+                TRACE_MSG0(TCD, "RESET - SET DM PULLDOWN");
+                i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DP_PULLDOWN);
+                break;
+        }
+}
+
+/*! isp1301_dm_det_func - used to enable or disable D- detect
+ *
+ */
+void isp1301_dm_det_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting DM_HI detect");
+                isp1301_int_src_set(ISP1301_DM_HI);
+                isp1301_bh_wakeup(TRUE);
+                isp1301_debounce = 0;
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting DM_HI detect");
+                isp1301_int_src_clr(ISP1301_DM_HI);
+                isp1301_bh_wakeup(TRUE);
+                isp1301_debounce = 1;
+                break;
+        }
+}
+
+/*! isp1301_dp_det_func - used to enable or disable D+ detect
+ *
+ */
+void isp1301_dp_det_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting DP_HI detect");
+                isp1301_int_src_set(ISP1301_DP_HI);
+                isp1301_bh_wakeup(TRUE);
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting DP_HI detect");
+                isp1301_int_src_clr(ISP1301_DP_HI);
+                isp1301_bh_wakeup(TRUE);
+                break;
+        }
+}
+
+/*! isp1301_cr_det_func - used to enable or disable D+ detect
+ *
+ */
+void isp1301_cr_det_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting CR_INT detect");
+                isp1301_int_src_set(ISP1301_CR_INT);
+                isp1301_bh_wakeup(TRUE);
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting CR_INT detect");
+                isp1301_int_src_clr(ISP1301_CR_INT);
+                isp1301_bh_wakeup(TRUE);
+                break;
+        }
+}
+
+/*! isp1301_bdis_acon_func - used to enable or disable auto a-connect
+ *
+ */
+void isp1301_bdis_acon_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting BDIS ACON");
+                isp1301_int_src_set(ISP1301_BDIS_ACON);
+                i2c_writeb(ISP1301_MODE_CONTROL_1_SET, ISP1301_BDIS_ACON_EN);
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting BDIS ACON");
+                i2c_writeb(ISP1301_MODE_CONTROL_1_CLR, ISP1301_BDIS_ACON_EN);
+                isp1301_int_src_clr(ISP1301_BDIS_ACON);
+                break;
+        }
+}
+
+/*! isp1301_id_pulldown_func - used to enable or disable ID pulldown
+ *
+ */
+void isp1301_id_pulldown_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting ID PULLDOWN");
+                i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_ID_PULLDOWN);
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting ID PULLDOWN");
+                i2c_writeb(ISP1301_OTG_CONTROL_CLR, ISP1301_ID_PULLDOWN);
+                break;
+        }
+}
+
+/*! isp1301_audio_func - used to enable or disable Carkit Interrupt
+ *
+ */
+void isp1301_audio_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "SET AUDIO_EN");
+                //isp1301_int_src_set(ISP1301_CR_INT);
+                i2c_writeb(ISP1301_MODE_CONTROL_2_SET, ISP1301_AUDIO_EN);
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "RESET AUDIO_EN");
+                i2c_writeb(ISP1301_MODE_CONTROL_2_CLR, ISP1301_AUDIO_EN);
+                //isp1301_int_src_clr(ISP1301_CR_INT);
+                break;
+        }
+}
+
+/*! isp1301_uart_func - used to enable or disable transparent uart mode
+ *
+ */
+void isp1301_uart_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting UART_EN");
+                i2c_writeb(ISP1301_MODE_CONTROL_1_SET, ISP1301_UART_EN);
+                /* XXX enable uart */
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting UART_EN");
+                i2c_writeb(ISP1301_MODE_CONTROL_1_CLR, ISP1301_UART_EN);
+                /* XXX disable uart */
+                break;
+        }
+}
+
+/*! isp1301_mono_func - used to enable or disable mono audio connection
+ *
+ */
+void isp1301_mono_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        //TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting MONO");
+                /* XXX enable mono output */
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting MONO");
+                /* XXX disable mono output */
+                break;
+        }
+}
+
+
+/* ********************************************************************************************* */
+extern int isp1301_procfs_init (void);
+extern void isp1301_procfs_exit (void);
+
+extern void mx2_isp1301_bh(void *arg);
+
+/*! isp1301_mod_init
+ */
+int isp1301_mod_init(WORK_PROC bh_proc)
+//int isp1301_mod_init(void)
+{
+        /* for interrupt bottom half handler
+         */
+        //PREPARE_WORK_ITEM(isp1301_private.bh, &isp1301_bh, NULL);
+
+        UNLESS(bh_proc)
+                bh_proc = &isp1301_bh;
+
+        PREPARE_WORK_ITEM(isp1301_private.bh, bh_proc, NULL);
+
+        //else
+        //        PREPARE_WORK_ITEM(isp1301_private.bh, &isp1301_bh, NULL);
+
+        /* setup isp1301, enable interrupts, clear latch
+         * XXX when and how do we do DM_HI and DP_HI, when ID is present?
+         */
+
+        isp1301_int_src(ISP1301_ID_FLOAT | ISP1301_DM_HI | ISP1301_ID_GND | ISP1301_DP_HI | ISP1301_SESS_VLD | ISP1301_VBUS_VLD);
+        
+        //isp1301_int_src(ISP1301_INT_SRC);
+        //isp1301_int_src(ISP1301_NO_SE1_INT);
+        //isp1301_int_src_clr(ISP1301_CR_INT);
+
+        //i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DM_PULLDOWN | ISP1301_DP_PULLDOWN);
+
+#ifdef CONFIG_OTG_ISP1301_PROCFS
+        isp1301_procfs_init ();
+#endif /* CONFIG_OTG_ISP1301_PROCFS */
+
+        return 0;
+}
+
+/*! isp1301_mod_exit
+ */
+void isp1301_mod_exit(void)
+{
+        i2c_writeb(ISP1301_INTERRUPT_ENABLE_LOW_CLR, 0xff);
+        i2c_writeb(ISP1301_INTERRUPT_ENABLE_HIGH_CLR, 0xff);
+        //i2c_close();
+#ifdef CONFIG_OTG_ISP1301_PROCFS
+        isp1301_procfs_exit ();
+#endif /* CONFIG_OTG_ISP1301_PROCFS */
+
+        while (PENDING_WORK_ITEM(isp1301_private.bh)) {
+                printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
+                schedule_timeout(10 * HZ);
+        }
+
+}
+
+/* ********************************************************************************************* */
+/*! isp1301_configure - configure the ISP1301 for this host
+ * @param tx_mode - the type of connection between the host USB and the ISP1301
+ * @param spd_ctrl - suspend control method
+ */
+void  isp1301_configure(tx_mode_t tx_mode, spd_ctrl_t spd_ctrl)
+{
+        u16 vendor = 0, product = 0, revision = 0;
+        u8 mode1, mode2, control;
+
+        struct otg_transceiver_map *map = isp1301_transceiver_map;
+
+
+#if defined(CONFIG_OTG_ISP1301_MX2ADS) || defined(CONFIG_OTG_ISP1301_MX2ADS_MODULE)
+        u32 vp;
+        TRACE_MSG0(TCD, "1. Read Transceiver ID's with long read");
+        vp = i2c_readl(ISP1301_VENDOR_ID);
+        isp1301_private.vendor = vp & 0xffff;
+        isp1301_private.product = vp >> 16;
+        isp1301_private.revision = i2c_readw(ISP1301_VERSION_ID);
+        mode1 = i2c_readb(ISP1301_MODE_CONTROL_1_SET);
+        mode2 = i2c_readb(ISP1301_MODE_CONTROL_2_SET);
+         
+        TRACE_MSG5(TCD, "2. OTG Transceiver: vendor: %04x product: %04x revision: %04x mode1: %02x mode2: %02x",
+                        vendor, product, revision, mode1, mode2); 
+
+#else /* defined(CONFIG_OTG_ISP1301_MX2ADS) */
+
+        isp1301_private.vendor = i2c_readw(ISP1301_VENDOR_ID);
+        isp1301_private.product = i2c_readw(ISP1301_PRODUCT_ID);
+        isp1301_private.revision = i2c_readw(ISP1301_VERSION_ID);
+        mode1 = i2c_readb(ISP1301_MODE_CONTROL_1_SET);
+        mode2 = i2c_readb(ISP1301_MODE_CONTROL_2_SET);
+
+        TRACE_MSG5(TCD, "2. OTG Transceiver: vendor: %04x product: %04x revision: %04x mode1: %02x mode2: %02x",
+                        isp1301_private.vendor, isp1301_private.product, isp1301_private.revision, mode1, mode2); 
+
+#endif /* defined(CONFIG_OTG_ISP1301_MX2ADS) */
+
+        for ( ; map && map->transceiver_type != unknown_transceiver; map++) {
+                CONTINUE_UNLESS ((isp1301_private.vendor == map->vendor) && (isp1301_private.product == map->product));
+                TRACE_MSG1(TCD, "Found Transceiver: %s", map->name);
+                isp1301_private.transceiver_map = map;
+                break;
+        }
+        UNLESS (isp1301_private.transceiver_map) 
+                isp1301_private.transceiver_map = isp1301_transceiver_map;
+
+        TRACE_MSG0(TCD, "3. Disable All Transceiver Control Register 1 ");
+        i2c_writeb(ISP1301_OTG_CONTROL_CLR, 0xff);                                    // clear
+         
+        TRACE_MSG0(TCD, "4. Enable D-/D+ Pulldowns in Transceiver Control Register 1 ");
+
+        i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DM_PULLDOWN | ISP1301_DP_PULLDOWN);
+        i2c_writeb(ISP1301_OTG_CONTROL_CLR, (u8) ISP1301_DM_PULLUP | ISP1301_DP_PULLUP);
+
+
+        TRACE_MSG0(TCD, "5. Clear latch and enable interrupts");
+        i2c_writeb(ISP1301_INTERRUPT_LATCH_CLR, 0xff);
+        //i2c_writeb(ISP1301_INTERRUPT_ENABLE_LOW_CLR, 0xeb);
+        //i2c_writeb(ISP1301_INTERRUPT_ENABLE_HIGH_CLR, 0xeb);
+        isp1301_int_src_set(0xeb);
+        
+        /* The PSW_OE enables the ADR/PSW pin for output driving either high
+         * or low depending on the address.
+         *
+         * ADR          ADR_REG Address         PSW_OE=0        PSW_OE=1
+         *
+         *      low     0       0x2c            LOW             HIGH
+         *
+         *      high    1       0x2d            HIGH            LOW
+         *
+         *
+         * The i2c address by tying the ADR/PSW pin either high or low.
+         * Setting the PSW_OE drives the ADR/PSW into the opposite of the
+         * default wiring.
+         *
+         * On the MX21ADS the ADR/PSW pin is wired high which enables the
+         * charge pump. So enabling the PSW_OE is required to disable Vbus
+         * generation on the Charge Pump.
+         *
+         * The MAX3355E will only enable Vbus when this signal is high AND
+         * the ID signal is low. So it may be safe to leave enabled when
+         * operating as a B-device (ID floating.)
+         */
+        
+        //i2c_writeb(ISP1301_MODE_CONTROL_2_SET, ISP1301_PSW_OE);              // PSW_OE - OFFVBUS low
+
+
+        TRACE_MSG1(TCD, "6. tx_mode: %02x", tx_mode);
+        switch (tx_mode) {
+        case vp_vm_bidirectional:
+                break;
+        case dat_se0_unidirectional:
+                i2c_writeb(ISP1301_MODE_CONTROL_2_CLR, ISP1301_BI_DI);
+        case dat_se0_bidirectional:
+                i2c_writeb(ISP1301_MODE_CONTROL_1_SET, ISP1301_DAT_SE0);
+                break;
+        }
+        TRACE_MSG0(TCD, "6. tx_mode done");
+
+        TRACE_MSG1(TCD, "7. spd_ctrl: %02x", spd_ctrl);
+        switch (spd_ctrl) {
+        case spd_susp_pins:
+                i2c_writeb(ISP1301_MODE_CONTROL_2_CLR, ISP1301_SPD_SUSP_CTRL);
+                break;
+        case spd_susp_reg:
+                i2c_writeb(ISP1301_MODE_CONTROL_2_SET, ISP1301_SPD_SUSP_CTRL);
+                break;
+        }
+
+        //i2c_writeb(ISP1301_MODE_CONTROL_2_SET, ISP1301_PSW_OE);              // PSW_OE - OFFVBUS low
+
+        TRACE_MSG0(TCD, "7. spd_ctrl done");
+
+        TRACE_MSG1(TCD, "8. transceiver_type: %02x", isp1301_private.transceiver_map);
+
+        TRACE_MSG1(TCD, "8. transceiver_type: %02x", isp1301_private.transceiver_map->transceiver_type);
+        switch (isp1301_private.transceiver_map->transceiver_type) {
+        case isp1301:
+                break;
+        case max3301e:
+                i2c_writeb(MAX3301E_SPECIAL_FUNCTION_1_SET, MAX3301E_SESS_END);
+                break;
+        case unknown_transceiver:
+                break;
+        }
+        TRACE_MSG0(TCD, "8. transceiver_type done");
+}
+
diff -uNr linux/drivers/no-otg/ocd/isp1301/tcd-mainstone.c linux/drivers/otg/ocd/isp1301/tcd-mainstone.c
--- linux/drivers/no-otg/ocd/isp1301/tcd-mainstone.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/isp1301/tcd-mainstone.c	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,177 @@
+/*
+ * otg/ocd/mx2/tcd-mainstone.c -- Mainstone ISP1301 Transceiver Controller driver 
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/isp1301/tcd-mainstone.c
+ * @brief Mainstone ISP1301 driver.
+ *
+ * This implements the ISP1301 Transceiver Controller Driver for the Mainstone
+ * using the USBOTG I2C controller for access.
+ *
+ * Notes
+ *
+ * 1. The interrupt source is handled by the OCD driver so we just publish
+ * an interrupt handler for it to call.
+ *
+ *
+ * @ingroup ISP1301TCD
+ */
+
+#include <otg/pcd-include.h>
+#include <linux/pci.h>
+#include <asm/arch/irq.h>
+#include <asm/arch/irqs.h>
+#include <otghw/isp1301-hardware.h>
+#include "mx2.h"
+#include "otghw/bvd-hardware.h"
+#include <otghw/isp1301.h>
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+
+
+/* ********************************************************************************************* */
+
+
+/*! isp1301_int_hndlr 
+ */
+static irqreturn_t isp1301_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
+{
+        TRACE_MSG0(TCD, "--");
+
+        SCHEDULE_WORK(isp1301_private.bh);
+
+        return IRQ_HANDLED;
+}
+
+
+/* ********************************************************************************************* */
+
+/*! mainstone_tcd_init - used to initialize/enable or disable the tcd driver
+ */
+void mainstone_tcd_init(struct otg_instance *otg, u8 flag)
+{
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "MAINSTONE_TCD_EN SET");
+                otg_event(otg, TCD_OK, TCD, "TCD_OK");
+                isp1301_thread_wakeup(1, 1);
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "MAINSTONE_TCD_EN RESET");
+                isp1301_thread_wakeup(0, 0);
+                otg_event(otg, TCD_OK, TCD, "TCD_OK");
+                break;
+        }
+}
+
+
+struct tcd_ops tcd_ops;
+struct tcd_instance *mainstone_tcd_instance;
+//wait_queue_head_t mx2_i2c_wait;                                         // wait structure for i2c i/o interrupt
+
+#define ADAPTOR_NAME "PXA-I2C-Adapter"
+
+/*! mainstone_mod_init
+ */
+int mainstone_mod_init(void)
+{
+        struct otg_instance *otg;
+        int i2c = i2c_configure(ADAPTOR_NAME, ISP1301_I2C_ADDR_HIGH);
+        int irq = request_irq (GPIOX_TO_IRQ(35), isp1301_int_hndlr, SA_INTERRUPT, "ISP1301", NULL);
+
+        TRACE_MSG0(TCD, "--");
+
+        THROW_IF(i2c, error);
+
+        TRACE_MSG0(TCD, "1. Enable Mainstone external OTG Transceiver!");
+
+        TRACE_MSG1(TCD, "MST_MSCWR2: %08x", MST_MSCWR2);
+        MST_MSCWR2 |= MSCWR2_USB_OTG_SEL | MSCWR2_USB_OTG_RST;
+        TRACE_MSG1(TCD, "MST_MSCWR2: %08x", MST_MSCWR2);
+
+
+        TRACE_MSG0(TCD, "2. configure i2c driver!");
+        isp1301_configure(dat_se0_bidirectional, spd_susp_reg);
+
+        TRACE_MSG0(TCD, "3. configure isp1301!");
+        isp1301_mod_init();
+
+        TRACE_MSG0(TCD, "4. set ops");
+        THROW_UNLESS(ocd_instance && (otg = ocd_instance->otg), error);
+        THROW_UNLESS(mainstone_tcd_instance = otg_set_tcd_ops(&tcd_ops), error);
+
+        /* Success!
+         */
+        TRACE_MSG0(TCD, "5. Success!");
+
+        otg_init(otg);
+        //otg_start(otg, ocd_ops.capabilities & OCD_CAPABILITIES_AUTO);
+
+        // XXX TESTING
+        //isp1301_dp_pullup_func(otg, 1);
+
+        /* XXX start thread to monitor for changes - not needed once gpio interrupt implmented
+         */
+        isp1301_thread_init(isp1301_bh);
+
+        /* error handling
+         */
+        CATCH(error) {
+                //if (irq) free_irq(GPIO_2_80_TO_IRQ(35), NULL);
+                if (irq) free_irq(GPIOX_TO_IRQ(35), NULL);
+                if (i2c) i2c_close();
+        }
+        return 0;
+}
+
+/*! mainstone_mod_exit
+ */
+void mainstone_mod_exit(void)
+{
+        //free_irq(GPIO_2_80_TO_IRQ(35), NULL);
+        free_irq(GPIOX_TO_IRQ(35), NULL);
+
+        /* XXX stop thread - not needed once gpio interrupt implmented
+         */
+        isp1301_thread_exit(NULL);
+
+        isp1301_mod_exit();
+        TRACE_MSG1(TCD, "MST_MSCWR2: %08x", MST_MSCWR2);
+        MST_MSCWR2 &= ~(MSCWR2_USB_OTG_SEL | MSCWR2_USB_OTG_RST);
+        TRACE_MSG1(TCD, "MST_MSCWR2: %08x", MST_MSCWR2);
+        //isp1301_thread_exit();
+        i2c_close();
+
+}
+
+/* ********************************************************************************************* */
+
+struct tcd_ops tcd_ops = {
+
+        vbus: isp1301_vbus,
+
+        mod_init: mainstone_mod_init,
+        mod_exit: mainstone_mod_exit,
+
+        tcd_init_func: mainstone_tcd_init,
+
+        dischrg_vbus_func: isp1301_dischrg_vbus,
+        chrg_vbus_func: isp1301_chrg_vbus,
+        drv_vbus_func: isp1301_drv_vbus,
+        dp_pullup_func: isp1301_dp_pullup_func,
+        dm_pullup_func: isp1301_dm_pullup_func,
+        dm_det_func: isp1301_dm_det_func,
+        dp_det_func: isp1301_dp_det_func,
+
+};
+
diff -uNr linux/drivers/no-otg/ocd/isp1301/tcd-omap-h2.c linux/drivers/otg/ocd/isp1301/tcd-omap-h2.c
--- linux/drivers/no-otg/ocd/isp1301/tcd-omap-h2.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/isp1301/tcd-omap-h2.c	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,180 @@
+/*
+ * otg/ocd/isp1301/tcd-omap-h2.c -- USB Transceiver Controller driver 
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/isp1301/tcd-omap-h2.c
+ * @brief OMAP H2 ISP1301 driver.
+ *
+ *
+ * @ingroup ISP1301TCD
+ */
+
+#include <otg/pcd-include.h>
+#include <linux/pci.h>
+#include <asm/arch/irq.h>
+#include <asm/arch/irqs.h>
+#include <otghw/isp1301-hardware.h>
+#include "otghw/bvd-hardware.h"
+#include <otghw/isp1301.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/i2c.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+//struct isp1301_private isp1301_private;
+
+/* ********************************************************************************************* */
+
+
+static irqreturn_t isp1301_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
+{
+        TRACE_MSG0(TCD, "--");
+
+        SCHEDULE_WORK(isp1301_private.bh);
+
+        return IRQ_HANDLED;
+}
+
+
+/* ********************************************************************************************* */
+
+struct tcd_ops tcd_ops;
+
+#define ADAPTOR_NAME "OMAP I2C"
+
+/*! omap_mod_init
+ */
+int omap_mod_init(void)
+{
+        int i2c = i2c_configure(ADAPTOR_NAME, ISP1301_I2C_ADDR_HIGH);
+
+        int gpio = omap_request_gpio (ISP1301_GPIO);
+        int irq = 0;
+
+        TRACE_MSG0(TCD, "--");
+
+        /* did we get gpio and i2c?
+         */
+        THROW_IF(gpio || i2c, error);
+
+        /* for interrupt bottom half handler
+         */
+        // moved isp1301.c - PREPARE_WORK_ITEM(isp1301_private.bh, &isp1301_bh, NULL);
+
+        /* 
+         * See H2 C.f. Figure 17 USBOTG Interface Connection
+         * GPIO2 M14
+         * setup gpio 2 and request interrupt for it
+         */
+        omap_set_gpio_direction(ISP1301_GPIO, 1);
+        //omap_cfg_reg(M14_1510_GPIO2);
+        omap_set_gpio_edge_ctrl(ISP1301_GPIO, OMAP_GPIO_FALLING_EDGE);
+        irq = request_irq (OMAP_GPIO_IRQ(ISP1301_GPIO), isp1301_int_hndlr, SA_INTERRUPT, "ISP1301", NULL);
+        THROW_IF(irq, error);
+
+        #ifdef CONFIG_OTG_OMAP_H2_3_WIRE
+
+        /* OTG on Pin Group 1 Using 3-Wire OTG Transceiver C.f. Figure 15-59
+         * See also H2 C.f. Figure 17 USBOTG Interface Connection
+         * DAT_SE0 mode
+         * Set DAT_SE0, SUSPEND_REG and BI_DI
+         */
+        //i2c_writeb(ISP1301_MODE_CONTROL_1_SET, ISP1301_DAT_SE0 | ISP1301_SUSPEND_REG);
+        //i2c_writeb(ISP1301_MODE_CONTROL_1_CLR, ~(ISP1301_DAT_SE0 | ISP1301_SUSPEND_REG));
+        //i2c_writeb(ISP1301_MODE_CONTROL_2_SET, ISP1301_BI_DI);
+        //i2c_writeb(ISP1301_MODE_CONTROL_2_CLR, ~ISP1301_BI_DI);
+
+        isp1301_configure(dat_se0_bidirectional, spd_susp_pins);
+
+        #elif CONFIG_OTG_OMAP_H2_4_WIRE
+
+        /* OTG on Pin Group 1 Using 4-Wire OTG Transceiver C.f. Figure 15-60
+         * See also H2 C.f. Figure 17 USBOTG Interface Connection
+         * VP_VM mode
+         * Reset DAT_SE0 
+         * Set SUSPEND_REG and BI_DI
+         */
+        //i2c_writeb(ISP1301_MODE_CONTROL_1_SET, ISP1301_SUSPEND_REG);
+        //i2c_writeb(ISP1301_MODE_CONTROL_1_CLR, ~ISP1301_SUSPEND_REG);
+        //i2c_writeb(ISP1301_MODE_CONTROL_2_SET, ISP1301_BI_DI);
+        //i2c_writeb(ISP1301_MODE_CONTROL_2_CLR, ~ISP1301_BI_DI);
+
+        isp1301_configure(vp_vm_bidirectional);
+
+        #else
+        #error "ISP1301 Connection style not selected!"
+        #endif /* CONFIG_OTG_OMAP_H2_4_WIRE */
+
+        isp1301_mod_init();
+
+        i2c_writeb(ISP1301_OTG_CONTROL_SET, ISP1301_DM_PULLDOWN | ISP1301_DP_PULLDOWN);
+
+        /* Success!
+         */
+
+        TRACE_MSG0(TCD, "5. Success!");
+
+        otg_init(otg);
+
+        /* error handling
+         */
+        CATCH(error) {
+                if (irq) free_irq(OMAP_GPIO_IRQ(ISP1301_GPIO), NULL);
+                if (gpio) omap_free_gpio(ISP1301_GPIO);
+                if (i2c) i2c_close();
+        }
+        return 0;
+}
+
+/*! omap_mod_exit
+ */
+void omap_mod_exit(void)
+{
+	#if 0
+	// moved to isp1301.c
+        while (PENDING_WORK_ITEM(isp1301_private.bh)) {
+                printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
+                schedule_timeout(10 * HZ);
+        }
+	#endif
+
+        isp1301_mod_exit();
+
+        i2c_writeb(ISP1301_INTERRUPT_ENABLE_LOW_CLR, 0xff);
+        i2c_writeb(ISP1301_INTERRUPT_ENABLE_HIGH_CLR, 0xff);
+        i2c_close();
+        free_irq(OMAP_GPIO_IRQ(ISP1301_GPIO), NULL);
+        omap_free_gpio(ISP1301_GPIO);
+}
+
+/* ********************************************************************************************* */
+
+struct tcd_ops tcd_ops = {
+
+        //initial_state: tr_init,
+        vbus: isp1301_vbus,
+
+        mod_init: omap_mod_init,
+        mod_exit: omap_mod_exit,
+
+        dischrg_vbus_func: isp1301_dischrg_vbus,
+        chrg_vbus_func: isp1301_chrg_vbus,
+        drv_vbus_func: isp1301_drv_vbus,
+        dp_pullup_func: isp1301_dp_pullup_func,
+        dm_pullup_func: isp1301_dm_pullup_func,
+        dm_det_func: isp1301_dm_det_func,
+        dp_det_func: isp1301_dp_det_func,
+
+};
+
diff -uNr linux/drivers/no-otg/ocd/isp1301/thread-l24.c linux/drivers/otg/ocd/isp1301/thread-l24.c
--- linux/drivers/no-otg/ocd/isp1301/thread-l24.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/isp1301/thread-l24.c	2006-09-01 21:41:31.000000000 +0200
@@ -0,0 +1,144 @@
+/*
+ * otg/ocd/isp1301/thread-l24.c -- MX21ADS ISP1301 Transceiver Controller driver 
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/isp1301/thread-l24.c
+ * @brief Implement a kernel thread for checking ISP1301.
+ *
+ *
+ * @ingroup ISP1301TCD
+ */
+
+#include <otg/pcd-include.h>
+#include <otg/otg-module.h>
+#include <linux/pci.h>
+//#include <asm/arch/mx2.h>
+#include <otghw/isp1301-hardware.h>
+//#include "mx2.h"
+//#include "otghw/mx2-hardware.h"
+
+
+/* isp1301_bh
+ */
+extern void isp1301_bh(void *arg);
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+
+/* I2C Thread
+ * The mx21 USBOTG module does not seem to be able to keep uptodate with the OTG Transceiver
+ * registers. This kernel thread will iterated endlessly reading the appropriate registers.
+ *
+ * If this is successful we can assume that the USBOTG module will correctly monitor the appropriate
+ * registers and allow us to follow them via the normal USBOTG interrupts and registers.
+ *
+ * Otherwise we can monitor here and issue the otg events directly.
+ */
+//#define ISP1301_THREAD_TIMEOUT_EN (10)
+#define ISP1301_THREAD_TIMEOUT_EN (1*HZ)
+#define ISP1301_THREAD_TIMEOUT_DIS (1*HZ)
+
+int isp1301_terminate;
+int mx2_pid;
+wait_queue_head_t isp1301_wait;
+static DECLARE_COMPLETION(mx2_exited);
+int isp1301_en;
+
+void (*isp1301_bh_proc)(void *);
+
+/*! isp1301_thread - implement a kernel task to monitor isp1301 for changes
+ */
+int isp1301_thread(void *data)
+{
+        u8 int_src_saved = 0, otg_status_saved = 0, int_src, otg_status;
+        TRACE_MSG0(TCD, "--");
+	daemonize();
+	reparent_to_init();
+	sprintf(current->comm, "isp1301_thread");
+                
+        /* loop until told to terminate
+         */
+	while (!isp1301_terminate) {
+
+                #if 0
+                // XXX TESTING
+                static int count = 0;
+                count++;
+                if (!(count % 5))
+                        isp1301_dp_pullup_func(tcd_instance->otg, !(count % 10)? 1 : 2);
+                #endif
+
+                /* sleep for a while if not enabled
+                 */
+                if (!isp1301_en) {
+                        TRACE_MSG1(TCD, "WAITING: %d", ISP1301_THREAD_TIMEOUT_DIS);
+                        interruptible_sleep_on_timeout(&isp1301_wait, ISP1301_THREAD_TIMEOUT_DIS);
+                        continue;
+                }
+
+                /* update 1301
+                 */
+                if (isp1301_bh_proc)
+                        isp1301_bh_proc(NULL);
+                
+                //TRACE_MSG1(TCD, "SLEEPING: %d", ISP1301_THREAD_TIMEOUT_EN);
+                interruptible_sleep_on_timeout(&isp1301_wait, ISP1301_THREAD_TIMEOUT_EN);
+                //TRACE_MSG0(TCD, "RUNNING");
+	}
+	TRACE_MSG0(TCD, "Exiting");
+	complete_and_exit(&mx2_exited, 0);
+}
+
+extern int isp1301_bh_first;
+/*! isp1301_thread_wakeup - wakeup the isp1301 task
+ */
+void isp1301_thread_wakeup(int enabled, int first)
+{
+        TRACE_MSG0(TCD, "--");
+        isp1301_bh_first |= first;
+        isp1301_en = enabled;
+	wake_up(&isp1301_wait);
+}
+
+/* ********************************************************************************************* */
+
+/*! isp1301_thread_init - initial tcd setup
+ * Allocate interrupts and setup hardware.
+ */
+int isp1301_thread_init (void (bh_proc)(void *))
+{
+	isp1301_terminate = 0;
+        TRACE_MSG0(TCD, "--");
+        isp1301_bh_proc = bh_proc;
+	init_waitqueue_head(&isp1301_wait);
+	THROW_IF((mx2_pid = kernel_thread(&isp1301_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND)) < 0, error);
+        isp1301_thread_wakeup(0, 0);
+
+        CATCH(error) {
+                return -EINVAL;
+        }
+        return 0;
+}
+
+/*! isp1301_thread_exit - de-initialize
+ */
+void isp1301_thread_exit (wait_queue_head_t *wait_queue)
+{
+        TRACE_MSG0(TCD, "MX2_MOD_TCD_EXIT - terminating");
+        isp1301_bh_proc = NULL;
+	isp1301_terminate = 1;
+        if (wait_queue)
+                wake_up_interruptible(wait_queue);                              // wakeup waiting bottom half handler
+        isp1301_thread_wakeup(0, 0);
+	wait_for_completion(&mx2_exited);
+        TRACE_MSG0(TCD, "MX2_MOD_TCD_EXIT - terminated");
+}
+
diff -uNr linux/drivers/no-otg/ocd/max3353e/Config.in linux/drivers/otg/ocd/max3353e/Config.in
--- linux/drivers/no-otg/ocd/max3353e/Config.in	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/Config.in	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,19 @@
+
+#
+# @(#) balden@belcarra.com|otg/ocd/max3353e/Config.in|20060831021117|26677
+# Copyright (c) 2004 Belcarra
+# Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
+#
+# MAX 3353E TCD
+
+if [ "$CONFIG_OTG_MAX3353E" = "y" ]; then
+    mainmenu_option next_comment
+
+    comment 'MAX 3353E (i2c)'
+
+        dep_bool 'Proc FS debug' CONFIG_OTG_MAX3353E_PROCFS $CONFIG_OTG_MAX3353E
+
+    endmenu
+else
+    define_bool CONFIG_OTG_MAX3353E_PROCFS n
+fi
diff -uNr linux/drivers/no-otg/ocd/max3353e/Makefile linux/drivers/otg/ocd/max3353e/Makefile
--- linux/drivers/no-otg/ocd/max3353e/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/Makefile	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,100 @@
+#
+# Makefile for the kernel USBD (device not host) drivers.
+# @(#) balden@belcarra.com|otg/ocd/max3353e/Makefile-l24|20060831021117|12633
+#
+# Copyright (c) 2004 Belcarra
+# Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
+
+# Subdirs.
+# This is a bit complex, because some subdirs are for
+# proprietary code, and are simply not present in a
+# general distribution.
+
+# The all-CAPS *_DIRS get nuked in the new versions
+# of Rules.make, so use only the subdir-* methods.
+subdir-y 	:=
+subdir-m 	:=
+subdir-n 	:=
+subdir- 	:=
+
+# The target object and module list name.
+
+O_TARGET	:= max3353e_target.o
+list-multi      := max3353e_tcd.o
+
+# Objects that export symbols.
+
+export-objs	:= i2c-max3353e.o max3353e.o
+
+# Multipart objects.
+
+#db1550_tcd-objs	:= tcd-init-l24.o tcd-omap-h2.o max3353e.o i2c-l26.o tcd.o max3353e-procfs.o
+#db1550_tcd-objs	:= tcd-init-l24.o tcd-db1550.o tcd-mx2ads.o max3353e.o i2c-l26.o tcd.o max3353e-procfs.o
+db1550_tcd-objs		:= tcd-init-l24.o max3353e.o tcd-db1550.o i2c-max3353e.o
+# Optional parts of multipart objects.
+
+# Object file lists.
+
+obj-y		:=
+obj-m		:=
+obj-n		:=
+obj-		:=
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_OTG_MAX3353E_DB1550)	+= db1550_tcd.o
+
+
+# Object files in subdirectories
+
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+int-m		:= $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
+OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+
+# The global Rules.make.
+
+DOT_DIR=$(TCD_DIR)/max3353e
+
+include $(TOPDIR)/Rules.make
+OTG=$(TOPDIR)/drivers/otg
+OCD_DIR=$(OTG)ocd/
+OTGLIB=$(OTG)/ocd/otglib
+INCLUDE_DIRS =          -I$(OTG)
+EXTRA_CFLAGS +=          -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
+EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
+
+I2C=$(OTG)/ocd/otg-i2c
+PCD=$(OTG)/ocd/otg-pcd
+TCD=$(OTG)/ocd/otg-tcd
+vpath %.c $(USBDCORE_DIR) $(OCD_DIR) $(PCD) $(TCD) $(OTGLIB)
+
+
+# Link rules for multi-part drivers.
+
+db1550_tcd.o: $(db1550_tcd-objs)
+	$(LD) -r -o $@ $(db1550_tcd-objs)
+
+# dependencies:
+
+# local
+
+
diff -uNr linux/drivers/no-otg/ocd/max3353e/Makefile-l26 linux/drivers/otg/ocd/max3353e/Makefile-l26
--- linux/drivers/no-otg/ocd/max3353e/Makefile-l26	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/Makefile-l26	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,28 @@
+#
+# Makefile for the kernel USBD (device not host) drivers.
+# @(#) balden@belcarra.com|otg/ocd/max3353e/Makefile-l26|20060831021117|56045
+#
+# Copyright (c) 2004 Belcarra Technologies Corp
+# Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
+
+DOT_DIR=$(TCD_DIR)/max3353e
+
+OTG=$(TOPDIR)/drivers/otg
+HCD_DIR=$(OTG)/hcd
+TCD_DIR=$(OTG)/tcd
+USBDCORE_DIR=$(OTG)/usbdcore
+OTGCORE_DIR=$(OTG)/otgcore
+INCLUDE_DIRS =          -I$(OTG)
+EXTRA_CFLAGS +=          -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
+EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format ${INCLUDE_DIRS}
+
+vpath %.c $(USBDCORE_DIR) $(OCD_DIR)
+
+
+# Link rules for multi-part drivers.
+
+db1550_tcd-objs	:= ../tcd-init-l24.o max3353e.o i2c-l26.o ../tcd.o
+obj-$(CONFIG_OTG_MAX3353E_DB1550)	+= db1550_tcd.o
+
+
+
diff -uNr linux/drivers/no-otg/ocd/max3353e/README linux/drivers/otg/ocd/max3353e/README
--- linux/drivers/no-otg/ocd/max3353e/README	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/README	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,9 @@
+Some notes for using max3353 tranciever in DB1550 development board
+1- Patch kernel with AMD DB1550 i2c driver.
+2- Patch arch/mips/au1000/db1x00/irqmap.c
+#if defined(CONFIG_MIPS_DB1550) || defined(CONFIG_MIPS_MTX2)
+        { AU1000_GPIO_3, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card 0 IRQ#
+        { AU1000_GPIO_5, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card 1 IRQ#
+        { AU1500_GPIO_207, INTC_INT_FALL_EDGE, 0 }, // OTG tranciever
+#else
+			
diff -uNr linux/drivers/no-otg/ocd/max3353e/i2c-max3353e.c linux/drivers/otg/ocd/max3353e/i2c-max3353e.c
--- linux/drivers/no-otg/ocd/max3353e/i2c-max3353e.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/i2c-max3353e.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,178 @@
+/* @(#) balden@belcarra.com|otg/ocd/max3353e/i2c-max3353e.c|20060831021117|42179
+ *	Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
+ */
+#include <otg/otg-compat.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/i2c.h>
+
+#include <otg/pcd-include.h>
+#include <linux/pci.h>
+#include <otghw/max3353e-hardware.h>
+//#include "isp1301.h"
+
+/*
+ * N.B. i2c functions must not be called from interrupt handlers
+ */
+
+static struct file *i2c_file;
+static struct i2c_client *db1550_i2c_client;
+static int initstate_i2c;
+static int initstate_region;
+#define MAX_I2C 16
+
+#ifdef CONFIG_OMAP_H2
+#define ADAPTOR_NAME "OMAP I2C"
+#endif /* CONFIG_OMAP_H2 */
+#ifdef CONFIG_ARCH_MAINSTONE
+#define ADAPTOR_NAME "PXA-I2C-Adapter"
+#endif /* CONFIG_ARCH_MAINSTONE */
+#ifdef CONFIG_OTG_DB1550_J15
+#define ADAPTOR_NAME "pb1550 adapter"
+#endif /* CONFIG_OTG_DB1550_J15 */
+
+void i2c_writeb(u8 subaddr, u8 buf)
+{
+        char tmpbuf[2];
+        int ret;
+
+        tmpbuf[0] = subaddr;    /*register number */
+        tmpbuf[1] = buf;        /*register data */
+
+        ret = i2c_master_send(db1550_i2c_client, &tmpbuf[0], 2);
+        while (ret != 2){
+                ret = i2c_master_send(db1550_i2c_client, &tmpbuf[0], 2);
+        }
+        TRACE_MSG1(TCD, "I2C write %d\n", ret);
+
+}
+
+void i2c_close()
+{
+        if (initstate_i2c)
+                filp_close(i2c_file, NULL);
+        initstate_i2c = 0;
+
+}
+
+int i2c_configure (char *name, int addr)
+{
+        char filename[20];
+        int tmp;
+
+        RETURN_ZERO_IF(initstate_i2c);
+
+        /*find the I2C driver we need
+         */
+        for (tmp = 0; tmp < MAX_I2C; tmp++) {
+
+                sprintf(filename, "/dev/i2c-%d", tmp);
+
+                printk(KERN_INFO"%s: %s\n", __FUNCTION__, filename);
+
+                UNLESS (IS_ERR(i2c_file = filp_open(filename, O_RDWR, 0))) {
+
+                        //printk(KERN_INFO"%s: %s found\n", __FUNCTION__, filename);
+
+                        /*found some driver */
+                        db1550_i2c_client = (struct i2c_client *)i2c_file->private_data;
+
+                        printk(KERN_INFO"%s: found %s\n", __FUNCTION__, db1550_i2c_client->adapter->name);
+                        if (strlen(db1550_i2c_client->adapter->name) >= 8) {
+                                if (!strncmp(db1550_i2c_client->adapter->name, name, strlen(name)))
+                                        break;  /*we found our driver! */
+                        }
+                        db1550_i2c_client = NULL;
+                        filp_close(i2c_file, NULL);
+                }
+                printk(KERN_INFO"%s: %s %d\n", __FUNCTION__, filename, i2c_file);
+        }
+        if (tmp == MAX_I2C) {                           // Nothing found
+                printk(KERN_ERR"%s: cannot find I2C driver", __FUNCTION__);
+                return -ENODEV;
+        }
+        db1550_i2c_client->addr = addr;
+        initstate_i2c = 1;
+        return 0;
+}
+
+/*! i2c_readb
+ * Read byte from i2c device
+ * @param subaddr
+ */
+u8 i2c_readb(u8 subaddr)
+{
+int ret;
+
+        u8 buf = 0;
+        ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
+        while (ret != 1){
+//              printk(KERN_INFO"send return %d\n", ret);
+                ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
+        }
+        //      printk(KERN_INFO"send return %d\n", ret);
+        ret = i2c_master_recv(db1550_i2c_client, &buf, 1);
+        while (ret != 1){
+                //      printk(KERN_INFO"rec return %d with %02x\n", ret, buf);
+                ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
+                while (ret != 1){
+                        //      printk(KERN_INFO"send return %d\n", ret);
+                        ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
+                }
+                ret = i2c_master_recv(db1550_i2c_client, &buf, 1);
+        }
+        //      printk(KERN_INFO"rec return %d with %02x\n", ret, buf);
+        TRACE_MSG2(TCD, "addr: %02x buf:  %02x", subaddr, buf);
+        return buf;
+}
+
+
+/*! i2c_readl
+ * Read long from i2c device
+ * @param subaddr
+ */
+u32 i2c_readl(u8 subaddr)
+{
+        int ret;
+        //        u32 buf = 0;
+        u8 buf[5];
+        ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
+        while (ret != 1){
+                printk(KERN_INFO"send return %d\n", ret);
+                ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
+        }
+        printk(KERN_INFO"send return %d\n", ret);
+        ret = i2c_master_recv(db1550_i2c_client, buf, 4);
+        while (ret != 4){
+                printk(KERN_INFO"rec return %d with %02x\n", ret, buf);
+                ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
+                while (ret != 1){
+                        printk(KERN_INFO"send return %d\n", ret);
+                        ret = i2c_master_send(db1550_i2c_client, &subaddr, 1);
+                }
+                ret = i2c_master_recv(db1550_i2c_client, buf, 4);
+        }
+        printk(KERN_INFO"rec return %d with %02x %02x %02x %02x\n", ret, buf[0], buf[1], buf[2], buf[3]);
+        TRACE_MSG2(TCD, "addr: %02x buf:  %08x", subaddr, buf);
+        return buf;
+}
+
+int i2c_readw (int addr)
+{
+        int data;
+
+        data = 0;
+
+        return data;
+}
+
+
+EXPORT_SYMBOL(i2c_writeb);
+EXPORT_SYMBOL(i2c_readw);
+EXPORT_SYMBOL(i2c_readb);
+EXPORT_SYMBOL(i2c_readl);
+EXPORT_SYMBOL(i2c_configure);
+EXPORT_SYMBOL(i2c_close);
+
diff -uNr linux/drivers/no-otg/ocd/max3353e/max3353-procfs.c linux/drivers/otg/ocd/max3353e/max3353-procfs.c
--- linux/drivers/no-otg/ocd/max3353e/max3353-procfs.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/max3353-procfs.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,303 @@
+/*
+ * otg/ocd/max3353e/max3353-procfs.c - USB Device Core Layer
+ * @(#) balden@belcarra.com|otg/ocd/max3353e/max3353-procfs.c|20060831021117|57336
+ *
+ *      Copyright (c) 2004-2005 Belcarra
+ *	Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
+ *
+ * By:
+ *      Stuart Lynne <sl@belcarra.com>,
+ *      Shahrad Payandeh <sp@belcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ */
+/*!
+ * @file otg/ocd/max3353e/max3353-procfs.c
+ * @brief Implement /proc/max3353 to dump MAX3353 registers.
+ *
+ *
+ * @ingroup MAX3353TCD
+ */
+
+
+#include <otg/pcd-include.h>
+#include "otghw/max3353-hardware.h"
+#include "max3353.h"
+
+#ifdef CONFIG_ARCH_MX2ADS
+#include <asm/arch/mx2.h>
+#define MX2_OTG_XCVR_DEVAD                      0x18
+#define MX2_SEQ_OP_REG                          0x19
+#define MX2_SEQ_RD_STARTAD                      0x1a
+#define MX2_I2C_OP_CTRL_REG                     0x1b
+#define MX2_SCLK_TO_SCL_HPER                    0x1e
+#define MX2_I2C_INTERRUPT_AND_CTRL              0x1f
+
+#define OTG_BASE_ADDR                           0x10024000
+//#define OTG_I2C_BASE                            (OTG_BASE_ADDR+0x100)
+
+#endif /* CONFIG_ARCH_MX2ADS */
+
+#ifdef CONFIG_OTG_MAX3353_PROCFS
+/* Proc Filesystem *************************************************************************** */
+
+extern struct max3353_private max3353_private;
+
+#define MAX_HISTORY     6
+struct reg_list {
+        u8 reg;
+        u8 size;
+        char *name;
+        u32 values[MAX_HISTORY];
+};
+
+#define REG(r, s)  {r, s, #r, }
+
+struct reg_list max3353_prod_list[] = {
+        REG(MAX3353_VENDOR_ID, 2),
+        REG(MAX3353_PRODUCT_ID, 2),
+        REG(MAX3353_VERSION_ID, 2),
+        { 0, 1, NULL,},
+};
+struct reg_list max3353_reg_list[] = {
+        REG(MAX3353_OTG_CONTROL_SET, 1),
+        REG(MAX3353_INTERRUPT_SOURCE, 1),
+        REG(MAX3353_INTERRUPT_LATCH_SET, 1),
+        REG(MAX3353_INTERRUPT_ENABLE_LOW_SET, 1),
+        REG(MAX3353_INTERRUPT_ENABLE_HIGH_SET, 1),
+        REG(MAX3353_MODE_CONTROL_1_SET, 1),
+        { 0, 1, NULL,},
+};
+struct reg_list max3353_spec_list[] = {
+        REG(MAX3353_MODE_CONTROL_2_SET, 1),
+        REG(MAX3353_OTG_STATUS, 1),
+        { 0, 1, NULL,},
+};
+struct reg_list max3301e_spec_list[] = {
+        REG(MAX3301E_SPECIAL_FUNCTION_1_SET, 1),
+        REG(MAX3301E_SPECIAL_FUNCTION_2_SET, 1),
+        { 0, 1, NULL,},
+};
+#ifdef CONFIG_ARCH_MX2ADS
+struct reg_list mx21_spec_list[] = {
+        REG(MX2_OTG_XCVR_DEVAD, 1),
+        REG(MX2_SEQ_OP_REG, 1),
+        REG(MX2_SEQ_RD_STARTAD, 1),
+        REG(MX2_I2C_OP_CTRL_REG, 1),
+        REG(MX2_SCLK_TO_SCL_HPER, 1),
+        REG(MX2_I2C_INTERRUPT_AND_CTRL, 1),
+        { 0, 1, NULL,},
+};
+#endif /* CONFIG_ARCH_MX2ADS */
+
+void max3353_update(struct reg_list *list)
+{
+        for (; list && list->name; list++) {
+                memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32));
+                switch(list->size) {
+                case 1:
+                        list->values[0] = i2c_readb(list->reg);
+                        break;
+                case 2:
+                        list->values[0] = i2c_readw(list->reg);
+                        break;
+                case 4:
+                        list->values[0] = i2c_readl(list->reg);
+                        break;
+                }
+        }
+}
+
+#ifdef CONFIG_ARCH_MX2ADS
+static u8 __inline__ mx2_rb(u32 port)
+{
+        return *(volatile u8 *) (MX2_IO_ADDRESS(port + OTG_I2C_BASE));
+}
+
+
+void mx21_update(struct reg_list *list)
+{
+        for (; list && list->name; list++) {
+                memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32));
+                list->values[0] = mx2_rb(list->reg);
+        }
+}
+
+#endif /* CONFIG_ARCH_MX2ADS */
+
+void max3353_update_all(void)
+{
+        max3353_update(max3353_reg_list);
+        switch (max3353_private.transceiver_map->transceiver_type) {
+        case max3353:
+                max3353_update(max3353_spec_list);
+                break;
+        case max3301e:
+                max3353_update(max3301e_spec_list);
+                break;
+        default:
+                break;
+        }
+#ifdef CONFIG_ARCH_MX2ADS
+        mx21_update(mx21_spec_list);
+#endif /* CONFIG_ARCH_MX2ADS */
+}
+
+
+
+/*
+ * dohex
+ *
+ */
+static void dohexdigit (char *cp, unsigned char val)
+{
+        if (val < 0xa)
+                *cp = val + '0';
+        else if ((val >= 0x0a) && (val <= 0x0f))
+                *cp = val - 0x0a + 'a';
+}
+
+/*
+ * dohex
+ *
+ */
+static void dohexval (char *cp, unsigned char val)
+{
+        dohexdigit (cp++, val >> 4);
+        dohexdigit (cp++, val & 0xf);
+}
+
+int max3353_dump(char *buf, char *name, char *fmt, struct reg_list *reg)
+{
+        int len = 0, i;
+        len += sprintf (buf + len, "%-20s  %-34s [%03x]:  ", name, reg->name, reg->reg);
+        len += sprintf (buf + len, fmt, reg->values[0]);
+        for (i = 1; i < MAX_HISTORY; i++)
+                if (reg->values[i - 1] == reg->values[i])
+                        len += sprintf (buf + len, "         ");
+                else
+                        len += sprintf (buf + len, fmt, reg->values[i]);
+        len += sprintf (buf + len, "\n");
+        return len;
+}
+
+int max3353_dump_list(char * buf, char *name, struct reg_list *list)
+{
+        int len = 0;
+        for (; list && list->name; list++)
+                switch(list->size) {
+                case 1: len += max3353_dump(buf + len, name, "       %02x", list); break;
+                case 2: len += max3353_dump(buf + len, name, "     %04x", list); break;
+                case 4: len += max3353_dump(buf + len, name, " %08x", list); break;
+                }
+        return len;
+}
+
+int max3353_dump_all(char *buf)
+{
+        int len = 0;
+        len += max3353_dump_list(buf + len, "MAX3353 Standard", max3353_reg_list);
+        switch (max3353_private.transceiver_map->transceiver_type) {
+        case max3353:
+                len += max3353_dump_list(buf + len, "MAX3353 Extra", max3353_spec_list);
+                break;
+        case max3301e:
+                len += max3353_dump_list(buf + len, "MAX3301E Extra", max3301e_spec_list);
+                break;
+        default:
+                break;
+        }
+#ifdef CONFIG_ARCH_MX2ADS
+        len += max3353_dump_list(buf + len, "MX21 ADS Extra", mx21_spec_list);
+#endif /* CONFIG_ARCH_MX2ADS */
+        return len;
+}
+
+
+
+/*!
+ * max3353_device_proc_read - implement proc file system read.
+ *
+ * Standard proc file system read function.
+ *
+ * We let upper layers iterate for us, *pos will indicate which device to return
+ * statistics for.
+ */
+static ssize_t max3353_device_proc_read_functions (struct file *file, char *buf, size_t count, loff_t * pos)
+{
+        unsigned long page;
+        int len = 0;
+        int index;
+        int i;
+        u32 r;
+
+        int config_size;
+
+        // get a page, max 4095 bytes of data...
+        RETURN_EINVAL_UNLESS ((page = get_free_page (GFP_KERNEL)));
+
+        len = 0;
+        index = (*pos)++;
+
+        switch(index) {
+        case 0:
+                len += sprintf ((char *) page + len, "MAX3353 Transceiver Registers\n");
+
+                max3353_update_all();
+                len += sprintf ((char *) page + len , "Vendor: %04x Product: %04x Revision: %04x %s\n",
+                                max3353_private.vendor, max3353_private.product,
+                                max3353_private.revision, max3353_private.transceiver_map->name
+                                );
+
+                len += max3353_dump_all((char *) page + len);
+                len += sprintf ((char *) page + len, "\n");
+
+                break;
+
+        case 1:
+                break;
+
+        }
+
+        if (len > count) {
+                len = -EINVAL;
+        }
+        else if ((len > 0) && copy_to_user (buf, (char *) page, len)) {
+                len = -EFAULT;
+        }
+        else {
+        }
+        free_page (page);
+        return len;
+}
+
+static struct file_operations max3353_device_proc_operations_functions = {
+        read:max3353_device_proc_read_functions,
+};
+
+/* Module init ******************************************************************************* */
+
+static int max3353_procfs_init (void)
+{
+        struct proc_dir_entry *p;
+
+        // create proc filesystem entries
+        if ((p = create_proc_entry ("max3353", 0, 0)) == NULL)
+                return -ENOMEM;
+
+        p->proc_fops = &max3353_device_proc_operations_functions;
+
+        max3353_update_all();
+
+        return 0;
+}
+static void max3353_procfs_exit (void)
+{
+        remove_proc_entry ("max3353", NULL);
+}
+#else
+static int max3353_procfs_init (void) { return 0;
+}
+static void max3353_procfs_exit (void) { }
+#endif
diff -uNr linux/drivers/no-otg/ocd/max3353e/max3353.c linux/drivers/otg/ocd/max3353e/max3353.c
--- linux/drivers/no-otg/ocd/max3353e/max3353.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/max3353.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,706 @@
+/*
+ * otg/ocd/max3353e/max3353.c -- USB Transceiver Controller driver
+ * @(#) balden@belcarra.com|otg/ocd/max3353e/max3353.c|20060831021117|27226
+ *
+ *      Copyright (c) 2003-2005 Belcarra
+ *	Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
+ *
+ * By:
+ *      Stuart Lynne <sl@lbelcarra.com>,
+ *      Shahrad Payandeh <sp@belcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/max3353e/max3353.c
+ * @brief MAX3353 OTG Transceiver Driver.
+ *
+ * This is the generic MAX3353 TCD core support.
+ *
+ * Notes:
+ *
+ * 1. The MAX3353 can control the speed and suspend directly, would it be
+ * appropriate to allow state machine to control this.
+ *
+ * 2. The MAX3353 has auto connect feature, can this be used without change
+ * to state machine.
+ *
+ * 3. The MAX3353 can control the ADR/PSW pin to enable / disable external
+ * charge pump.
+ *
+ * @ingroup MAX3353TCD
+ */
+
+#include <otg/otg-compat.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/i2c.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-ocd.h>
+#include <otg/otg-pcd.h>
+
+#include <otghw/max3353-hardware.h>
+#include "max3353.h"
+
+
+struct otg_transceiver_map max3353_transceiver_map[] = {
+        { max3353, 0x4cc, 0x1301, 0x00, "Phillips MAX3353", },
+        { max3301e, 0x6a0b, 0x0133, 0x00, "Maxim MAX3301E", },
+        { 0, 0, 0, 0, "Unknown Transceiver", },
+};
+
+struct max3353_private max3353_private;
+
+
+
+/* ********************************************************************************************* */
+#define TRACE_I2CB(t,r) TRACE_MSG3(t, "%-40s[%02x] %02x", #r, r, i2c_readb(r))
+#define TRACE_I2CW(t,r) TRACE_MSG3(t, "%-40s[%02x] %04x", #r, r, i2c_readw(r))
+#define TRACE_GPIO(t,b,r) TRACE_MSG2(t, "%-40s %04x", #r, readw(b + r))
+#define TRACE_REGL(t,r) TRACE_MSG2(t, "%-40s %08x", #r, readl(r))
+
+
+
+/*! max3353_int_src - update interrupt source test mask
+ *
+ * This sets the current mask and updates the interrupt registers to match.
+ */
+void max3353_int_src(u8 int_src)
+{
+        TRACE_MSG1(TCD, "setting int_src %02x", int_src);
+        max3353_private.int_src = int_src;
+        i2c_writeb(MAX3353_INTERRUPT_ENABLE_LOW_CLR, ~int_src);
+        i2c_writeb(MAX3353_INTERRUPT_ENABLE_HIGH_CLR, ~int_src);
+        i2c_writeb(MAX3353_INTERRUPT_ENABLE_LOW_SET, int_src);
+        i2c_writeb(MAX3353_INTERRUPT_ENABLE_HIGH_SET, int_src);
+        i2c_writeb(MAX3353_INTERRUPT_LATCH_CLR, int_src);
+}
+
+/*! max3353_int_src_set - add to the interrupt source mask
+ *
+ */
+void max3353_int_src_set(u8 int_src)
+{
+        max3353_int_src(int_src |= max3353_private.int_src);
+}
+
+/*! max3353_int_src_clr - remove from the interrup source mask
+ */
+void max3353_int_src_clr(u8 int_src)
+{
+        max3353_int_src(int_src = max3353_private.int_src & ~int_src);
+}
+
+/* ********************************************************************************************* */
+
+
+/*! max3353_event_set_irq
+ */
+void max3353_event_set_irq(struct otg_instance *otg, int changed, int flag, u32 input, otg_tag_t tag, char *mset, char *mreset)
+{
+        TRACE_MSG5(TCD, "changed: %x flag: %x input: %08x %s %s", changed, flag, input,
+                        flag ? mset: mreset,
+                        changed ? "": "(ignored)");
+
+        otg_event_set_irq(otg, changed, flag, input, tag, flag ? mset : mreset);
+}
+
+/*! max3353_update - called from mx2_i2c_xcvr_bh to find changes in the max3353 Interrupt Source Register
+ */
+u8 max3353_update_int_src(struct otg_instance *otg, u8 int_src, u8 changed)
+{
+        UNLESS (changed) return int_src;
+        TRACE_MSG2(TCD, "CHANGED INTERRUPT_SOURCE: %02x (%02x) ", int_src, changed);
+
+        /* Core events
+         */
+        max3353_event_set_irq(otg, MAX3353_ID_GND & changed, MAX3353_ID_GND & int_src,
+                        ID_GND, TCD, "ID_GND", "ID_GND/");
+        max3353_event_set_irq(otg, MAX3353_ID_FLOAT & changed, MAX3353_ID_FLOAT & int_src,
+                        ID_FLOAT, TCD, "ID_FLOAT", "ID_FLOAT/");
+        max3353_event_set_irq(otg, MAX3353_VBUS_VLD & changed, MAX3353_VBUS_VLD & int_src,
+                        VBUS_VLD, TCD, "VBUS_VLD", "VBUS_VLD/");
+        max3353_event_set_irq(otg, MAX3353_SESS_VLD & changed, MAX3353_SESS_VLD & int_src,
+                        A_SESS_VLD, TCD, "A_SESS_VLD", "A_SESS_VLD/");
+
+        max3353_event_set_irq(otg, MAX3353_DM_HI & changed, MAX3353_DM_HI & int_src,
+                        DM_HIGH, TCD, "DM_HIGH", "DM_HIGH/");
+
+        max3353_event_set_irq(otg, MAX3353_DP_HI & changed, MAX3353_DP_HI & int_src,
+                        DP_HIGH, TCD, "DP_HIGH", "DP_HIGH/");
+
+        //max3353_event_set_irq(otg, MAX3353_SE1 & changed, ((MAX3353_SE1 & int_src) == 0), SE0_DET, TCD, "SE0", "SE0/");
+
+        /* carkit
+         */
+        max3353_event_set_irq(otg, MAX3353_CR_INT & changed, !(MAX3353_CR_INT & int_src),
+                        CR_INT_DET, TCD, "CR_INT", "CR_INT/");
+
+        //TRACE_MSG3(TCD, "MAX3353_SE1: %02x & int_src: %02x = %02x", MAX3353_SE1, int_src, MAX3353_SE1 & int_src);
+        //max3353_event_set_irq(otg, MAX3353_SE1 & changed, ((MAX3353_SE1 & int_src) == MAX3353_SE1),
+        //                SE1_DET, TCD, "SE1", "SE1/");
+
+
+        /* A-Device
+         */
+        max3353_event_set_irq(otg, MAX3353_BDIS_ACON & changed, !(MAX3353_BDIS_ACON & int_src),
+                        BDIS_ACON, TCD, "BDIS_ACON", "BDIS_ACON/" );
+
+        return int_src;
+}
+
+/*! max3353_update - called from mx2_i2c_xcvr_bh to find changes in the max3353 OTG Status Register
+ */
+u8 max3353_update_otg_status(struct otg_instance *otg, u8 otg_status, u8 changed)
+{
+        UNLESS (changed) return otg_status;
+        TRACE_MSG2(TCD, "CHANGED OTG_STATUS_REG: %02x (%02x) ", otg_status, changed);
+
+        max3353_event_set_irq(otg, MAX3353_B_SESS_VLD & changed, MAX3353_B_SESS_VLD & otg_status,
+                        B_SESS_VLD, TCD, "B_SESS_VLD", "B_SESS_VLD/");
+        max3353_event_set_irq(otg, MAX3353_B_SESS_END & changed, MAX3353_B_SESS_END & otg_status,
+                        B_SESS_END, TCD, "B_SESS_END", "B_SESS_END/");
+
+        //otg_b_sess_vld(otg, first || (MAX3353_B_SESS_VLD & changed), MAX3353_B_SESS_VLD & otg_status, MAX3353_NAME );
+        return otg_status;
+}
+
+int max3353_bh_first;
+
+
+/*! max3353_bh
+ */
+void max3353_bh(void *arg)
+{
+        u8 int_lat, int_src = 0, otg_status = 0, special_function_22 = 0;
+        static u8 int_src_saved, otg_status_saved, special_function_22_saved;
+
+        //TRACE_MSG0(TCD, "--");
+        /* read the interrupt latch and and clear latch and update otg
+         */
+        if ((int_lat = i2c_readb(MAX3353_INTERRUPT_LATCH_SET))) {
+                //TRACE_MSG1(TCD, "CLEARING INT LAT: %02x", int_lat);
+                i2c_writeb(MAX3353_INTERRUPT_LATCH_CLR, int_lat);
+        }
+
+        /* If int_lat shows a change or we are forcing an update, read interrupt source.
+         * Note that we mask DP_HI and DM_HI when LOC_CONN is set, we don't want them
+         * when USB Bus is in use.
+         *
+         * Mask with bits we are currently interested in.
+         */
+        int_src = i2c_readb(MAX3353_INTERRUPT_SOURCE) & max3353_private.int_src;
+
+        UNLESS ( max3353_private.flags & MAX3353_LOC_CONN) {
+        }
+
+
+        /* further work if B-Device and VBUS_VLD
+         */
+        if ( (!(int_src & MAX3353_ID_GND) && (int_src & MAX3353_VBUS_VLD)) ||
+                        (!(int_src_saved & MAX3353_ID_GND) && (int_src_saved & MAX3353_VBUS_VLD)) )
+        {
+                /* read the otg_status register and update otg state machine
+                 *
+                 * XXX this needs to be conditional on Transceiver type. The
+                 * MAX3301E for example supports sess_end in a separate register.
+                 */
+                switch (max3353_private.transceiver_map->transceiver_type) {
+                case max3353:
+                        otg_status = i2c_readb(MAX3353_OTG_STATUS);
+                        if (max3353_bh_first)
+                                otg_status_saved = ~otg_status;
+                        otg_status_saved = max3353_update_otg_status(tcd_instance->otg, otg_status,
+                                        otg_status_saved ^ otg_status);
+                        break;
+                case max3301e:
+                        // XXX
+                        special_function_22 = i2c_readb(MAX3301E_SPECIAL_FUNCTION_2_SET);
+                        break;
+                case unknown_transceiver:
+                        break;
+                }
+        }
+        if (max3353_bh_first)
+                int_src_saved =  ~int_src;
+
+        int_src_saved = max3353_update_int_src(tcd_instance->otg, int_src, int_src_saved ^ int_src);
+
+        max3353_bh_first = 0;
+}
+
+/* ********************************************************************************************** */
+/*! max3353_vbus - Do we have Vbus (cable attached?)
+ * Return non-zero if Vbus is detected.
+ *
+ */
+int max3353_vbus (struct otg_instance *otg)
+{
+        return 0;
+}
+
+/*! max3353_id - Do we have Vbus (cable attached?)
+ * Return non-zero if Vbus is detected.
+ *
+ */
+int max3353_idvbus (struct otg_instance *otg)
+{
+        return 0;
+}
+
+
+/* ********************************************************************************************* */
+
+/*! max3353_chrg_vbus - used to enable or disable B-device Vbus charging
+ */
+void max3353_chrg_vbus(struct otg_instance *otg, u8 flag)
+{
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "CHRG_VBUS_SET");
+                i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8) MAX3353_VBUS_CHRG);
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "CHRG_VBUS_RESET");
+                i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8) MAX3353_VBUS_CHRG);
+                break;
+        case PULSE:
+                break;
+        }
+}
+
+/*! max3353_drv_vbus - used to enable or disable A-device driving Vbus
+ */
+void max3353_drv_vbus(struct otg_instance *otg, u8 flag)
+{
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "DRV_VBUS_SET");
+                i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8) MAX3353_VBUS_DRV);
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "DRV_VBUS_RESET");
+                i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8) MAX3353_VBUS_DRV);
+                break;
+        }
+}
+
+/*! max3353_dischrg_vbus - used to enable Vbus discharge
+ */
+void max3353_dischrg_vbus(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = otg->tcd;
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "OUTPUT: TCD_DISCHRG_VBUS_SET");
+                i2c_writeb(MAX3353_OTG_CONTROL_SET, MAX3353_VBUS_DISCHRG);
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "OUTPUT: TCD_DISCHRG_VBUS_RESET");
+                i2c_writeb(MAX3353_OTG_CONTROL_CLR, MAX3353_VBUS_DISCHRG);
+                break;
+        }
+}
+
+/*! max3353_dp_pullup_func - used to enable or disable peripheral connecting to bus
+ *
+ * C.f. 5.1.6, 5.1.7, 5.2.4 and 5.2.5
+ *
+ *                              host    peripheral
+ *              d+ pull-up      clr     set
+ *              d+ pull-down    set     clr
+ *
+ *              d- pull-up      clr     clr
+ *              d- pull-down    set     set
+ *
+ */
+void max3353_dp_pullup_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+		printk(KERN_INFO"%s: --\n", __FUNCTION__);
+                max3353_private.flags |= MAX3353_LOC_CONN;
+                TRACE_MSG0(TCD, "MAX3353_LOC_CONN SET - Clr DP PULLDOWN");
+                //i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8) MAX3353_DP_PULLDOWN);
+                //i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8) (MAX3353_DP_PULLDOWN | MAX3353_DM_PULLDOWN) );
+                TRACE_MSG0(TCD, "MAX3353_LOC_CONN SET - Set DP PULLUP");
+                i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8) MAX3353_DP_PULLUP);
+                break;
+
+        case RESET:
+                max3353_private.flags &= ~MAX3353_LOC_CONN;
+                TRACE_MSG0(TCD, "MAX3353_LOC_CONN RESET - Clr DP PULLUP");
+                i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8)MAX3353_DP_PULLUP);
+                TRACE_MSG0(TCD, "MAX3353_LOC_CONN SET - Set DP PULLDOWN");
+                //i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8)MAX3353_DP_PULLDOWN);
+                //i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8) (MAX3353_DP_PULLDOWN | MAX3353_DM_PULLDOWN) );
+                break;
+
+        case PULSE:
+                TRACE_MSG0(TCD, "MAX3353_LOC_CONN PULSE");
+                break;
+        }
+}
+
+/*! max3353_dm_pullup_func - used to enable or disable peripheral connecting to bus
+ *
+ */
+void max3353_dm_pullup_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                max3353_private.flags |= MAX3353_LOC_CONN;
+                TRACE_MSG0(TCD, "MAX3353_LOC_CONN SET - Clr DM PULLDOWN");
+                //i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8) MAX3353_DM_PULLDOWN);
+                TRACE_MSG0(TCD, "MAX3353_LOC_CONN SET - Set DM PULLUP");
+                i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8) MAX3353_DM_PULLUP);
+                break;
+
+        case RESET:
+                max3353_private.flags &= ~MAX3353_LOC_CONN;
+                TRACE_MSG0(TCD, "MAX3353_LOC_CONN RESET - Clr DM PULLUP");
+                i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8)MAX3353_DM_PULLUP);
+                TRACE_MSG0(TCD, "MAX3353_LOC_CONN SET - Set DM PULLDOWN");
+                //i2c_writeb(MAX3353_OTG_CONTROL_SET, (u8)MAX3353_DM_PULLDOWN);
+                break;
+
+        case PULSE:
+                TRACE_MSG0(TCD, "MAX3353_LOC_CONN PULSE");
+                break;
+        }
+}
+
+/*! max3353_dm_det_func - used to enable or disable D- detect
+ *
+ */
+void max3353_dm_det_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting DM_HI detect");
+                max3353_int_src_set(MAX3353_DM_HI);
+                max3353_bh_first = 1;
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting DM_HI detect");
+                max3353_int_src_clr(MAX3353_DM_HI);
+                break;
+        }
+}
+
+/*! max3353_dp_det_func - used to enable or disable D+ detect
+ *
+ */
+void max3353_dp_det_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting DP_HI detect");
+                max3353_int_src_set(MAX3353_DP_HI);
+                max3353_bh_first = 1;
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting DP_HI detect");
+                max3353_int_src_clr(MAX3353_DP_HI);
+                break;
+        }
+}
+
+/*! max3353_bdis_acon_func - used to enable or disable auto a-connect
+ *
+ */
+void max3353_bdis_acon_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting BDIS ACON");
+                i2c_writeb(MAX3353_OTG_CONTROL_SET, MAX3353_ID_PULLDOWN);
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting BDIS ACON");
+                i2c_writeb(MAX3353_OTG_CONTROL_CLR, MAX3353_ID_PULLDOWN);
+                break;
+        }
+}
+
+/*! max3353_id_pulldown_func - used to enable or disable ID pulldown
+ *
+ */
+void max3353_id_pulldown_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting ID PULLDOWN");
+                i2c_writeb(MAX3353_MODE_CONTROL_1_SET, MAX3353_BDIS_ACON_EN);
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting ID PULLDOWN");
+                i2c_writeb(MAX3353_MODE_CONTROL_1_CLR, MAX3353_BDIS_ACON_EN);
+                break;
+        }
+}
+
+/*! max3353_audio_func - used to enable or disable Carkit Interrupt
+ *
+ */
+void max3353_audio_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting CARKIT INT");
+                i2c_writeb(MAX3353_MODE_CONTROL_2_SET, MAX3353_AUDIO_EN);
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting CARKIT INT");
+                i2c_writeb(MAX3353_MODE_CONTROL_2_CLR, MAX3353_AUDIO_EN);
+                break;
+        }
+}
+
+/*! max3353_uart_func - used to enable or disable transparent uart mode
+ *
+ */
+void max3353_uart_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting UART");
+                i2c_writeb(MAX3353_MODE_CONTROL_1_SET, MAX3353_UART_EN);
+                /* XXX enable uart */
+                break;
+
+        case RESET:
+                MAX3353SG0(TCD, "reseting UART");
+                i2c_writeb(MAX3353_MODE_CONTROL_1_CLR, MAX3353_UART_EN);
+                /* XXX disable uart */
+                break;
+        }
+}
+
+/*! max3353_mono_func - used to enable or disable mono audio connection
+ *
+ */
+void max3353_mono_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "setting MONO");
+                /* XXX enable mono output */
+                break;
+
+        case RESET:
+                TRACE_MSG0(TCD, "reseting MONO");
+                /* XXX disable mono output */
+                break;
+        }
+}
+
+
+/* ********************************************************************************************* */
+extern int max3353_procfs_init (void);
+extern void max3353_procfs_exit (void);
+
+/*! max3353_mod_init
+ */
+int max3353_mod_init(void)
+{
+        /* for interrupt bottom half handler
+         */
+        PREPARE_WORK_ITEM(max3353_private.bh, &max3353_bh, NULL);
+
+        /* setup max3353, enable interrupts, clear latch
+         * XXX when and how do we do DM_HI and DP_HI, when ID is present?
+         */
+        max3353_int_src(MAX3353_INT_SRC);
+        //max3353_int_src(MAX3353_NO_SE1_INT);
+
+        i2c_writeb(MAX3353_OTG_CONTROL_SET, MAX3353_DM_PULLDOWN | MAX3353_DP_PULLDOWN);
+
+#ifdef CONFIG_OTG_MAX3353_PROCFS
+        max3353_procfs_init ();
+#endif /* CONFIG_OTG_MAX3353_PROCFS */
+
+        return 0;
+}
+
+/*! max3353_mod_exit
+ */
+void max3353_mod_exit(void)
+{
+        i2c_writeb(MAX3353_INTERRUPT_ENABLE_LOW_CLR, 0xff);
+        i2c_writeb(MAX3353_INTERRUPT_ENABLE_HIGH_CLR, 0xff);
+        //i2c_close();
+#ifdef CONFIG_OTG_MAX3353_PROCFS
+        max3353_procfs_exit ();
+#endif /* CONFIG_OTG_MAX3353_PROCFS */
+
+        while (PENDING_WORK_ITEM(max3353_private.bh)) {
+                printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
+                schedule_timeout(10 * HZ);
+        }
+
+}
+
+/* ********************************************************************************************* */
+/*! max3353_configure - configure the MAX3353 for this host
+ * @param tx_mode - the type of connection between the host USB and the MAX3353
+ * @param spd_ctrl - suspend control method
+ */
+void  max3353_configure(tx_mode_t tx_mode, spd_ctrl_t spd_ctrl)
+{
+        u16 vendor = 0, product = 0, revision = 0;
+        u8 mode1, mode2, control;
+
+        struct otg_transceiver_map *map = max3353_transceiver_map;
+
+
+#if defined(CONFIG_OTG_MAX3353_MX2ADS) || defined(CONFIG_OTG_MAX3353_MX2ADS_MODULE)
+        u32 vp;
+        MAX3353SG0(TCD, "1. Read Transceiver ID's with long read");
+        vp = i2c_readl(MAX3353_VENDOR_ID);
+        max3353_private.vendor = vp & 0xffff;
+        max3353_private.product = vp >> 16;
+        max3353_private.revision = i2c_readw(MAX3353_VERSION_ID);
+        mode1 = i2c_readb(MAX3353_MODE_CONTROL_1_SET);
+        mode2 = i2c_readb(MAX3353_MODE_CONTROL_2_SET);
+
+        TRACE_MSG5(TCD, "2. OTG Transceiver: vendor: %04x product: %04x revision: %04x mode1: %02x mode2: %02x",
+                        vendor, product, revision, mode1, mode2);
+
+#else /* defined(CONFIG_OTG_MAX3353_MX2ADS) */
+
+        max3353_private.vendor = i2c_readw(MAX3353_VENDOR_ID);
+        max3353_private.product = i2c_readw(MAX3353_PRODUCT_ID);
+        max3353_private.revision = i2c_readw(MAX3353_VERSION_ID);
+        mode1 = i2c_readb(MAX3353_MODE_CONTROL_1_SET);
+        mode2 = i2c_readb(MAX3353_MODE_CONTROL_2_SET);
+
+        TRACE_MSG5(TCD, "2. OTG Transceiver: vendor: %04x product: %04x revision: %04x mode1: %02x mode2: %02x",
+                        max3353_private.vendor, max3353_private.product, max3353_private.revision, mode1, mode2);
+
+#endif /* defined(CONFIG_OTG_MAX3353_MX2ADS) */
+
+        for ( ; map && map->transceiver_type != unknown_transceiver; map++) {
+                CONTINUE_UNLESS ((max3353_private.vendor == map->vendor) && (max3353_private.product == map->product));
+                TRACE_MSG1(TCD, "Found Transceiver: %s", map->name);
+                max3353_private.transceiver_map = map;
+                break;
+        }
+        UNLESS (max3353_private.transceiver_map)
+                max3353_private.transceiver_map = max3353_transceiver_map;
+
+        TRACE_MSG0(TCD, "3. Disable All Transceiver Control Register 1 ");
+        i2c_writeb(MAX3353_OTG_CONTROL_CLR, 0xff);                                    // clear
+
+        TRACE_MSG0(TCD, "4. Enable D-/D+ Pulldowns in Transceiver Control Register 1 ");
+
+        i2c_writeb(MAX3353_OTG_CONTROL_SET, MAX3353_DM_PULLDOWN | MAX3353_DP_PULLDOWN);
+        i2c_writeb(MAX3353_OTG_CONTROL_CLR, (u8) MAX3353_DM_PULLUP | MAX3353_DP_PULLUP);
+
+
+        TRACE_MSG0(TCD, "5. Clear latch and enable interrupts");
+        i2c_writeb(MAX3353_INTERRUPT_LATCH_CLR, 0xff);
+        i2c_writeb(MAX3353_INTERRUPT_ENABLE_LOW_CLR, 0xeb);
+        i2c_writeb(MAX3353_INTERRUPT_ENABLE_HIGH_CLR, 0xeb);
+
+        /* The PSW_OE enables the ADR/PSW pin for output driving either high
+         * or low depending on the address.
+         *
+         * ADR          ADR_REG Address         PSW_OE=0        PSW_OE=1
+         *
+         *      low     0       0x2c            LOW             HIGH
+         *
+         *      high    1       0x2d            HIGH            LOW
+         *
+         *
+         * The i2c address by tying the ADR/PSW pin either high or low.
+         * Setting the PSW_OE drives the ADR/PSW into the opposite of the
+         * default wiring.
+         *
+         * On the MX21ADS the ADR/PSW pin is wired high which enables the
+         * charge pump. So enabling the PSW_OE is required to disable Vbus
+         * generation on the Charge Pump.
+         *
+         * The MAX3355E will only enable Vbus when this signal is high AND
+         * the ID signal is low. So it may be safe to leave enabled when
+         * operating as a B-device (ID floating.)
+         */
+
+        //i2c_writeb(MAX3353_MODE_CONTROL_2_SET, MAX3353_PSW_OE);              // PSW_OE - OFFVBUS low
+
+
+        TRACE_MSG1(TCD, "6. tx_mode: %02x", tx_mode);
+        switch (tx_mode) {
+        case vp_vm_bidirectional:
+                break;
+        case dat_se0_unidirectional:
+                i2c_writeb(MAX3353_MODE_CONTROL_2_CLR, MAX3353_BI_DI);
+        MAX3353t_se0_bidirectional:
+                i2c_writeb(MAX3353_MODE_CONTROL_1_SET, MAX3353_DAT_SE0);
+                break;
+        }
+        TRACE_MSG0(TCD, "6. tx_mode done");
+
+        TRACE_MSG1(TCD, "7. spd_ctrl: %02x", spd_ctrl);
+        switch (spd_ctrl) {
+        case spd_susp_pins:
+                i2c_writeb(MAX3353_MODE_CONTROL_2_CLR, MAX3353_SPD_SUSP_CTRL);
+                break;
+        case spd_susp_reg:
+                i2c_writeb(MAX3353_MODE_CONTROL_2_SET, MAX3353_SPD_SUSP_CTRL);
+                break;
+        }
+
+        //i2c_writeb(MAX3353_MODE_CONTROL_2_SET, MAX3353_PSW_OE);              // PSW_OE - OFFVBUS low
+
+        TRACE_MSG0(TCD, "7. spd_ctrl done");
+
+        TRACE_MSG1(TCD, "8. transceiver_type: %02x", max3353_private.transceiver_map);
+
+        TRACE_MSG1(TCD, "8. transceiver_type: %02x", max3353_private.transceiver_map->transceiver_type);
+        switch (max3353_private.transceiver_map->transceiver_type) {
+        case max3353:
+                break;
+        case max3301e:
+                i2c_writeb(MAX3301E_SPECIAL_FUNCTION_1_SET, MAX3301E_SESS_END);
+                break;
+        case unknown_transceiver:
+                break;
+        }
+        TRACE_MSG0(TCD, "8. transceiver_type done");
+}
+
diff -uNr linux/drivers/no-otg/ocd/max3353e/max3353.h linux/drivers/otg/ocd/max3353e/max3353.h
--- linux/drivers/no-otg/ocd/max3353e/max3353.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/max3353.h	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,132 @@
+/*
+ * otg/ocd/max3353/max3353.h -- USB Transceiver Controller driver
+ * @(#) balden@belcarra.com|otg/ocd/max3353e/max3353.h|20060831021117|56821
+ *
+ *      Copyright (c) 2004-2005 Belcarra
+ *	Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
+ *
+ * By:
+ *      Stuart Lynne <sl@lbelcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+
+/*!
+ * @file otg/ocd/max3353e/max3353.h
+ * @brief Private structures and defines for MAX3353 Transciever Controller Driver.
+ *
+ * This file contains the private defines and structures for the MAX3353 Transceiver
+ * Driver.
+ *
+ * @ingroup MAX3353TCD
+ */
+
+
+#ifdef CONFIG_XXXXX
+#define MAX3353_GPIO     (2)
+#define TCD_MAX3353_I2C_ADDR  MAX3353_I2C_ADDR_HIGH;
+#endif
+
+#define MAX3353_NAME    "max3353"
+
+#define MAX3353_LOC_CONN 0x01
+
+#define MAX3353_INT_SRC         0xeb
+
+//#define MAX3353_ALL_INT_SRC     0xff
+//#define MAX3353_NO_SE1_INT    0xeb
+//#define MAX3353_NO_SE1_INT    0xfb              /* do not pay attention to DP_HI */
+
+typedef enum otg_transceiver {
+        unknown_transceiver,
+        max3353,
+        max3301e
+} otg_transceiver_t;
+
+struct otg_transceiver_map {
+        otg_transceiver_t transceiver_type;
+        u16 vendor;
+        u16 product;
+        u16 revision;
+        char *name;
+};
+
+struct max3353_private {
+        WORK_STRUCT bh;
+        u16 vendor;
+        u16 product;
+        u16 revision;
+        u32 flags;
+        u8  int_src;
+        struct otg_transceiver_map *transceiver_map;
+};
+
+/*! tx_mode
+ * This defines the various ways that the MAX3353 can be
+ * wired into the host USB.
+ */
+typedef enum tx_mode {
+        dat_se0_bidirectional,          /*!< 3-Wire */
+        vp_vm_bidirectional,            /*!< 4-Wire */
+        dat_se0_unidirectional          /*!< 6-Wire */
+} tx_mode_t;
+
+/*! spd_ctrl
+ * This defines how the speed and suspend pins are controlled
+ * for this host.
+ */
+typedef enum spd_ctrl {
+        spd_susp_pins,                  /*!< controlled by SPEED and SUSPEND pins */
+        spd_susp_reg,                   /*!< controled by SPEED_REG and SUSPEND_REG in Mode Control 1 register */
+} spd_ctrl_t;
+
+
+extern struct tcd_ops tcd_ops;
+extern struct max3353_private max3353_private;
+extern struct tcd_instance *tcd_instance;
+
+/* max3353.c */
+extern int max3353_mod_init(void);
+extern void max3353_mod_exit(void);
+extern void max3353_chrg_vbus(struct otg_instance *, u8 );
+extern void max3353_drv_vbus(struct otg_instance *, u8 );
+extern void max3353_dischrg_vbus(struct otg_instance *, u8 );
+extern void max3353_dp_pullup_func(struct otg_instance *, u8 );
+extern void max3353_dm_pullup_func(struct otg_instance *, u8 );
+extern void max3353_dm_det_func(struct otg_instance *, u8 );
+extern void max3353_dp_det_func(struct otg_instance *, u8 );
+extern void max3353_bdis_acon_func(struct otg_instance *otg, u8 flag);
+extern void max3353_id_pulldown_func(struct otg_instance *otg, u8 flag);
+extern void max3353_audio_func(struct otg_instance *otg, u8 flag);
+extern void max3353_uart_func(struct otg_instance *otg, u8 flag);
+extern void max3353_mono_func(struct otg_instance *otg, u8 flag);
+
+extern void max3353_otg_timer(struct otg_instance *, u8 );
+extern void max3353_bh(void *);
+extern int max3353_id (struct otg_instance *);
+extern int max3353_vbus (struct otg_instance *);
+extern void  max3353_configure(tx_mode_t, spd_ctrl_t );
+
+/* thread */
+extern int max3353_thread_init (void (bh_proc)(void *));
+extern void max3353_thread_exit (wait_queue_head_t *);
+extern void max3353_thread_wakeup(int enabled, int first);
+
+
+
+/* i2c-xxx.c */
+int  i2c_configure(char *name, int addr);
+extern void  i2c_close(void);
+extern u8 i2c_readb(u8 );
+extern u16 i2c_readw(u8 );
+extern u32 i2c_readl(u8 );
+extern int  i2c_writeb(u8 , u8 );
+
+
+/* ********************************************************************************************* */
+#define TRACE_I2CB(t,r) TRACE_MSG3(t, "%-40s[%02x] %02x", #r, r, i2c_readb(r))
+#define TRACE_I2CW(t,r) TRACE_MSG3(t, "%-40s[%02x] %04x", #r, r, i2c_readw(r))
+#define TRACE_GPIO(t,b,r) TRACE_MSG2(t, "%-40s %04x", #r, readw(b + r))
+#define TRACE_REGL(t,r) TRACE_MSG2(t, "%-40s %08x", #r, readl(r))
+
diff -uNr linux/drivers/no-otg/ocd/max3353e/max3353e-procfs.c linux/drivers/otg/ocd/max3353e/max3353e-procfs.c
--- linux/drivers/no-otg/ocd/max3353e/max3353e-procfs.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/max3353e-procfs.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,303 @@
+/*
+ * otg/ocd/max3353/max3353-procfs.c - USB Device Core Layer
+ * @(#) balden@belcarra.com|otg/ocd/max3353e/max3353e-procfs.c|20060831021117|57336
+ *
+ *      Copyright (c) 2004-2005 Belcarra
+ *	Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
+ *
+ * By:
+ *      Stuart Lynne <sl@belcarra.com>,
+ *      Shahrad Payandeh <sp@belcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ */
+/*!
+ * @file otg/ocd/max3353e/max3353e-procfs.c
+ * @brief Implement /proc/max3353 to dump MAX3353 registers.
+ *
+ *
+ * @ingroup MAX3353TCD
+ */
+
+
+#include <otg/pcd-include.h>
+#include "otghw/max3353-hardware.h"
+#include "max3353.h"
+
+#ifdef CONFIG_ARCH_MX2ADS
+#include <asm/arch/mx2.h>
+#define MX2_OTG_XCVR_DEVAD                      0x18
+#define MX2_SEQ_OP_REG                          0x19
+#define MX2_SEQ_RD_STARTAD                      0x1a
+#define MX2_I2C_OP_CTRL_REG                     0x1b
+#define MX2_SCLK_TO_SCL_HPER                    0x1e
+#define MX2_I2C_INTERRUPT_AND_CTRL              0x1f
+
+#define OTG_BASE_ADDR                           0x10024000
+//#define OTG_I2C_BASE                            (OTG_BASE_ADDR+0x100)
+
+#endif /* CONFIG_ARCH_MX2ADS */
+
+#ifdef CONFIG_OTG_MAX3353_PROCFS
+/* Proc Filesystem *************************************************************************** */
+
+extern struct max3353_private max3353_private;
+
+#define MAX_HISTORY     6
+struct reg_list {
+        u8 reg;
+        u8 size;
+        char *name;
+        u32 values[MAX_HISTORY];
+};
+
+#define REG(r, s)  {r, s, #r, }
+
+struct reg_list max3353_prod_list[] = {
+        REG(MAX3353_VENDOR_ID, 2),
+        REG(MAX3353_PRODUCT_ID, 2),
+        REG(MAX3353_VERSION_ID, 2),
+        { 0, 1, NULL,},
+};
+struct reg_list max3353_reg_list[] = {
+        REG(MAX3353_OTG_CONTROL_SET, 1),
+        REG(MAX3353_INTERRUPT_SOURCE, 1),
+        REG(MAX3353_INTERRUPT_LATCH_SET, 1),
+        REG(MAX3353_INTERRUPT_ENABLE_LOW_SET, 1),
+        REG(MAX3353_INTERRUPT_ENABLE_HIGH_SET, 1),
+        REG(MAX3353_MODE_CONTROL_1_SET, 1),
+        { 0, 1, NULL,},
+};
+struct reg_list max3353_spec_list[] = {
+        REG(MAX3353_MODE_CONTROL_2_SET, 1),
+        REG(MAX3353_OTG_STATUS, 1),
+        { 0, 1, NULL,},
+};
+struct reg_list max3301e_spec_list[] = {
+        REG(MAX3301E_SPECIAL_FUNCTION_1_SET, 1),
+        REG(MAX3301E_SPECIAL_FUNCTION_2_SET, 1),
+        { 0, 1, NULL,},
+};
+#ifdef CONFIG_ARCH_MX2ADS
+struct reg_list mx21_spec_list[] = {
+        REG(MX2_OTG_XCVR_DEVAD, 1),
+        REG(MX2_SEQ_OP_REG, 1),
+        REG(MX2_SEQ_RD_STARTAD, 1),
+        REG(MX2_I2C_OP_CTRL_REG, 1),
+        REG(MX2_SCLK_TO_SCL_HPER, 1),
+        REG(MX2_I2C_INTERRUPT_AND_CTRL, 1),
+        { 0, 1, NULL,},
+};
+#endif /* CONFIG_ARCH_MX2ADS */
+
+void max3353_update(struct reg_list *list)
+{
+        for (; list && list->name; list++) {
+                memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32));
+                switch(list->size) {
+                case 1:
+                        list->values[0] = i2c_readb(list->reg);
+                        break;
+                case 2:
+                        list->values[0] = i2c_readw(list->reg);
+                        break;
+                case 4:
+                        list->values[0] = i2c_readl(list->reg);
+                        break;
+                }
+        }
+}
+
+#ifdef CONFIG_ARCH_MX2ADS
+static u8 __inline__ mx2_rb(u32 port)
+{
+        return *(volatile u8 *) (MX2_IO_ADDRESS(port + OTG_I2C_BASE));
+}
+
+
+void mx21_update(struct reg_list *list)
+{
+        for (; list && list->name; list++) {
+                memmove(list->values + 1, list->values, sizeof(list->values) - sizeof(u32));
+                list->values[0] = mx2_rb(list->reg);
+        }
+}
+
+#endif /* CONFIG_ARCH_MX2ADS */
+
+void max3353_update_all(void)
+{
+        max3353_update(max3353_reg_list);
+        switch (max3353_private.transceiver_map->transceiver_type) {
+        case max3353:
+                max3353_update(max3353_spec_list);
+                break;
+        case max3301e:
+                max3353_update(max3301e_spec_list);
+                break;
+        default:
+                break;
+        }
+#ifdef CONFIG_ARCH_MX2ADS
+        mx21_update(mx21_spec_list);
+#endif /* CONFIG_ARCH_MX2ADS */
+}
+
+
+
+/*
+ * dohex
+ *
+ */
+static void dohexdigit (char *cp, unsigned char val)
+{
+        if (val < 0xa)
+                *cp = val + '0';
+        else if ((val >= 0x0a) && (val <= 0x0f))
+                *cp = val - 0x0a + 'a';
+}
+
+/*
+ * dohex
+ *
+ */
+static void dohexval (char *cp, unsigned char val)
+{
+        dohexdigit (cp++, val >> 4);
+        dohexdigit (cp++, val & 0xf);
+}
+
+int max3353_dump(char *buf, char *name, char *fmt, struct reg_list *reg)
+{
+        int len = 0, i;
+        len += sprintf (buf + len, "%-20s  %-34s [%03x]:  ", name, reg->name, reg->reg);
+        len += sprintf (buf + len, fmt, reg->values[0]);
+        for (i = 1; i < MAX_HISTORY; i++)
+                if (reg->values[i - 1] == reg->values[i])
+                        len += sprintf (buf + len, "         ");
+                else
+                        len += sprintf (buf + len, fmt, reg->values[i]);
+        len += sprintf (buf + len, "\n");
+        return len;
+}
+
+int max3353_dump_list(char * buf, char *name, struct reg_list *list)
+{
+        int len = 0;
+        for (; list && list->name; list++)
+                switch(list->size) {
+                case 1: len += max3353_dump(buf + len, name, "       %02x", list); break;
+                case 2: len += max3353_dump(buf + len, name, "     %04x", list); break;
+                case 4: len += max3353_dump(buf + len, name, " %08x", list); break;
+                }
+        return len;
+}
+
+int max3353_dump_all(char *buf)
+{
+        int len = 0;
+        len += max3353_dump_list(buf + len, "MAX3353 Standard", max3353_reg_list);
+        switch (max3353_private.transceiver_map->transceiver_type) {
+        case max3353:
+                len += max3353_dump_list(buf + len, "MAX3353 Extra", max3353_spec_list);
+                break;
+        case max3301e:
+                len += max3353_dump_list(buf + len, "MAX3301E Extra", max3301e_spec_list);
+                break;
+        default:
+                break;
+        }
+#ifdef CONFIG_ARCH_MX2ADS
+        len += max3353_dump_list(buf + len, "MX21 ADS Extra", mx21_spec_list);
+#endif /* CONFIG_ARCH_MX2ADS */
+        return len;
+}
+
+
+
+/*!
+ * max3353_device_proc_read - implement proc file system read.
+ *
+ * Standard proc file system read function.
+ *
+ * We let upper layers iterate for us, *pos will indicate which device to return
+ * statistics for.
+ */
+static ssize_t max3353_device_proc_read_functions (struct file *file, char *buf, size_t count, loff_t * pos)
+{
+        unsigned long page;
+        int len = 0;
+        int index;
+        int i;
+        u32 r;
+
+        int config_size;
+
+        // get a page, max 4095 bytes of data...
+        RETURN_EINVAL_UNLESS ((page = get_free_page (GFP_KERNEL)));
+
+        len = 0;
+        index = (*pos)++;
+
+        switch(index) {
+        case 0:
+                len += sprintf ((char *) page + len, "MAX3353 Transceiver Registers\n");
+
+                max3353_update_all();
+                len += sprintf ((char *) page + len , "Vendor: %04x Product: %04x Revision: %04x %s\n",
+                                max3353_private.vendor, max3353_private.product,
+                                max3353_private.revision, max3353_private.transceiver_map->name
+                                );
+
+                len += max3353_dump_all((char *) page + len);
+                len += sprintf ((char *) page + len, "\n");
+
+                break;
+
+        case 1:
+                break;
+
+        }
+
+        if (len > count) {
+                len = -EINVAL;
+        }
+        else if ((len > 0) && copy_to_user (buf, (char *) page, len)) {
+                len = -EFAULT;
+        }
+        else {
+        }
+        free_page (page);
+        return len;
+}
+
+static struct file_operations max3353_device_proc_operations_functions = {
+        read:max3353_device_proc_read_functions,
+};
+
+/* Module init ******************************************************************************* */
+
+static int max3353_procfs_init (void)
+{
+        struct proc_dir_entry *p;
+
+        // create proc filesystem entries
+        if ((p = create_proc_entry ("max3353", 0, 0)) == NULL)
+                return -ENOMEM;
+
+        p->proc_fops = &max3353_device_proc_operations_functions;
+
+        max3353_update_all();
+
+        return 0;
+}
+static void max3353_procfs_exit (void)
+{
+        remove_proc_entry ("max3353", NULL);
+}
+#else
+static int max3353_procfs_init (void) { return 0;
+}
+static void max3353_procfs_exit (void) { }
+#endif
diff -uNr linux/drivers/no-otg/ocd/max3353e/max3353e.c linux/drivers/otg/ocd/max3353e/max3353e.c
--- linux/drivers/no-otg/ocd/max3353e/max3353e.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/max3353e.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,657 @@
+/*
+ * otg/ocd/max3353/max3353.c -- USB Transceiver Controller driver
+ * @(#) balden@belcarra.com|otg/ocd/max3353e/max3353e.c|20060831021117|08740
+ *
+ *      Copyright (c) 2004-2005 Belcarra
+ *	Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
+ *
+ * By:
+ *      Stuart Lynne <sl@lbelcarra.com>,
+ *      Shahrad Payandeh <sp@belcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/max3353e/max3353e.c
+ * @brief MAX3353 OTG Transceiver Driver.
+ *
+ * This is the generic MAX3353 TCD core support.
+ *
+ * Notes:
+ *
+ * 1. The MAX3353 can control the speed and suspend directly, would it be
+ * appropriate to allow state machine to control this.
+ *
+ * 2. The MAX3353 has auto connect feature, can this be used without change
+ * to state machine.
+ *
+ * 3. The MAX3353 can control the ADR/PSW pin to enable / disable external
+ * charge pump.
+ *
+ * @ingroup MAX3353TCD
+ */
+
+#include <otg/otg-compat.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/au1000.h>
+#include <linux/i2c.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-ocd.h>
+#include <otg/otg-pcd.h>
+
+#include <otghw/max3353e-hardware.h>
+#include "max3353e.h"
+
+
+struct otg_transceiver_map max3353_transceiver_map[] = {
+        { max3353, 0x4cc, 0x1301, 0x00, "Phillips MAX3353", },
+        { max3301e, 0x6a0b, 0x0133, 0x00, "Maxim MAX3301E", },
+        { 0, 0, 0, 0, "Unknown Transceiver", },
+};
+
+struct max3353_private max3353_private;
+
+
+
+/* ********************************************************************************************* */
+#define TRACE_I2CB(t,r) TRACE_MSG3(t, "%-40s[%02x] %02x", #r, r, i2c_readb(r))
+#define TRACE_I2CW(t,r) TRACE_MSG3(t, "%-40s[%02x] %04x", #r, r, i2c_readw(r))
+#define TRACE_GPIO(t,b,r) TRACE_MSG2(t, "%-40s %04x", #r, readw(b + r))
+#define TRACE_REGL(t,r) TRACE_MSG2(t, "%-40s %08x", #r, readl(r))
+
+
+
+/*! max3353_int_src - update interrupt source test mask
+ *
+ * This sets the current mask and updates the interrupt registers to match.
+ */
+void max3353_int_src(u8 int_src)
+{
+        TRACE_MSG1(TCD, "setting int_src %02x", int_src);
+        max3353_private.int_src = int_src;
+        i2c_writeb(MAX3353E_INTERRUPT_MASK, int_src);
+        i2c_writeb(MAX3353E_INTERRUPT_EDGE, 3); //detect on positive edge
+        i2c_writeb(MAX3353E_INTERRUPT_LATCH, 0);
+}
+
+/*! max3353_int_src_set - add to the interrupt source mask
+ *
+ */
+void max3353_int_src_set(u8 int_src)
+{
+        max3353_int_src(int_src |= max3353_private.int_src);
+}
+
+/*! max3353_int_src_clr - remove from the interrup source mask
+ */
+void max3353_int_src_clr(u8 int_src)
+{
+        max3353_int_src(int_src = max3353_private.int_src & ~int_src);
+}
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+
+
+
+typedef struct max3353_test {
+        u32     input;
+        char   *name;
+        u8      mask;
+} max3353_test_t;
+
+#define OV(i, m) {i, #i, m}
+#define MAX3353E_B_SESS_END 1<<4
+#define MAX3353E_B_SESS_VLD 1<<6
+#define MAX3353E_A_SESS_VLD 1<<5
+
+
+struct max3353_test max3353_int_src_tests[5] = {
+        OV(VBUS_VLD, MAX3353E_VBUS_VALID),
+        OV(ID_GND, MAX3353E_ID_GND),
+        OV(ID_FLOAT, MAX3353E_ID_FLOAT),
+        OV(BDIS_ACON, MAX3353E_A_HNP),
+        {0, NULL, 0},
+};
+
+struct max3353_test max3353_otg_status_tests[4] = {
+        OV(B_SESS_END, MAX3353E_B_SESS_END),
+        OV(B_SESS_VLD, MAX3353E_B_SESS_VLD),
+        OV(A_SESS_VLD, MAX3353E_A_SESS_VLD),
+        {0, NULL, 0},
+};
+
+u64 max3353_event(struct otg_instance *otg, struct max3353_test *tests, int val, char *msg)
+{
+        int i;
+        u64 inputs = 0;
+        TRACE_MSG2(TCD, "%02x %s", val, msg);
+        for (i = 0; tests[i].mask; i++) {
+                u64 input = tests[i].input;
+                u8 mask = tests[i].mask;
+                inputs |= (val & mask) ? input : _NOT(input);
+                TRACE_MSG5(TCD, "%d - %s%s %02x %08x", i, tests[i].name, (val & mask) ? "" : "/", tests[i].mask, tests[i].input);
+        }
+        return inputs;
+}
+
+/*! max3353_event_set_irq
+ */
+void max3353_event_set_irq(struct otg_instance *otg, int changed, int flag, u32 input, otg_tag_t tag, char *mset, char *mreset)
+{
+        TRACE_MSG5(TCD, "changed: %x flag: %x input: %08x %s %s", changed, flag, input,
+                        flag ? mset: mreset,
+                        changed ? "": "(ignored)");
+
+        otg_event_set_irq(otg, changed, flag, input, tag, flag ? mset : mreset);
+}
+
+/*! max3353_update - called from mx2_i2c_xcvr_bh to find changes in the max3353 Interrupt Source Register
+ */
+u8 max3353_update_int_src(struct otg_instance *otg, u8 int_src, u8 changed)
+{
+        UNLESS (changed) return int_src;
+        TRACE_MSG2(TCD, "CHANGED INTERRUPT_SOURCE: %02x (%02x) ", int_src, changed);
+
+        /* Core events
+         */
+        max3353_event_set_irq(otg, MAX3353E_ID_GND & changed, MAX3353E_ID_GND & int_src,
+                        ID_GND, TCD, "ID_GND", "ID_GND/");
+        max3353_event_set_irq(otg, MAX3353E_ID_FLOAT & changed, MAX3353E_ID_FLOAT & int_src,
+                        ID_FLOAT, TCD, "ID_FLOAT", "ID_FLOAT/");
+        max3353_event_set_irq(otg, MAX3353E_VBUS_VALID & changed, MAX3353E_VBUS_VALID & int_src,
+                        VBUS_VLD, TCD, "VBUS_VLD", "VBUS_VLD/");
+        max3353_event_set_irq(otg, MAX3353E_SESSION_END & changed, MAX3353E_SESSION_END & int_src,
+                        A_SESS_VLD, TCD, "A_SESS_VLD", "A_SESS_VLD/");
+
+
+        return int_src;
+}
+
+/*! max3353_update - called from mx2_i2c_xcvr_bh to find changes in the max3353 OTG Status Register
+ */
+u8 max3353_update_otg_status(struct otg_instance *otg, u8 otg_status, u8 changed)
+{
+        UNLESS (changed) return otg_status;
+        TRACE_MSG2(TCD, "CHANGED OTG_STATUS_REG: %02x (%02x) ", otg_status, changed);
+
+        max3353_event_set_irq(otg, MAX3353E_SESSION_VALID_EN & changed, MAX3353E_SESSION_VALID_EN & otg_status,
+                        B_SESS_VLD, TCD, "B_SESS_VLD", "B_SESS_VLD/");
+        max3353_event_set_irq(otg, MAX3353E_SESSION_END & changed, MAX3353E_SESSION_END & otg_status,
+                        B_SESS_END, TCD, "B_SESS_END", "B_SESS_END/");
+
+        return otg_status;
+}
+
+
+int max3353_bh_first;
+
+/*! max3353_bh
+ */
+void max3353_bh(void *arg)
+{
+
+        u64 inputs = 0;
+        u8 int_lat,status_reg,otg_reg;
+        u8 reg1,reg2;
+
+        au_writel(0x40000000, IC1_MASKCLR);     //disable interrupt
+        au_writel(0x40000000, IC1_FALLINGCLR);
+        au_writel(0x40000000, IC1_RISINGCLR);
+        TRACE_MSG0(TCD, "--MAX3353 ISR start");
+//        printk(KERN_INFO"ISR Start .......\n");
+
+        /* read the interrupt latch and and clear latch and update otg
+         */
+        if ((int_lat = i2c_readb(MAX3353E_INTERRUPT_LATCH))) {
+                TRACE_MSG1(TCD, "INT LAT: %02x", int_lat);
+                i2c_writeb(MAX3353E_INTERRUPT_LATCH, 0);
+        }
+
+        status_reg = i2c_readb(MAX3353E_STATUS_REGISTER);
+        inputs |= max3353_event(tcd_instance->otg, max3353_int_src_tests, status_reg, "MAX3353 STAT SRC");
+        TRACE_MSG1(TCD, "inputs after applying status register %02x\n", inputs);
+
+
+        otg_reg = 0;
+
+        if (status_reg & MAX3353E_SESSION_VALID_EN) {   //1.4,,4.5
+                TRACE_MSG0(TCD, "Setting B_SESS_VLD");
+                otg_reg |= MAX3353E_B_SESS_VLD;
+        }
+        if (status_reg & MAX3353E_SESSION_END) {
+                TRACE_MSG0(TCD, "Setting B_SESS_END");
+                otg_reg |= MAX3353E_B_SESS_END;
+        }
+        if (!(status_reg & MAX3353E_SESSION_END)) {     //0.8<<1.4
+                if (!(status_reg & MAX3353E_SESSION_VALID_EN)){
+                        TRACE_MSG0(TCD, "Setting A_SESS_VLD");
+                        otg_reg |= MAX3353E_A_SESS_VLD;
+                }
+        }
+
+
+
+        inputs |= max3353_event(tcd_instance->otg, max3353_otg_status_tests, otg_reg, "MAX3353 OTG SRC");
+        TRACE_MSG1(TCD, "inputs after applying otg register %02x\n", inputs);
+
+
+
+        TRACE_MSG0(TCD, "--MAX3353 ISR end");
+        if (inputs) otg_event(tcd_instance->otg, inputs, TCD, "MAX3353");
+        au_writel(0x40000000, IC1_MASKSET);     //enable interrupt
+}
+
+
+
+/* ********************************************************************************************** */
+/*! max3353_vbus - Do we have Vbus (cable attached?)
+ * Return non-zero if Vbus is detected.
+ *
+ */
+int max3353_vbus (struct otg_instance *otg)
+{
+        return 0;
+}
+
+/*! max3353_id - Do we have Vbus (cable attached?)
+ * Return non-zero if Vbus is detected.
+ *
+ */
+int max3353_idvbus (struct otg_instance *otg)
+{
+        return 0;
+}
+
+
+/* ********************************************************************************************* */
+
+/*! max3353_chrg_vbus - used to enable or disable B-device Vbus charging
+ */
+void max3353_chrg_vbus(struct otg_instance *otg, u8 flag)
+{
+        u8 reg2;
+
+        TRACE_MSG0(TCD, "--");
+        reg2 = i2c_readb(MAX3353E_CONTROL_REGISTER_2);
+        TRACE_MSG1(TCD, "Control 2 - Begin = %02x", reg2);
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "CHRG_VBUS_SET");
+                reg2 |= MAX3353E_VBUS_CHG2;
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_2, (u8) reg2);
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "CHRG_VBUS_RESET");
+                reg2 &= (~MAX3353E_VBUS_CHG2);
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_2, (u8) reg2);
+                break;
+        case PULSE:
+                break;
+        }
+        TRACE_MSG1(TCD, "Control 2 - End = %02x", reg2);
+}
+
+/*! max3353_drv_vbus - used to enable or disable A-device driving Vbus
+ */
+void max3353_drv_vbus(struct otg_instance *otg, u8 flag)
+{
+u8 reg2;
+
+        TRACE_MSG0(TCD, "--");
+        reg2 = i2c_readb(MAX3353E_CONTROL_REGISTER_2);
+        TRACE_MSG1(TCD, "Control 2 - Begin = %02x", reg2);
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "DRV_VBUS_SET");
+                reg2 |= MAX3353E_VBUS_DRV;
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_2, (u8) reg2);
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "DRV_VBUS_RESET");
+                reg2 &= (~MAX3353E_VBUS_DRV);
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_2, (u8) reg2);
+                break;
+        case PULSE:
+                break;
+        }
+        TRACE_MSG1(TCD, "Control 2 - End = %02x", reg2);
+}
+
+/*! max3353_dischrg_vbus - used to enable Vbus discharge
+ */
+void max3353_dischrg_vbus(struct otg_instance *otg, u8 flag)
+{
+        u8 reg2;
+
+        TRACE_MSG0(TCD, "--");
+        reg2 = i2c_readb(MAX3353E_CONTROL_REGISTER_2);
+        TRACE_MSG1(TCD, "Control 2 - Begin = %02x", reg2);
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "DISCHG_VBUS_SET");
+                reg2 |= MAX3353E_VBUS_DISCHG;
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_2, (u8) reg2);
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "DISCHG_VBUS_RESET");
+                reg2 &= (~MAX3353E_VBUS_DISCHG);
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_2, (u8) reg2);
+                break;
+        case PULSE:
+                break;
+        }
+        TRACE_MSG1(TCD, "Control 2 - End = %02x", reg2);
+}
+
+/*! max3353_dp_pullup_func - used to enable or disable peripheral connecting to bus
+ *
+ * C.f. 5.1.6, 5.1.7, 5.2.4 and 5.2.5
+ *
+ *                              host    peripheral
+ *              d+ pull-up      clr     set
+ *              d+ pull-down    set     clr
+ *
+ *              d- pull-up      clr     clr
+ *              d- pull-down    set     set
+ *
+ */
+void max3353_dp_pullup_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        TRACE_MSG0(TCD, "-- ");
+        switch (flag) {
+        case SET:
+		printk(KERN_INFO"%s: --\n", __FUNCTION__);
+                max3353_private.flags = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
+                TRACE_MSG0(TCD, "Clr DP PULLDOWN");
+                max3353_private.flags &= (~MAX3353E_DP_PULLDOWN);
+                TRACE_MSG0(TCD, "Set DP PULLUP");
+                max3353_private.flags |= (MAX3353E_DP_PULLUP);
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
+                break;
+
+        case RESET:
+                max3353_private.flags = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
+                TRACE_MSG0(TCD, "Clr DP PULLUP");
+                max3353_private.flags &= (~MAX3353E_DP_PULLUP);
+                TRACE_MSG0(TCD, "Set DP PULLDOWN");
+                max3353_private.flags |= (MAX3353E_DP_PULLDOWN);
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
+                break;
+
+        case PULSE:
+                TRACE_MSG0(TCD, "MAX3353_LOC_CONN PULSE");
+                break;
+        }
+        int temp = 0;
+        temp = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
+        TRACE_MSG1(TCD, "Control Register 1: %02x", temp);
+
+}
+
+/*! max3353_dm_pullup_func - used to enable or disable peripheral connecting to bus
+ *
+ */
+void max3353_dm_pullup_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                max3353_private.flags = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
+                TRACE_MSG0(TCD, "Clr DM PULLDOWN");
+                max3353_private.flags &= (~MAX3353E_DM_PULLDOWN);
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
+                TRACE_MSG0(TCD, "Set DM PULLUP");
+                max3353_private.flags |= (MAX3353E_DM_PULLUP);
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
+                break;
+
+        case RESET:
+                max3353_private.flags = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
+                TRACE_MSG0(TCD, "Clr DM PULLUP");
+                max3353_private.flags &= (~MAX3353E_DM_PULLUP);
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
+                TRACE_MSG0(TCD, "Set DM PULLDOWN");
+                max3353_private.flags |= (MAX3353E_DM_PULLDOWN);
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
+                break;
+
+        case PULSE:
+                TRACE_MSG0(TCD, "MAX3353_LOC_CONN PULSE");
+                break;
+        }
+        int temp = 0;
+        temp = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
+        TRACE_MSG1(TCD, "Control Register 1 %02x", temp);
+}
+
+/*! max3353_dm_det_func - used to enable or disable D- detect
+ *
+ */
+void max3353_dm_det_func(struct otg_instance *otg, u8 flag)
+{
+        return;
+}
+
+/*! max3353_dp_det_func - used to enable or disable D+ detect
+ *
+ */
+void max3353_dp_det_func(struct otg_instance *otg, u8 flag)
+{
+        return;
+}
+
+/*! max3353_bdis_acon_func - used to enable or disable auto a-connect
+ *
+ */
+void max3353_bdis_acon_func(struct otg_instance *otg, u8 flag)
+{
+        return;
+}
+
+/*! max3353_id_pulldown_func - used to enable or disable ID pulldown
+ *
+ */
+void max3353_id_pulldown_func(struct otg_instance *otg, u8 flag)
+{
+        return;
+}
+
+/*! max3353_audio_func - used to enable or disable Carkit Interrupt
+ *
+ */
+void max3353_audio_func(struct otg_instance *otg, u8 flag)
+{
+        return;
+}
+
+/*! max3353_uart_func - used to enable or disable transparent uart mode
+ *
+ */
+void max3353_uart_func(struct otg_instance *otg, u8 flag)
+{
+        return;
+}
+
+/*! max3353_mono_func - used to enable or disable mono audio connection
+ *
+ */
+void max3353_mono_func(struct otg_instance *otg, u8 flag)
+{
+        return;
+}
+
+
+/* ********************************************************************************************* */
+extern int max3353_procfs_init (void);
+extern void max3353_procfs_exit (void);
+
+/*! max3353_mod_init
+ */
+int max3353_mod_init(void)
+{
+        int ret;
+
+        TRACE_MSG0(TCD, "Initilize");
+        /* for interrupt bottom half handler
+         */
+        PREPARE_WORK_ITEM(max3353_private.bh, &max3353_bh, NULL);
+
+        /* setup max3353, enable interrupts, clear latch
+         * XXX when and how do we do DM_HI and DP_HI, when ID is present?
+         */
+        max3353_int_src_set(0x1f);
+        //max3353_int_src(MAX3353_NO_SE1_INT);
+        /*Turn on the max3353 and discharge the bus*/
+        i2c_writeb(MAX3353E_CONTROL_REGISTER_2, 0x0);
+        i2c_writeb(MAX3353E_CONTROL_REGISTER_1, 0x0);
+        int status = i2c_readb(MAX3353E_STATUS_REGISTER);
+        if ((status & 0x1) == 0){
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_2, 0x10);
+        }
+        i2c_writeb(MAX3353E_CONTROL_REGISTER_2, 0x0);
+        i2c_writeb(MAX3353E_CONTROL_REGISTER_1, MAX3353E_DM_PULLDOWN | MAX3353E_DP_PULLDOWN);
+
+#ifdef CONFIG_OTG_MAX3353_PROCFS
+        TRACE_MSG0(TCD, "MAX3353 Procfs");
+        max3353_procfs_init ();
+#endif /* CONFIG_OTG_MAX3353_PROCFS */
+
+        au_sync();
+
+        //      au_writel(0x1, IC1_TESTBIT);    //disable test bit for low leve interrupt
+        //All this done when define type of interrupt in irqmap.c
+        /*au_writel(0x40000000, IC1_CFG0CLR); //low level activation
+                au_writel(0x40000000, IC1_CFG1SET);
+                au_writel(0x40000000, IC1_CFG2CLR);
+                au_writel(0x40000000, IC1_MASKSET);//enable interrupt
+         */
+        //au_writel(0x40000000, IC1_SRCCLR);//set test bit as a source
+        au_writel(0x40000000, IC1_SRCSET);//set source to original
+        //au_writel(0x0, IC1_TESTBIT);
+        //au_writel(0x1, IC1_TESTBIT);
+
+#if 0
+        ret = au_readl(IC0_CFG0RD);
+        printk (KERN_INFO"IC0 Reg 0 : %08x\n", ret);
+        ret = au_readl(IC0_CFG1RD);
+        printk (KERN_INFO"IC0 Reg 1 : %08x\n", ret);
+        ret = au_readl(IC0_CFG2RD);
+        printk (KERN_INFO"IC0 Reg 2 : %08x\n", ret);
+        ret = au_readl(IC0_SRCRD);
+        printk (KERN_INFO"IC0 Source : %08x\n", ret);
+        ret = au_readl(IC0_ASSIGNRD);
+        printk (KERN_INFO"IC0 Assign : %08x\n", ret);
+        ret = au_readl(IC0_WAKERD);
+        printk (KERN_INFO"IC0 Wakeup : %08x\n", ret);
+        ret = au_readl(IC0_MASKRD);
+        printk (KERN_INFO"IC0 Mask : %08x\n", ret);
+
+        ret = au_readl(IC1_CFG0RD);
+        printk (KERN_INFO"IC1 Reg 0 : %08x\n", ret);
+        ret = au_readl(IC1_CFG1RD);
+        printk (KERN_INFO"IC1 Reg 1 : %08x\n", ret);
+        ret = au_readl(IC1_CFG2RD);
+        printk (KERN_INFO"IC1 Reg 2 : %08x\n", ret);
+        ret = au_readl(IC1_SRCRD);
+        printk (KERN_INFO"IC1 Source : %08x\n", ret);
+        ret = au_readl(IC1_ASSIGNRD);
+        printk (KERN_INFO"IC1 Assign : %08x\n", ret);
+        ret = au_readl(IC1_WAKERD);
+        printk (KERN_INFO"IC1 Wakeup : %08x\n", ret);
+        ret = au_readl(IC1_MASKRD);
+        printk (KERN_INFO"IC1 Mask : %08x\n", ret);
+
+#endif
+
+        return 0;
+}
+
+/*! max3353_mod_exit
+ */
+void max3353_mod_exit(void)
+{
+        i2c_writeb(MAX3353E_INTERRUPT_MASK, 0x0);
+        //i2c_close();
+#ifdef CONFIG_OTG_MAX3353_PROCFS
+        max3353_procfs_exit ();
+#endif /* CONFIG_OTG_MAX3353_PROCFS */
+
+        while (PENDING_WORK_ITEM(max3353_private.bh)) {
+                printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
+                schedule_timeout(10 * HZ);
+        }
+
+}
+
+/* ********************************************************************************************* */
+/*! max3353_configure - configure the MAX3353 for this host
+ * @param tx_mode - the type of connection between the host USB and the MAX3353
+ * @param spd_ctrl - suspend control method
+ */
+void  max3353_configure(tx_mode_t tx_mode, spd_ctrl_t spd_ctrl)
+{
+        u16 vendor = 0, product = 0, revision = 0;
+        u8 mode1, mode2, control;
+
+        struct otg_transceiver_map *map = max3353_transceiver_map;
+        TRACE_MSG0(TCD, "Configure");
+
+        //#if defined(CONFIG_OTG_MAX3353_MX2ADS) || defined(CONFIG_OTG_MAX3353_MX2ADS_MODULE)
+        u32 vp;
+        u8 vb=0;
+        TRACE_MSG0(TCD, "1. Read Transceiver ID's with long read");
+        vb = i2c_readb(MAX3353E_MANUFACTURER_REGISTER_0);
+        max3353_private.vendor = vb;
+        vb = i2c_readb(MAX3353E_MANUFACTURER_REGISTER_1);
+        max3353_private.vendor += vb<<8;
+        vb = i2c_readb(MAX3353E_MANUFACTURER_REGISTER_2);
+        max3353_private.vendor += vb<<16;
+        vb = i2c_readb(MAX3353E_MANUFACTURER_REGISTER_3);
+        max3353_private.vendor += vb<<24;
+
+        vb = i2c_readb(MAX3353E_PRODUCT_ID_REGISTER_0);
+        max3353_private.product = vb;
+        vb = i2c_readb(MAX3353E_PRODUCT_ID_REGISTER_1);
+        max3353_private.product += vb<<8;
+        vb = i2c_readb(MAX3353E_PRODUCT_ID_REGISTER_2);
+        max3353_private.product += vb<<16;
+        vb = i2c_readb(MAX3353E_PRODUCT_ID_REGISTER_3);
+        max3353_private.product += vb<<24;
+
+        mode1 = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
+        mode2 = i2c_readb(MAX3353E_CONTROL_REGISTER_2);
+
+        TRACE_MSG4(TCD, "2. OTG Transceiver: vendor: %08x product: %08x mode1: %02x mode2: %02x",
+                        max3353_private.vendor, max3353_private.product, mode1, mode2);
+
+        TRACE_MSG0(TCD, "3. Disable All Transceiver Control Register 1 ");
+        i2c_writeb(MAX3353E_CONTROL_REGISTER_1, 0x0);                                    // clear
+        i2c_writeb(MAX3353E_CONTROL_REGISTER_2, 0x0);                                    // clear
+
+        TRACE_MSG0(TCD, "4. Enable D-/D+ Pulldowns in Transceiver Control Register 1 ");
+
+        i2c_writeb(MAX3353E_CONTROL_REGISTER_1, MAX3353E_DM_PULLDOWN | MAX3353E_DP_PULLDOWN);
+        max3353_private.flags = MAX3353E_DM_PULLDOWN | MAX3353E_DP_PULLDOWN;
+
+        TRACE_MSG0(TCD, "5. Clear latch and enable interrupts");
+        i2c_writeb(MAX3353E_INTERRUPT_LATCH, 0x0);
+        max3353_int_src_set(0x1f);
+
+
+
+}
+
+
diff -uNr linux/drivers/no-otg/ocd/max3353e/max3353e.h linux/drivers/otg/ocd/max3353e/max3353e.h
--- linux/drivers/no-otg/ocd/max3353e/max3353e.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/max3353e.h	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,134 @@
+/*
+ * otg/ocd/max3353/max3353.h -- USB Transceiver Controller driver
+ * @(#) balden@belcarra.com|otg/ocd/max3353e/max3353e.h|20060831021118|62926
+ *
+ *      Copyright (c) 2004-2005 Belcarra
+ *	Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
+ *
+ * By:
+ *      Stuart Lynne <sl@lbelcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @defgroup MAX3353TCD TCD - Maxim MAX3353
+ * @ingroup platformgroup
+ */
+/*!
+ * @file otg/ocd/max3353e/max3353e.h
+ * @brief Private structures and defines for MAX3353 Transciever Controller Driver.
+ *
+ * This file contains the private defines and structures for the MAX3353 Transceiver
+ * Driver.
+ *
+ * @ingroup MAX3353TCD
+ */
+
+
+#ifdef CONFIG_XXXXX
+#define MAX3353_GPIO            (2)
+#define TCD_MAX3353_I2C_ADDR    MAX3353_I2C_ADDR_HIGH;
+#endif
+
+#define MAX3353_NAME    "max3353"
+
+#define MAX3353_LOC_CONN 0x01
+
+#define MAX3353_INT_SRC         0xeb
+
+//#define MAX3353_ALL_INT_SRC     0xff
+//#define MAX3353_NO_SE1_INT    0xeb
+//#define MAX3353_NO_SE1_INT    0xfb              /* do not pay attention to DP_HI */
+
+typedef enum otg_transceiver {
+        unknown_transceiver,
+        max3353,
+        max3301e
+} otg_transceiver_t;
+
+struct otg_transceiver_map {
+        otg_transceiver_t transceiver_type;
+        u16 vendor;
+        u16 product;
+        u16 revision;
+        char *name;
+};
+
+struct max3353_private {
+        WORK_STRUCT bh;
+        u16 vendor;
+        u16 product;
+        u16 revision;
+        u32 flags;
+        u8  int_src;
+        struct otg_transceiver_map *transceiver_map;
+};
+
+/*! tx_mode
+ * This defines the various ways that the MAX3353 can be
+ * wired into the host USB.
+ */
+typedef enum tx_mode {
+        dat_se0_bidirectional,          /*!< 3-Wire */
+        vp_vm_bidirectional,            /*!< 4-Wire */
+        dat_se0_unidirectional          /*!< 6-Wire */
+} tx_mode_t;
+
+/*! spd_ctrl
+ * This defines how the speed and suspend pins are controlled
+ * for this host.
+ */
+typedef enum spd_ctrl {
+        spd_susp_pins,                  /*!< controlled by SPEED and SUSPEND pins */
+        spd_susp_reg,                   /*!< controled by SPEED_REG and SUSPEND_REG in Mode Control 1 register */
+} spd_ctrl_t;
+
+
+extern struct tcd_ops tcd_ops;
+extern struct max3353_private max3353_private;
+extern struct tcd_instance *tcd_instance;
+
+/* max3353.c */
+extern int max3353_mod_init(void);
+extern void max3353_mod_exit(void);
+extern void max3353_chrg_vbus(struct otg_instance *, u8 );
+extern void max3353_drv_vbus(struct otg_instance *, u8 );
+extern void max3353_dischrg_vbus(struct otg_instance *, u8 );
+extern void max3353_dp_pullup_func(struct otg_instance *, u8 );
+extern void max3353_dm_pullup_func(struct otg_instance *, u8 );
+extern void max3353_dm_det_func(struct otg_instance *, u8 );
+extern void max3353_dp_det_func(struct otg_instance *, u8 );
+extern void max3353_bdis_acon_func(struct otg_instance *otg, u8 flag);
+extern void max3353_id_pulldown_func(struct otg_instance *otg, u8 flag);
+extern void max3353_audio_func(struct otg_instance *otg, u8 flag);
+extern void max3353_uart_func(struct otg_instance *otg, u8 flag);
+extern void max3353_mono_func(struct otg_instance *otg, u8 flag);
+
+extern void max3353_otg_timer(struct otg_instance *, u8 );
+extern void max3353_bh(void *);
+extern int max3353_id (struct otg_instance *);
+extern int max3353_vbus (struct otg_instance *);
+extern void  max3353_configure(tx_mode_t, spd_ctrl_t );
+
+/* thread */
+extern int max3353_thread_init (void (bh_proc)(void *));
+extern void max3353_thread_exit (wait_queue_head_t *);
+extern void max3353_thread_wakeup(int enabled, int first);
+
+
+
+/* i2c-xxx.c */
+int  i2c_configure(char *name, int addr);
+extern void  i2c_close(void);
+extern u8 i2c_readb(u8 );
+extern u16 i2c_readw(u8 );
+extern u32 i2c_readl(u8 );
+extern int  i2c_writeb(u8 , u8 );
+
+
+/* ********************************************************************************************* */
+#define TRACE_I2CB(t,r) TRACE_MSG3(t, "%-40s[%02x] %02x", #r, r, i2c_readb(r))
+#define TRACE_I2CW(t,r) TRACE_MSG3(t, "%-40s[%02x] %04x", #r, r, i2c_readw(r))
+#define TRACE_GPIO(t,b,r) TRACE_MSG2(t, "%-40s %04x", #r, readw(b + r))
+#define TRACE_REGL(t,r) TRACE_MSG2(t, "%-40s %08x", #r, readl(r))
+
diff -uNr linux/drivers/no-otg/ocd/max3353e/tcd-db1550.c linux/drivers/otg/ocd/max3353e/tcd-db1550.c
--- linux/drivers/no-otg/ocd/max3353e/tcd-db1550.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/tcd-db1550.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,227 @@
+/*
+ * otg/ocd/max3353e/tcd-db1550.c -- USB Transceiver Controller driver
+ * @(#) balden@belcarra.com|otg/ocd/max3353e/tcd-db1550.c|20060831021118|37213
+ *
+ *      Copyright (c) 2004-2005 Belcarra
+ *	Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
+ *
+ * By:
+ *      Stuart Lynne <sl@lbelcarra.com>,
+ *      Shahrad Payandeh <sp@belcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/max3353e/tcd-db1550.c
+ * @brief DB1550 MAX3353 driver.
+ *
+ *
+ * @ingroup MAX3353TCD
+ */
+
+#include <otg/pcd-include.h>
+#include <linux/pci.h>
+#include <otghw/max3353e-hardware.h>
+#include "otghw/bvd-hardware.h"
+#include "max3353e.h"
+#include <asm/au1000.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+struct ocd_instance *ocd_instance;
+otg_tag_t OCD;
+
+#if 0
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/hcd.h>
+#include <otg/tcd.h>
+#include <otg/ocd.h>
+#include <otg/pcd.h>
+
+#include <otghw/isp1301-hardware.h>
+#include "isp1301.h"
+
+#endif
+/*SP
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+*/
+//struct isp1301_private isp1301_private;
+
+#ifdef CONFIG_OMAP_H2
+#define ADAPTOR_NAME "OMAP I2C"
+#endif /* CONFIG_OMAP_H2 */
+#ifdef CONFIG_ARCH_MAINSTONE
+#define ADAPTOR_NAME "PXA-I2C-Adapter"
+#endif /* CONFIG_ARCH_MAINSTONE */
+#ifdef CONFIG_OTG_DB1550_J15
+#define ADAPTOR_NAME "pb1550 adapter"
+#endif /* CONFIG_OTG_DB1550_J15 */
+
+/* ********************************************************************************************* */
+
+
+static irqreturn_t max3353_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
+{
+        TRACE_MSG0(TCD, "--");
+
+        SCHEDULE_WORK(max3353_private.bh);
+
+        return IRQ_HANDLED;
+}
+
+
+/* ********************************************************************************************* */
+
+struct ocd_ops ocd_ops;
+struct tcd_instance *db1550_tcd_instance;
+
+//#define ADAPTOR_NAME "pb1550 adapter"
+
+/*! tcd_mod_init
+ */
+int tcd_mod_init(void)
+{
+
+        struct otg_instance *otg;
+
+        int i2c = i2c_configure(ADAPTOR_NAME, MAX3353E_I2C_ADDR_HIGH);
+        int irq = request_irq (AU1500_GPIO_207, max3353_int_hndlr, SA_INTERRUPT, "MAX3353", NULL);
+        THROW_IF(irq, error);
+
+        TRACE_MSG0(TCD, "--");
+
+        THROW_IF(i2c, error);
+
+        TRACE_MSG0(TCD, "1. Enable db1550 external OTG Transceiver!");
+
+
+        TRACE_MSG0(TCD, "2. configure i2c driver!");
+        max3353_configure(dat_se0_bidirectional, spd_susp_reg);
+
+        TRACE_MSG0(TCD, "3. configure max3353!");
+        max3353_mod_init();
+
+        TRACE_MSG0(TCD, "4. set ops");
+	THROW_UNLESS(ocd_instance = otg_set_ocd_ops(&ocd_ops), error);
+        THROW_UNLESS(ocd_instance && (otg = ocd_instance->otg), error);
+        THROW_UNLESS(db1550_tcd_instance = otg_set_tcd_ops(&tcd_ops), error);
+
+#if 0	//test for making pulse on DP
+	for (;;){
+                max3353_private.flags = i2c_readb(MAX3353E_CONTROL_REGISTER_1);
+                TRACE_MSG0(TCD, "Clr DP PULLDOWN");
+                max3353_private.flags &= (~MAX3353E_DP_PULLDOWN);
+                TRACE_MSG0(TCD, "Set DP PULLUP");
+                max3353_private.flags |= (MAX3353E_DP_PULLUP);
+                i2c_writeb(MAX3353E_CONTROL_REGISTER_1, (u8) max3353_private.flags);
+	}
+#endif	
+												
+	
+        /* Success!
+         */
+
+        TRACE_MSG0(TCD, "5. Success!");
+
+        otg_init(otg);
+
+	//In device mode only this part makes a virtual interrupt, while the cable is
+	//and modules are loaded.
+	au_writel (0x40000000, IC1_SRCCLR);
+	au_writel (0x0, IC1_TESTBIT);
+	au_writel (0x1, IC1_TESTBIT);
+	au_writel (0x0, IC1_TESTBIT);
+	au_writel (0x40000000, IC1_SRCSET);
+
+	
+        /* error handling
+         */
+        CATCH(error) {
+		printk(KERN_INFO"Error in tcd initilization\n");
+                if (irq) free_irq(AU1500_GPIO_207, NULL);
+                if (i2c) i2c_close();
+		return -EINVAL;
+        }
+        return 0;
+}
+
+/*! tcd_mod_exit
+ */
+void tcd_mod_exit(void)
+{
+        struct otg_instance *otg = tcd_instance->otg;
+        TRACE_MSG0(TCD, "Exit.");
+
+        otg_event(otg, enable_otg_, OCD, "enable_otg_");
+        //if (otg)
+        //        otg_exit(otg);
+        
+        db1550_tcd_instance = otg_set_tcd_ops(NULL);
+        free_irq(AU1500_GPIO_207, NULL);
+        max3353_mod_exit();
+
+        i2c_writeb(MAX3353E_INTERRUPT_MASK, 0xff);
+        i2c_close();
+
+        if (otg)
+                otg_exit(otg);
+}
+/* ********************************************************************************************* */
+struct tcd_ops tcd_ops = {
+
+//        vbus: max3353_vbus,
+
+        mod_init: tcd_mod_init,
+        mod_exit: tcd_mod_exit,
+
+        dischrg_vbus_func: max3353_dischrg_vbus,
+        chrg_vbus_func: max3353_chrg_vbus,
+        drv_vbus_func: max3353_drv_vbus,
+        dp_pullup_func: max3353_dp_pullup_func,
+        dm_pullup_func: max3353_dm_pullup_func,
+
+};
+
+#if 0
+
+struct tcd_ops tcd_ops;
+
+
+void db1550_tcd_global_init(void)
+{
+	ZERO(tcd_ops);
+
+	tcd_ops.id = max3353_id;
+	tcd_ops.vbus = max3353_vbus;
+        tcd_ops.chrg_vbus_func = max3353_chrg_vbus;
+        tcd_ops.dischrg_vbus_func = max3353_dischrg_vbus;
+        tcd_ops.dp_pullup_func = max3353_dp_pullup_func;
+        tcd_ops.dm_pullup_func = max3353_dm_pullup_func;
+        tcd_ops.dp_pulldown_func = max3353_dp_pulldown_func;
+        tcd_ops.dm_pulldown_func = max3353_dm_pulldown_func;
+        tcd_ops.overcurrent_func = NULL;
+        tcd_ops.dm_det_func = max3353_dm_det_func;
+        tcd_ops.dp_det_func = max3353_dp_det_func;
+        tcd_ops.cr_det_func = max3353_cr_det_func;
+
+	tcd_ops.peripheral_host_func = max3353_peripheral_host_func;
+
+        tcd_ops.id_pulldown_func = max3353_id_pulldown_func;
+        tcd_ops.audio_func = max3353_audio_func;
+        tcd_ops.uart_func = max3353_uart_func;
+        tcd_ops.mono_func = max3353_mono_func;
+
+        tcd_ops.mod_init = tcd_mod_init;
+        tcd_ops.mod_exit = tcd_mod_exit;
+}
+
+	
+#endif
+	
+		
+	
+
diff -uNr linux/drivers/no-otg/ocd/max3353e/tcd-mx2ads.c linux/drivers/otg/ocd/max3353e/tcd-mx2ads.c
--- linux/drivers/no-otg/ocd/max3353e/tcd-mx2ads.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/max3353e/tcd-mx2ads.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,541 @@
+/*
+ * otg/ocd/max3353e/tcd-mx2ads.c -- MX21ADS ISP1301 Transceiver Controller driver
+ * @(#) balden@belcarra.com|otg/ocd/max3353e/tcd-mx2ads.c|20060831021118|46922
+ *
+ *      Copyright (c) 2004-2005 Belcarra
+ *	Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp
+ *
+ * By:
+ *      Stuart Lynne <sl@lbelcarra.com>,
+ *      Shahrad Payandeh <sp@belcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/max3353e/tcd-mx2ads.c
+
+ * @brief MX2ADS ISP1301 driver.
+ *
+ * This implements the ISP1301 Transceiver Controller Driver for the mx21
+ * using the USBOTG I2C controller for access.
+ *
+ * Notes
+ *
+ * 1. There are two interrupt sources, the I2C IO completion type generated when either of NOACK
+ * or RWREADY is set and the XCVR activity type generated when there is a OTG transceiver
+ * generated interrupt.
+ *
+ * It is important to only enable a single source at a time. By default we leave the XCVR
+ * interrupt enabled for normal operation and only enable the I2C IO type when we are actively
+ * waiting for an I2C IO operation to complete.
+ *
+ * 2. The USBOTG module can also interact with the OTG Transceiver, attempting to do register
+ * reads for various conditions (such as XCVR interrupts.) These interfere and cause problems so
+ * we keep the the I2C Controller interface in software mode at all times.
+ *
+ * 3. Because we must wait several hundred micro-seconds for I/O operations to complete, the i2c
+ * implementation is only usable from non-interrupt contexts. This means that all work that
+ * needs to be done needs to be pushed to a bottom half handler. A generic i2cWrite_irq() is
+ * provided where simple writes are all that are required.
+ *
+ * 4. The handling of the ISC_INTERRUPT_AND_CTRL register is complicated because the top nibble
+ * is r/w controlling the interrupt source enables while the bottom nibble is write 1 to clear
+ * to reset two of the three interrupt source bits (NOACK and RWREADY).
+ *
+ *
+ * TODO
+ *
+ * 1. The MX2ADS seems to have a hardware problem, when operating as a B-Device, Vbus does not
+ * drop to zero when disconnected (unplugged.) A 22kohm resister across C133 is suggested.
+ * Alternately I am just enabling VBUS_DISCHRG in LOC_CONN when we enable DP_PULLUP. Hopefully
+ * this will not be required in production code.
+ *
+ * @ingroup ISP1301TCD
+ */
+
+#include <otg/pcd-include.h>
+#include <linux/pci.h>
+#include <asm/arch/mx2.h>
+#include <otghw/isp1301-hardware.h>
+#include "mx2.h"
+#include <otghw/mx2-hardware.h>
+#include "isp1301.h"
+//#include <otg/otg-ops.h>
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+
+/*! mx2_urb
+ */
+u8 mx2_urbv(u32 port)
+{
+        u8 val =  mx2_rb(port);
+        TRACE_MSG2(TCD, "PORT: %08x %02x", port, val);
+        return val;
+}
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/* I2C Bottom Half I/O
+ *
+ * These are the I2C I/O routines that can be used from any non-interrupt
+ * context, typically from a bottom half handler.
+ *
+ * There is an interrupt safe, delayed i2cWrite function, it queues the
+ * writes and schedules work via a bottom half handler that can safely call
+ * the i2cWrite function.
+ */
+#define MX2_I2C_TIMEOUT         1
+#define I2C_READ_MASK           0x80
+#define I2C_MAX_WRITE           100
+
+DECLARE_MUTEX(i2c_sem);                                                 // semaphore to prevent overlapped i2c i/o
+wait_queue_head_t mx2_i2c_wait;                                         // wait structure for i2c i/o interrupt
+struct WORK_STRUCT mx2_i2c_io_work_struct;                              // work structure for queued i2c writes
+
+int i2c_Write_Queued;
+u8 i2c_Write_Data[I2C_MAX_WRITE];
+u32 i2c_Write_Addr[I2C_MAX_WRITE];
+char * i2c_Write_Msg[I2C_MAX_WRITE];
+
+/*! i2c_read - read from otg transceiver
+ * This programs the I2C controller to do a read, waits for the completion
+ * interrupt, cleans up and returns the value for the specified register.
+ */
+void i2c_read(u32 port, int ops)
+{
+        u8 i2c_interrupt_and_ctrl;
+        u8 ctrl_reg;
+        int count;
+        RETURN_IF(i2c_Write_Queued < 0);
+        down(&i2c_sem);                                                 // pass through semaphore
+#if 1
+        if ((ctrl_reg = mx2_rb(MX2_I2C_OP_CTRL_REG)) & 0x4) {
+                TRACE_MSG1(TCD, "bad ctrl_reg: %02x", ctrl_reg);
+        }
+        for (count = 0; (count < 100) && (ctrl_reg = mx2_rb(MX2_I2C_OP_CTRL_REG)) & 0x80; count++) {
+                TRACE_MSG1(TCD, "busy ctrl_reg: %02x", ctrl_reg);
+        }
+#endif
+        mx2_orb(MX2_I2C_INTERRUPT_AND_CTRL, 0x6);                   // reset and disable interrupts
+        mx2_wb(MX2_SEQ_OP_REG, ops);                                    // set number of sequential operations to 1
+        mx2_wb(MX2_SEQ_RD_STARTAD, port);                               // sequential read start address
+        mx2_wb(MX2_OTG_XCVR_DEVAD, I2C_READ_MASK | MX2_I2C_DEV_ADDR);   // receiver address
+        mx2_orb(MX2_I2C_INTERRUPT_AND_CTRL, I2C_NOACK_EN | I2C_RWREADY_EN); // enable i2x I/O interrupt
+        interruptible_sleep_on_timeout(&mx2_i2c_wait, MX2_I2C_TIMEOUT); // wait for signal from i2c io interrupt handler
+        up(&i2c_sem);
+}
+
+/*! i2c_readb - read a byte from otg transceiver
+ * This programs the I2C controller to do a single byte read, waits for the
+ * completion interrupt, cleans up and returns the value for the specified
+ * register.
+ */
+u8 i2c_readb(u8 port)
+{
+        u8 data;
+        u32 addr = OTG_I2C_BASE + port;
+        i2c_read(addr, 1);
+        data =  mx2_rb(addr);                                          // read the register
+        //TRACE_MSG2(TCD, "port: %08x data: %02x", port, data);
+        return data;
+}
+
+/*! i2c_readw - read two bytes from otg transceiver
+ * This programs the I2C controller to do a two byte read, waits for the
+ * completion interrupt, cleans up and returns the value for the specified
+ * registers.
+ */
+u16 i2c_readw(u8 port)
+{
+        u16 data;
+        u32 addr = OTG_I2C_BASE + port;
+        i2c_read(addr, 2);
+        data =  mx2_rb(addr) | (mx2_rb(addr + 1) << 8);               // read the register
+        //TRACE_MSG2(TCD, "port: %08x data: %04x", port, data);
+        return data;
+}
+
+/*! i2c_readl - read two bytes from otg transceiver
+ * This programs the I2C controller to do a two byte read, waits for the
+ * completion interrupt, cleans up and returns the value for the specified
+ * registers.
+ */
+u32 i2c_readl(u8 port)
+{
+        u32 data;
+        u32 addr = OTG_I2C_BASE + port;
+        i2c_read(addr, 2);
+        data = mx2_rb(addr) | (mx2_rb(addr + 1) << 8) | (mx2_rb(addr + 2) << 16) | (mx2_rb(addr + 3) << 24);
+        //TRACE_MSG2(TCD, "port: %08x data: %04x", port, data);
+        return data;
+}
+
+/*! i2cWrite - write a byte to otg transceiver
+ * This writes the data to the shadow register, programs the I2C controller
+ * to do a single byte write, waits for the completion interrupt, cleans up
+ * and exits.
+ */
+void i2cWrite(u32 port, u8 data, char *msg)
+{
+        u8 i2c_interrupt_and_ctrl;
+        u8 test;
+        u8 ctrl_reg;
+        int count;
+        //TRACE_FMSG3(TCD, msg, "i2cWrite: port: %s (%08x) data: %02x", mx2_ureg_name(port), port, data);
+        TRACE_FMSG2(TCD, msg, "i2cWrite: (%08x) data: %02x", port, data);
+
+        //test = i2c_readb(port & 0xfffffffe);
+        //TRACE_MSG2(TCD, "i2cWrite: %02x before %02x", port, test);
+
+        down(&i2c_sem);                                                 // pass through semaphore
+
+#if 1
+        if ((ctrl_reg = mx2_rb(MX2_I2C_OP_CTRL_REG)) & 0x4) {
+                TRACE_MSG1(TCD, "bad ctrl_reg: %02x", ctrl_reg);
+        }
+        for (count = 0; (count < 10) && (ctrl_reg = mx2_rb(MX2_I2C_OP_CTRL_REG)) & 0x80; count++) {
+                TRACE_MSG1(TCD, "busy ctrl_reg: %02x", ctrl_reg);
+        }
+#endif
+        mx2_orb(MX2_I2C_INTERRUPT_AND_CTRL, 0x6);                   // reset and disable interrupts
+        mx2_wb(port, data);                                           // write the register
+        mx2_wb(MX2_SEQ_OP_REG, 1);                                      // set number of sequential operations to 1
+        mx2_wb(MX2_SEQ_RD_STARTAD, port);                               // sequential read start address
+        mx2_wb(MX2_OTG_XCVR_DEVAD, MX2_I2C_DEV_ADDR);                   // receiver address
+        mx2_orb(MX2_I2C_INTERRUPT_AND_CTRL, I2C_NOACK_EN | I2C_RWREADY_EN); // enable i2x I/O interrupt
+        interruptible_sleep_on_timeout(&mx2_i2c_wait, MX2_I2C_TIMEOUT); // wait for signal from i2c io interrupt handler
+        up(&i2c_sem);
+
+        //test = i2c_readb(port & 0xfffffffe);
+        //TRACE_MSG2(TCD, "i2cWrite: %02x after %02x", port, test);
+}
+
+/*! mx2_i2c_io_bh - bottom half handler to use i2cWrite on queued data
+ */
+void mx2_i2c_io_bh(void *arg)
+{
+        while (i2c_Write_Queued > 0) {
+                u8 write = i2c_Write_Data[0];
+                u32 port = i2c_Write_Addr[0];
+                char *msg = i2c_Write_Msg[0];
+                u8 data;
+                unsigned long flags;                                    // atomic update of counter and saved values
+                local_irq_save (flags);
+                i2c_Write_Queued--;
+                memcpy(i2c_Write_Data, i2c_Write_Data + 1, sizeof(i2c_Write_Data) - 1);
+                memcpy(i2c_Write_Addr, i2c_Write_Addr + 1, sizeof(i2c_Write_Addr) - 4);
+                memcpy(i2c_Write_Msg, i2c_Write_Msg + 1, sizeof(i2c_Write_Msg) - 4);
+                local_irq_restore (flags);
+                i2cWrite(port, write, msg);                             // perform write
+        }
+}
+
+/*! i2cWrite_irq - queue data for i2cWrite bottom half handler
+ */
+void i2cWrite_irq(u32 port, u8 data, char *msg)
+{
+        RETURN_IF(i2c_Write_Queued < 0);
+        if ((i2c_Write_Queued == I2C_MAX_WRITE)) {
+                TRACE_MSG3(TCD, "TOO MANY QUEUED CANNOT WRITE port: %08x data: %02x active: %d", port, data, i2c_Write_Queued);
+                return;
+        }
+        i2c_Write_Addr[i2c_Write_Queued] = port;
+        i2c_Write_Data[i2c_Write_Queued] = data;
+        i2c_Write_Msg[i2c_Write_Queued] = msg;
+        i2c_Write_Queued++;
+        TRACE_FMSG3(TCD, msg, "i2cWrite_irq: port: %08x data: %02x active: %d", port, data, i2c_Write_Queued);
+        SCHEDULE_WORK(mx2_i2c_io_work_struct);
+}
+
+/*! i2c_writeb
+ */
+int i2c_writeb(u8 subaddr, u8 buf)
+{
+        i2cWrite_irq(OTG_I2C_BASE + subaddr, buf, "i2c_writeb");
+        return 0;
+}
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/*! mx2ads_bh
+ */
+void mx2ads_bh(void *arg)
+{
+        isp1301_bh(NULL);
+        //mx2_bh(NULL);
+
+        /* re-enable the OTG XCVRINT
+         */
+        mx2_orb(MX2_I2C_INTERRUPT_AND_CTRL, I2C_OTGXCVRINT_EN);
+}
+
+
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/* I2C I/O and XCVR Interrupt Handler
+ */
+
+/*! mx2_i2c_int_hndlr
+ * This is called from the main mx21ads interrupt handler to handle the
+ * i2c i/o interrupt. There are two main interrupt sources:
+ *
+ */
+irqreturn_t mx2_i2c_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
+{
+        //TRACE_MSG0(TCD, "MX2ADS I2C INTERRUPT: WAKEUP");
+        wake_up_interruptible(&mx2_i2c_wait);                                   // wakeup waiting bottom half handler
+        return IRQ_HANDLED;
+}
+
+/*! mx2_tcd_int_hndlr
+ * This is called from the main mx21ads interrupt handler to handle the
+ * i2c i/o interrupt. There are two main interrupt sources:
+ */
+irqreturn_t mx2_tcd_int_hndlr (int irq, void *dev_id, struct pt_regs *regs)
+{
+        //TRACE_MSG0(TCD, "MX2ADS TCD INTERRUPT: SCHEDULE WORK");
+        isp1301_thread_wakeup(1, 0);                                                       // wakeup kernel thread
+        return IRQ_HANDLED;
+}
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+
+/*! mx2_tcd_init - used to initialize/enable or disable the tcd driver
+ */
+void mx2_tcd_init(struct otg_instance *otg, u8 flag)
+{
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "MX2_TCD_EN SET");
+                otg_event(otg, TCD_OK | ID_FLOAT, TCD, "TCD_OK");
+                //mx2_i2c_xcvr_schedule(1);
+                isp1301_thread_wakeup(1, 1);
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "MX2_TCD_EN RESET");
+                isp1301_thread_wakeup(0, 0);
+                otg_event(otg, TCD_OK, TCD, "TCD_OK");
+                break;
+        }
+}
+
+/*! mx2_dp_pullup_func - used to enable or disable peripheral connecting to bus
+ */
+void mx2_dp_pullup_func(struct otg_instance *otg, u8 flag)
+{
+        struct tcd_instance *tcd = (struct tcd_instance *)otg->tcd;
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "MX2_LOC_CONN SET");
+
+                TRACE_MSG0(TCD, "MX2_LOC_CONN SET - enable function interrupts");
+                mx2_wl(OTG_FUNC_SINT_STEN, /*SYSTEM_DONEREGINTDS_EN | *//*SYSTEM_SOFDETINT_EN |*/ SYSTEM_DONEREGINT_EN |
+                                SYSTEM_SUSPDETINT_EN | SYSTEM_RSMFININT_EN | SYSTEM_RESETINT_EN);
+
+                TRACE_MSG0(TCD, "MX2_LOC_CONN SET - Set VBUS_DISCHRG");
+                i2c_writeb(ISP1301_OTG_CONTROL_SET, (u8) ISP1301_VBUS_DISCHRG);
+                break;
+        }
+
+        /* call generic dp pullup function
+         */
+        isp1301_dp_pullup_func(otg, flag);
+
+        switch (flag) {
+        case RESET:
+                TRACE_MSG0(TCD, "MX2_LOC_CONN SET - Clr VBUS_DISCHRG");
+                i2c_writeb(ISP1301_OTG_CONTROL_CLR, (u8) ISP1301_VBUS_DISCHRG);
+                break;
+        }
+
+}
+
+/*! mx2_drv_vbus - used to enable or disable A-device driving Vbus
+ */
+void mx2_drv_vbus(struct otg_instance *otg, u8 flag)
+{
+        TRACE_MSG0(TCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(TCD, "DRV_VBUS_SET");
+                i2c_writeb(ISP1301_OTG_CONTROL_CLR, (u8) ISP1301_VBUS_DRV);
+                break;
+        }
+
+        /* call generic drv vbus function
+         */
+        isp1301_drv_vbus(otg, flag);
+
+        switch (flag) {
+        case RESET:
+                TRACE_MSG0(TCD, "DRV_VBUS_RESET");
+                i2c_writeb(ISP1301_OTG_CONTROL_SET, (u8) ISP1301_VBUS_DRV);
+                break;
+        }
+}
+
+
+
+/*! mx2_id - return true if id is present
+ */
+int mx2_id(struct otg_instance *otg)
+{
+        /* this will force the bottom half handler to read the interrupt
+         * source register and generate an otg event
+         */
+        TRACE_MSG0(TCD, "ID: 0");
+        //mx2_i2c_xcvr_schedule(1);
+        isp1301_thread_wakeup(1, 1);
+        return 0;
+}
+
+/*! mx2_vbus - return true if Vbus is present
+ */
+int mx2_vbus(struct otg_instance *otg)
+{
+        /* this will force the bottom half handler to read the interrupt
+         * source register and generate an otg event
+         */
+        TRACE_MSG0(TCD, "VBUS: 0");
+        //mx2_i2c_xcvr_schedule(1);
+        isp1301_thread_wakeup(1, 1);
+        return 0;
+}
+
+/* ********************************************************************************************* */
+struct tcd_ops *otg_tcd_ops;
+struct tcd_instance *mx2ads_tcd_instance;
+
+/*! mx2_tcd_mod_init - initial tcd setup
+ * Allocate interrupts and setup hardware.
+ * This is called from mx2-ocd.c
+ */
+int mx2_tcd_mod_init (void)
+{
+        struct otg_instance *otg;
+
+        printk(KERN_INFO"%s\n", __FUNCTION__);
+
+        TRACE_MSG0(TCD, "0. Basic Setup");
+
+
+        init_waitqueue_head(&mx2_i2c_wait);
+        PREPARE_WORK_ITEM(mx2_i2c_io_work_struct, &mx2_i2c_io_bh, NULL);
+        //PREPARE_WORK_ITEM(mx2_i2c_xcvr_work_struct, &mx2_i2c_xcvr_bh, NULL);
+
+        isp1301_thread_init(mx2ads_bh);
+
+
+        TRACE_MSG1(TCD, "i2c_int_hndlr: %x", otg_tcd_ops);
+        TRACE_MSG2(TCD, "i2c_int_hndlr: %x %x", &tcd_ops, tcd_ops.i2c_int_hndlr);
+        TRACE_MSG2(TCD, "tcd_int_hndlr: %x %x", &tcd_ops, tcd_ops.tcd_int_hndlr);
+
+        TRACE_MSG0(TCD, "4. Enable Interrupts");
+
+        mx2_wb(MX2_I2C_OP_CTRL_REG, 0x04);                            // Software mode, output enabled
+
+        mx2_urbv(MX2_OTG_XCVR_DEVAD);
+        mx2_urbv(MX2_SEQ_OP_REG);
+        mx2_urbv(MX2_SEQ_RD_STARTAD);
+        mx2_urbv(MX2_I2C_OP_CTRL_REG);
+        mx2_urbv(MX2_SCLK_TO_SCL_HPER);
+        mx2_urbv(MX2_I2C_INTERRUPT_AND_CTRL);
+
+        mx2_wb(MX2_I2C_OP_CTRL_REG, 0x01);                            // Software mode, output enabled
+
+
+
+        mx2_wb(MX2_I2C_INTERRUPT_AND_CTRL, I2C_OTGXCVRINT_EN | I2C_NOACK_EN | I2C_RWREADY_EN);
+
+        isp1301_configure(vp_vm_bidirectional, spd_susp_pins);
+        isp1301_mod_init();
+
+        THROW_UNLESS(tcd_instance && (otg = tcd_instance->otg), error);
+        THROW_UNLESS(mx2ads_tcd_instance = otg_set_tcd_ops(&tcd_ops), error);
+
+        /* Success!
+         */
+
+        TRACE_MSG0(TCD, "5. Success!");
+
+        otg_init(otg);
+        //otg_start(otg, ocd_ops.capabilities & OCD_CAPABILITIES_AUTO);
+
+        /*
+        if ((ocd_ops.capabilities & OCD_CAPABILITIES_TR) && (ocd_ops.capabilities & OCD_CAPABILITIES_AUTO)) {
+                otg_event_irq(otg, enable_otg, TCD, "enable_otg");
+                otg_event_irq(otg, bus_req, TCD, "bus_req");
+        }
+        */
+
+        CATCH(error) {
+                printk(KERN_INFO"%s: failed\n", __FUNCTION__);
+                return -EINVAL;
+        }
+
+        TRACE_MSG0(TCD, "MX2_MOD_TCD_INIT FINISHED");
+        return 0;
+}
+
+/*! mx2_tcd_mod_exit - de-initialize
+ * This is called from mx2-ocd.c
+ */
+void mx2_tcd_mod_exit (void)
+{
+        struct otg_instance *otg = tcd_instance->otg;
+        TRACE_MSG0(TCD, "MX2_MOD_TCD_EXIT");
+
+        otg_event(otg, enable_otg_, OCD, "enable_otg_");
+        //if (otg)
+        //        otg_exit(otg);
+
+        mx2ads_tcd_instance = otg_set_tcd_ops(NULL);
+
+        i2c_Write_Queued = -1;
+        wake_up_interruptible(&mx2_i2c_wait);                                   // wakeup waiting bottom half handler
+
+        while (PENDING_WORK_ITEM(mx2_i2c_io_work_struct) /*|| PENDING_WORK_ITEM(mx2_i2c_xcvr_work_struct)*/ ) {
+                printk(KERN_ERR"%s: waiting for bh\n", __FUNCTION__);
+                schedule_timeout(10 * HZ);
+        }
+        isp1301_thread_exit(&mx2_i2c_wait);
+        isp1301_mod_exit();
+
+        if (otg)
+                otg_exit(otg);
+}
+
+/* ********************************************************************************************* */
+struct tcd_ops tcd_ops = {
+        id: mx2_id,
+        vbus: mx2_vbus,
+
+        tcd_init_func: mx2_tcd_init,
+        tcd_en_func: NULL,
+        chrg_vbus_func: isp1301_chrg_vbus,
+        drv_vbus_func: isp1301_drv_vbus,
+        dischrg_vbus_func: isp1301_dischrg_vbus,
+        dp_pullup_func: mx2_dp_pullup_func,
+        dm_pullup_func: isp1301_dm_pullup_func,
+
+        overcurrent_func: NULL,
+        dm_det_func: isp1301_dm_det_func,
+        dp_det_func: isp1301_dp_det_func,
+        charge_pump_func: NULL,
+        bdis_acon_func: isp1301_bdis_acon_func,
+        id_pulldown_func: isp1301_id_pulldown_func,
+        audio_func: isp1301_audio_func,
+        uart_func: isp1301_uart_func,
+        mono_func: isp1301_mono_func,
+
+        i2c_int_hndlr: mx2_i2c_int_hndlr,
+        tcd_int_hndlr: mx2_tcd_int_hndlr,
+        mod_init: mx2_tcd_mod_init,
+        mod_exit: mx2_tcd_mod_exit,
+};
+
diff -uNr linux/drivers/no-otg/ocd/otg-hcd/hcd-init-l24.c linux/drivers/otg/ocd/otg-hcd/hcd-init-l24.c
--- linux/drivers/no-otg/ocd/otg-hcd/hcd-init-l24.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/otg-hcd/hcd-init-l24.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,89 @@
+/*
+ * otg/ocd/otg-hcd/hcd-l24-init.c - OTG Host Controller Driver Module Initialization
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcara.com>, 
+ *      Tom Rushworth <tbr@belcara.com>, 
+ *      Bruce Balden <balden@belcara.com>
+ *
+ */
+/*!
+ * @file otg/ocd/otg-hcd/hcd-init-l24.c
+ * @brief 
+ *
+ * This file initializes the low level hardware drivers.
+ *
+ * This is the linux 2.4 version.
+ *
+ * @ingroup OTGHCD
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <otg/otg-compat.h>
+
+#include <otg/otg-compat.h>
+#include <otg/usbp-chap9.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-utils.h>
+#include <otg/otg-hcd.h>
+
+#ifdef MODULE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,4,17)
+MODULE_LICENSE ("GPL");
+#endif
+MODULE_PARM (serial_number_str, "s");
+MODULE_PARM_DESC (serial_number_str, "Serial Number");
+MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
+MODULE_DESCRIPTION ("USB On-The-Go HCD");
+#endif
+char *serial_number_str;
+
+otg_tag_t HCD;
+extern struct hcd_ops hcd_ops;
+struct hcd_instance *hcd_instance;
+
+/* ************************************************************************************* */
+
+/* hcd_modexit - This is *only* used for drivers compiled and used as a module.
+ */
+static void hcd_modexit (void)
+{
+        printk(KERN_INFO"%s\n", __FUNCTION__);
+        if (hcd_ops.mod_exit) hcd_ops.mod_exit();
+        hcd_instance = otg_set_hcd_ops(NULL);
+        otg_trace_invalidate_tag(HCD);
+}
+
+/* otg_modinit - linux module initialization
+ *
+ * This needs to initialize the hcd, pcd and tcd drivers. This includes tcd and possibly hcd
+ * for some architectures.
+ *
+ */
+static int hcd_modinit (void)
+{
+        printk(KERN_INFO"%s\n", __FUNCTION__);
+        HCD = otg_trace_obtain_tag();
+
+        THROW_UNLESS(hcd_instance = otg_set_hcd_ops(&hcd_ops), error);
+        THROW_IF((hcd_ops.mod_init) ? hcd_ops.mod_init() : 0, error);
+
+        CATCH(error) {
+                hcd_modexit();
+                return -EINVAL;
+        }
+        return 0;
+}
+
+module_init (hcd_modinit);
+#ifdef MODULE
+module_exit (hcd_modexit);
+#endif
+
+
+
diff -uNr linux/drivers/no-otg/ocd/otg-hcd/hcd-l26.c linux/drivers/otg/ocd/otg-hcd/hcd-l26.c
--- linux/drivers/no-otg/ocd/otg-hcd/hcd-l26.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/otg-hcd/hcd-l26.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,806 @@
+/*
+ * otg/ocd/otg-hcd/hcd-l26.c - Generic transfer level USBOTG aware Host Controller Driver (HCD)
+ *
+ *      Copyright (c) 2004 Belcarra Technologies
+ *
+ * By:
+ *      Tom Rushworth <tbr@belcara.com>,
+ *      Stuart Lynne <sl@belcara.com>,
+ *      Bruce Balden <balden@belcara.com>
+ *
+ */
+/*!
+ * @file otg/ocd/otg-hcd/hcd-l26.c
+ * @brief Linux Generic Host Controller Driver
+ *
+ * @ingroup OTGHCD
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/usb.h> 
+#include <asm/io.h> 
+
+
+#include <otg/otg-compat.h>
+
+#include "../core/hcd.h"
+
+#include <otg/usbp-chap9.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-hcd.h>
+
+#include <otg/hcd-l26.h>
+#include <otg/hcd-rh.h>
+#include <otg/hcd-hw.h>
+
+int hcd_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+        return 0;
+}
+
+void hcd_disconnect(struct usb_interface *intf)
+{
+}
+
+#define STATIC static
+
+STATIC __inline__ struct urb *grab_active_urb(struct bus_hcpriv *bus_hcpriv, int u)
+{
+        unsigned long flags;
+        struct urb *urb;
+        // Paranoia.
+        RETURN_NULL_UNLESS(bus_hcpriv && bus_hcpriv->active_urbs && (u < bus_hcpriv->max_active_urbs));
+        local_irq_save(flags);
+        urb = bus_hcpriv->active_urbs[u];
+        bus_hcpriv->active_urbs[u] = NULL;
+        local_irq_restore(flags);
+        return urb;
+}
+
+#define OUT(o,e)((o && e) ? 1 : 0)
+
+STATIC void hcd_queue_urb(struct dev_hcpriv *dev_hcpriv, struct urb *urb, int endpoint, int out)
+{
+        unsigned long flags;
+        // Paranoia.
+        RETURN_UNLESS(dev_hcpriv && urb && (endpoint < 16));
+        local_irq_save(flags);
+        dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint] += 1;
+        list_add_tail(&urb->urb_list, &dev_hcpriv->queued_urbs_both[OUT(out, endpoint)][endpoint]);
+        TRACE_MSG4(HCD,"urb: %08x ep: %d n: %u %s", (u32)(void*)urb, 
+                        endpoint, dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint], "IN");
+        local_irq_restore(flags);
+}
+
+STATIC struct urb *hcd_next_urb(struct dev_hcpriv *dev_hcpriv, int endpoint, int out)
+{
+        // MUST BE CALLED in_irq()!!
+        struct urb *urb;
+        struct list_head *epq;
+        // Paranoia.
+        RETURN_NULL_UNLESS(dev_hcpriv && (endpoint < 16));
+        epq = &dev_hcpriv->queued_urbs_both[OUT(out, endpoint)][endpoint];
+        RETURN_NULL_IF(list_empty(epq));
+        urb = list_entry(epq->next, struct urb, urb_list);
+        list_del_init(&urb->urb_list);
+        dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint] -= 1;
+        return urb;
+}
+
+STATIC void hcd_finish_urb(struct urb *urb, int reason)
+{
+        /* Call the upper layer completion routine.  Decrement the ref count
+         * (release our interest in this urb).
+         */
+        urb->status = reason;
+        if (urb->complete) 
+                urb->complete(urb, NULL);
+        usb_put_urb(urb);
+}
+
+STATIC int hcd_submit_to_hw(struct bus_hcpriv *bus_hcpriv, struct urb *urb, int out)
+{
+        // Pass the urb down to the hardware.
+        int rc;
+        void *data;
+        int dev_addr;
+        int endpoint;
+        int format;
+        int len;
+        int pid;
+        int toggle;
+        u32 other;
+        unsigned long flags;
+
+        struct usb_device *dev;
+        struct usb_bus *bus;
+        struct dev_hcpriv *dev_hcpriv;
+        u8 *cp;
+        
+        RETURN_EINVAL_UNLESS((dev = urb->dev));
+        RETURN_EINVAL_UNLESS((bus = dev->bus));
+        RETURN_EINVAL_UNLESS((dev_hcpriv = (struct dev_hcpriv *) (dev->hcpriv)));
+
+        dev_addr = usb_pipedevice(urb->pipe);
+        endpoint = usb_pipeendpoint(urb->pipe);
+
+        TRACE_MSG4(HCD,"urb: %08lx ep: %d %s len: %d", (u32)(void*)urb, endpoint, (out?"OUT":"IN"), urb->actual_length);
+        
+        if (out) {
+#if 0
+                int i;
+                u8 *cp = urb->transfer_buffer;
+
+                TRACE_MSG1(HCD, "NEXT TX: length: %d", urb->actual_length);
+
+                for (i = 0; i < urb->actual_length;  i+= 8)
+
+                        TRACE_MSG8(HCD, "SENT  %02x %02x %02x %02x %02x %02x %02x %02x",
+                                        cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
+                                        cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
+                                  );
+#endif
+        }
+
+        if (usb_endpoint_halted(urb->dev, endpoint, out)) {
+                TRACE_MSG4(HCD,"urb for halted endpoint urb: %08lx dev: %d ep: %d dir: %c", 
+                                urb, dev_addr, endpoint, (out?'O':'I'));
+                urb->actual_length = 0;
+                hcd_finish_urb(urb,-EPIPE);
+                return -EINVAL;
+        }
+
+        data = urb->transfer_buffer;
+        len = urb->transfer_buffer_length;
+        format = usb_pipetype(urb->pipe);
+        other = 0;
+
+        switch (format) {
+        case PIPE_CONTROL:
+                pid = USB_PID_SETUP;
+                // overload toggle with data phase direction (setup is always toggle 0)
+                // toggle == TRUE --> OUT  (HOST2DEVICE --> OUT)
+                
+                toggle = ((((struct usbd_device_request *) urb->setup_packet)->bmRequestType & USB_REQ_DIRECTION_MASK) == 
+                                USB_REQ_HOST2DEVICE);
+
+                other = (u32) (void *) urb->setup_packet;
+
+                // XXX send set feature otg enable IFF set configuration and
+                // to first device and previously otg descriptor was seen.
+                break;
+
+        case PIPE_BULK:
+                pid = (out ? USB_PID_OUT : USB_PID_IN);
+                toggle = usb_gettoggle(urb->dev,endpoint,out);
+                other = (urb->transfer_flags & URB_ZERO_PACKET);
+                break;
+
+        case PIPE_INTERRUPT:
+                pid = (out ? USB_PID_OUT : USB_PID_IN);
+                toggle = usb_gettoggle(urb->dev,endpoint,out);
+                other = urb->interval;
+                break;
+
+        case PIPE_ISOCHRONOUS:
+                pid = (out ? USB_PID_OUT : USB_PID_IN);
+                toggle = 0;
+                other = urb->interval;
+                break;
+
+        default:
+                pid = 0;
+                toggle = 0;
+                break;
+        }
+
+        /* We need an irq lock here in order to make sure the urb gets saved in
+           bus_hcpriv->active_urbs[] before any possible completion interrupt. */
+        local_irq_save(flags);
+        rc = hcd_hw_start_transfer(bus_hcpriv, len, data, toggle, usb_maxpacket(urb->dev, urb->pipe, out),
+                                   (((urb->pipe) >> 26) & 1), endpoint,dev_addr, pid, format,other);
+
+        if (rc >= 0 && rc < bus_hcpriv->max_active_urbs) {
+
+                if (!bus_hcpriv->active_urbs[rc]) 
+                        bus_hcpriv->active_urbs[rc] = urb;
+                 
+                /* Oops, total screw up, we shouldn't ever see this.
+                 * (The lower layer just told us it started a second urb in
+                 * an already busy slot.) 
+                 */
+                else 
+                        TRACE_MSG3(HCD,"ERROR - act: %08x urb: %08x slot: %d",
+                                        (u32)(void*)(bus_hcpriv->active_urbs[rc]), (u32)(void*)urb, rc);
+        }
+        local_irq_restore(flags);
+        if (rc < 0) {
+                // Resubmit is OK...
+                if (rc == -2) {
+                        TRACE_MSG1(HCD,"no ETDs for urb: %08lx",urb);
+                        return 1;
+                }
+
+                // Complete the urb as invalid.
+                urb->actual_length = 0;
+                hcd_finish_urb(urb,-EINVAL);
+                // And signal to try again.
+                return -1;
+        }
+        return 0;
+}
+
+STATIC void hcd_queue_start(struct bus_hcpriv *bus_hcpriv, struct dev_hcpriv *dev_hcpriv, int endpoint, int out)
+{
+        unsigned long flags;
+        struct urb *urb = NULL;
+        int rc;
+
+        TRACE_MSG2(HCD, "endpoint: %2x %s", endpoint, out ? "OUT" : "IN");
+
+        // Paranoia.
+        RETURN_UNLESS(dev_hcpriv && endpoint < 16);
+        do {
+                local_irq_save(flags);
+                if (dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint] == EPQ_RUNNING) {
+                        // There's already an urb for this device/endpoint in the HW, don't start another.
+                        urb = NULL;
+                } 
+                else if (!(urb = hcd_next_urb(dev_hcpriv, endpoint, out))) {
+                        dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint] = EPQ_EMPTY;
+                } 
+                else {
+                        // There is an urb to go, set the state to show the HW is (will be) busy.
+                        dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint] = EPQ_RUNNING;
+                }
+                local_irq_restore(flags);
+                if (!urb) {
+                        // This endpoint is already active in the HW, or doesn't need to be.
+                        rc = 0;
+                } 
+                else {
+                        // Try to pass the urb down to the HW.
+                        rc =  hcd_submit_to_hw(bus_hcpriv, urb, out);
+                }
+        } while (rc < 0);
+        if (rc > 0) {
+                // We've run out of HW resources, try again later.
+                local_irq_save(flags);
+                list_add(&urb->urb_list, &dev_hcpriv->queued_urbs_both[OUT(out, endpoint)][endpoint]);
+                dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint] += 1;
+                dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint] = EPQ_WAITING;
+                TRACE_MSG3(HCD,"urb: %08x ep: %d n: %u WAITING IN", 
+                                (u32)(void*)urb, endpoint, dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint]);
+                local_irq_restore(flags);
+                /* There should be no need to queue a task to try later, as the HW
+                 * should have lots of pending urbs, and urb completion will lead
+                 * to a search for new work.  There is a small chance that _all_ the
+                 * pending urbs will complete between the call to hcd_submit_to_hw(),
+                 * but it's unlikely. 
+                 */
+        }
+}
+
+
+/* ********************************************************************************************** */
+/* Functions provided to the HW dependent layer (below this one).
+ */
+void hcd_transfer_complete(struct bus_hcpriv *bus_hcpriv, int transfer_id, int format, int cc, u32 remaining, int next_toggle)
+{
+        struct urb *urb = grab_active_urb(bus_hcpriv, transfer_id);
+        struct usb_device *dev;
+        struct usb_bus *bus;
+        struct dev_hcpriv *dev_hcpriv;
+        int out;
+
+        int endpoint;
+        u8 *cp;
+
+        UNLESS (urb) {
+                TRACE_MSG1(HCD,"active_urb[%d] NULL",transfer_id);
+                return;
+        }
+
+        RETURN_UNLESS((dev = urb->dev));
+        RETURN_UNLESS((bus = dev->bus));
+        RETURN_UNLESS((dev_hcpriv = (struct dev_hcpriv *) (dev->hcpriv)));
+
+        out = usb_pipeout(urb->pipe);
+
+        TRACE_MSG5(HCD,"id: %d status: %d tlen: %d rem: %d buffer: %p", 
+                        transfer_id, cc, urb->transfer_buffer_length, remaining, urb->transfer_buffer);
+        //if (out) 
+        if (urb->transfer_buffer) {
+#if 0
+                int i;
+                u8 *cp = urb->transfer_buffer;
+
+                TRACE_MSG1(HCD, "NEXT TX: length: %d", urb->actual_length);
+
+                for (i = 0; i < urb->actual_length;  i+= 8)
+
+                        TRACE_MSG8(HCD, "RECV  %02x %02x %02x %02x %02x %02x %02x %02x",
+                                        cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
+                                        cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
+                                  );
+#endif
+        }
+
+        if (-ENOENT == cc) {
+                // Cancelled.
+                urb->actual_length = 0;
+        } 
+        else {
+                switch (format) {
+                case PIPE_CONTROL:
+                        urb->actual_length = urb->transfer_buffer_length - remaining;
+
+                        if ((cp = urb->setup_packet))
+                                TRACE_MSG8(HCD, "SETUP  %02x %02x %02x %02x %02x %02x %02x %02x",
+                                                cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+
+                        if ((dev == bus_hcpriv->first_dev) && !cc && urb->setup_packet) {
+                                struct usb_ctrlrequest *request = (struct usb_ctrlrequest*) urb->setup_packet;
+                                switch (request->bRequest) {
+                                case USB_REQ_SET_ADDRESS:
+                                        otg_event(hcd_instance->otg, ADDRESSED, HCD, "HCD COMPLETE ADDRESSED");
+                                        break;
+                                case USB_REQ_SET_CONFIGURATION:
+                                        otg_event(hcd_instance->otg, CONFIGURED, HCD, "HCD COMPLETE CONFIGURED");
+                                        break;
+                                // XXX check for GET_CONFIGURATION and otg descriptor here
+                                }
+                        }
+                        break;
+
+                case PIPE_BULK:
+                case PIPE_INTERRUPT:
+                        if (0 == cc) {
+                                // QQSV needed for BULK, what about interrupt? 
+                                TRACE_MSG4(HCD,"dev: %d ep: %d dir: %d TOGGLE: %d",urb->dev->devnum,
+                                                              usb_pipeendpoint(urb->pipe),usb_pipeout(urb->pipe),next_toggle);
+                                usb_settoggle(urb->dev,usb_pipeendpoint(urb->pipe),usb_pipeout(urb->pipe),next_toggle);
+                        }
+                        urb->actual_length = urb->transfer_buffer_length - remaining;
+                        //hcd_trace_mem(HCD,__FUNCTION__,"BULK/INTERRUPT urb",urb->actual_length,urb->transfer_buffer);
+                        break;
+
+                case PIPE_ISOCHRONOUS:
+                        urb->actual_length = urb->transfer_buffer_length - remaining;  // QQSV
+                        break;
+
+                default: // Paranoia.
+                        urb->actual_length = 0;
+                        break;
+                }
+        }
+        endpoint = usb_pipeendpoint(urb->pipe);
+        hcd_finish_urb(urb, cc);
+
+        // Start the next urb in the queue for this device/endpoint.
+                dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint] = EPQ_WAITING;
+
+        TRACE_MSG2(HCD,"queue_start  ep: %d %s >>>", endpoint, out ? "OUT" : "IN");
+        hcd_queue_start(bus_hcpriv, dev_hcpriv, endpoint, out);
+
+        //TRACE_MSG1(HCD,"queue_start  ep: %d <<<",endpoint);
+        // FIXME - in the future, need to kick off a BH to search other EPs/devs for waiting urbs
+        // if (dev_hcpriv->epq_state[endpoint] == EPQ_EMPTY) {
+        //          /* This queue is empty, so its HW resources are now available,
+        //             kick off BH to search for other EP's and other devs that are waiting. */
+        //          _________
+        // }
+}
+
+/* ********************************************************************************************** */
+/* Functions provided to the USB core layer (above this one).
+ */
+
+/* Allocate space for some USB function plugged into this HC or any hub below it.
+ * Return 0 on success, error code (e.g. -ENOMEM) on failure. 
+ */
+STATIC int hcd_allocate(struct usb_device *dev)
+{
+        struct usb_bus *bus;
+        struct bus_hcpriv *bus_hcpriv;
+        struct dev_hcpriv *dev_hcpriv;
+        int endpoint;
+
+        TRACE_MSG1(HCD,"entered devnum: %d", dev->devnum);
+
+        RETURN_ENOMEM_UNLESS((bus = dev->bus));
+        RETURN_ENOMEM_UNLESS((bus_hcpriv = (struct bus_hcpriv *) bus->hcpriv));
+
+        RETURN_ENOMEM_UNLESS(dev_hcpriv = (struct dev_hcpriv *) kmalloc(sizeof(struct dev_hcpriv), GFP_KERNEL));
+
+        memset(dev_hcpriv, 0, sizeof(struct dev_hcpriv));
+        for (endpoint = 0; endpoint < 16; endpoint++) {
+                INIT_LIST_HEAD(&dev_hcpriv->queued_urbs_both[0][endpoint]);
+                INIT_LIST_HEAD(&dev_hcpriv->queued_urbs_both[1][endpoint]);
+        }
+
+        dev->hcpriv = dev_hcpriv;
+        dev_hcpriv->dev = dev;
+
+        UNLESS (bus_hcpriv->roothub_dev) 
+                bus_hcpriv->roothub_dev = dev;
+        
+        else UNLESS (bus_hcpriv->first_dev) 
+                bus_hcpriv->first_dev = dev;
+
+        return 0;
+}
+
+
+STATIC int hcd_deallocate(struct usb_device *dev)
+{
+        struct usb_bus *bus = dev->bus;
+        struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *) bus->hcpriv;
+        struct dev_hcpriv *dev_hcpriv;
+
+        if (dev == bus_hcpriv->first_dev) 
+                bus_hcpriv->first_dev = NULL;
+        
+        if (dev == bus_hcpriv->roothub_dev) 
+                bus_hcpriv->roothub_dev = NULL;
+
+        if ((dev_hcpriv = (struct dev_hcpriv *) (dev->hcpriv))) {
+                dev_hcpriv->dev = NULL;
+                kfree(dev_hcpriv);
+                dev->hcpriv = NULL;
+        }
+        return 0;
+}
+
+
+STATIC void *hcd_buffer_alloc(struct usb_bus *usb_bus, size_t size, int mem_flags, dma_addr_t *dma)
+{
+        return consistent_alloc(0, size, dma);
+}
+
+STATIC void hcd_buffer_free(struct usb_bus *usb_bus, size_t size, void *addr, dma_addr_t dma)
+{
+        RETURN_UNLESS(addr);
+        consistent_free(addr,size,dma);
+}
+
+STATIC int frame_number(struct usb_device *usb_dev)
+{
+        u32 n = hcd_hw_frame_number((struct bus_hcpriv *)(usb_dev->bus->hcpriv));
+        TRACE_MSG1(HCD,"-->: %08lx",n);
+        return n;
+}
+
+STATIC int submit_urb(struct urb *urb, int mem_flags)
+{
+        struct bus_hcpriv *bus_hcpriv;
+        struct dev_hcpriv *dev_hcpriv;
+        int dev_addr;
+        int endpoint;
+        int out;
+
+        RETURN_EINVAL_UNLESS (urb && urb->dev && urb->dev->bus);
+        RETURN_EINVAL_UNLESS ((bus_hcpriv = (struct bus_hcpriv *) (urb->dev->bus->hcpriv)));
+        RETURN_EINVAL_UNLESS ((dev_hcpriv = (struct dev_hcpriv *) (urb->dev->hcpriv)));
+        RETURN_EINVAL_IF (bus_hcpriv->terminating);
+
+        dev_addr = usb_pipedevice(urb->pipe);
+        endpoint = usb_pipeendpoint(urb->pipe);
+        out = usb_pipeout(urb->pipe);
+
+        RETURN_EPIPE_IF (usb_endpoint_halted(urb->dev, endpoint, out));
+
+        /* Divert to root hub if appropriate, (note: NO ref count change).
+         */
+        if (urb->dev == bus_hcpriv->roothub_dev) {
+                TRACE_MSG4(HCD,"root hub --> urb: %08lx dev: %d ep: %d dir: %s", urb, dev_addr, endpoint, (out ? "OUT" : "IN"));
+                return hcd_rh_submit_urb(bus_hcpriv, urb, mem_flags);
+        }
+
+        /* Increase ref count so we own a piece of the URB.  Queue the urb,
+         * then make sure the queue is running.
+         */
+        TRACE_MSG4(HCD,"device --> urb: %08lx dev: %d ep: %d dir: %S", urb, dev_addr, endpoint, (out ? "OUT" : "IN"));
+        hcd_queue_urb(dev_hcpriv, usb_get_urb(urb), endpoint, out);
+        hcd_queue_start(bus_hcpriv, dev_hcpriv, endpoint, out);
+        return 0;
+}
+
+STATIC int unlink_urb(struct urb *urb)
+{
+        int u;
+        unsigned long flags;
+        struct bus_hcpriv *bus_hcpriv = NULL;
+        struct dev_hcpriv *dev_hcpriv = NULL;
+        int dev_addr;
+        int endpoint;
+        struct list_head *epq;
+        int out;
+        
+        RETURN_EINVAL_UNLESS (urb && urb->dev && urb->dev->bus);
+        RETURN_EINVAL_UNLESS ((dev_hcpriv = (struct dev_hcpriv *) (urb->dev->hcpriv)));
+        RETURN_EINVAL_UNLESS ((bus_hcpriv = (struct bus_hcpriv *) (urb->dev->bus->hcpriv)));
+
+        out = usb_pipeout(urb->pipe);
+        
+        dev_addr = usb_pipedevice(urb->pipe);
+
+        /* Does it belong to the root hub?
+         */
+        if (urb->dev == bus_hcpriv->roothub_dev) {
+                TRACE_MSG1(HCD,"root hub --> urb: %08lx",urb);
+                return hcd_rh_unlink_urb(bus_hcpriv,urb);
+        }
+
+        /* Look to see if it is in a device/endpoint queue.
+         */
+        endpoint = usb_pipeendpoint(urb->pipe);
+
+        epq = &dev_hcpriv->queued_urbs_both[OUT(out, endpoint)][endpoint];
+
+        /* Searching a list while in_irq - yuck.  For the time being,
+         * this just assumes that the list is short.  In the future,
+         * it may be possible to keep a small amount of state in the
+         * urb itself to indicate if it is in this list, so that all
+         * we need to do in_irq is check the state and delete from the
+         * list if the state indicates we should.  The state info will
+         * only needed while this HC "owns" the urb. 
+         */
+        local_irq_save(flags);
+
+        if (EPQ_EMPTY != dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint]) {
+                // There are queued urbs, search to see if this is one of them.
+                struct urb *qe;
+                list_for_each_entry(qe, epq, urb_list) {
+                        if (qe == urb) {
+                                // Found it.  It hasn't been sent to the HW yet, so it can be finished here.
+                                list_del_init(&urb->urb_list);
+                                dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint] -= 1;
+                                if (list_empty(epq)) 
+                                        dev_hcpriv->epq_state_both[OUT(out, endpoint)][endpoint] = EPQ_EMPTY;
+
+                                TRACE_MSG3(HCD,"urb: %08x ep: %d n: %u UNLINKED IN",
+                                                (u32)(void*)urb, endpoint, 
+                                                dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint]);
+                                hcd_finish_urb(urb,-ENOENT);
+                                local_irq_restore(flags);
+                                return 0;
+                        }
+                }
+        }
+
+        local_irq_restore(flags);
+
+        /* Look to see if this is one of the active urbs.
+         */
+        if (bus_hcpriv->active_urbs) {
+
+                for (u = 0; u < bus_hcpriv->max_active_urbs; u++) {
+                        local_irq_save(flags);
+                        /* This is the one we want, unlink from the HW.
+                         * HW layer does the completion through hcd_transfer_complete()
+                         * in this file, which releases bus_hcpriv->active_urbs[u]. 
+                         */
+                        if (urb == bus_hcpriv->active_urbs[u]) {
+                                int out;
+                                out = usb_pipeout(urb->pipe);
+                                u = hcd_hw_unlink_urb(bus_hcpriv, u);
+
+                                TRACE_MSG4(HCD,"urb: %08x ep: %d n: %u UNLINKED from HW %s", (u32)(void*)urb, endpoint, 
+                                                dev_hcpriv->num_urbs_both[OUT(out, endpoint)][endpoint], out ? "OUT" : "IN");
+
+                                local_irq_restore(flags);
+                                // FUTURE - think about starting a search for new work for the released HW slot.
+                                return u;
+                        }
+                        local_irq_restore(flags);
+                }
+        }
+        // The urb isn't ours, or completed while we were looking for it.
+        TRACE_MSG1(HCD,"Already completed, or someone else's urb: %08lx", urb);
+        return -EINVAL;
+}
+
+/* ********************************************************************************************** */
+
+// void disable(struct usb_device *dev, int bEndpointAddress);
+
+static struct usb_operations operations = {
+        .allocate          = hcd_allocate,
+        .deallocate        = hcd_deallocate,
+        .get_frame_number  = frame_number,
+        .submit_urb        = submit_urb,
+        .unlink_urb        = unlink_urb,
+        .buffer_alloc      = hcd_buffer_alloc, /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */
+        .buffer_free       = hcd_buffer_free,
+        .disable           = NULL
+};
+
+
+/* ********************************************************************************************** */
+
+/* Called as a "bottom-half" to do usbcore registration once all the HW is usable.
+ */
+STATIC void hcd_bh_init(void *arg)
+{
+        struct hcd_instance *hcd = (struct hcd_instance *) arg;
+        otg_event(hcd->otg, HCD_OK, HCD, "HCD_INIT SET HCD_OK");
+        TRACE_MSG0(HCD,"finished");
+}
+
+STATIC void hcd_bh_exit(void *arg)
+{
+        struct hcd_instance *hcd = (struct hcd_instance *) arg;
+        otg_event(hcd->otg, HCD_OK, HCD, "HCD_INIT RESET (EXIT) HCD_OK");
+}
+
+
+/*! hcd_init_func - per host controller common initialization
+ *
+ * This is called to initialize / de-initialize the HCD, all except the last
+ * stage of registering the root hub, because that needs to wait until rh_hcd_en_func()
+ *
+ * We start work items to do this.
+ *
+ */
+void hcd_init_func (struct otg_instance *otg, u8 flag)
+{
+        struct hcd_instance *hcd = otg->hcd;
+
+        switch (flag) {
+        case SET:
+                // Schedule BH for hcd_bh_init...
+                TRACE_MSG0(HCD, "HCD_INIT: SET");
+                PREPARE_WORK_ITEM(hcd->bh, hcd_bh_init, hcd);
+                SCHEDULE_WORK(hcd->bh);
+                TRACE_MSG0(HCD, "hcd_bh_init() schedule finished");
+                break;
+
+        case RESET:
+                TRACE_MSG0(HCD, "HCD_INIT: RESET");
+                PREPARE_WORK_ITEM(hcd->bh, hcd_bh_exit, hcd);
+                SCHEDULE_WORK(hcd->bh);
+                break;
+        }
+}
+
+
+/* ********************************************************************************************** */
+
+STATIC void release_hw_rh(struct bus_hcpriv *bus_hcpriv)
+{
+        RETURN_UNLESS (bus_hcpriv);
+
+        hcd_rh_exit(bus_hcpriv);
+
+        // Complete (cancel) any active urbs.
+        if (bus_hcpriv->active_urbs) {
+                int u;
+                for (u = 0; u < bus_hcpriv->max_active_urbs; u++) {
+                        struct urb *urb;
+                        if ((urb = grab_active_urb(bus_hcpriv,u))) {
+                                urb->actual_length = 0;
+                                hcd_finish_urb(urb,-ENOENT); // USB_ST_URB_KILLED
+                        }
+                }
+        }
+
+        // Release any resources from the layer above.
+        if (bus_hcpriv->usb_bus) {
+                usb_deregister_bus(bus_hcpriv->usb_bus);
+                bus_hcpriv->usb_bus = NULL;
+        }
+
+        // Lastly, release this layer's info.
+        if (bus_hcpriv->active_urbs) {
+                kfree(bus_hcpriv->active_urbs);
+                bus_hcpriv->active_urbs = NULL;
+        }
+}
+
+/* ********************************************************************************************** */
+/*
+ * Note that initialization and cleanup happen in two stages:
+ * 1. Allocation of the basic struct bus_hcpriv, the first level of LDM/USB driver registration, and OTG operations
+ * 2. Everything else - completion of data allocation, USBcore registration, HC HW init, root hub enumeration - when
+ *    called back by OTG (after any magic required to access the HCD hardware.)
+ * Only stage 1 is done on module entry.
+ */
+
+int __init hcd_init(struct bus_hcpriv *bus_hcpriv, struct usb_driver *usb_driver)
+{
+        struct usb_bus *usb_bus = NULL;
+        int usb_registered = 0;
+        int device_registered = 0;
+        int bus_registered = 0;
+        int rc = 0;
+        struct urb **active_urbs = NULL;
+
+        /* fixup bus_hcpriv structure
+         */
+        bus_hcpriv->usb_driver = usb_driver;
+        bus_hcpriv->bus_device.driver = &usb_driver->driver;
+        bus_hcpriv->max_active_urbs = bus_hcpriv->max_active_transfers;
+        usb_driver->probe = hcd_probe;
+
+        UNLESS (hcd_ops.hcd_init_func) hcd_ops.hcd_init_func = hcd_init_func;
+
+        /* allocate urb array 
+         */
+        THROW_UNLESS ((active_urbs = (struct urb **) kmalloc(bus_hcpriv->max_active_urbs*sizeof(struct urb *),GFP_KERNEL)), 
+                        error);
+
+        bus_hcpriv->active_urbs = active_urbs;
+        memset(bus_hcpriv->active_urbs,0,bus_hcpriv->max_active_urbs*sizeof(struct urb *));
+        TRACE_MSG1(HCD,"active_urbs ok, max active URBs: %d",bus_hcpriv->max_active_urbs);
+
+        /* register with usb core
+         */
+        THROW_UNLESS(usb_registered = usb_register(usb_driver) ? 0 : 1, error);
+        TRACE_MSG0(HCD,"usb_register ok");
+
+        /* We need a bus before we can initialize the root hub.
+         */
+        THROW_UNLESS ((usb_bus = usb_alloc_bus(&operations)), error);
+        bus_hcpriv->usb_bus = usb_bus; 
+        TRACE_MSG0(HCD,"usb bus allocated");
+
+        /* register bus
+         */
+        snprintf(bus_hcpriv->bus_device.bus_id, BUS_ID_SIZE, "bus_hcpriv%d", usb_bus->busnum);
+        snprintf(bus_hcpriv->bus_device.name, DEVICE_NAME_SIZE,"%s%d", bus_hcpriv->usb_driver->name, usb_bus->busnum); 
+        usb_bus->hcpriv = (void *) bus_hcpriv;
+        usb_bus->controller = &bus_hcpriv->bus_device;
+        THROW_UNLESS ((bus_registered = usb_register_bus(usb_bus)) ? 0 : 1, error);
+        TRACE_MSG0(HCD,"usb bus registered");
+
+        /* All set for the host controller, initialize the virtual root hub.
+         */
+        THROW_IF (hcd_rh_init(bus_hcpriv), error);
+        TRACE_MSG0(HCD,"root hub initialized");
+
+        /* register device
+         */
+        //THROW_IF ((device_registered = device_register(&bus_hcpriv->bus_device) ? 0 : 1), error);
+        if (device_register(&bus_hcpriv->bus_device)) {
+                printk(KERN_ERR"%s: device_register not ok\n", __FUNCTION__);
+        }
+        
+        /* Everybody's ready, enable the interrupts.
+         */
+        
+        /* Kick off the root hub.
+         */
+        THROW_IF ((rc = usb_register_root_hub(bus_hcpriv->rh_hcpriv->dev, &(bus_hcpriv->bus_device))), error); 
+
+        return 0;
+
+        CATCH(error) {
+
+                if (device_registered) device_unregister(&bus_hcpriv->bus_device);
+                if (usb_bus) {
+                        if (bus_registered && usb_bus) usb_deregister_bus(usb_bus);
+                        kfree(usb_bus);
+                }
+                if (usb_registered) usb_deregister(usb_driver);
+                if (active_urbs) kfree(active_urbs);
+                return -EINVAL;
+        }
+}
+
+#ifdef MODULE
+void hcd_exit(struct bus_hcpriv *bus_hcpriv, struct usb_driver *usb_driver)
+{
+        release_hw_rh(bus_hcpriv);
+
+        usb_deregister_bus(bus_hcpriv->usb_bus);
+        device_unregister(&bus_hcpriv->bus_device);
+        usb_deregister(usb_driver);
+}
+#endif
+
diff -uNr linux/drivers/no-otg/ocd/otg-hcd/hcd-rh.c linux/drivers/otg/ocd/otg-hcd/hcd-rh.c
--- linux/drivers/no-otg/ocd/otg-hcd/hcd-rh.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/otg-hcd/hcd-rh.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,1068 @@
+/*
+ * otg/ocd/otg-hcd/hcd-rh.c - Generic transfer level USBOTG aware
+ *                        virtual root hub _FUNCTION_ driver.
+ *
+ *      Copyright (c) 2004 Belcarra Technologies
+ *
+ * By:
+ *      Tom Rushworth <tbr@belcara.com>,
+ *      Stuart Lynne <sl@belcara.com>,
+ *      Bruce Balden <balden@belcara.com>
+ */
+/*!
+ * @file otg/ocd/otg-hcd/hcd-rh.c
+ * @brief Root Hub for Generic Host Controller Driver
+ *
+ *
+ *
+ * @ingroup OTGHCD
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/usb.h>
+
+#include <otg/otg-compat.h>
+#include "../core/hcd.h"
+
+#include <otg/usbp-chap9.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-utils.h>
+#include <otg/otg-hcd.h>
+
+#include <otg/hcd-l26.h>
+#include <otg/hcd-rh.h>
+#include <otg/hcd-hw.h>
+
+#define STATIC static
+
+/* NOTE: This code assumes the root hub has < 8 ports.  If it has
+         more some of the descriptors and other structures will have to
+         be re-sized. */
+
+STATIC u8 prepare_str(char *ascii, u8 *str, int str_size)
+{
+        int c;
+        u8 *up = str;
+        u8 *ep = (up + str_size) - 1;
+        while ((c = *ascii++) && up < ep) {
+                *up++ = (c & 0x7F);
+                *up++ = 0;
+        }
+        return (u8)(up - str);
+}
+
+STATIC int hcd_rh_string(struct bus_hcpriv *bus_hcpriv, int strno, u8 *buff, int buff_len)
+{
+        // Provide default strings, but let the HW component override them.
+        char *str;
+        switch (strno) {
+        case 0: // Language ID
+                *buff++ = 4;
+                *buff++ = USB_DT_STRING;
+                *buff++ = 0;
+                *buff++ = 0;
+                return 4;
+        case XHC_RH_STRING_CONFIGURATION:
+                str = "Root hub";
+                break;
+        case XHC_RH_STRING_INTERFACE:
+                str = "Root hub - Status";
+                break;
+        case XHC_RH_STRING_SERIAL:
+                str = bus_hcpriv->rh_serial ? bus_hcpriv->rh_serial : "000001";
+                break;
+        case XHC_RH_STRING_PRODUCT:
+                str = bus_hcpriv->rh_product ? bus_hcpriv->rh_product : "Virtual Root Hub";
+                break;
+        case XHC_RH_STRING_MANUFACTURER:
+                str = bus_hcpriv->rh_manufacturer ? bus_hcpriv->rh_manufacturer : "Belcarra Technologies";
+                break;
+        default:
+                str = "????";
+        }
+
+        buff[0] = 2 + prepare_str(str,buff+2,buff_len-2);
+        buff[1] = USB_DT_STRING;
+        return buff[0];
+}
+
+
+/* ********************************************************************************************** */
+
+
+static char *hub_feature_name[] = {
+        "C_HUB_LOCAL_POWER",
+        "C_HUB_OVER_POWER",
+};
+
+STATIC void hcd_rh_hub_feature(struct bus_hcpriv *bus_hcpriv, u16 wValue, int set_flag)
+{
+        unsigned long flags;
+        TRACE_MSG3(HCD,"%s feature %d %s",(set_flag?"SET":"CLR"), wValue, hub_feature_name[wValue]);
+        local_irq_save(flags);
+        if (set_flag) {
+                // SET feature USB2.0 11.24.2.12 pg 434 and USB2.0 11.24.2 tbl 11-17 pg 421
+                // R1: sec 23.11.29 pg 23-62
+                switch (wValue) {
+                // case C_HUB_OVER_CURRENT: ____ FIXME ----
+                // case C_HUB_LOCAL_POWER: ____ FIXME ----
+                default:
+                        // Error, but ignore.
+                        TRACE_MSG1(HCD,"SET invalid FEATURE %d", wValue);
+                        break;
+                }
+        } 
+        else {
+                // CLEAR feature USB2.0 11.24.2.1 pg 422 and USB2.0 11.24.2 tbl 11-17 pg 421
+                // R1: sec 23.11.29 pg 23-62
+                switch (wValue) {
+                case C_HUB_OVER_CURRENT:
+                        bus_hcpriv->rh_hcpriv->hub_change_status &= ~(1 << wValue);
+                        TRACE_MSG1(HCD,"CLR C_HUB_OVER_CURRENT hub_change_status: %08x", bus_hcpriv->rh_hcpriv->hub_change_status);
+                        break;
+                // case C_HUB_LOCAL_POWER: ____ FIXME ----
+                default:
+                        // Error, but ignore.
+                        TRACE_MSG1(HCD,"CLR invalid FEATURE %d", wValue);
+                        break;
+                }
+        }
+        local_irq_restore(flags);
+        hcd_hw_rh_hub_feature(bus_hcpriv, wValue, set_flag);
+}
+
+/* ********************************************************************************************** */
+
+char *port_feature_name[] = {
+        "PORT_CONNECTION",     "PORT_ENABLE",         "PORT_SUSPEND",        "FEATURE 0x03",        
+        "PORT_RESET",          "FEATURE 0x05",        "FEATURE 0x06",        "FEATURE 0x07",        
+        "PORT_POWER",          "PORT_LOW_SPEED",      "FEATURE 0x0a",        "FEATURE 0x0b",        
+        "FEATURE 0x0c",        "FEATURE 0x0d",        "FEATURE 0x0e",        "FEATURE 0x0f",        
+        "C_PORT_CONNECTION",   "C_PORT_ENABLE",       "C_PORT_SUSPEND",      "C_PORT_OVER_CURRENT", 
+        "C_PORT_RESET",        "PORT_TEST",           
+};
+
+void check_port_status_(int feature, u32 change_status, u32 hw_change_status)
+{
+        int mask = (1 << feature);
+        if ((change_status & mask) != (hw_change_status & mask))
+                TRACE_MSG4(HCD, "%-20s %2d %6s %6s MISMATCH",  port_feature_name[feature], feature,
+                                change_status & mask ? "SET" : "RESET", hw_change_status & mask ? "SET" : "RESET" );
+}
+
+void check_port_status(struct bus_hcpriv *bus_hcpriv, u16 wIndex, char *msg)
+{
+        struct rh_hcpriv *rh_hcpriv = bus_hcpriv->rh_hcpriv;
+        u32 change_status = ((wIndex -1) < bus_hcpriv->num_ports) ?  bus_hcpriv->rh_hcpriv->port_change_status[wIndex-1] : 0;
+        u32 hw_change_status = hcd_hw_rh_get_port_change_status(bus_hcpriv, wIndex);
+
+        TRACE_MSG4(HCD,"PORT_STATUS[%2d] %08x %08x %s", wIndex, 
+                        change_status, hcd_hw_rh_get_port_change_status(bus_hcpriv, wIndex), msg);
+
+        UNLESS(rh_hcpriv->suspended) {
+                // XXX
+        }
+
+        check_port_status_(PORT_CONNECTION, change_status, hw_change_status); 
+        check_port_status_(PORT_ENABLE, change_status, hw_change_status); 
+        check_port_status_(PORT_RESET, change_status, hw_change_status); 
+        check_port_status_(PORT_POWER, change_status, hw_change_status);
+        check_port_status_(C_PORT_CONNECTION, change_status, hw_change_status); 
+        check_port_status_(C_PORT_ENABLE, change_status, hw_change_status); 
+        check_port_status_(C_PORT_RESET, change_status, hw_change_status); 
+}
+/* ********************************************************************************************** */
+/*
+ * wIndex is port number (1-N)
+ * wValue is feature selector
+ */
+STATIC void hcd_rh_port_feature(struct bus_hcpriv *bus_hcpriv, u16 wValue, u16 wIndex, int set_flag)
+{
+        TRACE_MSG4(HCD,"%s port %d FEATURE %02x %s", (set_flag?"SET":"CLR"),  wIndex, 
+                        wValue, port_feature_name[wValue]);
+        /* Not a valid port number
+         */
+        if (wIndex > bus_hcpriv->num_ports) {
+                TRACE_MSG1(HCD, "invalid port: %d", wIndex);
+                return;
+        }
+        /* Feature selector is wValue
+         * wIndex is 1-origin
+         */
+        TRACE_MSG2(HCD, "port_change_status[%d]: -> %08x", wIndex, bus_hcpriv->rh_hcpriv->port_change_status[wIndex -1]);
+        if (set_flag) {
+                // SET feature
+                switch (wValue) {
+                case PORT_SUSPEND:
+                case PORT_RESET:
+                case PORT_POWER:
+                        bus_hcpriv->rh_hcpriv->port_change_status[wIndex - 1] |= (1 << wValue);
+                        break;
+                }
+        } 
+        else {
+                // CLEAR feature (valid features from USB2.0 11.24.2.2 pg 423).
+                switch (wValue) {
+                case PORT_ENABLE: // Disable port.
+                case PORT_SUSPEND: // Cause a Host initiated resume, or no-op if already active.
+                case PORT_POWER: // Put port in powered-off state.
+                case C_PORT_CONNECTION: // clear the PORT_CONNECTION change bit
+                case C_PORT_RESET: // clear the PORT_RESET change bit
+                case C_PORT_ENABLE: // clear the PORT_ENABLE change bit
+                case C_PORT_SUSPEND: // clear the PORT_SUSPEND change bit
+                case C_PORT_OVER_CURRENT: // clear the PORT_OVERCURRENT change bit
+                        bus_hcpriv->rh_hcpriv->port_change_status[wIndex - 1] &= ~(1 << wValue);
+                        break;
+                }
+        }
+        /* update hardware?
+         */
+
+        RETURN_UNLESS (wIndex == bus_hcpriv->otg_port);
+        RETURN_IF (bus_hcpriv->rh_hcpriv->otg_device_mask & (1 << wIndex));
+
+        hcd_hw_rh_port_feature(bus_hcpriv, wValue, wIndex, set_flag);
+
+        TRACE_MSG4(HCD, "OTG Port wValue: %x wIndex: %d %d set: %d", wValue, wIndex, bus_hcpriv->otg_port, set_flag);
+        if (set_flag) {
+                // SET feature
+                switch (wValue) {
+                case PORT_RESET:
+                        TRACE_MSG0(HCD, "OTG Port - HUB_PORT_ENABLED - PORT_RESET");
+                        //otg_event(bus_hcpriv->hcd->otg, HUB_PORT_ENABLED, HCD, "Hub Port Enable (PORT_RESET)");
+                        otg_event(hcd_instance->otg, BUS_RESET, HCD, "PORT_RESET (SET Feature)");
+                        break;
+                case PORT_SUSPEND:
+                case PORT_POWER:
+                        break;
+                }
+                check_port_status(bus_hcpriv, wIndex, "PORT SET");
+        } 
+        else {
+                // CLEAR feature (valid features from USB2.0 11.24.2.2 pg 423).
+                switch (wValue) {
+                case C_PORT_CONNECTION: // clear the PORT_CONNECTION change bit
+                        TRACE_MSG0(HCD, "OTG Port - HUB_PORT_ENABLED/ - C_PORT_CONNECTION");
+                        break;
+                case C_PORT_ENABLE: // clear the PORT_ENABLE change bit
+                        TRACE_MSG0(HCD, "OTG Port - HUB_PORT_ENABLED/ - C_PORT_ENABLE");
+                        break;
+                case PORT_ENABLE: // Disable port.
+                case PORT_SUSPEND: // Cause a Host initiated resume, or no-op if already active.
+                case PORT_POWER: // Put port in powered-off state.
+                case C_PORT_RESET: // clear the PORT_RESET change bit
+                case C_PORT_SUSPEND: // clear the PORT_SUSPEND change bit
+                case C_PORT_OVER_CURRENT: // clear the PORT_OVERCURRENT change bit
+                        break;
+                }
+                check_port_status(bus_hcpriv, wIndex, "PORT CLR");
+        }
+}
+
+/* ********************************************************************************************** */
+/*
+ * Functions for periodic response to the INT URB.
+ * Note that the USB2.0 spec says (sec 11.12.2 pg 337) that a hub controller
+ * will respond to an INT poll as long as the change bits remain set.  This
+ * means we have to record them and continue responding periodically (hence
+ * the timer) until the class driver clears them.
+ *
+ */
+
+void hcd_rh_urb_complete(struct bus_hcpriv *bus_hcpriv, struct urb *urb)
+{       
+        // Almost not needed (vrh could do this directly), except for tracing.
+        TRACE_MSG1(HCD,"urb %p",urb);
+        
+        /* Call the upper layer completion routine.
+         */
+        if (urb->complete)  
+                urb->complete(urb,NULL);
+                        
+        // XXX should we do this here
+        // usb_put_urb(int_urb);
+}                               
+/* ********************************************************************************************** */
+/*
+ * Some sort of change may have happened on the root hub or one of the ports,
+ * scan for changes in the shadow data, and notify usbcore if there is an
+ * INT URB available to do so with.
+ */
+STATIC void hcd_rh_portstatus_bh(void *data)
+{
+        struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *) data;
+        struct rh_hcpriv *rh_hcpriv = bus_hcpriv->rh_hcpriv;
+        u8 change_data;
+        struct urb *int_urb;
+
+        u32 hub_port_change_status;
+        unsigned long flags;
+
+        TRACE_MSG1(HCD, "suspended: %d", rh_hcpriv->suspended);
+        RETURN_IF(rh_hcpriv->suspended);
+
+        //printk(KERN_INFO"%s:\n", __FUNCTION__);
+        
+        local_irq_save(flags);
+        hub_port_change_status = bus_hcpriv->rh_hcpriv->hub_port_change_status;
+        bus_hcpriv->rh_hcpriv->hub_port_change_status = 0;
+        local_irq_restore(flags);
+
+
+        change_data = (u8) hub_port_change_status & 0xff;
+        //change_data ~= ~bus_hcpriv->rh_hcpriv->otg_device_mask;
+
+        RETURN_UNLESS (change_data && (int_urb = rh_hcpriv->int_urb));
+
+        TRACE_MSG1(HCD,"non-zero change_data: %02x", change_data);
+
+        change_data |= 1;       // set hub change bit XXX check
+
+        // Completing the urb will "use it up", so remove the link to it.
+
+        del_timer(&rh_hcpriv->poll_timer);
+        rh_hcpriv->int_urb = NULL;
+
+        *((u8 *)(int_urb->transfer_buffer)) = change_data;
+        int_urb->actual_length = 1;
+
+        /* Completing an INT urb will cause it to be immediately re-submitted, so this will call submit_urb()
+         */
+        hcd_rh_urb_complete(bus_hcpriv, int_urb);
+        usb_put_urb(int_urb);
+}
+/* ********************************************************************************************** */
+STATIC void poll_int_urb(unsigned long data)
+{
+        struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *) (void *) data;
+        unsigned long flags;
+
+        RETURN_UNLESS (bus_hcpriv && bus_hcpriv->rh_hcpriv);
+
+        local_irq_save(flags);
+        PREPARE_WORK_ITEM(bus_hcpriv->rh_hcpriv->psc_bh, hcd_rh_portstatus_bh, bus_hcpriv);
+        SCHEDULE_WORK(bus_hcpriv->rh_hcpriv->psc_bh);
+        local_irq_restore(flags);
+}
+/* ********************************************************************************************** */
+STATIC u32 rh_get_port_change_status(struct bus_hcpriv *bus_hcpriv, u16 wIndex)
+{
+        if ((wIndex != bus_hcpriv->otg_port) || !(bus_hcpriv->rh_hcpriv->otg_device_mask)) 
+                return hcd_hw_rh_get_port_change_status(bus_hcpriv, wIndex);
+        
+        TRACE_MSG0(HCD, "USING SHADOW INFORMATION");
+        return bus_hcpriv->rh_hcpriv->port_change_status[wIndex-1];
+}
+
+/*
+ * hcd_rh_submit_urb()
+ * Returns: values as for the generic submit_urb() function, see comp_code_to_status(int cc).
+ */
+int hcd_rh_submit_urb(struct bus_hcpriv *bus_hcpriv, struct urb *urb, int mem_flags)
+{
+        struct rh_hcpriv *rh_hcpriv;
+        unsigned int pipe = urb->pipe;
+        struct usbd_device_request *req;
+        u8 bRequest;
+        u8 bmRequestType;
+        u16 wValue;
+        u16 wIndex;
+        u16 wLength;
+        u8 direction;
+        u8 recipient;
+        u8 type;
+        int rc = 0;
+        int rc_stall = -EPIPE;
+        void *reply = NULL;
+        int rlen = 0;
+        u16 status[2];
+
+        static rh_urb; 
+
+        TRACE_MSG1(HCD,"pipe: %08x", pipe);
+
+
+        //printk(KERN_INFO"%s: rh_urb: %d\n", __FUNCTION__);
+        TRACE_MSG1(HCD, "rh_urb: %d", rh_urb++);
+
+        RETURN_ETIMEDOUT_UNLESS(bus_hcpriv && bus_hcpriv->rh_hcpriv);
+
+        rh_hcpriv = bus_hcpriv->rh_hcpriv;
+
+        if (usb_pipeint(pipe)) {
+                // This must be our interrupt endpoint poll.
+                TRACE_MSG1(HCD,"interrupt polling urb: %08lx",urb);
+                urb->status = 0;
+
+                // Increment the ref count, we're keeping this for a while.
+                usb_get_urb(urb);
+                if (rh_hcpriv->int_urb) {
+                        // Hmm, a new one while we still have the old...Shouldn't happen, and doesn't work if it does :(.
+                        //printk(KERN_INFO "%s: releasing old: %08x\n",__FUNCTION__,(u32)(void*)rh_hcpriv->int_urb);
+                        del_timer(&rh_hcpriv->poll_timer);
+                        usb_put_urb(rh_hcpriv->int_urb);
+                }
+
+                rh_hcpriv->int_urb = urb;
+                /* Schedule a scan for changes in case anything happened while there was no urb.
+                 * This has to be slightly delayed, in case this urb is a response to a completed
+                 * scan - usbcore submits a new int urb before clearing the hub/port change status,
+                 * relying on the int urb polling delay to give it time to do the clearing. 
+                 */
+                //printk(KERN_INFO "%s: scheduling PSC poll\n",__FUNCTION__);
+                //init_poll_timer(bus_hcpriv);
+                init_timer(&rh_hcpriv->poll_timer);
+                rh_hcpriv->poll_timer.function = poll_int_urb;
+                rh_hcpriv->poll_timer.data = (unsigned long) (void *) bus_hcpriv;
+                rh_hcpriv->poll_timer.expires = jiffies + 
+                        ((((rh_hcpriv->int_urb->interval < 10) ? 10 : rh_hcpriv->int_urb->interval) * HZ) / 1000);
+                add_timer(&rh_hcpriv->poll_timer);
+                return rc;
+        }
+
+        TRACE_MSG1(HCD,"req: %08x",(u32)(void*)urb->setup_packet);
+        RETURN_EINVAL_UNLESS((req = (struct usbd_device_request *) urb->setup_packet))
+
+        bRequest = req->bRequest;
+        bmRequestType = req->bmRequestType;
+        wValue = le16_to_cpu(req->wValue);
+        wIndex = le16_to_cpu(req->wIndex);
+        wLength = le16_to_cpu(req->wLength);
+        direction  = bmRequestType & USB_REQ_DIRECTION_MASK;
+        recipient = bmRequestType & USB_REQ_RECIPIENT_MASK;
+        type = bmRequestType & USB_REQ_TYPE_MASK;
+
+        TRACE_MSG8(HCD,"urb: %08lx req: %02x reqType: %02x val=%u ndx=%u len=%u dir: %02x recip: %02x",
+                  urb,bRequest,bmRequestType, wValue,wIndex,wLength,direction,recipient);
+
+        if (USB_REQ_HOST2DEVICE == direction) {
+                /* these do not require a reply */
+                int set_flag = (USB_REQ_SET_FEATURE == bRequest);
+                TRACE_MSG0(HCD,"H->D");
+                //printk(KERN_INFO "%s: H->D\n",__FUNCTION__);
+                urb->actual_length = 0;
+                switch (recipient) {
+                case USB_RECIP_HUB:
+                        switch (bRequest) {
+                        case USB_REQ_CLEAR_FEATURE:
+                        case USB_REQ_SET_FEATURE:
+                                if (USB_REQ_TYPE_CLASS == type) {
+                                        TRACE_MSG2(HCD,"%s hub feature: %04x",(set_flag?"set":"clear"),wValue);
+                                        //printk(KERN_INFO "%s hub feature: %04x\n",(set_flag?"set":"clear"),wValue);
+                                        hcd_rh_hub_feature(bus_hcpriv, wValue, set_flag);
+                                } 
+                                else {
+                                        TRACE_MSG2(HCD,"HUB C/S feature invalid type r: %02x t: %02x",bRequest,bmRequestType);
+                                        rc = rc_stall;
+                                }
+                                break;
+                        case USB_REQ_SET_ADDRESS:
+                                if (USB_REQ_TYPE_STANDARD == type) {
+                                        TRACE_MSG1(HCD,"set address %u",wValue);
+                                        //printk(KERN_INFO "set address %u\n",wValue);
+                                        bus_hcpriv->root_hub_addr = wValue;
+                                } 
+                                else {
+                                        TRACE_MSG2(HCD,"HUB SETADDRESS invalid type r: %02x t: %02x",bRequest,bmRequestType);
+                                        rc = rc_stall;
+                                }
+                                break;
+                        case USB_REQ_SET_CONFIGURATION:
+                                if (USB_REQ_TYPE_STANDARD == type) {
+                                        TRACE_MSG1(HCD,"set configuration: %02x",wValue);
+                                        //printk(KERN_INFO "set configuration: %02x\n",wValue);
+                                        rh_hcpriv->curr_cfg = (u8) (0xFF & wValue);
+                                } 
+                                else {
+                                        TRACE_MSG2(HCD,"HUB SETCONFIG invalid type r: %02x t: %02x",bRequest,bmRequestType);
+                                        rc = rc_stall;
+                                }
+                                break;
+                        case USB_REQ_SET_INTERFACE:
+                                // wIndex is interface number
+                                if (USB_REQ_TYPE_STANDARD == type) {
+                                        TRACE_MSG2(HCD,"set interface: %02x to : %02x",wIndex,wValue);
+                                        //printk(KERN_INFO "set interface: %02x to : %02x\n",wIndex,wValue);
+                                        rh_hcpriv->curr_itf = (u8) (0xFF & wValue);
+                                } 
+                                else {
+                                        TRACE_MSG2(HCD,"HUB SETINTERFACE invalid type r: %02x t: %02x",bRequest,bmRequestType);
+                                        rc = rc_stall;
+                                }
+                                break;
+                        default:
+                                TRACE_MSG2(HCD,"HUB invalid request r: %02x t: %02x",bRequest,bmRequestType);
+                                rc = rc_stall;
+                        }
+                        break;
+                case USB_RECIP_PORT:
+                        switch (bRequest) {
+                        case USB_REQ_CLEAR_FEATURE:
+                        case USB_REQ_SET_FEATURE:
+                                // At this point wIndex == port_num is 1-origin.
+                                if (USB_REQ_TYPE_CLASS == type && wIndex <= bus_hcpriv->num_ports && wIndex > 0) {
+                                        TRACE_MSG3(HCD,"%s port %u FEATURE: %04x",(set_flag?"set":"clear"),wIndex,wValue);
+                                        hcd_rh_port_feature(bus_hcpriv, wValue, wIndex, set_flag);
+                                } 
+                                else {
+                                        TRACE_MSG2(HCD,"PORT C/S FEATURE invalid type r: %02x t: %02x",bRequest,bmRequestType);
+                                        rc = rc_stall;
+                                }
+                                break;
+                        default:
+                                TRACE_MSG2(HCD,"PORT invalid request r: %02x t: %02x",bRequest,bmRequestType);
+                                rc = rc_stall;
+                        }
+                        break;
+                case USB_REQ_RECIPIENT_ENDPOINT:
+                        // Clear stalled endpoint
+                        if (USB_REQ_CLEAR_FEATURE != bRequest || 1 != wValue ||
+                            USB_REQ_TYPE_STANDARD != type) {  // QQSV verify type correct
+                                TRACE_MSG3(HCD,"ENDPOINT invalid request,val,type r: %02x t: %02x val=%u",
+                                               bRequest,bmRequestType,wValue);
+                                rc = rc_stall;
+                        }
+                        // Nothing to really do to "clear" the stalled EP.
+                        TRACE_MSG2(HCD,"clear endpoint ndx: %02x val: %02x",wIndex,wValue);
+                        //printk(KERN_INFO "clear endpoint ndx: %02x val: %02x\n",wIndex,wValue);
+                        break;
+                case USB_REQ_RECIPIENT_INTERFACE:
+                default:
+                        TRACE_MSG2(HCD,"H->D invalid recipient r: %02x t: %02x",bRequest,bmRequestType);
+                        rc = rc_stall;
+                }
+        } 
+        else {
+                /* these do require a reply */
+                TRACE_MSG0(HCD,"H<-D");
+                //printk(KERN_INFO "%s: H<-D\n",__FUNCTION__);
+                switch (recipient) {
+                case USB_RECIP_HUB:
+                        switch (bRequest) {
+                        case USB_REQ_GET_DESCRIPTOR:
+                                if (USB_REQ_TYPE_CLASS == type) {
+                                        // Return the hub class descriptor
+                                        TRACE_MSG0(HCD,"get hub class descriptor");
+                                        //printk(KERN_INFO "get hub class descriptor\n");
+                                        reply = (void *) rh_hcpriv->hd;
+                                        rlen = rh_hcpriv->hd->bDescLength;
+                                } 
+                                else if (USB_REQ_TYPE_STANDARD != type) {
+                                        TRACE_MSG2(HCD,"HUB GETDESCRIPTOR invalid type r: %02x t: %02x",bRequest,bmRequestType);
+                                        rc = rc_stall;
+                                } 
+                                else {
+                                        // Return one of the other descriptors
+                                        switch (wValue >> 8) {
+                                        case USB_DT_DEVICE:
+                                                TRACE_MSG0(HCD,"get device descriptor");
+                                                //printk(KERN_INFO "get device descriptor\n");
+                                                reply = (void *) rh_hcpriv->dd;
+                                                rlen = rh_hcpriv->dd->bLength;
+                                                break;
+                                        case USB_DT_CONFIGURATION:
+                                                TRACE_MSG0(HCD,"get configuration descriptor");
+                                                reply = (void *) rh_hcpriv->cd;
+                                                rlen = USB_DT_CONFIG_SIZE+USB_DT_INTERFACE_SIZE+USB_DT_ENDPOINT_SIZE;
+                                                break;
+                                        case USB_DT_STRING:
+                                                TRACE_MSG1(HCD,"get string descriptor %u",wValue);
+                                                reply = urb->transfer_buffer;
+                                                rlen = hcd_rh_string(bus_hcpriv,(wValue & 0xFF),reply,wLength);
+                                                break;
+                                        default:
+                                                TRACE_MSG1(HCD,"HUB GETDESCRIPTOR invalid wValue: %04x",wValue);
+                                                rc = rc_stall;
+                                        }
+                                }
+                                break;
+                        case USB_REQ_GET_STATUS:
+                                if (USB_REQ_TYPE_CLASS == type) {
+                                        u32 change_status = bus_hcpriv->rh_hcpriv->hub_change_status;
+                                        status[0] = cpu_to_le16(change_status & 0xFFFF);
+                                        status[1] = cpu_to_le16(change_status >> 16);
+                                        reply = (void *) &status[0];
+                                        rlen = 4;
+                                        TRACE_MSG1(HCD,"GET HUB_CHANGE_STATUS: %08x", bus_hcpriv->rh_hcpriv->hub_change_status);
+                                } 
+                                else {
+                                        TRACE_MSG2(HCD,"HUB GETSTATUS invalid type r: %02x t: %02x",bRequest,bmRequestType);
+                                        rc = rc_stall;
+                                }
+                                break;
+                        case USB_REQ_GET_INTERFACE:
+                                // FIXME Verify type and interface number (wIndex)
+                                TRACE_MSG1(HCD,"get interface %u",wIndex);
+                                reply = (void *) &rh_hcpriv->curr_itf;
+                                rlen = 1;
+                                break;
+                        case USB_REQ_GET_CONFIGURATION:
+                                // FIXME Verify type
+                                TRACE_MSG0(HCD,"get configuration");
+                                // Return a single byte value
+                                reply = (void *) &rh_hcpriv->curr_cfg;
+                                rlen = 1;
+                                break;
+                        default:
+                                TRACE_MSG2(HCD,"H<-D HUB invalid request r: %02x t: %02x",bRequest,bmRequestType);
+                                rc = rc_stall;
+                        }
+                        break;
+                case USB_RECIP_PORT:
+                        switch (bRequest) {
+                        case USB_REQ_GET_STATUS:
+                                if (USB_REQ_TYPE_CLASS == type) {
+                                        /* USB2.0 11.24.2.7 pg 426 says first hword of reply are status (Tbl 11-21),
+                                                                        second hword is change (Tbl 11-22). */
+                                        u32 change_status = ((wIndex -1) < bus_hcpriv->num_ports) ?
+                                                bus_hcpriv->rh_hcpriv->port_change_status[wIndex-1] : 0;
+                                        u32 hw_change_status = ((wIndex -1) < bus_hcpriv->num_ports) ?
+                                                rh_get_port_change_status(bus_hcpriv, wIndex) : 0;
+
+                                        check_port_status(bus_hcpriv, wIndex, "HOST POLL");
+
+                                        status[0] = cpu_to_le16(hw_change_status & 0xFFFF);
+                                        status[1] = cpu_to_le16(change_status >> 16);
+                                        reply = (void *) &status[0];
+                                        rlen = 4;
+
+                                        TRACE_MSG3(HCD,"GET PORT_CHANGE_STATUS[%2d] %04x %04x", wIndex, status[0], status[1]);
+                                } 
+                                else {
+                                        TRACE_MSG2(HCD,"PORT GETSTATUS invalid type r: %02x t: %02x",bRequest,bmRequestType);
+                                        rc = rc_stall;
+                                }
+                                break;
+                        default:
+                                TRACE_MSG2(HCD,"H<-D PORT invalid request r: %02x t: %02x",bRequest,bmRequestType);
+                                rc = rc_stall;
+                        }
+                        break;
+                case USB_REQ_RECIPIENT_INTERFACE:
+                case USB_REQ_RECIPIENT_ENDPOINT:
+                default:
+                        TRACE_MSG2(HCD,"H<-D invalid recipient r: %02x t: %02x",bRequest,bmRequestType);
+                        rc = rc_stall; 
+                }
+                if (!rc && reply) {
+                        // There is a reply to copy into place.
+                        if (rlen > wLength) {
+                                // Truncate the reply (used to get part of a descriptor).
+                                rlen = wLength;
+                        }
+                        if (rlen > 0 && reply != urb->transfer_buffer) {
+                                memcpy(urb->transfer_buffer,reply,rlen);
+                        }
+                        urb->actual_length = rlen;
+                }
+        }
+        // All done, "complete" it.
+        urb->status = rc;
+        TRACE_MSG3(HCD,"urb: %08lx completing status=%d len=%d",urb,urb->status,urb->actual_length);
+        hcd_rh_urb_complete(bus_hcpriv,urb);
+        TRACE_MSG2(HCD,"urb: %08lx completed->%d",urb,rc);
+        return rc;
+}
+
+/*
+ * hcd_rh_unlink_urb()
+ */
+int hcd_rh_unlink_urb(struct bus_hcpriv *bus_hcpriv, struct urb *urb)
+{
+        struct rh_hcpriv *rh_hcpriv = bus_hcpriv->rh_hcpriv;
+        RETURN_EINVAL_UNLESS(urb && (urb == rh_hcpriv->int_urb));
+        del_timer(&rh_hcpriv->poll_timer);
+        rh_hcpriv->int_urb = NULL;
+        urb->status = -ENOENT; // Cancelled
+        hcd_rh_urb_complete(bus_hcpriv,urb);
+        usb_put_urb(urb);
+        return 0;
+}
+/* ********************************************************************************************** */
+/*
+ * For the hardware specific root hub component.
+ */
+irqreturn_t hcd_rh_int_hndlr(int irq, void *dev_id, struct pt_regs *regs)
+{
+        struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *) dev_id;
+
+        // Assume port status change.
+        //printk(KERN_INFO "%s: scheduling hcd_rh_portstatus_bh\n",__FUNCTION__);
+        
+        PREPARE_WORK_ITEM(bus_hcpriv->rh_hcpriv->psc_bh, hcd_rh_portstatus_bh, bus_hcpriv);
+        SCHEDULE_WORK(bus_hcpriv->rh_hcpriv->psc_bh);
+        return IRQ_HANDLED;
+}
+/* ********************************************************************************************** */
+#if !defined(OTG_C99)
+struct usbd_device_descriptor rh_device_descriptor;
+struct usbd_configuration_descriptor rh_configuration_descriptor;
+struct usbd_interface_descriptor rh_interface_descriptor;
+struct usbd_endpoint_descriptor rh_endpoint_descriptor;
+struct hub_descriptor rh_hub_descriptor;
+
+void rh_global_init(void)
+{
+        ZERO(rh_device_descriptor);
+        rh_device_descriptor.bLength = USB_DT_DEVICE_SIZE;
+        rh_device_descriptor.bDescriptorType = USB_DT_DEVICE;
+        rh_device_descriptor.bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION);
+        rh_device_descriptor.bDeviceClass = USB_CLASS_HUB;
+        rh_device_descriptor.bDeviceSubClass = 0;
+        rh_device_descriptor.bDeviceProtocol = 0;
+        rh_device_descriptor.bMaxPacketSize0 = 8;
+        rh_device_descriptor.iManufacturer = XHC_RH_STRING_MANUFACTURER;
+        rh_device_descriptor.iProduct = XHC_RH_STRING_PRODUCT;
+        rh_device_descriptor.iSerialNumber = XHC_RH_STRING_SERIAL;
+        rh_device_descriptor.bNumConfigurations = 1;
+
+        ZERO(rh_configuration_descriptor);
+        rh_configuration_descriptor.bLength = USB_DT_CONFIG_SIZE;
+        rh_configuration_descriptor.bDescriptorType = USB_DT_CONFIGURATION;
+        rh_configuration_descriptor.wTotalLength = __constant_cpu_to_le16(USB_DT_CONFIG_SIZE+USB_DT_INTERFACE_SIZE
+                        + USB_DT_ENDPOINT_SIZE);
+        rh_configuration_descriptor.bNumInterfaces = 1;
+        rh_configuration_descriptor.bConfigurationValue = 1;
+        rh_configuration_descriptor.iConfiguration = XHC_RH_STRING_CONFIGURATION;
+
+        ZERO(rh_interface_descriptor);
+        rh_interface_descriptor.bLength = USB_DT_INTERFACE_SIZE;
+        rh_interface_descriptor.bDescriptorType = USB_DT_INTERFACE;
+        rh_interface_descriptor.bInterfaceNumber = 0;
+        rh_interface_descriptor.bAlternateSetting = 0;
+        rh_interface_descriptor.bNumEndpoints = 1;
+        rh_interface_descriptor.bInterfaceClass = USB_CLASS_HUB;
+        rh_interface_descriptor.bInterfaceSubClass = 0;
+        rh_interface_descriptor.bInterfaceProtocol = 0;
+        rh_interface_descriptor.iInterface = XHC_RH_STRING_INTERFACE;
+
+        ZERO(rh_endpoint_descriptor);
+        rh_endpoint_descriptor.bLength = USB_DT_ENDPOINT_SIZE;
+        rh_endpoint_descriptor.bDescriptorType = USB_DT_ENDPOINT;
+        rh_endpoint_descriptor.bEndpointAddress = USB_DIR_IN | 1;  // Fixed EP 1
+        rh_endpoint_descriptor.bmAttributes = INTERRUPT;
+        rh_endpoint_descriptor.wMaxPacketSize = __constant_cpu_to_le16(4);
+        rh_endpoint_descriptor.bInterval = 0xFF;
+
+        ZERO(rh_hub_descriptor);
+        rh_hub_descriptor.bDescLength = USB_DT_HUB_NONVAR_SIZE+2;
+        rh_hub_descriptor.bDescriptorType = USB_DT_HUB;
+};
+
+#else /* !defined(OTG_C99) */
+struct usbd_device_descriptor rh_device_descriptor = {
+        .bLength = USB_DT_DEVICE_SIZE,
+        .bDescriptorType = USB_DT_DEVICE,
+        .bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION),
+        .bDeviceClass = USB_CLASS_HUB,
+        .bDeviceSubClass = 0,
+        .bDeviceProtocol = 0,
+        .bMaxPacketSize0 = 8,
+        .iManufacturer = XHC_RH_STRING_MANUFACTURER,
+        .iProduct = XHC_RH_STRING_PRODUCT,
+        .iSerialNumber = XHC_RH_STRING_SERIAL,
+        .bNumConfigurations = 1,
+};
+
+struct usbd_configuration_descriptor rh_configuration_descriptor = {
+        .bLength = USB_DT_CONFIG_SIZE,
+        .bDescriptorType = USB_DT_CONFIGURATION,
+        .wTotalLength = __constant_cpu_to_le16(USB_DT_CONFIG_SIZE+USB_DT_INTERFACE_SIZE+USB_DT_ENDPOINT_SIZE),
+        .bNumInterfaces = 1,
+        .bConfigurationValue = 1,
+        .iConfiguration = XHC_RH_STRING_CONFIGURATION,
+};
+
+struct usbd_interface_descriptor rh_interface_descriptor = {
+        .bLength = USB_DT_INTERFACE_SIZE,
+        .bDescriptorType = USB_DT_INTERFACE,
+        .bInterfaceNumber = 0,
+        .bAlternateSetting = 0,
+        .bNumEndpoints = 1,
+        .bInterfaceClass = USB_CLASS_HUB,
+        .bInterfaceSubClass = 0,
+        .bInterfaceProtocol = 0,
+        .iInterface = XHC_RH_STRING_INTERFACE,
+};
+
+struct usbd_endpoint_descriptor rh_endpoint_descriptor = {
+        .bLength = USB_DT_ENDPOINT_SIZE,
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = USB_DIR_IN | 1,  // Fixed EP 1
+        .bmAttributes = INTERRUPT,
+        .wMaxPacketSize = __constant_cpu_to_le16(4),
+        .bInterval = 0xFF,
+};
+
+/* This assumes 1-8 ports.
+ * If ports > 8, then DeviceRemovable and PortPwrCtrlMask need to be sized accordingly. 
+ */
+struct hub_descriptor rh_hub_descriptor = {
+        .bDescLength = USB_DT_HUB_NONVAR_SIZE+2,
+        .bDescriptorType = USB_DT_HUB,
+};
+#endif /* !defined(OTG_C99) */
+
+/* ********************************************************************************************** */
+/*
+ * Copy static descriptors to buffer to allow modification for actual
+ * configuration and provide full configuration descriptor.
+ */
+STATIC void build_descriptors(struct bus_hcpriv *bus_hcpriv)
+{
+        struct rh_hcpriv *rh_hcpriv = bus_hcpriv->rh_hcpriv;
+        void *bp = rh_hcpriv->descriptors;
+
+
+        rh_hcpriv->dd = (struct usbd_device_descriptor *) bp;
+        memcpy(bp, &rh_device_descriptor, sizeof(rh_device_descriptor));
+        rh_hcpriv->cd = (struct usbd_configuration_descriptor *) bp = bp + USB_DT_DEVICE_SIZE;
+        memcpy(bp, &rh_configuration_descriptor, sizeof(rh_configuration_descriptor));
+        rh_hcpriv->id = (struct usbd_interface_descriptor *) bp = bp + USB_DT_CONFIG_SIZE;
+        memcpy(bp, &rh_interface_descriptor, sizeof(rh_interface_descriptor));
+        rh_hcpriv->ed = (struct usbd_endpoint_descriptor *) bp = bp + USB_DT_INTERFACE_SIZE;
+        memcpy(bp, &rh_endpoint_descriptor, sizeof(rh_endpoint_descriptor));
+        rh_hcpriv->hd = (struct hub_descriptor *) bp = bp + USB_DT_ENDPOINT_SIZE;
+        memcpy(bp, &rh_hub_descriptor, sizeof(rh_hub_descriptor));
+
+        rh_hcpriv->dd->idVendor = cpu_to_le16(bus_hcpriv->rh_vendorid);
+        rh_hcpriv->dd->idProduct = cpu_to_le16(bus_hcpriv->rh_productid);
+        rh_hcpriv->dd->bcdDevice = cpu_to_le16(bus_hcpriv->rh_bcddevice);
+        rh_hcpriv->cd->bmAttributes = bus_hcpriv->rh_bmAttributes;
+        rh_hcpriv->cd->bMaxPower = bus_hcpriv->rh_bMaxPower;
+        rh_hcpriv->hd->bNbrPorts = bus_hcpriv->num_ports,
+        rh_hcpriv->hd->wHubCharacteristics = cpu_to_le16(hcd_hw_rh_hub_attributes(bus_hcpriv));
+        rh_hcpriv->hd->bPwrOn2PwrGood = hcd_hw_rh_power_delay(bus_hcpriv);
+        rh_hcpriv->hd->bHubContrCurrent = hcd_hw_rh_hub_contr_current(bus_hcpriv);
+        rh_hcpriv->hd->DeviceRemovable = hcd_hw_rh_DeviceRemovable(bus_hcpriv);
+        rh_hcpriv->hd->PortPwrCtrlMask = hcd_hw_rh_PortPwrCtrlMask(bus_hcpriv);
+}
+
+/* ********************************************************************************************** */
+
+#define PORT_SYNC_MASK  ( (1 << PORT_POWER) | (1 << PORT_SUSPEND) | (1 << PORT_RESET) )
+
+/* puts OTG capable port into a_host or b_host state - attempt to use port */
+void rh_loc_sof_func(struct otg_instance *otg, u8 on)
+{
+        struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *)(((struct hcd_instance *)(otg->hcd))->privdata);
+        int i;
+        unsigned long flags;
+
+        RETURN_UNLESS (bus_hcpriv && bus_hcpriv->rh_hcpriv && bus_hcpriv->rh_hcpriv->port_change_status);
+
+        local_irq_save(flags);
+        switch (on) {
+        case SET:
+                //printk(KERN_INFO"%s: SET\n", __FUNCTION__);
+                TRACE_MSG0(HCD, "RH LOC_SOF SET");
+
+                // Stop treating otg capable port as a device
+                bus_hcpriv->rh_hcpriv->otg_device_mask &= ~(0x1 << (bus_hcpriv->otg_port));
+
+                /* Sync the state of the HW to the shadow values, because
+                 * the root hub was registered with usbcore a while back, and
+                 * at the very least it probably tried to turn on the power,
+                 * and until now, the otg_device_mask was preventing that. 
+                 */
+                for (i = 0; i < 16; i++) {
+
+                        if (PORT_SYNC_MASK & (0x1 << i) & bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1]) {
+                                hcd_hw_rh_port_feature(bus_hcpriv, i, bus_hcpriv->otg_port, TRUE);
+                                check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "OTG EN");
+                        }
+                }
+
+                /* "Connect" on OTG port and simulate a port status change interrupt
+                 */
+                bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1] |= 0x00010001;
+                TRACE_MSG2(HCD, "OUTPUT: RH LOC_SOF_SET port_change_status[%d]: %08x", 
+                                bus_hcpriv->otg_port, bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1]);
+                check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "SOF SET");
+                break;
+
+        case RESET:
+                //printk(KERN_INFO"%s: RESET\n", __FUNCTION__);
+                TRACE_MSG0(HCD, "RH LOC_SOF RESET");
+
+                check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "SOF RESET - BEFORE");
+
+                // "Disconnect" on OTG port and simulate a port status change interrupt
+                bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1] &= ~0x00000001;
+                bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1] |= 0x00010000;
+                TRACE_MSG2(HCD, "OUTPUT: RH LOC_SOF_RESET port_change_status[%d]: %08x",
+                                bus_hcpriv->otg_port, bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1]);
+
+
+                // Turn off port power.
+                hcd_hw_rh_port_feature(bus_hcpriv, PORT_POWER, bus_hcpriv->otg_port, FALSE);
+                //hcd_hw_rh_port_feature(bus_hcpriv, PORT_ENABLE, bus_hcpriv->otg_port, FALSE);
+
+                check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "SOF RESET - AFTER");
+
+                // Start treating otg capable port as a device
+                bus_hcpriv->rh_hcpriv->otg_device_mask |= (0x1 << (bus_hcpriv->otg_port));
+                break;
+        }
+        
+        bus_hcpriv->rh_hcpriv->hub_port_change_status |= (1 << bus_hcpriv->otg_port);
+        TRACE_MSG0(HCD, "Schedule hcd_rh_portstatus_bh");
+        PREPARE_WORK_ITEM(bus_hcpriv->rh_hcpriv->psc_bh, hcd_rh_portstatus_bh, bus_hcpriv);
+        SCHEDULE_WORK(bus_hcpriv->rh_hcpriv->psc_bh);
+        local_irq_restore(flags);
+}
+
+/* puts OTG capable port into a_host or b_host state - attempt to use port */
+void rh_loc_suspend_func(struct otg_instance *otg, u8 on)
+{
+        struct bus_hcpriv *bus_hcpriv = (struct bus_hcpriv *)(((struct hcd_instance *)(otg->hcd))->privdata);
+        struct rh_hcpriv *rh_hcpriv = bus_hcpriv->rh_hcpriv;
+        int i;
+        unsigned long flags;
+
+        //printk(KERN_INFO"%s: \n", __FUNCTION__);
+        RETURN_UNLESS (bus_hcpriv && bus_hcpriv->rh_hcpriv && bus_hcpriv->rh_hcpriv->port_change_status);
+
+        local_irq_save(flags);
+        switch (on) {
+        case SET:
+                TRACE_MSG0(HCD, "OUTPUT: RH LOC_SUSPEND SET");
+
+                rh_hcpriv->suspended = 1;
+
+                // suspend
+                hcd_hw_rh_port_feature(bus_hcpriv, PORT_SUSPEND, bus_hcpriv->otg_port, TRUE);
+
+                // "Connect" on OTG port and simulate a port status change interrupt
+                bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1] |= 0x00040004;
+                TRACE_MSG2(HCD, "OUTPUT: RH LOC_SUSPNED_SET port_change_status[%d]: %08x", 
+                                bus_hcpriv->otg_port, bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1]);
+                check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "LOC_SUSPEND SET");
+                break;
+
+        case RESET:
+
+                TRACE_MSG0(HCD, "OUTPUT: RH LOC_SUSPEND RESET");
+                check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "LOC_SUSPEND RESET - BEFORE");
+
+                // "Disconnect" on OTG port and simulate a port status change interrupt
+                bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1] &= ~0x00000004;
+                bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1] |= 0x00040000;
+                TRACE_MSG2(HCD, "OUTPUT: RH LOC_SUSPEND port_change_status[%d]: %08x",
+                                bus_hcpriv->otg_port, bus_hcpriv->rh_hcpriv->port_change_status[bus_hcpriv->otg_port - 1]);
+
+
+                // suspend
+                hcd_hw_rh_port_feature(bus_hcpriv, PORT_SUSPEND, bus_hcpriv->otg_port, FALSE);
+                check_port_status(bus_hcpriv, bus_hcpriv->otg_port, "SOF RESET - AFTER");
+
+                rh_hcpriv->suspended = 0;
+
+                break;
+        }
+
+        bus_hcpriv->rh_hcpriv->hub_port_change_status |= (1 << bus_hcpriv->otg_port);
+        TRACE_MSG0(HCD, "Schedule hcd_rh_portstatus_bh");
+        PREPARE_WORK_ITEM(bus_hcpriv->rh_hcpriv->psc_bh, hcd_rh_portstatus_bh, bus_hcpriv);
+        SCHEDULE_WORK(bus_hcpriv->rh_hcpriv->psc_bh);
+        local_irq_restore(flags);
+}
+
+void rh_suspend_func(struct otg_instance *otg, u8 flag)
+{
+        /* suspends the OTG capable port */
+        //TRACE_MSG0(HCD, "--");
+        switch (flag) {
+        case SET:
+                //printk(KERN_INFO"%s: SET\n", __FUNCTION__);
+                TRACE_MSG0(HCD, "OUTPUT: RH SUSPEND_SET");
+                break;
+        case RESET:
+                //printk(KERN_INFO"%s: RESET\n", __FUNCTION__);
+                TRACE_MSG0(HCD, "OUTPUT: RH SUSPEND_RESET");
+                break;
+        }
+}
+
+/* ********************************************************************************************* */
+
+int hcd_rh_init(struct bus_hcpriv *bus_hcpriv)
+{
+        struct rh_hcpriv *rh_hcpriv;
+        int wIndex;
+        int port_mask;
+
+        #if !defined(OTG_C99)
+        rh_global_init();
+        #endif /* !defined(OTG_C99) */
+
+        //printk(KERN_INFO"%s: \n", __FUNCTION__);
+        RETURN_ZERO_UNLESS (bus_hcpriv);
+        RETURN_ENOMEM_UNLESS ((rh_hcpriv = bus_hcpriv->rh_hcpriv = 
+                                (struct rh_hcpriv *) kmalloc(sizeof(struct rh_hcpriv),GFP_KERNEL)));
+        memset(rh_hcpriv, 0, sizeof(struct rh_hcpriv));
+
+        //printk(KERN_INFO "%s: rh_hcpriv: %08x\n",__FUNCTION__,(u32)(void*)rh_hcpriv);
+        //init_timer(&rh_hcpriv->poll_timer);
+        // Get the number of ports, and which port is OTG capable.
+        
+        //rh_hcpriv->num_ports = hcd_hw_rh_num_ports(bus_hcpriv);
+
+        // Allocate the shadow port_change_status array.
+        UNLESS ((rh_hcpriv->port_change_status = (u32 *)  kmalloc((bus_hcpriv->num_ports*sizeof(u32)),GFP_KERNEL))) {
+                //printk(KERN_ERR "%s: allocation of root hub shadow port data fails\n",__FUNCTION__);
+                kfree(rh_hcpriv);
+                bus_hcpriv->rh_hcpriv = rh_hcpriv = NULL;
+                return -ENOMEM;
+        }
+        memset(rh_hcpriv->port_change_status,0,(bus_hcpriv->num_ports*sizeof(u32)));
+        UNLESS ((rh_hcpriv->dev = usb_alloc_dev(NULL, bus_hcpriv->usb_bus, 0))) {
+                //printk(KERN_ERR "%s: allocation of root hub dev fails\n",__FUNCTION__);
+                kfree(rh_hcpriv->port_change_status);
+                rh_hcpriv->port_change_status = NULL;
+                kfree(rh_hcpriv);
+                bus_hcpriv->rh_hcpriv = rh_hcpriv = NULL;
+                return -ENOMEM;
+        }
+        rh_hcpriv->dev->speed = USB_SPEED_FULL;  // QQSV --- this belongs in the HW dependent portion...
+
+        // Build up USB descriptors
+        build_descriptors(bus_hcpriv);
+
+        // Leave OTG capable port as disabled as possible until OTG core enables it.
+        rh_hcpriv->otg_device_mask = bus_hcpriv->otg_capable_mask;
+
+        for (wIndex = 1; wIndex <= bus_hcpriv->num_ports; wIndex++) {
+                port_mask = (1 << (wIndex - 1));
+                if (port_mask & bus_hcpriv->otg_capable_mask) 
+                        TRACE_MSG1(HCD,"OTG capable port %d", wIndex);
+                else 
+                        TRACE_MSG1(HCD,"Standard port %d", wIndex);
+        }
+        return 0;
+}
+
+void hcd_rh_exit(struct bus_hcpriv *bus_hcpriv)
+{
+        struct rh_hcpriv *rh_hcpriv;
+        RETURN_UNLESS(bus_hcpriv && (rh_hcpriv = bus_hcpriv->rh_hcpriv));
+
+        (void *) hcd_rh_unlink_urb(bus_hcpriv,rh_hcpriv->int_urb);
+
+        if (rh_hcpriv->dev) {
+                usb_put_dev(rh_hcpriv->dev);
+                rh_hcpriv->dev = NULL;
+        }
+        if (rh_hcpriv->port_change_status) {
+                kfree(rh_hcpriv->port_change_status);
+                rh_hcpriv->port_change_status = NULL;
+        }
+        kfree(rh_hcpriv);
+        bus_hcpriv->rh_hcpriv = rh_hcpriv = NULL;
+}
+
diff -uNr linux/drivers/no-otg/ocd/otg-hcd/hcd.c linux/drivers/otg/ocd/otg-hcd/hcd.c
--- linux/drivers/no-otg/ocd/otg-hcd/hcd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/otg-hcd/hcd.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,139 @@
+/*
+ * otg/ocd/otg-hcd/hcd.c - OTG Host Controller Driver
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcara.com>, 
+ *      Tom Rushworth <tbr@belcara.com>, 
+ *      Bruce Balden <balden@belcara.com>
+ *
+ * Notes
+ *
+ * 1. The usbd-bi layer has be re-implemented to re-factor the UDC layer in a way to
+ * simplify implementation of UDC drivers. As much of the complexity of dealing with the middle
+ * layers and buffer (urb) handling is provided for in the common bi layer. 
+ *
+ * 2. TODO The udc interface will be further modified to allow the UDC to export a block of
+ * function pointers for the common bi layer to use. This will allow the common layer to
+ * implement default operations where the UDC does not provide an function. For example many UDC
+ * drivers do not provide full support for cable detection and usb pullup control. If these
+ * routines are not provided the common layer will supply defaults. This eliminates a reasonably
+ * larger amount of effectively unused code from many of the udc drivers.
+ *
+ */
+/*!
+ * @file otg/ocd/otg-hcd/hcd.c
+ * @brief Root Hub for Generic Host Controller Driver
+ *
+ *
+ * This file initializes the low level hardware drivers.
+ *
+ * This is the linux 2.4 version.
+ *
+ * @ingroup OTGHCD
+ */
+
+#include <otg/otg-compat.h>
+
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-pcd.h>
+
+/* ************************************************************************************* */
+
+void hcd_en_func (struct otg_instance *otg, u8 flag)
+{
+        //struct hcd_instance *hcd = otg->hcd;
+        TRACE_MSG0(HCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(HCD, "OUTPUT: HCD_EN_SET");
+                break;
+        case RESET:
+                TRACE_MSG0(HCD, "OUTPUT: HCD_EN_RESET");
+                break;
+        }
+}
+
+void hcd_init_func (struct otg_instance *otg, u8 flag)
+{
+        struct hcd_instance *hcd = otg->hcd;
+
+        TRACE_MSG0(HCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(HCD, "OUTPUT: HCD_INIT_SET");
+                otg_event(hcd->otg, HCD_OK, HCD, "HCD_INIT SET HCD_OK");
+                break;
+        case RESET:
+                TRACE_MSG0(HCD, "OUTPUT: HCD_INIT_RESET");
+                otg_event(hcd->otg, HCD_OK, HCD, "HCD_INIT SET HCD_OK");
+                break;
+        }
+}
+
+/* ************************************************************************************* */
+
+void hcd_loc_sof_func (struct otg_instance *otg, u8 flag)
+{
+        //struct hcd_instance *hcd = otg->hcd;
+        TRACE_MSG0(HCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(HCD, "OUTPUT: HCD_LOC_SOF_SET");
+                break;
+        case RESET:
+                TRACE_MSG0(HCD, "OUTPUT: HCD_LOC_SOF_RESET");
+                break;
+        }
+}
+
+void hcd_suspend_func (struct otg_instance *otg, u8 flag)
+{
+        //struct hcd_instance *hcd = otg->hcd;
+        TRACE_MSG0(HCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(HCD, "OUTPUT: HCD_SUSPEND_EN_SET");
+                break;
+        case RESET:
+                TRACE_MSG0(HCD, "OUTPUT: HCD_SUSPEND_EN_RESET");
+                break;
+        }
+}
+
+void hcd_remote_wakeup_en_func (struct otg_instance *otg, u8 flag)
+{
+        //struct hcd_instance *hcd = otg->hcd;
+        TRACE_MSG0(HCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(HCD, "OUTPUT: HCD_REMOTE_WAKEUP_EN_SET");
+                break;
+        case RESET:
+                TRACE_MSG0(HCD, "OUTPUT: HCD_REMOTE_WAKEUP_EN_RESET");
+                break;
+        }
+}
+
+void hcd_hnp_en_func (struct otg_instance *otg, u8 flag)
+{
+        //struct hcd_instance *hcd = otg->hcd;
+        TRACE_MSG0(HCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(HCD, "OUTPUT: HCD_HNP_EN_SET");
+                break;
+        case RESET:
+                TRACE_MSG0(HCD, "OUTPUT: HCD_HNP_EN_RESET");
+                break;
+        }
+}
+
+
diff -uNr linux/drivers/no-otg/ocd/otg-i2c/i2c-l26.c linux/drivers/otg/ocd/otg-i2c/i2c-l26.c
--- linux/drivers/no-otg/ocd/otg-i2c/i2c-l26.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/otg-i2c/i2c-l26.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,160 @@
+/*
+ * otg/ocd/otg-i2c/i2c-l26.c -- Linux 2.6 I2C access
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/otg-i2c/i2c-l26.c
+ * @brief Linux I2C I/O via generic i2c device.
+ *
+ * @ingroup ISP1301TCD
+ */
+
+#include <otg/otg-compat.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/i2c.h>
+
+#include <otg/pcd-include.h>
+#include <linux/pci.h>
+#include <otghw/isp1301-hardware.h>
+#include "isp1301.h"
+
+/* ********************************************************************************************* */
+
+/*
+ * N.B. i2c functions must not be called from interrupt handlers
+ */
+
+static struct file *i2c_file;
+static struct i2c_client *omap_i2c_client;
+static int initstate_i2c;
+static int initstate_region;
+#define MAX_I2C 16
+
+#ifdef CONFIG_OMAP_H2
+#define ADAPTOR_NAME "OMAP I2C"
+#endif /* CONFIG_OMAP_H2 */
+#ifdef CONFIG_ARCH_MAINSTONE
+#define ADAPTOR_NAME "PXA-I2C-Adapter"
+#endif /* CONFIG_ARCH_MAINSTONE */
+
+/*! i2c_configure
+ * Attempt to find and open generic i2c device
+ * @return - non-zero for failure
+ */
+int  i2c_configure(char *name, int addr)
+{
+        char filename[20];
+        int tmp;
+
+        RETURN_ZERO_IF(initstate_i2c);
+
+        /*find the I2C driver we need 
+         */
+        for (tmp = 0; tmp < MAX_I2C; tmp++) {
+
+                sprintf(filename, "/dev/i2c/%d", tmp);
+
+                printk(KERN_INFO"%s: %s\n", __FUNCTION__, filename);
+
+                UNLESS (IS_ERR(i2c_file = filp_open(filename, O_RDWR, 0))) {
+
+                        //printk(KERN_INFO"%s: %s found\n", __FUNCTION__, filename);
+
+                        /*found some driver */
+                        omap_i2c_client = (struct i2c_client *)i2c_file->private_data;
+
+                        printk(KERN_INFO"%s: found %s\n", __FUNCTION__, omap_i2c_client->adapter->name);
+                        if (strlen(omap_i2c_client->adapter->name) >= 8) {
+                                if (!strncmp(omap_i2c_client->adapter->name, name, strlen(name)))
+                                        break;  /*we found our driver! */
+                        }
+                        omap_i2c_client = NULL;
+                        filp_close(i2c_file, NULL);
+                }
+                printk(KERN_INFO"%s: %s %d\n", __FUNCTION__, filename, i2c_file);
+        }
+        if (tmp == MAX_I2C) {                           // Nothing found
+                printk(KERN_ERR"%s: cannot find I2C driver", __FUNCTION__);
+                return -ENODEV;
+        }
+        omap_i2c_client->addr = addr;
+        initstate_i2c = 1;
+        return 0;
+}
+
+/*! i2c_close
+ * Close i2c device fd.
+ */
+void  i2c_close(void)
+{
+        if (initstate_i2c)
+                filp_close(i2c_file, NULL);
+        initstate_i2c = 0;
+}
+
+/*! i2c_readb
+ * Read byte from i2c device
+ * @param subaddr
+ */
+u8 i2c_readb(u8 subaddr)
+{
+        u8 buf = 0;
+        i2c_master_send(omap_i2c_client, &subaddr, 1);
+        i2c_master_recv(omap_i2c_client, &buf, 1);
+        TRACE_MSG2(TCD, "addr: %02x buf:  %02x", subaddr, buf);
+        return buf;
+}
+
+/*! i2c_readw
+ * Read word from i2c device
+ * @param subaddr
+ */
+u16 i2c_readw(u8 subaddr)
+{
+        u16 buf = 0;
+        i2c_master_send(omap_i2c_client, &subaddr, 1);
+        i2c_master_recv(omap_i2c_client, (u8 *)&buf, 2);
+        TRACE_MSG2(TCD, "addr: %02x buf:  %04x", subaddr, buf);
+        return buf;
+}
+
+/*! i2c_readl
+ * Read long from i2c device
+ * @param subaddr
+ */
+u32 i2c_readl(u8 subaddr)
+{
+        u32 buf = 0;
+        i2c_master_send(omap_i2c_client, &subaddr, 1);
+        i2c_master_recv(omap_i2c_client, (u8 *)&buf, 4);
+        TRACE_MSG2(TCD, "addr: %02x buf:  %08x", subaddr, buf);
+        return buf;
+}
+
+
+/*! i2c_writeb
+ * Writw byte to i2c device
+ * @param subaddr
+ * @param buf
+ */
+int  i2c_writeb(u8 subaddr, u8 buf)
+{
+        char tmpbuf[2];
+
+        tmpbuf[0] = subaddr;    /*register number */
+        tmpbuf[1] = buf;        /*register data */
+        i2c_master_send(omap_i2c_client, &tmpbuf[0], 2);
+        
+        return 0;
+}
+
diff -uNr linux/drivers/no-otg/ocd/otg-pcd/pcd-init-l24.c linux/drivers/otg/ocd/otg-pcd/pcd-init-l24.c
--- linux/drivers/no-otg/ocd/otg-pcd/pcd-init-l24.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/otg-pcd/pcd-init-l24.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,119 @@
+/*
+ * otg/ocd/otg-pcd/pcd-init-l24.c - OTG Peripheral Controller Driver Module Initialization
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/otg-pcd/pcd-init-l24.c
+ * @brief PCD only driver init.
+ *
+ *
+ * PCD Initialization
+ *
+ * This file initializes all of the low level hardware drivers for a PCD.
+ *
+ * The Peripheral Controller Driver (pcd) implements the lowest layer of the
+ * USBD stack to send and receive data from the USB actings as a USB
+ * peripheral.
+ *
+ * Notes
+ *
+ * 1. This is the linux 2.4 version.
+ *
+ * TODO
+ *
+ * 1. hook up serial_number_str to pcd.c for use with bus interface layer.
+ *
+ *
+ * @ingroup OTGPCD
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/otg-module.h>
+#include <otg/usbp-bus.h>
+
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-pcd.h>
+
+#ifdef MODULE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,4,17)
+MODULE_LICENSE ("GPL");
+#endif
+MODULE_PARM (serial_number_str, "s");
+MODULE_PARM_DESC (serial_number_str, "Serial Number");
+MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
+MODULE_DESCRIPTION ("USB On-The-Go PCD");
+#endif
+char *serial_number_str;
+
+otg_tag_t PCD;
+struct pcd_instance *pcd_instance;
+
+/* ************************************************************************************* */
+
+/* pcd_modexit - module exit or init failure cleanup
+ *
+ * Specifically for each driver:
+ *
+ * 	call ops.mod_exit
+ * 	reset instance address and  ops table address in state machine to NULL
+ * 	invalidate tag
+ */
+static void pcd_modexit (void)
+{
+        struct otg_instance *otg = ocd_instance->otg;
+        printk(KERN_INFO"%s\n", __FUNCTION__);
+        if (otg)
+                otg_exit(otg);
+        if (pcd_ops.mod_exit) pcd_ops.mod_exit();
+        pcd_instance = otg_set_pcd_ops(NULL);
+        PCD = otg_trace_invalidate_tag(PCD);
+}
+
+/* pcd_modinit - linux module initialization
+ *
+ * This needs to initialize the ocd, pcd and tcd drivers.  
+ *
+ * Specifically for each driver:
+ *
+ * 	obtain tag
+ * 	pass ops table address to state machine and get instance address
+ * 	call ops.mod_init
+ *
+ * Note that we automatically provide a default tcd_init if
+ * none is set.
+ */
+static int pcd_modinit (void)
+{
+        printk(KERN_INFO"%s\n", __FUNCTION__);
+
+        #if !defined(OTG_C99)
+        pcd_global_init();
+        #endif /* !defined(OTG_C99) */
+
+        PCD = otg_trace_obtain_tag();
+
+        UNLESS(pcd_ops.pcd_init_func) pcd_ops.pcd_init_func = pcd_init_func;
+        THROW_UNLESS(pcd_instance = otg_set_pcd_ops(&pcd_ops), error);
+        THROW_IF((pcd_ops.mod_init) ? pcd_ops.mod_init() : 0, error);
+
+        CATCH(error) {
+                pcd_modexit();
+                return -EINVAL;
+        }
+        return 0;
+}
+MOD_EXIT(pcd_modexit);
+MOD_INIT(pcd_modinit);
diff -uNr linux/drivers/no-otg/ocd/otg-pcd/pcd-ocd-init-l24.c linux/drivers/otg/ocd/otg-pcd/pcd-ocd-init-l24.c
--- linux/drivers/no-otg/ocd/otg-pcd/pcd-ocd-init-l24.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/otg-pcd/pcd-ocd-init-l24.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,141 @@
+/*
+ * otg/pcd/pcd-ocd-init-l24.c - OTG Peripheral and OTG Controller Drivers Module Initialization
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/otg-pcd/pcd-ocd-init-l24.c
+ * @brief PCD only driver init.
+ *
+ *
+ * PCD/OCD Initialization
+ *
+ * This file initializes all of the low level hardware drivers for a combined
+ * PCD/OCD module. It does not initialize the TCD module.
+ *
+ * USB Periphirals using this must implement the following:
+ *
+ *      ocd_ops         operations from ocd driver
+ *      pcd_ops         operations from pcd driver
+ *
+ * The OTG Controller driver (ocd) implements any required OTG timers and if
+ * necessary mediates access to and initializes the OTG and/or USB hardware.
+ *
+ * The Peripheral Controller Driver (pcd) implements the lowest layer of the
+ * USBD stack to send and receive data from the USB actings as a USB
+ * peripheral.
+ *
+ * Notes
+ *
+ * 1. This is the linux 2.4 version.
+ *
+ * TODO
+ *
+ * 1. hook up serial_number_str to pcd.c for use with bus interface layer.
+ *
+ * @ingroup OTGPCD
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-bus.h>
+
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-pcd.h>
+#include <otg/otg-ocd.h>
+
+#ifdef MODULE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,4,17)
+MODULE_LICENSE ("GPL");
+#endif
+MODULE_PARM (serial_number_str, "s");
+MODULE_PARM_DESC (serial_number_str, "Serial Number");
+MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
+MODULE_DESCRIPTION ("USB On-The-Go PCD");
+#endif
+char *serial_number_str;
+
+otg_tag_t PCD;
+struct pcd_instance *pcd_instance;
+otg_tag_t OCD;
+struct ocd_instance *ocd_instance;
+
+
+/* ************************************************************************************* */
+
+/* pcd_ocd_modexit - module exit or init failure cleanup
+ *
+ * Specifically for each driver:
+ *
+ * 	call ops.mod_exit
+ * 	reset instance address and  ops table address in state machine to NULL
+ * 	invalidate tag
+ */
+static void pcd_ocd_modexit (void)
+{
+        struct otg_instance *otg = ocd_instance->otg;
+        printk(KERN_INFO"%s\n", __FUNCTION__);
+        if (otg)
+                otg_exit(otg);
+
+        if (pcd_ops.mod_exit) pcd_ops.mod_exit();
+        pcd_instance = otg_set_pcd_ops(NULL);
+        PCD = otg_trace_invalidate_tag(PCD);
+
+        if (ocd_ops.mod_exit) ocd_ops.mod_exit();
+        ocd_instance = otg_set_ocd_ops(NULL);
+        OCD = otg_trace_invalidate_tag(OCD);
+}
+
+/* pcd_ocd_modinit - linux module initialization
+ *
+ * This needs to initialize the ocd, pcd and tcd drivers.  
+ *
+ * Specifically for each driver:
+ *
+ * 	obtain tag
+ * 	pass ops table address to state machine and get instance address
+ * 	call ops.mod_init
+ *
+ * Note that we automatically provide a default tcd_init if
+ * none is set.
+ */
+static int pcd_ocd_modinit (void)
+{
+        printk(KERN_INFO"%s\n", __FUNCTION__);
+
+        #if !defined(OTG_C99)
+        pcd_global_init();
+        #endif /* !defined(OTG_C99) */
+
+        UNLESS(pcd_ops.pcd_init_func) pcd_ops.pcd_init_func = pcd_init_func;
+        PCD = otg_trace_obtain_tag();
+        THROW_UNLESS(pcd_instance = otg_set_pcd_ops(&pcd_ops), error);
+        THROW_IF((pcd_ops.mod_init) ? pcd_ops.mod_init() : 0, error);
+
+        OCD = otg_trace_obtain_tag();
+        THROW_UNLESS(ocd_instance = otg_set_ocd_ops(&ocd_ops), error);
+        THROW_IF((ocd_ops.mod_init) ? ocd_ops.mod_init() : 0, error);
+
+        CATCH(error) {
+                pcd_ocd_modexit();
+                return -EINVAL;
+        }
+        return 0;
+}
+
+MOD_EXIT (pcd_ocd_modexit);
+MOD_INIT (pcd_ocd_modinit);
+
+
diff -uNr linux/drivers/no-otg/ocd/otg-pcd/pcd.c linux/drivers/otg/ocd/otg-pcd/pcd.c
--- linux/drivers/no-otg/ocd/otg-pcd/pcd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/otg-pcd/pcd.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,845 @@
+/*
+ * otg/ocd/otg-pcd/pcd.c - OTG Peripheral Controller Driver
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/otg-pcd/pcd.c
+ * @brief PCD only driver init.
+ * Notes
+ *
+ * 1. The pcd file abstracts much of the UDC complexity as possible and
+ * provides a common implementation that is shared to various extents by the
+ * various pcd drivers.
+ *
+ * @ingroup OTGPCD
+ */
+
+#include <otg/pcd-include.h>
+#include <asm/au1000.h>
+
+
+extern char *serial_number_str;
+
+/* ******************************************************************************************* */
+/*! bus_request_endpoints
+ */
+int bus_request_endpoints(struct usbd_bus_instance *bus, struct usbd_endpoint_map *endpoint_map_array, int endpointsRequested, 
+                struct usbd_endpoint_request *requestedEndpoints)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        int i;
+        TRACE_MSG0(PCD, "BUS_REQUEST ENDPOINTS:");
+        if (usbd_pcd_ops.request_endpoints(pcd, endpoint_map_array, endpointsRequested, requestedEndpoints)) {
+                printk(KERN_INFO"%s: failed\n", __FUNCTION__);
+                return -EINVAL;
+        }
+        for (i = 0; i < endpointsRequested; i++) {
+                struct usbd_endpoint_map *endpoint_map = endpoint_map_array + i;
+                 TRACE_MSG4(PCD, "address: %02x physical: %02x request: %02x size: %04x", 
+                                 endpoint_map->bEndpointAddress[0], endpoint_map->physicalEndpoint[0], 
+                                 endpoint_map->bmAttributes[0], endpoint_map->wMaxPacketSize[0]);
+        }
+        return 0;
+}
+
+/*! bus_set_endpoints
+ */
+int bus_set_endpoints(struct usbd_bus_instance *bus, int endpointsRequested, struct usbd_endpoint_map *endpoint_map_array)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        TRACE_MSG0(PCD, "SET ENDPOINTS");
+        return usbd_pcd_ops.set_endpoints ? usbd_pcd_ops.set_endpoints(pcd, endpointsRequested, endpoint_map_array) : 0;
+}
+
+/*! bus_set_address
+ */
+int bus_set_address(struct usbd_bus_instance *bus, int address)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        if (usbd_pcd_ops.set_address) usbd_pcd_ops.set_address (pcd, address);
+        return 0;
+}
+
+/* ******************************************************************************************* */
+
+/*! pcd_search_endpoint_index - find endpoint map index given endpoint address
+ */
+int pcd_search_endpoint_index(struct usbd_bus_instance *bus, int bEndpointAddress)
+{
+        int i;
+        for (i = 0; i < bus->endpoints; i++)
+                BREAK_IF (bus->endpoint_array[i].bEndpointAddress == bEndpointAddress);
+        return i;
+}
+
+/*! pcd_search_endpoint - find endpoint given endpoint address
+ */
+struct usbd_endpoint_instance * pcd_search_endpoint(struct usbd_bus_instance *bus, int bEndpointAddress)
+{
+        int i = pcd_search_endpoint_index(bus, bEndpointAddress);
+        TRACE_MSG2(PCD, "BUS_SEARCH ENDPOINT:  addr: %02x index: %d", bEndpointAddress, i);
+        RETURN_NULL_UNLESS(i < bus->endpoints);
+        return &(bus->endpoint_array[i]);
+}
+
+/*! bus_endpoint_halted - check if endpoint halted
+ * Used by the USB Device Core to check endpoint halt status.
+ *
+ * Return actual halted status if available or'd with endpoint->feature_setting set value.
+ * Assume not halted if udc driver does not provide an endpoint halted function.
+ */
+int bus_endpoint_halted (struct usbd_bus_instance *bus, int bEndpointAddress)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        int endpoint_index = pcd_search_endpoint_index(bus, bEndpointAddress);
+        struct usbd_endpoint_instance *endpoint = pcd_search_endpoint(bus, bEndpointAddress);
+        int halted;
+
+        TRACE_MSG1(PCD, "BUS_ENDPOINT HALTED:  endpoint: %p", (int) endpoint);
+        RETURN_EINVAL_UNLESS(endpoint);
+
+        //halted = usbd_pcd_ops.endpoint_halted ? usbd_pcd_ops.endpoint_halted(pcd, endpoint_index) : 0;
+        halted = usbd_pcd_ops.endpoint_halted ? usbd_pcd_ops.endpoint_halted(pcd, endpoint) : 0;
+        TRACE_MSG1(PCD, "BUS_ENDPOINT HALTED: %08x", bus->endpoint_array[endpoint_index].feature_setting);
+
+        return halted || (endpoint->feature_setting & FEATURE(USB_ENDPOINT_HALT)? 1 : 0);
+}
+
+/*! bus_halt_endpoint - handle set/clear feature requests
+ * Used by the USB Device Core to set/clear endpoint halt status.
+ *
+ * We assume that if the udc driver does not implement anything then 
+ * we should just return zero for ok.
+ */
+int bus_halt_endpoint (struct usbd_bus_instance *bus, int bEndpointAddress, int flag)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        int endpoint_index = pcd_search_endpoint_index(bus, bEndpointAddress);
+        struct usbd_endpoint_instance *endpoint = pcd_search_endpoint(bus, bEndpointAddress);
+
+        TRACE_MSG1(PCD, "BUS_ENDPOINT HALT:  endpoint: %p", (int) endpoint);
+        RETURN_EINVAL_UNLESS(endpoint);
+        endpoint->feature_setting = flag;
+        return usbd_pcd_ops.halt_endpoint ? usbd_pcd_ops.halt_endpoint(pcd, endpoint, flag) : 0;
+}
+
+/*! pcd_disable_endpoints - disable udc and all endpoints
+ */
+static void pcd_disable_endpoints (struct usbd_bus_instance *bus)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        int i;
+        RETURN_IF (!bus || !bus->endpoint_array);
+        for (i = 1; i < usbd_pcd_ops.max_endpoints; i++) {
+                struct usbd_endpoint_instance *endpoint = (bus->endpoint_array + i);
+                CONTINUE_IF (!endpoint);
+                usbd_flush_endpoint (endpoint);
+        }
+}
+
+
+/*! bus_event_handler - handle generic bus event
+ * Called by usb core layer to inform bus of an event.
+ */
+int bus_event_handler (struct usbd_bus_instance *bus, usbd_device_event_t event, int data)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        int epn;
+        //struct usbd_endpoint_map *endpoint_map_array = bus->function_instance->endpoint_map_array;
+
+        //TRACE_MSG1(PCD, "BUS_EVENT %x", event);
+        switch (event) {
+        case DEVICE_UNKNOWN:
+                break;
+
+        case DEVICE_INIT:
+                TRACE_MSG0(PCD, "EVENT INIT");
+                break;
+
+        case DEVICE_CREATE:
+                TRACE_MSG0(PCD, "EVENT CREATE");
+                pcd_disable_endpoints (bus);
+                if (usbd_pcd_ops.start) usbd_pcd_ops.start (pcd);
+                break;
+
+        case DEVICE_HUB_CONFIGURED:
+                TRACE_MSG0(PCD, "EVENT HUB_CONFIGURED");
+                //bi_connect (bus, NULL);
+                break;
+
+        case DEVICE_RESET:
+                TRACE_MSG0(PCD, "EVENT RESET");
+
+                if (usbd_pcd_ops.set_address) usbd_pcd_ops.set_address (pcd, 0);
+
+                if (usbd_pcd_ops.reset_ep) usbd_pcd_ops.reset_ep (pcd, 0);
+
+                pcd_disable_endpoints (bus);
+                otg_event_irq(pcd->otg, BUS_RESET | BUS_SUSPENDED_, PCD, "DEVICE_RESET");
+
+                break;
+
+        case DEVICE_ADDRESS_ASSIGNED:
+                TRACE_MSG1(PCD, "EVENT ADDRESSED: %d", data);
+
+                otg_event_irq(pcd->otg, ADDRESSED, PCD, "ADDRESSED");
+
+                break;
+
+        case DEVICE_CONFIGURED:
+                TRACE_MSG0(PCD, "EVENT CONFIGURED");
+                otg_event_irq(pcd->otg, CONFIGURED, PCD, "CONFIGURED");
+                // iterate across the physical endpoint instance array to enable the endpoints
+                if (usbd_pcd_ops.setup_ep)
+                        for (epn = 1; epn < bus->endpoints; epn++) 
+                                usbd_pcd_ops.setup_ep (pcd, epn, bus->endpoint_array + epn);
+                break;
+
+        case DEVICE_DE_CONFIGURED:
+                TRACE_MSG0(PCD, "EVENT DE-CONFIGURED");
+                break;
+
+        case DEVICE_SET_INTERFACE:
+                TRACE_MSG0(PCD, "EVENT SET INTERFACE");
+                break;
+
+        case DEVICE_SET_FEATURE:
+                TRACE_MSG0(PCD, "EVENT SET FEATURE");
+                break;
+
+        case DEVICE_CLEAR_FEATURE:
+                TRACE_MSG0(PCD, "EVENT CLEAR FEATURE");
+                break;
+
+        case DEVICE_BUS_INACTIVE:
+                TRACE_MSG0(PCD, "EVENT INACTIVE");
+                TRACE_MSG1(PCD, "EVENT INACTIVE: state: %x", bus->device_state);
+                otg_event_irq(pcd->otg, BUS_SUSPENDED, PCD, "DEVICE_BUS_INACTIVE");
+                break;
+
+        case DEVICE_BUS_ACTIVITY:
+                TRACE_MSG0(PCD, "EVENT ACTIVITY");
+                otg_event_irq(pcd->otg, BUS_SUSPENDED_, PCD, "DEVICE_BUS_ACTIVITY");
+                break;
+
+        case DEVICE_POWER_INTERRUPTION:
+                TRACE_MSG0(PCD, "POWER INTERRUPTION");
+                break;
+
+        case DEVICE_HUB_RESET:
+                TRACE_MSG0(PCD, "HUB RESET");
+                break;
+
+        case DEVICE_DESTROY:
+                TRACE_MSG0(PCD, "DEVICE DESTROY");
+                //bi_disconnect (bus, NULL);
+                pcd_disable_endpoints (bus);
+                if (usbd_pcd_ops.stop) usbd_pcd_ops.stop (pcd);
+                break;
+
+        case DEVICE_CLOSE:
+                TRACE_MSG0(PCD, "DEVICE CLOSE");
+                break;
+        default:
+                TRACE_MSG1(PCD, "DEVICE UNKNOWN: %d", event);
+                break;
+        }
+        TRACE_MSG2(PCD, "EVENT bNumInterfaces: %x alternates: %x", bus->bNumInterfaces, bus->alternates);
+        return 0;
+}
+
+
+/*! bus_start_endpoint_in
+ */
+int bus_start_endpoint_in (struct usbd_bus_instance *bus, struct usbd_endpoint_instance *endpoint)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        unsigned long flags;
+
+        RETURN_ZERO_IF (!endpoint);
+        ocd_ops.interrupts++;
+
+        local_irq_save (flags);
+
+        // call pcd_start_endpoint_in IFF we didn't previously have a tx urb 
+        if (!endpoint->tx_urb && pcd_tx_next_irq (endpoint)) {
+                usbd_pcd_ops.start_endpoint_in (pcd, endpoint);
+        }
+        local_irq_restore (flags);
+        return 0;
+}
+
+/*! bus_start_endpoint_out
+ */
+int bus_start_endpoint_out (struct usbd_bus_instance *bus, struct usbd_endpoint_instance *endpoint)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        unsigned long flags;
+
+        RETURN_ZERO_IF (!endpoint);
+        ocd_ops.interrupts++;
+        local_irq_save (flags);
+        // call pcd_start_endpoint_OUT IFF we didn't previously have a rcv urb 
+        if (!endpoint->rcv_urb && pcd_rcv_next_irq (endpoint)) {
+                usbd_pcd_ops.start_endpoint_out (pcd, endpoint);
+        }
+        local_irq_restore (flags);
+        return 0;
+}
+
+
+/*! bus_cancel_urb_irq - cancel sending an urb
+ * Used by the USB Device Core to cancel an urb.
+ */
+int bus_cancel_urb_irq (struct usbd_urb *urb)
+{
+        struct usbd_bus_instance *bus = urb->bus;
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        RETURN_EINVAL_IF (!urb);
+        TRACE_MSG1(PCD, "BUS_CANCEL URB: %x", (int)urb);
+        switch (urb->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
+        case USB_DIR_IN:
+                // is this the active urb?
+                if (urb->endpoint->tx_urb == urb) {
+                        urb->endpoint->tx_urb = NULL;
+                        TRACE_MSG1(PCD, "CANCEL IN URB: %02x", urb->endpoint->bEndpointAddress);
+                        if (usbd_pcd_ops.cancel_in_irq) usbd_pcd_ops.cancel_in_irq (pcd, urb);
+                }
+                usbd_urb_finished_irq (urb, SEND_CANCELLED);
+                break;
+
+        case USB_DIR_OUT:
+                // is this the active urb?
+                if (urb->endpoint->rcv_urb == urb) {
+                        urb->endpoint->rcv_urb = NULL;
+                        TRACE_MSG1(PCD, "CANCEL OUT URB: %02x", urb->endpoint->bEndpointAddress);
+                        if (usbd_pcd_ops.cancel_out_irq) usbd_pcd_ops.cancel_out_irq (pcd, urb);
+                }
+                TRACE_MSG0(PCD, "CANCEL RECV URB");
+                usbd_urb_finished_irq (urb, RECV_CANCELLED);
+                break;
+        }
+        urb->endpoint->last = urb->endpoint->sent = 0;
+        return 0;
+}
+
+/*! pcd_rcv_finished_irq 
+ */
+struct usbd_urb * pcd_rcv_finished_irq (struct usbd_endpoint_instance *endpoint, int len, int urb_bad)
+{
+        struct usbd_urb *rcv_urb;
+
+        // if we had an urb then update actual_length, dispatch if neccessary
+        if (likely ( (int) (rcv_urb = endpoint->rcv_urb))) {
+                struct usbd_bus_instance *bus = rcv_urb->bus;
+                struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+
+                //TRACE_MSG5(PCD, "BUS_RCV COMPLETE: finished buffer: %x actual: %d len: %d bad: %d: status: %d",
+                //                rcv_urb->buffer, rcv_urb->actual_length, len, urb_bad, rcv_urb->status);
+
+                if (!urb_bad && !endpoint->rcv_error && (rcv_urb->bus->status == USBD_OK)) {
+
+#if 0
+                        int i;
+                        u8 *cp = rcv_urb->buffer;
+                        for (i = 0; i < rcv_urb->actual_length + len; i+= 8) {
+
+                                TRACE_MSG8(PCD, "RECV  %02x %02x %02x %02x %02x %02x %02x %02x",
+                                                cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
+                                                cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
+                                          );
+                        }
+#endif
+                        // increment the received data size
+                        rcv_urb->actual_length += len;
+
+                        endpoint->rcv_urb = NULL;
+                        rcv_urb->jiffies = jiffies;
+                        rcv_urb->framenum = pcd_ops.framenum ? pcd_ops.framenum () : 0;
+                        //TRACE_MSG1(PCD, "BUS_RCV COMPLETE: framenum: %x", (int) rcv_urb->framenum);
+                        usbd_urb_finished_irq (rcv_urb, RECV_OK);
+                        rcv_urb = NULL;
+                }
+                else {
+                        rcv_urb->actual_length = 0;
+                        //endpoint->rcv_error = 1;
+                }
+        }
+
+        // if we don't have an urb see if we can get one
+        return pcd_rcv_next_irq (endpoint);
+}
+
+/*! pcd_rcv_complete_irq 
+ */
+struct usbd_urb * pcd_rcv_complete_irq (struct usbd_endpoint_instance *endpoint, int len, int urb_bad)
+{
+        struct usbd_urb *rcv_urb;
+
+        // if we had an urb then update actual_length, dispatch if neccessary
+        if (likely ( (int) (rcv_urb = endpoint->rcv_urb))) {
+                struct usbd_bus_instance *bus = rcv_urb->bus;
+                struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+
+                TRACE_MSG4(PCD, "BUS_RCV COMPLETE: actual: %d len: %d bad: %d: status: %d",
+                                rcv_urb->actual_length, len, urb_bad, rcv_urb->status);
+
+                //TRACE_MSG4(PCD, "BUS_RCV COMPLETE: request: %d buffer: %d packet: %d transfer: %d",
+                //                rcv_urb->request_length, rcv_urb->buffer_length,
+                //                endpoint->wMaxPacketSize, endpoint->rcv_transferSize);
+
+                // check the urb is ok, are we adding data less than the packetsize
+                if (!urb_bad && !endpoint->rcv_error && (rcv_urb->bus->status == USBD_OK) && (len <= endpoint->wMaxPacketSize)) {
+
+                        // increment the received data size
+                        rcv_urb->actual_length += len;
+
+                        // if the current received data is short (less than full packetsize) which
+                        // indicates the end of the bulk transfer, we have received the maximum
+                        // transfersize, or if we do not have enough room to receive another packet 
+                        // then pass this data up to the function driver
+
+                        // XXX this needs to be fixed, for example the MSC driver 
+                        // has varying maximum sizes
+
+
+                        if (
+                                        ( (len < endpoint->wMaxPacketSize) ||
+                                          (rcv_urb->actual_length >= endpoint->rcv_transferSize) ||
+                                          (rcv_urb->actual_length >= rcv_urb->request_length) ||
+                                          (rcv_urb->actual_length + endpoint->wMaxPacketSize > rcv_urb->buffer_length)))
+                        {
+#if 0
+                                int i;
+                                u8 *cp = rcv_urb->buffer;
+                                for (i = 0; i < rcv_urb->actual_length; i+= 8)
+                                        TRACE_MSG8(PCD, "RECV  %02x %02x %02x %02x %02x %02x %02x %02x",
+                                                        cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
+                                                        cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
+                                                  );
+#endif
+                                endpoint->rcv_urb = NULL;
+                                rcv_urb->jiffies = jiffies;
+                                rcv_urb->framenum = pcd_ops.framenum ? pcd_ops.framenum () : 0;
+                                TRACE_MSG2(PCD, "BUS_RCV COMPLETE: finished length: %d framenum: %x", 
+                                                rcv_urb->actual_length, (int) rcv_urb->framenum);
+                                usbd_urb_finished_irq (rcv_urb, RECV_OK);
+                                rcv_urb = NULL;
+                        }
+                }
+                else {
+                        rcv_urb->actual_length = 0;
+                        //endpoint->rcv_error = 1;
+                }
+        }
+
+        // if we don't have an urb see if we can get one
+        return pcd_rcv_next_irq (endpoint);
+}
+
+/*! pcd_tx_complete_irq 
+ */
+struct usbd_urb * pcd_tx_complete_irq (struct usbd_endpoint_instance *endpoint, int restart)
+{
+        struct usbd_urb *tx_urb;
+
+        TRACE_MSG2(PCD, "tx_urb: %x restart: %d", endpoint->tx_urb, restart);
+
+        // if we have a tx_urb advance or reset, finish if complete
+        if ( (tx_urb = endpoint->tx_urb)) {
+
+                struct usbd_bus_instance *bus = tx_urb->bus;
+                struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+
+                TRACE_MSG5(PCD, "BUS_TX CURRENT TX_URB: %p actual: %d sent: %d last: %d: flags: %d", 
+                                (int)endpoint->tx_urb, tx_urb->actual_length, endpoint->sent,
+                                endpoint->last, tx_urb->flags);
+
+                if (likely (!restart)) {
+                        int sent = endpoint->last;
+                        endpoint->sent += sent;
+                        endpoint->last -= sent;
+                }
+                else {
+                        TRACE_MSG0(PCD, "RESTARTING");
+                        endpoint->last = 0;
+                }
+
+                //if ( ( (tx_urb->actual_length - endpoint->sent) <= 0) && ! (tx_urb->flags & USBD_URB_SENDZLP) ) {
+                
+                if ( (endpoint->sent >= tx_urb->actual_length) && ! (tx_urb->flags & USBD_URB_SENDZLP) ) {
+                        tx_urb->jiffies = jiffies;
+                        tx_urb->framenum = pcd_ops.framenum ? pcd_ops.framenum () : 0;
+                        TRACE_MSG2(PCD, "BUS_TX COMPLETE: finished tx_urb: %p framenum: %x", 
+                                        (int)tx_urb, (int)tx_urb->framenum);
+                        usbd_urb_finished_irq (tx_urb, SEND_FINISHED_OK);
+                        endpoint->tx_urb = NULL;
+                        endpoint->last = endpoint->sent = 0;
+                }
+        }
+        return pcd_tx_next_irq (endpoint);
+}
+
+/* ******************************************************************************************* */
+
+/*! pcd_disable - Stop using the USB Device Controller
+ * Stop using the USB Device Controller.
+ * Shutdown and free dma channels, de-register the interrupt handler.
+ */
+void pcd_disable (struct usbd_bus_instance *bus)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        TRACE_MSG0(PCD, "BUS_UDC DISABLE");
+        if (usbd_pcd_ops.disable_ep) usbd_pcd_ops.disable_ep (pcd, 0);
+        pcd_disable_endpoints (bus);
+
+        if (usbd_pcd_ops.disable) usbd_pcd_ops.disable (pcd);
+}
+
+/* ************************************************************************************* */
+/*! bus_framenum 
+ */
+int bus_framenum (void)
+{
+        return (pcd_ops.framenum) ? pcd_ops.framenum () : 0;
+}
+
+/*! bus_interrupts 
+ */
+u64 bus_interrupts (void)
+{
+        return ocd_ops.interrupts;
+}
+
+/*! bus_ticks 
+ */
+u64 bus_ticks (void)
+{
+        return (ocd_ops.ticks) ? ocd_ops.ticks () : 0;
+}
+
+/*! bus_elapsed 
+ */
+u64 bus_elapsed (u64 *t1, u64 *t2)
+{
+        return (ocd_ops.elapsed) ? (ocd_ops.elapsed (t1, t2)) : 0;
+}
+
+/*! pcd_recv_setup_emulate_irq - emulate a device request
+ */
+int pcd_recv_setup_emulate_irq(struct usbd_bus_instance *bus, u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        struct usbd_device_request request;
+
+        TRACE_MSG4(PCD, "bmRequestType: %02x bRequest: %02x wValue: %04x wIndex: %04x", bmRequestType, bRequest, wValue, wIndex);
+        request.bmRequestType = bmRequestType;
+        request.bRequest = bRequest;
+        request.wValue = cpu_to_le16(wValue);
+        request.wIndex = cpu_to_le16(wIndex);
+        request.wLength = cpu_to_le16(wLength);
+        return pcd_recv_setup_irq(pcd, &request);
+}
+
+/*! pcd_check_device_feature - verify that feature is set or clear
+ * Check current feature setting and emulate SETUP Request to set or clear
+ * if required.
+ */
+void pcd_check_device_feature(struct usbd_bus_instance *bus, int feature, int flag)
+{
+        int status = bus->device_feature_settings & (1 << feature);
+        TRACE_MSG2(PCD, "BUS_CHECK FEATURE: feature: %x flag: %x", feature, flag);
+        if (!status && flag)
+                pcd_recv_setup_emulate_irq(bus, USB_REQ_HOST2DEVICE, USB_REQ_SET_FEATURE, feature, 0, 0);
+        else if (status && !flag)
+                pcd_recv_setup_emulate_irq(bus, USB_REQ_HOST2DEVICE, USB_REQ_CLEAR_FEATURE, feature, 0, 0);
+        TRACE_MSG1(PCD, "BUS_CHECK FEATURE: features; %08x", bus->device_feature_settings);
+}
+
+/* ******************************************************************************************* */
+#if !defined(OTG_C99)
+struct usbd_bus_operations bus_ops;
+
+void pcd_global_init(void)
+{
+        ZERO(bus_ops);
+        bus_ops.start_endpoint_in = bus_start_endpoint_in;
+        bus_ops.start_endpoint_out = bus_start_endpoint_out;
+        bus_ops.cancel_urb_irq = bus_cancel_urb_irq;
+        bus_ops.endpoint_halted = bus_endpoint_halted;
+        bus_ops.halt_endpoint = bus_halt_endpoint;
+        bus_ops.set_address = bus_set_address;
+        bus_ops.event_handler = bus_event_handler;
+        bus_ops.request_endpoints = bus_request_endpoints;
+        bus_ops.set_endpoints = bus_set_endpoints;
+        bus_ops.framenum = bus_framenum;
+        bus_ops.ticks = bus_ticks;
+        bus_ops.elapsed = bus_elapsed;
+        bus_ops.interrupts = bus_interrupts;
+        //bus_ops.device_feature = bus_device_feature;
+}
+
+#else /* !defined(OTG_C99) */
+struct usbd_bus_operations bus_ops = {
+        .start_endpoint_in = bus_start_endpoint_in,
+        .start_endpoint_out = bus_start_endpoint_out,
+        .cancel_urb_irq = bus_cancel_urb_irq,
+        .endpoint_halted = bus_endpoint_halted,
+        .halt_endpoint = bus_halt_endpoint,
+        .set_address = bus_set_address,
+        .event_handler = bus_event_handler,
+        .request_endpoints = bus_request_endpoints,
+        .set_endpoints = bus_set_endpoints,
+        .framenum = bus_framenum,
+        .ticks = bus_ticks,
+        .elapsed = bus_elapsed,
+        .interrupts = bus_interrupts,
+        //.device_feature = bus_device_feature,
+};
+#endif /* !defined(OTG_C99) */
+
+
+struct usbd_bus_driver bus_driver = {
+        bops: &bus_ops,
+};
+
+
+
+/* ******************************************************************************************* */
+/* Prevent overlapp of bi administrative functions mainly:
+ *      bus_register_bh
+ *      bus_deregister_bh
+ */ 
+//DECLARE_MUTEX (usbd_bi_sem);     
+struct usbd_bus_instance *usbd_bus;
+
+/*! pcd_startup_events
+ */
+void pcd_startup_events(struct usbd_bus_instance *bus)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        //TRACE_MSG0(PCD, "BI_STARTUP");
+        if (usbd_pcd_ops.startup_events) {
+                TRACE_MSG0(PCD, "BI_STARTUP_EVENTS - udc");
+                usbd_pcd_ops.startup_events(pcd);
+        }
+        else {
+                TRACE_MSG0(PCD, "BI_STARTUP_EVENTS - default");
+                usbd_bus_event_handler_irq (bus, DEVICE_INIT, 0);
+                usbd_bus_event_handler_irq (bus, DEVICE_CREATE, 0);
+                usbd_bus_event_handler_irq (bus, DEVICE_HUB_CONFIGURED, 0);
+                usbd_bus_event_handler_irq (bus, DEVICE_RESET, 0);
+        }
+        //TRACE_MSG0(PCD, "BI_STARTUP: FINISHED");
+}
+
+/*! bus_register_bh
+ */
+void bus_register_bh(void *arg)
+{
+        struct pcd_instance *pcd = arg;
+        struct otg_instance *otg = pcd->otg;
+        struct usbd_bus_instance *bus;
+        struct usbd_endpoint_instance *endpoint;
+        unsigned long flags;
+
+        TRACE_MSG1(PCD, "BUS_REGISTER_BH: pcd: %p", (int)arg);
+        RETURN_UNLESS(pcd);
+
+        TRACE_MSG0(PCD, "BUS_REGISTER_BH");
+
+        bus_driver.name = usbd_pcd_ops.name;
+        bus_driver.max_endpoints = usbd_pcd_ops.max_endpoints;
+        bus_driver.maxpacketsize = usbd_pcd_ops.ep0_packetsize;
+        bus_driver.capabilities = usbd_pcd_ops.capabilities;
+        bus_driver.bMaxPower = usbd_pcd_ops.bMaxPower;
+        bus_driver.ports = usbd_pcd_ops.ports;
+        // XXX bus_driver.otg_bmAttributes = tcd_ops.bmAttributes;
+        bus_driver.otg_bmAttributes = usbd_pcd_ops.bmAttributes;
+
+        TRACE_MSG1(PCD, "BUS_REGISTER_BH UDC Capabilities: %x", bus_driver.capabilities);
+        // XXX TRACE_MSG1(PCD, "BUS_REGISTER_BH UDC OTG Attributes: %x\n", tcd_ops.bmAttributes);
+        TRACE_MSG1(PCD, "BUS_REGISTER_BH UDC OTG Attributes: %x\n", usbd_pcd_ops.bmAttributes);
+
+        // register this bus interface driver and create the device driver instance
+        if (! (bus = usbd_register_bus (&bus_driver, usbd_pcd_ops.ep0_packetsize))) {
+                TRACE_MSG0(PCD, "BUS_REGISTER_BH: register failed");
+                printk (KERN_INFO "%s: failed\n", __FUNCTION__);
+                pcd_disable (NULL);
+                otg_event(pcd->otg, enable_otg_ | PCD_OK, PCD, "BUS_REGISTER_BH");
+                return;
+        }
+
+        bus->privdata = (void *) pcd;
+        pcd->bus = bus;
+
+        //if (usbd_pcd_ops.serial_init ? usbd_pcd_ops.serial_init (pcd) : -EINVAL) {
+        //
+        //}
+        
+        if (serial_number_str && strlen(serial_number_str)) {
+                char *sp, *dp;
+                int i;
+                printk(KERN_INFO"%s:\n", __FUNCTION__);
+                printk(KERN_INFO"%s: serial_number_str: %s\n", __FUNCTION__, serial_number_str);
+                TRACE_MSG1(PCD, "prm serial_number_str: %s", serial_number_str);
+                for (sp = serial_number_str, dp = otg->serial_number, i = 0;
+                                *sp && (i < (sizeof(otg->serial_number) - 1)); i++, sp++)
+                        if (isxdigit(*sp)) *dp++ = toupper(*sp);
+        }
+
+
+        TRACE_MSG1(PCD, "otg serial_number_str: %s", pcd->otg->serial_number);
+        TRACE_MSG0(PCD, "BUS_REGISTER_BH: usbd_enable_function_irq");
+
+        if (usbd_enable_function_irq (bus, pcd->otg->function_name, pcd->otg->serial_number)) {
+                TRACE_MSG0(PCD, "BUS_REGISTER_BH: enable function failed");
+                printk (KERN_INFO "%s: failed\n", __FUNCTION__);
+                pcd_disable (NULL);
+                otg_event(pcd->otg, enable_otg_ | PCD_OK, PCD, "BUS_REGISTER_BH");
+                return;
+        }
+
+        // setup endpoint zero
+        endpoint = bus->endpoint_array + 0;
+        endpoint->bEndpointAddress = 0;
+
+        //endpoint->tx_attributes = 0;
+        //
+
+        endpoint->wMaxPacketSize = usbd_pcd_ops.ep0_packetsize;
+        endpoint->rcv_transferSize = 4096;       // XXX should this be higher
+        endpoint->wMaxPacketSize = usbd_pcd_ops.ep0_packetsize;
+        if (usbd_pcd_ops.setup_ep) usbd_pcd_ops.setup_ep (pcd, 0, endpoint);
+
+        TRACE_MSG0(PCD, "BUS_REGISTER_BH: startup");
+
+        // hopefully device enumeration will finish this process
+        // XXX should this move to pcd_en?
+        pcd_startup_events (bus);
+        TRACE_MSG0(PCD, "BUS_REGISTER_BH: FINISHED - sending PCD_OK");
+        //MOD_INC_USE_COUNT;
+        otg_event(pcd->otg, PCD_OK, PCD, "BUS_REGISTER_BH PCD_OK");
+}
+
+/*! bus_deregister_bh
+ */
+void bus_deregister_bh(void *arg)
+{
+        struct pcd_instance *pcd = arg;
+        struct usbd_bus_instance *bus;
+        struct bus_data *data;
+        unsigned long flags;
+
+        //TRACE_MSG1(PCD, "BUS_DEREGISTER_BH: pcd: %x", pcd);
+        if (pcd && (bus = pcd->bus) && (usbd_bus_state_enabled == bus->bus_state)) {
+
+                if (usbd_pcd_ops.disable) usbd_pcd_ops.disable (pcd);
+
+                if (bus->device_state != STATE_ATTACHED) {
+                        usbd_bus_event_handler_irq (bus, DEVICE_RESET, 0);
+                        usbd_bus_event_handler_irq (bus, DEVICE_POWER_INTERRUPTION, 0);
+                        usbd_bus_event_handler_irq (bus, DEVICE_HUB_RESET, 0);
+                }
+                usbd_bus_event_handler_irq (bus, DEVICE_DESTROY, 0);
+                pcd_disable_endpoints (bus);
+                pcd_disable (bus);
+
+                usbd_disable_function (bus);
+                bus->bus_state = usbd_bus_state_disabled;
+
+                //TRACE_MSG1(PCD, "%s: BI_SEM UP", (int)__FUNCTION__);
+                //otg_event(pcd->otg, exit_ok, "BUS_DISABLE EXIT_OK");
+
+                //if (bus->serial_number_str)
+                //        lkfree (pcd->bus->serial_number_str);
+
+                usbd_deregister_bus (bus);
+                pcd->bus = NULL;
+
+                TRACE_MSG0(PCD, "BUS_DEREGISTER_BH: FINISHED - sending PCD_OK");
+                //MOD_DEC_USE_COUNT;
+        }
+        otg_event(pcd->otg, PCD_OK, PCD, "BUS_DEREGISTER_BH PCD_OK");
+}
+
+/* ************************************************************************************* */
+
+
+/*! pcd_en_func - enable
+ *
+ * This is called to enable / disable the PCD and USBD stack.
+ */
+void pcd_en_func (struct otg_instance *otg, u8 flag)
+{
+        struct pcd_instance *pcd = otg->pcd;
+        struct usbd_bus_instance *bus = pcd->bus;
+
+        //TRACE_MSG0(PCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(PCD, "PCD_EN: SET");
+#ifdef CONFIG_OTG_DB1550_J15
+                int ret = au_readl(SYS_PINFUNC);
+                au_writel((ret | 0x8000),SYS_PINFUNC);
+                ret = au_readl(SYS_PINFUNC);
+                TRACE_MSG1(PCD, "Set the OTG for device mode (sys_pfunc = %04x)", ret);
+#endif
+                // check if we can see the UDC and register, then enable the function
+                if (usbd_pcd_ops.enable) usbd_pcd_ops.enable (pcd);
+                //BREAK_IF (pcd_enable_irq (bus));
+                //BREAK_IF (usbd_enable_function_irq (bus, otg->function_name));
+
+                // XXX should this move to here
+                // pcd_startup_events (bus);
+                break;
+
+        case RESET:
+                TRACE_MSG0(PCD, "PCD_EN: RESET");
+                usbd_bus_event_handler_irq (bus, DEVICE_RESET, 0);
+                TRACE_MSG0(PCD, "PCD_EN: DESTROY");
+                usbd_bus_event_handler_irq (bus, DEVICE_DESTROY, 0);
+                TRACE_MSG0(PCD, "PCD_EN: FINISHED");
+                // XXX need to set a flag here
+                break;
+        }
+}
+
+/*! pcd_init_func - per peripheral controller common initialization
+ *
+ * This is called to initialize / de-initialize the PCD and USBD stack.
+ *
+ * We start work items to do this.
+ *
+ */
+void pcd_init_func (struct otg_instance *otg, u8 flag)
+{
+        struct pcd_instance *pcd = otg->pcd;
+        struct usbd_bus_instance *bus = pcd->bus;
+        //struct bus_data *data = NULL;
+
+        //printk(KERN_INFO"%s:\n", __FUNCTION__);
+
+        //TRACE_MSG0(PCD, "--");
+        switch (flag) {
+        case SET:
+                TRACE_MSG0(PCD, "PCD_INIT: SET");
+                PREPARE_WORK_ITEM(pcd->bh, bus_register_bh, pcd);
+                SCHEDULE_WORK(pcd->bh);
+                TRACE_MSG0(PCD, "BUS_REGISTER_SCHEDULE: finished");
+                break;
+
+        case RESET:
+                TRACE_MSG0(PCD, "PCD_INIT: RESET");
+                PREPARE_WORK_ITEM(pcd->bh, bus_deregister_bh, pcd);
+                SCHEDULE_WORK(pcd->bh);
+        }
+}
+
diff -uNr linux/drivers/no-otg/ocd/otg-pcd/tr-init-l24.c linux/drivers/otg/ocd/otg-pcd/tr-init-l24.c
--- linux/drivers/no-otg/ocd/otg-pcd/tr-init-l24.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/otg-pcd/tr-init-l24.c	2006-09-01 21:41:32.000000000 +0200
@@ -0,0 +1,234 @@
+/*
+ * otg/ocd/otg-pcd/tr-init-l24.c - Traditional Device Peripheral and OTG Controller Drivers Module Initialization
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/ocd/otg-pcd/tr-init-l24.c
+ * @brief Traditional device driver init.
+ *
+ * TR OTG PCD/OCD/TCD Initialization
+ *
+ * This file initializes all of the low level hardware drivers for a traditional device.
+ *
+ * Traditional USB Devices must implement the following:
+ *
+ *      ocd_ops         operations from ocd driver
+ *      pcd_ops         operations from pcd driver
+ *      tcd_ops         operations from tcd driver
+ *
+ * The OTG Controller driver (ocd) implements any required OTG timers and if
+ * necessary mediates access to and initializes the OTG and/or USB hardware.
+ *
+ * The Peripheral Controller Driver (pcd) implements the lowest layer of the
+ * USBD stack to send and receive data from the USB actings as a USB
+ * peripheral.
+ *
+ * The Transceiver Controller Driver (tcd) implements control of the OTG or
+ * USB transceiver. At a minimum for a traditional device this should
+ * implement VBUS sensing (sometimes known as cable detect) and where
+ * possible control over the DP+ pullup resistor.
+ *
+ *
+ * Notes
+ *
+ * 1. This is the linux 2.4 version.
+ *
+ * 2. This will optionally do an auto start with TR_INIT if the OCD_CAPBILITIES_AUTO
+ * flag is set.
+ *
+ * TODO
+ *
+ * 1. hook up serial_number_str to pcd.c for use with bus interface layer.
+ *
+ * @ingroup OTGPCD
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-pcd.h>
+#include <otg/otg-ocd.h>
+
+EMBED_LICENSE();
+
+MOD_PARM (serial_number_str, "s");
+MOD_PARM_DESC (serial_number_str, "Serial Number");
+MOD_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
+MOD_DESCRIPTION ("Traditional USB Device");
+
+char *serial_number_str;
+
+otg_tag_t OCD;
+struct ocd_instance *ocd_instance;
+
+otg_tag_t PCD;
+struct pcd_instance *pcd_instance;
+
+otg_tag_t TCD;
+struct tcd_instance *tcd_instance;
+
+
+/* ************************************************************************************* */
+
+/* tr_ocd_start_timer
+ * Fake - Set or reset timer to interrupt in number of uS (micro-seconds). 
+ * This is only suitable for MN or TR firmware.
+ */
+int tr_ocd_start_timer(struct otg_instance *otg, int usec)
+{
+        otg_event(otg, TMOUT, OCD, "FAKE TMOUT");
+        return 0;
+}
+
+/* ************************************************************************** */
+/* tr_tcd_en_func - used to enable or disable transciever
+ *
+ */
+void tr_tcd_en_func(struct otg_instance *otg, u8 flag)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *) otg->pcd;
+        struct usbd_bus_instance *bus = pcd->bus;
+
+        //printk(KERN_INFO"%s: start\n", __FUNCTION__);
+        TRACE_MSG0(TCD, "--");
+        TRACE_MSG2(TCD, "pcd: %x bus: %x", pcd, pcd->bus);
+
+        switch (flag) {
+        case PULSE:
+        case SET:
+                TRACE_MSG0(TCD, "TR_TCD_EN SET");
+                /* enable clock interrupt */
+                otg_event_set_irq(tcd_instance->otg, 1, 1, B_SESS_VLD, TCD, "B_SESS_VLD");
+                break;
+        case RESET:
+                TRACE_MSG0(TCD, "TR_TCD_EN RESET");
+                /* disable clock interrupt */
+                break;
+        }
+//        TRACE_MSG2(TCD, "ep0 endpoint: %x bEndpointAddress: %02x BBB", bus->ep0->endpoint_map_array->endpoint,
+ //                       bus->ep0->endpoint_map_array->endpoint->bEndpointAddress);
+}
+
+
+/* ************************************************************************** */
+
+/* tr_modexit - This is used as module exit, and as cleanup if modinit fails.
+ *
+ * Specifically for each driver:
+ *
+ * 	call ops.mod_exit
+ * 	reset instance address and  ops table address in state machine to NULL
+ * 	invalidate tag
+ */
+static void tr_modexit (void)
+{
+        struct otg_instance *otg = ocd_instance->otg;
+        printk(KERN_INFO"%s\n", __FUNCTION__);
+
+        TRACE_MSG1(TCD, "otg: %x", otg);
+        if (otg) {
+                TRACE_MSG0(TCD, "Calling otg_exit()");
+                otg_exit(otg);
+                TRACE_MSG0(TCD, "back from otg_exit()");
+        } 
+        else
+                TRACE_MSG0(TCD, "did not call otg_exit()");
+
+#if 0
+        if ((ocd_ops.capabilities & OCD_CAPABILITIES_TR) && (ocd_ops.capabilities & OCD_CAPABILITIES_AUTO)) {
+                printk(KERN_INFO"%s calling otg_admin\n",__FUNCTION__);
+                otg_admin("exit_all", "Traditional Device Auto TR_INIT");
+        }
+#endif
+
+        if (tcd_ops.mod_exit) tcd_ops.mod_exit();
+        if (ocd_ops.mod_exit) ocd_ops.mod_exit();
+        if (pcd_ops.mod_exit) pcd_ops.mod_exit();
+
+        tcd_instance = otg_set_tcd_ops(NULL);
+        ocd_instance = otg_set_ocd_ops(NULL);
+        pcd_instance = otg_set_pcd_ops(NULL);
+
+        TCD = otg_trace_invalidate_tag(TCD);
+        OCD = otg_trace_invalidate_tag(OCD);
+        PCD = otg_trace_invalidate_tag(PCD);
+        printk(KERN_INFO"%s finished\n", __FUNCTION__);
+}
+
+
+/* tr_modinit - linux module initialization
+ *
+ * This needs to initialize the ocd, pcd and tcd drivers.  
+ *
+ * Specifically for each driver:
+ *
+ * 	obtain tag
+ * 	pass ops table address to state machine and get instance address
+ * 	call ops.mod_init
+ *
+ */
+static int tr_modinit (void)
+{
+        struct otg_instance *otg;
+        printk(KERN_INFO"%s\n", __FUNCTION__);
+
+        #if !defined(OTG_C99)
+        pcd_global_init();
+        #endif /* !defined(OTG_C99) */
+
+        /* For each of ocd, pcd and tcd do:
+         * 
+         *      get tag
+         *      update ops table with default functions where possible
+         *      do otg_set_xxx_ops() as appropriate
+         *      call xxx_ops.mod_init as appropriate
+         */
+        
+        OCD = otg_trace_obtain_tag();
+        PCD = otg_trace_obtain_tag();
+        TCD = otg_trace_obtain_tag();
+
+        UNLESS(ocd_ops.start_timer) ocd_ops.start_timer = tr_ocd_start_timer;
+        UNLESS(pcd_ops.pcd_init_func) pcd_ops.pcd_init_func = pcd_init_func;
+        UNLESS(pcd_ops.pcd_en_func) pcd_ops.pcd_en_func = pcd_en_func;
+        UNLESS(tcd_ops.tcd_en_func) tcd_ops.tcd_en_func = tr_tcd_en_func;
+
+        THROW_IF((ocd_ops.mod_init) ? ocd_ops.mod_init() : 0, error);
+        THROW_IF((pcd_ops.mod_init) ? pcd_ops.mod_init() : 0, error);
+        THROW_IF((tcd_ops.mod_init) ? tcd_ops.mod_init() : 0, error);
+
+        THROW_UNLESS(ocd_instance = otg_set_ocd_ops(&ocd_ops), error);
+        THROW_UNLESS(pcd_instance = otg_set_pcd_ops(&pcd_ops), error);
+        THROW_UNLESS(tcd_instance = otg_set_tcd_ops(&tcd_ops), error);
+
+        THROW_UNLESS(ocd_instance && (otg = ocd_instance->otg), error);
+
+        CATCH(error) {
+                tr_modexit();
+                return -EINVAL;
+        }
+        /* Success!
+         */
+        otg_init(otg);
+#if 0
+        otg_start(otg, ocd_ops.capabilities & OCD_CAPABILITIES_TR);
+#endif
+        return 0;
+}
+
+module_init(tr_modinit);
+MOD_EXIT (tr_modexit);
+
diff -uNr linux/drivers/no-otg/ocd/otg-tcd/tcd-init-l24.c linux/drivers/otg/ocd/otg-tcd/tcd-init-l24.c
--- linux/drivers/no-otg/ocd/otg-tcd/tcd-init-l24.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/otg-tcd/tcd-init-l24.c	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,95 @@
+/*
+ * otg/ocd/otg-tcd/tcd-init-l24.c - OTG Transceiver Controller Driver Module Initialization
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcara.com>, 
+ *      Tom Rushworth <tbr@belcara.com>, 
+ *      Bruce Balden <balden@belcara.com>
+ *
+ */
+/*!
+ * @file otg/ocd/otg-tcd/tcd-init-l24.c
+ * @brief PCD only driver init.
+ *
+ * OTG TCD Initialization
+ *
+ * This file initializes the low level hardware drivers.
+ *
+ * This is the linux 2.4 version.
+ *
+ * @ingroup OTGTCD
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-pcd.h>
+
+
+#ifdef MODULE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,4,17)
+MODULE_LICENSE ("GPL");
+#endif
+MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
+MODULE_DESCRIPTION ("USB On-The-Go TCD");
+#endif
+
+otg_tag_t TCD;
+
+extern struct tcd_ops tcd_ops;
+struct tcd_instance *tcd_instance;
+
+//extern void db1550_tcd_global_init(void);
+
+/* ************************************************************************************* */
+
+/* tcd_modexit - This is *only* used for drivers compiled and used as a module.
+ */
+static void tcd_modexit (void)
+{
+        struct otg_instance *otg = tcd_instance->otg;
+        //printk(KERN_INFO"%s\n", __FUNCTION__);
+
+        if (otg)
+                otg_exit(otg);
+
+        if (tcd_ops.mod_exit) tcd_ops.mod_exit();
+        tcd_instance = otg_set_tcd_ops(NULL);
+        otg_trace_invalidate_tag(TCD);
+}
+
+/* otg_modinit - linux module initialization
+ *
+ * This needs to initialize the hcd, pcd and tcd drivers. This includes tcd and possibly hcd
+ * for some architectures.
+ *
+ */
+static int tcd_modinit (void)
+{
+	printk(KERN_INFO"Initilize the tcd structure\n");
+//	db1550_tcd_global_init();
+        TCD = otg_trace_obtain_tag();
+        THROW_UNLESS(tcd_instance = otg_set_tcd_ops(&tcd_ops), error);
+        THROW_IF((tcd_ops.mod_init) ? tcd_ops.mod_init() : 0, error);
+        //printk(KERN_INFO"%s finish\n", __FUNCTION__);
+
+        TRACE_MSG0(TCD, "--");
+
+        CATCH(error) {
+                tcd_modexit();
+                return -EINVAL;
+        }
+        return 0;
+}
+
+module_init (tcd_modinit);
+module_exit (tcd_modexit);
+
diff -uNr linux/drivers/no-otg/ocd/otg-tcd/tcd.c linux/drivers/otg/ocd/otg-tcd/tcd.c
--- linux/drivers/no-otg/ocd/otg-tcd/tcd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/ocd/otg-tcd/tcd.c	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,55 @@
+/*
+ * otg/ocd/otg-tcd/tcd.c - OTG Transceiver Controller Driver
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcara.com>, 
+ *      Tom Rushworth <tbr@belcara.com>, 
+ *      Bruce Balden <balden@belcara.com>
+ *
+ */
+/*!
+ * @file otg/ocd/otg-tcd/tcd.c
+ * @brief TCD Support
+ * Notes
+ *
+ * @ingroup OTGTCD
+ */
+
+#include <otg/otg-compat.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-pcd.h>
+
+extern struct tcd_ops tcd_ops;
+
+/* ************************************************************************************* */
+void tcd_cable_event_irq (struct otg_instance *otg)
+{
+        TRACE_MSG1(TCD, "TCD_CABLE_EVENT: vbus: %d", tcd_vbus(otg));
+        otg_event(otg, VBUS_VLD, TCD, "CABLE");
+        //otg_b_sess_vld(otg, 1, tcd_vbus (otg), "Cable Event");
+}
+
+void tcd_cable_event (struct otg_instance *otg)
+{
+        unsigned long flags;
+        local_irq_save (flags);
+        tcd_cable_event_irq (otg);
+        local_irq_restore (flags);
+}
+
+/* ************************************************************************************* */
+int tcd_vbus (struct otg_instance *otg)
+{
+        TRACE_MSG0(TCD, "OCD VBUS");
+        return tcd_ops.vbus ? tcd_ops.vbus (otg) : 1;
+}
+
+
diff -uNr linux/drivers/no-otg/otg/hcd-hw.h linux/drivers/otg/otg/hcd-hw.h
--- linux/drivers/no-otg/otg/hcd-hw.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/hcd-hw.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,101 @@
+/*
+ * otg/hcd/hc_xfer_hw.h - Generic transfer level USBOTG aware Host Controller Driver (HCD)
+ *
+ *      Copyright (c) 2004 Belcarra Technologies
+ *
+ * By:
+ *      Tom Rushworth <tbr@belcara.com>,
+ *      Stuart Lynne <sl@belcara.com>,
+ *      Bruce Balden <balden@belcara.com>
+ *
+ */
+/*!
+ * @file otg/otg/hcd-hw.h
+ * @brief Implements Generic Host Controller Driver
+ *
+ * @ingroup OTGHCD
+ */
+#ifndef HC_XFER_HW_H
+#define HC_XFER_HW_H 1
+
+/*===========================================================================*
+ * Functions provided by the hardware specific component (whatever HW it is).
+ * Each HW specific component provides these functions.
+ *===========================================================================*/
+
+/*===========================================================================*
+ * For the generic transfer aware framework.
+ *===========================================================================*/
+
+/*
+ * hcd_hw_max_active_transfers()
+ * Returns: the (constant) maximum number of concurrently active transfers the HW will handle.
+ */
+extern int hcd_hw_max_active_transfers(struct bus_hcpriv *bus_hcpriv);
+
+/*
+ * hcd_hw_start_transfer()
+ * Returns: tid >= 0  when the transfer starts - this is an index in [0..hcd_hw_max_active_transfers]
+ *          -1        when the transfer is invalid,
+ *          -2        when there are no resources for the transfer currently available.
+ */
+extern int hcd_hw_start_transfer(struct bus_hcpriv *bus_hcpriv,
+                                 int len,       // length of data region
+                                 void *data,    // virtual address of data region
+                                 int toggle,    // toggle value to start the xfer with
+                                 int maxps,     // max packet size of endpoint
+                                 int slow,      // 1 ==> slow speed, 0 ==> full speed  QQSV verify: (((urb->pipe) >> 26) & 1)
+                                 int endpoint,  // endpoint number
+                                 int address,   // USB device address
+                                 int pid,       // {PID_OUT, PID_IN, PID_SETUP}
+                                 int format,    // PIPE_{CONTROL,BULK,INTERRUPT,ISOCHRONOUS}
+                                 u32 other);    // Values depending on format
+
+/*
+ * hcd_hw_unlink_urb()
+ * Called in irq_lock, calls back to xhc_transfer_complete().
+ * Returns: 0     when transfer is unlinked, non-zero otherwise.
+ */
+extern int hcd_hw_unlink_urb(struct bus_hcpriv *bus_hcpriv, int tid); // tid is value returned by hcd_hw_start_transfer()
+
+extern u32 hcd_hw_frame_number(struct bus_hcpriv *bus_hcpriv);
+
+extern void hcd_hw_enable_interrupts(struct bus_hcpriv *bus_hcpriv);
+extern void hcd_hw_disable_interrupts(struct bus_hcpriv *bus_hcpriv);
+
+extern void hcd_hw_get_ops(struct bus_hcpriv *bus_hcpriv);
+
+extern int hcd_hw_init(struct bus_hcpriv *bus_hcpriv);
+
+extern void hcd_hw_exit(struct bus_hcpriv *bus_hcpriv);
+
+/*===========================================================================*
+ * For the virtual root hub.
+ *===========================================================================*/
+
+extern int hcd_hw_rh_num_ports(struct bus_hcpriv *bus_hcpriv);
+extern u8 hcd_hw_rh_otg_capable_mask(struct bus_hcpriv *bus_hcpriv);
+
+extern char *hcd_hw_rh_string(struct bus_hcpriv *bus_hcpriv, int strno);
+extern u16 hcd_hw_rh_idVendor(struct bus_hcpriv *bus_hcpriv);
+extern u16 hcd_hw_rh_idProduct(struct bus_hcpriv *bus_hcpriv);
+extern u16 hcd_hw_rh_bcdDevice(struct bus_hcpriv *bus_hcpriv);
+extern u8 hcd_hw_rh_cfg_bmAttributes(struct bus_hcpriv *bus_hcpriv);
+extern u8 hcd_hw_rh_cfg_MaxPower(struct bus_hcpriv *bus_hcpriv);
+extern u16 hcd_hw_rh_hub_attributes(struct bus_hcpriv *bus_hcpriv);
+extern u8 hcd_hw_rh_power_delay(struct bus_hcpriv *bus_hcpriv);
+extern u8 hcd_hw_rh_hub_contr_current(struct bus_hcpriv *bus_hcpriv);
+extern u8 hcd_hw_rh_DeviceRemovable(struct bus_hcpriv *bus_hcpriv);
+extern u8 hcd_hw_rh_PortPwrCtrlMask(struct bus_hcpriv *bus_hcpriv);
+extern u32 hcd_hw_rh_get_hub_change_status(struct bus_hcpriv *bus_hcpriv);
+extern void hcd_hw_rh_hub_feature(struct bus_hcpriv *bus_hcpriv, int feat_selector, int set_flag);
+extern void hcd_hw_hcd_en_func(struct otg_instance *oi, u8 on);
+/*
+ * Note: in the following functions, portnum is 0-origin.
+ * (I.e., valid range is [0..(hcd_hw_rh_num_ports-1)].)
+ */
+extern u32 hcd_hw_rh_get_port_change_status(struct bus_hcpriv *bus_hcpriv, int portnum);
+extern void hcd_hw_rh_port_feature(struct bus_hcpriv *bus_hcpriv, u16 wValue, u16 wIndex, int set_flag);
+
+
+#endif
diff -uNr linux/drivers/no-otg/otg/hcd-l26.h linux/drivers/otg/otg/hcd-l26.h
--- linux/drivers/no-otg/otg/hcd-l26.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/hcd-l26.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,119 @@
+/*
+ * otg/hcd/hc_xfer.h - Generic transfer level USBOTG aware Host Controller Driver (HCD)
+ *
+ *      Copyright (c) 2004 Belcarra Technologies
+ *
+ * By:
+ *      Stuart Lynne <sl@belcara.com>,
+ *      Tom Rushworth <tbr@belcara.com>,
+ *      Bruce Balden <balden@belcara.com>
+ *
+ */
+/*!
+ * @file otg/otg/hcd-l26.h
+ * @brief Implements Linux version of Generic Host Controller driver
+ *
+ * @ingroup OTGHCD
+ */
+#ifndef HC_XFER_H
+#define HC_XFER_H 1
+
+/*===========================================================================*
+ * Data structures and functions provided by the generic transfer aware
+ * host controller framework.
+ *
+ * The generic framework must be linked with a hardware specific component,
+ * whose functions are specified in hc_xfer_hw.h, and a generic root hub
+ * component, whose functions are specified in hc_xfer_rh.h.
+ *
+ * The resulting module provides a table of operations to the usb core layer,
+ * passed to the core layer by a call to usb_alloc_bus().
+ *===========================================================================*/
+
+#define XHC_RH_DESCRIPTORS_SIZE (USB_DT_DEVICE_SIZE+USB_DT_CONFIG_SIZE+USB_DT_INTERFACE_SIZE+USB_DT_ENDPOINT_SIZE+USB_DT_HUB_NONVAR_SIZE+2)
+
+typedef struct rh_hcpriv {
+        struct urb *int_urb;
+        struct usbd_device_descriptor *dd;
+        struct usbd_configuration_descriptor *cd;
+        struct usbd_interface_descriptor *id;
+        struct usbd_endpoint_descriptor *ed;
+        struct hub_descriptor *hd;
+        struct timer_list poll_timer;
+        //int poll_jiffies;
+        struct usb_device *dev;
+        int dev_registered;
+        u32 hub_change_status;   // For shadowing the HW
+        u32 *port_change_status; // An array of [num_ports] values for shadowing the HW
+        u32 hub_port_change_status;
+        struct WORK_STRUCT psc_bh;
+        u8 curr_cfg;
+        u8 curr_itf;
+        //u8 num_ports;
+        u8 otg_device_mask;   // (1 << port_num) bit set iff port_num is acting as a device, not host, and so not usable
+        u8 descriptors[XHC_RH_DESCRIPTORS_SIZE];
+        int suspended;
+} rh_hcpriv_t;
+
+typedef struct bus_hcpriv {          // XFER level Host Controller Info
+        struct usb_bus *usb_bus;
+        void *hw_hci;              // HW specific information for this HC
+        int root_hub_addr;         // Initially 0, set by the virtual root hub when addressed.
+        struct rh_hcpriv *rh_hcpriv;          // Generic root hub info (see hc_xfer_rh.[hc])
+        int terminating;           // Boolean, TRUE if shutting down.
+        //struct hcd_instance *hcd;  // OTG Controller Info
+        int max_active_urbs;
+        struct urb **active_urbs;
+        int device_registered;     // bus_device status
+        struct device bus_device;      // Linux Driver Model info.
+        //struct hcd_ops otg_ops;    // operations for OTG component.
+        struct usb_driver *usb_driver;
+
+        u8 num_ports;
+        u8 otg_port;
+        u8 otg_capable_mask;
+        u16 rh_vendorid;
+        u16 rh_productid;
+        u16 rh_bcddevice;
+        char *rh_serial;
+        char *rh_product;
+        char *rh_manufacturer;
+        u8 rh_bmAttributes;
+        u8 rh_bMaxPower;
+
+        struct usb_device *roothub_dev;
+        struct usb_device *first_dev;
+
+        int max_active_transfers;
+
+} bus_hcpriv_t;
+
+typedef struct dev_hcpriv {      // XFER level HCI per attached device info
+        struct usb_device *dev;
+        struct list_head queued_urbs_both[2][16];
+        u32 num_urbs_both[2][16];
+        u8 epq_state_both[2][16];
+} dev_hcpriv_t;
+
+#define EPQ_EMPTY         0
+#define EPQ_RUNNING       1
+#define EPQ_WAITING       2
+
+/*===========================================================================*
+ * For the hardware specific component.
+ *===========================================================================*/
+
+extern void hcd_transfer_complete(struct bus_hcpriv *bus_hcpriv, int transfer_id, int format,
+                                  int cc, u32 remaining, int next_toggle);
+
+/*===========================================================================*
+ * For the virtual root hub.
+ *===========================================================================*/
+
+extern void hcd_rh_urb_complete(struct bus_hcpriv *bus_hcpriv, struct urb *urb);
+
+#include "../otg/otg-trace.h"
+extern otg_tag_t xfer_hci_trace_tag;
+
+
+#endif
diff -uNr linux/drivers/no-otg/otg/hcd-rh.h linux/drivers/otg/otg/hcd-rh.h
--- linux/drivers/no-otg/otg/hcd-rh.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/hcd-rh.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,55 @@
+/*
+ * otg/hcd/hc_xfer_rh.h - Generic transfer level USBOTG aware Host Controller Driver (HCD)
+ *
+ *      Copyright (c) 2004 Belcarra Technologies
+ *
+ * By:
+ *      Stuart Lynne <sl@belcara.com>,
+ *      Tom Rushworth <tbr@belcara.com>,
+ *      Bruce Balden <balden@belcara.com>
+ *
+ */
+/*!
+ * @file otg/otg/hcd-rh.h
+ * @brief Implements Generic Root Hub function for Generic Host Controller Driver.
+ *
+ * @ingroup OTGHCD
+ */
+#ifndef HC_XFER_RH_H
+#define HC_XFER_RH_H 1
+
+#define XHC_RH_STRING_CONFIGURATION 1
+#define XHC_RH_STRING_INTERFACE     2
+#define XHC_RH_STRING_SERIAL        3
+#define XHC_RH_STRING_PRODUCT       4
+#define XHC_RH_STRING_MANUFACTURER  5
+
+/*===========================================================================*
+ * Functions provided by the generic virtual root hub.
+ *===========================================================================*/
+
+/*===========================================================================*
+ * For the generic transfer aware framework.
+ *===========================================================================*/
+
+/*
+ * hcd_rh_submit_urb()
+ * Returns: values as for the generic submit_urb() function.
+ */
+extern int hcd_rh_submit_urb(struct bus_hcpriv *bus_hcpriv, struct urb *urb, int mem_flags);
+
+extern int hcd_rh_unlink_urb(struct bus_hcpriv *bus_hcpriv, struct urb *urb);
+
+extern void hcd_rh_get_ops(struct bus_hcpriv *bus_hcpriv);
+
+extern int hcd_rh_init(struct bus_hcpriv *bus_hcpriv);
+
+extern void hcd_rh_exit(struct bus_hcpriv *bus_hcpriv);
+
+/*===========================================================================*
+ * For the hardware specific root hub component.
+ *===========================================================================*/
+
+extern irqreturn_t hcd_rh_int_hndlr(int irq, void *dev_id, struct pt_regs *regs);
+
+#endif
diff -uNr linux/drivers/no-otg/otg/otg-api.h linux/drivers/otg/otg/otg-api.h
--- linux/drivers/no-otg/otg/otg-api.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-api.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,233 @@
+/*
+ * otg/otg-api.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*
+ * Doxygen group definitions - N.B. These much each be in
+ * their own separate comment...
+ */
+/*!
+ * @defgroup onthegogroup On-The-Go
+ */
+/*!
+ * @defgroup functiongroup Function Drivers
+ */
+/*!
+ * @defgroup tcdgroup Transceiver Controller Drivers
+ */
+/*!
+ * @defgroup pcdgroup Peripheral Controller Drivers
+ */
+/*!
+ * @defgroup libgroup Architecture Libraries
+ */
+/*!
+ * @defgroup platformgroup Platform Drivers
+ */
+
+
+/*!
+ * @defgroup OTGCore Core
+ * @ingroup onthegogroup
+ */
+
+/*!
+ * @file otg/otg/otg-api.h
+ * @brief Core Defines for USB OTG Core Layaer
+ *
+ * @ingroup OTGCore
+ */
+
+/*!
+ * @name OTGCORE OTG API Definitions
+ * This contains the OTG API structures and definitions.
+ * @{
+ */
+
+#include <otg/otg-fw.h>
+
+#ifdef CONFIG_OTG_FW_MN
+#include <otg/otg-fw-mn.h>
+#else /* CONFIG_OTG_FW_MN */                     
+#include <otg/otg-fw-df.h>
+#endif /* CONFIG_OTG_FW_MN */                     
+
+
+struct otg_instance;
+typedef void (*otg_output_proc_t) (struct otg_instance *, u8);
+
+extern struct otg_firmware *otg_firmware_loaded;
+extern struct otg_firmware *otg_firmware_orig;
+extern struct otg_firmware *otg_firmware_loading;
+
+
+char * otg_get_state_name(int state);
+
+/*!
+ * @struct otg_instance
+ *
+ * This tracks the current OTG configuration and state
+ */
+struct otg_instance {
+
+        u16                     state;                  /*!< current state      */
+        int                     previous;               /*!< previous state     */
+
+        int                     active;                 /*!< used as semaphore  */
+
+        u32                     current_inputs;         /*!< input settings     */
+        u64                     outputs;                /*!< output settings    */
+
+        u64                     tickcount;              /*!< when we transitioned to current state      */
+        u64                     bconn;                  /*!< when b_conn was set        */
+
+        struct otg_state       *current_outputs;       /*!< output table entry for current state        */
+        struct otg_state       *previous_outputs;      /*!< output table entry for current state        */
+
+        otg_output_proc_t       otg_output_ops[MAX_OUTPUTS]; /*!< array of functions mapped to output numbers */
+
+        int                     (*start_timer) (struct otg_instance *, int); /*!< OCD function to start timer */
+        u64                     (*ticks) (void);        /*!< OCD function to return ticks */
+        u64                     (*elapsed) ( u64 *, u64 *); /*!< OCD function to return elapsed ticks */
+
+        void *                  hcd;                    /*!< pointer to hcd instance */
+        void *                  ocd;                    /*!< pointer to ocd instance */
+        void *                  pcd;                    /*!< pointer to pcd instance */
+        void *                  tcd;                    /*!< pointer to tcd instance */
+
+        char                    function_name[OTGADMIN_MAXSTR]; /*!< current function */
+        char                    serial_number[OTGADMIN_MAXSTR]; /*!< current serial number */
+};
+
+typedef int (*otg_event_t) (struct otg_instance *, int, char *);
+
+struct otg_event_info {
+        char *name;
+        otg_event_t event;
+};
+
+
+/* 1 - used by external functions to pass in administrative commands as simple strings
+ */
+extern int otg_status(int, u32, u32, char *, int);
+extern void otg_message(char *);
+                                        
+/* 2 - used internally by any OTG stack component to single event from interrupt context
+ */
+extern int otg_event_irq(struct otg_instance *, u64, otg_tag_t, char *);
+                                        
+/* 3 - used internally by any OTG stack component to single event from non-interrupt context,
+ */
+extern int otg_event(struct otg_instance *, u64, otg_tag_t, char *);
+
+/* 5 - used by PCD/TCD drivers to signal various OTG Transceiver events
+ */
+int otg_event_set_irq(struct otg_instance *, int, int, u32, otg_tag_t, char *);
+
+
+extern void otg_init (struct otg_instance *otg);
+extern void otg_exit (struct otg_instance *otg);
+
+/* message 
+ */
+#if defined(OTG_LINUX)
+extern int otg_message_init_l24(struct otg_instance *);
+extern void otg_message_exit_l24(void);
+#endif /* defined(OTG_LINUX) */
+
+#if defined(OTG_WINCE)
+extern int otg_message_init_w42(struct otg_instance *);
+extern void otg_message_exit_w42(void);
+#endif /* defined(OTG_WINCE) */
+
+extern int otg_message_init(struct otg_instance *);
+extern void otg_message_exit(void);
+
+extern int otg_write_message_irq(char *buf, int size);
+extern int otg_write_message(char *buf, int size);
+extern int otg_read_message(char *buf, int size);
+extern int otg_data_queued(void);
+extern unsigned int otg_message_block(void);
+extern unsigned int otg_message_poll(struct file *, struct poll_table_struct *);
+
+
+/* trace
+ */
+extern int otg_trace_init (void);
+extern void otg_trace_exit (void);
+#if defined(OTG_LINUX)
+extern int otg_trace_init_l24(void);
+extern void otg_trace_exit_l24(void);
+#endif /* defined(OTG_LINUX) */
+
+#if defined(OTG_WINCE)
+extern int otg_trace_init_w42(void);
+extern void otg_trace_exit_w42(void);
+#endif /* defined(OTG_WINCE) */
+
+extern int otgtrace_init (void);
+extern void otgtrace_exit (void);
+extern int otg_trace_proc_read (char *page, int count, int * pos);
+extern int otg_trace_proc_write (const char *buf, int count, int * pos);
+
+/* usbp
+ */
+extern int usbd_device_init (void);
+extern void usbd_device_exit (void);
+
+
+/*
+ * otgcore/otg-mesg.c
+ */
+
+extern void otg_message(char *buf);
+extern void otg_mesg_get_status_update(struct otg_status_update *status_update);
+extern void otg_mesg_get_firmware_info(struct otg_firmware_info *firmware_info);
+extern int otg_mesg_set_firmware_info(struct otg_firmware_info *firmware_info);
+extern struct otg_instance * mesg_otg_instance;
+
+
+
+/*
+ * otgcore/otg.c
+ */
+extern char * otg_get_state_names(int i);
+
+/*
+ * ops
+ */
+
+extern struct hcd_ops *otg_hcd_ops;
+extern struct ocd_ops *otg_ocd_ops;
+extern struct pcd_ops *otg_pcd_ops;
+extern struct tcd_ops *otg_tcd_ops;
+extern struct usbd_ops *otg_usbd_ops;
+
+#define CORE core_trace_tag
+extern otg_tag_t CORE;
+
+extern struct hcd_instance * otg_set_hcd_ops(struct hcd_ops *);
+extern struct ocd_instance * otg_set_ocd_ops(struct ocd_ops *);
+extern struct pcd_instance * otg_set_pcd_ops(struct pcd_ops *);
+extern struct tcd_instance * otg_set_tcd_ops(struct tcd_ops *);
+extern int otg_set_usbd_ops(struct usbd_ops *);
+
+extern void otg_get_trace_info(otg_trace_t *p);
+extern int otg_tmr_id_gnd(void);
+extern u64 otg_tmr_ticks(void);
+extern u64 otg_tmr_elapsed(u64 *t1, u64 *t2);
+extern u16 otg_tmr_framenum(void);
+extern u32 otg_tmr_interrupts(void);
+
+extern void otg_write_info_message(char *msg);
+
+/* @} */
+
+
diff -uNr linux/drivers/no-otg/otg/otg-compat.h linux/drivers/otg/otg/otg-compat.h
--- linux/drivers/no-otg/otg/otg-compat.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-compat.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,73 @@
+/*
+ * otg/otgcore/otg-compat.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ */
+/*!
+ * @file otg/otg/otg-compat.h
+ * @brief Common include file to determine and include appropriate OS compatibility file.
+ *
+ *
+ * @ingroup OTGCore
+ */
+#ifndef _OTG_COMPAT_H
+#define _OTG_COMPAT_H 1
+
+#if defined(_WIN32_WCE)
+#define OTG_WINCE       _WIN32_WCE
+#endif /* defined(_WIN32_WCE) */
+
+        /* What operating system are we running under? */
+
+        /* Recursively include enough information to determine which release */
+
+        #if (__GNUC__ >=3)
+        #define GCC3
+        #else
+        #define GCC2
+        #endif
+        #include <linux/config.h>
+        #include <linux/kernel.h>
+        #include <linux/version.h>
+
+#if defined(__GNUC__)
+        #define OTG_LINUX
+        #ifndef CONFIG_OTG_NOC99
+        #define OTG_C99
+        #else
+        #endif
+
+        #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
+        #define LINUX26
+        #elif LINUX_VERSION_CODE > KERNEL_VERSION(2,4,5)
+        #define LINUX24
+        #else /* LINUX_VERSION_CODE > KERNEL_VERSION(2,4,5) */
+        #define LINUX24
+        #define LINUX_OLD
+        #warning "Early unsupported release of Linux kernel"
+        #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,4,5) */
+
+        /* We are running under a supported version of Linux */
+        #include <otg/otg-linux.h>
+
+#elif defined(OTG_WINCE)
+
+        /* We are running under a supported version of WinCE */
+        #include <otg/otg-wince.h>
+	#include <otg/otg-wince-ex.h>
+
+#else /* defined(OTG_WINCE) */
+
+        #error "Operating system not recognized"
+
+#endif /* defined(OTG_WINCE) */
+
+#include <otg/otg-utils.h>
+
+#if !defined(OTG_C99)
+#else /* !defined(OTG_C99) */
+#endif /* !defined(OTG_C99) */
+
+
+#endif /* _OTG_COMPAT_H */
diff -uNr linux/drivers/no-otg/otg/otg-fw-df.h linux/drivers/otg/otg/otg-fw-df.h
--- linux/drivers/no-otg/otg/otg-fw-df.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-fw-df.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,53 @@
+
+/* Generated by otg-states-h.awk
+ *
+ * Do not Edit thie file
+ */
+
+/*!
+* @file otg/otg/otg-fw-df.h
+* @brief OTG Firmware - Firmware for df
+*
+* This file defines the OTG State Machine tests.
+*
+* @ingroup OTGFW
+*/
+
+
+/*!
+* @page OTGFW
+* @section OTGFW - otg-fw-df.h
+* This contains the input, output and timout definitions for the OTG state machine firmware
+*/
+extern char     otg_fw_name_df[];
+extern int      otg_test_max_df;
+extern struct otg_test otg_tests_df[];
+extern struct otg_output otg_outputs_df[];
+
+ /*
+  * Copyright (c) 2004 Belcarra
+  *
+  */
+ /*!
+  * This is the default Firmware. It is included in the
+  * compiled modules and supports the auto Traditional USB
+  * mode. No user inputs are implemented.
+  */
+
+#define invalid_state                   0	 /*  State machine has been initialized. */
+
+#define otg_disabled                    1	 /*  State machine has been initialized. */
+
+#define terminator_state                2	 /*  terminator */
+ /*
+  * This is not an OTG State. It is used internally to mark the end of the
+  * list of states and inputs.
+  */
+
+#define OTG_STATES_DF      3
+
+extern struct otg_state otg_states_df[OTG_STATES_DF + 1];
+
+extern char    *otg_get_state_name_df(int);
+
+extern struct otg_firmware otg_firmware_df;
diff -uNr linux/drivers/no-otg/otg/otg-fw-mn.h linux/drivers/otg/otg/otg-fw-mn.h
--- linux/drivers/no-otg/otg/otg-fw-mn.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-fw-mn.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,201 @@
+
+/* Generated by otg-states-h.awk
+ *
+ * Do not Edit thie file
+ */
+
+/*!
+* @file otg/otg/otg-fw-mn.h
+* @brief OTG Firmware - Firmware for mn
+*
+* This file defines the OTG State Machine tests.
+*
+* @ingroup OTGFW
+*/
+
+
+/*!
+* @page OTGFW
+* @section OTGFW - otg-fw-mn.h
+* This contains the input, output and timout definitions for the OTG state machine firmware
+*/
+extern char     otg_fw_name_mn[];
+extern int      otg_test_max_mn;
+extern struct otg_test otg_tests_mn[];
+extern struct otg_output otg_outputs_mn[];
+
+ /*
+  * Copyright (c) 2004 Belcarra
+  */
+ /*!
+  * This is the initialization set for pcd and tcd.
+  */
+
+#define invalid_state                   0	 /*  Un-initialized state. */
+ /*
+  * This the initial state of the software when first loaded.
+  * It is not possible to return to this state.
+  */
+
+#define otg_disabled                    1	 /*  State Machine ready but disabled. */
+ /*
+  * The USBOTG State Machine has been initialized but is inactive.
+  * This state may have arrived at from either the invalid_state or
+  * from the otg_disable state.
+  */
+
+#define otg_disable_tcd                 2	 /*  State Machine waiting for driver de-initialization. */
+ /*
+  * The State Machine stops the device drivers and waits for them
+  * to signal that they have finished de-initializing.
+  *
+  * This state disables the TCD driver and waits for TCD ok.
+  */
+
+#define otg_disable_pcd                 3	 /*  State Machine waiting for driver de-initialization. */
+ /*
+  * The State Machine stops the device drivers and waits for them
+  * to signal that they have finished de-initializing.
+  *
+  * This state disables the PCD driver and waits for PCD ok.
+  */
+
+#define otg_enable_pcd                  4	 /*  State Machine waiting for driver initialization. */
+ /*
+  * The State Machine starts the device drivers and waits for them
+  * to signal that they have finished initializing.
+  *
+  * This state enables the PCD driver and waits for PCD ok.
+  */
+
+#define otg_enable_tcd                  5	 /*  State Machine waiting for driver initialization. */
+ /*
+  * The State Machine starts the device drivers and waits for them
+  * to signal that they have finished initializing.
+  *
+  * This state enables the PCD driver and waits for PCD ok.
+  */
+ /*
+  * Copyright (c) 2004 Belcarra
+  *
+  */
+ /*!
+  * This is the minimal firmware. It can be included in the
+  * compiled modules and supports the auto Traditional USB
+  * mode. No user inputs are required for normal operation.
+  *
+  * The b_bus_drop input can be optionally used to disconnect and re-connect.
+  *
+  * The enable_otg input can be optionally used to disable and re-enable.
+  * Note that disable/enable will reset b_bus_drop.
+  *
+  */
+ /*!
+  * @name Meta State - otg_init
+  * @{
+  */
+
+#define otg_enabled                     6	 /*  State machine has been initialized. */
+ /*!
+  * The State Machine has successfully started the device drivers and
+  * is waiting for an input event. Typically it will move from here to
+  * an idle state specific to the current conditions (a_idle, b_idle, mn_idle etc.)
+  * based on user request b_bus_drop.
+  *
+  */
+ /* @} */
+ /*!
+  * @name Meta State - b_idle
+  * @{
+  */
+
+#define mn_idle                         7	 /*  In idle mode with bus_drop reset. */
+ /*!
+  * The State Machine is in the idle state for a Traditional USB Device.
+  * It is waiting for Vbus to indicate that it has been plugged into a USB Host.
+  *
+  */
+
+#define mn_bus_drop                     8	 /*  In idle mode with bus_drop set. */
+ /*!
+  * The State Machine is in the idle state for a Traditional USB Device.
+  * The B-Device applications has requested that the bus connection be dropped.
+  * Wait for either enable_otg reset or b_bus_drop reset.
+  */
+ /* @} */
+ /*!
+  * @name Meta State - b_peripheral
+  * @{
+  */
+
+#define mn_peripheral                   9	 /*  Signal a connection and wait for packet traffic. */
+ /*!
+  * The State Machine in the peripheral state for a Traditional USB Device.
+  * The D+ pullup is enabled and we are waiting for a BUS_RESET to
+  * indicate that the USB Host has recognized that a USB Device is attached.
+  */
+
+#define mn_bus_reset                   10	 /*  The bus has been reset. */
+ /*!
+  * The State Machine in the bus_reset state for a Traditional USB Device.
+  * It is waiting to be enumerated and configured by the USB Host.
+  */
+
+#define mn_addressed                   11	 /*  The device has been addressed. */
+ /*!
+  * The State Machine in the configured state for a Traditional USB Device.
+  * This means that there is an active session, there is packet traffic
+  * with this device.
+  */
+
+#define mn_configured                  12	 /*  The device has been configured. */
+ /*!
+  * The State Machine in the configured state for a Traditional USB Device.
+  * This means that there is an active session, there is packet traffic
+  * with this device.
+  */
+
+#define mn_discharge                   13	 /*  Discharging Vbus */
+ /*!
+  * The State Machine in the discharge state for a Traditional USB Device.
+  * The device has been unplugged. The Vbus discharge resistor will be enabled
+  * for the TLDISC_DSCHRG time period.
+  */
+ /* @} */
+ /*!
+  * @name Meta State - b_suspended
+  * @{
+  */
+
+#define mn_suspended                   14	 /*  The bus has been suspended */
+ /*!
+  * The State Machine in the suspend state for a Traditional USB Device.
+  */
+
+#define mn_wakeup_enabled              15	 /*  Suspended with REMOTE WAKEUP enabled. */
+ /*!
+  * The State Machine in the suspend state for a Traditional USB Device,
+  * prior to suspended the USB Host enabled Remote Wakeup by sending a
+  * set REMOTE WAKUP request.
+  */
+
+#define mn_wakeup                      16	 /*  Perform REMOTE WAKEUP procedure. */
+ /*!
+  * The State Machine in the wakeup state for a Traditional USB Device,
+  * The REMOTE WAKEUP procedure will be performed.
+  */
+ /* @} */
+
+#define terminator_state               17	 /*  terminator */
+ /*!
+  * This is not an OTG State. It is used internally to mark the end of the
+  * list of states and inputs.
+  */
+
+#define OTG_STATES_MN     18
+
+extern struct otg_state otg_states_mn[OTG_STATES_MN + 1];
+
+extern char    *otg_get_state_name_mn(int);
+
+extern struct otg_firmware otg_firmware_mn;
diff -uNr linux/drivers/no-otg/otg/otg-fw.h linux/drivers/otg/otg/otg-fw.h
--- linux/drivers/no-otg/otg/otg-fw.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-fw.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,1309 @@
+
+/* Generated by otg-h.awk
+ *
+ * Do not Edit, see otg-state.awk
+ */
+
+
+/*!
+* @defgroup OTGFW Firmware
+* @ingroup onthegogroup
+*/
+
+/*!
+* @file otg/otg/otg-fw.h
+* @brief OTG Firmware - Input, Output and Timeout definitions
+* This file defines the OTG State Machine input, output and timeout constants.
+*
+*
+* @ingroup OTGFW
+*/
+
+/*!
+* @name OTGFW
+* @section OTGFW - otg-fw.h
+*/
+
+/*!
+* @name OTGVERSION OTG Version
+* Version information
+* @{
+*/
+
+#define OTG_VERSION_FW 200502152159L
+
+/*! @} */
+
+/*!
+* @name BASIC
+* These are the provided for application layer compatibility.
+* @{
+*/
+#ifdef OTG_APPLICATION
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+typedef unsigned long long u64;
+#include <stdio.h>
+#include <sys/ioctl.h>
+#endif	/* OTG_APPLICATION/ */
+
+/*! @} */
+
+/*!
+* @name OTGSTRUCT OTG Structures
+* Basic OTG Structures
+*/
+#define OTGADMIN_MAXSTR      48
+
+/*!
+ * @struct otg_test
+ * 
+ * This defines the tests that allow the state machine to move
+ * from state to state based on input events.
+ * 
+ *  Goto target: if (                               
+ *              (!test1 || (test1 & inputs)) && 
+ *              (!test2 || (test2 & inputs)) && 
+ * 
+ */
+typedef struct otg_test {
+	u16             test;	/*!< Test number */
+	u16             state;	/*!< State Machine State */
+	u32             target;	/*!< Goto this target if             */
+	u64             test1;	/*!< (!test1 || (test1 & inputs)) && */
+	u64             test2;	/*!< (!test2 || (test2 & inputs)) && */
+	u64             test3;	/*!< (!test3 || (test3 & inputs)) && */
+	/* N.B. An empty test is ignored.    */
+} otg_test_t;			/*!<                                 */
+
+
+/*!
+ * @struct otg_input_name
+ * This structure simply allows for a table of input names that can
+ * searched for by input mask
+ */
+typedef struct otg_input_name {
+	u32             value;	/*!< Bit value */
+	char            name[OTGADMIN_MAXSTR];	/*!< Name of state. */
+} otg_input_name_t;
+
+
+/*!
+ * @struct otg_state
+ * This defines an OTG State. Each state has a name, meta state,
+ * timeout, reset and outputs
+ * 
+ * On entry to the state the reset mask is or'd into the current 
+ * input mask, the settings defined in the output mask are used to.
+ * call the required output functions and then if present the timer
+ * is started with the timeout value (in uSec).
+ * 
+ */
+typedef struct otg_state {
+	u16             state;	/*!< State Machine State */
+	u16             meta;	/*!< Meta Machine State */
+	char            name[OTGADMIN_MAXSTR];	/*!< Name of state. */
+	u32             tmout;	/*!< Start timeout if non-zero */
+	u64             reset;	/*!< Or these inputs on entry to state */
+	u64             outputs;	/*!< Or these outputs on entry to state */
+} otg_state_t;
+
+
+/*!
+ * @struct otg_ioctl_name
+ * This structure allows a table for a table of IOCTL event names that can be
+ * searched for by the ioctl command value. It also stores the actual
+ * input mask to set or reset when according to the ioctl arguement.
+ */
+typedef struct otg_ioctl_name {
+	u32             cmd;	/*!< Ioctl cmd */
+	u32             set;	/*!< Signal to set/reset */
+	char           *name;	/*!< Name of ioctl. */
+} otg_ioctl_name_t;
+
+
+/*!
+ * @struct otg_admin_command
+ * This allows for a table of IOCTL admin commands.
+ */
+typedef struct otg_admin_command {
+	int             n;	/*!< Ioctl cmd */
+	char            string[OTGADMIN_MAXSTR];	/*!< Signal to set/reset */
+} otg_admin_command_t;
+
+
+/*!
+ * @struct otg_status_update
+ * This is used by the OTG administrative programs to pass data to and received
+ * data from the OTG State Machine driver.
+ */
+typedef struct otg_status_update {
+	u16             state;	/*!< current state */
+	u16             meta;	/*!< current meta state */
+	u32             inputs;	/*!< current inputs */
+	u64             outputs;	/*!< current outputs */
+	u32             capabilities;	/*!<  */
+	char            fw_name[OTGADMIN_MAXSTR];	/*!< name of firmware */
+	char            state_name[OTGADMIN_MAXSTR];	/*!< name of current state */
+	char            meta_name[OTGADMIN_MAXSTR];	/*!< name of current meta-state */
+	char            function_name[OTGADMIN_MAXSTR];	/*!< currently selected function */
+} otg_status_update_t;
+
+
+/*!
+ * @struct otg_firmware_info
+ * This is used by the OTG Administrative program to pass firmware information
+ * to the OTG State Machine./
+ */
+typedef struct otg_firmware_info {
+	int             number_of_states;	/*!< number of states */
+	int             number_of_tests;	/*!< number of tests */
+	char            fw_name[OTGADMIN_MAXSTR];	/*!< name of firmware */
+} otg_firmware_info_t;
+
+
+/*!
+ * @struct otg_firmware
+ * This is used by the OTG Administrative program to pass firmware
+ * to the OTG State Machine./
+ */
+typedef struct otg_firmware {
+	int             number_of_states;	/*!< number of states */
+	int             number_of_tests;	/*!< number of tests */
+	char            fw_name[OTGADMIN_MAXSTR];	/*!< name of firmware */
+	struct otg_state *otg_states;	/*!< output information */
+	struct otg_test *otg_tests;	/*!< test information */
+} otg_firmware_t;
+
+/*! @} */
+
+/*!
+* @name OTGTIME Time Macros
+* Basic OTG Time Macros
+*/
+
+#define US(n)                   (n)		 /*!< micro-seconds */
+
+#define MS(n)                   (1000 * US(n))	 /*!< milli-seconds */
+
+#define SEC(n)                  (1000 * MS(n))	 /*!< seconds */
+
+/*! @} */
+
+/*!
+* @name OTGOUTPUTM Output Macros
+* OTG Output Macros
+*/
+
+/* OTG State Outputs
+ *
+ * Each state that we transition to defines new settings for each of the defined
+ * outputs. Each output setting can have four settings:
+ *
+ *      
+ *      
+ *      
+ *      
+ */
+#define NC      ((u64)0x0)			 /*!< NC      no change */
+#define SET     ((u64)0x1)			 /*!< SET     the output should be set (i.e. enabled) */
+#define RESET   ((u64)0x2)			 /*!< RESET   the output should be reset (i.e. disabled) */
+#define PULSE   ((u64)0x3)			 /*!< OTHER   special setting, for example used for pulse vbus */
+#define POWER   ((u64)0x3)			 /*!< POWER   */
+
+#define _MASK(n)                (((u64) 1) << n) /*!< Set nth bit in 64 bit mask */
+#define _NOT(n)                 (((u64) n) << 32)	/*!< Set nth+32 bit in 64 bit mask */
+#define _ncmask(n)              (NC)		 /*!< No output change mask */
+#define _setmask(n)             (SET << (n*2))	 /*!< Output set mask */
+#define _resetmask(n)           (RESET << (n*2)) /*!< Output reset mask */
+#define _pulsemask(n)           (PULSE << (n*2)) /*!< Output pulse mask */
+#define _powermask(n)           (POWER << (n*2)) /*!< Output poser mask */
+
+/*! @} */
+
+/*!
+* @name OTGNAMES OTG Names
+* Basic OTG Name Tables
+*/
+
+extern struct otg_input_name otg_input_names[];
+extern struct otg_ioctl_name otg_ioctl_names[];
+extern struct otg_timeouts otg_timeouts[];
+extern struct otg_firmware *otg_firmware_loaded;
+extern char    *otg_output_names[];
+
+
+/*! @} */
+
+/* Generated by otg-inputs-h.awk
+ *
+ * Do not Edit this file.
+ */
+
+
+ /*!
+  * N.B. The OTG State Machine Documentation uses the syntax A and A/
+  * to indicate an event being true or not true. Because a trailing
+  * slash is not legal in C we use A and A_ to indicate true and not true.
+  */
+
+ /*!
+  * @name OTG Transceiver Inputs
+  * These inputs reflect changes seen in the OTG Transceiver. These
+  * what are available in most common OTG transceivers, for example
+  * the ISP1301 or MAX3353.
+  *
+  * The following are typical Vbus comparators.
+  *
+  * ISP1301 MAX3353E
+  * B-Session end threshold 0.2V-0.8V 0.5V
+  * Session Valid Comparator 0.8V-2.0V 1.4V
+  * B-Session Valid 2.0V-4.0V N/A
+  * A-Device Vbus Valid Comparator 4.4V 4.6V
+  *
+  * @{
+  */
+#define ID_GND                         _MASK( 0) /*!< otg_ok -    ID is grounded */
+#define ID_GND_                        _NOT(ID_GND)
+#define ID_FLOAT                       _MASK( 1) /*!< otg_ok -    ID is floating */
+#define ID_FLOAT_                      _NOT(ID_FLOAT)
+#define DP_HIGH                        _MASK( 2) /*!< otg_ok -    DP is pulled high */
+#define DP_HIGH_                       _NOT(DP_HIGH)
+#define DM_HIGH                        _MASK( 3) /*!< otg_ok -    DM pullup is pulled high */
+#define DM_HIGH_                       _NOT(DM_HIGH)
+#define B_SESS_END                     _MASK( 4) /*!< otg_ok -    Vbus less than B-Session end thresshold */
+#define B_SESS_END_                    _NOT(B_SESS_END)
+#define A_SESS_VLD                     _MASK( 5) /*!< otg_ok -    Vbus greater than Session valid threshold */
+#define A_SESS_VLD_                    _NOT(A_SESS_VLD)
+#define B_SESS_VLD                     _MASK( 6) /*!< otg_ok -    Vbus greater than B-Session Valid threshold */
+#define B_SESS_VLD_                    _NOT(B_SESS_VLD)
+#define VBUS_VLD                       _MASK( 7) /*!< otg_ok -    Vbus greater than A-Device Vbus Valid threshold */
+#define VBUS_VLD_                      _NOT(VBUS_VLD)
+#define SRP_DET                        _MASK( 8) /*!< a_idle -    SRP Detected (Vbus pulsed) */
+#define SRP_DET_                       _NOT(SRP_DET)
+#define SE0_DET                        _MASK( 9) /*!< b_idle -    SE0 Detected (Single Ended Zeros, DM and DP both low) */
+#define SE0_DET_                       _NOT(SE0_DET)
+#define SE1_DET                        _MASK(10) /*!< b_idle -    SE1 Detected (Single Ended Ones, DM and DP both high) */
+#define SE1_DET_                       _NOT(SE1_DET)
+#define BDIS_ACON                      _MASK(10) /*!< a_hnp_wait -    Auto DP pullup high after B-disconnect */
+#define BDIS_ACON_                     _NOT(BDIS_ACON)
+#define CR_INT_DET                     _MASK(10) /*!< ph_audio -    0.4V < DP < 0.6V */
+#define CR_INT_DET_                    _NOT(CR_INT_DET)
+ /* @} */
+ /*!
+  * @name Peripheral and Host driver signals.
+  *
+  *
+  * @{
+  */
+#define HUB_PORT_CONNECT               _MASK(12) /*!< otg_both -    Port Connection */
+#define HUB_PORT_CONNECT_              _NOT(HUB_PORT_CONNECT)
+#define BUS_RESET                      _MASK(13) /*!< otg_both -    Bus has reset. */
+#define BUS_RESET_                     _NOT(BUS_RESET)
+#define ADDRESSED                      _MASK(14) /*!< otg_both -    Device has been addressed (received SET ADDRESS request.) */
+#define ADDRESSED_                     _NOT(ADDRESSED)
+#define CONFIGURED                     _MASK(15) /*!< otg_both -    Device has been configured (received SET CONFIG request.) */
+#define CONFIGURED_                    _NOT(CONFIGURED)
+#define NOT_SUPPORTED                  _MASK(16) /*!< otg_both -    Peripheral not supported (no class driver.) */
+#define NOT_SUPPORTED_                 _NOT(NOT_SUPPORTED)
+#define BUS_SUSPENDED                  _MASK(17) /*!< otg_both -    Bus has been suspended. */
+#define BUS_SUSPENDED_                 _NOT(BUS_SUSPENDED)
+ /* @} */
+
+ /*!
+  * @name Administrative Policy Inputs
+  * These are only valid in the state indicated and
+  * can be enabled or disabled.
+  *
+  * @{
+  */
+#define a_bcon_no_tmout_req            _MASK(18) /*!< otg_host -    Application on A-host wants Ta_wait_bcon timeout disabled (non-OTG mode). */
+#define a_bcon_no_tmout_req_           _NOT(a_bcon_no_tmout_req)
+#define a_hpwr_req                     _MASK(19) /*!< otg_host -    Application on A-host wants external charge pump enabled. */
+#define a_hpwr_req_                    _NOT(a_hpwr_req)
+#define bus_drop                       _MASK(20) /*!< otg_ok -    Application on Device needs to power down bus. */
+#define bus_drop_                      _NOT(bus_drop)
+#define a_bus_drop                     _MASK(20) /*!< otg_ok -    Application on A-Device needs to power down bus. */
+#define a_bus_drop_                    _NOT(a_bus_drop)
+#define b_bus_drop                     _MASK(20) /*!< otg_ok -    Application on B-Device needs to disconnect from bus. */
+#define b_bus_drop_                    _NOT(b_bus_drop)
+#define bus_req                        _MASK(21) /*!< otg_ok -    Application on Device wants to use the bus. */
+#define bus_req_                       _NOT(bus_req)
+#define a_bus_req                      _MASK(21) /*!< otg_ok -    Application on A-Device wants to act as host */
+#define a_bus_req_                     _NOT(a_bus_req)
+#define b_bus_req                      _MASK(21) /*!< otg_ok -    Application on B-Device wants to act as host */
+#define b_bus_req_                     _NOT(b_bus_req)
+#define b_sess_req                     _MASK(21) /*!< otg_ok -    Application on B-Device to perform SRP (alias for b_srp_req.) */
+#define b_sess_req_                    _NOT(b_sess_req)
+#define suspend_req                    _MASK(22) /*!< otg_host -    Application on Device requests bus be suspended (alias for a_bus_req/.) */
+#define suspend_req_                   _NOT(suspend_req)
+#define a_suspend_req                  _MASK(22) /*!< otg_host -    Application on A-host requests bus be suspended (alias for a_bus_req/.) */
+#define a_suspend_req_                 _NOT(a_suspend_req)
+#define b_suspend_req                  _MASK(22) /*!< otg_host -    Application on B-host requests bus be suspended (alias for b_bus_req/.) */
+#define b_suspend_req_                 _NOT(b_suspend_req)
+ /* @} */
+
+ /*!
+  * @name Administrative Action Inputs
+  * These are only valid in state indicated. The
+  * state machine tests must reset in states
+  * prior and after use.
+  * @{
+  */
+#define set_remote_wakeup_cmd          _MASK(24) /*!< a_host -    A-Device will send Remote Wakeup Enable Request */
+#define set_remote_wakeup_cmd_         _NOT(set_remote_wakeup_cmd)
+#define remote_wakeup_cmd              _MASK(24) /*!< tr_configured -    B-Device will perform Remote Wakeup. */
+#define remote_wakeup_cmd_             _NOT(remote_wakeup_cmd)
+#define reset_remote_wakeup_cmd        _MASK(25) /*!< a_host -    A-Device will send Remote Wakeup Disable Request */
+#define reset_remote_wakeup_cmd_       _NOT(reset_remote_wakeup_cmd)
+#define clr_err_cmd                    _MASK(25) /*!< a_vbus_err -    A-Device ill clears Vbus overcurrent error. */
+#define clr_err_cmd_                   _NOT(clr_err_cmd)
+#define b_hnp_cmd                      _MASK(25) /*!< b_configured -    B-Device will attempt HNP */
+#define b_hnp_cmd_                     _NOT(b_hnp_cmd)
+#define ph_int_cmd                     _MASK(25) /*!< ph_audio -    B-Device will request Carkit interrupt */
+#define ph_int_cmd_                    _NOT(ph_int_cmd)
+#define ph_audio_cmd                   _MASK(25) /*!< ph_uart -    Application on B-Device connected to Carkit requests audio mode. */
+#define ph_audio_cmd_                  _NOT(ph_audio_cmd)
+#define cr_int_cmd                     _MASK(25) /*!< cr_aud -    Application on A-Device wants to emulate Carkit */
+#define cr_int_cmd_                    _NOT(cr_int_cmd)
+#define led_on_cmd                     _MASK(26) /*!< ph_uart -    B-Device will enable Carkit LED */
+#define led_on_cmd_                    _NOT(led_on_cmd)
+#define led_off_cmd                    _MASK(27) /*!< ph_uart -    B-Device will disable Carkit LED */
+#define led_off_cmd_                   _NOT(led_off_cmd)
+ /* @} */
+
+ /*!
+  * @name Internal State
+  * Used to track status changes.
+  * @{
+  */
+#define HNP_ENABLED                    _MASK(27) /*!< b_configured -    B-HNP Enable Request sent (a-host) or received (b-peripheral). */
+#define HNP_ENABLED_                   _NOT(HNP_ENABLED)
+#define HNP_CAPABLE                    _MASK(28) /*!< otg_both -    B-host Peripheral may do HNP */
+#define HNP_CAPABLE_                   _NOT(HNP_CAPABLE)
+#define HNP_SUPPORTED                  _MASK(28) /*!< otg_both -    B-host can do HNP (A-Host Received HNP Supported SET FEATURE) */
+#define HNP_SUPPORTED_                 _NOT(HNP_SUPPORTED)
+#define REMOTE_WAKEUP_ENABLED          _MASK(29) /*!< otg_configured -    Remote Wakeup Enable Request received. */
+#define REMOTE_WAKEUP_ENABLED_         _NOT(REMOTE_WAKEUP_ENABLED)
+#define REMOTE_CAPABLE                 _MASK(29) /*!< otg_both -    Peripheral can do remote wakeup */
+#define REMOTE_CAPABLE_                _NOT(REMOTE_CAPABLE)
+ /* @} */
+
+ /*!
+  * @name Global Administration
+  * @{
+  */
+ /* @} */
+
+ /*!
+  * @name Driver Initialization Finished signals
+  * @{
+  */
+#define PCD_OK                         _MASK(30) /*!< otg_driver -    PCD Driver Initialization Finished. */
+#define PCD_OK_                        _NOT(PCD_OK)
+#define TCD_OK                         _MASK(30) /*!< otg_driver -    TCD Driver Initialization Finished. */
+#define TCD_OK_                        _NOT(TCD_OK)
+#define HCD_OK                         _MASK(30) /*!< otg_driver -    HCD Driver Initialization Finished. */
+#define HCD_OK_                        _NOT(HCD_OK)
+#define OCD_OK                         _MASK(30) /*!< otg_driver -    OCD Driver Initialization Finished. */
+#define OCD_OK_                        _NOT(OCD_OK)
+ /* @} */
+
+ /*!
+  * @name Timeout and enable
+  * @{
+  */
+#define TMOUT                          _MASK(30) /*!< otg_all -    Generic Timeout */
+#define TMOUT_                         _NOT(TMOUT)
+#define enable_otg                     _MASK(31) /*!< otg_all -    Move State Machine otg_disabled state. */
+#define enable_otg_                    _NOT(enable_otg)
+#define AUTO                           _MASK(31) /*!< otg_all -    Auto Return (enable_otg only true when active) */
+#define AUTO_                          _NOT(AUTO)
+ /* @} */
+
+ /*! @name Timeouts C.f. OTG Table 5-2 A-Device Timing
+  * @{
+  */
+#define Ta_wait_vrise                  _MASK(30) /*!< a_wait_vrise -     Wait for Vbus Rise */
+#define Ta_wait_vrise_                 _NOT(Ta_wait_vrise)
+#define TA_WAIT_VRISE                  MS(100)
+#define Ta_wait_vrise_200              _MASK(30) /*!< a_wait_vrise -     Wait for Vbus Rise */
+#define Ta_wait_vrise_200_             _NOT(Ta_wait_vrise_200)
+#define TA_WAIT_VRISE_200              MS(200)
+#define Ta_wait_vrise_400              _MASK(30) /*!< a_wait_vrise -     Wait for Vbus Rise */
+#define Ta_wait_vrise_400_             _NOT(Ta_wait_vrise_400)
+#define TA_WAIT_VRISE_400              MS(400)
+#define Ta_wait_vrise_500              _MASK(30) /*!< a_wait_vrise -     Wait for Vbus Rise */
+#define Ta_wait_vrise_500_             _NOT(Ta_wait_vrise_500)
+#define TA_WAIT_VRISE_500              MS(500)
+#define Ta_wait_vrise_800              _MASK(30) /*!< a_wait_vrise -     Wait for Vbus Rise */
+#define Ta_wait_vrise_800_             _NOT(Ta_wait_vrise_800)
+#define TA_WAIT_VRISE_800              MS(800)
+#define Ta_bcon_ldb                    _MASK(30) /*!< a_bcon_ldb -     B-Connect Long Debounce */
+#define Ta_bcon_ldb_                   _NOT(Ta_bcon_ldb)
+#define TA_BCON_LDB                    MS(100)
+#define Ta_wait_bcon                   _MASK(30) /*!< a_wait_bcon -     Wait for 1 second for B-Connect */
+#define Ta_wait_bcon_                  _NOT(Ta_wait_bcon)
+#define TA_WAIT_BCON                   SEC(1)
+#define Ta_wait_bcon_5                 _MASK(30) /*!< a_wait_bcon -     Wait for 5 second for B-Connect */
+#define Ta_wait_bcon_5_                _NOT(Ta_wait_bcon_5)
+#define TA_WAIT_BCON_5                 SEC(5)
+#define Ta_wait_bcon_10                _MASK(30) /*!< a_wait_bcon -     Wait for 10 second for B-Connect */
+#define Ta_wait_bcon_10_               _NOT(Ta_wait_bcon_10)
+#define TA_WAIT_BCON_10                SEC(10)
+#define Ta_aidl_bdis                   _MASK(30) /*!< a_hnp_wait -     A-Idle to B-Disconnect */
+#define Ta_aidl_bdis_                  _NOT(Ta_aidl_bdis)
+#define TA_AIDL_BDIS                   MS(200)
+#define Ta_bdis_acon                   _MASK(30) /*!< a_suspend -     B-disconnect to A-Connect */
+#define Ta_bdis_acon_                  _NOT(Ta_bdis_acon)
+#define TA_BDIS_ACON                   MS(3)
+#define Ta_bidl_adis_min               _MASK(30) /*!< a_peripheral -     B-Idle to A-Disconnect minimum (TODO) */
+#define Ta_bidl_adis_min_              _NOT(Ta_bidl_adis_min)
+#define TA_BIDL_ADIS_MIN               MS(3)
+#define Ta_bcon_sdb                    _MASK(30) /*!< a_bcon_sdb -     B-Connect Short Debounce */
+#define Ta_bcon_sdb_                   _NOT(Ta_bcon_sdb)
+#define TA_BCON_SDB                    US(2)
+#define Ta_bcon_sdb_win                _MASK(30) /*!< a_bcon_win -     B-Connect Short Debounce Window */
+#define Ta_bcon_sdb_win_               _NOT(Ta_bcon_sdb_win)
+#define TA_BCON_SDB_WIN                MS(100)
+ /* @} */
+
+ /*! @name Timeouts C.f. OTG Table 5-3 B-Device Timing
+  * @{
+  */
+#define Tb_se0_srp                     _MASK(30) /*!< b_srp_se0 -     SE0 Time Before SRP */
+#define Tb_se0_srp_                    _NOT(Tb_se0_srp)
+#define TB_SE0_SRP                     MS(2)
+#define Tb_data_pls                    _MASK(30) /*!< b_srp_init -     Data-Line Pulse Time */
+#define Tb_data_pls_                   _NOT(Tb_data_pls)
+#define TB_DATA_PLS                    MS(7)
+#define Tb_data_pls_min                _MASK(30) /*!< a_srp_min -     Data-Line Pulse minimum time */
+#define Tb_data_pls_min_               _NOT(Tb_data_pls_min)
+#define TB_DATA_PLS_MIN                MS(5)
+#define Tb_data_pls_max                _MASK(30) /*!< a_srp_wait -     Data-Line Pulse maximum time */
+#define Tb_data_pls_max_               _NOT(Tb_data_pls_max)
+#define TB_DATA_PLS_MAX                MS(10)
+#define Tb_srp_init                    _MASK(30) /*!< b_srp_init -     SRP Initiate Time (TODO multi-state? Not-needed?) */
+#define Tb_srp_init_                   _NOT(Tb_srp_init)
+#define TB_SRP_INIT                    MS(100)
+#define Tb_srp_fail_min                _MASK(30) /*!< b_srp_wait -     SRP Fail Time minimum (TODO) */
+#define Tb_srp_fail_min_               _NOT(Tb_srp_fail_min)
+#define TB_SRP_FAIL_MIN                SEC(5)
+#define Tb_aidl_bdis_min               _MASK(30) /*!< b_peripheral -     A-idle to B-Disconnect minimum (TODO) */
+#define Tb_aidl_bdis_min_              _NOT(Tb_aidl_bdis_min)
+#define TB_AIDL_BDIS_MIN               MS(5)
+#define Tb_aidl_bdis_max               _MASK(30) /*!< b_peripheral -     A-idle to B-Disconnect maximum (TODO) */
+#define Tb_aidl_bdis_max_              _NOT(Tb_aidl_bdis_max)
+#define TB_AIDL_BDIS_MAX               MS(150)
+#define Tldisc_dschrg                  _MASK(30) /*!< b_dischrg -     Local Disconnect to Data Line Discharge (TODO) */
+#define Tldisc_dschrg_                 _NOT(Tldisc_dschrg)
+#define TLDISC_DSCHRG                  US(25)
+#define Tb_ase0_brst_min               _MASK(30) /*!< b_wait_acon -     A-SE0 to B-Reset minimum */
+#define Tb_ase0_brst_min_              _NOT(Tb_ase0_brst_min)
+#define TB_ASE0_BRST_MIN               US(3125)
+#define Tb_acon_dbnc                   _MASK(30) /*!< b_acon_dbnc -     A-Connect Debounce */
+#define Tb_acon_dbnc_                  _NOT(Tb_acon_dbnc)
+#define TB_ACON_DBNC                   US(2)
+#define Tb_acon_bse0                   _MASK(30) /*!< b_host_se0 -     A-Connect to B-SE0 */
+#define Tb_acon_bse0_                  _NOT(Tb_acon_bse0)
+#define TB_ACON_BSE0                   MS(1)
+#define Tid_ldb                        _MASK(30) /*!< otg_enable -     ID changes debounce */
+#define Tid_ldb_                       _NOT(Tid_ldb)
+#define TID_LDB                        MS(100)
+ /* @} */
+
+ /*! @name Timeouts for Carkit
+  * @{
+  */
+#define Tph_bcon_ldb                   _MASK(30) /*!< ph_init -     B-Connect Long Debounce */
+#define Tph_bcon_ldb_                  _NOT(Tph_bcon_ldb)
+#define TPH_BCON_LDB                   MS(100)
+#define Tph_init_pls                   _MASK(30) /*!< ph_int -     Timeout for Carkit interrupt. */
+#define Tph_init_pls_                  _NOT(Tph_init_pls)
+#define TPH_INIT_PLS                   US(500)
+#define Tcr_uart_rsp                   _MASK(30) /*!< ph_int -     Timeout for Carkit UART */
+#define Tcr_uart_rsp_                  _NOT(Tcr_uart_rsp)
+#define TCR_UART_RSP                   MS(30)
+#define Tcr_aud_det                    _MASK(30) /*!< ph_audio_wait -     Timeout waiting for Carkit Audio ack */
+#define Tcr_aud_det_                   _NOT(Tcr_aud_det)
+#define TCR_AUD_DET                    US(1000)
+#define Tph_led_off                    _MASK(30) /*!< ph_uart -     Timeout for LED off pulse */
+#define Tph_led_off_                   _NOT(Tph_led_off)
+#define TPH_LED_OFF                    US(10)
+#define Tph_led_on                     _MASK(30) /*!< ph_uart -     Timeout for LED on pulse */
+#define Tph_led_on_                    _NOT(Tph_led_on)
+#define TPH_LED_ON                     MS(4)
+#define Tcr_led_off                    _MASK(30) /*!< ph_uart -     Timeout for LED off pulse */
+#define Tcr_led_off_                   _NOT(Tcr_led_off)
+#define TCR_LED_OFF                    MS(4)
+#define Tcr_led_on                     _MASK(30) /*!< ph_uart -     Timeout for LED on pulse */
+#define Tcr_led_on_                    _NOT(Tcr_led_on)
+#define TCR_LED_ON                     MS(8)
+#define Tcr_dm_disc                    _MASK(30) /*!< cr_aud -     Timeout for DM disconnect */
+#define Tcr_dm_disc_                   _NOT(Tcr_dm_disc)
+#define TCR_DM_DISC                    MS(50)
+#define Tph_mono_ack                   _MASK(30) /*!< cr_wait -     Timeout for CR INT */
+#define Tph_mono_ack_                  _NOT(Tph_mono_ack)
+#define TPH_MONO_ACK                   MS(1)
+#define Tph_aud_det                    _MASK(30) /*!< cr_ack -     Timeout for CR ACK */
+#define Tph_aud_det_                   _NOT(Tph_aud_det)
+#define TPH_AUD_DET                    MS(100)
+ /* @} */
+
+ /*! @name Timeouts for timer test
+  * @{
+  */
+#define Tzero                          _MASK(30) /*!< otg_enabled -     Startup */
+#define Tzero_                         _NOT(Tzero)
+#define TZERO                          MS(2)
+#define Tst_one_ms                     _MASK(30) /*!< tm_start -     Timer test */
+#define Tst_one_ms_                    _NOT(Tst_one_ms)
+#define TST_ONE_MS                     MS(1)
+#define Tst_ten_ms                     _MASK(30) /*!< tm_start -     Timer test */
+#define Tst_ten_ms_                    _NOT(Tst_ten_ms)
+#define TST_TEN_MS                     MS(10)
+#define Tst_one_second                 _MASK(30) /*!< tm_start -     Timer test */
+#define Tst_one_second_                _NOT(Tst_one_second)
+#define TST_ONE_SECOND                 SEC(1)
+#define Tst_two_second                 _MASK(30) /*!< tm_start -     Timer test */
+#define Tst_two_second_                _NOT(Tst_two_second)
+#define TST_TWO_SECOND                 SEC(2)
+#define Tst_four_second                _MASK(30) /*!< tm_start -     Timer test */
+#define Tst_four_second_               _NOT(Tst_four_second)
+#define TST_FOUR_SECOND                SEC(4)
+#define Tst_eight_second               _MASK(30) /*!< tm_start -     Timer test */
+#define Tst_eight_second_              _NOT(Tst_eight_second)
+#define TST_EIGHT_SECOND               SEC(8)
+#define Tst_ten_second                 _MASK(30) /*!< tm_start -     Timer test */
+#define Tst_ten_second_                _NOT(Tst_ten_second)
+#define TST_TEN_SECOND                 SEC(10)
+ /* @} */
+
+/* Generated by otg-outputs-h.awk
+ *
+ * Do not Edit this file.
+ */
+
+
+
+ /* State Machine Outputs
+  */
+
+ /*! @name Driver Initialization Outputs
+  * N.B. tcd_en is used for older devices, to check if Vbus
+  * already enabled.
+  * @{
+  */
+
+#define TCD_INIT_OUT                    0	 /*!<  Initiate Transceiver Controller Driver Initialization (or De-initialization.) */
+#define tcd_init_out                   _setmask(TCD_INIT_OUT)
+#define tcd_init_out_                  _resetmask(TCD_INIT_OUT)
+#define tcd_init_out_set               _setmask(TCD_INIT_OUT)
+#define tcd_init_out_reset             _resetmask(TCD_INIT_OUT)
+#define tcd_init_out_power             _powermask(TCD_INIT_OUT)
+
+#define PCD_INIT_OUT                    1	 /*!<  Initiate Peripheral Controller Driver Initialization (or De-initialization.) */
+#define pcd_init_out                   _setmask(PCD_INIT_OUT)
+#define pcd_init_out_                  _resetmask(PCD_INIT_OUT)
+#define pcd_init_out_set               _setmask(PCD_INIT_OUT)
+#define pcd_init_out_reset             _resetmask(PCD_INIT_OUT)
+#define pcd_init_out_power             _powermask(PCD_INIT_OUT)
+
+#define HCD_INIT_OUT                    2	 /*!<  Initiate Host Controller Driver Initialization (or De-initialization). */
+#define hcd_init_out                   _setmask(HCD_INIT_OUT)
+#define hcd_init_out_                  _resetmask(HCD_INIT_OUT)
+#define hcd_init_out_set               _setmask(HCD_INIT_OUT)
+#define hcd_init_out_reset             _resetmask(HCD_INIT_OUT)
+#define hcd_init_out_power             _powermask(HCD_INIT_OUT)
+
+#define OCD_INIT_OUT                    3	 /*!<  Initiate OTG Controller Driver Initialization (or De-initialization). */
+#define ocd_init_out                   _setmask(OCD_INIT_OUT)
+#define ocd_init_out_                  _resetmask(OCD_INIT_OUT)
+#define ocd_init_out_set               _setmask(OCD_INIT_OUT)
+#define ocd_init_out_reset             _resetmask(OCD_INIT_OUT)
+#define ocd_init_out_power             _powermask(OCD_INIT_OUT)
+
+#define TCD_EN_OUT                      4	 /*!<  Enable Transceiver Controller Driver */
+#define tcd_en_out                     _setmask(TCD_EN_OUT)
+#define tcd_en_out_                    _resetmask(TCD_EN_OUT)
+#define tcd_en_out_set                 _setmask(TCD_EN_OUT)
+#define tcd_en_out_reset               _resetmask(TCD_EN_OUT)
+#define tcd_en_out_power               _powermask(TCD_EN_OUT)
+
+#define PCD_EN_OUT                      5	 /*!<  Enable Peripheral Controller Driver */
+#define pcd_en_out                     _setmask(PCD_EN_OUT)
+#define pcd_en_out_                    _resetmask(PCD_EN_OUT)
+#define pcd_en_out_set                 _setmask(PCD_EN_OUT)
+#define pcd_en_out_reset               _resetmask(PCD_EN_OUT)
+#define pcd_en_out_power               _powermask(PCD_EN_OUT)
+
+#define HCD_EN_OUT                      6	 /*!<  Enable Host Controller Driver */
+#define hcd_en_out                     _setmask(HCD_EN_OUT)
+#define hcd_en_out_                    _resetmask(HCD_EN_OUT)
+#define hcd_en_out_set                 _setmask(HCD_EN_OUT)
+#define hcd_en_out_reset               _resetmask(HCD_EN_OUT)
+#define hcd_en_out_power               _powermask(HCD_EN_OUT)
+ /* @) */
+
+ /*! @name Transceiver Controller Driver Outputs
+  * @{
+  */
+
+#define DRV_VBUS_OUT                    7	 /*!<  A-Device will Drive Vbus to 5V through charge pump. */
+#define drv_vbus_out                   _setmask(DRV_VBUS_OUT)
+#define drv_vbus_out_                  _resetmask(DRV_VBUS_OUT)
+#define drv_vbus_out_set               _setmask(DRV_VBUS_OUT)
+#define drv_vbus_out_reset             _resetmask(DRV_VBUS_OUT)
+#define drv_vbus_out_power             _powermask(DRV_VBUS_OUT)
+
+#define CHRG_VBUS_OUT                   8	 /*!<  B-Device will charge Vbus to 3.3V through resistor (SRP.) */
+#define chrg_vbus_out                  _setmask(CHRG_VBUS_OUT)
+#define chrg_vbus_out_                 _resetmask(CHRG_VBUS_OUT)
+#define chrg_vbus_out_set              _setmask(CHRG_VBUS_OUT)
+#define chrg_vbus_out_reset            _resetmask(CHRG_VBUS_OUT)
+#define chrg_vbus_out_power            _powermask(CHRG_VBUS_OUT)
+
+#define DISCHRG_VBUS_OUT                9	 /*!<  B-Device will discharge Vbus (enable dischage resistor.) */
+#define dischrg_vbus_out               _setmask(DISCHRG_VBUS_OUT)
+#define dischrg_vbus_out_              _resetmask(DISCHRG_VBUS_OUT)
+#define dischrg_vbus_out_set           _setmask(DISCHRG_VBUS_OUT)
+#define dischrg_vbus_out_reset         _resetmask(DISCHRG_VBUS_OUT)
+#define dischrg_vbus_out_power         _powermask(DISCHRG_VBUS_OUT)
+
+#define DM_PULLUP_OUT                  10	 /*!<  DM pullup control - aka loc_carkit */
+#define dm_pullup_out                  _setmask(DM_PULLUP_OUT)
+#define dm_pullup_out_                 _resetmask(DM_PULLUP_OUT)
+#define dm_pullup_out_set              _setmask(DM_PULLUP_OUT)
+#define dm_pullup_out_reset            _resetmask(DM_PULLUP_OUT)
+#define dm_pullup_out_power            _powermask(DM_PULLUP_OUT)
+
+#define DM_PULLDOWN_OUT                11	 /*!<  DM pulldown control */
+#define dm_pulldown_out                _setmask(DM_PULLDOWN_OUT)
+#define dm_pulldown_out_               _resetmask(DM_PULLDOWN_OUT)
+#define dm_pulldown_out_set            _setmask(DM_PULLDOWN_OUT)
+#define dm_pulldown_out_reset          _resetmask(DM_PULLDOWN_OUT)
+#define dm_pulldown_out_power          _powermask(DM_PULLDOWN_OUT)
+
+#define DP_PULLUP_OUT                  12	 /*!<  DP pullup control - aka loc_conn */
+#define dp_pullup_out                  _setmask(DP_PULLUP_OUT)
+#define dp_pullup_out_                 _resetmask(DP_PULLUP_OUT)
+#define dp_pullup_out_set              _setmask(DP_PULLUP_OUT)
+#define dp_pullup_out_reset            _resetmask(DP_PULLUP_OUT)
+#define dp_pullup_out_power            _powermask(DP_PULLUP_OUT)
+
+#define DP_PULLDOWN_OUT                13	 /*!<  DP pulldown control */
+#define dp_pulldown_out                _setmask(DP_PULLDOWN_OUT)
+#define dp_pulldown_out_               _resetmask(DP_PULLDOWN_OUT)
+#define dp_pulldown_out_set            _setmask(DP_PULLDOWN_OUT)
+#define dp_pulldown_out_reset          _resetmask(DP_PULLDOWN_OUT)
+#define dp_pulldown_out_power          _powermask(DP_PULLDOWN_OUT)
+
+#define CLR_OVERCURRENT_OUT            14	 /*!<  Clear overcurrent indication */
+#define clr_overcurrent_out            _setmask(CLR_OVERCURRENT_OUT)
+#define clr_overcurrent_out_           _resetmask(CLR_OVERCURRENT_OUT)
+#define clr_overcurrent_out_set        _setmask(CLR_OVERCURRENT_OUT)
+#define clr_overcurrent_out_reset      _resetmask(CLR_OVERCURRENT_OUT)
+#define clr_overcurrent_out_power      _powermask(CLR_OVERCURRENT_OUT)
+
+#define DM_DET_OUT                     15	 /*!<  Enable B-Device D- High detect */
+#define dm_det_out                     _setmask(DM_DET_OUT)
+#define dm_det_out_                    _resetmask(DM_DET_OUT)
+#define dm_det_out_set                 _setmask(DM_DET_OUT)
+#define dm_det_out_reset               _resetmask(DM_DET_OUT)
+#define dm_det_out_power               _powermask(DM_DET_OUT)
+
+#define DP_DET_OUT                     16	 /*!<  Enable B-Device D+ High detect */
+#define dp_det_out                     _setmask(DP_DET_OUT)
+#define dp_det_out_                    _resetmask(DP_DET_OUT)
+#define dp_det_out_set                 _setmask(DP_DET_OUT)
+#define dp_det_out_reset               _resetmask(DP_DET_OUT)
+#define dp_det_out_power               _powermask(DP_DET_OUT)
+
+#define CR_DET_OUT                     17	 /*!<  Enable D+ CR detect */
+#define cr_det_out                     _setmask(CR_DET_OUT)
+#define cr_det_out_                    _resetmask(CR_DET_OUT)
+#define cr_det_out_set                 _setmask(CR_DET_OUT)
+#define cr_det_out_reset               _resetmask(CR_DET_OUT)
+#define cr_det_out_power               _powermask(CR_DET_OUT)
+
+#define CHARGE_PUMP_OUT                18	 /*!<  Enable external charge pump. */
+#define charge_pump_out                _setmask(CHARGE_PUMP_OUT)
+#define charge_pump_out_               _resetmask(CHARGE_PUMP_OUT)
+#define charge_pump_out_set            _setmask(CHARGE_PUMP_OUT)
+#define charge_pump_out_reset          _resetmask(CHARGE_PUMP_OUT)
+#define charge_pump_out_power          _powermask(CHARGE_PUMP_OUT)
+
+#define BDIS_ACON_OUT                  19	 /*!<  Enable auto A-connect after B-disconnect. */
+#define bdis_acon_out                  _setmask(BDIS_ACON_OUT)
+#define bdis_acon_out_                 _resetmask(BDIS_ACON_OUT)
+#define bdis_acon_out_set              _setmask(BDIS_ACON_OUT)
+#define bdis_acon_out_reset            _resetmask(BDIS_ACON_OUT)
+#define bdis_acon_out_power            _powermask(BDIS_ACON_OUT)
+
+#define MX21_VBUS_DRAIN                20	 /*!<  MX21 hack */
+#define mx21_vbus_drain                _setmask(MX21_VBUS_DRAIN)
+#define mx21_vbus_drain_               _resetmask(MX21_VBUS_DRAIN)
+#define mx21_vbus_drain_set            _setmask(MX21_VBUS_DRAIN)
+#define mx21_vbus_drain_reset          _resetmask(MX21_VBUS_DRAIN)
+#define mx21_vbus_drain_power          _powermask(MX21_VBUS_DRAIN)
+
+#define ID_PULLDOWN_OUT                21	 /*!<  Enable the ID to ground pulldown ( (CEA-936 - 5 wire carkit.) */
+#define id_pulldown_out                _setmask(ID_PULLDOWN_OUT)
+#define id_pulldown_out_               _resetmask(ID_PULLDOWN_OUT)
+#define id_pulldown_out_set            _setmask(ID_PULLDOWN_OUT)
+#define id_pulldown_out_reset          _resetmask(ID_PULLDOWN_OUT)
+#define id_pulldown_out_power          _powermask(ID_PULLDOWN_OUT)
+
+#define UART_OUT                       22	 /*!<  Enable Transparent UART mode (CEA-936.) */
+#define uart_out                       _setmask(UART_OUT)
+#define uart_out_                      _resetmask(UART_OUT)
+#define uart_out_set                   _setmask(UART_OUT)
+#define uart_out_reset                 _resetmask(UART_OUT)
+#define uart_out_power                 _powermask(UART_OUT)
+
+#define AUDIO_OUT                      23	 /*!<  Enable Audio mode (CEA-936 CarKit interrupt detector.) */
+#define audio_out                      _setmask(AUDIO_OUT)
+#define audio_out_                     _resetmask(AUDIO_OUT)
+#define audio_out_set                  _setmask(AUDIO_OUT)
+#define audio_out_reset                _resetmask(AUDIO_OUT)
+#define audio_out_power                _powermask(AUDIO_OUT)
+
+#define MONO_OUT                       24	 /*!<  Enable Mono-Audio mode (CEA-936.) */
+#define mono_out                       _setmask(MONO_OUT)
+#define mono_out_                      _resetmask(MONO_OUT)
+#define mono_out_set                   _setmask(MONO_OUT)
+#define mono_out_reset                 _resetmask(MONO_OUT)
+#define mono_out_power                 _powermask(MONO_OUT)
+ /* @) */
+
+ /*! @name Peripheral Controller Driver Outputs
+  * @{
+  */
+
+#define REMOTE_WAKEUP_OUT              25	 /*!<  Peripheral will perform remote wakeup. */
+#define remote_wakeup_out              _setmask(REMOTE_WAKEUP_OUT)
+#define remote_wakeup_out_             _resetmask(REMOTE_WAKEUP_OUT)
+#define remote_wakeup_out_set          _setmask(REMOTE_WAKEUP_OUT)
+#define remote_wakeup_out_reset        _resetmask(REMOTE_WAKEUP_OUT)
+#define remote_wakeup_out_power        _powermask(REMOTE_WAKEUP_OUT)
+ /* @) */
+
+ /*! @name Host Controller Driver Outputs
+  * @{
+  */
+
+#define LOC_SOF_OUT                    26	 /*!<  Host will enable packet traffic. */
+#define loc_sof_out                    _setmask(LOC_SOF_OUT)
+#define loc_sof_out_                   _resetmask(LOC_SOF_OUT)
+#define loc_sof_out_set                _setmask(LOC_SOF_OUT)
+#define loc_sof_out_reset              _resetmask(LOC_SOF_OUT)
+#define loc_sof_out_power              _powermask(LOC_SOF_OUT)
+
+#define LOC_SUSPEND_OUT                27	 /*!<  Host will suspend bus. */
+#define loc_suspend_out                _setmask(LOC_SUSPEND_OUT)
+#define loc_suspend_out_               _resetmask(LOC_SUSPEND_OUT)
+#define loc_suspend_out_set            _setmask(LOC_SUSPEND_OUT)
+#define loc_suspend_out_reset          _resetmask(LOC_SUSPEND_OUT)
+#define loc_suspend_out_power          _powermask(LOC_SUSPEND_OUT)
+
+#define REMOTE_WAKEUP_EN_OUT           28	 /*!<  Host will send remote wakeup enable or disable request. */
+#define remote_wakeup_en_out           _setmask(REMOTE_WAKEUP_EN_OUT)
+#define remote_wakeup_en_out_          _resetmask(REMOTE_WAKEUP_EN_OUT)
+#define remote_wakeup_en_out_set       _setmask(REMOTE_WAKEUP_EN_OUT)
+#define remote_wakeup_en_out_reset     _resetmask(REMOTE_WAKEUP_EN_OUT)
+#define remote_wakeup_en_out_power     _powermask(REMOTE_WAKEUP_EN_OUT)
+
+#define HNP_EN_OUT                     29	 /*!<  Host will send HNP enable request. */
+#define hnp_en_out                     _setmask(HNP_EN_OUT)
+#define hnp_en_out_                    _resetmask(HNP_EN_OUT)
+#define hnp_en_out_set                 _setmask(HNP_EN_OUT)
+#define hnp_en_out_reset               _resetmask(HNP_EN_OUT)
+#define hnp_en_out_power               _powermask(HNP_EN_OUT)
+
+#define HPWR_OUT                       30	 /*!<  Host will enable high power (external charge pump.) */
+#define hpwr_out                       _setmask(HPWR_OUT)
+#define hpwr_out_                      _resetmask(HPWR_OUT)
+#define hpwr_out_set                   _setmask(HPWR_OUT)
+#define hpwr_out_reset                 _resetmask(HPWR_OUT)
+#define hpwr_out_power                 _powermask(HPWR_OUT)
+ /* @) */
+#define MAX_OUTPUTS        31
+
+/* Generated by otg-ioctls-h.awk
+ *
+ * Do not Edit this file,
+ */
+
+
+#if defined(OTG_LINUX)
+
+#define OTGADMIN_MAGIC              'O'
+#define OTGADMIN_VERSION            _IOR(OTGADMIN_MAGIC, 1, u64)
+#define OTGADMIN_STATUS             _IOR(OTGADMIN_MAGIC, 3, struct otg_status_update)
+#define OTGADMIN_SET_FUNCTION       _IOW(OTGADMIN_MAGIC, 4, struct otg_admin_command)
+#define OTGADMIN_GET_FUNCTION       _IOR(OTGADMIN_MAGIC, 4, struct otg_admin_command)
+#define OTGADMIN_SET_INFO           _IOW(OTGADMIN_MAGIC, 5, struct otg_firmware_info)
+#define OTGADMIN_GET_INFO           _IOR(OTGADMIN_MAGIC, 5, struct otg_firmware_info)
+#define OTGADMIN_SET_STATE          _IOW(OTGADMIN_MAGIC, 6, struct otg_state)
+#define OTGADMIN_GET_STATE          _IOR(OTGADMIN_MAGIC, 6, struct otg_state)
+#define OTGADMIN_SET_TEST           _IOW(OTGADMIN_MAGIC, 7, struct otg_test)
+#define OTGADMIN_GET_TEST           _IOR(OTGADMIN_MAGIC, 7, struct otg_test)
+#define OTGADMIN_SET_SERIAL         _IOW(OTGADMIN_MAGIC, 8, struct otg_admin_command)
+#define OTGADMIN_GET_SERIAL         _IOR(OTGADMIN_MAGIC, 8, struct otg_admin_command)
+
+
+
+ /*!
+  * Signal Sent: a_bcon_no_tmout_req
+  * State Valid: otg_host
+  *     Application on A-host wants Ta_wait_bcon timeout disabled (non-OTG mode).
+  */
+#define OTGADMIN_A_BCON_NO_TMOUT_REQ         _IOW(OTGADMIN_MAGIC, 10, int)
+
+ /*!
+  * Signal Sent: a_hpwr_req
+  * State Valid: otg_host
+  *     Application on A-host wants external charge pump enabled.
+  */
+#define OTGADMIN_A_HPWR_REQ                  _IOW(OTGADMIN_MAGIC, 11, int)
+
+ /*!
+  * Signal Sent: bus_drop
+  * State Valid: otg_ok
+  *     Application on Device needs to power down bus.
+  */
+#define OTGADMIN_BUS_DROP                    _IOW(OTGADMIN_MAGIC, 12, int)
+
+ /*!
+  * Signal Sent: a_bus_drop
+  * State Valid: otg_ok
+  *     Application on A-Device needs to power down bus.
+  */
+#define OTGADMIN_A_BUS_DROP                  _IOW(OTGADMIN_MAGIC, 13, int)
+
+ /*!
+  * Signal Sent: b_bus_drop
+  * State Valid: otg_ok
+  *     Application on B-Device needs to disconnect from bus.
+  */
+#define OTGADMIN_B_BUS_DROP                  _IOW(OTGADMIN_MAGIC, 14, int)
+
+ /*!
+  * Signal Sent: bus_req
+  * State Valid: otg_ok
+  *     Application on Device wants to use the bus.
+  */
+#define OTGADMIN_BUS_REQ                     _IOW(OTGADMIN_MAGIC, 15, int)
+
+ /*!
+  * Signal Sent: a_bus_req
+  * State Valid: otg_ok
+  *     Application on A-Device wants to act as host
+  */
+#define OTGADMIN_A_BUS_REQ                   _IOW(OTGADMIN_MAGIC, 16, int)
+
+ /*!
+  * Signal Sent: b_bus_req
+  * State Valid: otg_ok
+  *     Application on B-Device wants to act as host
+  */
+#define OTGADMIN_B_BUS_REQ                   _IOW(OTGADMIN_MAGIC, 17, int)
+
+ /*!
+  * Signal Sent: b_sess_req
+  * State Valid: otg_ok
+  *     Application on B-Device to perform SRP (alias for b_srp_req.)
+  */
+#define OTGADMIN_B_SESS_REQ                  _IOW(OTGADMIN_MAGIC, 18, int)
+
+ /*!
+  * Signal Sent: suspend_req
+  * State Valid: otg_host
+  *     Application on Device requests bus be suspended (alias for a_bus_req/.)
+  */
+#define OTGADMIN_SUSPEND_REQ                 _IOW(OTGADMIN_MAGIC, 19, int)
+
+ /*!
+  * Signal Sent: a_suspend_req
+  * State Valid: otg_host
+  *     Application on A-host requests bus be suspended (alias for a_bus_req/.)
+  */
+#define OTGADMIN_A_SUSPEND_REQ               _IOW(OTGADMIN_MAGIC, 20, int)
+
+ /*!
+  * Signal Sent: b_suspend_req
+  * State Valid: otg_host
+  *     Application on B-host requests bus be suspended (alias for b_bus_req/.)
+  */
+#define OTGADMIN_B_SUSPEND_REQ               _IOW(OTGADMIN_MAGIC, 21, int)
+
+ /*!
+  * Signal Sent: set_remote_wakeup_cmd
+  * State Valid: a_host
+  *     A-Device will send Remote Wakeup Enable Request
+  */
+#define OTGADMIN_SET_REMOTE_WAKEUP_CMD       _IOW(OTGADMIN_MAGIC, 22, int)
+
+ /*!
+  * Signal Sent: remote_wakeup_cmd
+  * State Valid: tr_configured
+  *     B-Device will perform Remote Wakeup.
+  */
+#define OTGADMIN_REMOTE_WAKEUP_CMD           _IOW(OTGADMIN_MAGIC, 23, int)
+
+ /*!
+  * Signal Sent: reset_remote_wakeup_cmd
+  * State Valid: a_host
+  *     A-Device will send Remote Wakeup Disable Request
+  */
+#define OTGADMIN_RESET_REMOTE_WAKEUP_CMD     _IOW(OTGADMIN_MAGIC, 24, int)
+
+ /*!
+  * Signal Sent: clr_err_cmd
+  * State Valid: a_vbus_err
+  *     A-Device ill clears Vbus overcurrent error.
+  */
+#define OTGADMIN_CLR_ERR_CMD                 _IOW(OTGADMIN_MAGIC, 25, int)
+
+ /*!
+  * Signal Sent: b_hnp_cmd
+  * State Valid: b_configured
+  *     B-Device will attempt HNP
+  */
+#define OTGADMIN_B_HNP_CMD                   _IOW(OTGADMIN_MAGIC, 26, int)
+
+ /*!
+  * Signal Sent: ph_int_cmd
+  * State Valid: ph_audio
+  *     B-Device will request Carkit interrupt
+  */
+#define OTGADMIN_PH_INT_CMD                  _IOW(OTGADMIN_MAGIC, 27, int)
+
+ /*!
+  * Signal Sent: ph_audio_cmd
+  * State Valid: ph_uart
+  *     Application on B-Device connected to Carkit requests audio mode.
+  */
+#define OTGADMIN_PH_AUDIO_CMD                _IOW(OTGADMIN_MAGIC, 28, int)
+
+ /*!
+  * Signal Sent: cr_int_cmd
+  * State Valid: cr_aud
+  *     Application on A-Device wants to emulate Carkit
+  */
+#define OTGADMIN_CR_INT_CMD                  _IOW(OTGADMIN_MAGIC, 29, int)
+
+ /*!
+  * Signal Sent: led_on_cmd
+  * State Valid: ph_uart
+  *     B-Device will enable Carkit LED
+  */
+#define OTGADMIN_LED_ON_CMD                  _IOW(OTGADMIN_MAGIC, 30, int)
+
+ /*!
+  * Signal Sent: led_off_cmd
+  * State Valid: ph_uart
+  *     B-Device will disable Carkit LED
+  */
+#define OTGADMIN_LED_OFF_CMD                 _IOW(OTGADMIN_MAGIC, 31, int)
+
+ /*!
+  * Signal Sent: enable_otg
+  * State Valid: otg_all
+  *     Move State Machine otg_disabled state.
+  */
+#define OTGADMIN_ENABLE_OTG                  _IOW(OTGADMIN_MAGIC, 32, int)
+
+#define OTGADMIN_MAXNR 33
+
+
+#endif				/* defined(OTG_LINUX) */
+
+/* Generated by otg-iocontrol-h.awk
+ *
+ * Do not Edit this file,
+ */
+
+
+#if defined(OTG_WINCE)
+
+#define OTGADMIN_BASE$              0x401
+#define _USBLAN_CTL_CODE(_Function, _Method, _Access) \
+        CTL_CODE(OTGADMIN_BASE, _Function, _Method, _Access)
+
+#define OTGADMIN_VERSION            OTGADMIN_CTL_CODE(0x401, METHOD_BUFFERRED, FILE_READ_ACCESS)
+#define OTGADMIN_STATUS             OTGADMIN_CTL_CODE(0x403, METHOD_BUFFERRED, FILE_READ_ACCESS)
+#define OTGADMIN_SET_FUNCTION       OTGADMIN_CTL_CODE(0x404, METHOD_BUFFERRED, FILE_WRITE_ACCESS)
+#define OTGADMIN_GET_FUNCTION       OTGADMIN_CTL_CODE(0x404, METHOD_BUFFERRED, FILE_READ_ACCESS)
+#define OTGADMIN_SET_INFO           OTGADMIN_CTL_CODE(0x405, METHOD_BUFFERRED, FILE_WRITE_ACCESS)
+#define OTGADMIN_GET_INFO           OTGADMIN_CTL_CODE(0x405, METHOD_BUFFERRED, FILE_READ_ACCESS)
+#define OTGADMIN_SET_STATE          OTGADMIN_CTL_CODE(0x406, METHOD_BUFFERRED, FILE_WRITE_ACCESS)
+#define OTGADMIN_GET_STATE          OTGADMIN_CTL_CODE(0x406, METHOD_BUFFERRED, FILE_READ_ACCESS)
+#define OTGADMIN_SET_TEST           OTGADMIN_CTL_CODE(0x407, METHOD_BUFFERRED, FILE_WRITE_ACCESS)
+#define OTGADMIN_GET_TEST           OTGADMIN_CTL_CODE(0x407, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+
+
+ /*!
+  * Signal Sent: a_bcon_no_tmout_req
+  * State Valid: otg_host
+  *     Application on A-host wants Ta_wait_bcon timeout disabled (non-OTG mode).
+  */
+#define OTGADMIN_A_BCON_NO_TMOUT_REQ         OTGADMIN_CTL_CODE(, 0x40a, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: a_hpwr_req
+  * State Valid: otg_host
+  *     Application on A-host wants external charge pump enabled.
+  */
+#define OTGADMIN_A_HPWR_REQ                  OTGADMIN_CTL_CODE(, 0x40b, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: bus_drop
+  * State Valid: otg_ok
+  *     Application on Device needs to power down bus.
+  */
+#define OTGADMIN_BUS_DROP                    OTGADMIN_CTL_CODE(, 0x40c, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: a_bus_drop
+  * State Valid: otg_ok
+  *     Application on A-Device needs to power down bus.
+  */
+#define OTGADMIN_A_BUS_DROP                  OTGADMIN_CTL_CODE(, 0x40d, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: b_bus_drop
+  * State Valid: otg_ok
+  *     Application on B-Device needs to disconnect from bus.
+  */
+#define OTGADMIN_B_BUS_DROP                  OTGADMIN_CTL_CODE(, 0x40e, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: bus_req
+  * State Valid: otg_ok
+  *     Application on Device wants to use the bus.
+  */
+#define OTGADMIN_BUS_REQ                     OTGADMIN_CTL_CODE(, 0x40f, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: a_bus_req
+  * State Valid: otg_ok
+  *     Application on A-Device wants to act as host
+  */
+#define OTGADMIN_A_BUS_REQ                   OTGADMIN_CTL_CODE(, 0x410, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: b_bus_req
+  * State Valid: otg_ok
+  *     Application on B-Device wants to act as host
+  */
+#define OTGADMIN_B_BUS_REQ                   OTGADMIN_CTL_CODE(, 0x411, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: b_sess_req
+  * State Valid: otg_ok
+  *     Application on B-Device to perform SRP (alias for b_srp_req.)
+  */
+#define OTGADMIN_B_SESS_REQ                  OTGADMIN_CTL_CODE(, 0x412, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: suspend_req
+  * State Valid: otg_host
+  *     Application on Device requests bus be suspended (alias for a_bus_req/.)
+  */
+#define OTGADMIN_SUSPEND_REQ                 OTGADMIN_CTL_CODE(, 0x413, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: a_suspend_req
+  * State Valid: otg_host
+  *     Application on A-host requests bus be suspended (alias for a_bus_req/.)
+  */
+#define OTGADMIN_A_SUSPEND_REQ               OTGADMIN_CTL_CODE(, 0x414, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: b_suspend_req
+  * State Valid: otg_host
+  *     Application on B-host requests bus be suspended (alias for b_bus_req/.)
+  */
+#define OTGADMIN_B_SUSPEND_REQ               OTGADMIN_CTL_CODE(, 0x415, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: set_remote_wakeup_cmd
+  * State Valid: a_host
+  *     A-Device will send Remote Wakeup Enable Request
+  */
+#define OTGADMIN_SET_REMOTE_WAKEUP_CMD       OTGADMIN_CTL_CODE(, 0x416, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: remote_wakeup_cmd
+  * State Valid: tr_configured
+  *     B-Device will perform Remote Wakeup.
+  */
+#define OTGADMIN_REMOTE_WAKEUP_CMD           OTGADMIN_CTL_CODE(, 0x417, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: reset_remote_wakeup_cmd
+  * State Valid: a_host
+  *     A-Device will send Remote Wakeup Disable Request
+  */
+#define OTGADMIN_RESET_REMOTE_WAKEUP_CMD     OTGADMIN_CTL_CODE(, 0x418, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: clr_err_cmd
+  * State Valid: a_vbus_err
+  *     A-Device ill clears Vbus overcurrent error.
+  */
+#define OTGADMIN_CLR_ERR_CMD                 OTGADMIN_CTL_CODE(, 0x419, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: b_hnp_cmd
+  * State Valid: b_configured
+  *     B-Device will attempt HNP
+  */
+#define OTGADMIN_B_HNP_CMD                   OTGADMIN_CTL_CODE(, 0x41a, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: ph_int_cmd
+  * State Valid: ph_audio
+  *     B-Device will request Carkit interrupt
+  */
+#define OTGADMIN_PH_INT_CMD                  OTGADMIN_CTL_CODE(, 0x41b, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: ph_audio_cmd
+  * State Valid: ph_uart
+  *     Application on B-Device connected to Carkit requests audio mode.
+  */
+#define OTGADMIN_PH_AUDIO_CMD                OTGADMIN_CTL_CODE(, 0x41c, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: cr_int_cmd
+  * State Valid: cr_aud
+  *     Application on A-Device wants to emulate Carkit
+  */
+#define OTGADMIN_CR_INT_CMD                  OTGADMIN_CTL_CODE(, 0x41d, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: led_on_cmd
+  * State Valid: ph_uart
+  *     B-Device will enable Carkit LED
+  */
+#define OTGADMIN_LED_ON_CMD                  OTGADMIN_CTL_CODE(, 0x41e, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: led_off_cmd
+  * State Valid: ph_uart
+  *     B-Device will disable Carkit LED
+  */
+#define OTGADMIN_LED_OFF_CMD                 OTGADMIN_CTL_CODE(, 0x41f, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+ /*!
+  * Signal Sent: enable_otg
+  * State Valid: otg_all
+  *     Move State Machine otg_disabled state.
+  */
+#define OTGADMIN_ENABLE_OTG                  OTGADMIN_CTL_CODE(, 0x420, METHOD_BUFFERRED, FILE_READ_ACCESS)
+
+#define OTGADMIN_MAXNR 33
+
+
+#endif				/* defined(OTG_WINCE) */
+
+/* Generated by otg-metas-h.awk
+ *
+ * Do not Edit thie file
+ */
+
+
+ /*! @name OTG Figure 6-2 Meta States
+  *
+  * These are the Meta States defined in the 2.0 OTG Specification
+  * Figure 6.2 - Dual-Role A-Device.
+  * @{
+  */
+
+#define m_a_idle                          0	 /*  */
+
+#define m_a_wait_vrise                    1	 /*  */
+
+#define m_a_wait_bcon                     2	 /*  */
+
+#define m_a_host                          3	 /*  */
+
+#define m_a_suspend                       4	 /*  */
+
+#define m_a_peripheral                    5	 /*  */
+
+#define m_a_wait_vfall                    6	 /*  */
+
+#define m_a_vbus_err                      7	 /*  */
+ /* @} */
+ /*! @name OTG Figure 6-3 Meta States
+  *
+  * These are the Meta States defined in the 2.0 OTG Specification
+  * Figure 6.3 - Dual-Role B-Device.
+  * @{
+  */
+
+#define m_b_idle                          8	 /*  */
+
+#define m_b_srp_init                      9	 /*  */
+
+#define m_b_peripheral                   10	 /*  */
+
+#define m_b_suspend                      11	 /*  */
+
+#define m_b_wait_acon                    12	 /*  */
+
+#define m_b_host                         13	 /*  */
+
+#define m_b_suspended                    14	 /*  */
+ /* @} */
+ /*! @name Carkit Meta States Figure 7-7
+  *
+  * @{
+  */
+
+#define m_ph_disc                        15	 /*  Equivalent to b_peripheral */
+
+#define m_ph_init                        16	 /*  */
+
+#define m_ph_uart                        17	 /*  */
+
+#define m_ph_aud                         18	 /*  */
+
+#define m_ph_wait                        19	 /*  */
+
+#define m_ph_exit                        20	 /*  */
+
+#define m_cr_init                        21	 /*  */
+
+#define m_cr_uart                        22	 /*  */
+
+#define m_cr_aud                         23	 /*  */
+
+#define m_cr_ack                         24	 /*  */
+
+#define m_cr_wait                        25	 /*  */
+
+#define m_cr_disc                        26	 /*  */
+ /* @} */
+ /*! @name Additional states used locally.
+  *
+  * @{
+  */
+
+#define m_otg_init                       27	 /*  */
+
+#define m_usb_accessory                  28	 /*  */
+
+#define m_usb_factory                    29	 /*  */
+
+#define m_unknown                        30	 /*  */
+ /* @} */
+
+#define OTG_METAS_FW     31
+
+extern char    *otg_meta_names[];
diff -uNr linux/drivers/no-otg/otg/otg-hcd.h linux/drivers/otg/otg/otg-hcd.h
--- linux/drivers/no-otg/otg/otg-hcd.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-hcd.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,85 @@
+/*
+ * otg/otg-hcd.h - OTG Host Controller Driver
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ */
+/*!
+ * @defgroup OTGHCD Host Controller Driver Support
+ * @ingroup onthegogroup
+ */
+/*!
+ * @file otg/otg/otg-hcd.h
+ * @brief Defines common to On-The-Go Host Controller Support
+ *
+ * This file defines the hcd_ops and hcd_instance structures.
+ *
+ * The hcd_ops structure contains all of the output functions that will
+ * be called as required by the OTG event handler when changing states.
+ *
+ * The hcd_instance structure is used to maintain the global data
+ * required by the host controller drivers.
+ *
+ * @ingroup OTGHCD
+ */
+
+/*!
+ * @name HCD Host Controller Driver
+ * @{
+ */
+struct hcd_instance;
+
+/*!
+ * @struct hcd_ops
+ * The pcd_ops structure contains pointers to all of the functions implemented for the
+ * linked in driver. Having them in this structure allows us to easily determine what
+ * functions are available without resorting to ugly compile time macros or ifdefs
+ *
+ * There is only one instance of this, defined in the device specific lower layer.
+ */
+struct hcd_ops {
+
+        /* mandatory */
+        int max_ports;                                  /*!< maximum number of ports available */
+        u32 capabilities;                               /*!< UDC Capabilities - see usbd-bus.h for details */
+        char *name;                                     /*!< name of controller */
+
+        /* Driver Initialization - by degrees
+         */
+        int (*mod_init) (void);                         /*!< HCD Module Initialization */
+        void (*mod_exit) (void);                        /*!< HCD Module Exit */
+
+
+        otg_output_proc_t       hcd_init_func;          /*!< OTG calls to initialize or de-initialize the HCD */
+        otg_output_proc_t       hcd_en_func;            /*!< OTG calls to enable or disable the HCD */
+        otg_output_proc_t       loc_sof_func;           /*!< OTG calls to into a_host or b_host state - attempt to use port */
+        otg_output_proc_t       loc_suspend_func;       /*!< OTG calls to suspend bus */
+        otg_output_proc_t       remote_wakeup_en_func;  /*!< OTG calls to issue SET FEATURE REMOTE WAKEUP */
+        otg_output_proc_t       hnp_en_func;            /*!< OTG calls to issues SET FEATURE B_HNP_ENABLE */
+};
+
+/*!
+ * @struct hcd_instance
+ */
+struct hcd_instance {
+        struct otg_instance *otg;                       /*!< pointer to OTG Instance */
+        void * privdata;                                /*!< pointer to private data for PCD */
+        struct WORK_STRUCT bh;                          /*!< work structure for bottom half handler */
+};
+
+#define HCD hcd_trace_tag
+extern otg_tag_t HCD;
+extern struct hcd_ops hcd_ops;
+extern struct hcd_instance *hcd_instance;
+
+extern void hcd_init_func(struct otg_instance *, u8 );
+extern void hcd_en_func(struct otg_instance *, u8 );
+
+/* @} */
+
diff -uNr linux/drivers/no-otg/otg/otg-linux.h linux/drivers/otg/otg/otg-linux.h
--- linux/drivers/no-otg/otg/otg-linux.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-linux.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,284 @@
+/*
+ * otg/otg/otg-linux.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ */
+
+/*!
+ * @file otg/otg/otg-linux.h
+ * @brief Linux OS Compatibility defines
+ *
+ * @ingroup OTGCore
+ */
+#ifndef _OTG_LINUX_H
+#define _OTG_LINUX_H 1
+
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <asm/types.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <asm/atomic.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+
+/*! @name Compilation Related
+ */
+
+/*! @{ */
+#undef PRAGMAPACK
+#define PACKED __attribute__((packed))
+#define INLINE __inline__
+
+/*! @} */
+
+/*! @name Memory Allocation Primitives
+ *
+ * CKMALLOC()
+ * LSTRDUP()
+ * LKFREE()
+ * LIST_ENTRY()
+ * LIST_FOR_EACH()
+ */
+
+ /*! @{ */
+
+#if defined(LINUX26)
+    #include <linux/gfp.h>
+#define GET_KERNEL_PAGE()  __get_free_page(GFP_KERNEL)
+
+#else /* LINUX26 */
+
+    #include <linux/mm.h>
+    #define GET_KERNEL_PAGE() get_free_page(GFP_KERNEL)
+#endif /* LINUX26 */
+
+
+
+// Common to all supported versions of Linux ??
+
+#define CKMALLOC(n,f) _ckmalloc(__FUNCTION__, __LINE__, n, f)
+#define LSTRDUP(str) _lstrdup(__FUNCTION__, __LINE__, str)
+#define LKFREE(p) _lkfree(__FUNCTION__, __LINE__, p)
+
+#define ckmalloc(n,f) _ckmalloc(__FUNCTION__, __LINE__, n, f)
+#define lstrdup(str) _lstrdup(__FUNCTION__, __LINE__, str)
+#define lkfree(p) _lkfree(__FUNCTION__, __LINE__, p)
+
+#define OTG_MALLOC_TEST
+#undef OTG_MALLOC_DEBUG
+
+#ifdef OTG_MALLOC_TEST
+    extern int otg_mallocs;
+#endif
+
+
+static INLINE void *_ckmalloc (const char *func, int line, int n, int f)
+{
+    void *p;
+    if ((p = kmalloc (n, f)) == NULL) {
+        return NULL;
+    }
+    memset (p, 0, n);
+    #ifdef OTG_MALLOC_TEST
+    ++otg_mallocs;
+    #endif
+    #ifdef OTG_MALLOC_DEBUG
+        printk(KERN_INFO"%s: %p %s %d %d\n", __FUNCTION__, p, func, line, otg_mallocs);
+    #endif
+    return p;
+}
+
+static INLINE char *_lstrdup (const char *func, int line, char *str)
+{
+    int n;
+    char *s;
+    if (str && (n = strlen (str) + 1) && (s = kmalloc (n, GFP_ATOMIC))) {
+#ifdef OTG_MALLOC_TEST
+        ++otg_mallocs;
+#endif
+#ifdef OTG_MALLOC_DEBUG
+        printk(KERN_INFO"%s: %p %s %d %d\n", __FUNCTION__, s, func, line, otg_mallocs);
+#endif
+        return strcpy (s, str);
+    }
+    return NULL;
+}
+
+static INLINE void _lkfree (const char *func, int line, void *p)
+{
+    if (p) {
+#ifdef OTG_MALLOC_TEST
+        --otg_mallocs;
+#endif
+#ifdef OTG_MALLOC_DEBUG
+        printk(KERN_INFO"%s: %p %s %d %d\n", __FUNCTION__, p, func, line, otg_mallocs);
+#endif
+        kfree (p);
+#ifdef MALLOC_TEST
+        if (otg_mallocs < 0) {
+                printk(KERN_INFO"%s: %p %s %d %d otg_mallocs less zero!\n", __FUNCTION__, p, func, line, otg_mallocs);
+        }
+#endif
+#ifdef OTG_MALLOC_DEBUG
+        else {
+            printk(KERN_INFO"%s: %s %d NULL\n", __FUNCTION__, func, line);
+        }
+#endif
+    }
+}
+
+#if 1
+#include <linux/list.h>
+#define LIST_NODE struct list_head
+#define LIST_NODE_INIT(name) struct list_head name = {&name, &name}
+#define LIST_ENTRY(pointer, type, member) list_entry(pointer, type, member)
+#define LIST_FOR_EACH(cursor, head) list_for_each(cursor, head)
+#define LIST_ADD_TAIL(n,h) list_add_tail(n,h)
+#define LIST_DEL(h) list_del(&(h))
+#else
+#include <otg/otg-list.h>
+#endif
+
+/*! @} */
+
+
+/*! @name Atomic Operations
+ *
+ * atomic_post_inc()
+ * atomic_pre_dec()
+ */
+/*! @{ */
+static __inline__ int atomic_post_inc(volatile atomic_t *v)
+{
+        unsigned long flags;
+        int result;
+        local_irq_save(flags);
+        result = (v->counter)++;
+        local_irq_restore(flags);
+        return(result);
+}
+
+static __inline__ int atomic_pre_dec(volatile atomic_t *v)
+{
+        unsigned long flags;
+        int result;
+        local_irq_save(flags);
+        result = --(v->counter);
+        local_irq_restore(flags);
+        return(result);
+}
+/*! @} */
+
+
+
+/*!@name Scheduling Primitives
+ *
+ * WORK_STRUCT
+ * WORK_ITEM
+ *
+ * SCHEDULE_TIMEOUT()\n
+ * SET_WORK_ARG()\n
+ * SCHEDULE_WORK()\n
+ * SCHEDULE_IMMEDIATE_WORK()\n
+ * NO_WORK_DATA()\n
+ * MOD_DEC_USE_COUNT\n
+ * MOD_INC_USE_COUNT\n
+ */
+
+/*! @{ */
+
+static void inline SCHEDULE_TIMEOUT(int seconds){
+        schedule_timeout( seconds * HZ );
+}
+
+
+/* Separate Linux 2.4 and 2.6 versions of scheduling primitives */
+#if defined(LINUX26)
+    #include <linux/workqueue.h>
+
+    #define WORK_STRUCT  work_struct
+    #define WORK_ITEM    work_struct
+    typedef struct WORK_ITEM WORK_ITEM;
+    #if 0
+        #define PREPARE_WORK_ITEM(__item,__routine,__data) INIT_WORK((__item),(__routine),(__data))
+    #else
+        #include <linux/interrupt.h>
+        #define PREPARE_WORK_ITEM(__item,__routine,__data) __prepare_work(&(__item),(__routine),(__data))
+        static inline void __prepare_work(struct work_struct *_work,
+            void (*_routine),
+            void * _data){
+            INIT_LIST_HEAD(&_work->entry);
+            _work->pending = 0;
+            _work->func = _routine;
+            _work->data = _data;
+            init_timer(&_work->timer);
+        }
+    #endif
+    #undef PREPARE_WORK
+    typedef void (* WORK_PROC)(void *);
+
+    #define SET_WORK_ARG(__item, __data) (__item).data = __data
+
+    #define SCHEDULE_WORK(item) schedule_work(&item)
+    #define SCHEDULE_IMMEDIATE_WORK(item) SCHEDULE_WORK((item))
+    #define PENDING_WORK_ITEM(item) (item.pending != 0)
+    #define NO_WORK_DATA(item) (!item.data)
+    #define _MOD_DEC_USE_COUNT   //Not used in 2.6
+    #define _MOD_INC_USE_COUNT   //Not used in 2.6
+
+#else /* LINUX26 */
+
+    #define WORK_STRUCT  tq_struct
+    #define WORK_ITEM    tq_struct
+    typedef struct WORK_ITEM WORK_ITEM;
+    #define PREPARE_WORK_ITEM(item,work_routine,work_data) { item.routine = work_routine; item.data = work_data; }
+    #define SET_WORK_ARG(__item, __data) (__item).data = __data
+    #define NO_WORK_DATA(item) (!(item).data)
+    #define SCHEDULE_WORK(item) schedule_task(&item)
+    #define PENDING_WORK_ITEM(item) (item.sync != 0)
+    #define _MOD_DEC_USE_COUNT   MOD_DEC_USE_COUNT
+    #define _MOD_INC_USE_COUNT   MOD_INC_USE_COUNT
+
+    typedef void (* WORK_PROC)(void *);
+
+    #if !defined(IRQ_HANDLED)
+        // Irq's
+        typedef void irqreturn_t;
+        #define IRQ_NONE
+        #define IRQ_HANDLED
+        #define IRQ_RETVAL(x)
+    #endif
+#endif /* LINUX26 */
+
+/*! @} */
+
+/*!@name Semaphores
+ *
+ * up()
+ * down()
+ */
+/*! @{ */
+#define UP(s) up(s)
+#define DOWN(s) down(s)
+/*! @} */
+
+/*! @name Printk
+ *
+ * PRINTK()
+ */
+/*! @{ */
+#define PRINTK(s) printk(s)
+/*! @} */
+
+
+#endif /* _OTG_LINUX_H */
diff -uNr linux/drivers/no-otg/otg/otg-list.h linux/drivers/otg/otg/otg-list.h
--- linux/drivers/no-otg/otg/otg-list.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-list.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,69 @@
+#ifndef _OTG_LIST_H
+#define _OTG_LIST_H 1
+
+/*
+	This file defines doubly linked list capabilities 
+	needed. Many operating systems have built in capabilities
+	which match and may possibly be borrowed.
+
+
+        Here is a typical implementation
+*/
+
+struct otg_list_node { 
+	struct otg_list_node *previous, *next;
+};
+typedef struct otg_list_node otg_list_node_t, *otg_list_node_ptr;
+
+//A macro to define an list node within a structure
+#define OTG_LIST_HEAD     struct otg_list_node  
+#define OTG_LIST_HEAD_INIT(name) struct otg_list_node name = {&name, &name};
+//Assume that an OTG_LIST_HEAD pointer is embedded as structure
+// Recover numerical offset of member "member" within a pointer to a "type"
+#define __OTG_PTR_OFFSET(type, member) (u32) (   &(((type *) 0)->member) )
+//Recover typed pointer from pointer to interior of type at the given offset
+#define __OTG_PTR_CONTAINER(ptr, type, member) (type *) ((char *) ptr - __OTG_PTR_OFFSET(type,member))
+// member "member" of type "type". Recover a pointer to the beginning of the structure
+
+#define OTG_LIST_ENTRY(pointer, type, member) __OTG_PTR_CONTAINER(pointer, type, member)
+
+//Recover list header embedded in structure which is a member of a list
+#define OTG_LIST_MEMBER(pointer, member) &(ptr->member)
+//Add an entry at the logical end of the list
+
+//#define INLINE inline
+#define OTG_LIST_ADD_TAIL(new_entry, list_head) __otg_list_add_tail(new_entry, list_head)
+static INLINE void __otg_list_add_tail(struct otg_list_node *new_entry, struct otg_list_node *list_head)
+{
+	struct otg_list_node *old_previous = list_head->previous;
+	old_previous->next = new_entry;
+        new_entry->next = list_head;
+        new_entry->previous = old_previous;
+        list_head -> previous = new_entry;
+
+}
+
+//Delete an entry from the surrounding list
+#define OTG_LIST_DEL_ENTRY(del_entry)  __otg_list_del_entry(&(del_entry))
+
+static void INLINE __otg_list_del_entry(struct otg_list_node *del_entry){
+	//Remove from list 
+	del_entry->previous->next = del_entry->next;
+	del_entry->next->previous = del_entry->previous;
+	//Invalidate the entry
+	del_entry->previous = NULL;
+	del_entry->next = NULL;
+}
+
+#define  OTG_LIST_FOR_EACH(cursor, list) for(cursor=(list)->next; cursor != (list); cursor=cursor->next)
+
+#undef LIST_HEAD
+#define LIST_HEAD OTG_LIST_HEAD
+#undef LIST_HEAD_INIT
+#define LIST_HEAD_INIT(name) OTG_LIST_HEAD_INIT(name)
+#define LIST_ENTRY(pointer,type,member) OTG_LIST_ENTRY(pointer,type,member)
+#define LIST_ADD_TAIL(new_entry, list_head) OTG_LIST_ADD_TAIL(new_entry, list_head)
+#define LIST_DEL_ENTRY(del_entry) OTG_LIST_DEL_ENTRY(del_entry)
+#define LIST_FOR_EACH(cursor, list)  OTG_LIST_FOR_EACH(cursor, list)
+
+#endif /*_OTG_LIST_H */
diff -uNr linux/drivers/no-otg/otg/otg-module.h linux/drivers/otg/otg/otg-module.h
--- linux/drivers/no-otg/otg/otg-module.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-module.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,71 @@
+/*
+ * otg/otg/otg-module.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ */
+/*!
+ * @file otg/otg/otg-module.h
+ * @brief Linux Module OS Compatibility defines
+ *
+ *
+ * @ingroup OTGCore
+ */
+#ifndef _OTG_MODULE_H
+#define _OTG_MODULE_H 1
+
+#if defined(OTG_LINUX)
+    #if !defined(_LINUX_MODULE_H)
+        #include <linux/module.h>
+    #endif /* _LINUX_MODULE_H */
+    
+    #if defined(MODULE)
+
+        #define MOD_EXIT(exit_routine) module_exit(exit_routine)
+        #define MOD_INIT(init_routine) module_init(init_routine)
+        #define MOD_PROC(proc) (proc)
+        #define MOD_AUTHOR(string) MODULE_AUTHOR(string)
+        #define MOD_PARM(param, type) MODULE_PARM(param, type)
+        #define MOD_PARM_DESC(param,desc) MODULE_PARM_DESC(param, desc)
+        #define MOD_DESCRIPTION(description) MODULE_DESCRIPTION(description)
+        #define OTG_EXPORT_SYMBOL(symbol) EXPORT_SYMBOL(symbol)
+        #define OTG_EPILOGUE  1 /* EPILOGUE ROUTINE NEEDED */
+    
+    #else /* defined(MODULE) */
+
+        #define MOD_EXIT(exit_routine) 
+        #define MOD_INIT(init_routine) module_init(init_routine)
+        #define MOD_PROC(proc) NULL
+        #define MOD_AUTHOR(string) 
+        #define MOD_PARM(param, type)
+        #define MOD_PARM_DESC(param,desc)
+        #define MOD_DESCRIPTION(description) 
+        #define OTG_EXPORT_SYMBOL(symbol) //EXPORT_SYMBOL(symbol)
+        #undef EXPORT_SYMBOL
+        #define OTG_EPILOGUE 0  /* EPILOGUE ROUTINE NOT NEEDED */
+
+    #endif /* defined(MODULE) */
+    
+    //#undef MODULE_AUTHOR
+    //#undef MODULE_DESCRIPTION
+    //#undef MODULE_PARM_DESC
+    //#undef MODULE_PARM
+    #if defined(LINUX24) || defined(LINUX26)
+        #include <linux/version.h>
+        #if defined(MODULE) && (LINUX_VERSION_CODE >= KERNEL_VERSION (2,4,17))
+        //"GPL License applies under certain cirumstances; consult your vendor for details"
+            #define EMBED_LICENSE() MODULE_LICENSE ("GPL")
+        #else 
+            #define EMBED_LICENSE()   //Operation not supported for earlier Linux kernels
+        #endif
+
+    #else /* defined(LINUX24) || defined(LINUX26) */
+        #error "Need to define EMBED_LICENSE for the current operating system"
+    #endif /* defined(LINUX24) || defined(LINUX26) */
+    #define EMBED_MODULE_INFO(section,moduleinfo) static char __##section##_module_info[] = moduleinfo "balden@belcarra.com"
+    #define EMBED_USBD_INFO(moduleinfo) EMBED_MODULE_INFO(usbd,moduleinfo)
+    #define GET_MODULE_INFO(section) __##section##_module_info
+#endif /* defined(OTG_LINUX) */
+    
+    
+#endif
diff -uNr linux/drivers/no-otg/otg/otg-ocd.h linux/drivers/otg/otg/otg-ocd.h
--- linux/drivers/no-otg/otg/otg-ocd.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-ocd.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,94 @@
+/*
+ * otg/otg-ocd.h - OTG Controller Driver
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ */
+/*!
+ * @defgroup OTGOCD OTG Controller Driver Support
+ * @ingroup onthegogroup
+ */
+/*!
+ * @file otg/otg/otg-ocd.h
+ * @brief Defines common to On-The-Go OTG Controller Support
+ *
+ * This file defines the ocd_ops and ocd_instance structures.
+ *
+ * The ocd_ops structure contains all of the output functions that will
+ * be called as required by the OTG event handler when changing states.
+ *
+ * The ocd_instance structure is used to maintain the global data
+ * required by the OTG controller drivers.
+ *
+ * @ingroup OTGOCD
+ */
+
+/*!
+ * @name OCD OTG Controller Driver
+ * @{
+ */
+//struct ocd_instance;
+
+struct ocd_instance {
+        struct otg_instance *otg;
+        void * privdata;
+};
+
+
+typedef int (*otg_timer_callback_proc_t) (void *);
+
+#define OCD_CAPABILITIES_DR          1 << 0
+#define OCD_CAPABILITIES_PO          1 << 1
+#define OCD_CAPABILITIES_TR          1 << 2
+#define OCD_CAPABILITIES_HOST        1 << 3
+
+#define OCD_CAPABILITIES_AUTO        1 << 4
+
+
+/*!
+ * @struct ocd_ops
+ * The ocd_ops structure contains pointers to all of the functions implemented for the
+ * linked in driver. Having them in this structure allows us to easily determine what
+ * functions are available without resorting to ugly compile time macros or ifdefs
+ *
+ * There is only one instance of this, defined in the device specific lower layer.
+ */
+struct ocd_ops {
+
+        u32 capabilities;                               /* OCD Capabilities */
+
+        /* Driver Initialization - by degrees
+         */
+        int (*mod_init) (void);                         /*!< OCD Module Initialization */
+        void (*mod_exit) (void);                        /*!< OCD Module Exit */
+
+        otg_output_proc_t       ocd_init_func;          /*!< OTG calls to initialize or de-initialize the OCD */
+
+        int (*start_timer) (struct otg_instance *, int);/*!< called by OTG to start timer */
+        u64 (*ticks) (void);            /*!< called by OTG to  fetch current ticks, typically micro-seconds when available */
+        u64 (*elapsed) ( u64 *, u64 *);                 /*!< called by OTG to get micro-seconds elapsed between two ticks */
+        u32 interrupts;                                 /*!< called by OTG to get number of interrupts */
+};
+
+
+#if 0
+struct ocd_instance {
+        struct otg_instance *otg;
+        void * privdata;
+};
+#endif
+
+#ifndef OTG_APPLICATION
+
+//#define OCD ocd_trace_tag
+extern otg_tag_t OCD;
+extern struct ocd_ops ocd_ops;
+extern struct ocd_instance *ocd_instance;
+#endif
+/* @} */
diff -uNr linux/drivers/no-otg/otg/otg-p2k.h linux/drivers/otg/otg/otg-p2k.h
--- linux/drivers/no-otg/otg/otg-p2k.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-p2k.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,208 @@
+/*
+ * otg/otg/otg-p2k.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ */
+/*!
+ * @file otg/otg/otg-p2k.h
+ * @brief Linux OS Compatibility defines
+ *
+ * @ingroup OTGCore
+ */
+
+#ifndef _OTG_P2K_H 1
+#define _OTG_P2K_H 1
+
+/*!@name Common Platform 2000 includes
+ */
+/*! * @{ */
+
+/* UNKNOWN SO FAR */
+/*! @} */
+
+/*!@name  Compilation Related
+ */
+
+/*! @{ */
+#define PRAGMAPACK
+#define PACKED 
+#define INLINE __inline
+
+/*! @} */
+
+/*!@name OTG int typedefs
+ */
+/*! * @{ */
+typedef unsigned short u16;
+typedef unsigned char u8;
+typedef unsigned long int u32;
+typedef __int64 u64;
+typedef unsigned char __u8;
+typedef unsigned short __u16;
+typedef unsigned long int __u32;
+typedef __int64 __u64;
+
+/*! @} */
+
+/*!@name  Memory Allocation Primitives
+ *
+ * CKMALLOC()
+ * LSTRDUP()
+ * LKFREE()
+ * LIST_ENTRY()
+ */
+/*! @{ */
+
+#define GFP_KERNEL 0
+#define GFP_ATOMIC 0
+
+#define CKMALLOC(n,f) _ckmalloc(__FILE__, __LINE__, n, f)
+#define LSTRDUP(str) _lstrdup(__FILE__, __LINE__, str)
+#define LKFREE(p) _lkfree(__FILE__, __LINE__, p)
+
+#define OTG_MALLOC_TEST
+#undef OTG_MALLOC_DEBUG
+
+#ifdef OTG_MALLOC_TEST
+    extern int otg_mallocs;
+#endif
+
+static INLINE void *_ckmalloc (const char *func, int line, int n, int f)
+{
+
+	return 0;
+}
+static INLINE char *_lstrdup (const char *func, int line, char *str)
+{
+
+	return 0;
+}
+static INLINE void _lkfree (const char *func, int line, void *p)
+{
+}
+
+// XXX 
+#define LIST_ENTRY(p, t, m) \
+        ((t *)((char *)(p)-(unsigned long)(&((t *)0)->m)))
+
+// XXX
+#define LIST_FOR_EACH(p, h) \
+        for (p = (h)->next, (p->next); p != (h); \
+                p = p->next, (p->next))
+
+#define LIST_ADD_TAIL(n,h) (0)
+#define LIST_ADD_TAIL(n,h) (0)
+#define LIST_DEL(h) (0)
+
+
+/*! @} */
+
+
+/*! @name Atomic Operations
+ *
+ * atomic_post_inc()
+ * atomic_pre_dec()
+ */
+/*! @{ */
+
+/* @} */
+
+
+
+/*! @name Scheduling Primitives
+ *
+ * WORK_STRUCT
+ * WORK_ITEM
+ *
+ * SCHEDULE_TIMEOUT()
+ * SET_WORK_ARG()
+ * SCHEDULE_WORK()
+ * SCHEDULE_IMMEDIATE_WORK()
+ * NO_WORK_DATA()
+ * MOD_DEC_USE_COUNT
+ * MOD_INC_USE_COUNT
+ */
+/*! @{ */
+#define HZ      60
+#define SCHEDULE_TIMEOUT(seconds)
+
+    #define SCHEDULE_WORK(item) (0)
+#define PENDING_WORK_ITEM(item) (0)
+#define PREPARE_WORK_ITEM(__item,__routine,__data) (0)
+
+/*! @} */
+
+
+/*! @name Semaphores
+ *
+ * up()
+ * down()
+ */
+/*! @{ */
+#define UP(s) 
+#define DOWN(s) 
+/*! @} */
+
+
+/*!@name Printk
+ *
+ * PRINTK()
+ */
+/*! @{ */
+//#define PRINTK(s) printk(s)
+//          DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s"), _T(msg)));
+
+/*! @} */
+
+/*! @name Little Endian Macros
+ * /
+ *! @{ 
+ */
+
+__inline u16 cpu_to_le16 ( u16 x )
+{
+        return (x<<8) | (x>>8);
+}
+
+__inline u16 le16_to_cpu ( u16 val )
+{
+        return ((((val) >> 8) & 0xff) | (((val) & 0xff) << 8));
+}
+
+__inline u32 le32_to_cpu (u32 val)
+{
+        return (((val) & 0xff000000) >> 24) | (((val) & 0x00ff0000) >>  8) |
+                (((val) & 0x0000ff00) <<  8) | (((val) & 0x000000ff) << 24);
+}
+/*! @} */
+
+/*! @name little endian macros
+ */
+/*! @{ */
+#define local_irq_save(f) f = 0; __asm cli
+#define local_irq_restore(f) __asm sti
+
+/*! @} */
+
+/*! @name Ioctl
+ */
+/*! @{ */
+#define _IOR(m,n,s) ((m)|(n))
+#define _IOW(m,n,s) ((m)|(n))
+#define _IOCSIZE(a) (sizeof(a))
+#define copy_from_user(d,s,n) memcpy(d,s,n)
+#define copy_to_user(d,s,n) memcpy(d,s,n)
+
+/*! @} */
+
+/*! @name ERRNO
+ */
+/*! @{ */
+#define EINVAL  WSAEINVAL
+
+/*! @} */
+
+
+
+#endif /* _OTG_P2K_H */
diff -uNr linux/drivers/no-otg/otg/otg-pcd.h linux/drivers/otg/otg/otg-pcd.h
--- linux/drivers/no-otg/otg/otg-pcd.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-pcd.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,84 @@
+/*
+ * otg/otg-pcd.h - OTG Peripheral Controller Driver
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+/*!
+ * @defgroup OTGPCD Peripheral Controller Driver Support
+ * @ingroup onthegogroup
+ */
+/*!
+ * @file otg/otg/otg-pcd.h
+ * @brief Defines common to On-The-Go Peripheral Controller Support
+ *
+ * This file defines the pcd_ops and pcd_instance structures.
+ *
+ * The pcd_ops structure contains all of the output functions that will
+ * be called as required by the OTG event handler when changing states.
+ *
+ * The pcd_instance structure is used to maintain the global data
+ * required by the peripheral controller drivers.
+ *
+ * @ingroup OTGPCD
+ */
+
+/*!
+ * @name PCD Peripheral Controller Driver
+ * @{
+ */
+typedef u16 (*framenum_t)(void);
+
+/*!
+ * @struct pcd_ops
+ *
+ * The pcd_ops structure contains pointers to all of the functions implemented for the
+ * linked in driver. Having them in this structure allows us to easily determine what
+ * functions are available without resorting to ugly compile time macros or ifdefs
+ *
+ * There is only one instance of this, defined in the device specific lower layer.
+ */
+struct pcd_ops {
+
+        int (*mod_init) (void);                         /*!< PCD Module Initialization */
+        void (*mod_exit) (void);                        /*!< PCD Module Exit */
+       
+        otg_output_proc_t       pcd_init_func;          /*!< OTG calls to initialize or de-initialize the PCD */
+        otg_output_proc_t       pcd_en_func;            /*!< OTG calls to enable or disable the PCD */
+        otg_output_proc_t       remote_wakeup_func;     /*!< OTG calls to have PCD perform remote wakeup */
+
+        framenum_t		framenum;               /*!< OTG calls to get current USB Frame number */
+};
+
+#define PCD pcd_trace_tag
+extern otg_tag_t PCD;
+extern struct pcd_ops pcd_ops;
+extern struct pcd_instance *pcd_instance;
+
+/*!
+ * @struct pcd_instance
+ */
+struct pcd_instance {
+        struct otg_instance *otg;                       /*!< pointer to OTG Instance */
+        struct usbd_bus_instance *bus;                  /*!< pointer to usb bus instance */
+        void * privdata;                                /*!< pointer to private data for PCD */
+        int pcd_exiting;                                /*!< non-zero if OTG is unloading */
+        struct WORK_STRUCT bh;                          /*!< work structure for bottom half handler */
+        
+};
+
+
+#if !defined(OTG_C99)
+extern void pcd_global_init(void);
+#endif /* !defined(OTG_C99) */
+extern void pcd_init_func(struct otg_instance *, u8 );
+extern void pcd_en_func(struct otg_instance *, u8 );
+
+/* @} */
+
diff -uNr linux/drivers/no-otg/otg/otg-tcd.h linux/drivers/otg/otg/otg-tcd.h
--- linux/drivers/no-otg/otg/otg-tcd.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-tcd.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,114 @@
+/*
+ * otg/otg-tcd.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+/*!
+ * @defgroup OTGTCD Transceiver Controller Driver Support
+ * @ingroup onthegogroup
+ */
+/*!
+ * @file otg/otg/otg-tcd.h
+ * @brief Defines common to On-The-Go Transceiver Controller Support
+ *
+ * This file defines the tcd_ops and tcd_instance structures.
+ *
+ * The tcd_ops structure contains all of the output functions that will
+ * be called as required by the OTG event handler when changing states.
+ *
+ * The tcd_instance structure is used to maintain the global data
+ * required by the transceiver controller drivers.
+ *
+ * @ingroup OTGTCD
+ */
+
+/*!
+ * @name TCD Transceiver Controller Driver
+ * @{
+ */
+
+
+/*!
+ * @struct tcd_ops
+ * The pcd_ops structure contains pointers to all of the functions implemented for the
+ * linked in driver. Having them in this structure allows us to easily determine what
+ * functions are available without resorting to ugly compile time macros or ifdefs
+ *
+ * There is only one instance of this, defined in the device specific lower layer.
+ */
+struct tcd_ops {
+        u64 initial_state;
+        
+        void * privdata;
+
+        /* Driver Initialization - by degrees
+         */
+        int (*mod_init) (void);                         /*!< TCD Module Initialization */
+        void (*mod_exit) (void);                        /*!< TCD Module Exit */
+
+
+        /* 3. called for usbd_vbus() if defined */
+        int (*vbus) (struct otg_instance *);            /* return non-zero if the Vbus valid */
+        int (*id) (struct otg_instance *);              /* return non-zero if the ID valid */
+
+        /* 4. called by otg event to control outputs
+         */
+
+        otg_output_proc_t       tcd_init_func;          /*!< OTG calls to initialize or de-initialize the HCD */
+        otg_output_proc_t       tcd_en_func;            /*!< OTG calls to enable or disable the TCD */
+        otg_output_proc_t       chrg_vbus_func;         /*!< OTG calls to enable or disable charging Vbus */
+        otg_output_proc_t       drv_vbus_func;          /*!< OTG calls to enable or disable Vbus */
+        otg_output_proc_t       dischrg_vbus_func;      /*!< OTG calls to enable or disable discharging Vbus */
+        otg_output_proc_t       dp_pullup_func;         /*!< OTG calls to enable or disable D+ pullup (aka loc_conn) */
+        otg_output_proc_t       dm_pullup_func;         /*!< OTG calls to enable or disable D- pullup (aka loc_carkit) */
+        otg_output_proc_t       dp_pulldown_func;       /*!< OTG calls to enable or disable D+ pulldown (aka loc_conn) */
+        otg_output_proc_t       dm_pulldown_func;       /*!< OTG calls to enable or disable D- pulldown (aka loc_carkit) */
+        otg_output_proc_t       peripheral_host_func;   /*!< OTG calls to enable or disable D- pulldown (aka loc_carkit) */
+        otg_output_proc_t       overcurrent_func;       /*!< OTG calls to clear overcurrent indication */
+        otg_output_proc_t       dm_det_func;            /*!< OTG calls to enable or disable D+ pullup detection */
+        otg_output_proc_t       dp_det_func;            /*!< OTG calls to enable or disable D- pullup detection */
+        otg_output_proc_t       cr_det_func;            /*!< OTG calls to enable or disable D+ CRINT detection */
+        otg_output_proc_t       charge_pump_func;       /*!< OTG calls to enable or disable external charge pump */
+        otg_output_proc_t       bdis_acon_func;         /*!< OTG calls to enable or disable the BDIS ACON feature */
+        otg_output_proc_t       mx21_vbus_drain_func;   /*!< OTG calls to enable or disable the mx21 vbus drain feature */
+        otg_output_proc_t       id_pulldown_func;       /*!< OTG calls to enable or disable ID pulldown to ground */
+        otg_output_proc_t       audio_func;             /*!< OTG calls to enable or disable audio function */
+        otg_output_proc_t       uart_func;              /*!< OTG calls to enable or disable uart function */
+        otg_output_proc_t       mono_func;              /*!< OTG calls to enable or disable mono function */
+};
+
+/*!
+ * @struct hcd_instance
+ */
+struct tcd_instance {
+        struct otg_instance *otg;                       /*!< pointer to OTG Instance */
+        struct WORK_STRUCT bh;                          /*!< work structure for bottom half handler */
+};
+
+
+extern struct trace_ops trace_ops;
+extern struct tcd_ops tcd_ops;
+
+
+extern struct tcd_instance *tcd_instance;
+extern int tcd_vbus (struct otg_instance *otg);
+
+/* pcd_cable_event[_irq] - these can be called in a traditional PCD implementation 
+ * to set b_sess_vld appropriately when vbus is sensed (pcd must implement ocd_ops.vbus)
+ */
+extern void tcd_cable_event_irq (struct otg_instance *);
+extern void tcd_cable_event (struct otg_instance *);
+
+//extern void tcd_init(struct otg_instance *, u8 );
+
+#define TCD tcd_trace_tag
+extern otg_tag_t TCD;
+
+/* @} */
diff -uNr linux/drivers/no-otg/otg/otg-trace.h linux/drivers/otg/otg/otg-trace.h
--- linux/drivers/no-otg/otg/otg-trace.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-trace.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,404 @@
+/*
+ * otg/otgcore/otg-trace.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *
+ */
+/*!
+ * @file otg/otg/otg-trace.h
+ * @brief Core Defines for USB OTG Core Layaer
+ *
+ * Fast Trace Utility
+ * This set of definitions and code is meant to provide a _fast_ debugging facility
+ * (much faster than printk) so that time critical code can be debugged by looking
+ * at a trace of events provided by reading a file in the procfs without affecting
+ * the timing of events in the critical code.
+ *
+ * The mechanism used it to allocate a (large) ring buffer of relatively small structures
+ * that include location and high-res timestamp info, and up to 8 bytes of optional
+ * data.  Values are stored and timestamps are taken as the critical code runs, but
+ * data formatting and display are done during the procfs read, when more time is
+ * available :).
+ *
+ * Note that there is usually some machine dependent code involved in getting the
+ * high-res timestamp, and there may be other bits used just to keep the overall
+ * time impact as low as possible.
+ *
+ * Varargs up to 9 arguments are now supported, but you have to supply the number
+ * of args, since examining the format string for the number at trace event time
+ * was deemed too expensive time-wise.
+ * 
+ *
+ * @ingroup OTGCore
+ */
+
+#ifndef OTG_TRACE_H
+#define OTG_TRACE_H 1
+
+//#include <linux/interrupt.h>
+
+
+
+typedef u8 otg_tag_t;  // 1-origin tags (0 ==> invalid/unused trace entry.  Max is 32.
+
+#ifdef PRAGMAPACK
+#pragma pack(push,1)
+#endif /* PRAGMAPACK */
+typedef enum otg_trace_types {
+        otg_trace_msg_invalid_n,
+        otg_trace_msg_va_start_n,
+        otg_trace_msg_va_list_n,
+        otg_trace_setup_n,
+        otg_trace_msg_n,
+        otg_trace_msg32_n,
+        otg_trace_msg16_n,
+        otg_trace_msg8_n
+} PACKED otg_trace_types_t;
+#ifdef PRAGMAPACK
+#pragma pack(pop)
+#endif /* PRAGMAPACK */
+
+typedef struct otg_trace_msg {
+        char    *msg;
+} otg_trace_msg_t;
+
+typedef struct otg_trace_msg32 {
+        char    *msg;
+        u32      val;
+} otg_trace_msg32_t;
+
+typedef struct otg_trace_msg16 {
+        char    *msg;
+        u16     val0;
+        u16     val1;
+} otg_trace_msg16_t;
+
+typedef struct otg_trace_msg8 {
+        char    *msg;
+        u8      val0;
+        u8      val1;
+        u8      val2;
+        u8      val3;
+} otg_trace_msg8_t;
+
+#define OTG_TRACE_MAX_IN_VA                  7
+typedef struct otg_trace_msg_va_list {
+        u32     val[OTG_TRACE_MAX_IN_VA];
+} otg_trace_msg_va_list_t;
+
+typedef struct otg_trace_msg_va_start {
+        const char    *function;
+        u32     interrupts;
+        u64     ticks;
+        u16     framenum;
+        u16     dummy;
+
+        union {
+                otg_trace_msg_t        msg;
+                otg_trace_msg8_t       msg8;
+                otg_trace_msg16_t      msg16;
+                otg_trace_msg32_t      msg32;
+
+#if !defined(BELCARRA_DEBUG)
+                struct usbd_device_request       setup;
+#else
+                unsigned char setup[8];
+#endif /* !defined(BELCARRA_DEBUG) */
+
+        } trace;
+} PACKED otg_trace_msg_va_start_t;
+
+typedef struct trace {
+        otg_trace_types_t        otg_trace_type;
+        otg_tag_t                tag;
+        u8                       va_num_args;
+        u8                       in_interrupt:1;
+        u8                       id_gnd:1;
+        union {
+                otg_trace_msg_va_start_t s;
+                otg_trace_msg_va_list_t l;
+        } va;
+} PACKED otg_trace_t;
+
+#define TRACE_MAX_IS_2N 1
+#define TRACE_MAX  0x00008000
+#define TRACE_MASK 0x00007FFF
+//#define TRACE_MAX  0x000080
+//#define TRACE_MASK 0x00007F
+
+
+#if defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE)
+
+#if !defined(OLD_TRACE_API)
+
+// The new API hides otg_trace_get_next(), and adds otg_trace_setup() as part of the core.
+
+#if !defined(BELCARRA_DEBUG)
+extern void otg_trace_setup(otg_tag_t tag, const char *fn, void *setup);
+#define TRACE_SETUP(tag,setup)     otg_trace_setup(tag,__FUNCTION__,setup)
+#endif
+#define TRACE_MSG0(tag, msg)       otg_trace_msg(tag, __FUNCTION__, 0, msg,  0)                                
+#define TRACE_FMSG0(tag, f, msg)   otg_trace_msg(tag, f, 0, msg,  0)                                
+
+#else
+
+extern int otg_trace_first;
+extern int otg_trace_last_read;
+extern int otg_trace_next;
+
+#if 0
+
+extern otg_trace_t *otg_traces;
+
+
+otg_trace_t *otg_trace_get_next(otg_tag_t tag, const char *fn, otg_trace_types_t otg_trace_type, int n);
+
+#if !defined(BELCARRA_DEBUG)
+/*
+ * Trace a setup packet.
+ * The BELCARRA_DEBUG guard is so the rest of these functions can be used
+ * outside of a USB context, such as debugging TTY flow control.
+ */
+static __inline__ void otg_trace_setup(otg_tag_t tag, const char *fn, struct usbd_device_request *setup)
+{
+        if (otg_traces) {
+                otg_trace_t *p = otg_trace_get_next(tag,fn,otg_trace_setup_n,1);
+                memcpy(&p->va.s.trace.setup, setup, sizeof(struct usbd_device_request));
+        }
+}
+#define TRACE_SETUP(tag,setup) otg_trace_setup(tag,__FUNCTION__,setup)
+#endif /* !defined(BELCARRA_DEBUG) */
+
+/*
+ * Trace a single non-parameterized message.
+ */
+static __inline__ void otg_trace_msg_0(otg_tag_t tag, const char *fn, char *msg)
+{
+        if (otg_traces) {
+                otg_trace_t *p = otg_trace_get_next(tag,fn,otg_trace_msg_n,1);
+                p->va.s.trace.msg.msg = msg;
+        }
+}
+#define TRACE_MSG0(tag, msg) otg_trace_msg_0(tag, __FUNCTION__, msg)
+#define TRACE_FMSG0(tag, f, msg) otg_trace_msg_0(tag, f, msg)
+
+/*
+ * Trace a message with a single 32-bit value.
+ */
+static __inline__ void otg_trace_msg_1xU32(otg_tag_t tag, const char *fn, char *fmt, u32 val)
+{
+        if (otg_traces) {
+                otg_trace_t *p = otg_trace_get_next(tag,fn,otg_trace_msg32_n,1);
+                p->va.s.trace.msg32.val = val;
+                p->va.s.trace.msg32.msg = fmt;
+        }
+}
+#define OTRACE_MSG1(tag,fmt,val) otg_trace_msg_1xU32(tag,__FUNCTION__,fmt,(u32)val)
+
+/*
+ * Trace a message with two 16-bit values.
+ */
+static __inline__ void otg_trace_msg_2xU16(otg_tag_t tag, const char *fn, char *fmt, u16 val0, u16 val1)
+{
+        if (otg_traces) {
+                otg_trace_t *p = otg_trace_get_next(tag,fn,otg_trace_msg16_n,1);
+                p->va.s.trace.msg16.val0 = val0;
+                p->va.s.trace.msg16.val1 = val1;
+                p->va.s.trace.msg16.msg = fmt;
+        }
+}
+#define OTRACE_MSG2(tag,fmt,val0,val1) otg_trace_msg_2xU16(tag,__FUNCTION__,fmt,(u16)val0,(u16)val1)
+
+/*
+ * Trace a message with four 8-bit values.
+ */
+static __inline__ void otg_trace_msg_4xU8(otg_tag_t tag, const char *fn, char *fmt, u8 val0, u8 val1, u8 val2, u8 val3)
+{
+        if (otg_traces) {
+                otg_trace_t *p = otg_trace_get_next(tag,fn,otg_trace_msg8_n,1);
+                p->va.s.trace.msg8.val0 = val0;
+                p->va.s.trace.msg8.val1 = val1;
+                p->va.s.trace.msg8.val2 = val2;
+                p->va.s.trace.msg8.val3 = val3;
+                p->va.s.trace.msg8.msg = fmt;
+        }
+}
+#define OTRACE_MSG4(tag,fmt,val0,val1,val2,val3) otg_trace_msg_4xU8(tag,__FUNCTION__,fmt,(u8)val0,(u8)val1,(u8)val2,(u8)val3)
+#endif
+
+#endif
+
+extern void otg_trace_msg(otg_tag_t tag, const char *fn, u8 nargs, char *fmt, ...);
+
+#define eprintf(format, args...)  printk (KERN_INFO format , ## args)
+
+#define TRACE_MSG(tag, nargs, fmt, args...) otg_trace_msg(tag, __FUNCTION__, nargs, fmt, ## args)
+
+#define TRACE_MSG1(tag, fmt, a1) \
+        otg_trace_msg(tag, __FUNCTION__, 1, fmt,  a1)                                
+#define TRACE_MSG2(tag, fmt, a1, a2) \
+        otg_trace_msg(tag, __FUNCTION__, 2, fmt,  a1, a2)                            
+#define TRACE_MSG3(tag, fmt, a1, a2, a3) \
+        otg_trace_msg(tag, __FUNCTION__, 3, fmt,  a1, a2, a3)                        
+#define TRACE_MSG4(tag, fmt, a1, a2, a3, a4) \
+        otg_trace_msg(tag, __FUNCTION__, 4, fmt,  a1, a2, a3, a4)                    
+#define TRACE_MSG5(tag, fmt, a1, a2, a3, a4, a5) \
+        otg_trace_msg(tag, __FUNCTION__, 5, fmt,  a1, a2, a3, a4, a5)                
+#define TRACE_MSG6(tag, fmt, a1, a2, a3, a4, a5, a6) \
+        otg_trace_msg(tag, __FUNCTION__, 6, fmt,  a1, a2, a3, a4, a5, a6)            
+#define TRACE_MSG7(tag, fmt, a1, a2, a3, a4, a5, a6, a7) \
+        otg_trace_msg(tag, __FUNCTION__, 7, fmt,  a1, a2, a3, a4, a5, a6, a7)        
+#define TRACE_MSG8(tag, fmt, a1, a2, a3, a4, a5, a6, a7, a8) \
+        otg_trace_msg(tag, __FUNCTION__, 8, fmt,  a1, a2, a3, a4, a5, a6, a7, a8)    
+#if 0
+#define TRACE_MSG9(tag, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
+        otg_trace_msg(tag, __FUNCTION__, 9, fmt,  a1, a2, a3, a4, a5, a6, a7, a8, a9)
+#endif
+#define TRACE_FMSG1(tag, f, fmt, a1) \
+        otg_trace_msg(tag, f, 1, fmt,  a1)                                
+#define TRACE_FMSG2(tag, f, fmt, a1, a2) \
+        otg_trace_msg(tag, f, 2, fmt,  a1, a2)                            
+#define TRACE_FMSG3(tag, f, fmt, a1, a2, a3) \
+        otg_trace_msg(tag, f, 3, fmt,  a1, a2, a3)                        
+#define TRACE_FMSG4(tag, f, fmt, a1, a2, a3, a4) \
+        otg_trace_msg(tag, f, 4, fmt,  a1, a2, a3, a4)                    
+#define TRACE_FMSG5(tag, f, fmt, a1, a2, a3, a4, a5) \
+        otg_trace_msg(tag, f, 5, fmt,  a1, a2, a3, a4, a5)                
+#define TRACE_FMSG6(tag, f, fmt, a1, a2, a3, a4, a5, a6) \
+        otg_trace_msg(tag, f, 6, fmt,  a1, a2, a3, a4, a5, a6)            
+#define TRACE_FMSG7(tag, f, fmt, a1, a2, a3, a4, a5, a6, a7) \
+        otg_trace_msg(tag, f, 7, fmt,  a1, a2, a3, a4, a5, a6, a7)        
+#define TRACE_FMSG8(tag, f, fmt, a1, a2, a3, a4, a5, a6, a7, a8) \
+        otg_trace_msg(tag, f, 8, fmt,  a1, a2, a3, a4, a5, a6, a7, a8)    
+#if 0
+#define TRACE_FMSG9(tag, f, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
+        otg_trace_msg(tag, f, 9, fmt,  a1, a2, a3, a4, a5, a6, a7, a8, a9)
+#endif
+extern otg_tag_t otg_trace_obtain_tag(void);
+extern otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag);
+
+#elif defined(OTG_WINCE)
+
+#define TRACE_MSG0(tag, msg) \
+          DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s"), _T(msg)))
+
+#define TRACE_MSG1(tag, fmt, a1) \
+		  DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d"), _T(fmt), a1))
+
+#define TRACE_MSG2(tag, fmt, a1, a2) \
+		  DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d"), _T(fmt), a1, a2))
+
+#define TRACE_MSG3(tag, fmt, a1, a2, a3) \
+		  DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d"), _T(fmt), a1, a2, a3));
+
+#define TRACE_MSG4(tag, fmt, a1, a2, a3, a4) \
+		  DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d %d %d"), _T(fmt), a1, a2, a3, a4));
+
+#define TRACE_MSG5(tag, fmt, a1, a2, a3, a4, a5) \
+		  DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d %d %d %d"), _T(fmt), a1, a2, a3, a4, a5));
+
+#define TRACE_MSG6(tag, fmt, a1, a2, a3, a4, a5, a6) \
+		  DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d %d %d %d %d %d"), _T(fmt), a1, a2, a3, a4, a5, a6));
+
+#define TRACE_MSG7(tag, fmt, a1, a2, a3, a4, a5, a6, a7) \
+		  DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d %d %d %d %d %d %d"), _T(fmt), a1, a2, a3, a4, a5, a6, a7));
+
+#define TRACE_MSG8(tag, fmt, a1, a2, a3, a4, a5, a6, a7, a8) \
+		  DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CORE - %s %d %d %d %d %d %d %d %d %d"), _T(fmt), a1, a2, a3, a4, a5, a6, a7, a8));
+
+extern otg_tag_t otg_trace_obtain_tag(void);
+extern otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag);
+
+/*
+#define TRACE_OTG_CURRENT(o) \
+          DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CURRENT - %s (%s) RESET: %08x SET: %08x"),\
+                                otg_state_names[o->state], \
+                                otg_state_names[o->previous], \
+                                (u32)(~o->current_inputs), \
+                                (u32)(o->current_inputs))\
+						);
+
+#define TRACE_OTG_CHANGE(o) \
+          DEBUGMSG(ZONE_INIT,(_T("OTGCORE - CHANGE - %s (%s) RESET: %08x SET: %08x"),\
+                                otg_state_names[o->state], \
+                                otg_state_names[o->previous], \
+                                (u32)(~o->current_inputs), \
+                                (u32)(o->current_inputs))\
+						);
+
+#define TRACE_OTG_NEW(o) \
+          DEBUGMSG(ZONE_INIT,(_T("OTGCORE - NEW - %s (%s) RESET: %08x SET: %08x"),\
+                                otg_state_names[o->state], \
+                                otg_state_names[o->previous], \
+                                (u32)(~o->current_inputs), \
+                                (u32)(o->current_inputs))\
+						);
+
+#define TRACE_OTG_INPUTS(u) \
+          DEBUGMSG(ZONE_INIT,(_T("OTGCORE - INPUTS - RESET: %08x SET: %08x"),\
+                                (u32)(u >> 32), \
+                                (u32)(u & 0xffffffff))\
+						);
+*/
+
+extern otg_tag_t otg_trace_obtain_tag(void);
+extern otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag);
+
+#else /* defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE) */
+
+#define TRACE_SETUP(tag,setup)
+
+//#define TRACE_MSG(tag,nargs,fmt,...)
+//#define TRACE_FMSG(tag, nargs,fmt,...)
+
+#define TRACE_MSG0(tag, fmt) 
+#define TRACE_MSG1(tag, fmt, a1) 
+#define TRACE_MSG2(tag, fmt, a1, a2) 
+#define TRACE_MSG3(tag, fmt, a1, a2, a3) 
+#define TRACE_MSG4(tag, fmt, a1, a2, a3, a4) 
+#define TRACE_MSG5(tag, fmt, a1, a2, a3, a4, a5) 
+#define TRACE_MSG6(tag, fmt, a1, a2, a3, a4, a5, a6) 
+#define TRACE_MSG7(tag, fmt, a1, a2, a3, a4, a5, a6, a7) 
+#define TRACE_MSG8(tag, fmt, a1, a2, a3, a4, a5, a6, a7, a8) 
+//#define TRACE_MSG9(tag, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) 
+
+#define TRACE_FMSG0(tag, f, fmt) 
+#define TRACE_FMSG1(tag, f, fmt, a1) 
+#define TRACE_FMSG2(tag, f, fmt, a1, a2) 
+#define TRACE_FMSG3(tag, f, fmt, a1, a2, a3) 
+#define TRACE_FMSG4(tag, f, fmt, a1, a2, a3, a4) 
+#define TRACE_FMSG5(tag, f, fmt, a1, a2, a3, a4, a5) 
+#define TRACE_FMSG6(tag, f, fmt, a1, a2, a3, a4, a5, a6) 
+#define TRACE_FMSG7(tag, f, fmt, a1, a2, a3, a4, a5, a6, a7) 
+#define TRACE_FMSG8(tag, f, fmt, a1, a2, a3, a4, a5, a6, a7, a8) 
+//#define TRACE_FMSG9(tag, f, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) 
+
+//static inline otg_tag_t otg_trace_obtain_tag(void)
+//{
+//        return 0;
+//}
+
+//static inline otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag)
+//{
+//        return 0;
+//}
+
+extern otg_tag_t otg_trace_obtain_tag(void);
+extern otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag);
+
+#endif /* defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE) */
+
+#define USBD usbd_trace_tag
+extern otg_tag_t USBD;
+
+//#define ACM acm_trace_tag
+//extern otg_tag_t ACM;
+
+//#define NETWORK network_trace_tag
+//extern otg_tag_t NETWORK;
+
+#endif /* OTG_TRACE_H */
diff -uNr linux/drivers/no-otg/otg/otg-utils.h linux/drivers/otg/otg/otg-utils.h
--- linux/drivers/no-otg/otg/otg-utils.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/otg-utils.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,151 @@
+/*
+ * otg/otg/otg-utils.h
+ *
+ *      Basic utilities for OTG package
+ *      Copyright (c) 2004 Belcarra
+ */
+/*!
+ * @file otg/otg/otg-utils.h
+ * @brief Useful macros.
+ *
+ *
+ * @ingroup OTGCore
+ */
+
+
+#if !defined(_OTG_UTILS_H)
+#define _OTG_UTILS_H 1
+
+/*! @name Min, Max and zero
+ * @{
+ */
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define ZERO(a) memset(&a, 0, sizeof(a))
+
+/* @} */
+
+/*! @name TRUE and FALSE
+ *
+ * @{
+ */
+#if !defined(TRUE)
+#define TRUE 1
+#endif
+
+#if !defined(FALSE)
+#define FALSE 0
+#endif
+/* @} */
+
+
+/*! @name CATCH and THROW
+ *
+ * These macros implement a conceptually clean way to use
+ * C's goto to implement a standard error handler. The typical forms are:
+ *
+ *      THROW(error);                   // continue execution in CATCH statement
+ *      THROW_IF(test, error);          // continue execution in CATCH statement if test true
+ *      THROW_UNLESS(test, error);      // continue execution in CATCH statement if test false
+ *      
+ *      // program execution will continue after the CATCH statement;
+ *      CATCH(error) {
+ *              // handle error here
+ *      }
+ *
+ * @{
+ */
+#define CATCH(x) while(0) x:
+#define THROW(x) goto x
+#define THROW_IF(e, x) if (e)  goto x; 
+#define THROW_UNLESS(e, x) UNLESS (e)  goto x; 
+/* @} */
+
+
+/*! @name UNLESS
+ *
+ * This implements a simple equivalent to negated if (expression).
+ *
+ *      Unless expression then statement else statement.
+ *
+ * @{
+ */
+#define unless(x) if(!(x))
+#define UNLESS(x) if(!(x))
+/* @} */
+
+/*! @name BREAK_ and CONTINUE_
+ *
+ * These implement a conditional break and continue statement.
+ *
+ * @{
+ */
+#define BREAK_UNLESS(x) UNLESS (x)  break; 
+#define BREAK_IF(x) if (x)  break; 
+#define CONTINUE_IF(x) if (x)  continue; 
+#define CONTINUE_UNLESS(x) UNLESS (x)  continue; 
+
+/* @} */
+
+
+/*! @name RETURN_
+ *
+ * These implement conditional return statement.
+ * @{
+ */
+#define RETURN_IF(x) if (x)  return; 
+#define RETURN_ZERO_IF(x) if (x)  return 0; 
+#define RETURN_NULL_IF(x) if (x)  return NULL; 
+#define RETURN_EBUSY_IF(x) if (x)  return -EBUSY; 
+#define RETURN_EFAULT_IF(x) if (x)  return -EFAULT; 
+#define RETURN_EINVAL_IF(x) if (x)  return -EINVAL; 
+#define RETURN_ENOMEM_IF(x) if (x)  return -ENOMEM; 
+#define RETURN_EAGAIN_IF(x) if (x)  return -EAGAIN; 
+#define RETURN_ETIMEDOUT_IF(x) if (x)  return -ETIMEDOUT; 
+#define RETURN_EPIPE_IF(x) if (x)  return -EPIPE; 
+#define RETURN_IRQ_HANDLED_IF(x) if (x)  return IRQ_HANDLED; 
+#define RETURN_TRUE_IF(x) if (x)  return TRUE; 
+#define RETURN_FALSE_IF(x) if (x)  return FALSE; 
+
+#define RETURN_UNLESS(x) UNLESS (x)  return; 
+#define RETURN_NULL_UNLESS(x) UNLESS (x)  return NULL; 
+#define RETURN_ZERO_UNLESS(x) UNLESS (x)  return 0; 
+#define RETURN_EBUSY_UNLESS(x) UNLESS (x)  return -EBUSY; 
+#define RETURN_EFAULT_UNLESS(x) UNLESS (x)  return -EFAULT; 
+#define RETURN_EINVAL_UNLESS(x) UNLESS (x)  return -EINVAL; 
+#define RETURN_ENOMEM_UNLESS(x) UNLESS (x)  return -ENOMEM; 
+#define RETURN_EAGAIN_UNLESS(x) UNLESS (x)  return -EAGAIN; 
+#define RETURN_ETIMEDOUT_UNLESS(x) UNLESS (x)  return -ETIMEDOUT; 
+#define RETURN_EPIPE_UNLESS(x) UNLESS (x)  return -EPIPE; 
+#define RETURN_IRQ_HANDLED_UNLESS(x) UNLESS (x)  return IRQ_HANDLED; 
+#define RETURN_TRUE_UNLESS(x) UNLESS (x)  return TRUE; 
+#define RETURN_FALSE_UNLESS(x) UNLESS (x)  return FALSE; 
+
+/* @} */
+
+
+/*! @name likely and unlikely
+ *
+ * Under linux these can be used to provide a hint to GCC that
+ * the expression being evaluated is probably going to evaluate
+ * to true (likely) or false (unlikely). The intention is that
+ * GCC can then provide optimal code for that.
+ * @{
+ */
+#ifndef likely
+#define likely(x) x
+#endif
+
+#ifndef unlikely 
+#define unlikely(x) x
+#endif
+/* @} */
+
+
+#endif /* _OTG_UTILS_H */
+
diff -uNr linux/drivers/no-otg/otg/pcd-include.h linux/drivers/otg/otg/pcd-include.h
--- linux/drivers/no-otg/otg/pcd-include.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/pcd-include.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,36 @@
+/*
+ * otg/udc.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/otg/pcd-include.h
+ * @brief Linux OS Precompiled Headers 
+ *
+ * @ingroup OTGCore
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <otg/usbp-chap9.h>
+//#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-pcd.h>
+#include <otg/otg-ocd.h>
+#include <otg/usbp-pcd.h>
+
diff -uNr linux/drivers/no-otg/otg/usbp-bus.h linux/drivers/otg/otg/usbp-bus.h
--- linux/drivers/no-otg/otg/usbp-bus.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/usbp-bus.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,354 @@
+/*
+ * otg/otg/usbp-bus.h - USB Device Bus Interface Driver Interface
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+/*!
+ * @file otg/otg/usbp-bus.h
+ * @brief Bus interface Defines for USB Device Core Layaer
+ *
+ * This file contains the USB Peripheral Driver definitions.
+ *
+ * The 
+ *
+ * This is the interface between the bottom of the USB Core and the top of
+ * the Bus Interace Drivers and is comprised of:
+ *
+ *      o public functions exported by the USB Core layer 
+ *
+ *      o structures and functions passed by the Function Driver to the USB
+ *      Core layer
+ *
+ * USB Peripheral Controller Drivers are structured such that the upper edge
+ * implements interfaces to the USB Peripheral Core layer to provide low
+ * level USB services and the lower edge interfaces to the actual USB
+ * Hardware (typically called the USB Device Controller or UDC.)
+ *
+ * The peripheral controller layer primarily deals with endpoints.
+ * There is one control endpoint and one or more data endpoints.
+ *
+ * The control endpoint is special, with received data processed with
+ * the built in EP0 function. Which in turn will pass requests to 
+ * interface functions as appropriate.
+ *
+ * Data endpoints are controlled by interface driver and have a
+ * function callback specified by the interface driver to perform
+ * whatever needs to be done when data is sent or received.
+ *
+ *
+ *
+ * @ingroup USBP
+ */
+
+struct usbd_endpoint_map; 
+struct usbd_endpoint_instance;
+struct usbd_bus_instance;
+struct usbd_urb;
+
+/*!
+ * USB Bus Interface Driver structures
+ *
+ * Driver description:
+ * 
+ *  struct usbd_bus_operations
+ *  struct usbd_bus_driver
+ *
+ */
+
+extern int usbd_maxstrings;
+
+
+/*!
+ * exported to otg
+ */
+struct usbd_ops {
+        int (*admin) (char *);
+        char * (*function_name) (int);
+};
+
+
+
+/*! Operations that the slave layer or function driver can use to interact
+ * with the bus interface driver. 
+ *
+ * The send_urb() function is used by the usb-device endpoint 0 driver and
+ * function drivers to submit data to be sent.
+ *
+ * The cancel_urb() function is used by the usb-device endpoint 0 driver and
+ * function drivers to remove previously queued data to be sent.
+ *
+ * The endpoint_halted() function is used by the ep0 control function to
+ * check if an endpoint is halted.
+ *
+ * The endpoint_feature() function is used by the ep0 control function to
+ * set/reset device features on an endpoint.
+ *
+ * The device_event() function is used by the usb device core to tell the
+ * bus interface driver about various events.
+ */
+struct usbd_bus_operations {
+        //int (*xbus_serial_number) (struct usbd_bus_instance *, char *);
+
+        int (*start_endpoint_in) (struct usbd_bus_instance *, struct usbd_endpoint_instance *);
+        int (*start_endpoint_out) (struct usbd_bus_instance *, struct usbd_endpoint_instance *);
+        int (*cancel_urb_irq) (struct usbd_urb *);
+        //int (*device_feature) (struct usbd_bus_instance *, int, int);
+        int (*endpoint_halted) (struct usbd_bus_instance *, int, int);
+        int (*halt_endpoint) (struct usbd_bus_instance *, int, int, int);
+        int (*set_address) (struct usbd_bus_instance *, int);
+        int (*event_handler) (struct usbd_bus_instance *, usbd_device_event_t, int);
+        int (*request_endpoints) (struct usbd_bus_instance *, struct usbd_endpoint_map *, 
+                        int, struct usbd_endpoint_request *);
+        int (*set_endpoints) (struct usbd_bus_instance *, int , struct usbd_endpoint_map *);
+        int (*framenum) (void); 
+        u64 (*ticks) (void); 
+        u64 (*elapsed) (u64 *, u64 *); 
+        u64 (*interrupts) (void);
+};
+
+/*! Endpoint Map
+ *
+ * An array of these structures is created by the bus interface driver to
+ * show what endpoints have been configured for the function driver.
+ *
+ * This is the logical array of endpoints that are indexed into by the 
+ * function layer using the logical endpoint numbers defined by the function
+ * drivers. It maps these numbers into a real physical endpoint.
+ *
+ * Fields that can be different for Full speed versus High speed are 
+ * represented with an array both values are available.
+ *
+ * For interfaces with multiple alternate settings, each separate
+ * combinantion of interface_num/altsetting/endpoint must be specified.
+ * It is up to the lower layers to determine if / when overlapped 
+ * endpoints can be re-used.
+ *
+ */
+struct usbd_endpoint_map {
+        u8 configuration;
+        u8 interface_num;
+        u8 alternate;
+        u8 bEndpointAddress[2];         // logical endpoint address
+        u16 wMaxPacketSize[2];          // packetsSize for requested endpoint
+        u8 bmAttributes[2];             // requested endpoint type
+        u16 transferSize[2];            // transferSize for bulk transfers
+        u8 physicalEndpoint[2];         // physical endpoint number
+        struct usbd_endpoint_instance    *endpoint;
+};
+
+
+/*! Endpoint configuration
+ *
+ * Per endpoint configuration data. Used to track which actual physical
+ * endpoints.
+ *
+ * The bus layer maintains an array of these to represent all physical
+ * endpoints.
+ *
+ */
+struct usbd_endpoint_instance {
+        int                             bEndpointAddress;       // logical endpoint address 
+        int                             physical_endpoint;      // physical endpoint address - bus interface specific
+        int                             bmAttributes;           // endpoint type
+        u16                             wMaxPacketSize;         // packet size for requested endpoint
+        u32                             feature_setting;        // save set feature information
+
+        // control
+        int                             state;                  // available for use by bus interface driver
+
+        // receive side
+        struct urb_link                 rdy;                    // empty urbs ready to receive
+        struct usbd_urb                 *rcv_urb;               // active urb
+        u32                             rcv_transferSize;       // maximum transfer size from function driver
+        int                             rcv_error;              // current bulk-in has an error
+
+        // transmit side
+        struct urb_link                 tx;                     // urbs ready to transmit
+        struct usbd_urb                 *tx_urb;                // active urb
+        u32                             tx_transferSize;        // maximum transfer size from function driver
+
+        u32                             sent;                   // data already sent
+        u32                             last;                   // data sent in last packet XXX do we need this
+
+        void                            *privdata;
+
+};
+
+/*! @name endpoint zero states
+ * @{
+ */
+#define WAIT_FOR_SETUP          0
+#define DATA_STATE_XMIT         1
+#define DATA_STATE_NEED_ZLP     2
+#define WAIT_FOR_OUT_STATUS     3
+#define DATA_STATE_RECV         4
+#define DATA_STATE_PENDING_XMIT 5
+#define WAIT_FOR_IN_STATUS      6
+/*! @} */
+
+/*! Bus Interface data structure
+ *
+ * Keep track of specific bus interface. 
+ *
+ * This is passed to the usb-device layer when registering. It contains all
+ * required information about each real bus interface found such that the
+ * usb-device layer can create and maintain a usb-device structure.
+ *
+ * Note that bus interface registration is incumbent on finding specific
+ * actual real bus interfaces. There will be a registration for each such
+ * device found.
+ *
+ * The max_tx_endpoints and max_rx_endpoints are the maximum number of
+ * possible endpoints that this bus interface can support. The default
+ * endpoint 0 is not included in these counts.
+ *
+ */
+struct usbd_bus_driver {
+        char                            *name;
+        u8                              max_endpoints;  // maximimum number of rx enpoints
+        u8                              otg_bmAttributes;
+        u8                              maxpacketsize;
+        u8                              HighSpeedCapable;
+        struct usbd_device_description   *device_description;
+        struct usbd_bus_operations       *bops;
+        void                            *privdata;
+        u32                             capabilities;
+        u8                              bMaxPower;
+        u8                              ports;
+};
+
+/*!
+ * Bus state
+ *
+ * enabled or disabled
+ */
+typedef enum usbd_bus_state {
+        usbd_bus_state_unknown,
+        usbd_bus_state_disabled,
+        usbd_bus_state_enabled
+} usbd_bus_state_t;
+
+
+/*!
+ * @name UDC Capabilities
+ * @{
+ */
+#define HAVE_CABLE_IRQ                  0x0001
+#define REMOTE_WAKEUP_SUPPORTED         0x0002
+#define ROOT_HUB                        0x0004
+/*! @} */
+
+/*! Bus Interface configuration structure
+ *
+ * This is allocated for each configured instance of a bus interface driver.
+ *
+ * It contains a pointer to the appropriate bus interface driver.
+ *
+ * The privdata pointer may be used by the bus interface driver to store private
+ * per instance state information.
+ */
+struct usbd_bus_instance {
+
+        struct usbd_bus_driver           *driver;
+
+        int                              endpoints;
+        struct usbd_endpoint_instance    *endpoint_array;        // array of available configured endpoints
+
+        struct urb_link                 finished;               // processed urbs
+
+        //char                            *serial_number_str;
+
+        usbd_device_status_t             status;                 // device status
+        usbd_bus_state_t                 bus_state;
+        usbd_device_state_t              device_state;           // current USB Device state
+        usbd_device_state_t              suspended_state;        // previous USB Device state
+
+        struct usbd_function_instance    *ep0;                   // ep0 configuration
+        struct usbd_function_instance    *function_instance;
+
+
+        u8                              HighSpeedFlag;
+
+        u8                              ConfigurationValue;     // current set configuration (zero is default)
+        u8                              bNumInterfaces;         // number of interfaces in the current configuration
+        u8                              *alternates;            // array[0..interfaces-1] of alternate settings 
+                                                                // for each interface
+
+        u32                             device_feature_settings;// save set feature information
+        u8                              otg_bmAttributes;
+
+        struct WORK_STRUCT              device_bh;              // runs as bottom half, equivalent to interrupt time
+
+        void                            *privdata;              // private data for the bus interface
+        char                            *arg;
+};
+
+
+
+
+/*! bus driver registration
+ *
+ * Called by bus interface drivers to register themselves when loaded
+ * or de-register when unloading.
+ */
+struct usbd_bus_instance *usbd_register_bus (struct usbd_bus_driver *, int);
+void usbd_deregister_bus (struct usbd_bus_instance *);
+
+
+/*! Enable/Disable Function
+ *
+ * Called by a bus interface driver to select and enable a specific function 
+ * driver.
+ */
+int usbd_enable_function_irq (struct usbd_bus_instance *, char *, char *);
+void usbd_disable_function (struct usbd_bus_instance *);
+
+
+/*! 
+ * usbd_configure_device is used by function drivers (usually the control endpoint)
+ * to change the device configuration.
+ *
+ * usbd_device_event is used by bus interface drivers to tell the higher layers that
+ * certain events have taken place.
+ */
+void usbd_bus_event_handler (struct usbd_bus_instance *, usbd_device_event_t, int);
+void usbd_bus_event_handler_irq (struct usbd_bus_instance *, usbd_device_event_t, int);
+
+
+/*!
+ * usbd_device_request - process a received urb
+ * @urb: pointer to an urb structure
+ *
+ * Used by a USB Bus interface driver to pass received data in a URB to the
+ * appropriate USB Function driver.
+ *
+ * This function must return 0 for success and -EINVAL if the request
+ * is to be stalled.
+ *
+ * Not that if the SETUP is Host to Device with a non-zero wLength then there
+ * *MUST* be a valid receive urb queued OR the request must be stalled.
+ */
+int usbd_device_request (struct usbd_bus_instance*, struct usbd_device_request *);
+
+/*!
+ * Device I/O
+ */
+void usbd_urb_finished (struct usbd_urb *, int );
+void usbd_urb_finished_irq (struct usbd_urb *, int );
+struct usbd_urb *usbd_first_urb_detached_irq (urb_link * hd);
+
+/*! flush endpoint
+ */
+void usbd_flush_endpoint_irq (struct usbd_endpoint_instance *);
+void usbd_flush_endpoint (struct usbd_endpoint_instance *);
+int usbd_find_endpoint_index(struct usbd_bus_instance *bus, int bEndpointAddress);
+
+
+
diff -uNr linux/drivers/no-otg/otg/usbp-chap9.h linux/drivers/otg/otg/usbp-chap9.h
--- linux/drivers/no-otg/otg/usbp-chap9.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/usbp-chap9.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,1577 @@
+/*
+ * otg/otg/usbp-chap9.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ * By:
+ *      Stuart Lynne <sl@belcarra.com>,
+ *      Tom Rushworth <tbr@belcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @defgroup USBP USB Peripheral Support
+ * @ingroup onthegogroup
+ */
+
+ 
+/*!
+ * @file otg/otg/usbp-chap9.h
+ * @brief Chapter 9 and other class descriptor structure definitions.
+ *
+ * USB Descriptors are used to build a configuration database for each USB
+ * Function driver.
+ *
+ * @ingroup USBP
+ */
+
+/*!
+ * @name Device and/or Interface Class Codes
+ */
+
+ /*! @{ */
+
+
+#define USB_CLASS_PER_INTERFACE         0       /* for DeviceClass */
+#define USB_CLASS_AUDIO                 1
+#define USB_CLASS_COMM                  2
+#define USB_CLASS_HID                   3
+#define USB_CLASS_PHYSICAL              5
+#define USB_CLASS_PRINTER               7
+#define USB_CLASS_MASS_STORAGE          8
+#define USB_CLASS_HUB                   9
+#define USB_CLASS_DATA                  10
+#define USB_CLASS_APP_SPEC              0xfe
+#define USB_CLASS_VENDOR_SPEC           0xff
+/*! @} */
+
+
+/*! @name USB Device Request Types (bmRequestType)
+ *C.f. USB 2.0 Table 9-2
+*/
+
+/*! @{ */
+
+#define USB_TYPE_STANDARD               (0x00 << 5)
+#define USB_TYPE_CLASS                  (0x01 << 5)
+#define USB_TYPE_VENDOR                 (0x02 << 5)
+#define USB_TYPE_RESERVED               (0x03 << 5)
+
+#define USB_RECIP_DEVICE                0x00
+#define USB_RECIP_INTERFACE             0x01
+#define USB_RECIP_ENDPOINT              0x02
+#define USB_RECIP_OTHER                 0x03
+
+#define USB_RECIP_HUB                   0x00
+#define USB_RECIP_PORT                  0x03
+
+#define USB_DIR_OUT                     0
+#define USB_DIR_IN                      0x80
+#define USB_ENDPOINT_OPT                0x40
+/*! @} */
+
+/*! @name Descriptor types
+ * C.f. USB Table 9-5
+ */
+
+/*! @{ */
+
+#define USB_DT_DEVICE                           0x01
+#define USB_DT_CONFIGURATION                    0x02
+#define USB_DT_STRING                           0x03
+#define USB_DT_INTERFACE                        0x04
+#define USB_DT_ENDPOINT                         0x05
+#define USB_DT_DEVICE_QUALIFIER                 0x06
+#define USB_DT_OTHER_SPEED_CONFIGURATION        0x07
+#define USB_DT_INTERFACE_POWER                  0x08
+#define USB_DT_OTG                              0x09
+
+
+#define USB_DT_HID                      (USB_TYPE_CLASS | 0x01)
+#define USB_DT_REPORT                   (USB_TYPE_CLASS | 0x02)
+#define USB_DT_PHYSICAL                 (USB_TYPE_CLASS | 0x03)
+#define USB_DT_HUB                      (USB_TYPE_CLASS | 0x09)
+/*! @} */
+
+/*! @name Descriptor sizes per descriptor type
+ */
+ /*! @{ */
+
+#define USB_DT_DEVICE_SIZE              18
+#define USB_DT_CONFIG_SIZE              9
+#define USB_DT_INTERFACE_SIZE           9
+#define USB_DT_ENDPOINT_SIZE            7
+#define USB_DT_ENDPOINT_AUDIO_SIZE      9               /* Audio extension */
+#define USB_DT_HUB_NONVAR_SIZE          7
+#define USB_DT_HID_SIZE                 9
+/*! @} */
+
+/*! @name Endpoints
+ */
+/*! @{ */
+#define USB_ENDPOINT_NUMBER_MASK        0x0f            /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK           0x80
+
+#define USB_ENDPOINT_MASK               0x03            /* in bmAttributes */
+#define USB_ENDPOINT_CONTROL            0x00
+#define USB_ENDPOINT_ISOCHRONOUS        0x01
+#define USB_ENDPOINT_BULK               0x02
+#define USB_ENDPOINT_INTERRUPT          0x03
+/*! @} */
+
+/*!
+ * @name USB Packet IDs (PIDs)
+ */
+/*! @{ */
+#define USB_PID_UNDEF_0                        0xf0
+#define USB_PID_OUT                            0xe1
+#define USB_PID_ACK                            0xd2
+#define USB_PID_DATA0                          0xc3
+#define USB_PID_PING                           0xb4             /* USB 2.0 */
+#define USB_PID_SOF                            0xa5
+#define USB_PID_NYET                           0x96             /* USB 2.0 */
+#define USB_PID_DATA2                          0x87             /* USB 2.0 */
+#define USB_PID_SPLIT                          0x78             /* USB 2.0 */
+#define USB_PID_IN                             0x69
+#define USB_PID_NAK                            0x5a
+#define USB_PID_DATA1                          0x4b
+#define USB_PID_PREAMBLE                       0x3c             /* Token mode */
+#define USB_PID_ERR                            0x3c             /* USB 2.0: handshake mode */
+#define USB_PID_SETUP                          0x2d
+#define USB_PID_STALL                          0x1e
+#define USB_PID_MDATA                          0x0f             /* USB 2.0 */
+/*! @} */
+
+/*! * @name Standard requests
+ */
+
+  /*! @{ */
+
+#define USB_REQ_GET_STATUS              0x00
+#define USB_REQ_CLEAR_FEATURE           0x01
+#define USB_REQ_SET_FEATURE             0x03
+#define USB_REQ_SET_ADDRESS             0x05
+#define USB_REQ_GET_DESCRIPTOR          0x06
+#define USB_REQ_SET_DESCRIPTOR          0x07
+#define USB_REQ_GET_CONFIGURATION       0x08
+#define USB_REQ_SET_CONFIGURATION       0x09
+#define USB_REQ_GET_INTERFACE           0x0A
+#define USB_REQ_SET_INTERFACE           0x0B
+#define USB_REQ_SYNCH_FRAME             0x0C
+/*! @} */
+
+/*!
+ * @name Hub requests
+ */
+ /*! @{ */
+#define USB_REQ_CLEAR_TT_BUFFER         0x08
+#define USB_REQ_RESET_TT                0x09
+#define USB_REQ_GET_TT_STATE            0x0A
+#define USB_REQ_STOP_TT                 0x0B
+/*! @} */
+
+/*!
+ * @name HID requests
+ */
+ /*! @{ */
+#define USB_REQ_GET_REPORT              0x01
+#define USB_REQ_GET_IDLE                0x02
+#define USB_REQ_GET_PROTOCOL            0x03
+#define USB_REQ_SET_REPORT              0x09
+#define USB_REQ_SET_IDLE                0x0A
+#define USB_REQ_SET_PROTOCOL            0x0B
+/*! @} */
+
+
+/*!
+ * @name USB Spec Release number
+ */
+ /*! @{ */
+
+#define USB_BCD_VERSION                 0x0200
+/*! @} */
+
+/*!
+ * @name Audio
+ */
+ /*! @{ */
+
+#define CS_AUDIO_UNDEFINED              0x20
+#define CS_AUDIO_DEVICE                 0x21
+#define CS_AUDIO_CONFIGURATION          0x22
+#define CS_AUDIO_STRING                 0x23
+#define CS_AUDIO_INTERFACE              0x24
+#define CS_AUDIO_ENDPOINT               0x25
+
+#define AUDIO_HEADER                    0x01
+#define AUDIO_INPUT_TERMINAL            0x02
+#define AUDIO_OUTPUT_TERMINAL           0x03
+#define AUDIO_MIXER_UNIT                0x04
+#define AUDIO_SELECTOR_UNIT             0x05
+#define AUDIO_FEATURE_UNIT              0x06
+#define AUDIO_PROCESSING_UNIT           0x07
+#define AUDIO_EXTENSION_UNIT            0x08
+/*! @} */
+
+
+/*!
+ * @name Device Requests      (c.f Table 9-2)
+ */
+ /*! @{ */
+
+#define USB_REQ_DIRECTION_MASK          0x80
+#define USB_REQ_TYPE_MASK               0x60
+#define USB_REQ_RECIPIENT_MASK          0x1f
+
+#define USB_REQ_DEVICE2HOST             0x80
+#define USB_REQ_HOST2DEVICE             0x00
+
+#define USB_REQ_TYPE_STANDARD           0x00
+#define USB_REQ_TYPE_CLASS              0x20
+#define USB_REQ_TYPE_VENDOR             0x40
+
+#define USB_REQ_RECIPIENT_DEVICE        0x00
+#define USB_REQ_RECIPIENT_INTERFACE     0x01
+#define USB_REQ_RECIPIENT_ENDPOINT      0x02
+#define USB_REQ_RECIPIENT_OTHER         0x03
+/*! @} */
+
+/*!
+ * @name Hub Recipients
+ */
+ /*! @{ */
+#define USB_REQ_RECIPIENT_HUB           0x00
+#define USB_REQ_RECIPIENT_PORT          0x03
+/*! @} */
+
+/*!
+ * @name get status bits
+ */
+ /*! @{ */
+
+#define USB_STATUS_SELFPOWERED          0x01
+#define USB_STATUS_REMOTEWAKEUP         0x02
+
+#define USB_STATUS_HALT                 0x01
+/*! @} */
+
+/*!
+ * @name Convert Feature Selector to a Status Flag Setting
+ */
+ /*! @{ */
+#define FEATURE(f)                      (1 << f)
+/*! @} */
+
+/*!
+ * @name standard feature selectors
+ */
+ /*! @{ */
+#define USB_ENDPOINT_HALT               0x00
+#define USB_DEVICE_REMOTE_WAKEUP        0x01
+#define USB_TEST_MODE                   0x02
+/*! @} */
+
+/*!
+ * @name Hub Feature Selectors C.f. Table 11-17
+ */
+ /*! @{ */
+#if !defined(C_HUB_LOCAL_POWER)
+#define C_HUB_LOCAL_POWER  0x0
+#endif
+#if !defined(C_HUB_OVER_CURRENT)
+#define C_HUB_OVER_CURRENT  0x1
+#endif
+
+#define PORT_CONNECTION   0
+#define PORT_ENABLE   1
+#define PORT_SUSPEND   2
+#define PORT_OVER_CURRENT  3
+#define PORT_RESET   4
+
+#define PORT_POWER   8
+#define PORT_LOW_SPEED   9
+#define PORT_HIGH_SPEED   10
+
+#define C_PORT_CONNECTION         16
+#define C_PORT_ENABLE          17
+#define C_PORT_SUSPEND          18
+#define C_PORT_OVER_CURRENT         19
+#define C_PORT_RESET          20
+
+#define PORT_TEST   21
+#define PORT_INDICATOR   22
+
+/*! @} */
+
+#ifdef PRAGMAPACK
+#pragma pack(push,1)
+#endif
+
+
+struct usbd_device_request {
+        u8 bmRequestType;
+        u8 bRequest;
+        u16 wValue;
+        u16 wIndex;
+        u16 wLength;
+} PACKED;
+
+
+
+struct usbd_otg_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;
+        u8 bmAttributes;
+} PACKED;
+
+/*!
+ * @name OTG
+ */
+ /*! @{ */
+#define USB_OTG_HNP_SUPPORTED   0x02
+#define USB_OTG_SRP_SUPPORTED   0x01
+/*! @} */
+
+/*!
+ * @name OTG Feature selectors
+ */
+ /*! @{ */
+#define USB_OTG_B_HNP_ENABLE     0x03
+#define USB_OTG_A_HNP_SUPPORT    0x04
+#define USB_OTG_A_ALT_HNP_ENABLE 0x05
+/*! @} */
+
+/*!
+ * @name Class-Specific Request Codes
+ * C.f. CDC Table 46
+ */
+ /*! @{ */
+
+#define CDC_CLASS_REQUEST_SEND_ENCAPSULATED     0x00
+#define CDC_CLASS_REQUEST_GET_ENCAPSULATED      0x01
+
+#define CDC_CLASS_REQUEST_SET_COMM_FEATURE      0x02
+#define CDC_CLASS_REQUEST_GET_COMM_FEATURE      0x03
+#define CDC_CLASS_REQUEST_CLEAR_COMM_FEATURE    0x04
+
+#define CDC_CLASS_REQUEST_SET_LINE_CODING       0x20
+#define CDC_CLASS_REQUEST_GET_LINE_CODING       0x21
+
+#define CDC_CLASS_REQUEST_SET_CONTROL_LINE_STATE 0x22
+#define CDC_CLASS_REQUEST_SEND_BREAK            0x23
+/*! @} */
+
+/*!
+ * @name Notification codes
+ * c.f. CDC Table 68
+ */
+ /*! @{ */
+
+#define CDC_NOTIFICATION_NETWORK_CONNECTION         0x00
+#define CDC_NOTIFICATION_RESPONSE_AVAILABLE         0x01
+#define CDC_NOTIFICATION_AUX_JACK_HOOK_STATE        0x08
+#define CDC_NOTIFICATION_RING_DETECT                0x09
+#define CDC_NOTIFICATION_SERIAL_STATE               0x20
+#define CDC_NOTIFICATION_CALL_STATE_CHANGE          0x28
+#define CDC_NOTIFICATION_LINE_STATE_CHANGE          0x29
+#define CDC_NOTIFICATION_CONNECTION_SPEED_CHANGE    0x2a
+/*! @} */
+
+struct hub_descriptor {
+ u8 bDescLength;
+ u8 bDescriptorType;
+ u8 bNbrPorts;
+ u16 wHubCharacteristics;
+ u8 bPwrOn2PwrGood;
+ u8 bHubContrCurrent;
+ u8 DeviceRemovable;
+ u8 PortPwrCtrlMask;
+} PACKED;
+
+/*!
+ * @name Hub Descriptor C.f. 11.23.2.1 Table 11-13
+ * N.B. This assumes 1-8 ports, DeviceRemovable and PortPwrCtrlMask
+ * must be sized for the number of if ports > 8.
+ */
+ /*! @{ */
+
+
+#define HUB_GANGED_POWER  0x00
+#define HUB_INDIVIDUAL_POWER  0x01
+#define HUB_COMPOUND_DEVICE  0x04
+#define HUB_GLOBAL_OVERCURRENT  0x00
+#define HUB_INDIVIDUAL_OVERCURRENT 0x08
+#define HUB_NO_OVERCURRENT  0x10
+#define HUB_TT_8   0x00
+#define HUB_TT_16   0x20
+#define HUB_TT_24   0x40
+#define HUB_TT_32   0x60
+#define HUB_INDICATORS_SUPPORTED 0x80
+/*! @} */
+
+/*!
+ * @name HID - Class Descriptors
+ * C.f. 7.1.1
+ */
+ /*! @{ */
+
+#define HID     0x21
+#define HID_REPORT      0x22
+#define HID_PHYSICAL    0x23
+/*! @} */
+
+/*!
+ * name HID Descriptor
+ * C.f. E.8
+ */
+ /*! @{ */
+
+
+struct hid_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;
+        u16 bcdHID;
+        u8 bCountryCode;
+        u8 bNumDescriptors;
+        u8 bReportType;
+        u16 wItemLength;
+} PACKED;
+
+/*! @} */
+
+/*!
+ * name ACM - Line Coding structure
+ * C.f. CDC Table 50
+ */
+ /*! @{ */
+
+
+struct cdc_acm_line_coding {
+        u32 dwDTERate;
+        u8 bCharFormat;
+        u8 bParityType;
+        u8 bDataBits;
+} PACKED;
+
+ /*!@} */
+ 
+/*!
+ * @name ACM - Line State
+ * C.f. CDC Table 51
+ */
+ /*! @{ */
+typedef u16 cdc_acm_bmLineState;
+#define CDC_LINESTATE_D1_RTS            (1 << 1)
+#define CDC_LINESTATE_D0_DTR            (1 << 0)
+/*! @} */
+
+/*!
+ * Serial State - C.f. 6.3.5
+ */
+struct acm_serial_state {
+        u16     uart_state_bitmap;
+};
+
+
+/*! @name ACM - UART State
+ * C.f. Table 69 - UART State Bitmap Values
+ */
+/*! @{ */
+typedef u16 cdc_acm_bmUARTState;
+#define CDC_UARTSTATE_BOVERRUN        (1 << 6)
+#define CDC_UARTSTATE_BPARITY         (1 << 5)
+#define CDC_UARTSTATE_BFRAMING        (1 << 4)
+#define CDC_UARTSTATE_BRINGSIGNAL     (1 << 3)
+#define CDC_UARTSTATE_BBREAK          (1 << 2)
+#define CDC_UARTSTATE_BTXCARRIER_DSR  (1 << 1)
+#define CDC_UARTSTATE_BRXCARRIER_DCD  (1 << 0)
+/*! @} */
+
+/* !USB Notification
+ *
+ */
+
+struct cdc_notification_descriptor {
+        u8 bmRequestType;
+        u8 bNotification;
+        u16 wValue;
+        u16 wIndex;
+        u16 wLength;
+        u8 data[2];
+} PACKED;
+
+
+
+
+/*!
+ * @name Communications Class Types
+ *
+ * c.f. CDC  USB Class Definitions for Communications Devices
+ * c.f. WMCD USB CDC Subclass Specification for Wireless Mobile Communications Devices
+ *
+ * @{
+ */
+
+#define CLASS_BCD_VERSION               0x0110
+/*! @} */
+
+/*! @name c.f. CDC 4.1 Table 14 */
+
+/*! @{ */
+
+#define AUDIO_CLASS                     0x01
+#define COMMUNICATIONS_DEVICE_CLASS     0x02
+/*! @} */
+
+/*! @name c.f. CDC 4.2 Table 15
+ */
+ /*! @{ */
+#define COMMUNICATIONS_INTERFACE_CLASS  0x02
+/*! @} */
+
+/*! @name c.f. CDC 4.3 Table 16
+ */
+ /*! @{ */
+#define COMMUNICATIONS_NO_SUBCLASS      0x00
+#define COMMUNICATIONS_DLCM_SUBCLASS    0x01
+#define COMMUNICATIONS_ACM_SUBCLASS     0x02
+#define COMMUNICATIONS_TCM_SUBCLASS     0x03
+#define COMMUNICATIONS_MCCM_SUBCLASS    0x04
+#define COMMUNICATIONS_CCM_SUBCLASS     0x05
+#define COMMUNICATIONS_ENCM_SUBCLASS    0x06
+#define COMMUNICATIONS_ANCM_SUBCLASS    0x07
+
+#define AUDIO_CONTROL_SUBCLASS          0x01
+#define AUDIO_STREAMING_SUBCLASS        0x02
+/*! @} */
+
+/*! @name c.f. WMCD 5.1
+ */
+ /*! @{ */
+#define COMMUNICATIONS_WHCM_SUBCLASS    0x08
+#define COMMUNICATIONS_DMM_SUBCLASS     0x09
+#define COMMUNICATIONS_MDLM_SUBCLASS    0x0a
+#define COMMUNICATIONS_OBEX_SUBCLASS    0x0b
+/*! @} */
+
+/*! @name c.f. CDC 4.6 Table 18
+ */
+ /*! @{ */
+#define DATA_INTERFACE_CLASS            0x0a
+/*! @} */
+
+/*! @name c.f. CDC 4.7 Table 19
+ */
+ /*! @{ */
+#define COMMUNICATIONS_NO_PROTOCOL      0x00
+/*! @} */
+
+
+/*! @name c.f. CDC 5.2.3 Table 24
+ * c.f. Audio Appendix A.4
+ */
+ /*! @{ */
+#define CS_UNDEFINED                    0x20
+#define CS_DEVICE                       0x21
+#define CS_CONFIG                       0x22
+#define CS_STRING                       0x23
+#define CS_INTERFACE                    0x24
+#define CS_ENDPOINT                     0x25
+/*! @} */
+
+/*!
+ * @name Audio Interface Class - c.f Appendix A.1
+ */
+ /*! @{ */
+#define AUDIO_INTERFACE_CLASS           0x01
+/*! @} */
+
+/*! @name Audio Interface Subclass - c.f Appendix A.2
+ */
+ /*! @{ */
+#define AUDIO_SUBCLASS_UNDEFINED        0x00
+#define AUDIO_AUDIOCONTROL              0x01
+#define AUDIO_AUDIOSTREAMING            0x02
+#define AUDIO_MIDISTREAMING             0x03
+/*! @} */
+
+/*! @name Audio Interface Proctol - c.f. Appendix A.3
+ */
+ /*! @{ */
+#define AUDIO_PR_PROTOCOL_UNDEFINED     0x00
+/*! @} */
+
+/*! @name Audio Class-Specific AC Interface Descriptor Subtypes - c.f. A.5
+ */
+ /*! @{ */
+#define AUDIO_AC_DESCRIPTOR_UNDEFINED   0x00
+#define AUDIO_AC_HEADER                 0x01
+#define AUDIO_AC_INPUT_TERMINAL         0x02
+#define AUDIO_AC_OUTPUT_TERMINAL        0x03
+#define AUDIO_AC_MIXER_UNIT             0x04
+#define AUDIO_AC_SELECTOR_UNIT          0x05
+#define AUDIO_AC_FEATURE_UNIT           0x06
+#define AUDIO_AC_PROCESSING_UNIT        0x07
+#define AUDIO_AC_EXTENSION_UNIT         0x08
+/*! @} */
+
+/*! @name Audio Class-Specific AS Interface Descriptor Subtypes - c.f. A.6
+ */
+ /*! @{ */
+#define AUDIO_AS_DESCRIPTOR_UNDEFINED   0x00
+#define AUDIO_AS_GENERAL                0x01
+#define AUDIO_AS_FORMAT_TYPE            0x02
+#define AUDIO_AS_FORMAT_UNSPECFIC       0x03
+/*! @} */
+
+/*! @name Audio Class Processing Unit Processing Types - c.f. A.7
+ */
+ /*! @{ */
+#define AUDIO_PROCESS_UNDEFINED         0x00
+#define AUDIO_UP_DOWN_MUIX_PROCESS      0x01
+#define AUDIO_DOLBY_PROLOGIC_PROCESS    0x02
+#define AUDIO_3D_STEREO_EXTENDER_PROCESS 0x03
+#define AUDIO_REVERBERATION_PROCESS     0x04
+#define AUDIO_CHORUS_PROCESS            0x05
+#define AUDIO_DYN_RANGE_COMP_PROCESS    0x06
+/*! @} */
+
+/*! @name Audio Class-Specific Endpoint Descriptor Subtypes - c.f. A.8
+ */
+ /*! @{ */
+#define AUDIO_DESCRIPTOR_UNDEFINED      0x00
+#define AUDIO_EP_GENERAL                0x01
+/*! @} */
+
+/*! @name Audio Class-Specific Request Codes - c.f. A.9
+ */
+ /*! @{ */
+#define AUDIO_REQUEST_CODE_UNDEFINED    0x00
+#define AUDIO_SET_CUR                   0x01
+#define AUDIO_GET_CUR                   0x81
+#define AUDIO_SET_MIN                   0x02
+#define AUDIO_GET_MIN                   0x82
+#define AUDIO_SET_MAX                   0x03
+#define AUDIO_GET_MAX                   0x83
+#define AUDIO_SET_RES                   0x04
+#define AUDIO_GET_RES                   0x84
+#define AUDIO_SET_MEM                   0x05
+#define AUDIO_GET_MEM                   0x85
+#define AUDIO_GET_STAT                  0xff
+/*! @} */
+
+/*!
+ * @name bDescriptorSubtypes
+ *
+ * c.f. CDC 5.2.3 Table 25
+ * c.f. WMCD 5.3 Table 5.3
+ */
+ /*! @{ */
+
+#define USB_ST_HEADER                   0x00
+#define USB_ST_CMF                      0x01
+#define USB_ST_ACMF                     0x02
+#define USB_ST_DLMF                     0x03
+#define USB_ST_TRF                      0x04
+#define USB_ST_TCLF                     0x05
+#define USB_ST_UF                       0x06
+#define USB_ST_CSF                      0x07
+#define USB_ST_TOMF                     0x08
+#define USB_ST_USBTF                    0x09
+#define USB_ST_NCT                      0x0a
+#define USB_ST_PUF                      0x0b
+#define USB_ST_EUF                      0x0c
+#define USB_ST_MCMF                     0x0d
+#define USB_ST_CCMF                     0x0e
+#define USB_ST_ENF                      0x0f
+#define USB_ST_ATMNF                    0x10
+
+#define USB_ST_WHCM                     0x11
+#define USB_ST_MDLM                     0x12
+#define USB_ST_MDLMD                    0x13
+#define USB_ST_DMM                      0x14
+#define USB_ST_OBEX                     0x15
+#define USB_ST_CS                       0x16
+#define USB_ST_CSD                      0x17
+#define USB_ST_TCM                      0x18
+/*! @} */
+
+/*!
+ * @name Class Descriptor Description Structures...
+ * c.f. CDC 5.1
+ * c.f. WCMC 6.7.2
+ *
+ * XXX add the other dozen class descriptor description structures....
+ *
+ */
+ /*! @{ */
+struct usbd_header_functional_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u16 bcdCDC;
+};
+
+struct usbd_call_management_functional_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u8 bmCapabilities;
+        u8 bDataInterface;
+};
+
+struct usbd_abstract_control_functional_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u8 bmCapabilities;
+};
+
+struct usbd_union_functional_functor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u8 bMasterInterface;
+        u8 bSlaveInterface[1];
+        //u8        bSlaveInterface[0];                    // XXX FIXME
+};
+
+struct usbd_ethernet_networking_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        char *iMACAddress;
+        u8 bmEthernetStatistics;
+        u16 wMaxSegmentSize;
+        u16 wNumberMCFilters;
+        u8 bNumberPowerFilters;
+};
+
+struct usbd_mobile_direct_line_model_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u16 bcdVersion;
+        u8 bGUID[16];
+};
+
+struct usbd_mobile_direct_line_model_detail_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u8 bGuidDescriptorType;
+        u8 bDetailData[2];
+        //u8      bDetailData[0];                         // XXX FIXME
+};
+#if 0
+struct usbd_header_description {
+        u8 bDescriptorSubtype;
+        u16 bcdCDC;
+};
+
+struct usbd_call_management_description {
+        u8 bmCapabilities;
+        u8 bDataInterface;
+};
+
+struct usbd_abstract_control_description {
+        u8 bmCapabilities;
+};
+
+struct usbd_union_function_description {
+        u8 bMasterInterface;
+        u8 bSlaveInterface[1];
+        //u8        bSlaveInterface[0];                    // XXX FIXME
+};
+
+struct usbd_ethernet_networking_description {
+        char *iMACAddress;
+        u8 bmEthernetStatistics;
+        u16 wMaxSegmentSize;
+        u16 wNumberMCFilters;
+        u8 bNumberPowerFilters;
+};
+
+struct usbd_mobile_direct_line_model_description {
+        u16 bcdVersion;
+        u8 bGUID[16];
+};
+
+struct usbd_mobile_direct_line_model_detail_description {
+        u8 bGuidDescriptorType;
+        u8 bDetailData[2];
+        //u8      bDetailData[0];                         // XXX FIXME
+};
+
+struct usbd_class_description {
+        u8 bDescriptorSubtype;
+        u8 elements;
+        union {
+                struct usbd_header_description header;
+                struct usbd_call_management_description call_management;
+                struct usbd_abstract_control_description abstract_control;
+                struct usbd_union_function_description union_function;
+                struct usbd_ethernet_networking_description ethernet_networking;
+                struct usbd_mobile_direct_line_model_description mobile_direct;
+                struct usbd_mobile_direct_line_model_detail_description mobile_direct_detail;
+        } description;
+};
+#endif
+/*! @} */
+
+/*!
+ * @name Endpoint Modifiers
+ * static struct usbd_endpoint_description function_default_A_1[] = {
+ *
+ *     {this_endpoint: 0, attributes: CONTROL,   max_size: 8,  polling_interval: 0 },
+ *     {this_endpoint: 1, attributes: BULK,      max_size: 64, polling_interval: 0, direction: IN},
+ *     {this_endpoint: 2, attributes: BULK,      max_size: 64, polling_interval: 0, direction: OUT},
+ *     {this_endpoint: 3, attributes: INTERRUPT, max_size: 8,  polling_interval: 0},
+ *
+ *
+ */
+ /*! @{ */
+
+#define CONTROL         0x00
+#define ISOCHRONOUS     0x01
+#define BULK            0x02
+#define INTERRUPT       0x03
+/*! @} */
+
+
+/*! @name configuration modifiers
+ */
+
+/* @{ */
+#define BMATTRIBUTE_RESERVED            0x80
+#define BMATTRIBUTE_SELF_POWERED        0x40
+#define BMATTRIBUTE_REMOTE_WAKEUP       0x20
+
+#if 0
+/*
+ * The UUT tester specifically tests for MaxPower to be non-zero (> 0).
+ */
+#if !defined(CONFIG_OTG_MAXPOWER) || (CONFIG_OTG_MAXPOWER == 0)
+        #define BMATTRIBUTE BMATTRIBUTE_RESERVED | BMATTRIBUTE_SELF_POWERED
+        #define BMAXPOWER 1
+#else
+        #define BMATTRIBUTE BMATTRIBUTE_RESERVED
+        #define BMAXPOWER CONFIG_USBD_MAXPOWER
+#endif
+#endif
+/*! @} */
+
+
+
+/*!
+ * @name Standard Usb Descriptor Structures
+ */
+ /*! @{ */
+
+struct usbd_endpoint_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;   // 0x5
+        u8 bEndpointAddress;
+        u8 bmAttributes;
+        u16 wMaxPacketSize;
+        u8 bInterval;
+} PACKED;
+
+struct usbd_interface_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;   // 0x04
+        u8 bInterfaceNumber;
+        u8 bAlternateSetting;
+        u8 bNumEndpoints;
+        u8 bInterfaceClass;
+        u8 bInterfaceSubClass;
+        u8 bInterfaceProtocol;
+        u8 iInterface;
+} PACKED;
+
+struct usbd_configuration_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;   // 0x2
+        u16 wTotalLength;
+        u8 bNumInterfaces;
+        u8 bConfigurationValue;
+        u8 iConfiguration;
+        u8 bmAttributes;
+        u8 bMaxPower;
+} PACKED;
+
+struct usbd_device_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;   // 0x01
+        u16 bcdUSB;
+        u8 bDeviceClass;
+        u8 bDeviceSubClass;
+        u8 bDeviceProtocol;
+        u8 bMaxPacketSize0;
+        u16 idVendor;
+        u16 idProduct;
+        u16 bcdDevice;
+        u8 iManufacturer;
+        u8 iProduct;
+        u8 iSerialNumber;
+        u8 bNumConfigurations;
+} PACKED;
+
+struct usbd_string_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;   // 0x03
+        u16 wData[0];
+} PACKED;
+
+struct usbd_device_qualifier_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;
+        u16 bcdUSB;
+        u8 bDeviceClass;
+        u8 bDeviceSubClass;
+        u8 bDeviceProtocol;
+        u8 bMaxPacketSize0;
+        u8 bNumConfigurations;
+        u8 bReserved;
+} PACKED;
+
+struct usbd_generic_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;
+} PACKED;
+
+struct usbd_generic_class_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+} PACKED;
+/*! @} */
+
+/*!
+ * @name Communications Class Dscriptor Structures
+ * c.f. CDC 5.2 Table 25c
+  */
+
+/*! @{*/
+
+struct usbd_class_function_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+} PACKED;
+
+struct usbd_class_function_descriptor_generic {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u8 bmCapabilities;
+} PACKED;
+
+struct usbd_class_header_function_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x00
+        u16 bcdCDC;
+} PACKED;
+
+struct usbd_class_call_management_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x01
+        u8 bmCapabilities;
+        u8 bDataInterface;
+} PACKED;
+
+struct usbd_class_abstract_control_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x02
+        u8 bmCapabilities;
+} PACKED;
+
+struct usbd_class_direct_line_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x03
+} PACKED;
+
+struct usbd_class_telephone_ringer_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x04
+        u8 bRingerVolSeps;
+        u8 bNumRingerPatterns;
+} PACKED;
+
+struct usbd_class_telephone_call_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x05
+        u8 bmCapabilities;
+} PACKED;
+
+struct usbd_class_union_function_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x06
+        u8 bMasterInterface;
+        u8 bSlaveInterface0[0];
+} PACKED;
+
+struct usbd_class_country_selection_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x07
+        u8 iCountryCodeRelDate;
+        u16 wCountryCode0[0];
+} PACKED;
+
+
+struct usbd_class_telephone_operational_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x08
+        u8 bmCapabilities;
+} PACKED;
+
+
+struct usbd_class_usbd_terminal_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x09
+        u8 bEntityId;
+        u8 bInterfaceNo;
+        u8 bOutInterfaceNo;
+        u8 bmOptions;
+        u8 bChild0[0];
+} PACKED;
+
+struct usbd_class_network_channel_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x0a
+        u8 bEntityId;
+        u8 iName;
+        u8 bChannelIndex;
+        u8 bPhysicalInterface;
+} PACKED;
+
+struct usbd_class_protocol_unit_function_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x0b
+        u8 bEntityId;
+        u8 bProtocol;
+        u8 bChild0[0];
+} PACKED;
+
+struct usbd_class_extension_unit_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x0c
+        u8 bEntityId;
+        u8 bExtensionCode;
+        u8 iName;
+        u8 bChild0[0];
+} PACKED;
+
+struct usbd_class_multi_channel_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x0d
+        u8 bmCapabilities;
+} PACKED;
+
+struct usbd_class_capi_control_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x0e
+        u8 bmCapabilities;
+} PACKED;
+
+struct usbd_class_ethernet_networking_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x0f
+        u8 iMACAddress;
+        u32 bmEthernetStatistics;
+        u16 wMaxSegmentSize;
+        u16 wNumberMCFilters;
+        u8 bNumberPowerFilters;
+} PACKED;
+
+struct usbd_class_atm_networking_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x10
+        u8 iEndSystermIdentifier;
+        u8 bmDataCapabilities;
+        u8 bmATMDeviceStatistics;
+        u16 wType2MaxSegmentSize;
+        u16 wType3MaxSegmentSize;
+        u16 wMaxVC;
+} PACKED;
+
+
+struct usbd_class_mdlm_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x12
+        u16 bcdVersion;
+        u8 bGUID[16];
+} PACKED;
+
+/*
+struct usbd_class_mdlmd_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x13
+        u8 bGuidDescriptorType;
+        u8 bDetailData[0];
+} PACKED;
+*/
+
+struct usbd_class_blan_descriptor {
+        u8 bFunctionLength;           // 0x7
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x13
+        u8 bGuidDescriptorType;
+        u8 bmNetworkCapabilities;
+        u8 bmDataCapabilities;
+        u8 bPad;
+} PACKED;
+
+struct usbd_class_safe_descriptor {
+        u8 bFunctionLength;           // 0x6
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;        // 0x13
+        u8 bGuidDescriptorType;
+        u8 bmNetworkCapabilities;
+        u8 bmDataCapabilities;
+} PACKED;
+
+/*@}*/
+
+
+/*!
+ * @name Descriptor Union Structures
+ */
+ /*! @{ */
+
+struct usbd_descriptor {
+        union {
+                struct usbd_generic_descriptor generic_descriptor;
+                struct usbd_generic_class_descriptor generic_class_descriptor;
+                struct usbd_endpoint_descriptor endpoint_descriptor;
+                struct usbd_interface_descriptor interface_descriptor;
+                struct usbd_configuration_descriptor configuration_descriptor;
+                struct usbd_device_descriptor device_descriptor;
+                struct usbd_string_descriptor string_descriptor;
+        } descriptor;
+
+} PACKED;
+
+struct usbd_class_descriptor {
+        union {
+                struct usbd_class_function_descriptor function;
+                struct usbd_class_function_descriptor_generic generic;
+                struct usbd_class_header_function_descriptor header_function;
+                struct usbd_class_call_management_descriptor call_management;
+                struct usbd_class_abstract_control_descriptor abstract_control;
+                struct usbd_class_direct_line_descriptor direct_line;
+                struct usbd_class_telephone_ringer_descriptor telephone_ringer;
+                struct usbd_class_telephone_operational_descriptor telephone_operational;
+                struct usbd_class_telephone_call_descriptor telephone_call;
+                struct usbd_class_union_function_descriptor union_function;
+                struct usbd_class_country_selection_descriptor country_selection;
+                struct usbd_class_usbd_terminal_descriptor usb_terminal;
+                struct usbd_class_network_channel_descriptor network_channel;
+                struct usbd_class_extension_unit_descriptor extension_unit;
+                struct usbd_class_multi_channel_descriptor multi_channel;
+                struct usbd_class_capi_control_descriptor capi_control;
+                struct usbd_class_ethernet_networking_descriptor ethernet_networking;
+                struct usbd_class_atm_networking_descriptor atm_networking;
+                struct usbd_class_mdlm_descriptor mobile_direct;
+                //struct usbd_class_mdlmd_descriptor mobile_direct_detail;
+                struct usbd_class_blan_descriptor mobile_direct_blan_detail;
+                struct usbd_class_safe_descriptor mobile_direct_safe_detail;
+        } descriptor;
+
+} PACKED;
+/*! @} */
+
+/*!
+ * @name Audio Status Word Format - c.f. Table 3.1
+ */
+ /*! @{ */
+
+#define AUDIO_STATUS_INTERRUPT_PENDING                          1<<7
+#define AUDIO_STATUS_MEMORY_CONTENT_CHANGED                     1<<6
+#define AUDIO_STATUS_ORIGINATOR_AUDIO_CONTROL_INTERFACE         0
+#define AUDIO_STATUS_ORIGINATOR_AUDIO_STREAMING_INTERFACE       1
+#define AUDIO_STATUS_ORIGINATOR_AUDIO_STREAMING_ENDPOINT        2
+#define AUDIO_STATUS_ORIGINATOR_AUDIOCONTROL_INTERFACE          0
+
+struct usbd_audio_status_word {
+        u8 bStatusType;
+        u8 bOriginator;
+} PACKED;
+
+struct usbd_audio_ac_interface_header_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u16 bcdADC;
+        u16 wTotalLength;
+        u8 binCollection;
+        u8 bainterfaceNr[0];
+} PACKED;
+
+struct usbd_audio_input_terminal_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u8 bTerminalID;
+        u16 wTerminalType;
+        u8 bAssocTerminal;
+        u8 bNrChannels;
+        u16 wChannelConfig;
+        u8 iChannelNames;
+        u8 iTerminal;
+} PACKED;
+
+struct usbd_audio_input_terminal_description {
+        struct usbd_audio_input_terminal_descriptor *audio_input_terminal_descriptor;
+        u16 wTerminalType;
+        u16 wChannelConfig;
+        char * iChannelNames;
+        char * iTerminal;
+};
+
+struct usbd_audio_output_terminal_descriptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u8 bTerminalID;
+        u16 wTerminalType;
+        u8 bAssocTerminal;
+        u8 bSourceID;
+        u8 iTerminal;
+} PACKED;
+
+struct usbd_audio_output_terminal_description {
+        struct usbd_audio_output_terminal_descriptor *audio_output_terminal_descriptor;
+        u16 wTerminalType;
+        char * iTerminal;
+};
+
+struct usbd_audio_mixer_unit_descriptor_a {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u8 bUniteID;
+        u8 bNrinPins;
+} PACKED;
+
+struct usbd_audio_mixer_unit_descriptor_b {
+        u8 baSourceID;
+        u8 bNrChannels;
+        u16 wChannelConfig;
+        u8 iChannelNames;
+        u8 bmControls;
+        u8 iMixer;
+} PACKED;
+
+struct usbd_audio_mixer_unit_description {
+        struct usbd_audio_mixer_unit_descriptor *audio_mixer_unit_descriptor;
+        u16 wChannelConfig;
+        char * iMixer;
+};
+
+
+struct usbd_audio_as_general_interface_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u8 bTerminalLink;
+        u8 bDelay;
+        u16 wFormatTag;
+} PACKED;
+
+struct usbd_audio_as_general_interface_description {
+        struct usbd_audio_as_general_interface_descriptor *audio_as_general_interface_descriptor;
+        u16 wFormatTag;
+};
+
+struct usbd_audio_as_format_type_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u8 bFormatType;
+        u8 bNrChannels;
+        u8 bSubFrameSize;
+        u8 bBitResolution;
+        u8 bSamFreqType;
+        u8 iSamFreq[3];
+} PACKED;
+
+struct usbd_audio_as_format_type_description {
+        struct usbd_audio_as_format_type_descriptor *audio_as_format_type_descriptor;
+        u16 wFormatTag;
+};
+
+
+
+
+struct usbd_audio_descriptor {
+        union {
+                struct usbd_audio_ac_interface_header_descriptor header;
+                struct usbd_audio_input_terminal_descriptor input;
+                struct usbd_audio_output_terminal_descriptor output;
+        } descriptor;
+} PACKED;
+
+
+
+struct usbd_ac_endpoint_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;
+        u8 bEndpointAddress;
+        u8 bmAttributes;
+        u16 wMaxPacketSize;
+        u8 bInterval;
+        u8 bRefresh;
+        u8 bSynchAddress;
+} PACKED;
+
+
+struct usbd_as_iso_endpoint_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubtype;
+        u8 bmAttributes;
+        u8 bLockDelayUnits;
+        u16 wLockDelay;
+} PACKED;
+/*! @}*/
+
+
+/*!
+ * @name MCPC
+ */
+ /*! @{ */
+
+/*! struct usbd_interface_association
+ * Used in AB-1 or DL-1 interface bundles.
+ */
+struct usbd_interface_association_descriptor {
+        u8 bLength;
+        u8 bDescriptorType;
+        u8 bFirstInterface;
+        u8 bInterfaceCount;
+        u8 bFunctionClass;
+        u8 bFunctionSubClass;
+        u8 bFunctionProcotol;
+        u8 iFunction;
+} PACKED;
+
+struct usbd_mobile_abstract_control_model_specific_desciptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubType;
+        u8 bType;
+        u8 bMode_1;
+};
+
+struct usbd_mobile_direct_line_model_specific_desciptor {
+        u8 bFunctionLength;
+        u8 bDescriptorType;
+        u8 bDescriptorSubType;
+        u8 bType;
+        u8 bMode_N[2];
+};
+
+
+/*! @} */
+
+/*! 
+ * Device Events 
+ *
+ * These are defined in the USB Spec (c.f USB Spec 2.0 Figure 9-1).
+ *
+ * There are additional events defined to handle some extra actions we need to have handled.
+ *
+ */
+typedef enum usbd_device_event {
+
+        DEVICE_UNKNOWN,         // bi - unknown event
+        DEVICE_INIT,            // bi  - initialize
+        DEVICE_CREATE,          // bi  - 
+        DEVICE_HUB_CONFIGURED,  // bi  - bus has been plugged int
+        DEVICE_RESET,           // bi  - hub has powered our port
+
+        DEVICE_ADDRESS_ASSIGNED,// ep0 - set address setup received
+        DEVICE_CONFIGURED,      // ep0 - set configure setup received
+        DEVICE_SET_INTERFACE,   // ep0 - set interface setup received
+
+        DEVICE_SET_FEATURE,     // ep0 - set feature setup received
+        DEVICE_CLEAR_FEATURE,   // ep0 - clear feature setup received
+
+        DEVICE_DE_CONFIGURED,   // ep0 - set configure setup received for ??
+
+        DEVICE_BUS_INACTIVE,    // bi  - bus in inactive (no SOF packets)
+        DEVICE_BUS_ACTIVITY,    // bi  - bus is active again
+
+        DEVICE_POWER_INTERRUPTION,// bi  - hub has depowered our port
+        DEVICE_HUB_RESET,       // bi  - bus has been unplugged
+        DEVICE_DESTROY,         // bi  - device instance should be destroyed
+        DEVICE_CLOSE,           // bi  - device instance should be destroyed
+
+} usbd_device_event_t;
+
+/*! USB Request Block structure 
+ *
+ * This is used for both sending and receiving data. 
+ *
+ * The callback function is used to let the function driver know when
+ * transmitted data has been sent.
+ *
+ * The callback function is set by the alloc_recv function when an urb is
+ * allocated for receiving data for an endpoint and used to call the
+ * function driver to inform it that data has arrived.
+ *
+ * Note that for OUT urbs the buffer is always allocated to a multiple of
+ * the packetsize that is 1 larger than the requested size. This prevents
+ * overflow if the host unexpectedly sends a full sized packet when we are
+ * expecting a short one (the host is always right..)
+ *
+ * USBD_URB_SENDZLP - set this flag if a ZLP (zero length packet) should be
+ * sent after the data is sent. This is required if sending data that is a
+ * multiple of the packetsize but less than the maximum transfer size for
+ * the protocol in use.  A ZLP is required to ensure that the host
+ * recognizes a short transfer.
+ *
+ */
+
+typedef struct urb_link {
+        struct urb_link *next;
+        struct urb_link *prev;
+} urb_link;
+
+
+/*! URB Status
+ *
+ * This defines the current status of a pending or finshed URB.
+ *
+ */
+typedef enum usbd_urb_status {
+        SEND_IN_QUEUE,
+        SEND_IN_PROGRESS,
+        SEND_FINISHED_OK,
+        SEND_FINISHED_ERROR,
+        SEND_CANCELLED,
+        SEND_STALLED,
+        SEND_DISABLED,
+        RECV_IN_QUEUE,
+        RECV_IN_PROGRESS,
+        RECV_OK,
+        RECV_ERROR,
+        RECV_CANCELLED,
+        RECV_STALLED,
+        RECV_DISABLED
+} usbd_urb_status_t;
+
+#define USBD_URB_SENDZLP        0x01
+
+struct usbd_urb {
+
+        struct usbd_bus_instance        *bus;
+        struct usbd_function_instance   *function_instance;
+        struct usbd_endpoint_instance   *endpoint;
+
+        int                             (*callback) (struct usbd_urb *, int);
+
+        u8                              *buffer;        // data received (OUT) or being sent (IN)
+        u32                             request_length; // maximum data expected for OUT
+        u32                             buffer_length;  // allocated size of buffer
+        u32                             actual_length;  // actual data received (OUT or being sent (IN)
+        u32                             flags;
+        
+        void                            *function_privdata;
+        void                            *bus_privdata;
+        void                            *pcimap;
+
+        struct urb_link                 link;   
+        usbd_urb_status_t               status;         // what is the current status of the urb
+        time_t                          jiffies;        // timestamp for when urb was started or finished
+        u16                             framenum;       // SOF framenum when urb was finished
+};
+
+/*! Endpoint Request
+ *
+ * An array of these structures is initialized by each function driver to specify the endpoints
+ * it requires. 
+ *
+ * The bus interface driver will attempt to fulfill these requests with the actual endpoints it
+ * has available.
+ *
+ * Note that in most cases the bEndpointAddress should be left as zero except for specialized
+ * function drivers that both require a specific value and know ahead of time that the specified
+ * value is legal for the bus interface driver being used.
+ */
+struct usbd_endpoint_request {
+        u8 configuration;               /* configuration endpoint will be in */
+        u8 interface_num;               /* interface endpoint will be in */
+        u8 alternate;                   /* altsetting for this request */
+        u8 bmAttributes;                /* endpoint type AND direction */
+        u16 fs_requestedTransferSize;   /* max full speed transfer size for this endpoint */
+        u16 hs_requestedTransferSize;   /* max high speed transfer size for this endpoint */
+        u8 bEndpointAddress;            /* specific bEndpointAddress function driver requires */
+        u8 physical;                    /* physical endpoint used */
+};
+
+/*!
+ * Device status
+ *
+ * Overall state, we use this to show when we are suspended.
+ * This is required because when resumed we need to go back
+ * to previous state.
+ */
+typedef enum usbd_device_status {
+        USBD_OPENING,                   // we are currently opening
+        USBD_RESETING,                  // we are currently opening
+        USBD_OK,                        // ok to use
+        USBD_SUSPENDED,                 // we are currently suspended
+        USBD_CLOSING,                   // we are currently closing
+        USBD_CLOSED,                    // we are currently closing
+        USBD_UNKNOWN,
+} usbd_device_status_t;
+
+
+/*! 
+ * Device State (c.f USB Spec 2.0 Figure 9-1)
+ *
+ * What state the usb device is in. 
+ *
+ * Note the state does not change if the device is suspended, we simply set a
+ * flag to show that it is suspended.
+ *
+ */
+typedef enum usbd_device_state {
+        STATE_INIT,                     // just initialized
+        STATE_CREATED,                  // just created
+        STATE_ATTACHED,                 // we are attached 
+        STATE_POWERED,                  // we have seen power indication (electrical bus signal)
+        STATE_DEFAULT,                  // we been reset
+        STATE_ADDRESSED,                // we have been addressed (in default configuration)
+        STATE_CONFIGURED,               // we have seen a set configuration device command
+        STATE_SUSPENDED,                // device has been suspended
+        STATE_UNKNOWN,                  // destroyed
+} usbd_device_state_t;
+
+
+
+#ifdef PRAGMAPACK
+#pragma pack(pop)
+#endif
+
+
diff -uNr linux/drivers/no-otg/otg/usbp-func.h linux/drivers/otg/otg/usbp-func.h
--- linux/drivers/no-otg/otg/usbp-func.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/usbp-func.h	2006-09-01 21:41:33.000000000 +0200
@@ -0,0 +1,428 @@
+/*
+ * otg/otg/usbp-func.h - USB Device Function Driver Interface
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ *
+ */
+
+/*!
+ * @file otg/otg/usbp-func.h
+ * @brief Function Driver related structures and definitions.
+ *
+ * This file contains the USB Function Driver and USB Interface Driver 
+ * definitions.
+ *
+ * The USBOTG support allows for implementation of composite devices.
+ *
+ * From USB 2.0, C.f. 5.2.3:
+ *
+ *      A Device that has multiple interfaces controlled independantly of
+ *      each other is referred to as a composite device. A composite device
+ *      has only a single device.
+ *
+ * In this implemenation the function portion of the device is split into
+ * two types of drivers:
+ *
+ *      - USB Interface Driver
+ *      - USB Function Driver
+ *
+ *
+ * USB Interface Driver
+ *
+ * An USB Interface Driver specifies the Interface related descriptors and
+ * implements the data handling processes for each of the data endpoints
+ * associated with the interface (or interfaces) required for the function.
+ * It typically will also implement the upper edge interface to the OS.
+ *
+ * The USB Interface Driver will also handle non-standard device requests
+ * and feature requests that are for the interface or an endpoint associated
+ * with one of the interfaces associated with the driver.
+ *
+ * Each interface implemented by an USB Interface Driver will have a
+ * interface instance that stores a pointer to the parent USB Function
+ * Driver and has an array of pointers to endpoint instances for the data
+ * endpoints associated with the interface.
+ *
+ *
+ * USB Function Driver
+ *
+ * A USB Function Driver specifies the device and configuration descriptors.
+ * A configuration descriptor is assembled from the interface descriptors
+ * from the USB Interface Driver (or drivers) that it is making available to
+ * the USB Host.
+ *
+ * The USB Function Driver handles non-standard device requests and feature
+ * requests for the device.
+ *
+ * Each function driver has a function instance that maintains an array
+ * of pointers to configuration instances and a pointer to the device
+ * descriptor.
+ *
+ * Each configuration instance maintains an array of pointers to the 
+ * interface instances for that configuration and a pointer to the 
+ * complete configuration descriptor.
+ *
+ * @ingroup USBP
+ */
+
+/*!
+ * This file contains the USB Device Core Common definitions. It also contains definitions for
+ * functions that are commonly used by both Function Drivers and Bus Interface Drivers.
+ *
+ * Specifically:
+ *
+ *      o public functions exported by the USB Core layer 
+ *
+ *      o common structures and definitions 
+ *
+ */
+
+
+
+struct usbd_bus_instance;
+struct usbd_endpoint_instance;
+struct usbd_function_instance;
+
+/*!
+ * USB Function Driver types
+ */
+typedef enum usbd_function_types {
+        function_simple,
+        function_interface,
+        function_composite
+} usbd_function_types_t; 
+
+
+/*!
+ * USB Function Driver structures
+ *
+ * Descriptors:
+ *   struct usbd_endpoint_description
+ *   struct usbd_interface_description 
+ *   struct usbd_configuration_description
+ *
+ * Driver description:
+ *   struct usbd_function_driver
+ *   struct usbd_function_operations
+ *
+ */
+
+struct usbd_function_operations {
+
+        int (*function_enable) (struct usbd_function_instance *);
+        void (*function_disable) (struct usbd_function_instance *);
+
+        /*
+         * All of the following may be called from an interrupt context
+         */
+        void (*event_handler) (struct usbd_function_instance *, usbd_device_event_t, int);
+        int (*device_request) (struct usbd_function_instance *, struct usbd_device_request *);
+        int (*set_configuration) (struct usbd_function_instance *, int configuration);
+
+        int (*set_interface) (struct usbd_function_instance *, int interface, int altsetting);
+
+        void * (*get_descriptor)(struct usbd_function_instance *, int descriptor_type, int descriptor_index);
+        int * (*set_descriptor)(struct usbd_function_instance *, int descriptor_type, int descriptor_index, void *);
+
+        void (*endpoint_cleared)(struct usbd_function_instance*, int wIndex, int);
+
+};
+
+
+/*!
+ * function driver definitions
+ */
+struct usbd_alternate_instance {
+        struct usbd_interface_descriptor *interface_descriptor;
+        int                             classes;
+        struct usbd_generic_class_descriptor    **class_list;
+        int                             endpoints;
+        struct usbd_endpoint_descriptor  **endpoint_list;
+        u8                              *endpoint_indexes;
+};
+
+
+/*!
+ * usb device description structures
+ */
+
+struct usbd_alternate_description {
+        struct usbd_interface_descriptor *interface_descriptor;
+        char                            *iInterface;
+
+        // list of CDC class descriptions for this alternate interface
+        u8                              classes;
+        struct usbd_generic_class_descriptor    **class_list;
+
+        // list of endpoint descriptions for this alternate interface
+        u8                              endpoints;
+        struct usbd_endpoint_descriptor  **endpoint_list;
+
+        // list of indexes into endpoint request map for each endpoint descriptor
+        u8                              *endpoint_indexes;
+};
+
+typedef struct usbd_generic_class_descriptor usbd_class_descriptor_t;
+typedef struct usbd_endpoint_descriptor      usbd_endpoint_descriptor_t;
+
+struct usbd_interface_description {
+        // list of alternate interface descriptions for this interface
+        u8                              alternates;
+        struct usbd_alternate_description *alternate_list;
+};
+
+struct usbd_configuration_description {
+        struct usbd_configuration_descriptor *configuration_descriptor;
+        char                            *iConfiguration;
+        // list of interface descriptons for this configuration
+        //u8                              bNumInterfaces;
+        //struct usbd_interface_description *interface_list;
+        int                             configuration_type;
+};
+
+struct usbd_device_description {
+        struct usbd_device_descriptor   *device_descriptor;
+        #ifdef CONFIG_OTG_HIGH_SPEED
+        struct usbd_device_qualifier_descriptor *device_qualifier_descriptor;
+        #endif /* CONFIG_OTG_HIGH_SPEED */
+        struct usbd_otg_descriptor      *otg_descriptor;
+        u8                              *iManufacturer;
+        u8                              *iProduct;
+        u8                              *iSerialNumber;
+        //u8                              endpointsRequested;
+        //struct usbd_endpoint_request    *requestedEndpoints;
+};
+
+
+struct usbd_interfaces_instance {
+        u8                              alternates;
+        struct usbd_alternate_instance  *alternates_instance_array;
+};
+
+struct usbd_configuration_instance {
+        int                             bNumInterfaces;
+        struct usbd_configuration_descriptor *configuration_descriptor;
+        struct usbd_interfaces_instance  *interfaces_instance_array;
+        struct usbd_function_driver     *function_driver;
+};
+
+
+/*! Function Driver data structure
+ *
+ * Function driver and its configuration descriptors. 
+ *
+ * This is passed to the usb-device layer when registering. It contains all
+ * required information about the function driver for the usb-device layer
+ * to use the function drivers configuration data and to configure this
+ * function driver an active configuration.
+ *
+ * Note that each function driver registers itself on a speculative basis.
+ * Whether a function driver is actually configured will depend on the USB
+ * HOST selecting one of the function drivers configurations. 
+ *
+ * This may be done multiple times WRT to either a single bus interface
+ * instance or WRT to multiple bus interface instances. In other words a
+ * multiple configurations may be selected for a specific bus interface. Or
+ * the same configuration may be selected for multiple bus interfaces. 
+ *
+ */
+struct usbd_function_driver {
+        const char                              *name;
+        struct usbd_function_operations         *fops;  // functions 
+
+        // device & configuration descriptions 
+        struct usbd_device_description  *device_description;
+        struct usbd_configuration_description *configuration_description;
+        int                             bNumConfigurations;
+
+        u16                             idVendor;
+        u16                             idProduct;
+        u16                             bcdDevice;
+
+        u8                              bNumInterfaces;
+        struct usbd_interface_description *interface_list;
+
+        u8                              endpointsRequested;
+        struct usbd_endpoint_request    *requestedEndpoints;
+
+        // constructed descriptors
+        struct usbd_device_descriptor   *device_descriptor;
+#ifdef CONFIG_OTG_HIGH_SPEED
+        struct usbd_device_qualifier_descriptor *device_qualifier_descriptor;
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        struct usbd_otg_descriptor       *otg_descriptor;
+        struct usbd_configuration_instance *configuration_instance_array;
+};
+
+/*! Function configuration structure
+ *
+ * This is allocated for each configured instance of a function driver.
+ *
+ * It stores pointers to the usbd_function_driver for the appropriate function,
+ * and pointers to the USB HOST requested usbd_configuration_description and
+ * usbd_interface_description.
+ *
+ * The privdata pointer may be used by the function driver to store private
+ * per instance state information.
+ *
+ * The endpoint map will contain a list of all endpoints for the configuration 
+ * driver, and only related endpoints for an interface driver.
+ *
+ * The interface driver array will be NULL for an interface driver.
+ */
+struct usbd_function_instance {
+        char *                          name;
+        LIST_NODE                       instances;             // linked list (was drivers in usbd_function_driver)
+        struct usbd_bus_instance        *bus;
+        struct usbd_function_driver     *function_driver;
+        void                            *privdata;              // private data for the function
+
+        usbd_function_types_t           function_type;
+
+        int                             configuration;          // configuration driver only
+        int                             altsetting;             // interface driver only
+
+        char                            **interfaces_list;
+
+        int                             interfaces;
+        struct usbd_function_instance   **interfaces_array;
+
+        int                             endpoints;
+        struct usbd_endpoint_request    *requestedEndpoints;
+        struct usbd_endpoint_map        *endpoint_map_array;  
+
+};
+
+
+struct usbd_function_instance;
+
+/*!
+ * @name Function Driver Registration
+ *
+ * Called by function drivers to register themselves when loaded
+ * or de-register when unloading.
+ * @{ 
+ */
+struct usbd_function_instance * usbd_register_function (struct usbd_function_driver *, char *, void *);
+struct usbd_function_instance * usbd_register_interface (struct usbd_function_driver *, char *, void *);
+struct usbd_function_instance * usbd_register_composite (struct usbd_function_driver *function_driver, char*, char **, void *);
+
+void usbd_deregister_function (struct usbd_function_instance *);
+struct usbd_function_instance *usbd_find_function (char *name);
+struct usbd_function_instance *usbd_find_interface(char *name);
+/*! @} */
+
+
+/*!
+ * @name String Descriptor database
+ *
+ * @{
+ */
+
+struct usbd_string_descriptor *usbd_get_string_descriptor (u8);
+u8 usbd_realloc_string (u8, char *);
+u8 usbd_alloc_string (char *);
+void usbd_free_string_descriptor(u8 );
+
+//extern struct usbd_string_descriptor **usb_strings;
+//void usbd_free_descriptor_strings (struct usbd_descriptor *);
+
+/*! @} */
+
+
+
+/*!
+ * @name Device Information
+ * 
+ * @}
+ */
+int usbd_high_speed(struct usbd_function_instance *);
+int usbd_bmaxpower(struct usbd_function_instance *);
+int usbd_endpoint_wMaxPacketSize(struct usbd_function_instance *, int, int);
+int usbd_endpoint_zero_wMaxPacketSize(struct usbd_function_instance *, int);
+int usbd_endpoint_bEndpointAddress(struct usbd_function_instance *, int, int);
+int usbd_get_bMaxPower(struct usbd_function_instance *);
+/*! @} */
+
+
+/*!
+ * @name Device Control
+ * 
+ * @}
+ */
+usbd_device_state_t usbd_get_device_state(struct usbd_function_instance *);
+usbd_device_status_t usbd_get_device_status(struct usbd_function_instance *);
+int usbd_framenum(struct usbd_function_instance *);
+u64 usbd_ticks(struct usbd_function_instance *);
+u64 usbd_elapsed(struct usbd_function_instance *, u64 *, u64 *);
+
+/*! @} */
+
+/*!
+ * @name Endpoint I/O
+ * 
+ * @}
+ */
+
+struct usbd_urb *usbd_alloc_urb (struct usbd_function_instance *, int, int length, int (*callback) (struct usbd_urb *, int));
+struct usbd_urb *usbd_alloc_urb_ep0 (struct usbd_function_instance *, int length, int (*callback) (struct usbd_urb *, int));
+void usbd_free_urb (struct usbd_urb *urb);
+int usbd_start_in_urb (struct usbd_urb *urb);
+int usbd_start_out_urb (struct usbd_urb *);
+int usbd_cancel_urb(struct usbd_urb *);
+int usbd_halt_endpoint (struct usbd_function_instance *function, int endpoint_index);
+int usbd_endpoint_halted (struct usbd_function_instance *function, int endpoint);
+
+
+/*! @} */
+
+
+/*! 
+ * @name endpoint information
+ *
+ * Used by function drivers to get specific endpoint information
+ * @{ 
+ */
+
+int usbd_endpoint_transferSize(struct usbd_function_instance *, int, int);
+int usbd_endpoint_interface(struct usbd_function_instance *, int);
+int usbd_interface_AltSetting(struct usbd_function_instance *, int);
+int usbd_ConfigurationValue(struct usbd_function_instance *);
+void usbd_endpoint_update(struct usbd_function_instance *, int , struct usbd_endpoint_descriptor *, int);
+/*! @} */
+
+//int usbd_remote_wakeup_enabled(struct usbd_function_instance *);
+
+/*! 
+ * @name device information
+ *
+ * Used by function drivers to get device feature information
+ * @{ 
+ */
+int usbd_otg_bmattributes(struct usbd_function_instance *);
+/*! @} */
+
+/*! 
+ * @name usbd_feature_enabled - return non-zero if specified feature has been enabled
+ * @{ 
+ */
+int usbd_feature_enabled(struct usbd_function_instance *function, int f);
+/*! @} */
+
+/* DEPRECATED */
+/*! 
+ * @name Access to function privdata (DEPRECATED)
+ * @{ 
+ */
+void *usbd_function_get_privdata(struct usbd_function_instance *function);
+void usbd_function_set_privdata(struct usbd_function_instance *function, void *privdata);
+void usbd_flush_endpoint_index (struct usbd_function_instance *, int );
+int usbd_old_get_descriptor (struct usbd_function_instance *function, u8 *buffer, int max, int descriptor_type, int index);
+/*! @} */
+
diff -uNr linux/drivers/no-otg/otg/usbp-pcd.h linux/drivers/otg/otg/usbp-pcd.h
--- linux/drivers/no-otg/otg/usbp-pcd.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otg/usbp-pcd.h	2006-09-01 21:41:34.000000000 +0200
@@ -0,0 +1,279 @@
+/*
+ * otg/otg/usbp-pcd.h - OTG Peripheral Controller Driver
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+/*!
+ * @file otg/otg/usbp-pcd.h
+ * @brief Peripheral Controller Driver Related Structures and Definitions.
+ *
+ * @ingroup USBP
+ */
+
+/*!
+ * The pcd_ops structure contains pointers to all of the functions implemented for the
+ * linked in driver. Having them in this structure allows us to easily determine what
+ * functions are available without resorting to ugly compile time macros or ifdefs
+ *
+ * There is only one instance of this, defined in the device specific lower layer.
+ */
+struct usbd_pcd_ops {
+
+        /* mandatory */
+        u8 bmAttributes;
+        int max_endpoints;
+        int ep0_packetsize;
+        u32 capabilities;                               /* UDC Capabilities - see usbd-bus.h for details */
+        u8 bMaxPower;
+        char *name;
+        u8 ports;
+
+
+        /* 3. called by ot_init() if defined */
+        int (* serial_init) (struct pcd_instance *);    /* get device serial number if available */
+
+        /* 4. called from usbd_enable_function_irq() - REQUIRED */
+        int (*request_endpoints)                        /* process endpoint_request list and return endpoint_map */
+                (struct pcd_instance *,
+                 struct usbd_endpoint_map *,            /* showing allocated endpoints with attributes, addresses */
+                 int, struct usbd_endpoint_request*);   /* and other associated information */
+
+        /* 5. called from usbd_enable_function_irq() - REQUIRED */
+        int (*set_endpoints)                            /* setup required endpoints in hardware */
+                (struct pcd_instance *, int , struct usbd_endpoint_map *);      
+
+        /* 6. called by xxx() if defined */
+        void (*enable) (struct pcd_instance *);         /* enable the UDC */
+
+        /* 7. called by xxx() if defined */
+        void (*disable) (struct pcd_instance *);        /* disable the UDC */
+
+        /* 8. called by xxx() if defined */
+        void (*start) (struct pcd_instance *);          /* called for DEVICE_CREATE to start the UDC */
+        void (*stop) (struct pcd_instance *);           /* called for DEVICE_DESTROY to stop the UDC */
+        void (*disable_ep) 
+                (struct pcd_instance *, 
+                 unsigned int ep);                      /* called for DEVICE_DESTROTY to disable endpoint zero */
+
+        /* 9. called by xxx() if defined */
+        void (*set_address) 
+                (struct pcd_instance *,
+                unsigned char address);                 /* called for DEVICE_RESET and DEVICE_ADDRESS_ASSIGNED to */
+
+
+        /* 10. called by xxx() if defined */
+        void (*setup_ep) 
+                (struct pcd_instance *,
+                unsigned int ep,                        /* called for DEVICE_CONFIGURED to setup specified endpoint for use */
+                struct usbd_endpoint_instance *endpoint); 
+
+        /* 11. called by xxx() if defined */
+        void (*reset_ep) 
+                (struct pcd_instance *,
+                unsigned int ep);                       /* called for DEVICE_RESET to reset endpoint zero */
+
+
+        /* 12. called by usbd_send_urb() - REQUIRED */
+        void (*start_endpoint_in)                       /* start an IN urb */
+                (struct pcd_instance *,
+                struct usbd_endpoint_instance *);       
+
+        /* 13. called by usbd_start_recv() - REQUIRED */
+        void (*start_endpoint_out)                      /* start an OUT urb */
+                (struct pcd_instance *,
+                struct usbd_endpoint_instance *);
+
+        /* 14. called by usbd_cancel_urb_irq() */
+        void (*cancel_in_irq) 
+                (struct pcd_instance *,
+                struct usbd_urb *urb);                  /* cancel active urb for IN endpoint */
+        void (*cancel_out_irq) 
+                (struct pcd_instance *,
+                struct usbd_urb *urb);                  /* cancel active urb for OUT endpoint */
+
+
+        /* 15. called from ep0_recv_setup() for GET_STATUS request */
+        int (*endpoint_halted) 
+                (struct pcd_instance *, 
+                 struct usbd_endpoint_instance *);      /* Return non-zero if requested endpoint is halted */
+        int (*halt_endpoint) 
+                (struct pcd_instance *, 
+                 struct usbd_endpoint_instance *,
+                 int);                                  /* Return non-zero if requested endpoint clear fails */
+
+        /* 16 */
+        void (*startup_events) (struct pcd_instance *);   /* perform UDC specific USB events */
+
+	/* 17. root hub operations
+	 */
+	int (*hub_status) (struct pcd_instance *);
+	int (*port_status) (struct pcd_instance *, int);
+	int (*hub_feature) (struct pcd_instance *, int, int);
+	int (*port_feature) (struct pcd_instance *, int, int, int);
+	int (*get_ports_status) (struct pcd_instance *);
+	int (*wait_for_change) (struct pcd_instance *);
+};
+
+extern struct usbd_pcd_ops usbd_pcd_ops;
+
+
+/*! pcd_rcv_next_irq - get the current or next urb to receive into
+ * Called by UDC driver to get current receive urb or next available receive urb.
+ */
+static __inline__ struct usbd_urb * pcd_rcv_next_irq (struct usbd_endpoint_instance *endpoint)
+{
+        if (!endpoint->rcv_urb)
+                if ( (endpoint->rcv_urb = usbd_first_urb_detached_irq (&endpoint->rdy)))
+                        endpoint->rcv_urb->status = RECV_IN_PROGRESS;
+
+        //TRACE_MSG1(PCD, "BUS_RCV_URB: %p", endpoint->rcv_urb);
+        return endpoint->rcv_urb;
+}
+
+
+/*! pcd_rcv_complete_irq - complete a receive operation
+ * Called by UDC driver to show completion of outstanding I/O, this will
+ * update the urb length and if necessary will finish the urb passing it to the
+ * bottom half which will in turn call the function driver callback.
+ */
+struct usbd_urb * pcd_rcv_complete_irq (struct usbd_endpoint_instance *endpoint, int len, int urb_bad);
+struct usbd_urb * pcd_rcv_finished_irq (struct usbd_endpoint_instance *endpoint, int len, int urb_bad);
+
+
+/*! pcd_rcv_cancelled_irq - cancel current receive urb
+ * Called by UDC driver to cancel the current receive urb.
+ */
+static __inline__ void pcd_rcv_cancelled_irq (struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *rcv_urb;
+
+        TRACE_MSG1(PCD, "BUS_RCV CANCELLED: %p", (int) endpoint->rcv_urb);
+        RETURN_IF (! (rcv_urb = endpoint->rcv_urb));
+        //TRACE_MSG1(PCD, "rcv_urb: %p", (int)endpoint->rcv_urb);
+        usbd_urb_finished_irq (rcv_urb, RECV_CANCELLED);
+        endpoint->sent = endpoint->last = 0;
+        endpoint->rcv_urb = NULL;
+}
+
+
+/*! pcd_tx_next_irq - get the current or next urb to transmit
+ * Called by UDC driver to get current transmit urb or next available transmit urb.
+ */
+static __inline__ struct usbd_urb * pcd_tx_next_irq (struct usbd_endpoint_instance *endpoint)
+{
+        if (!endpoint->tx_urb)
+                if ( (endpoint->tx_urb = usbd_first_urb_detached_irq (&endpoint->tx))) {
+#if 0
+                        int i;
+                        u8 *cp = endpoint->tx_urb->buffer;
+
+                        TRACE_MSG2(PCD, "NEXT TX: length: %d flags: %x", 
+                                        endpoint->tx_urb->actual_length, endpoint->tx_urb->flags);
+
+                        for (i = 0; i < endpoint->tx_urb->actual_length;  i+= 8)
+
+                                TRACE_MSG8(PCD, "SENT  %02x %02x %02x %02x %02x %02x %02x %02x",
+                                                cp[i + 0], cp[i + 1], cp[i + 2], cp[i + 3],
+                                                cp[i + 4], cp[i + 5], cp[i + 6], cp[i + 7]
+                                          );
+#endif
+                        endpoint->tx_urb->status = SEND_IN_PROGRESS;
+                }
+        //TRACE_MSG1(PCD, "BUS_TX NEXT TX_URB: %p", (int)endpoint->tx_urb);
+        return endpoint->tx_urb;
+}
+
+
+/*! pcd_tx_complete_irq - complete a transmit operation
+ * Called by UDC driver to show completion of an outstanding I/O, this will update the urb sent
+ * information and if necessary will finish the urb passing it to the bottom half which will in
+ * turn call the function driver callback.
+ */
+struct usbd_urb * pcd_tx_complete_irq (struct usbd_endpoint_instance *endpoint, int restart);
+
+
+/*! pcd_tx_cancelled_irq - finish pending tx_urb with SEND_CANCELLED
+ * Called by UDC driver to cancel the current transmit urb.
+ */
+static __inline__ void pcd_tx_cancelled_irq (struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *tx_urb;
+
+        TRACE_MSG1(PCD, "BUS_TX CANCELLED: %p", (int) endpoint->tx_urb);
+        RETURN_IF (! (tx_urb = endpoint->tx_urb));
+        usbd_urb_finished_irq (tx_urb, SEND_CANCELLED);
+        endpoint->sent = endpoint->last = 0;
+        endpoint->tx_urb = NULL;
+}
+
+
+/*! pcd_tx_sendzlp - test if we need to send a ZLP
+ * This has a side-effect of reseting the USBD_URB_SENDZLP flag.
+ */
+static __inline__ int pcd_tx_sendzlp (struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *tx_urb = endpoint->tx_urb;
+        RETURN_FALSE_IF (!tx_urb || (tx_urb->actual_length < endpoint->sent) || ! (tx_urb->flags & USBD_URB_SENDZLP)); 
+        tx_urb->flags &= ~USBD_URB_SENDZLP;
+        return TRUE;
+}
+
+
+/*! pcd_rcv_complete_irq - complete a receive
+ * Called from rcv interrupt to complete.
+ */
+static __inline__ void pcd_rcv_fast_complete_irq (struct usbd_endpoint_instance *endpoint, struct usbd_urb *rcv_urb)
+{
+        //TRACE_MSG1(PCD, "BUS_RCV FAST COMPLETE: %d", rcv_urb->actual_length);
+        usbd_urb_finished_irq (rcv_urb, RECV_OK);
+} 
+
+/*! pcd_recv_setup - process a device request
+ * Note that we verify if a receive urb has been queued for H2D with non-zero wLength
+ * and return -EINVAL to stall if the upper layers have not properly tested for and 
+ * setup a receive urb in this case.
+ */
+static __inline__ int pcd_recv_setup_irq (struct pcd_instance *pcd, struct usbd_device_request *request)
+{
+        struct usbd_bus_instance *bus = pcd->bus;
+        struct usbd_endpoint_instance *endpoint = bus->endpoint_array + 0;
+        TRACE_SETUP (PCD, request);
+        RETURN_EINVAL_IF (usbd_device_request(bus, request));         // fail if already failed
+
+        //TRACE_MSG2(PCD, "BUS_RECV SETUP: RCV URB: %x TX_URB: %x", (int)endpoint->rcv_urb, (int)endpoint->tx_urb);
+        RETURN_ZERO_IF ( (request->bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_DEVICE2HOST);      
+        RETURN_ZERO_IF (!le16_to_cpu (request->wLength));
+        RETURN_EINVAL_IF (!endpoint->rcv_urb);
+        return 0;
+}
+
+/*! pcd_recv_setup_emulate_irq - emulate a device request
+ * Called by the UDC driver to inject a SETUP request. This is typically used
+ * by drivers for UDC's that do not pass all SETUP requests to us but instead give us
+ * a configuration change interrupt. 
+ */
+int pcd_recv_setup_emulate_irq(struct usbd_bus_instance *, u8, u8, u16, u16, u16);
+
+/*! pcd_ep0_reset_irq - reset ep0 endpoint 
+ */
+static void __inline__ pcd_ep0_reset_endpoint_irq (struct usbd_endpoint_instance *endpoint)
+{
+        TRACE_MSG0(PCD, "BUS_EP0 RESET");
+        pcd_tx_cancelled_irq (endpoint);
+        pcd_rcv_cancelled_irq (endpoint);
+        endpoint->sent = endpoint->last = 0;
+}
+
+/*! pcd_check_device_feature - verify that feature is set or clear
+ * Check current feature setting and emulate SETUP Request to set or clear
+ * if required.
+ */
+void pcd_check_device_feature(struct usbd_bus_instance *, int , int );
+
diff -uNr linux/drivers/no-otg/otgcore/Makefile linux/drivers/otg/otgcore/Makefile
--- linux/drivers/no-otg/otgcore/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/Makefile	2006-09-01 21:41:34.000000000 +0200
@@ -0,0 +1,107 @@
+#
+# Belcarra OTG - On-The-Go 
+#
+# Copyright (c) 2004 Belcarra Technologies Corp
+
+TOPDIR ?= ../../../..
+
+subdir-y 	:= 
+subdir-m 	:=
+subdir-n 	:=
+subdir- 	:=
+
+
+# The target object and module list name.
+
+O_TARGET	:= otgcore_target.o 
+
+# Objects that export symbols.
+
+export-objs	:= core-init-l24.o otg.o otg-trace.o otg-mesg.o usbp-bops.o usbp-fops.o otg-mesg-l24.o
+
+# Multipart objects. (core layer)
+
+list-multi		:= otgtrace.o otgcore.o otgadmin.o 
+
+otgcore-objs		:= core-init-l24.o otg.o \
+			otg-trace.o otg-trace-l24.o \
+			otg-mesg.o otg-mesg-l24.o \
+			otg-fw.o \
+			usbp-fops.o usbp-bops.o 
+
+
+usbprocfs-objs		:= usbp-procfs.o
+
+
+ifeq ("$(CONFIG_OTG_FW_MN)", "y")
+otgcore-objs		+= otg-fw-mn.o
+else
+otgcore-objs		+= otg-fw-df.o
+endif
+
+
+# Optional parts of multipart objects.
+
+# Object file lists.
+
+obj-y		:=
+obj-m		:=
+obj-n		:=
+obj-		:=
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_OTG)		+= otgcore.o 
+obj-$(CONFIG_OTG_PROCFSM)       += usbprocfs.o
+
+
+# Object files in subdirectories
+
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+int-m		:= $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
+OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
+OTG=$(TOPDIR)/drivers/otg
+#USBDCORE_DIR=$(OTG)/usbdcore
+OTGCORE_DIR=$(OTG)/otgcore
+EXTRA_CFLAGS +=          -Wno-missing-prototypes -Wno-unused -Wno-format -I$(OTG)
+EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format -I$(OTG) 
+
+vpath %.c $(OTGCORE_DIR)
+
+# Link rules for multi-part drivers.
+
+otgadmin.o: $(otgadmin-objs)
+	$(LD) -r -o $@ $(otgadmin-objs)
+
+otgcore.o: $(otgcore-objs)
+	$(LD) -r -o $@ $(otgcore-objs)
+
+otgtrace.o: $(otgtrace-objs)
+	$(LD) -r -o $@ $(otgtrace-objs)
+
+usbprocfs.o: $(usbprocfs-objs)
+	$(LD) -r -o $@ $(usbprocfs-objs)
+
diff -uNr linux/drivers/no-otg/otgcore/Makefile-l26 linux/drivers/otg/otgcore/Makefile-l26
--- linux/drivers/no-otg/otgcore/Makefile-l26	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/Makefile-l26	2006-09-01 21:41:34.000000000 +0200
@@ -0,0 +1,24 @@
+#
+# Belcarra OTG - On-The-Go 
+#
+# Copyright (c) 2004 Belcarra Technologies Corp
+
+OTG=$(TOPDIR)/drivers/otg
+EXTRA_CFLAGS +=          -Wno-missing-prototypes -Wno-unused -Wno-format -I$(OTG) 
+EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format -I$(OTG) 
+
+#otgadmin-objs		:= admin-init-l24.o otg-admin.o otg-decode.o 
+#obj-$(CONFIG_OTG)	+= otgadmin.o 
+
+otgcore-objs		:= core-init-l24.o otg.o \
+			otg-trace.o otg-trace-l24.o \
+			otg-mesg.o otg-mesg-l24.o \
+			otg-fw.o \
+			usbp-bops.o \
+			usbp-fops.o \
+
+obj-$(CONFIG_OTG)	+= otgcore.o 
+
+#otgtrace-objs		:= otg-trace.o
+#obj-$(CONFIG_OTG_TRACE)	+= otgtrace.o 
+
diff -uNr linux/drivers/no-otg/otgcore/TODO-USBP.txt linux/drivers/otg/otgcore/TODO-USBP.txt
--- linux/drivers/no-otg/otgcore/TODO-USBP.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/TODO-USBP.txt	2006-09-01 21:41:34.000000000 +0200
@@ -0,0 +1,51 @@
+USBD Core Architecture ToDo                                     Stuart Lynne
+Belcarra                                        Fri Aug 13 14:37:13 PDT 2004 
+
+
+The following need to be addressed to support ongoing development and support
+for the USB Device core and functions.
+
+
+Specifically:
+        - finish acm, make CDC compliant, support all possible operations
+        - enhance network, add NDIS support, 
+        - wmc - implement wmc
+        - obex
+        - mass storage
+
+
+These require:
+
+        - enhancements to allow building composite functions
+        - common routines for handling CDC class requirements
+
+
+1. interface list
+        
+        - currently we have an endpoint list that allows each endpoint to be
+          mapped to a function
+
+        - we need to do the same for interfaces, allow each interface to be
+          owned by a function, this will allow ep0 to multiplex per
+          interface standard requests to the proper function driver
+
+
+2. common functions
+
+        - a common send_interrupt_urb function
+        
+                int usbd_send_interrupt(struct usbd_function_instance *,
+                        int, void *, int,  int (*callback) (struct usbd_urb *, int));
+                
+
+        - this creates an interrupt urb on the required endpoint, copies the
+          data in, and starts it with the appropriate callback etc.
+
+
+        - notification
+
+                usbd_network_notfication
+                usbd_response_available
+                usbd_serial_state
+
+
diff -uNr linux/drivers/no-otg/otgcore/core-init-l24.c linux/drivers/otg/otgcore/core-init-l24.c
--- linux/drivers/no-otg/otgcore/core-init-l24.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/core-init-l24.c	2006-09-01 21:41:34.000000000 +0200
@@ -0,0 +1,173 @@
+/*
+ * otg/otg/core-init-l24.c - OTG Peripheral Controller Driver Module Initialization
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcara.com>, 
+ *      Tom Rushworth <tbr@belcara.com>, 
+ *      Bruce Balden <balden@belcara.com>
+ *
+ * This is the linux 2.4 version.
+ *
+ */
+/*!
+ * @file otg/otgcore/core-init-l24.c
+ * @brief OTG Core Linux initialization.
+ *
+ * This file is the starting point for defining the Linux OTG Core 
+ * driver. It references and starts all of the other components that
+ * must be "linked" into the OTGCORE mdoule.
+ *
+ * @ingroup OTGCore
+ */
+
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-pcd.h>
+#include <otg/otg-ocd.h>
+
+EMBED_LICENSE(); // When supported by the OS, embed license information in the binary
+
+
+#ifdef OTG_MALLOC_TEST
+int otg_mallocs;
+#endif /* OTG_MALLOC_TEST */
+
+otg_tag_t CORE;
+
+#ifdef CONFIG_OTG_FW_MN
+struct otg_firmware *otg_firmware_loaded = &otg_firmware_mn;
+struct otg_firmware *otg_firmware_orig = &otg_firmware_mn;
+#else /* CONFIG_OTG_FW_MN */
+struct otg_firmware *otg_firmware_loaded = &otg_firmware_df;
+struct otg_firmware *otg_firmware_orig = &otg_firmware_df;
+#endif /* CONFIG_OTG_FW_MN */
+
+struct otg_firmware *otg_firmware_loading;
+
+
+struct otg_instance otg_instance_private;
+
+struct hcd_instance hcd_instance_private = { otg: &otg_instance_private, };
+struct ocd_instance ocd_instance_private = { otg: &otg_instance_private, };
+struct pcd_instance pcd_instance_private = { otg: &otg_instance_private, };
+struct tcd_instance tcd_instance_private = { otg: &otg_instance_private, };
+
+struct otg_instance otg_instance_private = {
+        hcd: &hcd_instance_private,
+        ocd: &ocd_instance_private,
+        pcd: &pcd_instance_private,
+        tcd: &tcd_instance_private,
+};
+
+struct otg_instance *otg_instance = &otg_instance_private;
+
+char * otg_get_state_name(int state)
+{
+        struct otg_state *otg_state;
+        if (!otg_firmware_loaded || (state >= otg_firmware_loaded->number_of_states))
+                return "UNKNOWN_STATE";
+
+        otg_state = otg_firmware_loaded->otg_states + state;
+        return otg_state->name;
+}
+
+
+/* ************************************************************************************* */
+
+
+/* otg_modinit - linux module initialization
+ */
+static int otg_modinit (void)
+{
+	int message_init = 0;
+	int message_init_l24 = 0;
+	int trace_init = 0;
+	int trace_init_l24 = 0;
+
+
+        printk(KERN_INFO"%s: \n", __FUNCTION__);
+
+        trace_init = otg_trace_init();
+        trace_init_l24 = otg_trace_init_l24();
+
+        CORE = otg_trace_obtain_tag();
+
+        TRACE_MSG0(CORE,"--");
+        otg_instance->current_outputs = otg_firmware_loaded->otg_states;
+        otg_instance->previous_outputs = otg_firmware_loaded->otg_states;
+
+	/* initialize otg-mesg and usbp 
+	 */
+        THROW_IF((message_init = otg_message_init(otg_instance)), error);
+        THROW_IF((message_init_l24 = otg_message_init_l24(otg_instance)), error);
+	THROW_IF(usbd_device_init(), error);
+
+        otg_set_ocd_ops(NULL);
+        otg_set_tcd_ops(NULL);
+        otg_set_hcd_ops(NULL);
+        otg_set_pcd_ops(NULL);
+
+        CATCH(error) {
+                CORE = otg_trace_invalidate_tag(CORE);
+                if (trace_init_l24 )otg_trace_exit_l24();
+                if (trace_init) otg_trace_exit();
+                if (message_init_l24 )otg_message_exit_l24();
+                if (message_init) otg_message_exit();
+                return -EINVAL;
+        }
+        return 0;
+}
+module_init (otg_modinit);
+
+
+#if OTG_EPILOGUE  /* Set nonzero in <otg-module.h> when -DMODULE is in force */
+/* otg_modexit - This is *only* used for drivers compiled and used as a module.
+ */
+static void otg_modexit (void)
+{
+        printk(KERN_INFO"%s: \n", __FUNCTION__);
+
+	usbd_device_exit();
+        otg_message_exit_l24();
+
+        CORE = otg_trace_invalidate_tag(CORE);
+        otg_trace_exit();
+
+        if (otg_firmware_loading) {
+                lkfree(otg_firmware_loading->otg_states);
+                lkfree(otg_firmware_loading->otg_tests);
+                lkfree(otg_firmware_loading);
+        }
+        if (otg_firmware_loaded && (otg_firmware_loaded != otg_firmware_orig)) {
+                lkfree(otg_firmware_loaded->otg_states);
+                lkfree(otg_firmware_loaded->otg_tests);
+                lkfree(otg_firmware_loaded);
+        }
+}
+#endif
+
+#if defined (CONFIG_OTG_USBD_PM)
+int usbd_load(char * arg) { return 0; }
+int usbd_unload(char *arg) { return 0; }
+OTG_EXPORT_SYMBOL(usbd_load);
+OTG_EXPORT_SYMBOL(usbd_unload);
+#endif
+
+MOD_EXIT(otg_modexit);
+OTG_EXPORT_SYMBOL(otg_get_state_name);
+
+#ifdef OTG_MALLOC_TEST
+OTG_EXPORT_SYMBOL(otg_mallocs);
+#endif /* OTG_MALLOC_TEST */
+
diff -uNr linux/drivers/no-otg/otgcore/hub.c linux/drivers/otg/otgcore/hub.c
--- linux/drivers/no-otg/otgcore/hub.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/hub.c	2006-09-01 21:41:34.000000000 +0200
@@ -0,0 +1,607 @@
+/*
+ * otg/otgcore/hub.c
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ * This is a root hub function.
+ *
+ */
+/*!
+ * @file otg/otgcore/hub.c
+ * @brief A simple hub function driver.
+ *
+ *
+ * @ingroup USBDCore
+ */
+#include <otg/otg-compat.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/ctype.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+
+#ifdef CONFIG_OTG_ROOT_HUB
+/*
+ * Root Hub Configuration
+ *
+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
+ * Data Interface Alternate description(s)
+ * Interface description(s)
+ * Configuration description(s)
+ * Device Description
+ */
+
+#define BULK_INT        0x00
+#define ENDPOINTS       0x01
+
+#if 0
+
+Configuration descriptor [1      ] 09 02 19 00 01 01 02 00 00 
+                                   09 02 19 00 01 01 00 40 00
+
+Interface descriptor     [1:1:0  ] 09 04 00 00 01 09 00 00 03 
+Endpoint descriptor      [1:1:0:1] 07 05 81 03 10 00 ff 
+
+#endif
+
+#if defined(OTG_WINCE)
+
+static struct hub_descriptor rh_hub_descriptor;
+struct usbd_endpoint_descriptor rh_data;
+
+static struct usbd_endpoint_descriptor *rh_default[] = { &rh_data, };
+u8 rh_indexes[] = { BULK_INT, };
+
+static struct usbd_interface_descriptor rh_data_alternate_descriptor;
+static struct usbd_alternate_description rh_data_alternate_descriptions[1];
+};
+
+static struct usbd_interface_description rh_interfaces[1];
+
+struct usbd_configuration_descriptor rh_configuration_descriptor;
+
+struct usbd_configuration_description rh_description[1];
+
+static struct usbd_device_descriptor rh_device_descriptor;
+#ifdef CONFIG_OTG_HIGH_SPEED
+static struct usbd_device_qualifier_descriptor rh_device_qualifier_descriptor;
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+static struct usbd_endpoint_request rh_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
+        { 0, },
+};
+
+static struct usbd_otg_descriptor rh_otg_descriptor;
+
+struct usbd_device_description rh_device_description;
+
+void hub_global_init(void)
+{
+        ZERO(rh_hub_descriptor);
+        rh_hub_descriptor.bDescLength = 0x09;
+        rh_hub_descriptor.bDescriptorType = USB_DT_HUB;
+        rh_hub_descriptor.bNbrPorts = 0x00;
+        rh_hub_descriptor.wHubCharacteristics = HUB_GANGED_POWER | HUB_GLOBAL_OVERCURRENT;
+        rh_hub_descriptor.bPwrOn2PwrGood = 0x01;
+        rh_hub_descriptor.bHubContrCurrent = 0x01;
+        rh_hub_descriptor.DeviceRemovable = 0x00;
+        rh_hub_descriptor.PortPwrCtrlMask = 0xff;
+
+        ZERO(rh_data);
+        rh_data.bLength: 0x07; 
+        rh_data.bDescriptorType = USB_DT_ENDPOINT; 
+        rh_data.bEndpointAddress = USB_DIR_IN; 
+        rh_data.bmAttributes = INTERRUPT; 
+        rh_data.wMaxPacketSize = __constant_cpu_to_le16(0x4);
+        rh_data.bInterval: 0xff; 
+
+        ZERO(rh_data_alternate_desriptor);
+        rh_data_alternate_descriptor.bLength = 0x09;
+        rh_data_alternate_descriptor.bDescriptorType = USB_DT_INTERFACE;
+        rh_data_alternate_descriptor.bNumEndpoints = 0x01;
+        rh_data_alternate_descriptor.bInterfaceClass = USB_CLASS_HUB;
+
+        ZERO(rh_data_alternate_descriptions);
+        rh_data_alternate_descriptors[0].iInterface =Root hub - Status";
+        rh_data_alternate_descriptors[0].interface_descriptor = &rh_data_alternate_descriptor;
+        rh_data_alternate_descriptors[0].endpoints = sizeof (rh_default) / sizeof(struct usbd_endpoint_descriptor *);
+        rh_data_alternate_descriptors[0].endpoint_list = rh_default;
+        rh_data_alternate_descriptors[0].endpoint_indexes = rh_indexes;
+
+        ZERO(rh_interfaces);
+
+        rh_interfaces[0].alternates = sizeof (rh_data_alternate_descriptions) / sizeof (struct usbd_alternate_description);
+        rh_interfaces[0].alternate_list = rh_data_alternate_descriptions;
+
+
+        ZERO(rh_configuration_descriptor);
+        rh_configuration_descriptor.bLength = 0x09;
+        rh_configuration_descriptor.bDescriptorType = USB_DT_CONFIGURATION;
+        rh_configuration_descriptor.bNumInterfaces = sizeof (rh_interfaces) / sizeof (struct usbd_interface_description);
+        rh_configuration_descriptor.bConfigurationValue = 0x01;
+
+
+        ZERO(rh_description);
+        rh_description[0].configuration_descriptor =  &rh_configuration_descriptor;
+        rh_description[0].iConfiguration = Root Hub";
+        rh_description[0].bNumInterfaces = sizeof (rh_interfaces) / sizeof (struct usbd_interface_description);
+        rh_description[0].interface_list = rh_interfaces;
+
+        ZERO(rh_device_descriptor);
+
+        rh_device_descriptor.bLength = sizeof(struct usbd_device_descriptor);
+        rh_device_descriptor.bDescriptorType = USB_DT_DEVICE;
+        rh_device_descriptor.bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION);
+        rh_device_descriptor.bDeviceClass = USB_CLASS_HUB;
+
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+        ZERO(rh_device_qualifier_descriptor);
+        rh_device_qualifier_descriptor.bLength = sizeof(struct usbd_device_qualifier_descriptor);
+        rh_device_qualifier_descriptor.bDescriptorType = USB_DT_DEVICE_QUALIFIER;
+        rh_device_qualifier_descriptor.bcdUSB = __constant_cpu_to_le16(USB_BCD_VERSION);
+        rh_device_qualifier_descriptor.bDeviceClass = USB_CLASS_HUB;
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+        ZERO(rh_otg_descriptor);
+        rh_otg_descriptor.bLength = sizeof(struct usbd_otg_descriptor);
+        rh_otg_descriptor.bDescriptorType = USB_DT_OTG;
+        rh_otg_descriptor.bmAttributes = 0;
+
+
+        ZERO(rh_device_description);
+        rh_device_description.device_descriptor = &rh_device_descriptor;
+        #ifdef CONFIG_OTG_HIGH_SPEED
+        rh_device_description.device_qualifier_descriptor = &rh_device_qualifier_descriptor;
+        #endif /* CONFIG_OTG_HIGH_SPEED */
+        rh_device_description.otg_descriptor = &rh_otg_descriptor;
+        rh_device_description.iManufacturer = "";
+        rh_device_description.iProduct = "root hub";
+        rh_device_description.endpointsRequested = ENDPOINTS;
+        rh_device_description.requestedEndpoints = rh_endpoint_requests;
+
+}
+#else /* defined(OTG_WINCE) */
+
+static struct hub_descriptor rh_hub_descriptor = {
+        bDescLength: 0x09,
+        bDescriptorType: USB_DT_HUB,
+        bNbrPorts: 0x00,
+        wHubCharacteristics: HUB_GANGED_POWER | HUB_GLOBAL_OVERCURRENT,
+        bPwrOn2PwrGood: 0x01,
+        bHubContrCurrent: 0x01,
+        DeviceRemovable: 0x00,
+        PortPwrCtrlMask: 0xff,
+};
+
+struct usbd_endpoint_descriptor rh_data = {
+        bLength: 0x07, 
+        bDescriptorType: USB_DT_ENDPOINT, 
+        bEndpointAddress: USB_DIR_IN, 
+        bmAttributes: INTERRUPT, 
+        wMaxPacketSize: __constant_cpu_to_le16(0x4), 
+        bInterval: 0xff, 
+};
+
+static struct usbd_endpoint_descriptor *rh_default[] = { &rh_data, };
+u8 rh_indexes[] = { BULK_INT, };
+
+static struct usbd_interface_descriptor rh_data_alternate_descriptor = {
+        bLength: 0x09,
+        bDescriptorType: USB_DT_INTERFACE,
+        bNumEndpoints: 0x01,
+        bInterfaceClass: USB_CLASS_HUB,
+}; 
+
+static struct usbd_alternate_description rh_data_alternate_descriptions[] = {
+      { iInterface:"Root hub - Status",
+              interface_descriptor: &rh_data_alternate_descriptor,
+              endpoints:sizeof (rh_default) / sizeof(struct usbd_endpoint_descriptor *),
+              endpoint_list: rh_default,
+              endpoint_indexes: rh_indexes,
+      },
+};
+
+static struct usbd_interface_description rh_interfaces[] = {
+      { alternates:sizeof (rh_data_alternate_descriptions) / sizeof (struct usbd_alternate_description),
+              alternate_list:rh_data_alternate_descriptions,},
+};
+
+
+struct usbd_configuration_descriptor rh_configuration_descriptor = {
+        bLength: 0x09,
+        bDescriptorType: USB_DT_CONFIGURATION,
+        bNumInterfaces: sizeof (rh_interfaces) / sizeof (struct usbd_interface_description),
+        bConfigurationValue: 0x01,
+};
+
+struct usbd_configuration_description rh_description[] = {
+      { configuration_descriptor: &rh_configuration_descriptor,
+              iConfiguration:"Root Hub",
+                bNumInterfaces:sizeof (rh_interfaces) / sizeof (struct usbd_interface_description),
+              interface_list:rh_interfaces,},
+};
+
+static struct usbd_device_descriptor rh_device_descriptor = {
+        bLength: sizeof(struct usbd_device_descriptor),
+        bDescriptorType: USB_DT_DEVICE,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: USB_CLASS_HUB,
+};
+
+#ifdef CONFIG_OTG_HIGH_SPEED
+static struct usbd_device_qualifier_descriptor rh_device_qualifier_descriptor = {
+        bLength: sizeof(struct usbd_device_qualifier_descriptor),
+        bDescriptorType: USB_DT_DEVICE_QUALIFIER,
+        bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
+        bDeviceClass: USB_CLASS_HUB,
+};
+#endif /* CONFIG_OTG_HIGH_SPEED */
+
+static struct usbd_endpoint_request rh_endpoint_requests[ENDPOINTS+1] = {
+        { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
+        { 0, },
+};
+
+static struct usbd_otg_descriptor rh_otg_descriptor = {
+        bLength : sizeof(struct usbd_otg_descriptor),
+        bDescriptorType: USB_DT_OTG,
+        bmAttributes: 0,
+};
+
+struct usbd_device_description rh_device_description = {
+        device_descriptor: &rh_device_descriptor,
+        #ifdef CONFIG_OTG_HIGH_SPEED
+        device_qualifier_descriptor: &rh_device_qualifier_descriptor,
+        #endif /* CONFIG_OTG_HIGH_SPEED */
+        otg_descriptor: &rh_otg_descriptor,
+        iManufacturer: "",
+        iProduct: "root hub",
+        endpointsRequested: ENDPOINTS,
+        requestedEndpoints: rh_endpoint_requests,
+};
+#endif /* defined(OTG_WINCE) */
+
+/* root hub Private variables ******************************************************************** */
+
+struct rh_private {
+        struct usbd_function_instance *function;
+        int usb_driver_registered;              // non-zero if usb function registered
+        unsigned char connected;                // non-zero if connected to host (configured)
+        u8 ports;
+        u8 hub_features;
+        u32 *port_features;
+        u32 ports_status;
+        struct WORK_STRUCT bh;
+};
+
+struct rh_private rh_private;
+
+/* Transmit Function *************************************************************************** */
+
+void rh_task(void *data)
+{
+
+        //struct rh_private *rh = (struct rh_private *)data;
+        //struct usbd_function_instance *function = rh->function;
+        //struct usbd_bus_instance *bus = function->bus;
+
+        printk(KERN_INFO"%s: start\n", __FUNCTION__);
+#if 0
+        wait_queue_head_t rh_wait_queue;
+        init_waitqueue_head(&rh_wait_queue);
+
+        while (rh->bh.data && rh->connected) {
+                u32 ports_status = cpu_to_le32(bus->driver->bops->get_ports_status(bus));
+
+                printk(KERN_INFO"%s: status: %08x\n", __FUNCTION__, ports_status);
+
+                if (rh->ports_status != ports_status) {
+                        struct usbd_urb *urb = usbd_alloc_urb (function, BULK_INT, 4, NULL);
+                        BREAK_UNLESS(urb);
+                        memcpy(urb->buffer, &ports_status, 4);
+                        urb->actual_length = 4;
+                        if (usbd_send_urb(urb)) {
+                                printk(KERN_INFO"%s: usbd_send_urb failed\n", __FUNCTION__);
+                                usbd_dealloc_urb (urb);
+                        }
+                }
+                rh->ports_status = ports_status;
+                interruptible_sleep_on_timeout(&rh_wait_queue, 10000);
+        }
+#endif
+        printk(KERN_INFO"%s: exiting\n", __FUNCTION__);
+}
+
+/* USB Device Functions ************************************************************************ */
+
+/* rh_event_irq - process a device event
+ */
+void rh_event_irq (struct usbd_function_instance *function, usbd_device_event_t event, int data)
+{
+        struct rh_private *rh = &rh_private;
+
+        switch (event) {
+        case DEVICE_CONFIGURED:
+                rh->connected = 1;
+
+		SET_WORK_ARG(rh->bh, &rh_private);
+//                rh->bh.data = &rh_private;
+		SCHEDULE_WORK(rh_private.bh);
+//                schedule_task(&rh_private.bh);
+                break;
+
+        case DEVICE_RESET:
+        case DEVICE_DE_CONFIGURED:
+                BREAK_UNLESS(rh->connected);
+                rh->connected = 0;
+                rh->bh.data = 0;
+                break;
+        default: 
+                break;
+        }
+}
+
+/* copy_config
+ * @urb: pointer to urb
+ * @data: pointer to configuration data
+ * @length: length of data
+ *
+ * Copy configuration data to urb transfer buffer if there is room for it.
+ */
+static int copy_report (struct usbd_urb *urb, void *data, int size, int max_buf)
+{
+        int available;
+        int length = size;
+
+        //printk(KERN_INFO"%s: data: %p size: %d max: %d\n", __FUNCTION__, data, size, max_buf);
+        RETURN_EINVAL_UNLESS (urb);
+        RETURN_EINVAL_UNLESS (data);
+        RETURN_EINVAL_UNLESS (size);
+
+        RETURN_EINVAL_IF ((available = max_buf - urb->actual_length) <= 0);
+
+        //printk(KERN_INFO"%s: length: %d available: %d\n", __FUNCTION__, length, available);
+
+        length = (length < available) ? length : available;
+        memcpy (urb->buffer + urb->actual_length, data, length);
+        urb->actual_length += length;
+        return 0;
+}
+
+/* rh_recv_setup_irq - called to indicate urb has been received
+ */
+int rh_recv_setup_irq (struct usbd_function_instance *function, struct usbd_device_request *request)
+{
+        struct usbd_bus_instance *bus = function->bus;
+        u8 bRequest = request->bRequest;
+        u8 bmRequestType = request->bmRequestType;
+        u16 wValue = le16_to_cpu(request->wValue);
+        u16 wIndex = le16_to_cpu(request->wIndex);
+        u16 wLength = le16_to_cpu(request->wLength);
+
+        u8 direction  = bmRequestType & USB_REQ_DIRECTION_MASK;
+        u8 recipient = bmRequestType & USB_REQ_RECIPIENT_MASK;
+
+        //printk(KERN_INFO"%s:\n", __FUNCTION__);
+        /* verify that this is a class request
+         */
+        RETURN_EINVAL_UNLESS((request->bmRequestType & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS);
+
+        //printk(KERN_INFO"%s: valid direction: %x recipient: %x bRequest: %02x\n", 
+        //                __FUNCTION__, direction, recipient, bRequest);
+
+        if (USB_REQ_HOST2DEVICE == direction) {
+
+                //printk(KERN_INFO"%s: H2D\n", __FUNCTION__);
+
+                /* these do not require a reply
+                 */
+                int setclear_flag = USB_REQ_SET_FEATURE == bRequest;
+                switch (recipient) {
+                case USB_RECIP_HUB:
+                        switch (request->bRequest) {
+                        case USB_REQ_CLEAR_FEATURE:
+                        case USB_REQ_SET_FEATURE:
+                                bus->driver->bops->hub_feature(bus, wValue, setclear_flag);
+                        }
+                        return 0;
+                case USB_RECIP_PORT:
+                        switch (request->bRequest) {
+                        case USB_REQ_CLEAR_FEATURE:
+                        case USB_REQ_SET_FEATURE:
+                                bus->driver->bops->port_feature(bus, wValue, wIndex, setclear_flag);
+#if 0
+                        case USB_REQ_CLEAR_TT_BUFFER:
+                        case USB_REQ_RESET_TT:
+                        case USB_REQ_STOP_TT:
+#endif
+                        }
+                        return 0;
+                }
+        }
+        else {
+                //printk(KERN_INFO"%s: D2H\n", __FUNCTION__);
+
+                /* these do require a reply
+                 */
+                struct usbd_urb *urb;
+                int rc = 0;
+                u32 status;
+
+                RETURN_EINVAL_UNLESS(wLength);
+                RETURN_EINVAL_UNLESS((urb = usbd_alloc_urb_ep0(function, wLength, NULL)));
+
+                switch (recipient) {
+                case USB_RECIP_HUB:
+                        //printk(KERN_INFO"%s: HUB\n", __FUNCTION__);
+                        switch (request->bRequest) {
+                        case USB_REQ_GET_DESCRIPTOR:
+                                BREAK_UNLESS (copy_report(urb, (void *)&rh_hub_descriptor, sizeof(rh_hub_descriptor), wLength));
+                                rc = -EINVAL;
+                                break;
+
+                        case USB_REQ_GET_STATUS:
+                                status = cpu_to_le16(bus->driver->bops->hub_status(bus));
+                                urb->actual_length = 4;
+                                memcpy(urb->buffer, &status, 4);
+                                break;
+                        }
+                        break;
+                case USB_RECIP_PORT:
+                        //printk(KERN_INFO"%s: PORT\n", __FUNCTION__);
+                        switch (request->bRequest) {
+                        case USB_REQ_GET_STATUS:
+                                status = cpu_to_le16(bus->driver->bops->port_status(bus, wIndex));
+                                urb->actual_length = 4;
+                                memcpy(urb->buffer, &status, 4);
+                                break;
+#if 0
+                        case USB_REQ_GET_TT_STATE:
+#endif
+                        }
+                        break;
+                default:
+                        rc = -EINVAL; 
+                }
+                UNLESS (rc)
+                        RETURN_ZERO_IF(!usbd_send_urb(urb));
+                /* error */
+                usbd_dealloc_urb(urb);
+        }
+        return -EINVAL;
+}
+
+
+static int rh_function_enable (struct usbd_function_instance *function)
+{
+        struct rh_private *rh = &rh_private;
+        struct usbd_bus_instance *bus = function->bus;
+        int ports;
+
+        printk (KERN_INFO "%s:\n", __FUNCTION__);
+
+        if (rh->port_features)
+                lkfree(rh->port_features);
+
+        rh->ports = ports = bus->driver->ports;
+        rh->port_features = ckmalloc(4 * ports, GFP_KERNEL);
+        rh_private.bh.data = &rh_private;
+        
+        rh_hub_descriptor.bNbrPorts = ports;
+
+        printk (KERN_INFO "%s: ports: %d\n", __FUNCTION__, ports);
+
+        //schedule_task(&rh_private.bh);
+
+        printk (KERN_INFO "%s: finished\n", __FUNCTION__);
+
+        return 0;
+}
+
+static void rh_function_disable (struct usbd_function_instance *function)
+{               
+        struct rh_private *rh = &rh_private;
+        printk (KERN_INFO "%s:\n", __FUNCTION__);
+        if (rh->port_features)
+                lkfree(rh->port_features);
+        printk (KERN_INFO "%s: finished\n", __FUNCTION__);
+}
+
+#if defined(OTG_WINCE)
+
+struct otg_instance otg_instance_private;
+
+void hub_ops_init(void)
+{
+        ZERO(otg_instance_private);
+        otg_instance_private.hcd = &hcd_instance_privatej
+}
+
+#else /* defined(OTG_WINCE) */
+
+static struct usbd_function_operations function_ops = {
+        event_irq: rh_event_irq,
+        recv_setup_irq: rh_recv_setup_irq,
+        function_enable: rh_function_enable,
+        function_disable: rh_function_disable,
+};
+
+static struct usbd_function_driver function_driver = {
+        name:"root hub",
+        fops:&function_ops,
+        device_description:&rh_device_description,
+        bNumConfigurations:sizeof (rh_description) / sizeof (struct usbd_configuration_description),
+        configuration_description:rh_description,
+        idVendor: __constant_cpu_to_le16(0x15ec),
+        idProduct: __constant_cpu_to_le16(0xf010),
+        bcdDevice: __constant_cpu_to_le16(0x000),
+};
+#endif /* defined(OTG_WINCE) */
+
+/* USB Module init/exit ************************************************************************ */
+#if defined(OTG_WINCE)
+
+
+#else /* defined(OTG_WINCE) */
+
+
+/*
+ * rh_modinit - module init
+ */
+int rh_init (void)
+{
+        printk (KERN_INFO "%s:\n", __FUNCTION__);
+
+        THROW_IF (usbd_register_function (&function_driver), error);
+
+        printk (KERN_INFO "%s: registered\n", __FUNCTION__);
+
+        rh_private.usb_driver_registered++;
+
+//        rh_private.bh.sync = 0;
+//        rh_private.bh.routine = rh_task;
+	PREPARE_WORK_ITEM(rh_private.bh,rh_task,NULL);
+
+        CATCH(error) {
+                if (rh_private.usb_driver_registered) {
+                        usbd_deregister_function (&function_driver);
+                        rh_private.usb_driver_registered = 0;
+                }
+                return -EINVAL;
+        }
+        printk (KERN_INFO "%s: finished\n", __FUNCTION__);
+        return 0;
+}
+
+/* rh_modexit - module cleanup
+ */
+void rh_exit (void)
+{
+        //while (rh_private.bh.sync) 
+        while (PENDING_WORK_ITEM(rh_private.bh))
+                schedule_timeout(HZ);
+
+        //rh_private.bh.data = 0;
+        SET_WORK_ARG(rh_private.bh,0);
+        while (PENDING_WORK_ITEM(rh_private.bh))
+                schedule_timeout(HZ);
+        
+        if (rh_private.usb_driver_registered) 
+                usbd_deregister_function (&function_driver);
+}
+#endif /* defined(OTG_WINCE) */
+#endif /* CONFIG_OTG_ROOT_HUB */
+
diff -uNr linux/drivers/no-otg/otgcore/otg-fw-df.c linux/drivers/otg/otgcore/otg-fw-df.c
--- linux/drivers/no-otg/otgcore/otg-fw-df.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/otg-fw-df.c	2006-09-01 21:41:34.000000000 +0200
@@ -0,0 +1,121 @@
+
+/* Generated by otg-tests-c.awk
+ *
+ * Do not Edit, see otg-state.awk
+ */
+
+
+/*!
+* @file otg/otgcore/otg-fw-df.c
+* @brief OTG Firmware - Firmware for df
+*
+* This file defines the OTG State Machine tests.
+*
+*
+* @ingroup OTGFW
+*/
+
+/*!
+* @page OTGFW
+* @section OTGFW - otg-fw-df.c
+* This contains the input, output and timout definitions for the OTG state machine firmware
+*/
+
+
+#ifdef OTG_APPLICATION
+#define NULL 0
+#include "otg-fw.h"
+#include "otg-fw-df.h"
+#else	/* OTG_APPLICATION/ */
+#include <otg/otg-compat.h>
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+//#include <otg/otg-api.h>
+#include <otg/otg-fw.h>
+#include <otg/otg-fw-df.h>
+#endif	/* OTG_APPLICATION */
+
+char            otg_fw_name_df[] = "otg_df";
+
+
+struct otg_test otg_tests_df[] = {
+	/*
+	 * Copyright (c) 2004 Belcarra
+	 *
+	 */
+	/*!
+	 * This is the default Firmware. It is included in the
+	 * compiled modules and supports the auto Traditional USB
+	 * mode. No user inputs are implemented.
+	 */
+	{					 /*   */
+	 0,					 /* .test */
+	 invalid_state,				 /* .state */
+	 otg_disabled,				 /* .target */
+	 enable_otg,				 /* .test1 */
+	 },
+	/*
+	 * This is not an OTG State. It is used internally to mark the end of the
+	 * list of states and inputs.
+	 */
+	{					 /*   */
+	 1,					 /* .test */
+	 terminator_state,			 /* .state */
+	 invalid_state,				 /* .target */
+	 0,					 /* .test1 */
+	 },
+	{2, invalid_state,},
+
+};
+
+#define OTG_TESTS_DF 2
+
+int             otg_test_max_df = 2;
+
+ /* eof */
+
+/* Generated by otg-info-c.awk
+ *
+ * Do not Edit, see otg-state.awk
+ */
+
+struct otg_state otg_states_df[OTG_STATES_DF + 1] = {
+	{					 /* 0 */
+	 invalid_state,				 /* .state */
+	 m_otg_init,				 /* .meta */
+	 "invalid_state",			 /* .name */
+	 0,					 /* .tmout */
+	 0,					 /* .reset */
+	 },
+	{					 /* 1 */
+	 otg_disabled,				 /* .state */
+	 m_otg_init,				 /* .meta */
+	 "otg_disabled",			 /* .name */
+	 0,					 /* .tmout */
+	 0,					 /* .reset */
+	 },
+	{					 /* 2 */
+	 terminator_state,			 /* .state */
+	 m_otg_init,				 /* .meta */
+	 "terminator_state",			 /* .name */
+	 0,					 /* .tmout */
+	 0,					 /* .reset */
+	 /* .outputs */
+	 0,
+	 },
+
+	{0, 0, "", 0, 0,},
+
+};
+
+struct otg_firmware otg_firmware_df = {
+	OTG_STATES_DF,				 /* number of states */
+	OTG_TESTS_DF,				 /* number of tests */
+	"otg-df",				 /* name of firmware */
+	otg_states_df,				 /* struct otg_state * */
+	otg_tests_df,				 /* struct otg_test * */
+};
+
+/* eof */
diff -uNr linux/drivers/no-otg/otgcore/otg-fw-mn.c linux/drivers/otg/otgcore/otg-fw-mn.c
--- linux/drivers/no-otg/otgcore/otg-fw-mn.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/otg-fw-mn.c	2006-09-01 21:41:34.000000000 +0200
@@ -0,0 +1,511 @@
+
+/* Generated by otg-tests-c.awk
+ *
+ * Do not Edit, see otg-state.awk
+ */
+
+
+/*!
+* @file otg/otgcore/otg-fw-mn.c
+* @brief OTG Firmware - Firmware for mn
+*
+* This file defines the OTG State Machine tests.
+*
+*
+* @ingroup OTGFW
+*/
+
+/*!
+* @page OTGFW
+* @section OTGFW - otg-fw-mn.c
+* This contains the input, output and timout definitions for the OTG state machine firmware
+*/
+
+
+#ifdef OTG_APPLICATION
+#define NULL 0
+#include "otg-fw.h"
+#include "otg-fw-mn.h"
+#else	/* OTG_APPLICATION/ */
+#include <otg/otg-compat.h>
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+//#include <otg/otg-api.h>
+#include <otg/otg-fw.h>
+#include <otg/otg-fw-mn.h>
+#endif	/* OTG_APPLICATION */
+
+char            otg_fw_name_mn[] = "otg_mn";
+
+
+struct otg_test otg_tests_mn[] = {
+	/*
+	 * Copyright (c) 2004 Belcarra
+	 */
+	/*!
+	 * This is the initialization set for pcd and tcd.
+	 */
+	/*
+	 * This the initial state of the software when first loaded.
+	 * It is not possible to return to this state.
+	 */
+	{					 /*   Initialize by sending the otg_enable signal. */
+	 0,					 /* .test */
+	 invalid_state,				 /* .state */
+	 otg_disabled,				 /* .target */
+	 enable_otg,				 /* .test1 */
+	 },
+	/*
+	 * The USBOTG State Machine has been initialized but is inactive.
+	 * This state may have arrived at from either the invalid_state or
+	 * from the otg_disable state.
+	 */
+	{					 /*   Initialize by sending the otg_enable signal. */
+	 1,					 /* .test */
+	 otg_disabled,				 /* .state */
+	 otg_enable_pcd,			 /* .target */
+	 enable_otg,				 /* .test1 */
+	 },
+	/*
+	 * The State Machine stops the device drivers and waits for them
+	 * to signal that they have finished de-initializing.
+	 *
+	 * This state disables the TCD driver and waits for TCD ok.
+	 */
+	{					 /*   Wait for ok from de-initializing drivers. */
+	 2,					 /* .test */
+	 otg_disable_tcd,			 /* .state */
+	 otg_disable_pcd,			 /* .target */
+	 TCD_OK,				 /* .test1 */
+	 },
+	/*
+	 * The State Machine stops the device drivers and waits for them
+	 * to signal that they have finished de-initializing.
+	 *
+	 * This state disables the PCD driver and waits for PCD ok.
+	 */
+	{					 /*   Wait for ok from de-initializing drivers. */
+	 3,					 /* .test */
+	 otg_disable_pcd,			 /* .state */
+	 otg_disabled,				 /* .target */
+	 PCD_OK,				 /* .test1 */
+	 },
+	/*
+	 * The State Machine starts the device drivers and waits for them
+	 * to signal that they have finished initializing.
+	 *
+	 * This state enables the PCD driver and waits for PCD ok.
+	 */
+	{					 /*   Wait for ok from initializing drivers. */
+	 4,					 /* .test */
+	 otg_enable_pcd,			 /* .state */
+	 otg_enable_tcd,			 /* .target */
+	 PCD_OK,				 /* .test1 */
+	 },
+	/*
+	 * The State Machine starts the device drivers and waits for them
+	 * to signal that they have finished initializing.
+	 *
+	 * This state enables the PCD driver and waits for PCD ok.
+	 */
+	{					 /*   Wait for ok from initializing drivers. */
+	 5,					 /* .test */
+	 otg_enable_tcd,			 /* .state */
+	 otg_enabled,				 /* .target */
+	 TCD_OK,				 /* .test1 */
+	 },
+	/*
+	 * Copyright (c) 2004 Belcarra
+	 *
+	 */
+	/*!
+	 * This is the minimal firmware. It can be included in the
+	 * compiled modules and supports the auto Traditional USB
+	 * mode. No user inputs are required for normal operation.
+	 *
+	 * The b_bus_drop input can be optionally used to disconnect and re-connect.
+	 *
+	 * The enable_otg input can be optionally used to disable and re-enable.
+	 * Note that disable/enable will reset b_bus_drop.
+	 *
+	 */
+	/*!
+	 * The State Machine has successfully started the device drivers and
+	 * is waiting for an input event. Typically it will move from here to
+	 * an idle state specific to the current conditions (a_idle, b_idle, mn_idle etc.)
+	 * based on user request b_bus_drop.
+	 *
+	 */
+	{					 /*   Check for disable. */
+	 6,					 /* .test */
+	 otg_enabled,				 /* .state */
+	 otg_disable_tcd,			 /* .target */
+	 enable_otg_,				 /* .test1 */
+	 },
+	{					 /*   Move to idle. */
+	 7,					 /* .test */
+	 otg_enabled,				 /* .state */
+	 mn_idle,				 /* .target */
+	 AUTO | AUTO_,				 /* .test1 */
+	 },
+	/*!
+	 * The State Machine is in the idle state for a Traditional USB Device.
+	 * It is waiting for Vbus to indicate that it has been plugged into a USB Host.
+	 *
+	 */
+	{					 /*   Check for disable (must be done for check for bus_drop.) */
+	 8,					 /* .test */
+	 mn_idle,				 /* .state */
+	 otg_disable_tcd,			 /* .target */
+	 enable_otg_,				 /* .test1 */
+	 },
+	{					 /*   Check for b_bus_drop */
+	 9,					 /* .test */
+	 mn_idle,				 /* .state */
+	 mn_bus_drop,				 /* .target */
+	 b_bus_drop,				 /* .test1 */
+	 },
+	{					 /*   move to peripheral mode when SESSION valid. */
+	 10,					 /* .test */
+	 mn_idle,				 /* .state */
+	 mn_peripheral,				 /* .target */
+	 b_bus_drop_,				 /* .test1 */
+	 B_SESS_VLD,				 /* .test2 */
+	 },
+	/*!
+	 * The State Machine is in the idle state for a Traditional USB Device.
+	 * The B-Device applications has requested that the bus connection be dropped.
+	 * Wait for either enable_otg reset or b_bus_drop reset.
+	 */
+	{					 /*   Wait for b_bus_drop/ or enable_otg/ */
+	 11,					 /* .test */
+	 mn_bus_drop,				 /* .state */
+	 mn_idle,				 /* .target */
+	 b_bus_drop_ | enable_otg_,		 /* .test1 */
+	 },
+	/*!
+	 * The State Machine in the peripheral state for a Traditional USB Device.
+	 * The D+ pullup is enabled and we are waiting for a BUS_RESET to
+	 * indicate that the USB Host has recognized that a USB Device is attached.
+	 */
+	{					 /*   Move to idle if we loose any of these inputs. */
+	 12,					 /* .test */
+	 mn_peripheral,				 /* .state */
+	 mn_idle,				 /* .target */
+	 enable_otg_ | B_SESS_VLD_ | b_bus_drop, /* .test1 */
+	 },
+	{					 /*   Move to next state if bus reset is seen. */
+	 13,					 /* .test */
+	 mn_peripheral,				 /* .state */
+	 mn_bus_reset,				 /* .target */
+	 BUS_RESET,				 /* .test1 */
+	 },
+	/*!
+	 * The State Machine in the bus_reset state for a Traditional USB Device.
+	 * It is waiting to be enumerated and configured by the USB Host.
+	 */
+	{					 /*   Move to idle via discharge, if we loose any of these inputs. */
+	 14,					 /* .test */
+	 mn_bus_reset,				 /* .state */
+	 mn_discharge,				 /* .target */
+	 enable_otg_ | B_SESS_VLD_ | b_bus_drop, /* .test1 */
+	 },
+	{					 /*   Progress if we are addressed. */
+	 15,					 /* .test */
+	 mn_bus_reset,				 /* .state */
+	 mn_addressed,				 /* .target */
+	 ADDRESSED,				 /* .test1 */
+	 },
+	/*!
+	 * The State Machine in the configured state for a Traditional USB Device.
+	 * This means that there is an active session, there is packet traffic
+	 * with this device.
+	 */
+	{					 /*   Move to idle via discharge, if we loose any of these inputs. */
+	 16,					 /* .test */
+	 mn_addressed,				 /* .state */
+	 mn_discharge,				 /* .target */
+	 enable_otg_ | B_SESS_VLD_ | b_bus_drop, /* .test1 */
+	 },
+	{					 /*   Progress if we are configured. */
+	 17,					 /* .test */
+	 mn_addressed,				 /* .state */
+	 mn_configured,				 /* .target */
+	 CONFIGURED,				 /* .test1 */
+	 },
+	/*!
+	 * The State Machine in the configured state for a Traditional USB Device.
+	 * This means that there is an active session, there is packet traffic
+	 * with this device.
+	 */
+	{					 /*   */
+	 18,					 /* .test */
+	 mn_configured,				 /* .state */
+	 mn_suspended,				 /* .target */
+	 BUS_SUSPENDED,				 /* .test1 */
+	 },
+	{					 /*   Move to idle via discharge, if we loose any of these inputs. */
+	 19,					 /* .test */
+	 mn_configured,				 /* .state */
+	 mn_discharge,				 /* .target */
+	 enable_otg_ | B_SESS_VLD_ | b_bus_drop, /* .test1 */
+	 },
+	/*!
+	 * The State Machine in the discharge state for a Traditional USB Device.
+	 * The device has been unplugged. The Vbus discharge resistor will be enabled
+	 * for the TLDISC_DSCHRG time period.
+	 */
+	{					 /*   Progress to idle on timeout. */
+	 20,					 /* .test */
+	 mn_discharge,				 /* .state */
+	 mn_idle,				 /* .target */
+	 Tldisc_dschrg,				 /* .test1 */
+	 },
+	/*!
+	 * The State Machine in the suspend state for a Traditional USB Device.
+	 */
+	{					 /*   Move to idle via discharge, if we loose any of these inputs. */
+	 21,					 /* .test */
+	 mn_suspended,				 /* .state */
+	 mn_discharge,				 /* .target */
+	 enable_otg_ | B_SESS_VLD_ | b_bus_drop, /* .test1 */
+	 },
+	{					 /*   Check for a resumed bus. */
+	 22,					 /* .test */
+	 mn_suspended,				 /* .state */
+	 mn_configured,				 /* .target */
+	 BUS_SUSPENDED_,			 /* .test1 */
+	 },
+	{					 /*   Is remote wakeup enabled? */
+	 23,					 /* .test */
+	 mn_suspended,				 /* .state */
+	 mn_wakeup_enabled,			 /* .target */
+	 REMOTE_WAKEUP_ENABLED,			 /* .test1 */
+	 },
+	/*!
+	 * The State Machine in the suspend state for a Traditional USB Device,
+	 * prior to suspended the USB Host enabled Remote Wakeup by sending a
+	 * set REMOTE WAKUP request.
+	 */
+	{					 /*   Move to idle via discharge, if we loose any of these inputs. */
+	 24,					 /* .test */
+	 mn_wakeup_enabled,			 /* .state */
+	 mn_discharge,				 /* .target */
+	 enable_otg_ | b_bus_req_ | B_SESS_VLD_, /* .test1 */
+	 },
+	{					 /*   Check for a resumed bus. */
+	 25,					 /* .test */
+	 mn_wakeup_enabled,			 /* .state */
+	 mn_suspended,				 /* .target */
+	 BUS_SUSPENDED_,			 /* .test1 */
+	 },
+	{					 /*   Remote wakeup requested? */
+	 26,					 /* .test */
+	 mn_wakeup_enabled,			 /* .state */
+	 mn_wakeup,				 /* .target */
+	 remote_wakeup_cmd,			 /* .test1 */
+	 },
+	/*!
+	 * The State Machine in the wakeup state for a Traditional USB Device,
+	 * The REMOTE WAKEUP procedure will be performed.
+	 */
+	{					 /*   Automatic return. */
+	 27,					 /* .test */
+	 mn_wakeup,				 /* .state */
+	 mn_wakeup_enabled,			 /* .target */
+	 AUTO | AUTO_,				 /* .test1 */
+	 },
+	/*!
+	 * This is not an OTG State. It is used internally to mark the end of the
+	 * list of states and inputs.
+	 */
+	{					 /*   */
+	 28,					 /* .test */
+	 terminator_state,			 /* .state */
+	 invalid_state,				 /* .target */
+	 0,					 /* .test1 */
+	 },
+	{29, invalid_state,},
+
+};
+
+#define OTG_TESTS_MN 29
+
+int             otg_test_max_mn = 29;
+
+ /* eof */
+
+/* Generated by otg-info-c.awk
+ *
+ * Do not Edit, see otg-state.awk
+ */
+
+struct otg_state otg_states_mn[OTG_STATES_MN + 1] = {
+	{					 /* 0 */
+	 invalid_state,				 /* .state */
+	 m_otg_init,				 /* .meta */
+	 "invalid_state",			 /* .name */
+	 0,					 /* .tmout */
+	 0,					 /* .reset */
+	 },
+	{					 /* 1 */
+	 otg_disabled,				 /* .state */
+	 m_otg_init,				 /* .meta */
+	 "otg_disabled",			 /* .name */
+	 0,					 /* .tmout */
+	 enable_otg_,				 /* .reset */
+	 /* .outputs */
+	 chrg_vbus_out_ | drv_vbus_out_ | dp_pullup_out_ | loc_sof_out_,
+	 },
+	{					 /* 2 */
+	 otg_disable_tcd,			 /* .state */
+	 m_otg_init,				 /* .meta */
+	 "otg_disable_tcd",			 /* .name */
+	 0,					 /* .tmout */
+	 TCD_OK_,				 /* .reset */
+	 /* .outputs */
+	 tcd_init_out_,
+	 },
+	{					 /* 3 */
+	 otg_disable_pcd,			 /* .state */
+	 m_otg_init,				 /* .meta */
+	 "otg_disable_pcd",			 /* .name */
+	 0,					 /* .tmout */
+	 PCD_OK_,				 /* .reset */
+	 /* .outputs */
+	 pcd_init_out_,
+	 },
+	{					 /* 4 */
+	 otg_enable_pcd,			 /* .state */
+	 m_otg_init,				 /* .meta */
+	 "otg_enable_pcd",			 /* .name */
+	 0,					 /* .tmout */
+	 PCD_OK_,				 /* .reset */
+	 /* .outputs */
+	 chrg_vbus_out_ | drv_vbus_out_ | dp_pullup_out_ | loc_sof_out_ | pcd_init_out,
+	 },
+	{					 /* 5 */
+	 otg_enable_tcd,			 /* .state */
+	 m_otg_init,				 /* .meta */
+	 "otg_enable_tcd",			 /* .name */
+	 0,					 /* .tmout */
+	 TCD_OK_,				 /* .reset */
+	 /* .outputs */
+	 chrg_vbus_out_ | drv_vbus_out_ | dp_pullup_out_ | loc_sof_out_ | tcd_init_out,
+	 },
+	{					 /* 6 */
+	 otg_enabled,				 /* .state */
+	 m_otg_init,				 /* .meta */
+	 "otg_enabled",				 /* .name */
+	 0,					 /* .tmout */
+	 b_bus_drop_,				 /* .reset */
+	 },
+	{					 /* 7 */
+	 mn_idle,				 /* .state */
+	 m_b_idle,				 /* .meta */
+	 "mn_idle",				 /* .name */
+	 0,					 /* .tmout */
+	 0,					 /* .reset */
+	 /* .outputs */
+	 dp_pullup_out_ | pcd_en_out_ | tcd_en_out_power | dischrg_vbus_out_,
+	 },
+	{					 /* 8 */
+	 mn_bus_drop,				 /* .state */
+	 m_b_idle,				 /* .meta */
+	 "mn_bus_drop",				 /* .name */
+	 0,					 /* .tmout */
+	 0,					 /* .reset */
+	 },
+	{					 /* 9 */
+	 mn_peripheral,				 /* .state */
+	 m_b_peripheral,			 /* .meta */
+	 "mn_peripheral",			 /* .name */
+	 0,					 /* .tmout */
+	 BUS_RESET_,				 /* .reset */
+	 /* .outputs */
+	 dp_pullup_out | pcd_en_out | dischrg_vbus_out_,
+	 },
+	{					 /* 10 */
+	 mn_bus_reset,				 /* .state */
+	 m_b_peripheral,			 /* .meta */
+	 "mn_bus_reset",			 /* .name */
+	 0,					 /* .tmout */
+	 BUS_RESET_ | ADDRESSED_,		 /* .reset */
+	 },
+	{					 /* 11 */
+	 mn_addressed,				 /* .state */
+	 m_b_peripheral,			 /* .meta */
+	 "mn_addressed",			 /* .name */
+	 0,					 /* .tmout */
+	 ADDRESSED_ | CONFIGURED_,		 /* .reset */
+	 /* .outputs */
+	 dp_pullup_out | pcd_en_out | dischrg_vbus_out_,
+	 },
+	{					 /* 12 */
+	 mn_configured,				 /* .state */
+	 m_b_peripheral,			 /* .meta */
+	 "mn_configured",			 /* .name */
+	 0,					 /* .tmout */
+	 CONFIGURED_ | BUS_SUSPENDED_,		 /* .reset */
+	 /* .outputs */
+	 dp_pullup_out | pcd_en_out | dischrg_vbus_out_,
+	 },
+	{					 /* 13 */
+	 mn_discharge,				 /* .state */
+	 m_b_peripheral,			 /* .meta */
+	 "mn_discharge",			 /* .name */
+	 TLDISC_DSCHRG,				 /* .tmout */
+	 0,					 /* .reset */
+	 /* .outputs */
+	 dischrg_vbus_out | pcd_en_out_,
+	 },
+	{					 /* 14 */
+	 mn_suspended,				 /* .state */
+	 m_b_suspended,				 /* .meta */
+	 "mn_suspended",			 /* .name */
+	 0,					 /* .tmout */
+	 0,					 /* .reset */
+	 },
+	{					 /* 15 */
+	 mn_wakeup_enabled,			 /* .state */
+	 m_b_suspended,				 /* .meta */
+	 "mn_wakeup_enabled",			 /* .name */
+	 0,					 /* .tmout */
+	 remote_wakeup_cmd_,			 /* .reset */
+	 /* .outputs */
+	 remote_wakeup_out_,
+	 },
+	{					 /* 16 */
+	 mn_wakeup,				 /* .state */
+	 m_b_suspended,				 /* .meta */
+	 "mn_wakeup",				 /* .name */
+	 0,					 /* .tmout */
+	 0,					 /* .reset */
+	 /* .outputs */
+	 remote_wakeup_out,
+	 },
+	{					 /* 17 */
+	 terminator_state,			 /* .state */
+	 m_otg_init,				 /* .meta */
+	 "terminator_state",			 /* .name */
+	 0,					 /* .tmout */
+	 0,					 /* .reset */
+	 /* .outputs */
+	 0,
+	 },
+
+	{0, 0, "", 0, 0,},
+
+};
+
+struct otg_firmware otg_firmware_mn = {
+	OTG_STATES_MN,				 /* number of states */
+	OTG_TESTS_MN,				 /* number of tests */
+	"otg-mn",				 /* name of firmware */
+	otg_states_mn,				 /* struct otg_state * */
+	otg_tests_mn,				 /* struct otg_test * */
+};
+
+/* eof */
diff -uNr linux/drivers/no-otg/otgcore/otg-fw.c linux/drivers/otg/otgcore/otg-fw.c
--- linux/drivers/no-otg/otgcore/otg-fw.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/otg-fw.c	2006-09-01 21:41:34.000000000 +0200
@@ -0,0 +1,251 @@
+
+/* Generated by otg-fw-c.awk
+ *
+ * Do not Edit, see otg-state.awk
+ */
+
+/*!
+* @file otg/otgcore/otg-fw.c
+* @brief OTG Firmware - Input, Output and Timeout definitions
+*
+* This file defines the OTG State Machine input, output and timeout constants.
+*
+*
+* @ingroup OTGFW
+*/
+
+/*!
+* @page OTGFW
+* @section OTGFW - otg-fw.c
+* This contains the input, output and timout definitions for the OTG state machine firmware
+*/
+
+
+#ifdef OTG_APPLICATION
+#include "otg-fw.h"
+#else	/* OTG_APPLICATION/ */
+#include <otg/otg-compat.h>
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#endif	/* OTG_APPLICATION */
+
+#define OTG_VERSION_FWC 200502152159L
+
+
+#if OTG_VERSION_FWC != OTG_VERSION_FW
+#error OTG_VERSION_FWC != OTG_VERSION_FW
+#endif	/* OTG_VERSION_FWC != OTG_VERSION_FW */
+
+/* Generated by otg-input-name-c.awk
+ *
+ * Do not Edit, see otg-state.awk
+ */
+
+
+/* #include "otg-fw.h" */
+
+#define OTG_VERSION_INPUT_TABLE 200502152159L
+
+
+#if OTG_VERSION_INPUT_TABLE != OTG_VERSION_FW
+#error OTG_VERSION_INPUT_TABLE != OTG_VERSION_FW
+#endif	/* OTG_VERSION_INPUT_TABLE != OTG_VERSION_FW */
+
+
+struct otg_input_name otg_input_names[] = {
+	{ID_GND, "ID_GND",},
+	{ID_FLOAT, "ID_FLOAT",},
+	{DP_HIGH, "DP_HIGH",},
+	{DM_HIGH, "DM_HIGH",},
+	{B_SESS_END, "B_SESS_END",},
+	{A_SESS_VLD, "A_SESS_VLD",},
+	{B_SESS_VLD, "B_SESS_VLD",},
+	{VBUS_VLD, "VBUS_VLD",},
+	{SRP_DET, "SRP_DET",},
+	{SE0_DET, "SE0_DET",},
+	{SE1_DET, "SE1_DET",},
+	{BDIS_ACON, "BDIS_ACON",},
+	{CR_INT_DET, "CR_INT_DET",},
+	{HUB_PORT_CONNECT, "HUB_PORT_CONNECT",},
+	{BUS_RESET, "BUS_RESET",},
+	{ADDRESSED, "ADDRESSED",},
+	{CONFIGURED, "CONFIGURED",},
+	{NOT_SUPPORTED, "NOT_SUPPORTED",},
+	{BUS_SUSPENDED, "BUS_SUSPENDED",},
+	{a_bcon_no_tmout_req, "a_bcon_no_tmout_req",},
+	{a_hpwr_req, "a_hpwr_req",},
+	{bus_drop, "bus_drop",},
+	{a_bus_drop, "a_bus_drop",},
+	{b_bus_drop, "b_bus_drop",},
+	{bus_req, "bus_req",},
+	{a_bus_req, "a_bus_req",},
+	{b_bus_req, "b_bus_req",},
+	{b_sess_req, "b_sess_req",},
+	{suspend_req, "suspend_req",},
+	{a_suspend_req, "a_suspend_req",},
+	{b_suspend_req, "b_suspend_req",},
+	{set_remote_wakeup_cmd, "set_remote_wakeup_cmd",},
+	{remote_wakeup_cmd, "remote_wakeup_cmd",},
+	{reset_remote_wakeup_cmd, "reset_remote_wakeup_cmd",},
+	{clr_err_cmd, "clr_err_cmd",},
+	{b_hnp_cmd, "b_hnp_cmd",},
+	{ph_int_cmd, "ph_int_cmd",},
+	{ph_audio_cmd, "ph_audio_cmd",},
+	{cr_int_cmd, "cr_int_cmd",},
+	{led_on_cmd, "led_on_cmd",},
+	{led_off_cmd, "led_off_cmd",},
+	{HNP_ENABLED, "HNP_ENABLED",},
+	{HNP_CAPABLE, "HNP_CAPABLE",},
+	{HNP_SUPPORTED, "HNP_SUPPORTED",},
+	{REMOTE_WAKEUP_ENABLED, "REMOTE_WAKEUP_ENABLED",},
+	{REMOTE_CAPABLE, "REMOTE_CAPABLE",},
+	{PCD_OK, "PCD_OK",},
+	{TCD_OK, "TCD_OK",},
+	{HCD_OK, "HCD_OK",},
+	{OCD_OK, "OCD_OK",},
+	{TMOUT, "TMOUT",},
+	{enable_otg, "enable_otg",},
+	{AUTO, "AUTO",},
+	{0, "0",},
+
+};
+
+ /* eof */
+
+/* Generated by otg-ioctls-names-c.awk
+ *
+ * Do not Edit, see otg-state.awk
+ */
+#if defined(OTG_LINUX) || defined(OTG_WINCE)
+
+
+/* #include "otg-fw.h" */
+
+#define OTG_VERSION_IOCTL_TABLE 200502152159L
+
+
+#if OTG_VERSION_IOCTL_TABLE != OTG_VERSION_FW
+#error OTG_VERSION_IOCTL_TABLE != OTG_VERSION_FW
+#endif	/* OTG_VERSION_IOCTL_TABLE != OTG_VERSION_FW */
+
+struct otg_ioctl_name otg_ioctl_names[] = {
+	{OTGADMIN_A_BCON_NO_TMOUT_REQ, a_bcon_no_tmout_req, "OTGADMIN_A_BCON_NO_TMOUT_REQ",},
+	{OTGADMIN_A_HPWR_REQ, a_hpwr_req, "OTGADMIN_A_HPWR_REQ",},
+	{OTGADMIN_BUS_DROP, bus_drop, "OTGADMIN_BUS_DROP",},
+	{OTGADMIN_A_BUS_DROP, a_bus_drop, "OTGADMIN_A_BUS_DROP",},
+	{OTGADMIN_B_BUS_DROP, b_bus_drop, "OTGADMIN_B_BUS_DROP",},
+	{OTGADMIN_BUS_REQ, bus_req, "OTGADMIN_BUS_REQ",},
+	{OTGADMIN_A_BUS_REQ, a_bus_req, "OTGADMIN_A_BUS_REQ",},
+	{OTGADMIN_B_BUS_REQ, b_bus_req, "OTGADMIN_B_BUS_REQ",},
+	{OTGADMIN_B_SESS_REQ, b_sess_req, "OTGADMIN_B_SESS_REQ",},
+	{OTGADMIN_SUSPEND_REQ, suspend_req, "OTGADMIN_SUSPEND_REQ",},
+	{OTGADMIN_A_SUSPEND_REQ, a_suspend_req, "OTGADMIN_A_SUSPEND_REQ",},
+	{OTGADMIN_B_SUSPEND_REQ, b_suspend_req, "OTGADMIN_B_SUSPEND_REQ",},
+	{OTGADMIN_SET_REMOTE_WAKEUP_CMD, set_remote_wakeup_cmd, "OTGADMIN_SET_REMOTE_WAKEUP_CMD",},
+	{OTGADMIN_REMOTE_WAKEUP_CMD, remote_wakeup_cmd, "OTGADMIN_REMOTE_WAKEUP_CMD",},
+	{OTGADMIN_RESET_REMOTE_WAKEUP_CMD, reset_remote_wakeup_cmd, "OTGADMIN_RESET_REMOTE_WAKEUP_CMD",},
+	{OTGADMIN_CLR_ERR_CMD, clr_err_cmd, "OTGADMIN_CLR_ERR_CMD",},
+	{OTGADMIN_B_HNP_CMD, b_hnp_cmd, "OTGADMIN_B_HNP_CMD",},
+	{OTGADMIN_PH_INT_CMD, ph_int_cmd, "OTGADMIN_PH_INT_CMD",},
+	{OTGADMIN_PH_AUDIO_CMD, ph_audio_cmd, "OTGADMIN_PH_AUDIO_CMD",},
+	{OTGADMIN_CR_INT_CMD, cr_int_cmd, "OTGADMIN_CR_INT_CMD",},
+	{OTGADMIN_LED_ON_CMD, led_on_cmd, "OTGADMIN_LED_ON_CMD",},
+	{OTGADMIN_LED_OFF_CMD, led_off_cmd, "OTGADMIN_LED_OFF_CMD",},
+	{OTGADMIN_ENABLE_OTG, enable_otg, "OTGADMIN_ENABLE_OTG",},
+	{0, 0, "",},
+
+};
+
+ /* eof */
+#endif				/* defined(OTG_LINUX) || defined(OTG_WINCE) */
+
+/* Generated by otg-output-names-c.awk
+ *
+ * Do not Edit, see otg-state.awk
+ */
+
+char           *otg_output_names[] = {
+	"tcd_init_out",				 /* 0   Initiate Transceiver Controller Driver Initialization (or De-initialization.) */
+	"pcd_init_out",				 /* 1   Initiate Peripheral Controller Driver Initialization (or De-initialization.) */
+	"hcd_init_out",				 /* 2   Initiate Host Controller Driver Initialization (or De-initialization). */
+	"ocd_init_out",				 /* 3   Initiate OTG Controller Driver Initialization (or De-initialization). */
+	"tcd_en_out",				 /* 4   Enable Transceiver Controller Driver */
+	"pcd_en_out",				 /* 5   Enable Peripheral Controller Driver */
+	"hcd_en_out",				 /* 6   Enable Host Controller Driver */
+	"drv_vbus_out",				 /* 7   A-Device will Drive Vbus to 5V through charge pump. */
+	"chrg_vbus_out",			 /* 8   B-Device will charge Vbus to 3.3V through resistor (SRP.) */
+	"dischrg_vbus_out",			 /* 9   B-Device will discharge Vbus (enable dischage resistor.) */
+	"dm_pullup_out",			 /* 10   DM pullup control - aka loc_carkit */
+	"dm_pulldown_out",			 /* 11   DM pulldown control */
+	"dp_pullup_out",			 /* 12   DP pullup control - aka loc_conn */
+	"dp_pulldown_out",			 /* 13   DP pulldown control */
+	"clr_overcurrent_out",			 /* 14   Clear overcurrent indication */
+	"dm_det_out",				 /* 15   Enable B-Device D- High detect */
+	"dp_det_out",				 /* 16   Enable B-Device D+ High detect */
+	"cr_det_out",				 /* 17   Enable D+ CR detect */
+	"charge_pump_out",			 /* 18   Enable external charge pump. */
+	"bdis_acon_out",			 /* 19   Enable auto A-connect after B-disconnect. */
+	"mx21_vbus_drain",			 /* 20   MX21 hack */
+	"id_pulldown_out",			 /* 21   Enable the ID to ground pulldown ( (CEA-936 - 5 wire carkit.) */
+	"uart_out",				 /* 22   Enable Transparent UART mode (CEA-936.) */
+	"audio_out",				 /* 23   Enable Audio mode (CEA-936 CarKit interrupt detector.) */
+	"mono_out",				 /* 24   Enable Mono-Audio mode (CEA-936.) */
+	"remote_wakeup_out",			 /* 25   Peripheral will perform remote wakeup. */
+	"loc_sof_out",				 /* 26   Host will enable packet traffic. */
+	"loc_suspend_out",			 /* 27   Host will suspend bus. */
+	"remote_wakeup_en_out",			 /* 28   Host will send remote wakeup enable or disable request. */
+	"hnp_en_out",				 /* 29   Host will send HNP enable request. */
+	"hpwr_out",				 /* 30   Host will enable high power (external charge pump.) */
+	NULL,
+
+};
+
+ /* eof */
+
+/* Generated by otg-meta-names-c.awk
+ *
+ * Do not Edit, see otg-state.awk
+ */
+
+
+
+char           *otg_meta_names[] = {
+	"a_idle",				 /*  0 -  */
+	"a_wait_vrise",				 /*  1 -  */
+	"a_wait_bcon",				 /*  2 -  */
+	"a_host",				 /*  3 -  */
+	"a_suspend",				 /*  4 -  */
+	"a_peripheral",				 /*  5 -  */
+	"a_wait_vfall",				 /*  6 -  */
+	"a_vbus_err",				 /*  7 -  */
+	"b_idle",				 /*  8 -  */
+	"b_srp_init",				 /*  9 -  */
+	"b_peripheral",				 /* 10 -  */
+	"b_suspend",				 /* 11 -  */
+	"b_wait_acon",				 /* 12 -  */
+	"b_host",				 /* 13 -  */
+	"b_suspended",				 /* 14 -  */
+	"ph_disc",				 /* 15 -  Equivalent to b_peripheral */
+	"ph_init",				 /* 16 -  */
+	"ph_uart",				 /* 17 -  */
+	"ph_aud",				 /* 18 -  */
+	"ph_wait",				 /* 19 -  */
+	"ph_exit",				 /* 20 -  */
+	"cr_init",				 /* 21 -  */
+	"cr_uart",				 /* 22 -  */
+	"cr_aud",				 /* 23 -  */
+	"cr_ack",				 /* 24 -  */
+	"cr_wait",				 /* 25 -  */
+	"cr_disc",				 /* 26 -  */
+	"otg_init",				 /* 27 -  */
+	"usb_accessory",			 /* 28 -  */
+	"usb_factory",				 /* 29 -  */
+	"unknown",				 /* 30 -  */
+
+	"",
+};
+
+/* eof */
diff -uNr linux/drivers/no-otg/otgcore/otg-mesg-l24.c linux/drivers/otg/otgcore/otg-mesg-l24.c
--- linux/drivers/no-otg/otgcore/otg-mesg-l24.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/otg-mesg-l24.c	2006-09-01 21:41:34.000000000 +0200
@@ -0,0 +1,399 @@
+/*
+ * otg/otgcore/otg-mesg-l24.c - OTG state machine Administration
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/otgcore/otg-mesg-l24.c
+ * @brief OTG Core Linux Message Interface.
+ *
+ * Implement linux char device via /proc/otg-mesg.
+ *
+ * @ingroup OTGCore
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-pcd.h>
+#include <otg/otg-ocd.h>
+
+#include <linux/poll.h>
+#include <linux/sched.h>
+
+        
+wait_queue_head_t otg_message_queue;
+
+/*!
+ * otg_message() - queue message data
+ * @param buf message to send.
+ */
+void otg_message (char *buf)
+{
+        char time_buf[64];
+        static u64 save_ticks;
+        u64 new_ticks;
+        u64 ticks;
+
+        new_ticks = otg_tmr_ticks();
+
+        otg_write_message(buf, strlen(buf));
+
+        ticks = otg_tmr_elapsed(&new_ticks, &save_ticks); 
+        save_ticks = new_ticks;
+
+        if (ticks < 10000)
+                sprintf(time_buf, " %d uS\n", ticks);
+        else if (ticks < 10000000)
+                //sprintf(time_buf, " %d mS\n", ticks / 1000);
+                sprintf(time_buf, " %d mS\n", ticks >> 10);
+        else 
+                //sprintf(time_buf, " %d S\n", ticks / 1000000);
+                sprintf(time_buf, " %d S\n", ticks >> 20);
+
+        otg_write_message(time_buf, strlen(time_buf));
+
+
+        //TRACE_MSG0(CORE, "wakeup ");
+        //printk(KERN_INFO"%s: wakeup\n", __FUNCTION__);
+        wake_up_interruptible(&otg_message_queue);
+}
+
+/*!
+ * otg_message_block() - implement block
+ */
+unsigned int otg_message_block(void)
+{
+        int count = otg_data_queued();
+        if (count) return count;
+        //TRACE_MSG0(CORE, "sleeping ");
+        //printk(KERN_INFO"%s: sleeping\n", __FUNCTION__);
+        interruptible_sleep_on(&otg_message_queue);
+        return otg_data_queued();
+}
+
+/*!
+ * otg_message_poll() - implement poll
+ * @param filp file pointer
+ * @param wait poll table structure
+ */
+unsigned int otg_message_poll(struct file *filp, struct poll_table_struct *wait)
+{
+        //TRACE_MSG0(CORE, "polling ");
+        poll_wait(filp, &otg_message_queue, wait);
+        return otg_data_queued() ? POLLIN | POLLRDNORM : 0;
+}
+
+/*! 
+ * otg_message_ioctl_internal() - ioctl call
+ * @param cmd ioctl command.
+ * @param arg ioctl arguement.
+ * @return non-zero for error.
+ */
+int otg_message_ioctl_internal(unsigned int cmd, unsigned long arg)
+{
+        int i;
+        int len;
+        int flag;
+        struct otg_admin_command admin_command;
+        struct otg_status_update status_update;
+        struct otg_firmware_info firmware_info;
+        struct otg_state otg_state;
+        struct otg_test otg_test;
+        struct otg_ioctl_name *otg_ioctl_name;
+        static char func_buf[32];
+        char *sp, *dp;
+	char *name;
+
+        switch (cmd) {
+
+        case OTGADMIN_GET_FUNCTION:
+                //TRACE_MSG0(CORE, "OTGADMIN_GET_FUNCTION");
+                RETURN_EINVAL_UNLESS(otg_firmware_loaded);
+                RETURN_EINVAL_IF(copy_from_user(&admin_command, (void *)arg, _IOC_SIZE(cmd)));
+		name = otg_usbd_ops->function_name(admin_command.n);
+                admin_command.string[0] = '\0';
+		if (name)
+			strncat(admin_command.string, name, sizeof(admin_command.string));
+
+                RETURN_EINVAL_IF(copy_to_user((void *)arg, &admin_command, _IOC_SIZE(cmd)));
+                return 0;
+
+        case OTGADMIN_SET_FUNCTION:
+                //TRACE_MSG0(CORE, "OTGADMIN_SET_FUNCTION");
+                RETURN_EINVAL_UNLESS(otg_firmware_loaded);
+                memset(&admin_command, 0x41, sizeof(struct otg_admin_command));
+                RETURN_EINVAL_IF(copy_from_user(&admin_command, (void *)arg, _IOC_SIZE(cmd)));
+                len = sizeof(mesg_otg_instance->function_name);
+                admin_command.string[len] = '\0';
+                //TRACE_MSG1(CORE, "Setting function: \"%s\"", mesg_otg_instance->function_name);
+                strncpy(mesg_otg_instance->function_name, admin_command.string, len);
+                mesg_otg_instance->function_name[len-1] = '\0';
+                return 0;
+
+        case OTGADMIN_GET_SERIAL:
+                //TRACE_MSG0(CORE, "OTGADMIN_GET_SERIAL");
+                RETURN_EINVAL_UNLESS(otg_firmware_loaded);
+                strncpy(admin_command.string, mesg_otg_instance->serial_number, sizeof(admin_command.string));
+                admin_command.string[sizeof(admin_command.string) - 1] = '\0';
+                RETURN_EINVAL_IF(copy_to_user((void *)arg, &admin_command, _IOC_SIZE(cmd)));
+                return 0;
+
+        case OTGADMIN_SET_SERIAL:
+                //TRACE_MSG0(CORE, "OTGADMIN_SET_SERIAL");
+                RETURN_EINVAL_UNLESS(otg_firmware_loaded);
+                RETURN_EINVAL_IF(copy_from_user(&admin_command, (void *)arg, _IOC_SIZE(cmd)));
+                admin_command.string[sizeof(admin_command.string) - 1] = '\0';
+                printk(KERN_INFO"%s: string: %s\n", __FUNCTION__, admin_command.string);
+                for (sp = admin_command.string, dp = mesg_otg_instance->serial_number, i = 0; 
+                                *sp && (i < (sizeof(admin_command.string) - 1)); i++, sp++)
+                        if (isxdigit(*sp)) *dp++ = toupper(*sp);
+                        
+                *sp = '\0';
+                //TRACE_MSG1(CORE, "serial_number: %s", mesg_otg_instance->serial_number);
+                printk(KERN_INFO"%s: serial: %s\n", __FUNCTION__, mesg_otg_instance->serial_number);
+                return 0;
+
+        case OTGADMIN_STATUS:
+                //TRACE_MSG0(CORE, "OTGADMIN_STATUS");
+                RETURN_EINVAL_UNLESS(otg_firmware_loaded);
+                memset(&status_update, 0, sizeof(struct otg_status_update));
+
+                otg_mesg_get_status_update(&status_update);
+
+                RETURN_EINVAL_IF(copy_to_user((void *)arg, &status_update, _IOC_SIZE(cmd)));
+                return 0;
+
+        case OTGADMIN_GET_INFO:
+                //TRACE_MSG0(CORE, "OTGADMIN_GET_INFO");
+                RETURN_EINVAL_UNLESS(otg_firmware_loaded);
+
+                otg_mesg_get_firmware_info(&firmware_info);
+
+                RETURN_EINVAL_IF(copy_to_user((void *)arg, &firmware_info, _IOC_SIZE(cmd)));
+                //TRACE_MSG0(CORE, "OTGADMIN_GET_INFO: finished");
+                return 0;
+
+        case OTGADMIN_SET_INFO:
+                //TRACE_MSG0(CORE, "OTGADMIN_SET_INFO");
+                memset(&firmware_info, 0x41, sizeof(firmware_info));
+                RETURN_EINVAL_IF(copy_from_user(&firmware_info, (void *)arg, _IOC_SIZE(cmd)));
+
+
+                return otg_mesg_set_firmware_info(&firmware_info);
+                return 0;
+
+        case OTGADMIN_GET_STATE:
+        case OTGADMIN_SET_STATE:
+                //TRACE_MSG0(CORE, "OTGADMIN_XXX_STATE");
+                RETURN_EINVAL_IF(copy_from_user(&otg_state, (void *)arg, _IOC_SIZE(cmd)));
+
+                switch (cmd) {
+                case OTGADMIN_GET_STATE:
+                        RETURN_EINVAL_UNLESS(otg_firmware_loaded);
+                        //TRACE_MSG0(CORE, "OTGADMIN_GET_STATE");
+                        RETURN_EINVAL_UNLESS (otg_state.state < otg_firmware_loaded->number_of_states);
+                        memcpy(&otg_state, otg_firmware_loaded->otg_states + otg_state.state, sizeof(otg_state));
+                        RETURN_EINVAL_IF(copy_to_user((void *)arg, &otg_state, _IOC_SIZE(cmd)));
+                        break;
+                case OTGADMIN_SET_STATE:
+                        RETURN_EINVAL_UNLESS(otg_firmware_loading);
+                        //TRACE_MSG0(CORE, "OTGADMIN_SET_STATE");
+                        RETURN_EINVAL_UNLESS (otg_state.state < otg_firmware_loading->number_of_states);
+                        memcpy(otg_firmware_loading->otg_states + otg_state.state, &otg_state, sizeof(otg_state));
+                        break;
+                }
+                return 0;
+
+
+        case OTGADMIN_GET_TEST:
+        case OTGADMIN_SET_TEST:
+                RETURN_EINVAL_IF(copy_from_user(&otg_test, (void *)arg, _IOC_SIZE(cmd)));
+
+                switch (cmd) {
+                case OTGADMIN_GET_TEST:
+                        RETURN_EINVAL_UNLESS(otg_firmware_loaded);
+                        //TRACE_MSG1(CORE, "OTGADMIN_GET_TEST: %d", otg_test.test);
+                        RETURN_EINVAL_UNLESS (otg_test.test < otg_firmware_loaded->number_of_tests);
+                        memcpy(&otg_test, otg_firmware_loaded->otg_tests + otg_test.test, sizeof(otg_test));
+                        RETURN_EINVAL_IF(copy_to_user((void *)arg, &otg_test, _IOC_SIZE(cmd)));
+                        break;
+                case OTGADMIN_SET_TEST:
+                        RETURN_EINVAL_UNLESS(otg_firmware_loading);
+                        //TRACE_MSG1(CORE, "OTGADMIN_SET_TEST : %d", otg_test.test);
+                        RETURN_EINVAL_UNLESS (otg_test.test < otg_firmware_loading->number_of_tests);
+                        memcpy(otg_firmware_loading->otg_tests + otg_test.test, &otg_test, sizeof(otg_test));
+                        break;
+                }
+                return 0;
+
+        default:
+                //TRACE_MSG0(CORE, "OTGADMIN_");
+                RETURN_EINVAL_UNLESS(otg_firmware_loaded);
+                for (otg_ioctl_name = otg_ioctl_names; otg_ioctl_name && otg_ioctl_name->cmd; otg_ioctl_name++) {
+                        //TRACE_MSG4(CORE, "lookup: %04x %04x %08x %08x", 
+                        //                _IOC_NR(cmd), _IOC_NR(otg_ioctl_name->cmd), cmd, otg_ioctl_name->cmd);
+                        BREAK_IF(_IOC_NR(otg_ioctl_name->cmd) == _IOC_NR(cmd));
+                }
+                //TRACE_MSG3(CORE, "checking %d %08x %08x", _IOC_NR(cmd), otg_ioctl_name->cmd, cmd);
+                RETURN_EINVAL_UNLESS(otg_ioctl_name->cmd);
+                __get_user(flag, (int *)arg);
+                //TRACE_MSG3(CORE, "%s %08x flag: %d", otg_ioctl_name->name, otg_ioctl_name->set, flag);
+                otg_event (mesg_otg_instance, flag ? otg_ioctl_name->set : _NOT(otg_ioctl_name->set), CORE, otg_ioctl_name->name);
+                return 0;
+        }
+        return 0;
+}
+
+
+
+/*! 
+ * otg_message_ioctl() - ioctl
+ * @param inode inode structure.
+ * @param filp file.
+ * @param cmd ioctl command.
+ * @param arg ioctl argument.
+ * @return non-zero for error.
+ */
+int otg_message_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+        int i;
+        int len;
+        int flag;
+        struct otg_admin_command admin_command;
+        struct otg_status_update status_update;
+        struct otg_firmware_info firmware_info;
+        struct otg_state otg_state;
+        struct otg_test otg_test;
+        //struct otg_ioctl_map *map = ioctl_map;
+        struct otg_ioctl_name *otg_ioctl_name;
+
+        static char func_buf[32];
+
+        //TRACE_MSG6(CORE, "cmd: %08x arg: %08x type: %02d nr: %02d dir: %02d size: %02d", 
+        //                cmd, arg, _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_DIR(cmd), _IOC_SIZE(cmd));
+        
+        RETURN_EINVAL_UNLESS (_IOC_TYPE(cmd) == OTGADMIN_MAGIC);
+        RETURN_EINVAL_UNLESS (_IOC_NR(cmd) <= OTGADMIN_MAXNR);
+
+        RETURN_EFAULT_IF((_IOC_DIR(cmd) == _IOC_READ) && !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)));
+        RETURN_EFAULT_IF((_IOC_DIR(cmd) == _IOC_WRITE) && !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)));
+
+        return otg_message_ioctl_internal(cmd, arg);
+}
+
+
+/*! 
+ * otg_message_proc_read() - implement proc file system read.
+ * Standard proc file system read function.
+ * @param file file.
+ * @param buf buffer to fill
+ * @param count size of buffer
+ * @param pos file position
+ * @return number of bytes or negative number for error
+ */
+static ssize_t otg_message_proc_read (struct file *file, char *buf, size_t count, loff_t * pos)
+{
+        unsigned long page;
+        int len = 0, avail;
+        char *bp,*ep;
+        struct list_head *lhd;
+        int state;
+
+        // get a page, max 4095 bytes of data...
+        RETURN_ENOMEM_UNLESS ((page = GET_KERNEL_PAGE()));
+
+        bp = (char *) page;
+
+        len = bp - (char *) page;
+
+        if (( avail = otg_message_block())) {
+
+                len += otg_read_message(bp, 4095);
+
+                if (len > count)
+                        len = -EINVAL;
+                else if ((len > 0) && copy_to_user (buf, (char *) page, len))
+                        len = -EFAULT;
+
+        }
+
+        free_page (page);
+        return len;
+}
+
+/*! otg_message_proc_ioctl() -
+ * @param inode inode structure.
+ * @param filp file.
+ * @param cmd ioctl command.
+ * @param arg ioctl argument.
+ * @return non-zero for error.
+ */
+int otg_message_proc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+        return otg_message_ioctl(inode, filp, cmd, arg);
+}
+
+/*!
+ * @param filp file.
+ * @param wait buffer to fill
+ * @return number of bytes or negative number for error
+ */
+unsigned int otg_message_proc_poll(struct file *filp, struct poll_table_struct *wait)
+{
+        return otg_message_poll(filp, wait);
+}
+
+/*!
+ * @var otg_message_proc_switch_functions
+ */
+static struct file_operations otg_message_proc_switch_functions = {
+        ioctl:otg_message_proc_ioctl,
+        poll:otg_message_proc_poll,
+        read:otg_message_proc_read,
+};
+
+
+/*!
+ * otg_message_init_l24() - initialize
+ */
+int otg_message_init_l24(struct otg_instance *otg)
+{
+        struct proc_dir_entry *message = NULL;
+        init_waitqueue_head(&otg_message_queue);
+
+        THROW_IF (!(message = create_proc_entry ("otg_message", 0666, 0)), error);
+        message->proc_fops = &otg_message_proc_switch_functions;
+        CATCH(error) {
+                printk(KERN_ERR"%s: creating /proc/otg_message failed\n", __FUNCTION__);
+                if (message)
+                        remove_proc_entry("otg_message", NULL);
+                return -EINVAL;
+        }
+        return 0;
+}
+
+/*!
+ * otg_message_exit_l24() - exit
+ */
+void otg_message_exit_l24(void)
+{
+        remove_proc_entry("otg_message", NULL);
+}
+
+EXPORT_SYMBOL(otg_message);
+
+
diff -uNr linux/drivers/no-otg/otgcore/otg-mesg.c linux/drivers/otg/otgcore/otg-mesg.c
--- linux/drivers/no-otg/otgcore/otg-mesg.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/otg-mesg.c	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,369 @@
+/*
+ * otg/otgcore/otg-mesg.c - OTG state machine Administration
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/otgcore/otg-mesg.c
+ * @brief OTG Core Message Facility.
+ *
+ * The OTG Core Message Facility has two functions:
+ *
+ *      1. implement a message queue for messages from the otg state machine to the otg
+ *         management application
+ *
+ *      2. implement an ioctl control mechanism allowing the otg managment application 
+ *         to pass data and commands to the otg state machine
+ *
+ * @ingroup OTGCore
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-pcd.h>
+#include <otg/otg-ocd.h>
+
+#if defined(OTG_LINUX)
+#include <linux/poll.h>
+#include <linux/sched.h>
+#endif /* defined(OTG_LINUX) */
+
+//#define OTG_MESSAGE_BUF_SIZE    512
+#define OTG_MESSAGE_BUF_SIZE    2048
+
+struct otg_instance * mesg_otg_instance;
+
+char *otg_message_buf;          // buffer
+char *otg_message_head;         // next available empty space
+char *otg_message_tail;         // next available data if not equal to head
+
+/*! 
+ * otg_data_avail() - amount of data in buffer
+ *                                      space                   data
+ *           tp     hp                   20 - (10 - 5) = 15      (10 - 5)
+ *     0......5.data.10......20
+ *
+ *          hp     tp                   (10 - 5) = 5            20 - (10 - 5)
+ *     0.data.5......10.data.20
+ *
+ * @return Bytes available in message ring buffer.
+ */
+int otg_data_avail(void)
+{
+        int avail = (otg_message_head >= otg_message_tail) ? 
+                (otg_message_head - otg_message_tail) :
+                OTG_MESSAGE_BUF_SIZE - (otg_message_tail - otg_message_head) ;
+
+        //TRACE_MSG4(CORE, "buf: %p head: %p tail: %p  data avail: %d", otg_message_buf, otg_message_head, otg_message_tail, avail);
+        return avail;
+}
+
+/*! 
+ * otg_space_avail() - amount of space in buffer
+ *
+ * @return Space available in message ring buffer.
+ */
+int otg_space_avail(void)
+{
+        int avail = (otg_message_head >= otg_message_tail) ? 
+                OTG_MESSAGE_BUF_SIZE - (otg_message_head - otg_message_tail) :
+                (otg_message_tail - otg_message_head) ;
+
+        //TRACE_MSG4(CORE, "buf: %p head: %p tail: %p space avail: %d", otg_message_buf, otg_message_head, otg_message_tail, avail);
+        return avail;
+}
+
+/*! 
+ * otg_get_byte() - return next byte
+ *
+ * @return Next byte in message ring buffer
+ */
+char otg_get_byte(void)
+{
+        char c = *otg_message_tail;
+
+        //TRACE_MSG3(CORE, "buf: %p head: %p tail: %p", otg_message_buf, otg_message_head, otg_message_tail);
+        if ((otg_message_tail - otg_message_buf) == OTG_MESSAGE_BUF_SIZE)
+                otg_message_tail = otg_message_buf;
+        else
+                otg_message_tail++;
+
+        return c;
+}
+
+/*!
+ * otg_put_byte() - put byte into buffer
+ *
+ * Put byte into message ring buffer
+ *
+ * @param byte put into message ring.
+ */
+void otg_put_byte(char byte)
+{
+        *otg_message_head = byte;
+        if ((otg_message_head - otg_message_buf) == OTG_MESSAGE_BUF_SIZE)
+                otg_message_head = otg_message_buf;
+        else
+                otg_message_head++;
+
+}
+
+/*! 
+ * otg_write_message_irq() - queue message data (interrupt version)
+ *
+ * Attempt to write message data into ring buffer, return amount
+ * of data actually written.
+ *
+ * @param buf - pointer to data
+ * @param size - amount of available data
+ * @return number of bytes that where not written.
+ */
+int otg_write_message_irq (char *buf, int size)
+{
+        struct pcd_instance *pcd = NULL;
+        struct usbd_bus_instance *bus = NULL;
+
+        pcd = (struct pcd_instance *)mesg_otg_instance->pcd;
+        if (pcd)
+                bus = pcd->bus;
+
+        if (size >= (OTG_MESSAGE_BUF_SIZE - 2))
+                return size;
+
+        while (otg_space_avail() < (size + 1))
+                otg_get_byte();
+
+
+        /* copy, note that we don't have to test for space as we have
+         * already ensured that there is enough room for all of the data
+         */
+        while (size--) 
+                otg_put_byte(*buf++);
+
+        //otg_put_byte('\n');
+
+        return size;
+}
+
+/*! 
+ * otg_write_message() - queue message data
+ *
+ * Attempt to write message data into ring buffer, return amount
+ * of data actually written.
+ *
+ * @param buf - pointer to data
+ * @param size - amount of available data
+ * @return number of bytes that where not written.
+ */
+int otg_write_message (char *buf, int size)
+{
+	int rc;
+        unsigned long flags;
+        local_irq_save (flags);
+	rc = otg_write_message_irq(buf, size);
+        local_irq_restore (flags);
+        return size;
+}
+
+/*!
+ * otg_read_message() - get queued message data
+ *
+ * @param buf - pointer to data
+ * @param size - amount of available data
+ * @return the number of bytes read.
+ */
+int otg_read_message(char *buf, int size)
+{
+        int count = 0;
+        unsigned long flags;
+	
+        local_irq_save (flags);
+
+        /* Copy bytes to the buffer while there is data available and space
+         * to put it in the buffer
+         */
+        for ( ; otg_data_avail() && size--; count++)
+                BREAK_IF((*buf++ = otg_get_byte()) == '\n');
+
+        local_irq_restore (flags);
+        return count;
+}
+
+/*!
+ * otg_data_queued() - return amount of data currently queued
+ *
+ * @return Amount of data currently queued in mesage ring buffer.
+ */
+int otg_data_queued(void)
+{
+        int count;
+        unsigned long flags;
+        local_irq_save (flags);
+        count = otg_data_avail();
+        local_irq_restore (flags);
+        //printk(KERN_INFO"%s: count: %d\n", __FUNCTION__, count);
+        return count;
+}
+
+
+/*!
+ * otg_message_init() - initialize
+ * @param otg OTG instance
+ */
+int otg_message_init(struct otg_instance *otg)
+{
+        struct proc_dir_entry *message = NULL;
+        otg_message_buf = otg_message_head = otg_message_tail = NULL;
+        THROW_UNLESS((otg_message_buf = CKMALLOC(OTG_MESSAGE_BUF_SIZE + 16, GFP_KERNEL)), error);
+        otg_message_head = otg_message_tail = otg_message_buf ;
+
+        mesg_otg_instance = otg;
+        CATCH(error) {
+                #if defined(OTG_LINUX)
+                printk(KERN_ERR"%s: creating /proc/otg_message failed\n", __FUNCTION__);
+                #endif /* defined(OTG_LINUX) */
+                #if defined(OTG_WINCE)
+                DEBUGMSG(ZONE_INIT, (_T("otg_message_init: creating //proc//otg_message failed\n")) );
+                #endif /* defined(OTG_LINUX) */
+                return -EINVAL;
+        }
+        return 0;
+}
+
+/*!
+ * otg_message_exit() - exit
+ */
+void otg_message_exit(void)
+{
+        mesg_otg_instance = NULL;
+        if (otg_message_buf)
+                LKFREE(otg_message_buf);
+        otg_message_buf = otg_message_head = otg_message_tail = NULL;
+}
+
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+
+/*!
+ * otg_mesg_get_status_update() - get status update
+ * @param status_update
+ */
+void otg_mesg_get_status_update(struct otg_status_update *status_update)
+{
+
+        TRACE_MSG0(CORE, "--");
+        status_update->state = mesg_otg_instance->state;
+        status_update->meta = mesg_otg_instance->current_outputs->meta;
+        status_update->inputs = mesg_otg_instance->current_inputs;
+        status_update->outputs = mesg_otg_instance->outputs;
+        status_update->capabilities = otg_ocd_ops ? otg_ocd_ops->capabilities : 0;
+
+        strncpy(status_update->fw_name, otg_firmware_loaded->fw_name, OTGADMIN_MAXSTR);
+        strncpy(status_update->state_name, otg_get_state_name(mesg_otg_instance->state), OTGADMIN_MAXSTR);
+
+        if (mesg_otg_instance->function_name)
+                strncpy(status_update->function_name, mesg_otg_instance->function_name, OTGADMIN_MAXSTR);
+
+        TRACE_MSG5(CORE, "state: %02x meta: %02x inputs: %08x outputs: %04x", 
+                        status_update->state, status_update->meta, status_update->inputs, 
+                        status_update->outputs, status_update->capabilities);
+}
+
+
+/*!
+ * otg_mesg_get_firmware_info() - get firmware info
+ * @param firmware_info
+ */
+void otg_mesg_get_firmware_info(struct otg_firmware_info *firmware_info)
+{
+        memset(firmware_info, 0, sizeof(firmware_info));
+        // XXX irq lock
+
+        firmware_info->number_of_states = otg_firmware_loaded->number_of_states;
+        firmware_info->number_of_tests = otg_firmware_loaded->number_of_tests;
+        memcpy(&firmware_info->fw_name, otg_firmware_loaded->fw_name, sizeof(firmware_info->fw_name));
+
+}
+
+/*! 
+ * otg_mesg_set_firmware_info() - set firmware info
+ * @param firmware_info
+ */
+int otg_mesg_set_firmware_info(struct otg_firmware_info *firmware_info)
+{
+
+        if (otg_firmware_loading) {
+
+                if ( (otg_firmware_loading->number_of_states == firmware_info->number_of_states) &&
+                                (otg_firmware_loading->number_of_tests == firmware_info->number_of_tests) 
+                   ) {
+                        TRACE_MSG0(CORE, "OTGADMIN_SET_INFO: loaded");
+                        otg_firmware_loaded = otg_firmware_loading;
+                        otg_firmware_loading = NULL;
+                        return 0;
+                }
+                else {
+                        TRACE_MSG0(CORE, "OTGADMIN_SET_INFO: abandoned");
+                        LKFREE(otg_firmware_loading->otg_states);
+                        LKFREE(otg_firmware_loading->otg_tests);
+                        LKFREE(otg_firmware_loading);
+                        return -EINVAL;
+                }
+        }
+
+        TRACE_MSG2(CORE, "OTGADMIN_SET_INFO: otg_firmware_loaded: %x otg_firmware_orig: %x", 
+                        otg_firmware_loaded, otg_firmware_orig);
+        if (otg_firmware_loaded && (otg_firmware_loaded != otg_firmware_orig)) {
+                LKFREE(otg_firmware_loaded->otg_states);
+                LKFREE(otg_firmware_loaded->otg_tests);
+                LKFREE(otg_firmware_loaded);
+                otg_firmware_loaded = otg_firmware_orig;
+                TRACE_MSG0(CORE, "OTGADMIN_SET_INFO: unloaded");
+        }
+        if (firmware_info->number_of_states && firmware_info->number_of_tests) {
+                int size;
+                otg_firmware_loaded = NULL;
+                TRACE_MSG0(CORE, "OTGADMIN_SET_INFO: setup");
+                THROW_UNLESS((otg_firmware_loading = CKMALLOC(sizeof(struct otg_firmware), GFP_KERNEL)), error);
+                size = sizeof(struct otg_state) * firmware_info->number_of_states;
+                THROW_UNLESS((otg_firmware_loading->otg_states = CKMALLOC(size, GFP_KERNEL)), error);
+                size = sizeof(struct otg_test) * firmware_info->number_of_tests;
+                THROW_UNLESS((otg_firmware_loading->otg_tests = CKMALLOC(size, GFP_KERNEL)), error);
+
+                otg_firmware_loading->number_of_states = firmware_info->number_of_states;
+                otg_firmware_loading->number_of_tests = firmware_info->number_of_tests;
+                memcpy(otg_firmware_loading->fw_name, &firmware_info->fw_name, sizeof(firmware_info->fw_name));
+
+                CATCH(error) {
+                        TRACE_MSG0(CORE, "OTGADMIN_SET_INFO: setup error");
+                        if (otg_firmware_loading) {
+                                if (otg_firmware_loading->otg_states) LKFREE(otg_firmware_loading->otg_states);
+                                if (otg_firmware_loading->otg_tests) LKFREE(otg_firmware_loading->otg_tests);
+                                LKFREE(otg_firmware_loading);
+                                return -EINVAL;
+                        }
+                }
+
+        }
+        return 0;
+}
+
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+
diff -uNr linux/drivers/no-otg/otgcore/otg-trace-l24.c linux/drivers/otg/otgcore/otg-trace-l24.c
--- linux/drivers/no-otg/otgcore/otg-trace-l24.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/otg-trace-l24.c	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,174 @@
+/*
+ * otg/otgcore/otg-trace-l24.c
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *
+ */
+/*!
+ * @file otg/otgcore/otg-trace-l24.c
+ * @brief OTG Core Linux Debug Trace Facility
+ *
+ * This allows access to the OTG Core Trace via /proc/trace_otg. Each time
+ * this file is opened and read it will contain a snapshot of the most
+ * recent trace messages. 
+ *
+ * Reading the trace resets it, the next read will open a new snapshot.
+ *
+ * N.B. There is no protection from multiple reads.
+ *
+ * N.B. This is for debugging and is not normally enabled for production software.
+ *
+ * @ingroup OTGCore
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+#include <linux/vmalloc.h>
+#include <stdarg.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+
+#if defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE)
+
+DECLARE_MUTEX(otg_trace_sem_l24);
+
+
+/* *    
+ * otg_trace_proc_read_l24 - implement proc file system read.
+ * @file        
+ * @buf         
+ * @count
+ * @pos 
+ *      
+ * Standard proc file system read function.
+ */         
+static ssize_t otg_trace_proc_read_l24 (struct file *file, char *buf, size_t count, loff_t * pos)
+{                                  
+        unsigned long page;
+        int len = 0;
+        int index;
+        int oindex;
+        int rc;
+
+        u64 ticks = 0;
+
+        unsigned char *cp;
+        int skip = 0;
+
+        otg_trace_t px;
+        otg_trace_t ox;
+        otg_trace_t vx;
+        otg_trace_t *o, *p;
+
+        RETURN_ENOMEM_IF (!(page = GET_KERNEL_PAGE()));
+
+        _MOD_INC_USE_COUNT;
+
+        // Lock out tag changes while reading
+        DOWN(&otg_trace_sem_l24);
+        len = otg_trace_proc_read((char *)page, count, (int *)pos);
+
+        if (len > count) 
+                len = -EINVAL;
+        
+        else if (len > 0 && copy_to_user (buf, (char *) page, len)) 
+                len = -EFAULT;
+        
+        free_page (page);
+
+        UP(&otg_trace_sem_l24);
+        free_page (page);
+        _MOD_DEC_USE_COUNT;
+        return len;
+}
+
+#define MAX_TRACE_CMD_LEN  64
+/* *
+ * otg_trace_proc_write_l24 - implement proc file system write.
+ * @file
+ * @buf
+ * @count
+ * @pos
+ *
+ * Proc file system write function.
+ */
+static ssize_t otg_trace_proc_write_l24 (struct file *file, const char *buf, size_t count, loff_t * pos)
+{
+        char command[MAX_TRACE_CMD_LEN+1];
+        size_t l = MIN(count, MAX_TRACE_CMD_LEN);
+
+        RETURN_ZERO_UNLESS(count);
+        RETURN_EINVAL_IF (copy_from_user (command, buf, l));
+
+
+        RETURN_EINVAL_IF(copy_from_user (command, buf, l));
+
+        return otg_trace_proc_write(command, l, (int *)pos);
+#if 0
+        else {
+                n -= l;
+                while (n > 0) {
+                        if (copy_from_user (&c, buf + (count - n), 1)) {
+                                count = -EFAULT;
+                                break;
+                        }
+                        n -= 1;
+                }
+                // Terminate command[]
+                if (l > 0 && command[l-1] == '\n') {
+                        l -= 1;
+                }
+                command[l] = 0;
+        }
+#endif
+}
+
+/* Module init ************************************************************** */
+
+
+
+static struct file_operations otg_trace_proc_operations_functions = {
+        read: otg_trace_proc_read_l24,
+        write: otg_trace_proc_write_l24,
+};
+
+/*! otg_trace_init_l24
+ *
+ * Return non-zero if not successful.
+ */
+int otg_trace_init_l24 (void)
+{
+        struct proc_dir_entry *p;
+
+        // create proc filesystem entries
+        if ((p = create_proc_entry ("trace_otg", 0, 0)) == NULL) 
+                printk(KERN_INFO"%s PROC FS failed\n", "trace_otg");
+        else 
+                p->proc_fops = &otg_trace_proc_operations_functions;
+
+        return 0;
+}
+
+/*! otg_trace_exit_l24 - remove procfs entry, free trace data space.
+ */
+void otg_trace_exit_l24 (void)
+{
+        otg_trace_t *p;
+        unsigned long flags;
+        remove_proc_entry ("trace_otg", NULL);
+}
+
+#else /* defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE) */
+int otg_trace_init_l24 (void) {return 0;}
+void otg_trace_exit_l24 (void) {}
+#endif /* defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE) */
+
diff -uNr linux/drivers/no-otg/otgcore/otg-trace.c linux/drivers/otg/otgcore/otg-trace.c
--- linux/drivers/no-otg/otgcore/otg-trace.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/otg-trace.c	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,615 @@
+/*
+ * otg/otgcore/otg-trace.c
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *
+ */
+/*!
+ * @file otg/otgcore/otg-trace.c
+ * @brief OTG Core Debug Trace Facility
+ *
+ * This implements the OTG Core Trace Facility. 
+ *
+ * @ingroup OTGCore
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#if defined(OTG_LINUX)
+#include <linux/vmalloc.h>
+#include <stdarg.h>
+#endif /* defined(OTG_LINUX) */
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+
+#define STATIC static
+
+#if defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE)
+
+DECLARE_MUTEX(otg_trace_sem);
+
+static int otg_trace_exiting;
+
+#define OTG_TRACE_NAME "trace_otg"
+
+typedef struct otg_trace_snapshot {
+        int first;
+        int next;
+        int total;
+        otg_trace_t *traces;
+} otg_trace_snapshot;
+
+otg_trace_snapshot otg_snapshot1;
+otg_trace_snapshot otg_snapshot2;
+
+static otg_trace_snapshot *otg_trace_current_traces;
+static otg_trace_snapshot *otg_trace_other_traces;
+
+STATIC otg_trace_snapshot *rel_snapshot(otg_trace_snapshot *tss)
+{
+        RETURN_NULL_UNLESS(tss);
+        if (tss->traces) {
+                vfree(tss->traces);
+                tss->traces = NULL;
+        }
+        //vfree(tss);
+        return NULL;
+}
+
+STATIC void init_snapshot(otg_trace_snapshot *tss)
+{
+        tss->first = tss->next = tss->total = 0;
+        memset(tss->traces,0,sizeof(otg_trace_t) * TRACE_MAX);
+}
+
+STATIC otg_trace_snapshot *get_snapshot(otg_trace_snapshot *tss)
+{
+        //otg_trace_snapshot *tss;
+        unsigned long flags;
+        //UNLESS ((tss = vmalloc(sizeof(otg_trace_snapshot)))) {
+        //        printk(KERN_ERR "Cannot allocate memory for OTG trace snapshot.\n");
+        //        return NULL;
+        //}
+        
+        UNLESS ((tss->traces = vmalloc(sizeof(otg_trace_t) * TRACE_MAX))) {
+                printk(KERN_ERR "Cannot allocate memory for OTG trace log.\n");
+                return rel_snapshot(tss);
+        }
+        init_snapshot(tss);
+        return tss;
+}
+
+/*! otg_trace_get_next
+ */
+STATIC otg_trace_t *otg_trace_get_next(otg_trace_snapshot *tss, otg_tag_t tag, const char *fn, otg_trace_types_t otg_trace_type, int n)
+{
+        otg_trace_t *p;
+
+        // Get the next (n) trace slots.
+
+        p = tss->traces + tss->next;
+        
+        while (n-- > 0) {
+                tss->next = (tss->next + 1) & TRACE_MASK;
+                if (tss->next == tss->first) {
+                        // We have wraparound, bump tss->first
+                        tss->first = (tss->first + 1) & TRACE_MASK;
+                }
+                tss->total++;
+        }
+        // End of next trace slot.
+        
+        otg_get_trace_info(p);
+        p->otg_trace_type = otg_trace_type;
+        p->tag = tag;
+        p->va.s.function = fn;
+
+        return p;
+}
+
+/* otg_trace_next_va
+ */
+STATIC otg_trace_t *otg_trace_next_va(otg_trace_snapshot *tss, otg_trace_t *p)
+{
+        /* Return the next trace slot in a va group.
+           No need to be atomic, just worry about wraparound. */
+        int nxt = (p - tss->traces);
+        nxt = (nxt + 1) & TRACE_MASK;
+        p = tss->traces + nxt;
+        return(p);
+}
+
+/* otg_trace_setup
+ */
+void otg_trace_setup(otg_tag_t tag, const char *fn, void *setup)
+{
+        otg_trace_t *p;
+        otg_trace_snapshot *tss;
+        unsigned long flags;
+        local_irq_save(flags);
+        UNLESS ((tss = otg_trace_current_traces)) {
+                local_irq_restore(flags);
+                return;
+        }
+        // Reserve the trace slots.
+        UNLESS ((p = otg_trace_get_next(tss,tag,fn,otg_trace_setup_n,1))) {
+                local_irq_restore(flags);
+                return;
+        }
+        p->va_num_args = 0;
+        memcpy(&p->va.s.trace.setup, setup, sizeof(p->va.s.trace.setup) /*sizeof(struct usbd_device_request)*/);
+        local_irq_restore(flags);
+}
+
+/* otg_trace_msg
+ */
+void otg_trace_msg(otg_tag_t tag, const char *fn, u8 nargs, char *fmt, ...)
+{
+        int n;
+        otg_trace_t *p;
+        otg_trace_snapshot *tss;
+        unsigned long flags;
+
+        // Figure out how many trace slots we're going to need.
+        n = 1;
+        if (nargs > 1) {
+                n = 2;
+                // Too many arguments, bail.
+                RETURN_IF (nargs > (OTG_TRACE_MAX_IN_VA+1));
+        }
+
+        local_irq_save(flags);
+        UNLESS ((tss = otg_trace_current_traces)) {
+                local_irq_restore(flags);
+                return;
+        }
+        // Reserve the trace slots.
+        UNLESS((p = otg_trace_get_next(tss,tag,fn,otg_trace_msg_va_start_n,n))) {
+                local_irq_restore(flags);
+                return;
+        }
+        p->va.s.trace.msg32.msg = fmt;
+        p->va_num_args = nargs;
+        if (nargs > 0) {
+                va_list ap;
+                va_start(ap,fmt);
+                p->va.s.trace.msg32.val = va_arg(ap,u32);
+                if (--nargs > 0) {
+                        // We need the next trace slot.
+                        int i;
+                        while (nargs >= 8) {
+                                p = otg_trace_next_va(tss,p);
+                                p->otg_trace_type = otg_trace_msg_va_list_n;
+                                for (i = 0; i < 8; i++) p->va.l.val[i] = va_arg(ap,u32);
+                                nargs -= 8;
+                        }
+                        p = otg_trace_next_va(tss,p);
+                        p->otg_trace_type = otg_trace_msg_va_list_n;
+                        for (i = 0; i < nargs; i++) p->va.l.val[i] = va_arg(ap,u32);
+                }
+                va_end(ap);
+        }
+        local_irq_restore(flags);
+}
+
+/* Proc Filesystem *************************************************************************** */
+
+/* int slot_in_data
+ */
+STATIC int slot_in_data(otg_trace_snapshot *tss, int slot)
+{
+        // Return 1 if slot is in the valid data region, 0 otherwise.
+        return (((tss->first < tss->next) && (slot >= tss->first) && (slot < tss->next)) ||
+                ((tss->first > tss->next) && ((slot < tss->next) || (slot >= tss->first))));
+
+}
+
+/*! otg_trace_read_slot
+ *
+ * Place a slot pointer in *ps (and possibly *pv), with the older entry (if any) in *po.
+ * Return: -1 at end of data
+ *          0 if not a valid enty
+ *          1 if entry valid but no older valid entry
+ *          2 if both entry and older are valid.
+ */
+STATIC int otg_trace_read_slot(otg_trace_snapshot *tss, int index, otg_trace_t **ps, otg_trace_t **po)
+{
+        int res;
+        int previous;
+        otg_trace_t *s,*o;
+
+        *ps = *po = NULL;
+        index = (tss->first + index) & TRACE_MASK;
+        // Are we at the end of the data?
+        if (!slot_in_data(tss,index)) {
+                // End of data.
+                return(-1);
+        }
+        /* Nope, there's data to show. */
+        s = tss->traces + index;
+        if (!s->tag ||
+            s->otg_trace_type == otg_trace_msg_invalid_n ||
+            s->otg_trace_type == otg_trace_msg_va_list_n) {
+                /* Ignore this slot, it's not valid, or is part
+                   of a previously processed varargs. */
+                return(0);
+        }
+        *ps = s;
+        res = 1;
+        // Is there a previous event (for "ticks" calculation)?
+        previous = (index - 1) & TRACE_MASK;
+        if (previous != tss->next && tss->total > 1) {
+                // There is a valid previous event.
+                res = 2;
+                o = tss->traces + previous;
+                /* If the previous event was a varargs event, we want
+                   a copy of the first slot, not the last. */
+                while (o->otg_trace_type == otg_trace_msg_va_list_n) {
+                        previous = (previous - 1) & TRACE_MASK;
+                        if (previous == tss->next) {
+                                res = 1;
+                                o = NULL;
+                                break;
+                        }
+                        o = tss->traces + previous;
+                }
+                *po = o;
+        }
+        return(res);
+}
+
+
+/*! otg_trace_proc_read - implement proc file system read.
+ *      
+ * Standard proc file system read function.
+ * @file        
+ * @buf         
+ * @count
+ * @pos 
+ */         
+int otg_trace_proc_read(char *page, int count, int * pos)
+{                                  
+        int len = 0;
+        int index;
+        int oindex;
+        int rc;
+
+        u64 ticks = 0;
+
+        unsigned char *cp;
+        int skip = 0;
+
+        otg_trace_t *o;
+        otg_trace_t *s;
+        otg_trace_snapshot *tss;
+
+        DOWN(&otg_trace_sem);
+
+        /* Grab the current snapshot, and replace it with the other.  This
+         * needs to be atomic WRT otg_trace_msg() calls.
+         */
+        UNLESS (*pos) {
+                unsigned long flags;
+                tss = otg_trace_other_traces;
+                init_snapshot(tss);                                     // clear previous
+                local_irq_save(flags);
+                otg_trace_other_traces = otg_trace_current_traces;      // swap snapshots
+                otg_trace_current_traces = tss;
+                local_irq_restore(flags);
+        } 
+
+        tss = otg_trace_other_traces;
+
+        /* Get the index of the entry to read - this needs to be atomic WRT tag operations. 
+         */
+        s = o = NULL;
+        oindex = index = (*pos)++;
+        do {
+                rc = otg_trace_read_slot(tss,index,&s,&o);
+                switch (rc) {
+                case -1: // End of data.
+                        UP(&otg_trace_sem);
+                        return(0);
+
+                case 0: // Invalid slot, skip it and try the next.
+                        index = (*pos)++;
+                        break;
+
+                case 1: // s valid, o NULL
+                case 2: // s and o valid
+                        break;
+                }
+        } while (rc == 0);
+
+        len = 0;
+
+        UNLESS (oindex) 
+                len += sprintf((char *) page + len, "Tag  Index     Ints Framenum   Ticks\n");
+
+        /* If there is a previous trace event, we want to calculate how many
+         * ticks have elapsed siince it happened.  Unfortunately, determining
+         * if there _is_ a previous event isn't obvious, since we have to watch
+         * out for startup, varargs and wraparound. 
+         */
+        if (o) {
+        
+                ticks = otg_tmr_elapsed(&s->va.s.ticks, &o->va.s.ticks);
+
+                if ((o->va.s.interrupts != s->va.s.interrupts) || (o->tag != s->tag) || (o->in_interrupt != s->in_interrupt)) 
+                        skip++;
+        }
+
+        len += sprintf((char *) page + len, "%s%02x %c %8u %8d ", skip?"\n":"", 
+                        s->tag, s->id_gnd ? 'A' : 'B', index, s->va.s.interrupts);
+
+        len += sprintf((char *) page + len, "%03x  ", s->va.s.framenum);
+
+        if (ticks < 10000)
+                len += sprintf((char *) page + len, "%8duS", ticks);
+        else if (ticks < 10000000)
+                len += sprintf((char *) page + len, "%8dmS", ticks >> 10);
+        else 
+                len += sprintf((char *) page + len, "%8dS ", ticks >> 20);
+
+        len += sprintf((char *) page + len, " %s ", s->in_interrupt ? "--" : "==");
+        len += sprintf((char *) page + len, "%-24s: ",s->va.s.function);
+
+        switch (s->otg_trace_type) {
+        case otg_trace_msg_invalid_n:
+        case otg_trace_msg_va_list_n:
+                len += sprintf((char *) page + len, " --          N/A");
+                break;
+
+        case otg_trace_msg_va_start_n:
+                if (s->va_num_args <= 1) 
+                        len += sprintf((char *) page + len, s->va.s.trace.msg32.msg, s->va.s.trace.msg32.val);
+                
+                else {
+                        otg_trace_t *v = otg_trace_next_va(tss,s);
+                        len += sprintf((char *) page + len, s->va.s.trace.msg32.msg, s->va.s.trace.msg32.val,
+                                       v->va.l.val[0], v->va.l.val[1], v->va.l.val[2], v->va.l.val[3],
+                                       v->va.l.val[4], v->va.l.val[5], v->va.l.val[6]);
+                }
+                break;
+
+        case otg_trace_msg_n:
+                len += sprintf((char *) page + len, s->va.s.trace.msg.msg);
+                break;
+
+        case otg_trace_msg32_n:
+                len += sprintf((char *) page + len, s->va.s.trace.msg32.msg, s->va.s.trace.msg32.val);
+                break;
+
+        case otg_trace_msg16_n:
+                len += sprintf((char *) page + len, s->va.s.trace.msg16.msg, s->va.s.trace.msg16.val0, s->va.s.trace.msg16.val1);
+                break;
+
+        case otg_trace_msg8_n:
+                len += sprintf((char *) page + len, s->va.s.trace.msg8.msg, 
+                               s->va.s.trace.msg8.val0, s->va.s.trace.msg8.val1, s->va.s.trace.msg8.val2, 
+                               s->va.s.trace.msg8.val3);
+                break;
+
+        case otg_trace_setup_n:
+                cp = (unsigned char *)&s->va.s.trace.setup;
+                len += sprintf((char *) page + len, 
+                               " --      request [%02x %02x %02x %02x %02x %02x %02x %02x]", 
+                               cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+                break;
+        }
+        len += sprintf((char *) page + len, "\n");
+
+        UP(&otg_trace_sem);
+        return len;
+}
+
+/*! otg_trace_proc_write - implement proc file system write.
+ * @file
+ * @buf
+ * @count
+ * @pos
+ *
+ * Proc file system write function.
+ */
+int otg_trace_proc_write (const char *buf, int count, int * pos)
+{
+#define MAX_TRACE_CMD_LEN  64
+        char command[MAX_TRACE_CMD_LEN+1];
+        size_t n = count;
+        size_t l;
+        char c;
+
+        if (n > 0) {
+                l = MIN(n,MAX_TRACE_CMD_LEN);
+                if (copy_from_user (command, buf, l)) 
+                        count = -EFAULT;
+                else {
+                        n -= l;
+                        while (n > 0) {
+                                if (copy_from_user (&c, buf + (count - n), 1)) {
+                                        count = -EFAULT;
+                                        break;
+                                }
+                                n -= 1;
+                        }
+                        // Terminate command[]
+                        if (l > 0 && command[l-1] == '\n') {
+                                l -= 1;
+                        }
+                        command[l] = 0;
+                }
+        }
+
+        if (0 >= count) {
+                printk(KERN_INFO"%s: count <= 0 %d\n", __FUNCTION__, count);
+                return count;
+        }
+
+
+        return count;
+}
+
+static u32 otg_tags_mask = 0x0;
+extern void otg_trace_exit (void);
+
+/*! otg_trace_obtain_tag(void)
+ */
+otg_tag_t otg_trace_obtain_tag(void)
+{
+        /* Return the next unused tag value [1..32] if one is available,
+         * return 0 if none is available. 
+         */
+        otg_tag_t tag = 0;
+        DOWN(&otg_trace_sem);
+        if (otg_tags_mask == 0xffffffff || otg_trace_exiting) {
+                // They're all in use.
+                UP(&otg_trace_sem);
+                return tag;
+        }
+        if (otg_tags_mask != 0x00000000) {
+                // 2nd or later tag, search for an unused one
+                while (otg_tags_mask & (0x1 << tag)) {
+                        tag += 1;
+                }
+        } 
+        
+        // Successful 1st or later tag.
+        otg_tags_mask |= 0x1 << tag;
+        UP(&otg_trace_sem);
+        return tag + 1;
+}
+
+/*! otg_trace_invalidate_tag(otg_tag_t tag)
+ */
+otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag)
+{
+        otg_trace_t *p,*e;
+        otg_trace_snapshot *css,*oss;
+        unsigned long flags;
+
+        // Nothing to do
+        RETURN_ZERO_IF ((0 >= tag) || (tag > 32));
+        
+        // Grab a local copy of the snapshot pointers.
+        local_irq_save(flags);
+        css = otg_trace_current_traces;
+        oss = otg_trace_other_traces;
+        local_irq_restore(flags);
+
+
+        // Run through all the trace messages, and invalidate any with the given tag.
+
+        DOWN(&otg_trace_sem);
+        if (css)
+                for (e = TRACE_MAX + (p = css->traces); p < e; p++) {
+                        if (p->tag == tag) {
+                                p->otg_trace_type = otg_trace_msg_invalid_n;
+                                p->tag = 0;
+                        }
+                }
+        if (oss)
+                for (e = TRACE_MAX + (p = oss->traces); p < e; p++) {
+                        if (p->tag == tag) {
+                                p->otg_trace_type = otg_trace_msg_invalid_n;
+                                p->tag = 0;
+                        }
+                }
+        
+        // Turn off the tag
+        otg_tags_mask &= ~(0x1 << (tag-1));
+        if (otg_tags_mask == 0x00000000) { /* otg_trace_exit (); */ }
+        UP(&otg_trace_sem);
+        return 0;
+}
+
+
+
+/* Module init ************************************************************** */
+
+#define OT otg_trace_init_test
+otg_tag_t OT;
+
+/*! otg_trace_init
+ *
+ * Return non-zero if not successful.
+ */
+int otg_trace_init (void)
+{
+        otg_trace_exiting = 0;
+        otg_trace_current_traces = otg_trace_other_traces = NULL;
+        UNLESS ((otg_trace_current_traces = get_snapshot(&otg_snapshot1)) && 
+                        (otg_trace_other_traces = get_snapshot(&otg_snapshot2))) 
+        {
+                printk(KERN_ERR"%s: malloc failed (2x) %d\n", __FUNCTION__, sizeof(otg_trace_t) * TRACE_MAX);
+                otg_trace_current_traces = rel_snapshot(otg_trace_current_traces);
+                otg_trace_other_traces = rel_snapshot(otg_trace_other_traces);
+                return -ENOMEM;
+        }
+        OT = otg_trace_obtain_tag();
+        RETURN_ENOMEM_IF(!OT);
+        TRACE_MSG0(OT,"--");
+        return 0;
+}
+
+/*! otg_trace_exit - remove procfs entry, free trace data space.
+ */
+void otg_trace_exit (void)
+{
+        otg_trace_t *p;
+        otg_tag_t tag;
+
+        unsigned long flags;
+        otg_trace_snapshot *c,*o;
+
+        otg_trace_invalidate_tag(OT);
+        otg_trace_exiting = 1;
+
+        local_irq_save (flags);
+
+        /* Look for any outstanding tags. */
+        for (tag = 32; otg_tags_mask && tag > 0; tag--) 
+                if (otg_tags_mask & (0x1 << (tag-1))) 
+                        otg_trace_invalidate_tag(tag);
+
+        c = otg_trace_current_traces;
+        o = otg_trace_other_traces;
+        otg_trace_current_traces = otg_trace_other_traces = NULL;
+        local_irq_restore (flags);
+
+        c = rel_snapshot(c);
+        o = rel_snapshot(o);
+}
+
+#else /* defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE) */
+int otg_trace_init (void) {return 0;}
+void otg_trace_exit (void) {}
+otg_tag_t otg_trace_obtain_tag(void) { return 0; }
+void otg_trace_setup(otg_tag_t tag, const char *fn, void *setup) { }
+void otg_trace_msg(otg_tag_t tag, const char *fn, u8 nargs, char *fmt, ...) { }
+otg_tag_t otg_trace_invalidate_tag(otg_tag_t tag) { return 0; }
+#endif /* defined(CONFIG_OTG_TRACE) || defined(CONFIG_OTG_TRACE_MODULE) */
+
+OTG_EXPORT_SYMBOL(otg_trace_setup);
+OTG_EXPORT_SYMBOL(otg_trace_msg);
+OTG_EXPORT_SYMBOL(otg_trace_obtain_tag);
+OTG_EXPORT_SYMBOL(otg_trace_invalidate_tag);
+
+#if 0
+// These are only needed when debugging the trace code itself.
+OTG_EXPORT_SYMBOL(otg_trace_get_next);
+OTG_EXPORT_SYMBOL(otg_trace_next_va);
+OTG_EXPORT_SYMBOL(slot_in_data);
+OTG_EXPORT_SYMBOL(otg_trace_read_slot);
+OTG_EXPORT_SYMBOL(otg_trace_proc_read);
+#endif
+
diff -uNr linux/drivers/no-otg/otgcore/otg.c linux/drivers/otg/otgcore/otg.c
--- linux/drivers/no-otg/otgcore/otg.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/otg.c	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,936 @@
+/*
+ * otg/otgcore/otg.c - OTG state machine
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/otgcore/otg.c
+ * @brief OTG Core State Machine Event Processing
+ *
+ * The OTG State Machine receives "input" information passed to it
+ * from the other drivers (pcd, tcd, hcd and ocd) that describe what
+ * is happening.
+ *
+ * The State Machine uses the inputs to move from state to state. Each
+ * state defines four things:
+ *
+ * 1. Reset - what inputs to set or reset on entry to the state.
+ *
+ * 2. Outputs - what output functions to call to set or reset.
+ *
+ * 3. Timeout - an optional timeout value to set
+ *
+ * 4. Tests - a series of tests that allow the state machine to move to
+ * new states based on current or new inputs.
+ *
+ * @ingroup OTGCore
+ */
+#ifndef OTG_REGRESS
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-tcd.h>
+#include <otg/otg-hcd.h>
+#include <otg/otg-pcd.h>
+#include <otg/otg-ocd.h>
+
+
+struct hcd_ops *otg_hcd_ops;
+struct ocd_ops *otg_ocd_ops;
+struct pcd_ops *otg_pcd_ops;
+struct tcd_ops *otg_tcd_ops;
+struct usbd_ops *otg_usbd_ops;
+
+extern struct otg_instance otg_instance_private;
+extern struct hcd_instance hcd_instance_private;
+extern struct ocd_instance ocd_instance_private;
+extern struct pcd_instance pcd_instance_private;
+extern struct tcd_instance tcd_instance_private;
+
+#if 0
+/* otg_vbus - return vbus status
+ *
+ * XXX Should we default to set or reset if there is no vbus function
+ */
+int otg_vbus(struct otg_instance *otg)
+{
+        TRACE_MSG2(CORE, "otg_tcd_ops: %p vbus: %p", otg_tcd_ops, otg_tcd_ops ? otg_tcd_ops->vbus : NULL);
+        return (otg_tcd_ops && otg_tcd_ops->vbus) ? otg_tcd_ops->vbus(otg) : 1;
+}
+#endif
+
+#if defined (OTG_WINCE)
+#define TRACE_SM_CURRENT(t, m, o) \
+				
+#else
+#define TRACE_SM_CURRENT(t, m, o) \
+                TRACE_MSG5(t, "SM_CURRENT: RESET: %08x SET: %08x %s (%s) %s",\
+                                (u32)(~o->current_inputs), \
+                                (u32)(o->current_inputs), \
+                                o->current_outputs->name, \
+                                o->previous_outputs->name, \
+                                m \
+                          );
+#endif //OTG_WINCE
+#define TRACE_SM_CHANGE(t, m, o) \
+                TRACE_MSG5(t, "SM_CHANGE:  RESET: %08x SET: %08x %s (%s) %s",\
+                                (u32)(~o->current_inputs), \
+                                (u32)(o->current_inputs), \
+                                o->current_outputs->name, \
+                                o->previous_outputs->name, \
+                                m \
+                          );
+
+#define TRACE_SM_NEW(t, m, o) \
+                TRACE_MSG5(t, "SM_NEW:     RESET: %08x SET: %08x %s (%s) %s",\
+                                (u32)(~o->current_inputs), \
+                                (u32)(o->current_inputs), \
+                                o->current_outputs->name, \
+                                o->previous_outputs->name, \
+                                m \
+                          );
+
+
+#define TRACE_SM_INPUTS(t, m, u, c) \
+                TRACE_MSG4(t, "SM_INPUTS:  RESET: %08x SET: %08x CUR: %08x %s",\
+                                (u32)(u >> 32), \
+                                (u32)(u & 0xffffffff), \
+                                c, \
+                                m \
+                                )
+
+#endif
+
+
+
+DECLARE_MUTEX (otg_sem);
+
+/*!
+ * Output change lookup table - this maps the current output and the desired
+ * output to what should be done. This is just so that we don't redo changes,
+ * if the output does not change we do not want to re-call the output function
+ */
+u8 otg_output_lookup[4][4] = {
+      /*  NC       SET      RESET    PULSE, <--- current/  new     */
+        { NC,      NC,      NC,      PULSE,  },         /* NC      */ 
+        { SET,     NC,      SET,     PULSE,  },         /* SET     */ 
+        { RESET,   RESET,   NC,      PULSE,  },         /* RESET   */ 
+        { PULSE,   PULSE,   PULSE,   PULSE,  },         /* UNKNOWN */ 
+};
+
+
+/*!
+ * otg_new() - check OTG new inputs and select new state to be in
+ *
+ * This is used by the OTG event handler to see if the state should
+ * change based on the current input values.
+ *
+ * @param otg pointer to the otg instance.
+ * @return either the next OTG state or invalid_state if no change.
+ */
+static int otg_new(struct otg_instance *otg)
+{
+        int state = otg->state;
+        struct otg_test *otg_test = otg_firmware_loaded ? otg_firmware_loaded->otg_tests : NULL;
+        u64 input_mask = ((u64)otg->current_inputs) | ((u64)(~otg->current_inputs) << 32);   // get a copy of current inputs
+
+        UNLESS(otg_test) return invalid_state;
+
+        TRACE_MSG3(CORE, "OTG_NEW: %s inputs: %08x %08x", otg_get_state_name(state),
+                        (u32)(input_mask>>32&0xffffffff), (u32)(input_mask&0xffffffff));
+
+        /* iterate across the otg inputs table, for each entry that matches the current
+         * state, test the input_mask to see if a state transition is required.
+         */
+        for (; otg_test->target != invalid_state; otg_test++) {
+
+                u64 test1 = otg_test->test1;
+                u64 test2 = otg_test->test2;
+                u64 test3 = otg_test->test3;
+
+                CONTINUE_UNLESS(otg_test->state == state);     // skip states that don't match
+
+
+                TRACE_MSG7(CORE, "OTG_NEW: %s (%s, %d) test1: %08x %08x test2 %08x %08x",
+                                otg_get_state_name(otg_test->state),
+                                otg_get_state_name(otg_test->target),
+                                otg_test->test,
+                                (u32)(test1>>32&0xffffffff), (u32)(test1&0xffffffff),
+                                (u32)(test2>>32&0xffffffff), (u32)(test2&0xffffffff)
+                                );
+
+                /* the otg inputs table has multiple masks that define between multiple tests. Each
+                 * test is a simple OR to check if specific inputs are present.
+                 */
+                CONTINUE_UNLESS (
+                                (!otg_test->test1 || ((test1 = otg_test->test1 & input_mask))) &&
+                                (!otg_test->test2 || ((test2 = otg_test->test2 & input_mask))) &&
+                                (!otg_test->test3 || ((test3 = otg_test->test3 & input_mask))) /*&&
+                                (!otg_test->test4 || (otg_test->test4 & input_mask)) */ );
+
+                TRACE_MSG7(CORE, "OTG_NEW: GOTO %s test1: %08x %08x test2 %08x %08x test3 %08x %08x",
+                                otg_get_state_name(otg_test->target),
+                                (u32)(test1>>32&0xffffffff), (u32)(test1&0xffffffff),
+                                (u32)(test2>>32&0xffffffff), (u32)(test2&0xffffffff),
+                                (u32)(test3>>32&0xffff), (u32)(test3&0xffff)
+                                );
+
+                return otg_test->target;
+        }
+        return invalid_state;
+}
+
+char mbuf[96];
+
+/*!
+ * otg_write_state_message_irq() -
+ *
+ * Send a message to the otg management application.
+ *
+ * @param msg
+ * @param reset
+ * @param inputs
+ */
+void otg_write_state_message_irq(char *msg, u64 reset, u32 inputs)
+{
+        sprintf(mbuf, "State: %s reset: %08x set: %08x inputs: %08x ", msg, (u32)(reset>>32), (u32)(reset&0xffffffff), inputs);
+        mbuf[95] = '\0';
+        otg_message(mbuf);
+}
+
+/*!
+ * otg_write_output_message_irq() -
+ *
+ * Send a message to the otg management application.
+ *
+ * @param msg
+ * @param val
+ */
+void otg_write_output_message_irq(char *msg, int val)
+{
+        strcpy(mbuf, "Output: ");
+        strncat(mbuf, msg, 64 - strlen(mbuf));
+        if (val == 2) strncat(mbuf, "/", 64 - strlen(mbuf));
+        mbuf[95] = '\0';
+        otg_message(mbuf);
+}
+
+/*!
+ * otg_write_timer_message_irq() -
+ *
+ * Send a message to the otg management application.
+ *
+ * @param msg
+ * @param val
+ */
+void otg_write_timer_message_irq(char *msg, int val)
+{
+        if (val < 10000)
+                sprintf(mbuf, "Timer: %s %d uS %u", msg, val, otg_tmr_ticks());
+        else if (val < 10000000)
+                //sprintf(time_buf, " %d mS\n", ticks / 1000);
+                sprintf(mbuf, "Timer: %s %d mS %u", msg, val >> 10, otg_tmr_ticks());
+        else
+                //sprintf(time_buf, " %d S\n", ticks / 1000000);
+                sprintf(mbuf, "Timer: %s %d S %u", msg, val >> 20, otg_tmr_ticks());
+
+        mbuf[95] = '\0';
+        otg_message(mbuf);
+}
+
+/*!
+ * otg_write_info_message_irq() -
+ *
+ * Send a message to the otg management application.
+ *
+ * @param msg
+ */
+void otg_write_info_message(char *msg)
+{
+        unsigned long flags;
+        local_irq_save (flags);
+        sprintf(mbuf, "Info: %s", msg);
+        mbuf[95] = '\0';
+        otg_message(mbuf);
+        local_irq_restore (flags);
+}
+
+/*!
+ * otg_write_reset_message_irq() -
+ *
+ * Send a message to the otg management application.
+ *
+ * @param msg
+ * @param val
+ */
+void otg_write_reset_message(char *msg, int val)
+{
+        unsigned long flags;
+        local_irq_save (flags);
+        sprintf(mbuf, "State: %s reset: %x", msg, val);
+        mbuf[95] = '\0';
+        otg_message(mbuf);
+        local_irq_restore (flags);
+}
+
+OTG_EXPORT_SYMBOL(otg_write_info_message);
+
+char otg_change_names[4] = {
+        '_', ' ', '/', '#',
+};
+
+/*!
+ * otg_do_event_irq() - process OTG events and determine OTG outputs to reflect new state
+ *
+ * This function is passed a mask with changed input values. This
+ * is passed to the otg_new() function to see if the state should
+ * change. If it changes then the output functions required for
+ * the new state are called.
+ *
+ * @param otg pointer to the otg instance.
+ * @param inputs input mask
+ * @param tag trace tag to use for tracing
+ * @param msg message for tracing
+ * @return non-zero if state changed.
+ */
+static int otg_do_event_irq(struct otg_instance *otg, u64 inputs, otg_tag_t tag, char *msg)
+{
+        u32 current_inputs = otg->current_inputs;
+        int current_state = otg->state;
+        u32 inputs_set = (u32)(inputs & 0xffffffff);           // get changed inputs that SET something
+        u32 inputs_reset = (u32) (inputs >> 32);                // get changed inputs that RESET something
+        int target;
+
+        RETURN_ZERO_UNLESS(otg && inputs);;
+        TRACE_SM_INPUTS(tag, msg, inputs, current_inputs);
+
+        /* Special Overrides - These are special tests that satisfy specific injunctions from the
+         * OTG Specification.
+         */
+        if (inputs_set & inputs_reset) {                // verify that there is no overlap between SET and RESET masks
+                TRACE_MSG1(CORE, "OTG_EVENT: ERROR attempting to set and reset the same input: %08x", inputs_set & inputs_reset);
+                return 0;
+        }
+        /* don't allow bus_req and bus_drop to be set at the same time
+         */
+        if ((inputs_set & (bus_req | bus_drop)) == (bus_req | bus_drop) ) {
+                TRACE_MSG2(CORE, "OTG_EVENT: ERROR attempting to set both bus_req and bus_drop: %08x %08x",
+                                inputs_set, (bus_req | bus_drop));
+                return 0;
+        }
+        /* set bus_drop_ if bus_req, set bus_req_ if bus_drop
+         */
+        if (inputs_set & bus_req) {
+                inputs |= bus_drop_;
+                TRACE_MSG1(CORE, "OTG_EVENT: forcing bus_drop/: %08x", inputs_set);
+        }
+        if (inputs_set & bus_drop) {
+                inputs |= bus_req_;
+                TRACE_MSG1(CORE, "OTG_EVENT: forcing bus_req/: %08x", inputs_set);
+        }
+
+        otg->current_inputs &= ~inputs_reset;
+        otg->current_inputs |= inputs_set;
+        TRACE_MSG3(CORE, "OTG_EVENT: reset: %08x set: %08x inputs: %08x", inputs_reset, inputs_set, otg->current_inputs);
+
+        TRACE_SM_CHANGE(tag, msg, otg);
+
+        RETURN_ZERO_IF(otg->active);
+
+        otg->active++;
+
+        /* Search the state input change table to see if we need to change to a new state.
+         * This may take several iterations.
+         */
+        while (invalid_state != (target = otg_new(otg))) {
+
+                struct otg_state *otg_state;
+                int original_state = otg->state;
+                u64 current_outputs;
+                u64 output_results;
+                u64 new_outputs;
+                int i;
+
+                /* if previous output started timer, then cancel timer before proceeding
+                 */
+                if ((otg_state = otg->current_outputs) && otg_state->tmout && otg->start_timer) {
+                        TRACE_MSG0(CORE, "reseting timer");
+                        otg->start_timer(otg, 0);
+                }
+
+                BREAK_UNLESS(otg_firmware_loaded);
+
+                BREAK_UNLESS(target < otg_firmware_loaded->number_of_states);
+
+                otg_state = otg_firmware_loaded->otg_states + target;
+
+                BREAK_UNLESS(otg_state->name);
+
+                otg->previous = otg->state;
+                otg->state = target;
+                otg->tickcount = otg_tmr_ticks();
+
+
+                otg->previous_outputs= otg->current_outputs;
+                //otg->current_outputs = NULL;
+
+
+                /* A matching input table rule has been found, we are transitioning to a new
+                 * state.  We need to find the new state entry in the output table.
+                 * XXX this could be a table lookup instead of linear search.
+                 */
+
+                current_outputs = otg->outputs;
+                new_outputs = otg_state->outputs;
+                output_results = 0;
+
+                TRACE_SM_NEW(tag, msg, otg);
+
+                /* reset any inputs that the new state want's reset
+                 */
+                otg_do_event_irq(otg, otg_state->reset | TMOUT_, tag, otg_state->name);
+
+                otg_write_state_message_irq(otg_state->name, otg_state->reset, otg->current_inputs);
+
+#if 1
+                switch (target) {                            /* C.f. 6.6.1.12 b_conn reset */
+                case otg_disabled:
+                        otg->current_inputs = 0;
+                        otg->outputs = 0;
+                        break;
+                default:
+                        //otg_event_irq(otg, not(b_conn), "a_host/ & a_suspend/: set b_conn/");
+                        break;
+                }
+#endif
+                TRACE_MSG5(CORE, "OTG_EVENT: CALLING OUTPUT MAX:%d OUTPUTS CURRENT: %08x %08x NEW: %08x %08x",
+                                MAX_OUTPUTS,
+                                (u32)(current_outputs >> 32),
+                                (u32)(current_outputs & 0xffffffff),
+                                (u32)(new_outputs >> 32),
+                                (u32)(new_outputs & 0xffffffff)
+                          );
+
+                /* Iterate across the outputs bitmask, calling the appropriate functions
+                 * to make required changes. The current outputs are saved and we DO NOT
+                 * make calls to change output values until they change again.
+                 */
+                for (i = 0; i < MAX_OUTPUTS; i++) {
+
+                        u8 current_output = (u8)(current_outputs & 0x3);
+                        u8 new_output = (u8)(new_outputs & 0x3);
+                        u8 changed = otg_output_lookup[new_output][current_output];
+
+                        output_results >>= 2;
+
+                        switch (changed) {
+                        case NC:
+                                output_results |= ((current_outputs & 0x3) << (MAX_OUTPUTS * 2));
+                                break;
+                        case SET:
+                        case RESET:
+                                output_results |= (((u64)changed) << (MAX_OUTPUTS * 2));
+                        case PULSE:
+
+
+                                otg_write_output_message_irq(otg_output_names[i], changed);
+
+                                //TRACE_MSG3(CORE, "OTG_EVENT: CHECKING OUTPUT %s %d %s",
+                                //                otg_state->name, i, otg_output_names[i]);
+
+                                BREAK_UNLESS(otg->otg_output_ops[i]); // Check if we have an output routine
+
+                                TRACE_MSG7(CORE, "OTG_EVENT: CALLING OUTPUT %s %d %s%c cur: %02x new: %02x chng: %02x",
+                                                otg_state->name, i, otg_output_names[i],
+                                                otg_change_names[changed&0x3],
+                                                current_output, new_output,
+                                                changed);
+
+                                otg->otg_output_ops[i](otg, changed); // Output changed, call function to do it
+
+                                //TRACE_MSG2(CORE, "OTG_EVENT: OUTPUT FINISED %s %s", otg_state->name, otg_output_names[i]);
+                                break;
+                        }
+
+                        current_outputs >>= 2;
+                        new_outputs >>= 2;
+                }
+
+                output_results >>= 2;
+                otg->outputs = output_results;
+                otg->current_outputs = otg_state;
+
+                //TRACE_MSG2(CORE, "OTG_EVENT: STATE: otg->current_outputs: %08x %08x",
+                //                (u32)(otg->outputs & 0xffffffff), (u32)(otg->outputs >> 32));
+
+                if (((otg->outputs & pcd_en_out_set) == pcd_en_out_set) &&
+                                        ((otg->outputs & hcd_en_out_set) == hcd_en_out_set))
+                {
+                        TRACE_MSG0(CORE, "WARNING PCD_EN and HCD_EN both set");
+                        printk(KERN_INFO "%s: WARNING PCD_EN and HCD_EN both set\n", __FUNCTION__);
+                }
+
+                /* start timer?
+                 */
+                CONTINUE_UNLESS(otg_state->tmout);
+                TRACE_MSG1(CORE, "setting timer: %d", otg_state->tmout);
+                if (otg->start_timer) {
+                        otg_write_timer_message_irq(otg_state->name, otg_state->tmout);
+                        otg->start_timer(otg, otg_state->tmout);
+                }
+                else {
+                        //TRACE_MSG0(CORE, "NO TIMER");
+                        otg_do_event_irq(otg, TMOUT_, CORE, otg_state->name);
+                }
+
+        }
+        //TRACE_MSG0(CORE, "finishing");
+        otg->active = 0;
+
+        if (current_state == otg->state)
+                TRACE_MSG0(CORE, "OTG_EVENT: NOT CHANGED");
+
+        otg->active = 0;
+        return 0;
+}
+
+/*!
+ * otg_write_input_message_irq() -
+
+ * @param inputs input mask
+ * @param tag trace tag to use for tracing
+ * @param msg message for tracing
+ */
+void otg_write_input_message_irq(u64 inputs, otg_tag_t tag, char *msg)
+{
+        u32 reset = (u32)(inputs >> 32);
+        u32 set = (u32) (inputs & 0xffffffff);
+
+        char buf[64];
+        //snprintf(buf, sizeof(buf), "Input: %08x %08x %s", *inputs >> 32, *inputs & 0xffffffff, msg ? msg : "NULL");
+        TRACE_MSG3(tag, "Inputs: %08x %08x %s", set, reset, msg ? msg : "NULL");
+        #ifdef OTG_WINCE
+        sprintf(buf, "Inputs: %08x %08x %s", reset, set, msg ? msg : "NULL");
+        #else /* OTG_WINCE */
+        snprintf(buf, sizeof(buf), "Inputs: %08x %08x %s", reset, set, msg ? msg : "NULL");
+        #endif /* OTG_WINCE */
+        buf[63] = '\0';
+        otg_message(buf);
+}
+
+
+/*!
+ * otg_event_input_message_irq() -
+ * @param otg pointer to the otg instance.
+ * @param inputs input mask
+ * @param tag trace tag to use for tracing
+ * @param msg message for tracing
+ * @return non-zero if state changed.
+ */
+int otg_event_irq(struct otg_instance *otg, u64 inputs, otg_tag_t tag, char *msg)
+{
+        TRACE_SM_INPUTS(tag, msg, inputs, otg->current_inputs);
+        //otg_write_input_message_irq((u32)(inputs >> 32), (u32) (inputs & 0xffffffff), tag, msg);
+        otg_write_input_message_irq(inputs, tag, msg);
+        return otg_do_event_irq(otg, inputs, tag, msg);
+}
+
+/*!
+ * otg_event() -
+ * @param otg pointer to the otg instance.
+ * @param inputs input mask
+ * @param tag trace tag to use for tracing
+ * @param msg message for tracing
+ * @return non-zero if state changed.
+ */
+int otg_event(struct otg_instance *otg, u64 inputs, otg_tag_t tag, char *msg)
+{
+        int rc; 
+        unsigned long flags;
+        RETURN_ZERO_UNLESS(otg);
+        local_irq_save (flags);
+        rc = otg_event_irq(otg, inputs, tag, msg);
+        local_irq_restore (flags);
+        return rc;
+}
+
+
+/*!
+ * otg_event_set_irq() -
+ * @param otg pointer to the otg instance.
+ * @param changed
+ * @param flag
+ * @param input input mask
+ * @param tag trace tag to use for tracing
+ * @param msg message for tracing
+ * @return non-zero if state changed.
+ */
+int otg_event_set_irq(struct otg_instance *otg, int changed, int flag, u32 input, otg_tag_t tag, char *msg)
+{
+        RETURN_ZERO_UNLESS(changed);
+        TRACE_MSG4(tag, "%s: %08x changed: %d flag: %d", msg, input, changed, flag);
+        return otg_event(otg, flag ? input : _NOT(input), tag, msg);
+}
+
+
+/*!
+ * otg_init() - create and initialize otg instance
+ *
+ * Called to initialize the OTG state machine. This will cause the state
+ * to change from the invalid_state to otg_disabled.
+ *
+ * If the device has the OCD_CAPABILITIES_AUTO flag set then
+ * an initial enable_otg event is generated. This will cause
+ * the state to move from otg_disabled to otg_enabled. The
+ * requird drivers will be initialized by calling the appropriate
+ * output functions:
+ *
+ *      - pcd_init_func
+ *      - hcd_init_func
+ *      - tcd_init_func
+ *
+ * @param otg pointer to the otg instance.
+ */
+void otg_init (struct otg_instance *otg)
+{
+        DOWN(&otg_sem);
+        otg->outputs = tcd_init_out_ | pcd_init_out_ | hcd_init_out_;
+
+        /* This will move the state machine into the otg_disabled state
+         */
+        otg_event(otg, enable_otg, CORE, "enable_otg"); // XXX
+
+        if (otg_ocd_ops->capabilities & OCD_CAPABILITIES_AUTO)
+                otg_event(otg, AUTO, CORE, "AUTO"); // XXX
+
+        UP(&otg_sem);
+}
+
+
+/*!
+ * otg_exit()
+ *
+ * This is called by the driver that started the state machine to
+ * cause it to exit. The state will move to otg_disabled.
+ *
+ * The appropriate output functions will be called to disable the
+ * peripheral drivers.
+ *
+ * @param otg pointer to the otg instance.
+ */
+void otg_exit (struct otg_instance *otg)
+{
+        //TRACE_MSG0(CORE, "DOWN OTG_SEM");
+        DOWN(&otg_sem);
+
+        //TRACE_MSG0(CORE, "OTG_EXIT");
+        //otg_event(otg, exit_all | not(a_bus_req) | a_bus_drop | not(b_bus_req), "tcd_otg_exit");
+
+        otg_event(otg, enable_otg_, CORE, "enable_otg_");
+
+        while (otg->state != otg_disabled) {
+                // TRACE_MSG pointless here, module will be gon before we can look at it.
+                #ifdef OTG_WINCE
+                //DEBUGMSG(KERN_ERR"%s: waiting for state machine to disable\n", __FUNCTION__);
+                #else /* OTG_WINCE */
+                printk(KERN_ERR"%s: waiting for state machine to disable\n", __FUNCTION__);
+                #endif /* OTG_WINCE */
+                SCHEDULE_TIMEOUT(10 * HZ);
+        }
+        //TRACE_MSG0(CORE, "UP OTG_SEM");
+        UP(&otg_sem);
+}
+
+
+OTG_EXPORT_SYMBOL(otg_event);
+OTG_EXPORT_SYMBOL(otg_event_irq);
+OTG_EXPORT_SYMBOL(otg_init);
+OTG_EXPORT_SYMBOL(otg_exit);
+OTG_EXPORT_SYMBOL(otg_event_set_irq);
+
+/* ********************************************************************************************* */
+
+/*!
+ * otg_tcd_init_func() -
+ *
+ * This is a default tcd_init_func. It will be used
+ * if no other is provided.
+ *
+ * @param otg pointer to the otg instance.
+ * @param flag set or reset
+ */
+void otg_tcd_init_func (struct otg_instance *otg, u8 flag)
+{
+        otg_event(otg, TCD_OK, CORE, "TCD_OK");
+}
+
+/*!
+ * otg_pcd_init_func() -
+ *
+ * This is a default pcd_init_func. It will be used
+ * if no other is provided.
+ *
+ * @param otg pointer to the otg instance.
+ * @param flag set or reset
+ */
+void otg_pcd_init_func (struct otg_instance *otg, u8 flag)
+{
+        otg_event(otg, PCD_OK, CORE, "PCD_OK");
+}
+
+/*!
+ * otg_hcd_init_func() -
+ *
+ * This is a default hcd_init_func. It will be used
+ * if no other is provided.
+ *
+ * @param otg pointer to the otg instance.
+ * @param flag set or reset
+ */
+void otg_hcd_init_func (struct otg_instance *otg, u8 flag)
+{
+        otg_event(otg, HCD_OK, CORE, "HCD_OK");
+}
+
+/*!
+ * otg_ocd_init_func() -
+ *
+ * This is a default hcd_init_func. It will be used
+ * if no other is provided.
+ *
+ * @param otg pointer to the otg instance.
+ * @param flag set or reset
+ */
+void otg_ocd_init_func (struct otg_instance *otg, u8 flag)
+{
+        otg_event(otg, HCD_OK, CORE, "OCD_OK");
+}
+
+/*!
+ * otg_hcd_set_ops() -
+ * @param hcd_ops - host operations table to use
+ */
+struct hcd_instance * otg_set_hcd_ops(struct hcd_ops *hcd_ops)
+{
+        otg_hcd_ops = hcd_ops;
+        if (hcd_ops) {
+                otg_instance_private.otg_output_ops[HCD_INIT_OUT] = otg_hcd_ops->hcd_init_func;
+                otg_instance_private.otg_output_ops[HCD_EN_OUT] = otg_hcd_ops->hcd_en_func;
+                otg_instance_private.otg_output_ops[LOC_SOF_OUT] = otg_hcd_ops->loc_sof_func;
+                otg_instance_private.otg_output_ops[LOC_SUSPEND_OUT] = otg_hcd_ops->loc_suspend_func;
+                otg_instance_private.otg_output_ops[REMOTE_WAKEUP_EN_OUT] = otg_hcd_ops->remote_wakeup_en_func;
+                otg_instance_private.otg_output_ops[HNP_EN_OUT] = otg_hcd_ops->hnp_en_func;
+        }
+        else
+                otg_instance_private.otg_output_ops[HCD_INIT_OUT] =
+                otg_instance_private.otg_output_ops[HCD_EN_OUT] =
+                otg_instance_private.otg_output_ops[LOC_SOF_OUT] =
+                otg_instance_private.otg_output_ops[LOC_SUSPEND_OUT] =
+                otg_instance_private.otg_output_ops[REMOTE_WAKEUP_EN_OUT] =
+                otg_instance_private.otg_output_ops[HNP_EN_OUT] = NULL;
+
+
+        UNLESS (otg_instance_private.otg_output_ops[HCD_INIT_OUT])
+                otg_instance_private.otg_output_ops[HCD_INIT_OUT] = otg_hcd_init_func;
+
+        return &hcd_instance_private;
+}
+
+/*!
+ * otg_ocd_set_ops() -
+ *
+ * @param ocd_ops - ocd operations table to use
+ */
+struct ocd_instance * otg_set_ocd_ops(struct ocd_ops *ocd_ops)
+{
+        otg_ocd_ops = ocd_ops;
+        if (ocd_ops) {
+                otg_instance_private.otg_output_ops[OCD_INIT_OUT] = otg_ocd_ops->ocd_init_func;
+                otg_instance_private.start_timer = ocd_ops->start_timer;
+        }
+        else {
+                otg_instance_private.otg_output_ops[OCD_INIT_OUT] = NULL;
+                otg_instance_private.start_timer = NULL;
+        }
+
+        UNLESS (otg_instance_private.otg_output_ops[OCD_INIT_OUT])
+                otg_instance_private.otg_output_ops[OCD_INIT_OUT] = otg_ocd_init_func;
+
+        return &ocd_instance_private;
+}
+
+/*!
+ * otg_pcd_set_ops() -
+ * @param pcd_ops - pcd operations table to use
+ */
+struct pcd_instance * otg_set_pcd_ops(struct pcd_ops *pcd_ops)
+{
+        otg_pcd_ops = pcd_ops;
+        if (pcd_ops) {
+                otg_instance_private.otg_output_ops[PCD_INIT_OUT] = otg_pcd_ops->pcd_init_func;
+                otg_instance_private.otg_output_ops[PCD_EN_OUT] = otg_pcd_ops->pcd_en_func;
+                otg_instance_private.otg_output_ops[REMOTE_WAKEUP_OUT] = otg_pcd_ops->remote_wakeup_func;
+        }
+        else
+                otg_instance_private.otg_output_ops[PCD_INIT_OUT] =
+                otg_instance_private.otg_output_ops[PCD_EN_OUT] =
+                otg_instance_private.otg_output_ops[REMOTE_WAKEUP_OUT] = NULL;
+
+        UNLESS (otg_instance_private.otg_output_ops[PCD_INIT_OUT])
+                otg_instance_private.otg_output_ops[PCD_INIT_OUT] = otg_pcd_init_func;
+
+        return &pcd_instance_private;
+}
+
+/*!
+ * otg_tcd_set_ops() -
+ * @param tcd_ops - tcd operations table to use
+ */
+struct tcd_instance * otg_set_tcd_ops(struct tcd_ops *tcd_ops)
+{
+        otg_tcd_ops = tcd_ops;
+        if (tcd_ops) {
+                otg_instance_private.otg_output_ops[TCD_INIT_OUT] = otg_tcd_ops->tcd_init_func;
+                otg_instance_private.otg_output_ops[TCD_EN_OUT] = otg_tcd_ops->tcd_en_func;
+                otg_instance_private.otg_output_ops[CHRG_VBUS_OUT] = otg_tcd_ops->chrg_vbus_func;
+                otg_instance_private.otg_output_ops[DRV_VBUS_OUT] = otg_tcd_ops->drv_vbus_func;
+                otg_instance_private.otg_output_ops[DISCHRG_VBUS_OUT] = otg_tcd_ops->dischrg_vbus_func;
+                otg_instance_private.otg_output_ops[DP_PULLUP_OUT] = otg_tcd_ops->dp_pullup_func;
+                otg_instance_private.otg_output_ops[DM_PULLUP_OUT] = otg_tcd_ops->dm_pullup_func;
+                otg_instance_private.otg_output_ops[DP_PULLDOWN_OUT] = otg_tcd_ops->dp_pulldown_func;
+                otg_instance_private.otg_output_ops[DM_PULLDOWN_OUT] = otg_tcd_ops->dm_pulldown_func;
+                //otg_instance_private.otg_output_ops[PERIPHERAL_HOST] = otg_tcd_ops->peripheral_host_func;
+                otg_instance_private.otg_output_ops[CLR_OVERCURRENT_OUT] = otg_tcd_ops->overcurrent_func;
+                otg_instance_private.otg_output_ops[DM_DET_OUT] = otg_tcd_ops->dm_det_func;
+                otg_instance_private.otg_output_ops[DP_DET_OUT] = otg_tcd_ops->dp_det_func;
+                otg_instance_private.otg_output_ops[CR_DET_OUT] = otg_tcd_ops->cr_det_func;
+                otg_instance_private.otg_output_ops[AUDIO_OUT] = otg_tcd_ops->audio_func;
+                otg_instance_private.otg_output_ops[CHARGE_PUMP_OUT] = otg_tcd_ops->charge_pump_func;
+                otg_instance_private.otg_output_ops[BDIS_ACON_OUT] = otg_tcd_ops->bdis_acon_func;
+                otg_instance_private.otg_output_ops[MX21_VBUS_DRAIN] = otg_tcd_ops->mx21_vbus_drain_func;
+                otg_instance_private.otg_output_ops[ID_PULLDOWN_OUT] = otg_tcd_ops->id_pulldown_func;
+                otg_instance_private.otg_output_ops[UART_OUT] = otg_tcd_ops->uart_func;
+                otg_instance_private.otg_output_ops[MONO_OUT] = otg_tcd_ops->mono_func;
+        }
+        else 
+                otg_instance_private.otg_output_ops[TCD_INIT_OUT] = 
+                otg_instance_private.otg_output_ops[TCD_EN_OUT] = 
+                otg_instance_private.otg_output_ops[CHRG_VBUS_OUT] = 
+                otg_instance_private.otg_output_ops[DRV_VBUS_OUT] = 
+                otg_instance_private.otg_output_ops[DISCHRG_VBUS_OUT] = 
+                otg_instance_private.otg_output_ops[DP_PULLUP_OUT] = 
+                otg_instance_private.otg_output_ops[DM_PULLUP_OUT] = 
+                otg_instance_private.otg_output_ops[DP_PULLDOWN_OUT] = 
+                otg_instance_private.otg_output_ops[DM_PULLDOWN_OUT] = 
+                //otg_instance_private.otg_output_ops[PERIPHERAL_HOST] = 
+                otg_instance_private.otg_output_ops[CLR_OVERCURRENT_OUT] =
+                otg_instance_private.otg_output_ops[DM_DET_OUT] =
+                otg_instance_private.otg_output_ops[DP_DET_OUT] =
+                otg_instance_private.otg_output_ops[CR_DET_OUT] = 
+                otg_instance_private.otg_output_ops[AUDIO_OUT] =
+                otg_instance_private.otg_output_ops[CHARGE_PUMP_OUT] =
+                otg_instance_private.otg_output_ops[BDIS_ACON_OUT] =
+                otg_instance_private.otg_output_ops[MX21_VBUS_DRAIN] = 
+                otg_instance_private.otg_output_ops[ID_PULLDOWN_OUT] =
+                otg_instance_private.otg_output_ops[UART_OUT] =
+                otg_instance_private.otg_output_ops[MONO_OUT] = NULL;
+
+        UNLESS (otg_instance_private.otg_output_ops[TCD_INIT_OUT])
+                otg_instance_private.otg_output_ops[TCD_INIT_OUT] = otg_tcd_init_func;
+
+        return &tcd_instance_private;
+}
+
+/*!
+ * otg_set_usbd_ops() -
+ * @param usbd_ops
+ */
+int otg_set_usbd_ops(struct usbd_ops *usbd_ops)
+{
+        otg_usbd_ops = usbd_ops;
+        return 0;
+}
+
+
+/*!
+ * otg_get_trace_info()
+ */
+void otg_get_trace_info(otg_trace_t *p)
+{
+        p->id_gnd = otg_instance_private.current_inputs & ID_GND ? 1 : 0;
+        p->va.s.ticks = (otg_ocd_ops && otg_ocd_ops->ticks) ? otg_ocd_ops->ticks () : 0;
+        p->va.s.interrupts = (otg_ocd_ops && otg_ocd_ops->interrupts) ? otg_ocd_ops->interrupts : 0;
+        p->va.s.framenum = (otg_pcd_ops && otg_pcd_ops->framenum) ? otg_pcd_ops->framenum() : 0;
+        p->in_interrupt = in_interrupt();
+}
+
+/*!
+ * otg_tmr_ticks() -
+ * @return number of ticks.
+ */
+u64 otg_tmr_ticks(void)
+{
+        return (otg_ocd_ops && otg_ocd_ops->ticks) ? otg_ocd_ops->ticks () : 0;
+}
+
+/*!
+ * otg_tmr_elapsed() -
+ * @param t1
+ * @param t2
+ * @return number of uSecs between t1 and t2 ticks.
+ */
+u64 otg_tmr_elapsed(u64 *t1, u64 *t2)
+{
+	return (otg_ocd_ops && otg_ocd_ops->elapsed) ? otg_ocd_ops->elapsed (t1, t2) : 0;
+}
+
+/*!
+ * otg_tmr_framenum() -
+ * @return the current USB frame number.
+ */
+u16 otg_tmr_framenum(void)
+{
+	return (otg_pcd_ops && otg_pcd_ops->framenum) ? otg_pcd_ops->framenum() : 0;
+}
+
+/*!
+ * otg_tmr_interrupts() -
+ * @return the current number of interrupts.
+ */
+u32 otg_tmr_interrupts(void)
+{
+	return (otg_ocd_ops && otg_ocd_ops->interrupts) ? otg_ocd_ops->interrupts : 0;
+}
+
+
+OTG_EXPORT_SYMBOL(otg_hcd_ops);
+OTG_EXPORT_SYMBOL(otg_ocd_ops);
+OTG_EXPORT_SYMBOL(otg_pcd_ops);
+OTG_EXPORT_SYMBOL(otg_tcd_ops);
+OTG_EXPORT_SYMBOL(otg_set_hcd_ops);
+OTG_EXPORT_SYMBOL(otg_set_ocd_ops);
+OTG_EXPORT_SYMBOL(otg_set_pcd_ops);
+OTG_EXPORT_SYMBOL(otg_set_tcd_ops);
+OTG_EXPORT_SYMBOL(otg_set_usbd_ops);
+OTG_EXPORT_SYMBOL(otg_tmr_ticks);
+OTG_EXPORT_SYMBOL(otg_tmr_elapsed);
+OTG_EXPORT_SYMBOL(otg_write_input_message_irq);
+
+
+#if defined(OTG_WINCE)
+#else /* defined(OTG_WINCE) */
+#endif /* defined(OTG_WINCE) */
+
diff -uNr linux/drivers/no-otg/otgcore/sources linux/drivers/otg/otgcore/sources
--- linux/drivers/no-otg/otgcore/sources	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/sources	2006-09-01 21:41:34.000000000 +0200
@@ -0,0 +1,41 @@
+!if 0
+Copyright (c) Microsoft Corporation.  All rights reserved.
+!endif
+!if 0
+Use of this source code is subject to the terms of the Microsoft end-user
+license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
+If you did not accept the terms of the EULA, you are not authorized to use
+this source code. For a copy of the EULA, please see the LICENSE.RTF on your
+install media.
+!endif
+
+SYNCHRONIZE_DRAIN=1
+
+INCLUDES= \
+		$(_PUBLICROOT)\common\ddk\inc; $(_PUBLICROOT)\common\oak\inc; $(_PUBLICROOT)\common\sdk\inc; \
+		$(_WINCEROOT)\public\common\oak\DRIVERS\otg;
+
+
+TARGETNAME=otgcore
+TARGETTYPE=LIBRARY
+
+
+SOURCES=                \
+        core-init-w42.c \
+        otg.c \
+        otg-mesg.c \
+        otg-mesg-w42.c \
+        otg-ops.c \
+        usbp-bops.c \
+        usbp-fops.c \
+        otg-fw.c \
+        otg-fw-df.c \
+        otg-fw-mn.c \
+        usbp.c \
+        otg-trace.c \
+        otg-trace-w42.c \
+        ep0.c \
+
+#        usbp-procfs.c \
+
+
diff -uNr linux/drivers/no-otg/otgcore/usbp-bops.c linux/drivers/otg/otgcore/usbp-bops.c
--- linux/drivers/no-otg/otgcore/usbp-bops.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/usbp-bops.c	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,1857 @@
+/*
+ * otg/otgcore/usbp-bops.c - USB Device Prototype
+ *
+ *      Copyright (c) 2004-2005 Belcarra
+ *
+ * By:
+ *      Stuart Lynne <sl@belcarra.com>,
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/otgcore/usbp-bops.c
+ * @brief Bus Interface related functions.
+ *
+ * This implements the functions used to implement Peripheral Controller Drivers (PCD.)
+ *
+ * @ingroup USBP
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/otg-trace.h>
+#include <otg/otg-api.h>
+#include <otg/otg-trace.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+#include <otg/otg-pcd.h>
+
+/* ********************************************************************************************* */
+/*!
+ * Note that all of the list functions overlapped operation using the usbd_bus_sem;
+ *
+ *      usbd_device_bh
+ *
+ *      usbd_register_bus
+ *      usbd_deregister_bus
+ *      usbd_enable_function_irq
+ *      usbd_disable_function
+ */
+DECLARE_MUTEX(usbd_bus_sem);
+void usbd_device_bh (void *data);
+
+/* ********************************************************************************************* */
+/*!
+ * Function driver enable/disable
+ *
+ * Called by usbd_enable_function/usbd_disable_function to call the selected
+ * function drivers function_enable or function_disable function.
+ */
+int usbd_strings_init (void);
+void usbd_strings_exit(void);
+
+extern struct usbd_function_instance *usbd_find_function (char *name);
+
+struct usbd_bus_instance *usbd_bus_instance;
+OTG_EXPORT_SYMBOL(usbd_bus_instance);
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/*!
+ * Bus Interface Management:
+ *      usbd_register_bus()
+ *      usbd_deregister_bus()
+ */
+
+/*! urb_link_init() - initialize urb linke
+ *
+ * Initialize an urb_link to be a single element list.
+ * If the urb_link is being used as a distinguished list head
+ * the list is empty when the head is the only link in the list.
+ *
+ * @param ul link to urb
+ */
+static INLINE void urb_link_init (urb_link * ul)
+{
+        ul->prev = ul->next = ul;
+}
+
+static struct usbd_function_operations ep0_ops;
+struct usbd_function_driver ep0_driver;
+        
+
+/*! 
+ * usbd_register_bus() - called by a USB BUS INTERFACE driver to register a bus driver
+ *
+ * Used by a USB Bus interface driver to register itself with the usb device layer.
+ *
+ * @param driver
+ * @param ep0_wMaxPacketSize
+ * @return non-zero if error
+ */
+struct usbd_bus_instance *usbd_register_bus (struct usbd_bus_driver *driver, int ep0_wMaxPacketSize)
+{
+        int i;
+        struct usbd_bus_instance *bus = NULL;
+
+        DOWN(&usbd_bus_sem);
+
+        THROW_IF(usbd_bus_instance, error);
+        THROW_IF((bus = CKMALLOC (sizeof (struct usbd_bus_instance), GFP_ATOMIC)) == NULL, error);
+
+        bus->driver = driver;
+        bus->endpoints = bus->driver->max_endpoints;
+        bus->otg_bmAttributes = bus->driver->otg_bmAttributes;
+
+        THROW_IF(!(bus->endpoint_array = CKMALLOC(sizeof (struct usbd_endpoint_instance) * bus->endpoints, GFP_ATOMIC)), error); 
+
+        for (i = 0; i < bus->endpoints; i++) {
+                struct usbd_endpoint_instance *endpoint = bus->endpoint_array + i;
+                endpoint->physical_endpoint = i;
+                urb_link_init (&endpoint->rdy);
+                urb_link_init (&endpoint->tx);
+        }
+
+        urb_link_init (&bus->finished);
+
+        ZERO(ep0_ops);
+        ZERO(ep0_driver);
+        ep0_driver.name = "EP0";
+        ep0_driver.fops = &ep0_ops;
+        
+
+        THROW_IF((bus->ep0 = CKMALLOC (sizeof (struct usbd_function_instance), GFP_ATOMIC)) == NULL, error);
+        bus->ep0->function_driver = &ep0_driver;
+        THROW_IF(!(bus->ep0->endpoint_map_array = CKMALLOC(sizeof(struct usbd_endpoint_map) * 2, GFP_KERNEL)), error);
+        bus->ep0->endpoint_map_array[0].wMaxPacketSize[0] = ep0_wMaxPacketSize;
+        bus->ep0->endpoint_map_array[0].wMaxPacketSize[1] = ep0_wMaxPacketSize;
+
+        bus->device_state = STATE_CREATED;
+        bus->status = USBD_OPENING;
+
+        usbd_bus_instance = bus;
+
+        CATCH(error) {
+                if (bus) {
+                        if (bus->endpoint_array) 
+                                LKFREE(bus->endpoint_array);
+                        LKFREE(bus);
+                }
+                bus->endpoints = 0;
+                #if defined(OTG_LINUX)
+                printk(KERN_INFO"%s: FAILED\n", __FUNCTION__);
+                #endif /* defined(OTG_LINUX) */
+                #if defined(OTG_WINCE)
+                DEBUGMSG(ZONE_INIT, (_T("usbd_register_bus: FAILED\n")));
+                #endif /* defined(OTG_LINUX) */
+                bus =  NULL;
+        }
+
+        UP(&usbd_bus_sem);
+        return bus;
+}
+
+/*! 
+ * usbd_deregister_bus() - called by a USB BUS INTERFACE driver to deregister a bus driver
+ *
+ * Used by a USB Bus interface driver to de-register itself with the usb device
+ * layer.
+ *
+ * @param bus
+ */
+void usbd_deregister_bus (struct usbd_bus_instance *bus)
+{
+        DOWN(&usbd_bus_sem);
+
+        usbd_bus_instance = NULL;
+
+        if (bus->ep0) {
+                if (bus->ep0->endpoint_map_array)
+                        LKFREE(bus->ep0->endpoint_map_array);
+                LKFREE(bus->ep0);
+        }
+
+        LKFREE (bus->arg);
+        LKFREE (bus->endpoint_array);
+        LKFREE (bus);
+        bus->endpoints = 0;
+        UP(&usbd_bus_sem);
+}
+
+OTG_EXPORT_SYMBOL(usbd_register_bus);
+OTG_EXPORT_SYMBOL(usbd_deregister_bus);
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/*!
+ * Function Management:
+ *      usbd_enable_function()
+ *      usbd_disable_function()
+ *
+ */
+
+/*!
+ * alloc_function_alternates() - allocate alternate instance array
+ *
+ * Return a pointer to an array of alternate instances. Each instance contains a pointer
+ * to a filled in alternate descriptor and a pointer to the endpoint descriptor array.
+ *
+ * Returning NULL will cause the caller to cleanup all previously allocated memory.
+ * @param bInterfaceNumber
+ * @param interface_description
+ * @param alternates
+ * @param alternate_description_array
+ * @return pointer to alternate instance array
+ */
+static struct usbd_alternate_instance *
+alloc_function_alternates (int bInterfaceNumber,
+                struct usbd_interface_description *interface_description,
+                int alternates, struct usbd_alternate_description *alternate_description_array)
+{
+        int alternate_num;
+        struct usbd_alternate_instance *alternate_instance_array = NULL;
+
+        // allocate array of alternate instances
+        RETURN_NULL_IF(!(alternate_instance_array = (struct usbd_alternate_instance *)
+                                CKMALLOC (sizeof (struct usbd_alternate_instance) * alternates, GFP_KERNEL)));
+
+        // iterate across the alternate descriptions
+        for (alternate_num = 0; alternate_num < alternates; alternate_num++) {
+
+                struct usbd_alternate_description *alternate_description = alternate_description_array + alternate_num;
+                struct usbd_alternate_instance *alternate_instance = alternate_instance_array + alternate_num;
+                struct usbd_interface_descriptor *interface_descriptor;
+
+                interface_descriptor = alternate_description->interface_descriptor;
+                if (interface_descriptor->bInterfaceNumber != bInterfaceNumber) {
+                        //TRACE_MSG2(USBD, "bInterfaceNumber mis-match: %d should be %d",
+                        //                interface_descriptor->bInterfaceNumber, bInterfaceNumber);
+                        LKFREE(alternate_instance_array);
+                        return NULL;
+                }
+
+                interface_descriptor->bNumEndpoints = alternate_description->endpoints;
+                interface_descriptor->iInterface = usbd_alloc_string (alternate_description->iInterface );
+
+                alternate_instance->class_list = alternate_description->class_list;
+                alternate_instance->classes = alternate_description->classes;
+                alternate_instance->endpoint_list = alternate_description->endpoint_list;
+                alternate_instance->endpoint_indexes = alternate_description->endpoint_indexes;
+
+                // save number of alternates, classes and endpoints for this alternate
+                alternate_instance->endpoints = alternate_description->endpoints;
+                alternate_instance->interface_descriptor = interface_descriptor;
+        }
+        return alternate_instance_array;
+}
+
+/*!
+ * alloc_function_interfaces() - allocate interface instance array
+ *
+ * Return a pointer to an array of interface instances. Each instance contains a pointer
+ * to a filled in interface descriptor and a pointer to the endpoint descriptor array.
+ *
+ * Returning NULL will cause the caller to cleanup all previously allocated memory.
+ *
+ * @param bNumInterfaces
+ * @param interface_description_array
+ * @return interface instance
+ */
+static struct usbd_interfaces_instance *
+alloc_function_interfaces (int bNumInterfaces, struct usbd_interface_description *interface_description_array)
+{
+        int interface_num;
+        struct usbd_interfaces_instance *interfaces_instance_array = NULL;
+
+        // allocate array of interface instances
+        RETURN_NULL_IF(!(interfaces_instance_array = (struct usbd_interfaces_instance *)
+                                CKMALLOC (sizeof (struct usbd_interfaces_instance) * bNumInterfaces, GFP_KERNEL)));
+
+        // iterate across the interface descriptions
+        for (interface_num = 0; interface_num < bNumInterfaces; interface_num++) {
+
+                struct usbd_interface_description *interface_description = interface_description_array + interface_num;
+                struct usbd_interfaces_instance *interfaces_instance = interfaces_instance_array + interface_num;
+
+                interfaces_instance->alternates_instance_array =
+                        alloc_function_alternates (interface_num, interface_description,
+                                        interface_description->alternates, interface_description->alternate_list);
+                interfaces_instance->alternates = interface_description->alternates;
+        }
+        return interfaces_instance_array;
+}
+
+
+/*!
+ * alloc_function_configurations() - allocate configuration instance array
+ *
+ * Return a pointer to an array of configuration instances. Each instance contains a pointer
+ * to a filled in configuration descriptor and a pointer to the interface instances array.
+ *
+ * Returning NULL will cause the caller to cleanup all previously allocated memory.
+ *
+ * @param bNumConfigurations
+ * @param configuration_description_array
+ * @param otg_descriptor
+ * @param remote_wakeup_supported
+ * @param bMaxPower
+ * @return configuration instance
+ */
+static struct usbd_configuration_instance *
+alloc_function_configurations (struct usbd_function_driver *function_driver,
+                int remote_wakeup_supported,
+                int bMaxPower)
+{
+
+        int bNumConfigurations = function_driver->bNumConfigurations;
+        struct usbd_configuration_description *configuration_description_array = function_driver->configuration_description;
+        struct usbd_otg_descriptor *otg_descriptor = function_driver->otg_descriptor;
+        int config_num;
+        struct usbd_configuration_instance *configuration_instance_array = NULL;
+
+        //TRACE_MSG2(USBD, "remote: %x bMaxPower: %x", remote_wakeup_supported, bMaxPower);
+
+        // allocate array
+        RETURN_NULL_IF(!(configuration_instance_array = (struct usbd_configuration_instance *)
+                                CKMALLOC (sizeof (struct usbd_configuration_instance) * bNumConfigurations, GFP_KERNEL)));
+        // fill in array
+        for (config_num = 0; config_num < bNumConfigurations; config_num++) {
+                int interface_num;
+                int length;
+
+                struct usbd_configuration_description *configuration_description = configuration_description_array + config_num;
+                struct usbd_configuration_descriptor *configuration_descriptor;
+
+                configuration_descriptor = configuration_description->configuration_descriptor;
+
+                // setup fields in configuration descriptor
+                // XXX c.f. 9.4.7 zero is default, so config MUST BE 1 to n, not 0 to n-1
+                // XXX N.B. the configuration itself is fetched 0 to n-1.
+
+                configuration_descriptor->bConfigurationValue = config_num + 1;
+                configuration_descriptor->wTotalLength = 0;
+                configuration_descriptor->bNumInterfaces = function_driver->bNumInterfaces;
+                configuration_descriptor->iConfiguration = usbd_alloc_string (configuration_description->iConfiguration);
+                configuration_descriptor->bMaxPower = bMaxPower;
+                configuration_descriptor->bmAttributes = BMATTRIBUTE_RESERVED | 
+                        bMaxPower ? 0 : BMATTRIBUTE_SELF_POWERED | 
+                        remote_wakeup_supported ? BMATTRIBUTE_REMOTE_WAKEUP : 0;
+                
+                // save the configuration descriptor in the configuration instance array
+                configuration_instance_array[config_num].configuration_descriptor = configuration_descriptor;
+
+                RETURN_NULL_IF (!(configuration_instance_array[config_num].interfaces_instance_array = 
+                                        alloc_function_interfaces (function_driver->bNumInterfaces, 
+                                                function_driver->interface_list)));
+
+                length = sizeof(struct usbd_configuration_descriptor);
+
+                for (interface_num = 0; interface_num < configuration_descriptor->bNumInterfaces; interface_num++) {
+
+                        int alternate_num;
+                        struct usbd_interfaces_instance *interfaces_instance = 
+                                configuration_instance_array[config_num].interfaces_instance_array + interface_num;
+
+                        TRACE_MSG2(USBD, "len: %02x:%02d configuration", length, length);
+                        for (alternate_num = 0; alternate_num < interfaces_instance->alternates; alternate_num++) {
+                                int class_num;
+                                int endpoint;
+                                struct usbd_alternate_instance *alternate_instance = 
+                                        interfaces_instance->alternates_instance_array + alternate_num;
+
+                                length += sizeof (struct usbd_interface_descriptor);
+
+                                TRACE_MSG2(USBD, "len: %02x:%02d interface", length, length);
+                                for (class_num = 0; class_num < alternate_instance->classes; class_num++) {
+                                        struct usbd_generic_class_descriptor * class_descriptor = 
+                                                *(alternate_instance->class_list + class_num);
+                                        length += class_descriptor->bLength;
+                                        TRACE_MSG2(USBD, "len: %02x:%02d class_num", length, length);
+                                }
+
+                                for (endpoint = 0; endpoint < alternate_instance->endpoints; endpoint++) {
+                                        struct usbd_endpoint_descriptor * endpoint_descriptor = 
+                                                *(alternate_instance->endpoint_list + endpoint);
+                                        length += endpoint_descriptor->bLength;
+                                        TRACE_MSG2(USBD, "len: %02x:%02d endpoint", length, length);
+                                }
+                        }
+                }
+                length += otg_descriptor ? sizeof(struct usbd_otg_descriptor) : 0;
+                configuration_descriptor->wTotalLength = cpu_to_le16 ((u16)length);
+                // XXX only support a single configuration currently
+                configuration_instance_array[config_num].bNumInterfaces = function_driver->bNumInterfaces;
+                TRACE_MSG3(USBD, "configuration_instance_array[%d]: %p wTotalLength: %d", config_num, 
+                                &configuration_instance_array[config_num], length);
+        }
+        return configuration_instance_array;
+}
+
+
+/*!
+ * bus_function_enable() - enable a usbd function driver for use
+ *
+ * This will copy descriptors from the function driver and get them ready
+ * for use.
+ * @param bus
+ * @param function
+ * @param serial_number
+ * @return non-zero if error
+ */
+static int 
+bus_function_enable (struct usbd_bus_instance *bus, struct usbd_function_instance *function, char *serial_number)
+{
+        struct usbd_function_driver *function_driver = function->function_driver;
+        struct usbd_device_description *device_description;
+        struct usbd_device_descriptor *device_descriptor;
+#ifdef CONFIG_OTG_HIGH_SPEED
+        struct usbd_device_qualifier_descriptor *device_qualifier_descriptor;
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        struct usbd_otg_descriptor *otg_descriptor;
+        int rc = 0;
+
+        function->bus = bus;
+
+        RETURN_EINVAL_IF(function_driver->fops->function_enable && function_driver->fops->function_enable (function));
+        RETURN_ZERO_IF(!(device_description = function_driver->device_description));
+        RETURN_ZERO_IF(!(device_descriptor = device_description->device_descriptor));
+
+        device_descriptor->bMaxPacketSize0 = bus->driver->maxpacketsize;
+        device_descriptor->iManufacturer = usbd_alloc_string (device_description->iManufacturer);
+        device_descriptor->iProduct = usbd_alloc_string (device_description->iProduct);
+
+        if (strlen (serial_number))
+                device_descriptor->iSerialNumber = usbd_alloc_string (serial_number);
+        else
+                device_descriptor->iSerialNumber = usbd_alloc_string (device_description->iSerialNumber);
+
+        device_descriptor->bNumConfigurations = function_driver->bNumConfigurations;
+        device_descriptor->idVendor = function_driver->idVendor;
+        device_descriptor->idProduct = function_driver->idProduct;
+        device_descriptor->bcdDevice = function_driver->bcdDevice;
+
+        if ((otg_descriptor = device_description->otg_descriptor)) {
+                otg_descriptor->bmAttributes = usbd_otg_bmattributes(function);
+                function_driver->otg_descriptor = otg_descriptor;
+        }
+
+        /* call alloc_function_configurations() to allocate the configuration descriptor array
+         */
+        RETURN_EINVAL_IF (!(function_driver->configuration_instance_array =
+                                alloc_function_configurations (function_driver, 
+                                        bus->driver->capabilities & REMOTE_WAKEUP_SUPPORTED,
+                                        bus->driver->bMaxPower
+                                        )));
+
+        function_driver->device_descriptor = device_descriptor;
+#ifdef CONFIG_OTG_HIGH_SPEED
+        TRACE_MSG0(USBD, "HIGH SPEED");
+        if ((device_qualifier_descriptor = device_description->device_qualifier_descriptor)) {
+                device_qualifier_descriptor->bNumConfigurations = function_driver->bNumConfigurations;
+                function_driver->device_qualifier_descriptor = device_qualifier_descriptor;
+        }
+#endif /* CONFIG_OTG_HIGH_SPEED */
+        //TRACE_MSG0(USBD, "finished");
+        return rc;
+}
+
+/*!
+ * usbd_function_disable() - disable a usbd function driver
+ * @param function
+ */
+void usbd_function_disable (struct usbd_function_instance *function)
+{
+        int configuration;
+        struct usbd_function_driver *function_driver = function->function_driver;
+        struct usbd_configuration_instance *configuration_instance_array = function_driver->configuration_instance_array;
+
+        if (function->function_driver->fops->function_disable) 
+                function->function_driver->fops->function_disable (function);
+
+        RETURN_IF(!function_driver->configuration_instance_array);
+
+        // iterate across the descriptors list and de-allocate all structures
+        if (function_driver->configuration_instance_array) {
+                for (configuration = 0; configuration < function_driver->bNumConfigurations; configuration++) {
+                        int interface_num;
+                        struct usbd_configuration_instance *configuration_instance = configuration_instance_array + configuration;
+
+                        for (interface_num = 0; interface_num < configuration_instance->bNumInterfaces; interface_num++) {
+
+                                //int alternate_num;
+                                struct usbd_interfaces_instance *interfaces_instance = 
+                                        configuration_instance->interfaces_instance_array + interface_num;
+
+                                LKFREE (interfaces_instance->alternates_instance_array);
+                        }
+                        LKFREE (configuration_instance->interfaces_instance_array);
+                }
+        }
+        LKFREE (configuration_instance_array);
+        function->bus = NULL;
+}
+
+
+/*! 
+ * usbd_enable_function() - called to enable the desired function
+ *
+ * Used by a USB Bus interface driver to create a virtual device.
+ *
+ * @param bus
+ * @param arg
+ * @param serial_number
+ * @return non-zero if error
+ */
+int usbd_enable_function(struct usbd_bus_instance *bus, char *arg, char *serial_number)
+{
+        struct usbd_function_instance *function = NULL;
+        struct usbd_function_driver *function_driver = NULL;
+        LIST_NODE *lhd = NULL;
+        int len = 0;
+        int i;
+        int rc = -EINVAL;
+        int epn, endpointsRequested;
+        int endpoints;
+
+        DOWN(&usbd_bus_sem);
+
+        if (arg && bus->arg) 
+                LKFREE(bus->arg);
+
+        if (arg) {
+                bus->arg = LSTRDUP(arg);
+                len = strlen(arg);
+        }
+
+        /* initialize the strings pool, and zero endpoint array urbs
+         */
+        THROW_IF(usbd_strings_init (), error);
+
+        for (i = 1; i < bus->endpoints; i++) {
+                struct usbd_endpoint_instance *endpoint = bus->endpoint_array + i;
+                endpoint->rcv_urb = endpoint->tx_urb = NULL;
+        }               
+        
+        /* find requested function
+         */
+        if ((function = usbd_find_function(arg))) {
+
+                function_driver = function->function_driver;
+
+                TRACE_MSG1(USBD, "request endpoints: %x", function_driver);
+
+                switch(function->function_type) {
+                case function_simple:
+                        THROW_IF(bus->driver->bops->request_endpoints( bus, function->endpoint_map_array,
+                                                function->function_driver->endpointsRequested,
+                                                function->function_driver->requestedEndpoints), error);
+                        break;
+                case function_interface:
+                        break;
+                case function_composite:
+                        THROW_IF(bus->driver->bops->request_endpoints( bus, function->endpoint_map_array,
+                                                function->endpoints,
+                                                function->requestedEndpoints), error);
+                        break;
+                }
+
+
+                bus_function_enable (bus, function, serial_number);
+        }
+
+        THROW_IF (!(bus->function_instance = function), error);
+
+
+        /* if composite we need to compose the interface list and endpoint map
+         */
+        if(function_composite == function->function_type) {
+                char *name;
+                int i;
+        }
+
+        /* we need to de-compose the endpoint request array into the individual
+         * interface endpoint map array.
+         */
+        for (endpoints = 0, i = 0; i < function->interfaces; i++) {
+                struct usbd_function_instance *interface_function = function->interfaces_array[i];
+                interface_function->endpoint_map_array = function->endpoint_map_array;
+                endpoints += interface_function->endpoints;
+        }
+
+
+        switch(bus->function_instance->function_type) {
+        case function_simple:
+        case function_composite:
+                THROW_IF(bus->driver->bops->set_endpoints( bus, 
+                                        function->function_driver->endpointsRequested,
+                                        function->endpoint_map_array), error);
+                break;
+        case function_interface:
+                break;
+        }
+
+        // device bottom half
+	PREPARE_WORK_ITEM(bus->device_bh, usbd_device_bh, bus);
+        bus->status = USBD_OK;
+        bus->bus_state = usbd_bus_state_enabled;
+        bus->ep0->endpoint_map_array->endpoint = bus->endpoint_array;
+        THROW_IF (bus_function_enable (bus, bus->ep0, NULL), error);
+
+        // iterate across the logical endpoint map to copy appropriate information 
+        // into the physical endpoint instance array
+
+        endpointsRequested = bus->function_instance->function_driver->endpointsRequested;
+
+        for (epn = 0; epn < /*bus->function_instance->*/endpointsRequested; epn++) {
+
+                struct usbd_endpoint_map *endpoint_map = bus->function_instance->endpoint_map_array + epn;
+                int physicalEndpoint = endpoint_map->physicalEndpoint[0];
+                struct usbd_endpoint_instance *endpoint = bus->endpoint_array + physicalEndpoint;
+
+                endpoint_map->endpoint = endpoint;
+                endpoint->bEndpointAddress = endpoint_map->bEndpointAddress[0];
+                endpoint->bmAttributes = endpoint_map->bmAttributes[0];
+
+                switch(endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
+                case USB_DIR_IN:
+                        endpoint->tx_transferSize = endpoint_map->transferSize[0];
+                        endpoint->wMaxPacketSize = endpoint_map->wMaxPacketSize[0];
+                        endpoint->last = 0;
+                        endpoint->tx_urb = NULL;
+                        break;
+
+                case USB_DIR_OUT:
+                        endpoint->rcv_transferSize = endpoint_map->transferSize[0];
+                        endpoint->wMaxPacketSize = endpoint_map->wMaxPacketSize[0];
+                        endpoint->rcv_urb = NULL;
+                        break;
+                }
+        }
+
+        /* if composite we need to de-compose the endpoint map into the individual
+         * interface endpoint maps.
+         */
+        if(function_composite == function->function_type) {
+        }
+
+        rc = 0;
+
+        CATCH(error) {
+                usbd_strings_exit();
+        }
+        UP(&usbd_bus_sem);
+        return rc;
+}
+
+int usbd_enable_function_irq (struct usbd_bus_instance *bus, char *arg, char *serial_number)
+{
+        return usbd_enable_function(bus, arg, serial_number);
+}
+
+/*! 
+ * usbd_disable_function() - called to disable the current function
+ *
+ * Used by a USB Bus interface driver to destroy a virtual device.
+ *
+ * @param bus
+ */
+void usbd_disable_function (struct usbd_bus_instance *bus)
+{
+        DOWN(&usbd_bus_sem);
+
+        // prevent any more bottom half scheduling
+        bus->status = USBD_CLOSING;
+        UP(&usbd_bus_sem);
+
+        /* XXX 
+         * if composite ???
+         */
+        switch(bus->function_instance->function_type) {
+        case function_simple:
+        case function_interface:
+                break;
+        case function_composite:
+                break;
+        }
+
+        // wait for pending device bottom half to finish
+//XXX FIXME
+        //while (bus->device_bh.data /*|| device->function_bh.data */) {
+	while (PENDING_WORK_ITEM(bus->device_bh)){
+
+                //printk(KERN_INFO"%s: waiting for usbd_device_bh %ld %p interrupt: %d\n", __FUNCTION__, 
+                //                bus->device_bh.sync, bus->device_bh.data, in_interrupt());
+
+                // This can probably be either, but for consistency's sake...
+#if 1
+		//I.e. run this task immediately and then delay up to 2000 secdons ...
+#ifdef LINUX24
+                queue_task(&bus->device_bh, &tq_immediate);
+                mark_bh (IMMEDIATE_BH);
+#else
+		SCHEDULE_WORK(bus->device_bh);
+#endif
+                // schedule_task(&device->device_bh);
+
+                SCHEDULE_TIMEOUT (2000 * HZ);
+#else
+		//Generic version ...
+		SCHEDULE_IMMEDIATE_WORK(bus->device_bh);
+		SCHEDULE_TIMEOUT(2000); //Seconds
+#endif
+        }
+        DOWN(&usbd_bus_sem);
+
+        // tell the function driver to close
+        usbd_function_disable (bus->ep0);
+        usbd_function_disable (bus->function_instance);
+
+        // free alternates memory
+        if (bus->alternates) {
+                bus->bNumInterfaces = 0;
+                LKFREE(bus->alternates);
+                bus->alternates = NULL;
+        }
+        if (bus->function_instance) {
+#if 0
+                if (bus->function_instance->endpoint_map_array) 
+                        LKFREE(bus->function_instance->endpoint_map_array);
+                LKFREE(bus->function_instance);
+#endif
+                bus->function_instance = NULL;
+        }
+        usbd_strings_exit();
+        bus->status = USBD_CLOSED;
+        UP(&usbd_bus_sem);
+}
+
+OTG_EXPORT_SYMBOL(usbd_enable_function);
+OTG_EXPORT_SYMBOL(usbd_enable_function_irq);
+OTG_EXPORT_SYMBOL(usbd_disable_function);
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/*!
+ * Bus Event Handling:
+ *      usbd_bus_event_handler()
+ *
+ */
+static usbd_device_state_t event_states[DEVICE_CLOSE] = {
+        STATE_UNKNOWN, STATE_INIT, STATE_ATTACHED, STATE_POWERED,
+        STATE_DEFAULT, STATE_ADDRESSED, STATE_CONFIGURED, STATE_UNKNOWN,
+        STATE_UNKNOWN, STATE_UNKNOWN, STATE_ADDRESSED, STATE_SUSPENDED,
+        STATE_UNKNOWN, STATE_POWERED, STATE_ATTACHED,
+};
+
+static usbd_device_status_t event_status[DEVICE_CLOSE+1] = {
+        USBD_UNKNOWN,   // DEVICE_UNKNOWN
+        USBD_OPENING,   // DEVICE_INIT
+        USBD_OPENING,   // DEVICE_CREATE
+        USBD_OPENING,   // DEVICE_HUB_CONFIGURED
+        USBD_RESETING,  // DEVICE_RESET
+        USBD_OK,        // DEVICE_ADDRESS_ASSIGNED
+        USBD_OK,        // DEVICE_CONFIGURED
+        USBD_OK,        // DEVICE_SET_INTERFACE
+        USBD_OK,        // DEVICE_SET_FEATURE
+        USBD_OK,        // DEVICE_CLEAR_FEATURE
+        USBD_OK,        // DEVICE_DE_CONFIGURED
+        USBD_SUSPENDED, // DEVICE_BUS_INACTIVE
+        USBD_OK,        // DEVICE_BUS_ACTIVITY
+        USBD_RESETING,  // DEVICE_POWER_INTERRUPTION
+        USBD_RESETING,  // DEVICE_HUB_RESET
+        USBD_CLOSING,   // DEVICE_DESTROY
+        USBD_CLOSED,    // DEVICE_CLOSE
+};
+
+/*!
+ * usbd_bus_event_handler_irq() - called to respond to various usb events
+ *
+ * This is called from an interrupt context.
+ *
+ * Used by a Bus driver to indicate an event.
+ * @param bus
+ * @param event
+ * @param data
+ */
+void usbd_bus_event_handler_irq (struct usbd_bus_instance *bus, usbd_device_event_t event, int data)
+{
+        RETURN_UNLESS(bus);
+
+        /* get the next bus device state by table lookup of event, we need to save the
+         * current state IFF we are suspending so that it can be restored on resume.
+         */
+        switch (event) {
+        case DEVICE_BUS_INACTIVE:
+                bus->suspended_state = bus->device_state;
+                /* FALL THROUGH */
+        default:
+                bus->device_state = event_states[event];
+                //TRACE_MSG0(USBD, "default");
+                break;
+        case DEVICE_UNKNOWN:
+                //TRACE_MSG0(USBD, "UNKNOWN");
+                break;
+        case DEVICE_BUS_ACTIVITY:
+                bus->device_state = bus->suspended_state;
+                //TRACE_MSG0(USBD, "ACTIVITY");
+                break;
+
+        case DEVICE_SET_INTERFACE:
+        case DEVICE_SET_FEATURE:
+        case DEVICE_CLEAR_FEATURE:
+                //TRACE_MSG0(USBD, "SET");
+                break;
+        }
+
+        /* set the bus status by table lookup of event.
+         */
+        switch (event) {
+        case DEVICE_BUS_ACTIVITY:
+        case DEVICE_BUS_INACTIVE:
+                BREAK_IF(USBD_CLOSING != bus->status);
+                /* FALL THROUGH */
+        default:
+                bus->status = event_status[event];
+                //TRACE_MSG0(USBD, "DEFAULT");
+                break;
+        }
+
+        /* we need to reset things on some transitions
+         */
+        switch (bus->device_state) {
+        default:
+                // if we lost configuration then get rid of alternate settings
+                if (bus->alternates) {
+                        LKFREE(bus->alternates);
+                        bus->alternates = NULL;
+                }
+                bus->bNumInterfaces = 0;
+                bus->device_feature_settings = 0; 
+                bus->ConfigurationValue = 0; 
+        case STATE_CONFIGURED:
+                break;
+        case STATE_SUSPENDED:
+                // XXX Checkme - is suspend equivalent to end of session?
+                // C.f. OTG 6.5.1-6.5.3 imply that these must be reset at the end of a session or reset
+                //bus->device_feature_settings &= 
+                //        ~(FEATURE(USB_OTG_A_HNP_ENABLE) | FEATURE(USB_OTG_B_HNP_ENABLE) | FEATURE(USB_OTG_A_ALT_HNP_ENABLE)); 
+                break;
+        }
+        /* Pass the event to the bus interface driver and then the function driver and 
+         * any interface function drivers.
+         */
+        bus->driver->bops->event_handler (bus, event, data);
+        bus->function_instance->function_driver->fops->event_handler(bus->function_instance, event, data);
+        #if 0
+        // XXX pass to interface function drivers
+        #endif
+}
+
+/*! 
+ * usbd_bus_event_handler() - process bus event
+ * @param bus
+ * @param event
+ * @param data
+ */
+void usbd_bus_event_handler (struct usbd_bus_instance *bus, usbd_device_event_t event, int data)
+{
+        unsigned long flags;
+        local_irq_save (flags);
+        usbd_bus_event_handler_irq(bus, event, data);
+        local_irq_restore (flags);
+}
+
+OTG_EXPORT_SYMBOL(usbd_bus_event_handler);
+OTG_EXPORT_SYMBOL(usbd_bus_event_handler_irq);
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/*!
+ * Device Request Processing:
+ *	usbd_device_request()
+ *
+ */
+
+/*! 
+ * C.f. 9.4 Standard Requests and table 9.3
+ *
+ * Encode valid requests into a bitmap for each recipient type for 
+ * both directions. This is needed because there are some requests
+ * that appear to be a standard request but are not described in
+ * Chapter nine. For example the mouse driver hid request.
+ *
+ * So we only process the actual set of standard requests that are 
+ * defined in chapter nine and even if it appears to be standard but
+ * is not in chapter nine then we pass it to the function driver.
+ *
+ * @{
+ */
+
+#define STD(x) (1<<(x+1))
+
+/*! @{ */
+/*! h2d_standard_requests and d2h_standard_requests
+ *
+ * These tables list all of the valid Chapter Nine requests. Any request
+ * not listed in these tables will NOT be processed by the EP0 function and 
+ * will instead be passed to the appropriate function driver.
+ */
+u32 h2d_standard_requests[4] = {
+        // 0 - Device
+        STD(USB_REQ_CLEAR_FEATURE) |
+        STD(USB_REQ_SET_FEATURE) |
+        STD(USB_REQ_SET_ADDRESS) |
+        STD(USB_REQ_SET_DESCRIPTOR) |
+        STD(USB_REQ_SET_CONFIGURATION) ,
+        // 1 - Interface
+        STD(USB_REQ_CLEAR_FEATURE) |
+        STD(USB_REQ_SET_FEATURE) |
+        STD(USB_REQ_SET_INTERFACE) ,
+        // 2 - Endpoint
+        STD(USB_REQ_CLEAR_FEATURE) |
+        STD(USB_REQ_SET_FEATURE) ,
+        // 3 - Other
+        0,
+};
+
+u32 d2h_standard_requests[4] = {
+        // 0 - Device
+        STD(USB_REQ_GET_STATUS) |
+        STD(USB_REQ_GET_DESCRIPTOR) | 
+        STD(USB_REQ_GET_CONFIGURATION),
+        // 1 - Interface
+        STD(USB_REQ_GET_STATUS) |
+        STD(USB_REQ_GET_INTERFACE) ,
+        // 2 - Endpoint
+        STD(USB_REQ_GET_STATUS) |
+        STD(USB_REQ_SYNCH_FRAME) ,
+        // 3 - Other
+        0,
+};
+
+/* @} */
+
+
+/*!
+ * devreq_set_configuration() - process a received urb
+ *
+ * Used by a USB Bus interface driver to pass received device request to
+ * the appropriate USB Function driver.
+ *
+ * @param function
+ * @param request
+ * @return non-zero if errror
+ */
+static int devreq_set_configuration(struct usbd_function_instance *function, int wValue)
+{
+        struct usbd_bus_instance *bus = function->bus;
+        struct usbd_function_driver *function_driver = bus->function_instance->function_driver;
+        int bNumConfigurations = function_driver->bNumConfigurations;
+        int bNumInterfaces;
+        u8 ConfigurationValue;
+
+        struct usbd_configuration_instance *configuration_instance;
+        struct usbd_configuration_descriptor *configuration_descriptor;
+
+        // get rid of previous interface and alternates 
+        if (bus->bNumInterfaces && bus->alternates) {
+                bus->bNumInterfaces = 0;
+                LKFREE(bus->alternates);
+                bus->alternates = NULL;
+        }
+
+        // c.f. 9.4.7 - the top half of wValue is reserved
+        //
+        // c.f. 9.4.7 - zero is the default or addressed state, in our case this
+        // is the same is configuration zero, but will be fixed in usbd.c when used.
+
+        ConfigurationValue = wValue & 0x7f;
+
+        RETURN_EINVAL_IF(ConfigurationValue > bNumConfigurations);
+
+        /* save ConfigurationValue for GET_CONFIGURATION request
+         */
+        bus->ConfigurationValue = ConfigurationValue;
+
+        /* A ConfigurationValue of zero is for the default configuration (i.e.) the
+         * first one. A non-zero value needs to be decremented to allow it to be used
+         * as an index.
+         */
+        ConfigurationValue = !ConfigurationValue ? 0 : ConfigurationValue -1;
+
+        configuration_instance = 
+                &function_driver->configuration_instance_array[ConfigurationValue];
+
+        configuration_descriptor = configuration_instance->configuration_descriptor;
+
+        RETURN_EINVAL_IF(!configuration_descriptor);
+
+        bNumInterfaces = configuration_instance->bNumInterfaces;
+
+        /* reset interface and alternate settings
+         */
+        RETURN_EINVAL_IF (!(bus->alternates = (u8 *) CKMALLOC(bNumInterfaces, GFP_ATOMIC)));
+        bus->bNumInterfaces = bNumInterfaces;
+
+        /* Call function driver set_configuration() operation and if available any
+         * interface drivers set_configuration() operations.
+         */
+        if (function_driver->fops->set_configuration) {
+                function_driver->fops->function_enable && function_driver->fops->set_configuration (function, wValue);
+        }
+        /*
+         * XXX
+         */
+
+        usbd_bus_event_handler (bus, DEVICE_CONFIGURED, 0);
+        return 0;
+}
+
+/*!
+ * devreq_set_interface_altsetting() -
+ *
+ * Used by a USB Bus interface driver to pass received device request to
+ * the appropriate USB Function driver.
+ *
+ * @param function
+ * @param request
+ * @return non-zero if errror
+ */
+static int devreq_set_interface_altsetting(struct usbd_function_instance *function, int wIndex, int wValue)
+{
+        struct usbd_bus_instance *bus = function->bus;
+        struct usbd_function_driver *function_driver = function->function_driver;
+
+        RETURN_EINVAL_IF(wIndex > bus->bNumInterfaces);         // wIndex is interface
+        
+        bus->alternates[wIndex] = (u8) wValue;
+
+        /* Call function driver set_interface() operation and if available any
+         * interface drivers set_interface() operations.
+         */
+        if (function_driver->fops->set_interface)
+                function_driver->fops->function_enable && function_driver->fops->set_interface (function, wIndex, wValue);
+        /*
+         * XXX
+         */
+
+        usbd_bus_event_handler (bus, DEVICE_SET_INTERFACE, 0);
+
+        return 0;
+}
+
+/*!
+ * devreq_get_device_feature_settings() - process a received urb
+ *
+ * Used by a USB Bus interface driver to pass received device request to
+ * the appropriate USB Function driver.
+ *
+ * @param function
+ * @param request
+ * @return non-zero if errror
+ */
+int devreq_get_device_feature_settings(struct usbd_function_instance *function)
+{
+        struct usbd_bus_instance *bus = function->bus;
+        return bus->device_feature_settings;
+}
+
+
+/*! devreq_device_feature - handle set/clear feature requests for device
+ * Used by the USB Device Core to set/clear endpoint halt status.
+ *
+ * We assume that if the udc driver does not implement anything then 
+ * we should just return zero for ok.
+ */
+int devreq_device_feature (struct usbd_bus_instance *bus, int features, int flag)
+{
+        struct pcd_instance *pcd = (struct pcd_instance *)bus->privdata;
+        //u32 features = bus->device_feature_settings;
+
+        TRACE_MSG0(USBD, "BUS_DEVICE FEATURE");
+
+        /* if A-Device has enabled hnp 
+         */
+        if (features & FEATURE(USB_OTG_B_HNP_ENABLE) )
+                otg_event(pcd->otg, HNP_ENABLED, USBD, "DEVICE FEATURE - B_HNP_ENABLE");
+
+        /* if A-Device does not support HNP on this port
+         */
+        else if ( features & FEATURE(USB_OTG_A_ALT_HNP_ENABLE) )
+                ; //otg_event(pcd->otg, not(a_hnp_support));
+
+        /* if A-Device does support HNP
+         */
+        else if (features & FEATURE(USB_OTG_A_HNP_SUPPORT))
+                ; //otg_event(pcd->otg, a_hnp_support);
+
+        return 0;
+        //return usbd_pcd_ops.device_feature ? usbd_pcd_ops.device_feature() : 0;
+}
+
+/*! 
+ * copy_config() - copy data into buffer
+ */
+static int copy_config (u8 *cp, void *data, int actual_length, int max_buf)
+{
+        int available = max_buf - actual_length;
+        int length = MIN(*(u8 *)data, available);
+        RETURN_ZERO_UNLESS (data);
+        RETURN_ZERO_UNLESS (length);
+        memcpy (cp, data, length);
+        return length;
+}
+
+/*! 
+ * copy_endpoint() - copy data into buffer
+ */
+static int copy_endpoint (struct usbd_function_instance *function, u8 *cp,
+                struct usbd_endpoint_descriptor *endpoint, int endpoint_index, int actual_length, int max_buf, int hs)
+{
+        int available = max_buf - actual_length;
+        int length = MIN(endpoint->bLength, available);
+        struct usbd_endpoint_descriptor endpoint_copy;
+
+        RETURN_ZERO_IF (!length);
+        memcpy (&endpoint_copy, endpoint, endpoint->bLength);
+        usbd_endpoint_update(function, endpoint_index, &endpoint_copy, hs);
+        memcpy (cp, &endpoint_copy, length);
+        return length;
+}
+
+
+/*! 
+ * usbd_old_get_descriptor() - copy a descriptor into buffer
+ *
+ * Return non-zero for error.
+ */
+int usbd_old_get_descriptor (struct usbd_function_instance *function, u8 *buffer, int max, int descriptor_type, int index)
+{
+        struct usbd_bus_instance *bus = function->bus;
+        struct usbd_function_driver *function_driver = bus->function_instance->function_driver;
+        int actual_length = 0;
+
+        switch (descriptor_type) {
+        case USB_DT_DEVICE:
+                {
+                        struct usbd_device_descriptor *device_descriptor = function_driver->device_descriptor;
+
+                        // copy descriptor for this device
+                        actual_length += copy_config (buffer + actual_length, device_descriptor, actual_length, max);
+
+                        // correct the correct control endpoint 0 max packet size into the descriptor
+                        device_descriptor = (struct usbd_device_descriptor *) buffer;
+                        device_descriptor->bMaxPacketSize0 = bus->driver->maxpacketsize;
+                }
+                break;
+
+        #ifdef CONFIG_OTG_HIGH_SPEED
+        case USB_DT_DEVICE_QUALIFIER:      // c.f. 9.6.2 Device Qualifier
+                {
+                        struct usbd_device_qualifier_descriptor *device_qualifier_descriptor = 
+                                function_driver->device_qualifier_descriptor;
+
+                        // copy descriptor for this device
+                        actual_length += copy_config (buffer + actual_length, device_qualifier_descriptor, actual_length, max);
+
+                }
+                break;
+
+        case USB_DT_OTHER_SPEED_CONFIGURATION:
+        #endif /* CONFIG_OTG_HIGH_SPEED */
+
+        case USB_DT_CONFIGURATION:
+                {
+                        #ifdef CONFIG_OTG_HIGH_SPEED
+                        int hs = bus->HighSpeedFlag ?  descriptor_type == USB_DT_CONFIGURATION:
+                                descriptor_type == USB_DT_OTHER_SPEED_CONFIGURATION;
+                        #else /* CONFIG_OTG_HIGH_SPEED */
+                        int hs = 0;
+                        #endif /* CONFIG_OTG_HIGH_SPEED */
+                        int interface_num;
+
+                        struct usbd_configuration_instance *configuration_instance = 
+                                &function_driver->configuration_instance_array[index];
+
+                        struct usbd_configuration_descriptor *configuration_descriptor = 
+                                configuration_instance->configuration_descriptor;
+
+                        struct usbd_otg_descriptor *otg_descriptor = function_driver->otg_descriptor;
+
+                        RETURN_EINVAL_IF (!configuration_descriptor);
+                        RETURN_EINVAL_IF (index > function_driver->device_descriptor->bNumConfigurations);
+
+                        actual_length += copy_config (buffer + actual_length, configuration_descriptor, actual_length, max);
+
+                        // iterate across all bNumInterfaces for specified configuration
+                        for (interface_num = 0; interface_num < configuration_descriptor->bNumInterfaces; interface_num++) {
+
+                                int alternate_num;
+                                struct usbd_interfaces_instance *interfaces_instance =
+                                        configuration_instance->interfaces_instance_array + interface_num;
+
+                                // iterate across all interface alternates
+                                for (alternate_num = 0; alternate_num < interfaces_instance->alternates; alternate_num++) {
+
+                                        int class_num;
+                                        int endpoint;
+
+                                        struct usbd_alternate_instance *alternate_instance =
+                                                interfaces_instance->alternates_instance_array + alternate_num;
+
+                                        //struct usbd_interface_descriptor *usbd_interface_descriptor;
+
+                                        // copy descriptor for this interface
+                                        actual_length += copy_config (buffer + actual_length, 
+                                                        alternate_instance->interface_descriptor, actual_length, max);
+
+                                        // iterate across all classes for the alternate interface
+                                        for (class_num = 0; class_num < alternate_instance->classes; class_num++) 
+                                                actual_length += copy_config (buffer + actual_length, 
+                                                                *(alternate_instance->class_list + class_num), 
+                                                                actual_length, max);
+
+                                        // iterate across all endpoints for the alternate interface
+                                        //interface_descriptor = alternate_instance->interface_descriptor;
+
+                                        for (endpoint = 0; endpoint < alternate_instance->endpoints ; endpoint++) {
+
+                                                TRACE_MSG2(USBD, "endpoint: %d index: %d",
+                                                                endpoint, alternate_instance->endpoint_indexes[endpoint]);
+
+                                                actual_length += copy_endpoint (
+                                                                bus->function_instance, 
+                                                                buffer + actual_length, 
+                                                                *(( alternate_instance->endpoint_list) + endpoint), 
+                                                                alternate_instance->endpoint_indexes[endpoint],
+                                                                actual_length, 
+                                                                max, 
+                                                                hs);
+                                        }
+                                }
+                        }
+
+                        /* copy the OTG descriptor if required
+                         */
+                        actual_length += copy_config (buffer + actual_length, otg_descriptor, actual_length, max);
+
+                        /* set the configuration attributes and power fields in the configuration descriptor
+                         */
+                        configuration_descriptor = (struct usbd_configuration_descriptor *)buffer;
+
+                        configuration_descriptor->bmAttributes = BMATTRIBUTE_RESERVED;
+
+                        if (bus->device_feature_settings & FEATURE(USB_DEVICE_REMOTE_WAKEUP))
+                                configuration_descriptor->bmAttributes |= BMATTRIBUTE_REMOTE_WAKEUP;
+
+                        if (bus->driver->bMaxPower == 0) {
+                                configuration_descriptor->bmAttributes |= BMATTRIBUTE_SELF_POWERED;
+                                configuration_descriptor->bMaxPower  = 1;
+                        }
+                        else
+                                configuration_descriptor->bMaxPower  = bus->driver->bMaxPower;
+
+                        TRACE_MSG2(USBD, "bmAttributes: %02x bMaxPower: %02x", 
+                                        configuration_descriptor->bmAttributes, configuration_descriptor->bMaxPower);
+                }
+                break;
+
+        case USB_DT_STRING:
+                {
+                        struct usbd_string_descriptor *string_descriptor = NULL;
+                        RETURN_EINVAL_IF (!(string_descriptor = usbd_get_string_descriptor ((u8)index)));
+                        actual_length += copy_config (buffer + actual_length, string_descriptor, actual_length, max);
+                }
+                break;
+        default:
+                return -EINVAL;
+        }
+        return actual_length;
+}
+
+
+
+
+/*!
+ * setclear() - set or reset a bit in a mask
+ * @param features
+ * @param flag
+ * @param value
+ */
+static void setclear(u32 *features, u32 flag, u32 value)
+{
+        if (value) *features |= flag;
+        else *features &= ~flag;
+}
+
+/*! do_standard_device_request - process a device request
+ *
+ * Process a received device request. If not a Chapter nine request pass it
+ * to the other loaded function driver device_request() function.
+ *
+ * Return non-zero to indicate failure.
+ */
+static int do_standard_device_request (struct usbd_function_instance *function, struct usbd_device_request *request)
+{
+        struct usbd_bus_instance *bus = function->bus;
+        u8 bRequest = request->bRequest;
+        u8 bmRequestType = request->bmRequestType;
+        u16 wValue = le16_to_cpu(request->wValue);
+        u16 wIndex = le16_to_cpu(request->wIndex);
+        u16 wLength = le16_to_cpu(request->wLength);
+        u16 endpoint_index;
+
+        usbd_device_state_t device_state = usbd_get_device_state(function);
+
+        switch (device_state) {
+        case STATE_CREATED:
+        case STATE_ATTACHED:
+        case STATE_POWERED:
+                TRACE_MSG1(USBD, "bad device_state: %d", device_state);
+                return -EINVAL;
+
+        case STATE_INIT:
+        case STATE_DEFAULT:
+                switch (bRequest) {
+                case USB_REQ_CLEAR_FEATURE:
+                case USB_REQ_GET_INTERFACE:
+                case USB_REQ_GET_STATUS:
+                case USB_REQ_SET_DESCRIPTOR:
+                case USB_REQ_SET_INTERFACE:
+                case USB_REQ_SYNCH_FRAME:
+                        TRACE_MSG2(USBD, "bad request: %d for this device_state: %d", bRequest, device_state);
+                        return -EINVAL;
+
+                case USB_REQ_GET_CONFIGURATION:
+                case USB_REQ_SET_ADDRESS:
+                case USB_REQ_SET_CONFIGURATION:
+                case USB_REQ_GET_DESCRIPTOR:
+                case USB_REQ_SET_FEATURE:
+                        break;
+                }
+        case STATE_ADDRESSED:
+        case STATE_CONFIGURED:
+        case STATE_SUSPENDED:
+                break;
+        case STATE_UNKNOWN:
+                TRACE_MSG1(USBD, "unknown device_state: %d", device_state);
+                return -EINVAL;
+        }
+
+        /* Handle all requests that return data (direction bit set on bm RequestType).
+         * N.B. no Chapter 9 requests send additional data.
+         */
+        if ((bmRequestType & USB_REQ_DIRECTION_MASK)) {
+                struct usbd_urb *urb;
+                int rc = 0;
+                switch (bRequest) {
+                case USB_REQ_CLEAR_FEATURE:
+                case USB_REQ_SET_ADDRESS:
+                case USB_REQ_SET_CONFIGURATION:
+                case USB_REQ_SET_DESCRIPTOR:
+                case USB_REQ_SET_FEATURE:
+                case USB_REQ_SET_INTERFACE:
+                case USB_REQ_SYNCH_FRAME:
+                        TRACE_MSG0(USBD, "bad direction");
+                        return -EINVAL;
+                }
+
+                RETURN_EINVAL_IF(!wLength);
+
+                /* allocate urb, no callback, urb will be automatically de-allocated
+                 */
+                RETURN_EINVAL_IF(!(urb = usbd_alloc_urb_ep0 (function, wLength, NULL)));
+
+                switch (bRequest) {
+
+                case USB_REQ_GET_STATUS:
+                        urb->actual_length = 2;
+                        urb->buffer[0] = urb->buffer[1] = 0;
+
+                        rc = 0;
+                        switch (bmRequestType & USB_REQ_RECIPIENT_MASK) {
+                        case USB_REQ_RECIPIENT_DEVICE:
+
+                                UNLESS (usbd_get_bMaxPower(function)) urb->buffer[0] |= USB_STATUS_SELFPOWERED;
+                                urb->buffer[0] |= 
+                                        (devreq_get_device_feature_settings(function) & FEATURE(USB_DEVICE_REMOTE_WAKEUP)) ? 
+                                        USB_STATUS_REMOTEWAKEUP : 0;
+                                break;
+                        case USB_REQ_RECIPIENT_ENDPOINT:
+                                RETURN_EINVAL_UNLESS((endpoint_index = usbd_find_endpoint_index(bus, wIndex)) < bus->endpoints);
+                                urb->buffer[0] = usbd_endpoint_halted (function, endpoint_index);
+                                break;
+                        case USB_REQ_RECIPIENT_INTERFACE:
+                                break;
+                        case USB_REQ_RECIPIENT_OTHER:
+                        default:
+                                TRACE_MSG0(USBD, "bad recipient");
+                                rc = -EINVAL;
+                        }
+                        break;
+
+                case USB_REQ_GET_DESCRIPTOR:
+                        rc = usbd_old_get_descriptor (function, urb->buffer, wLength, wValue >> 8, wValue & 0xff);
+                        if (rc != -EINVAL) {
+                                urb->actual_length = rc;
+                                rc = 0;
+                        }
+                        else
+                                TRACE_MSG0(USBD, "bad description");
+                        break;
+
+                case USB_REQ_GET_CONFIGURATION:
+                        TRACE_MSG1(USBD, "GET CONFIGURATION: %d", bus->ConfigurationValue);
+                        urb->actual_length = 1; 
+                        urb->buffer[0] = bus->ConfigurationValue;
+                        break;
+
+                case USB_REQ_GET_INTERFACE:
+                        RETURN_EINVAL_IF(wIndex > bus->bNumInterfaces);
+                        urb->actual_length = 1; 
+                        urb->buffer[0] = bus->alternates[wIndex];
+                        break;
+                default:
+                        TRACE_MSG0(USBD, "bad descriptor type");
+                        rc = 1;
+                }
+
+                if (!(urb->actual_length % usbd_endpoint_zero_wMaxPacketSize(function, usbd_high_speed(function))) && 
+                                (urb->actual_length < wLength)) 
+                        urb->flags |= USBD_URB_SENDZLP;
+                
+                RETURN_ZERO_UNLESS(rc || usbd_start_in_urb(urb));
+                /* only get here if error */
+                usbd_free_urb(urb);
+                TRACE_MSG0(USBD, "get failed");
+                return -EINVAL;
+        }
+        /* Handle the requests that do not return data. 
+         */
+        else {
+                int setclear_flag = USB_REQ_SET_FEATURE == bRequest;
+                switch (bRequest) {
+                case USB_REQ_CLEAR_FEATURE:
+                case USB_REQ_SET_FEATURE:
+                        TRACE_MSG2(USBD, "FEATURE: recipient: %d wValue: %d", 
+                                        bmRequestType & USB_REQ_RECIPIENT_MASK, wValue);
+                        switch (bmRequestType & USB_REQ_RECIPIENT_MASK) {
+                        case USB_REQ_RECIPIENT_DEVICE:
+                                //switch (wValue) {
+                                //        otg_event(pcd->otg, HNP_ENABLED, PCD, "DEVICE FEATURE - B_HNP_ENABLE");
+                                //        break;
+                                //}
+                                switch (wValue) {
+                                case USB_OTG_A_ALT_HNP_ENABLE:                  // C.f. OTG 6.5.3
+                                case USB_OTG_A_HNP_SUPPORT:                     // C.f. OTG 6.5.2
+                                case USB_OTG_B_HNP_ENABLE:                      // C.f. OTG 6.5.1
+                                        RETURN_EINVAL_UNLESS(setclear_flag);    // cleared by reset
+                                case USB_DEVICE_REMOTE_WAKEUP:
+                                        break;
+                                default:
+                                        return -EINVAL;
+                                }
+                                setclear(&bus->device_feature_settings, FEATURE(wValue), setclear_flag);
+                                return devreq_device_feature(bus, FEATURE(wValue), setclear_flag);
+
+                        case USB_REQ_RECIPIENT_ENDPOINT:
+                                RETURN_EINVAL_UNLESS(USB_ENDPOINT_HALT == wValue);
+
+                                setclear(&(bus->endpoint_array[wIndex].feature_setting), 
+                                                FEATURE(wValue), bRequest == USB_REQ_SET_FEATURE);
+
+                                /* wIndex contains bEndpointAddress, also find and verify the endpoint map index as well. 
+                                 * Then clear the endpoint using the bus interface driver halt_endpoint() operation,
+                                 * if that is ok, then inform the function driver using the endpoint_cleared() operation.
+                                 *
+                                 */
+                                RETURN_EINVAL_UNLESS((endpoint_index = usbd_find_endpoint_index(bus, wIndex)) < bus->endpoints);
+                                RETURN_EINVAL_IF(function->bus->driver->bops->halt_endpoint(bus, wIndex,
+                                                        endpoint_index, setclear_flag));
+
+                                if (function->function_driver->fops->endpoint_cleared && !setclear_flag)
+                                        function->function_driver->fops->endpoint_cleared(function, wIndex, endpoint_index );
+
+                                return 0;
+
+                        case USB_REQ_RECIPIENT_INTERFACE:
+                        case USB_REQ_RECIPIENT_OTHER:
+                        default:
+                                TRACE_MSG0(USBD, "bad recipient");
+                                return -EINVAL;
+                        }
+
+                case USB_REQ_SET_ADDRESS:
+                        if (bus->driver->bops->set_address)  bus->driver->bops->set_address (bus, wValue);
+                        usbd_bus_event_handler (bus, DEVICE_ADDRESS_ASSIGNED, wValue);
+                        return 0;
+
+                case USB_REQ_SET_DESCRIPTOR:
+                        TRACE_MSG0(USBD, "set descriptor not supported");
+                        return -EINVAL;
+
+                case USB_REQ_SET_CONFIGURATION:
+                        return devreq_set_configuration(function, wValue);
+
+                case USB_REQ_SET_INTERFACE:
+                        return devreq_set_interface_altsetting(function, wIndex, wValue);
+
+                case USB_REQ_GET_CONFIGURATION:
+                case USB_REQ_GET_DESCRIPTOR:
+                case USB_REQ_GET_INTERFACE:
+                case USB_REQ_GET_STATUS:
+                case USB_REQ_SYNCH_FRAME: 
+                        TRACE_MSG0(USBD, "unkown");
+                        return -EINVAL;
+                }
+        }
+        TRACE_MSG0(USBD, "not possible");
+        return -EINVAL;
+}
+
+
+/*!
+ * usbd_device_request() - process a device request
+ *
+ * Used by a USB Bus interface driver to pass received device request to
+ * the appropriate USB Function driver.
+ *
+ * @param function
+ * @param request
+ * @return non-zero if errror
+ */
+int usbd_device_request(struct usbd_bus_instance *bus, struct usbd_device_request *request)
+{
+        struct usbd_function_instance *function = bus->function_instance;
+        u8 bRequest = request->bRequest;
+        u8 bmRequestType = request->bmRequestType;
+        u16 wValue = le16_to_cpu(request->wValue);
+        u16 wIndex = le16_to_cpu(request->wIndex);
+        u16 wLength = le16_to_cpu(request->wLength);
+
+        TRACE_MSG5(USBD, "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x",
+                        bmRequestType, bRequest, wValue, wIndex, wLength);
+
+        /* Handle only USB Standard Requests (c.f. USB Spec table 9-2, D6..5 must be 0),
+         * otherwise call the currently enabled function specific receive setup.
+         */
+        if (!(bmRequestType & USB_REQ_TYPE_MASK) && 
+                                ((bmRequestType & USB_DIR_IN ?  d2h_standard_requests : h2d_standard_requests)
+                                [bmRequestType & 0x3] & STD(bRequest)))
+                return do_standard_device_request(function, request);
+
+        /* Standard Requests not in Chapter nine, Class and Vendor device requests
+         * must be handled by the function driver or interface driver as appropriate.
+         */
+        switch(bmRequestType & USB_REQ_RECIPIENT_MASK) {
+        case USB_REQ_RECIPIENT_INTERFACE:
+        case USB_REQ_RECIPIENT_ENDPOINT:
+                /* XXX
+                 * if function->interfaces[] is valid then we shuffle request off to
+                 * interface driver for interface and endpoint recipients, otherwise
+                 * fall through.
+                 */
+
+                /*
+                 * XXX for now just fall through for all.
+                 */
+                
+        case USB_REQ_RECIPIENT_DEVICE:
+        case USB_REQ_RECIPIENT_OTHER:
+        default:
+                return function->function_driver->fops->device_request(function, request);
+        }
+}
+
+OTG_EXPORT_SYMBOL(usbd_device_request);
+OTG_EXPORT_SYMBOL(usbd_old_get_descriptor);
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/*!
+ * Device I/O:
+ *      usbd_urb_finished()
+ *      usbd_first_urb_detached()
+ *      usbd_find_endpoint_address()
+ */
+
+/*!
+ * do_urb_callback() - tell function that an urb has been transmitted.
+ *
+ * Must be called from an interrupt or with interrupts disabled.
+ *
+ * Used by a USB Bus driver to pass a sent urb back to the function
+ * driver via the endpoints done queue.
+ *
+ * If there is no callback or if the URB call back returns non-zero then the
+ * urb must be de-allocated here.
+ *
+ * @param urb
+ * @param rc
+ */
+static void do_urb_callback (struct usbd_urb *urb, int rc)
+{
+        RETURN_UNLESS (urb);
+        if (!urb->callback || urb->callback(urb,rc))
+                usbd_free_urb(urb);
+}
+
+/*!
+ * urb_append_irq() - append a linked list of urbs to another linked list
+ * @param hd link to urb list
+ * @param urb to append to list
+ */
+static INLINE void urb_append_irq (urb_link * hd, struct usbd_urb *urb)
+{
+        urb_link *new;
+        urb_link *pul;
+        RETURN_UNLESS (hd && urb);
+        new = &urb->link;
+        pul = hd->prev;
+        new->prev->next = hd;
+        hd->prev = new->prev;
+        new->prev = pul;
+        pul->next = new;
+}
+
+/*!
+ * urb_append() - irq safe version
+ * @param hd list of urbs
+ * @param urb urb to append
+ */
+void urb_append(urb_link *hd, struct usbd_urb *urb)
+{
+        unsigned long flags;
+        local_irq_save (flags);
+        urb_append_irq(hd, urb);
+        local_irq_restore (flags);
+}
+
+
+/*!
+ * usbd_urb_finished() - tell function that an urb has been finished.
+ *
+ * Used by a USB Bus driver to pass a sent urb back to the function
+ * driver via the endpoints finished queue.
+ * @param urb urb to process
+ * @param rc result code
+ *
+ */
+void usbd_urb_finished(struct usbd_urb *urb, int rc)
+{
+        urb->status = (usbd_urb_status_t)rc;
+        #if defined(OTG_LINUX)
+        urb->jiffies = jiffies;
+        #endif /* defined(OTG_LINUX) */
+        if (USBD_OK != urb->bus->status)
+                do_urb_callback (urb, rc);
+        else {
+                urb_append_irq (&(urb->bus->finished), urb);
+                RETURN_IF (PENDING_WORK_ITEM(urb->bus->device_bh));
+#ifdef LINUX24
+		//FIXME XXX
+                queue_task (&urb->bus->device_bh, &tq_immediate);
+                mark_bh (IMMEDIATE_BH);
+#else
+		SCHEDULE_WORK(urb->bus->device_bh);
+#endif
+        }
+}
+void usbd_urb_finished_irq (struct usbd_urb *urb, int rc)
+{
+        usbd_urb_finished(urb, rc);
+}
+
+/*!
+ * @name STRUCT
+ * @brief
+ * Structure member address manipulation macros.
+ *
+ * These are used by client code (code using the urb_link routines), since
+ * the urb_link structure is embedded in the client data structures.
+ *
+ * Note: a macro offsetof equivalent to member_offset is defined in stddef.h
+ *       but this is kept here for the sake of portability.
+ *
+ * p2surround returns a pointer to the surrounding structure given
+ * type of the surrounding structure, the name memb of the structure
+ * member pointed at by ptr.  For example, if you have:
+ *
+ *      struct foo {
+ *          int x;
+ *          float y;
+ *          char z;
+ *      } thingy;
+ *
+ *      char *cp = &thingy.z;
+ *
+ * then
+ *      &thingy == p2surround(struct foo, z, cp)
+ *
+ * @{
+ */
+
+#define _cv_(ptr)                 ((char*)(void*)(ptr))
+#define member_offset(type,memb)  (_cv_(&(((type*)0)->memb))-(char*)0)
+#define p2surround(type,memb,ptr) ((type*)(void*)(_cv_(ptr)-member_offset(type,memb)))
+
+/*!
+ * @name list
+ * @brief List support functions
+ *
+ * @{
+ */
+
+/*!
+ * urb_link() - return first urb_link in list
+ *
+ * Return the first urb_link in a list with a distinguished
+ * head "hd", or NULL if the list is empty.  This will also
+ * work as a predicate, returning NULL if empty, and non-NULL
+ * otherwise.
+ *
+ * Called from interrupt.
+ *
+ * @return link to urb
+ */
+static INLINE urb_link *first_urb_link_irq (urb_link * hd)
+{
+        urb_link *nx;
+        return (!hd || !(nx = hd->next) || (nx == hd)) ? NULL : nx;
+}
+
+/*!
+ * first_urb_irq() - return first urb in list
+ * Return the first urb in a list with a distinguished
+ * head "hd", or NULL if the list is empty.
+ *
+ * Called from interrupt.
+ *
+ * @param hd linked list of urbs
+ * @return pointer to urb
+ */
+static INLINE struct usbd_urb *first_urb_irq (urb_link * hd)
+{
+        urb_link *nx;
+        return (!(nx = first_urb_link_irq (hd))) ? NULL : p2surround (struct usbd_urb, link, nx);
+}
+
+
+
+/*!
+ * usbd_first_urb_detached_irq() - detach an return first urb
+ * Detach and return the first urb in a list with a distinguished
+ * head "hd", or NULL if the list is empty.
+ *
+ * @param hd linked list of urbs
+ * @return pointer to urb or NULL
+ */
+struct usbd_urb *usbd_first_urb_detached_irq (urb_link * hd)
+{
+        struct usbd_urb *urb;
+        urb_link *ul;
+        RETURN_NULL_IF (!(urb = first_urb_irq (hd)));
+        ul = &urb->link;
+        ul->next->prev = ul->prev;
+        ul->prev->next = ul->next;
+        ul->prev = ul->next = ul;
+        return urb;
+}
+/* @} */
+
+/*!
+ * usbd_first_urb_detached() - detach and return urb
+ *
+ * Detach and return the first urb in a list with a distinguished
+ * head "hd", or NULL if the list is empty.
+ *
+ * @param hd list of urbs
+ * @return pointer to urb or NULL
+ */
+struct usbd_urb *usbd_first_urb_detached (urb_link * hd)
+{
+        struct usbd_urb *urb;
+        unsigned long flags;
+        local_irq_save (flags);
+        urb = usbd_first_urb_detached_irq (hd);
+        local_irq_restore (flags);
+        return urb;
+}
+
+
+/*!
+ * usbd_find_endpoint_index()
+ * @param bus
+ * @param bEndpointAddress
+ * Find the endpoint map index for the specified bEndpointAddress.
+ */
+int usbd_find_endpoint_index(struct usbd_bus_instance *bus, int bEndpointAddress)
+{
+        int i;
+        for (i = 0; i < bus->endpoints; i++)
+                BREAK_IF (bus->endpoint_array[i].bEndpointAddress == bEndpointAddress);
+        return i;
+}
+
+OTG_EXPORT_SYMBOL(usbd_urb_finished);
+OTG_EXPORT_SYMBOL(usbd_urb_finished_irq);
+OTG_EXPORT_SYMBOL(usbd_first_urb_detached);
+OTG_EXPORT_SYMBOL(usbd_first_urb_detached_irq);
+OTG_EXPORT_SYMBOL(usbd_find_endpoint_index);
+
+/* ********************************************************************************************** */
+/* usbb bus bottom half ************************************************************************* */
+
+/*! 
+ * usbd_device_bh() -  Bottom half handler to process sent or received urbs.
+ * @param data
+ */
+void usbd_device_bh (void *data)
+{
+        struct usbd_bus_instance *bus = data;
+        struct usbd_endpoint_instance *endpoint;
+        struct usbd_urb *urb;
+
+        RETURN_IF (!bus || !(endpoint = bus->endpoint_array));
+        DOWN(&usbd_bus_sem);
+
+        for (; (urb = usbd_first_urb_detached (&bus->finished)); do_urb_callback (urb, urb->status));
+
+        #if defined(OTG_LINUX)
+        if (USBD_CLOSING == bus->status)
+                bus->device_bh.data = NULL;
+        #endif /* defined(OTG_LINUX) */
+        UP(&usbd_bus_sem);
+}
+
+/* ********************************************************************************************** */
+/* Module init ********************************************************************************** */
+
+extern char * usbd_function_name(int n);
+struct usbd_ops usbd_ops;
+otg_tag_t USBD;
+
+/*!
+ * usbd_device_init() - initialize
+ */
+int usbd_device_init (void)
+{
+        USBD = otg_trace_obtain_tag();
+        TRACE_MSG0(USBD,"--");
+        usbd_ops.function_name = usbd_function_name;
+        otg_set_usbd_ops(&usbd_ops);
+        return 0;
+}
+
+/*!
+ * usbd_device_exit() - de-initialize
+ */
+void usbd_device_exit (void)
+{
+        otg_set_usbd_ops(NULL);
+        otg_trace_invalidate_tag(USBD);
+}
+
+
diff -uNr linux/drivers/no-otg/otgcore/usbp-fops.c linux/drivers/otg/otgcore/usbp-fops.c
--- linux/drivers/no-otg/otgcore/usbp-fops.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/usbp-fops.c	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,1123 @@
+/*
+ * otg/otgcore/usbp-fops.c - USB Function support
+ *
+ *      Copyright (c) 2004-2005 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/otgcore/usbp-fops.c
+ * @brief Function driver related functions.
+ *
+ * This implements the functions used to implement USB Function drivers.
+ *
+ * @ingroup USBP
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#include <otg/usbp-chap9.h>
+#include <otg/otg-trace.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+
+
+struct usbd_string_descriptor **usb_strings;
+void urb_append(urb_link *hd, struct usbd_urb *urb);
+
+LIST_NODE_INIT(usbd_function_instances);      // list of all registered configuration function modules
+LIST_NODE_INIT(usbd_interface_instances);          // list of all registered interface function modules
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/*!
+ * Function Registration:
+ *	usbd_register_function()
+ *	usbd_register_interface()
+ *	usbd_register_composite()
+ *	usbd_deregister_function()
+ *	usbd_find_function()
+ *	usbd_find_interface()
+ *
+ */
+
+/*!
+ * usbd_register_function_internal() - register a usbd function driver
+ *
+ * USBD Function drivers call this to register with the USBD Core layer.
+ * Return NULL on failure.
+ *
+ * @param function_driver
+ * @param privdata
+ * @return function instance
+ *
+ */
+static struct usbd_function_instance *
+usbd_register_function_internal(struct usbd_function_driver *function_driver, char *name, 
+                usbd_function_types_t function_type, char **interface_list, void *privdata)
+{
+        struct usbd_function_instance *function = NULL;
+
+        TRACE_MSG3(USBD, "interface: %s driver: %s endpoints: %d", name, 
+                        function_driver->name, function_driver->endpointsRequested);
+
+        if (!(function = (struct usbd_function_instance *) CKMALLOC (sizeof (struct usbd_function_instance), GFP_KERNEL))) {
+                #if defined(OTG_LINUX)
+                printk(KERN_ERR,"usbd_function_instance allocation failed.\n");
+                #endif /* defined(OTG_LINUX) */
+                #if defined(OTG_WINCE)
+                DEBUGMSG(ZONE_INIT, (_T("usbd_register_function: FAILED\n")));
+                #endif /* defined(OTG_LINUX) */
+                return(NULL);
+        }
+        function->name = LSTRDUP(name);
+        function->function_driver = function_driver;
+        function->privdata = privdata;
+        function->function_type = function_type;
+        function->interfaces_list = interface_list;
+
+        //function->endpointsRequested = function->function_driver->endpointsRequested;
+        //function->requestedEndpoitns = function->function_driver->requestedEndpoints;
+
+        switch(function_type) {
+        case function_simple:
+        case function_interface:
+                break;
+        case function_composite:
+                break;
+        }
+
+        if (!(function->endpoint_map_array = (struct usbd_endpoint_map *)
+                                CKMALLOC (sizeof(struct usbd_endpoint_map) * 
+                                        function_driver->endpointsRequested, GFP_KERNEL))) {
+                #if defined(OTG_LINUX)
+                printk(KERN_ERR,"usbd_endpoint_map allocation failed.\n");
+                #endif /* defined(OTG_LINUX) */
+                #if defined(OTG_WINCE)
+                DEBUGMSG(ZONE_INIT, (_T("usbd_register_function: FAILED\n")));
+                #endif /* defined(OTG_LINUX) */
+                LKFREE(function);
+                return(NULL);
+        }
+
+        switch(function_type) {
+        case function_simple:
+        case function_interface:
+        case function_composite:
+                break;
+        }
+        return function;
+}
+
+/*!
+ * usbd_register_function() - register a usbd function driver
+ *
+ * USBD Function drivers call this to register with the USBD Core layer.
+ * Return NULL on failure.
+ *
+ * @param function_driver
+ * @param privdata
+ * @return function instance
+ *
+ */
+struct usbd_function_instance *
+usbd_register_function (struct usbd_function_driver *function_driver, char * name, void *privdata)
+{
+        struct usbd_function_instance *function = 
+                usbd_register_function_internal(function_driver, name, function_simple, NULL, privdata);
+        TRACE_MSG1(USBD, "%s", name);
+
+        LIST_ADD_TAIL (&function->instances, &usbd_function_instances);
+        return function;
+}
+
+/*!
+ * usbd_register_interface() - register a usbd function driver
+ *
+ * USBD Function drivers call this to register with the USBD Core layer.
+ * Return NULL on failure.
+ *
+ * @param function_driver
+ * @param privdata
+ * @return function instance
+ *
+ */
+struct usbd_function_instance *
+usbd_register_interface(struct usbd_function_driver *function_driver, char * name, void *privdata)
+{
+        struct usbd_function_instance *function = 
+                usbd_register_function_internal(function_driver, name, function_interface, NULL, privdata);
+        TRACE_MSG1(USBD, "%s", name);
+        LIST_ADD_TAIL (&function->instances, &usbd_interface_instances);
+        return function;
+}
+
+/*!
+ * usbd_register_composite() - register a usbd function driver
+ *
+ * USBD Function drivers call this to register with the USBD Core layer.
+ * Return NULL on failure.
+ *
+ * @param function_driver
+ * @param privdata
+ * @return function instance
+ *
+ */
+struct usbd_function_instance *
+usbd_register_composite (struct usbd_function_driver *function_driver, char * name, char **interfaces_list, void *privdata)
+{
+        struct usbd_function_instance *function = NULL;
+        struct usbd_function_instance **interfaces_array = NULL;
+        struct usbd_endpoint_request *requestedEndpoints = NULL;
+        struct usbd_endpoint_map *endpoint_map_array = NULL;
+
+        int i, j, k, l;
+        char *interface_name;
+        int endpoints = 0;
+        int cfg_length = 0;
+
+        TRACE_MSG1(USBD, "%s", name);
+        THROW_UNLESS((function = usbd_register_function_internal(function_driver, 
+                                        name, function_composite, interfaces_list, privdata)), error);
+
+        /* list and count interfaces, then allocate interfaces_array.
+         */
+        for (i = 0; (interface_name = function->interfaces_list[i]); i++) {
+                TRACE_MSG2(USBD, "INTERFACE[%02d] %20s", i, interface_name);
+        }
+        function->interfaces = i;
+        
+        TRACE_MSG1(USBD, "interfaces: %d", function->interfaces);
+
+        THROW_UNLESS((interfaces_array = (struct usbd_function_instance **) 
+                                CKMALLOC (sizeof(struct usbd_function_instance) * function->interfaces, GFP_KERNEL)), error);
+        function->interfaces_array = interfaces_array;
+
+#if 0
+        /* Find all interfaces and compose the interface list, count the endpoints 
+         * and allocte the endpoint request array. Also find and total descriptor sizes.
+         */
+        for (i = 0; i < function->interfaces; i++) {
+                struct usbd_function_instance *interface_function;
+                struct usbd_interface_description *interface_description = interface_function->interface_list;
+                THROW_UNLESS(interface_function = usbd_find_interface(interfaces_list[i]), error);
+
+                TRACE_MSG4(USBD, "interface_function: %x name: %s driver: %s %d", interface_function, 
+                                interface_function->name, 
+                                interface_function->function_driver->name, 
+                                interface_function->function_driver->endpointsRequested);
+
+                interfaces_array[i] = interface_function;
+                endpoints += interface_function->function_driver->endpointsRequested;
+                TRACE_MSG4(USBD, "ENDPOINT [%02d] %20s %02d %02d", 
+                                i, interfaces_list[i], interface_function->function_driver->endpointsRequested, endpoints);
+
+                /* iterate across all interface descriptions */
+                for (j = 0; j < bNumInterfaces; j++) {
+                        struct usbd_alternate_instance *alternate_instance = interface_description[j];
+                        
+                        /* iterate across all alternates for this interface */
+                        for (k = 0; k < interface_description[j].alternates; k++) {
+
+                                
+
+                        }
+                }
+
+        }
+#endif
+        function->endpoints = endpoints;
+        TRACE_MSG2(USBD, "endpoints: %d %d", endpoints, function->endpoints);
+
+
+        /* requeset the endpoints from the bus interface driver
+         */
+        THROW_UNLESS((requestedEndpoints = (struct usbd_endpoint_request *) 
+                                CKMALLOC (sizeof(struct usbd_endpoint_request) * function->endpoints, GFP_KERNEL)), error);
+
+        function->requestedEndpoints = requestedEndpoints;
+#if 0
+        /* we need to compose the endpoint request array
+         */
+        for (endpoints = 0, i = 0; i < function->interfaces; i++) {
+                struct usbd_function_instance *interface_function = interfaces_array[i];
+                struct usbd_interface_description *interface_description = interface_function->interface_list;
+
+                for (j = 0; j < interface_function->endpoints; j++) {
+                        memcpy(&requestedEndpoints[endpoints], &interface_function->requestedEndpoints[j],
+                                        sizeof(struct usbd_endpoint_request));
+                        requestedEndpoints[endpoints].interface_num = i;
+                }
+        }
+#endif
+
+
+        /* Insert into function list
+         */
+        LIST_ADD_TAIL (&function->instances, &usbd_function_instances);
+        return function;
+
+        CATCH(error) {
+                if (requestedEndpoints) LKFREE(requestedEndpoints);
+                if (interfaces_array) LKFREE(interfaces_array);
+                if (function) usbd_deregister_function(function);
+                return NULL;
+        }
+}
+
+/*! 
+ * usbd_deregister_function() - de-register a usbd function driver instance
+ *
+ * USBD Function drivers call this to de-register with the USBD Core layer.
+ * @param function_instance
+ */
+void usbd_deregister_function (struct usbd_function_instance *function_instance)
+{
+        RETURN_UNLESS (function_instance);
+        LIST_DEL (function_instance->instances);
+        if (function_instance->name) LKFREE(function_instance->name);
+        if (function_instance->endpoint_map_array) LKFREE(function_instance->endpoint_map_array);
+        LKFREE(function_instance);
+}
+
+/*!
+ * usbd_find_function_internal() - register a usbd function driver
+ *
+ * USBD Function drivers call this to register with the USBD Core layer.
+ * Return NULL on failure.
+ *
+ * @param name
+ * @return function instance
+ *
+ */
+static struct usbd_function_instance *
+usbd_find_function_internal(LIST_NODE *usbd_function_instances, char *name)
+{
+        int len = name ? strlen(name) : 0;
+        LIST_NODE *lhd = NULL;
+        TRACE_MSG1(USBD, "%s", name);
+        LIST_FOR_EACH (lhd, usbd_function_instances) {
+
+		struct usbd_function_instance *function = LIST_ENTRY (lhd, struct usbd_function_instance, instances);
+                struct usbd_function_driver *function_driver;
+                function_driver = function->function_driver;
+                printk(KERN_ERR"%s: name: %s len: %d function: %s\n", __FUNCTION__, name ? name : "", len, function_driver->name);
+                CONTINUE_IF(len || strncmp(function_driver->name, name, len));
+
+                TRACE_MSG5(USBD, "%s %s %d %s %d", name, function->name, len,
+                                function->function_driver->name,
+                                function->function_driver->endpointsRequested);
+                CONTINUE_IF(len && strncmp(function->name, name, len));
+
+                TRACE_MSG4(USBD, "FOUND %s %x %s %d", name, function, 
+                                function->function_driver->name,
+                                function->function_driver->endpointsRequested);
+
+                return function;
+
+                //struct usbd_function_driver *function_driver = function->function_driver;
+                //printk(KERN_ERR"%s: name: %s len: %d function: %s\n", __FUNCTION__,name?name : "", len, function_driver->name);
+                //CONTINUE_IF(len || strncmp(function_driver->name, name, len));
+        }
+        return NULL;
+}
+
+
+/*!
+ * usbd_find_function() - register a usbd function driver
+ *
+ * USBD Function drivers call this to register with the USBD Core layer.
+ * Return NULL on failure.
+ *
+ * @param name
+ * @return function instance
+ *
+ */
+struct usbd_function_instance *
+usbd_find_function (char *name)
+{
+        return usbd_find_function_internal(&usbd_function_instances, name);
+}
+
+/*!
+ * usbd_default_function() - register a usbd function driver
+ *
+ * USBD Function drivers call this to register with the USBD Core layer.
+ * Return NULL on failure.
+ *
+ * @param name
+ * @return function instance
+ *
+ */
+struct usbd_function_instance *
+usbd_default_function (char *name)
+{
+        return usbd_find_function_internal(&usbd_function_instances, "");
+}
+
+/*!
+ * usbd_find_interface() - register a usbd function driver
+ *
+ * USBD Function drivers call this to register with the USBD Core layer.
+ * Return NULL on failure.
+ *
+ * @param name
+ * @return function instance
+ *
+ */
+struct usbd_function_instance *usbd_find_interface(char *name)
+{
+        TRACE_MSG1(USBD, "%s", name);
+        return usbd_find_function_internal(&usbd_interface_instances, name);
+}
+
+
+/*! 
+ * usbd_function_name() - return name of nth function driver
+ * @param n index to function name
+ */
+char * usbd_function_name(int n)
+{
+        struct usbd_function_instance *function = NULL;
+        LIST_NODE *lhd = NULL;
+
+        LIST_FOR_EACH (lhd, &usbd_function_instances) {
+                struct usbd_function_driver *function_driver;
+                function = LIST_ENTRY (lhd, struct usbd_function_instance, instances);
+                function_driver = function->function_driver;
+
+                TRACE_MSG2(USBD, "name: [%d] %s", n, function_driver->name);
+
+                CONTINUE_IF(n--);
+                return (char *)function_driver->name;
+        };
+        return NULL;
+}
+
+OTG_EXPORT_SYMBOL(usbd_register_function);
+OTG_EXPORT_SYMBOL(usbd_register_interface);
+OTG_EXPORT_SYMBOL(usbd_register_composite);
+OTG_EXPORT_SYMBOL(usbd_deregister_function);
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/*!
+ * String Descriptors:
+ *	usbd_alloc_string_descriptor()
+ *	usbd_free_string_descriptor()
+ *	usbd_get_string_descriptor()
+ */
+
+#define LANGID_ENGLISH          "\011"
+#define LANGID_US_ENGLISH       "\004"
+#define LANGIDs  LANGID_US_ENGLISH LANGID_ENGLISH
+
+/*!
+ * usbd_alloc_string_zero() - allocate a string descriptor and return index number
+ *
+ * Find an empty slot in index string array, create a corresponding descriptor
+ * and return the slot number.
+ *
+ * @param str string to allocate
+ * @return the slot number
+ */
+static u8 usbd_alloc_string_zero (char *str)
+{
+        u8 bLength;
+        u16 *wData;
+        struct usbd_string_descriptor *string = NULL;
+
+        RETURN_ZERO_IF(usb_strings[0] != NULL);
+
+        bLength = sizeof (struct usbd_string_descriptor) + strlen (str);
+
+        RETURN_ZERO_IF(!(string = (struct usbd_string_descriptor *) CKMALLOC (bLength, GFP_KERNEL)));
+
+        string->bLength = bLength;                              // set descriptor length
+        string->bDescriptorType = USB_DT_STRING;                // set descriptor type
+
+        for (wData = string->wData; *str; str += 2, wData++)    // copy
+                *wData = (u16) ((str[0] << 8 | str[1]));
+
+        usb_strings[0] = string;                                // save in string index array
+        return 0;
+}
+
+int usbd_maxstrings = 40;
+
+/*!
+ * usbd_strings_init() - initialize usb strings pool
+ */
+int usbd_strings_init (void)
+{
+        //TRACE_MSG0(USBD, "entered");
+        RETURN_ZERO_IF(usb_strings);
+        usbd_maxstrings = MIN(usbd_maxstrings, 254);
+
+        RETURN_EINVAL_IF (!(usb_strings = CKMALLOC (sizeof (struct usbd_string_descriptor *) * usbd_maxstrings, GFP_KERNEL)));
+        if (usbd_alloc_string_zero (LANGIDs) != 0) {
+                LKFREE (usb_strings);
+                return -1;
+        }
+        return 0;
+}
+
+/*!
+ * usbd_strings_exit() - de-initialize usb strings pool
+ */
+void usbd_strings_exit(void)
+{
+        int i;
+        //TRACE_MSG0(USBD, "entered");
+        RETURN_IF (!usb_strings);
+        for (i = 0; i < usbd_maxstrings; i++)
+                usbd_free_string_descriptor((u8)i);
+        LKFREE (usb_strings);
+        usb_strings = NULL;
+}
+
+
+/*! 
+ * usbd_get_string_descriptor() - find and return a string descriptor
+ *
+ * Find an indexed string and return a pointer to a it.
+ * @param index of string
+ * @return pointer to string descriptor or NULL
+ */
+struct usbd_string_descriptor *usbd_get_string_descriptor (u8 index)
+{
+        RETURN_NULL_IF (index >= usbd_maxstrings);
+        return usb_strings[index];
+}
+
+/*! 
+ * usbd_realloc_string() - allocate a string descriptor and return index number
+ *
+ * Find an empty slot in index string array, create a corresponding descriptor
+ * and return the slot number.
+ * @param index
+ * @param str
+ * @return new index
+ */
+u8 usbd_realloc_string (u8 index, char *str)
+{
+        struct usbd_string_descriptor *string;
+        u8 bLength;
+        u16 *wData;
+
+        RETURN_ZERO_IF(!str || !strlen (str));
+        //TRACE_MSG2(USBD, "index: %d str: %s", index, str);
+
+        // XXX should have semaphores...
+
+        if ((index < usbd_maxstrings) && (string = usb_strings[index])) {
+                usb_strings[index] = NULL;
+                LKFREE (string);
+        }
+
+        bLength = sizeof (struct usbd_string_descriptor) + 2 * strlen (str);
+
+        RETURN_ZERO_IF(!(string = (struct usbd_string_descriptor *)CKMALLOC (bLength, GFP_KERNEL)));
+
+        string->bLength = bLength;
+        string->bDescriptorType = USB_DT_STRING;
+
+        for (wData = string->wData; *str;) 
+                *wData++ = (u16) (*str++);
+
+        // store in string index array
+        usb_strings[index] = string;
+        return index;
+}
+
+/*! 
+ * usbd_alloc_string() - allocate a string descriptor and return index number
+ *
+ * Find an empty slot in index string array, create a corresponding descriptor
+ * and return the slot number.
+ * @param str
+ * @return index
+ *
+ * XXX rename to usbd_alloc_string_descriptor
+ */
+u8 usbd_alloc_string (char *str)
+{
+        int i;
+        struct usbd_string_descriptor *string = NULL;
+        u8 bLength;
+        u16 *wData;
+
+        RETURN_ZERO_IF(!str || !strlen (str));
+
+        // find an empty string descriptor slot
+        for (i = 1; i < usbd_maxstrings; i++) {
+
+                CONTINUE_IF (usb_strings[i] != NULL);
+
+                bLength = sizeof (struct usbd_string_descriptor) + 2 * strlen (str);
+
+                RETURN_ZERO_IF(!(string = (struct usbd_string_descriptor *)CKMALLOC (bLength, GFP_KERNEL)));
+
+                string->bLength = bLength;
+                string->bDescriptorType = USB_DT_STRING;
+
+                for (wData = string->wData; *str;) 
+                        *wData++ = (u16) (*str++);
+
+                // store in string index array
+                usb_strings[i] = string;
+                return i;
+        }
+        return 0;
+}
+
+
+/*! 
+ * usbd_free_string_descriptor() - deallocate a string descriptor
+ *
+ * Find and remove an allocated string.
+ * @param index
+ *
+ */
+void usbd_free_string_descriptor (u8 index)
+{
+        struct usbd_string_descriptor *string;
+
+        if ((index < usbd_maxstrings) && (string = usb_strings[index])) {
+                usb_strings[index] = NULL;
+                LKFREE (string);
+        }
+}
+
+OTG_EXPORT_SYMBOL(usbd_realloc_string);
+OTG_EXPORT_SYMBOL(usbd_alloc_string);
+OTG_EXPORT_SYMBOL(usbd_free_string_descriptor);
+OTG_EXPORT_SYMBOL(usbd_get_string_descriptor);
+OTG_EXPORT_SYMBOL(usbd_maxstrings);
+
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/*!
+ * Device Information:
+ *	usbd_high_speed()
+ *	usbd_get_bMaxPower()
+ *	usbd_endpoint_wMaxPacketsize()
+ *	usbd_endpoint_wMaxPacketsize_ep0()
+ *	usbd_endpoint_bEndpointAddress()
+ *	
+ */
+
+
+/*!
+ * usbd_high_speed() - return high speed status
+ * @return true if operating at high speed
+ */
+int usbd_high_speed(struct usbd_function_instance *function)
+{
+        // XXX TODO - per function modifications for composite devices
+        return function->bus->HighSpeedFlag ? 1 : 0;
+}
+
+/*!
+ * usbd_get_bMaxPower() - process a received urb
+ *
+ * Used by a USB Bus interface driver to pass received device request to
+ * the appropriate USB Function driver.
+ *
+ * @param function
+ * @param request
+ * @return non-zero if errror
+ */
+int usbd_get_bMaxPower(struct usbd_function_instance *function)
+{
+        struct usbd_bus_instance *bus = function->bus;
+        return bus->driver->bMaxPower;
+}
+
+
+/*!
+ * usbd_endpoint_wMaxPacketSize() - get maximum packet size for endpoint
+ * @param function
+ * @param endpoint_index 
+ * @param hs highspeed flag
+ * @return endpoint size
+ */
+int usbd_endpoint_wMaxPacketSize(struct usbd_function_instance *function, int endpoint_index, int hs)
+{
+        struct usbd_endpoint_map *endpoint_map;
+        RETURN_ZERO_IF(!(endpoint_map = function->endpoint_map_array));
+        return le16_to_cpu(endpoint_map[endpoint_index].wMaxPacketSize[hs]);
+}
+
+/*!
+ * usbd_endpoint_zero_wMaxPacketSize() - get maximum packet size for endpoint zero
+ * @param function
+ * @param hs highspeed flag
+ * @return endpoint size
+ */
+int usbd_endpoint_zero_wMaxPacketSize(struct usbd_function_instance *function, int hs)
+{
+        struct usbd_endpoint_map *endpoint_map;
+        RETURN_ZERO_IF(!(endpoint_map = function->bus->ep0->endpoint_map_array));
+        return le16_to_cpu(endpoint_map[0].wMaxPacketSize[hs]);
+}
+
+/*!
+ * usbd_endpoint_bEndpointAddress() - get endpoint addrsess
+ * @param function
+ * @param endpoint_index
+ * @param hs high speed flag
+ * @return endpoint address
+ */
+int usbd_endpoint_bEndpointAddress(struct usbd_function_instance *function, int endpoint_index, int hs)
+{
+        struct usbd_endpoint_map *endpoint_map;
+        RETURN_ZERO_IF(!(endpoint_map = function->endpoint_map_array));
+        return endpoint_map[endpoint_index].bEndpointAddress[hs];
+}
+
+OTG_EXPORT_SYMBOL(usbd_endpoint_wMaxPacketSize);
+OTG_EXPORT_SYMBOL(usbd_endpoint_zero_wMaxPacketSize);
+OTG_EXPORT_SYMBOL(usbd_endpoint_bEndpointAddress);
+OTG_EXPORT_SYMBOL(usbd_high_speed);
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/*!
+ * Device Control:
+ *
+ *	XXX usbd_request_endpoints()
+ *	XXX usbd_configure_endpoints()
+ *
+ *      usbd_get_device_state()
+ *      usbd_get_device_status()
+ *      usbd_framenum()
+ *      usbd_ticks()
+ *      usbd_elapsed()
+ */
+
+/*!
+ * usbd_flush_endpoint_irq() - flush urbs from endpoint
+ *
+ * Iterate across the approrpiate tx or rcv list and cancel any outstanding urbs.
+ *
+ * @param endpoint flush urbs on this endpoint
+ */
+void usbd_flush_endpoint_irq (struct usbd_endpoint_instance *endpoint)
+{
+        struct usbd_urb *urb;
+
+        if (endpoint->bEndpointAddress)
+                TRACE_MSG1(USBD, "bEndpointAddress: %02x", endpoint->bEndpointAddress);
+
+        if ((urb = endpoint->tx_urb))
+                usbd_cancel_urb(urb);
+
+        for (; (urb = usbd_first_urb_detached_irq (&endpoint->tx)); usbd_cancel_urb(urb));
+
+        if ((urb = endpoint->rcv_urb))
+                usbd_cancel_urb(urb);
+
+        for (; (urb = usbd_first_urb_detached_irq (&endpoint->rdy)); usbd_cancel_urb(urb));
+}
+
+/*!
+ * usbd_flush_endpoint() - flush urbs from endpoint
+ *
+ * Iterate across the approrpiate tx or rcv list and cancel any outstanding urbs.
+ *
+ * @param endpoint flush urbs on this endpoint
+ */
+void usbd_flush_endpoint (struct usbd_endpoint_instance *endpoint)
+{
+        unsigned long flags;
+        local_irq_save (flags);
+        usbd_flush_endpoint_irq(endpoint);
+        local_irq_restore (flags);
+}
+
+/*!
+ * usbd_flush_endpoint_address() - flush endpoint
+ * @param function
+ * @param endpoint_index
+ */
+void usbd_flush_endpoint_index (struct usbd_function_instance *function, int endpoint_index)
+{
+        struct usbd_endpoint_map *endpoint_map;
+        struct usbd_endpoint_instance *endpoint;
+
+        RETURN_IF(!function);
+        RETURN_IF(!(endpoint_map = function->endpoint_map_array));
+        RETURN_IF(!(endpoint = endpoint_map[endpoint_index].endpoint));
+        usbd_flush_endpoint (endpoint);
+}
+
+/*!
+ * usbd_get_device_state() - return device state
+ * @param function
+ * @return current device state
+ */
+usbd_device_state_t usbd_get_device_state(struct usbd_function_instance *function)
+{
+        //TRACE_MSG1(USBD, "%d", function->bus->device_state);
+        return (function && function->bus) ? function->bus->device_state : STATE_UNKNOWN;
+}
+
+/*!
+ * usbd_get_device_status() - return device status
+ * @param function
+ * @return current device status
+ */
+usbd_device_status_t usbd_get_device_status(struct usbd_function_instance *function)
+{
+        //TRACE_MSG1(USBD, "%d", function->bus->status);
+        return (function && function->bus) ?  function->bus->status : USBD_UNKNOWN;
+}
+
+/*!
+ * usbd_framenum() - return framenum
+ * @param function
+ * @return current framenum
+ */
+int usbd_framenum(struct usbd_function_instance * function)
+{
+        RETURN_ZERO_UNLESS(function);
+        RETURN_ZERO_UNLESS(function->bus->driver->bops->framenum);
+        return function->bus->driver->bops->framenum ();
+}
+
+/*!
+ * usbd_ticks() - return ticks
+ * @param function
+ * @return current ticks
+ */
+u64 usbd_ticks(struct usbd_function_instance *function)
+{
+        RETURN_ZERO_UNLESS(function);
+        RETURN_ZERO_UNLESS(function->bus->driver->bops->ticks);
+        return function->bus->driver->bops->ticks ();
+}
+
+/*!
+ * usbd_elapsed() - return elapsed
+ * @param function
+ * @param t1
+ * @param t2
+ * @return elapsed uSecs between t1 and t2
+ */
+u64 usbd_elapsed(struct usbd_function_instance *function, u64 *t1, u64 *t2)
+{
+        RETURN_ZERO_UNLESS(function);
+        RETURN_ZERO_UNLESS(function->bus->driver->bops->elapsed);
+        return function->bus->driver->bops->elapsed (t1, t2);
+}
+
+
+//OTG_EXPORT_SYMBOL(usbd_set_endpoint_halt);
+//OTG_EXPORT_SYMBOL(usbd_endpoint_halted);
+OTG_EXPORT_SYMBOL(usbd_get_device_state);
+OTG_EXPORT_SYMBOL(usbd_get_device_status);
+OTG_EXPORT_SYMBOL(usbd_framenum);
+OTG_EXPORT_SYMBOL(usbd_ticks);
+OTG_EXPORT_SYMBOL(usbd_elapsed);
+OTG_EXPORT_SYMBOL(usbd_flush_endpoint);
+OTG_EXPORT_SYMBOL(usbd_flush_endpoint_index);
+
+/* ********************************************************************************************* */
+/* ********************************************************************************************* */
+/*!
+ * Endpoint I/O:
+ *	usbd_alloc_urb()
+ *	usbd_start_in_urb()
+ *	usbd_start_out_urb()
+ *	usbd_cancel_urb()
+ *
+ */
+
+/*!
+ * usbd_alloc_urb() - allocate an URB appropriate for specified endpoint
+ *
+ * Allocate an urb structure. The usb device urb structure is used to
+ * contain all data associated with a transfer, including a setup packet for
+ * control transfers.
+ * 
+ * @param function
+ * @param endpoint_index
+ * @param length
+ * @param callback
+ * @return urb
+ */
+struct usbd_urb *usbd_alloc_urb (struct usbd_function_instance *function, int endpoint_index,
+                int length, int (*callback) (struct usbd_urb *, int))
+{
+        struct usbd_urb *urb = NULL;
+        struct usbd_endpoint_map *endpoint_map;
+        struct usbd_endpoint_instance *endpoint;
+        unsigned long flags;
+
+        RETURN_NULL_IF(!(endpoint_map = function->endpoint_map_array));
+        RETURN_NULL_IF(!(endpoint = endpoint_map[endpoint_index].endpoint));
+
+        local_irq_save(flags);
+        THROW_IF (!(urb = (struct usbd_urb *)CKMALLOC (sizeof (struct usbd_urb), GFP_ATOMIC)), error); 
+        urb->endpoint = endpoint;
+        urb->bus = function->bus;
+        urb->function_instance = function;
+        urb->link.prev = urb->link.next = &urb->link;
+        urb->callback = callback;
+        urb->buffer_length = urb->actual_length = 0;
+
+        if (length) {
+                urb->request_length = length;
+
+                /* For receive we always overallocate to ensure that receiving another
+                 * full sized packet when we are only expecting a short packet will
+                 * not overflow the buffer
+                 */
+                if (!endpoint->bEndpointAddress || endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
+                        length = ((length / endpoint->wMaxPacketSize) + 1) * endpoint->wMaxPacketSize;
+                }
+                urb->buffer_length = length;
+
+                #if 0
+                if (urb->endpoint && urb->endpoint->bEndpointAddress && urb->function_instance && 
+                                urb->function_instance->function_driver->fops->alloc_urb_data) 
+                {
+                        THROW_IF(urb->function_instance->function_driver->fops->alloc_urb_data (urb, length), error); 
+                }
+                else 
+                #endif
+                        THROW_IF(!(urb->buffer = (u8 *)CKMALLOC (length, GFP_ATOMIC)), error);
+                
+        }
+
+        CATCH(error) {
+                #if defined(OTG_LINUX)
+                printk(KERN_ERR"%s: dealloc %p\n", __FUNCTION__, urb); 
+                #endif /* defined(OTG_LINUX) */
+                #if defined(OTG_WINCE)
+                DEBUGMSG(ZONE_INIT, (_T("usbd_alloc_urb: FAILED\n")));
+                #endif /* defined(OTG_LINUX) */
+                usbd_free_urb(urb);
+                urb = NULL;
+        }
+        local_irq_restore(flags);
+        return urb;
+}
+
+/*!
+ * usbd_halt_endpoint() - 
+ *
+ * @param function function that owns endpoint
+ * @param endpoint endpoint number
+ * @return non-zero if endpoint is halted.
+ */
+int usbd_halt_endpoint (struct usbd_function_instance *function, int endpoint_index)
+{
+        struct usbd_endpoint_map *endpoint_map;
+        struct usbd_endpoint_instance *endpoint;
+
+        RETURN_ZERO_IF(!(endpoint_map = function->endpoint_map_array));
+        RETURN_ZERO_IF(!(endpoint = endpoint_map[endpoint_index].endpoint));
+
+        return function->bus->driver->bops->halt_endpoint (function->bus, endpoint->bEndpointAddress, endpoint_index, 1);
+}
+
+
+/*!
+ * usbd_alloc_urb_ep0() - allocate an urb for endpoint zero
+ * @param function
+ * @param length
+ * @param callback
+ * @return urb
+ */
+struct usbd_urb *usbd_alloc_urb_ep0 (struct usbd_function_instance *function, int length, 
+                int (*callback) (struct usbd_urb *, int))
+{
+        return usbd_alloc_urb(function->bus->ep0, 0, length, callback);
+}
+
+/*!
+ * usbd_free_urb() - deallocate an URB and associated buffer
+ *
+ * Deallocate an urb structure and associated data.
+ * @param urb
+ */
+void usbd_free_urb (struct usbd_urb *urb)
+{
+        RETURN_IF (!urb);
+        if (urb->buffer) {
+                #if 0
+                if (urb->function_instance && urb->function_instance->function_driver->fops->dealloc_urb_data)
+                        urb->function_instance->function_driver->fops->dealloc_urb_data ((void *) urb->buffer);
+                else
+                #endif
+                        LKFREE ((void *) urb->buffer);
+        }
+        LKFREE (urb);
+}
+
+
+/*!
+ * usbd_start_in_urb() - submit a urb to send
+ *
+ * Used by a USB Function driver to submit data to be sent in an urb to the
+ * appropriate USB Bus driver via the endpoints transmit queue.
+ *
+ * @param urb to send
+ * @return non-zero if error
+ */
+int usbd_start_in_urb (struct usbd_urb *urb)
+{
+        RETURN_EINVAL_IF (urb->endpoint->bEndpointAddress && (USBD_OK != urb->bus->status));
+        if (urb->endpoint->feature_setting & FEATURE(USB_ENDPOINT_HALT)) {
+                usbd_urb_finished(urb, SEND_STALLED);
+                return 0;
+        }
+        urb->status = SEND_IN_QUEUE;
+        #if defined(OTG_LINUX)
+        urb->jiffies = jiffies;
+        #endif /* defined(OTG_LINUX) */
+        urb_append (&(urb->endpoint->tx), urb);
+        return urb->bus->driver->bops->start_endpoint_in(urb->bus, urb->endpoint);
+}
+
+/*!
+ * usbd_start_out_urb() - recycle a received urb
+ *
+ * Used by a USB Function interface driver to recycle an urb.
+ *
+ * @param urb to process
+ * @return non-zero if error
+ */
+int usbd_start_out_urb (struct usbd_urb *urb)
+{
+        RETURN_EINVAL_IF (urb->endpoint->bEndpointAddress && (USBD_OK != urb->bus->status));
+        if (urb->endpoint->feature_setting & FEATURE(USB_ENDPOINT_HALT)) {
+                usbd_urb_finished(urb, RECV_STALLED);
+                return 0;
+        }
+        urb->actual_length = 0;
+        urb->status = RECV_IN_QUEUE;
+        #if defined(OTG_LINUX)
+        urb->jiffies = jiffies;
+        #endif /* defined(OTG_LINUX) */
+        urb_append (&(urb->endpoint->rdy), urb);
+        return urb->bus->driver->bops->start_endpoint_out(urb->bus, urb->endpoint);
+}
+
+/*!
+ * usbd_cancel_urb() - cancel an urb being sent
+ *
+ * @param urb to process
+ * @return non-zero if error
+ */
+int usbd_cancel_urb (struct usbd_urb *urb)
+{
+        //TRACE_MSG0(USBD, "entered");
+        return urb->bus->driver->bops->cancel_urb_irq (urb);
+}
+
+
+/*!
+ * usbd_endpoint_halted() - return halt status
+ *
+ * @param function function that owns endpoint
+ * @param endpoint endpoint number
+ * @return non-zero if endpoint is halted.
+ */
+int usbd_endpoint_halted (struct usbd_function_instance *function, int endpoint_index)
+{
+        struct usbd_endpoint_instance *endpoint;
+        struct usbd_endpoint_map *endpoint_map;
+        //TRACE_MSG0(USBD, "entered");
+        //
+        RETURN_ZERO_UNLESS((endpoint_map = function->endpoint_map_array));
+        RETURN_ZERO_UNLESS((endpoint = endpoint_map[endpoint_index].endpoint));
+        return function->bus->driver->bops->endpoint_halted (function->bus, endpoint->bEndpointAddress, endpoint_index);
+}
+
+
+OTG_EXPORT_SYMBOL(usbd_alloc_urb);
+OTG_EXPORT_SYMBOL(usbd_alloc_urb_ep0);
+OTG_EXPORT_SYMBOL(usbd_free_urb);
+
+OTG_EXPORT_SYMBOL(usbd_start_in_urb);
+OTG_EXPORT_SYMBOL(usbd_start_out_urb);
+OTG_EXPORT_SYMBOL(usbd_cancel_urb);
+OTG_EXPORT_SYMBOL(usbd_halt_endpoint);
+
+/* ********************************************************************************************* */
+
+/*!
+ * usbd_function_get_privdata() - get private data pointer
+ * @param function
+ * @return void * pointer to private data
+ */
+void *usbd_function_get_privdata(struct usbd_function_instance *function)
+{
+        return(function->privdata);
+}
+
+/*!
+ * usbd_function_set_privdata() - set private data structure in function
+ * @param function
+ * @param privdata
+ */
+void usbd_function_set_privdata(struct usbd_function_instance *function, void *privdata)
+{
+        function->privdata = privdata;
+}
+
+
+
+
+/*!
+ * usbd_endpoint_transferSize() - get transferSize for endpoint
+ * @param function
+ * @param endpoint_index
+ * @param hs highspeed flag
+ * @return transfer size
+ */
+int usbd_endpoint_transferSize(struct usbd_function_instance *function, int endpoint_index, int hs)
+{
+        struct usbd_endpoint_map *endpoint_map;
+        RETURN_ZERO_IF(!(endpoint_map = function->endpoint_map_array));
+        return endpoint_map[endpoint_index].transferSize[hs];
+}
+
+/*!
+ * usbd_endpoint_update() - update endpoint address and size
+ * @param function
+ * @param endpoint_index
+ * @param endpoint descriptor
+ * @param hs high speed flag
+ */
+void usbd_endpoint_update(struct usbd_function_instance *function, int endpoint_index, 
+                struct usbd_endpoint_descriptor *endpoint, int hs)
+{
+        endpoint->bEndpointAddress = usbd_endpoint_bEndpointAddress(function, endpoint_index, hs);
+        endpoint->wMaxPacketSize = usbd_endpoint_wMaxPacketSize(function, endpoint_index, hs);
+}
+
+/*!
+ * usbd_otg_bmattributes() - return attributes
+ * @param function
+ * @return endpoint attributes
+ */
+int usbd_otg_bmattributes(struct usbd_function_instance *function)
+{
+        // XXX TODO - per function modifications for composite devices
+        return function->bus->otg_bmAttributes;
+}
+
+OTG_EXPORT_SYMBOL(usbd_function_get_privdata);
+OTG_EXPORT_SYMBOL(usbd_function_set_privdata);
+OTG_EXPORT_SYMBOL(usbd_endpoint_transferSize);
+OTG_EXPORT_SYMBOL(usbd_otg_bmattributes);
+OTG_EXPORT_SYMBOL(usbd_endpoint_update);
diff -uNr linux/drivers/no-otg/otgcore/usbp-procfs.c linux/drivers/otg/otgcore/usbp-procfs.c
--- linux/drivers/no-otg/otgcore/usbp-procfs.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otgcore/usbp-procfs.c	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,302 @@
+/*
+ * otg/otgcore/usbp-procfs.c - USB Device Core Layer
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/otgcore/usbp-procfs.c
+ * @brief Implements /proc/usbd-functions, which displays descriptors for the current selected function.
+ *
+ *
+ * @ingroup USBP
+ */
+
+#include <otg/otg-compat.h>
+#include <otg/otg-module.h>
+
+#ifdef LINUX24
+EXPORT_NO_SYMBOLS;
+#endif
+
+
+MOD_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
+MOD_DESCRIPTION ("USB Device Core Support Procfs");
+EMBED_LICENSE();
+
+#include <otg/usbp-chap9.h>
+#include <otg/usbp-func.h>
+#include <otg/usbp-bus.h>
+
+EMBED_USBD_INFO ("usbdprocfs 2.0-beta");
+
+#define MAX_INTERFACES 2
+
+extern struct usbd_bus_instance *usbd_bus_instance;
+
+/* Proc Filesystem *************************************************************************** */
+/* *
+ * dohex
+ *
+ */
+static void dohexdigit (char *cp, unsigned char val)
+{
+        if (val < 0xa) {
+                *cp = val + '0';
+        } else if ((val >= 0x0a) && (val <= 0x0f)) {
+                *cp = val - 0x0a + 'a';
+        }
+}
+
+/* *
+ * dohex
+ *
+ */
+static void dohexval (char *cp, unsigned char val)
+{
+        dohexdigit (cp++, val >> 4);
+        dohexdigit (cp++, val & 0xf);
+}
+
+/* *
+ * dump_descriptor
+ */
+static int dump_descriptor (char *buf, char *sp)
+{
+        int num;
+        int len = 0;
+
+        RETURN_ZERO_UNLESS(sp);
+
+        num = *sp;
+
+        //printk(KERN_INFO"%s: %p %d %d %d\n", __FUNCTION__, buf, *buf, buf[0], num);
+
+        while (sp && num--) {
+                dohexval (buf, *sp++);
+                buf += 2;
+                *buf++ = ' ';
+                len += 3;
+        }
+        len++;
+        *buf = '\n';
+        return len;
+}
+
+/* dump_descriptors
+ */
+static int dump_config_descriptor(char *buf, char *sp)
+{
+        struct usbd_configuration_descriptor *config = (struct usbd_configuration_descriptor *) sp;
+
+        int wTotalLength = le16_to_cpu(config->wTotalLength);
+        int bConfigurationValue = config->bConfigurationValue;
+        int interface_num;
+        int class_num;
+        int endpoint_num;
+        int total;
+
+        interface_num = class_num = endpoint_num = 0;
+
+        for (total = 0; wTotalLength > 0; ) {
+                //printk(KERN_INFO"%s: wTotalLength: %d total: %d bLength: %d type: %d\n",
+                //                __FUNCTION__, wTotalLength, total, sp[0], sp[1]);
+                BREAK_UNLESS(sp[0]);
+                switch (sp[1]) {
+                case USB_DT_CONFIGURATION:
+                        interface_num = class_num = endpoint_num = 0;
+                        total += sprintf(buf + total, "\nConfiguration descriptor [%d      ] ",
+                                        bConfigurationValue);
+                        break;
+                case USB_DT_INTERFACE:
+                        class_num = 0;
+                        total += sprintf(buf + total, "\nInterface descriptor     [%d:%d:%d  ] ",
+                                        bConfigurationValue, ++interface_num, class_num);
+                        break;
+                case USB_DT_ENDPOINT:
+                        class_num = endpoint_num = 0;
+                        total += sprintf(buf + total, "Endpoint descriptor      [%d:%d:%d:%d] ",
+                                        bConfigurationValue, interface_num, class_num, ++endpoint_num);
+                        break;
+                case USB_DT_OTG:
+                        class_num = endpoint_num = 0;
+                        total += sprintf(buf + total, "OTG descriptor           [%d      ] ", bConfigurationValue);
+                        break;
+                default:
+                        endpoint_num = 0;
+                        total += sprintf(buf + total, "Class descriptor         [%d:%d:%d  ] ",
+                                        bConfigurationValue, interface_num, ++class_num);
+                        break;
+                }
+                total += dump_descriptor(buf + total, sp);
+                wTotalLength -= sp[0];
+                sp += sp[0];
+        }
+        total += sprintf(buf + total, "\n");
+        return total;
+}
+
+/*! *
+ * usbd_device_proc_read - implement proc file system read.
+ * @param file
+ * @param buf
+ * @param count
+ * @param pos
+ *
+ * Standard proc file system read function.
+ *
+ * We let upper layers iterate for us, *pos will indicate which device to return
+ * statistics for.
+ */
+static ssize_t usbd_device_proc_read_functions (struct file *file, char *buf, size_t count, loff_t * pos)
+{
+        unsigned long page;
+        int len = 0;
+        int index;
+
+        u8 config_descriptor[512];
+        int config_size;
+
+        //struct list_head *lhd;
+
+        // get a page, max 4095 bytes of data...
+//        if (!(page = GET_FREE_PAGE(GFP_KERNEL))) {
+
+        if (!(page = GET_KERNEL_PAGE())) {
+                return -ENOMEM;
+        }
+
+        len = 0;
+        index = (*pos)++;
+
+        if (index == 0) {
+                len += sprintf ((char *) page + len, "usb-device list\n");
+        }
+
+        //printk(KERN_INFO"%s: index: %d len: %d\n", __FUNCTION__, index, len);
+
+        if (usbd_bus_instance && usbd_bus_instance->function_instance) {
+                int configuration = index;
+                struct usbd_function_instance *function_instance = usbd_bus_instance->function_instance;
+                struct usbd_function_driver *function_driver = function_instance->function_driver;
+                struct usbd_configuration_instance *configuration_instance_array = function_driver->configuration_instance_array;
+                if (configuration_instance_array) {
+
+                        if (index == 0) {
+                                len += sprintf ((char *) page + len, "\nDevice descriptor                  ");
+                                len += dump_descriptor ((char *) page + len, (char *) function_driver->device_descriptor);
+#ifdef CONFIG_OTG_HIGH_SPEED
+                                len += sprintf ((char *) page + len, "\nDevice Qualifier descriptor        ");
+                                len += dump_descriptor ((char *) page + len, 
+                                                (char *) function_driver->device_qualifier_descriptor);
+#endif
+                        }
+                        if (configuration < function_driver->bNumConfigurations) {
+
+                                if ((config_size = usbd_old_get_descriptor(usbd_bus_instance->ep0, config_descriptor, 
+                                                                sizeof(config_descriptor),
+                                                                USB_DT_CONFIGURATION, 0)) > index) {
+                                        len += dump_config_descriptor((char *)page + len, config_descriptor );
+                                }
+#ifdef CONFIG_OTG_HIGH_SPEED
+                                if ((config_size = usbd_old_get_descriptor(usbd_bus_instance->ep0, config_descriptor, 
+                                                                sizeof(config_descriptor),
+                                                                USB_DT_OTHER_SPEED_CONFIGURATION, index)) > 0) {
+                                        len += dump_config_descriptor((char *)page + len, config_descriptor );
+                                }
+
+#endif
+                        }
+                        else if (configuration == function_driver->bNumConfigurations) {
+                                int i;
+                                int k;
+                                struct usbd_string_descriptor *string_descriptor;
+
+                                //len += sprintf ((char *) page + len, "\n\n");
+
+                                if ((string_descriptor = usbd_get_string_descriptor (0)) != NULL) {
+                                        len += sprintf ((char *) page + len, "String                   [%2d]      ", 0);
+
+                                        for (k = 0; k < (string_descriptor->bLength / 2) - 1; k++) {
+                                                len += sprintf ((char *) page + len, "%02x %02x ", 
+                                                                string_descriptor->wData[k] >> 8, 
+                                                                string_descriptor->wData[k] & 0xff);
+                                                len++;
+                                        }
+                                        len += sprintf ((char *) page + len, "\n");
+                                }
+
+                                for (i = 1; i < usbd_maxstrings; i++) {
+
+                                        if ((string_descriptor = usbd_get_string_descriptor (i)) != NULL) {
+
+                                                len += sprintf((char *)page+len, "String                   [%2d:%2d]   ", 
+                                                                i, string_descriptor->bLength);
+
+                                                // bLength = sizeof(struct usbd_string_descriptor) + 2*strlen(str)-2;
+
+                                                for (k = 0; k < (string_descriptor->bLength / 2) - 1; k++) {
+                                                        *(char *) (page + len) = (char) string_descriptor->wData[k];
+                                                        len++;
+                                                }
+                                                len += sprintf ((char *) page + len, "\n");
+                                        }
+                                }
+                                len += sprintf((char *)page + len, "\n--\n"); 
+                        }
+                }
+        }
+
+        //printk(KERN_INFO"%s: len: %d count: %d\n", __FUNCTION__, len, count);
+
+        if (len > count) {
+                //printk(KERN_INFO"%s: len > count\n", __FUNCTION__);
+                //printk(KERN_INFO"%s", page);
+                len = -EINVAL;
+        } 
+        else if ((len > 0) && copy_to_user (buf, (char *) page, len)) {
+                //printk(KERN_INFO"%s: EFAULT\n", __FUNCTION__);
+                len = -EFAULT;
+        }
+        else {
+                //printk(KERN_INFO"%s: OK\n", __FUNCTION__);
+        }
+        free_page (page);
+        return len;
+}
+
+/* Module init ******************************************************************************* */
+#if defined(OTG_WINCE)
+
+#else /* defined(OTG_WINCE) */
+
+static struct file_operations usbd_device_proc_operations_functions = {
+        read:usbd_device_proc_read_functions,
+};
+
+static int usbd_procfs_init (void)
+{
+        struct proc_dir_entry *p;
+        // create proc filesystem entries
+        if ((p = create_proc_entry ("usb-functions", 0, 0)) == NULL)
+                return -ENOMEM;
+        p->proc_fops = &usbd_device_proc_operations_functions;
+        return 0;
+}
+
+static void usbd_procfs_exit (void)
+{
+        // remove proc filesystem entry
+        remove_proc_entry ("usb-functions", NULL);
+}
+
+module_init (usbd_procfs_init);
+module_exit (usbd_procfs_exit);
+
+#endif /* defined(OTG_WINCE) */
+
diff -uNr linux/drivers/no-otg/otghw/atlas-hardware.h linux/drivers/otg/otghw/atlas-hardware.h
--- linux/drivers/no-otg/otghw/atlas-hardware.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otghw/atlas-hardware.h	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,59 @@
+/*
+ * otg/include/atlas-hardware.h -- Atlas Transceiver hardware specific defines
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @defgroup ATLAS
+ * @ingroup tcdgroup
+ */
+/*!
+ * @file otghw/atlas-hardware.h
+ * @brief Hardware defines for Freescale USBOTG Hardware
+ *
+ * @ingroup ATLAS
+ */
+
+/* References are to:
+ *
+ *      Atlas DTS 0.7 - 04/02/27
+ */
+
+/*
+ * SPI Register Summary
+ */
+
+#define ATLAS_FSENB             (1 << 0)
+#define ATLAS_USB_SUSPEND       (1 << 1)
+#define ATLAS_USB_PU            (1 << 2)
+#define ATLAS_UDP_PD            (1 << 3)
+#define ATLAS_UDM_PD            (1 << 4)
+#define ATLAS_PULLOVR           (1 << 5)
+#define ATLAS_VUSB_EN           (1 << 6)
+#define ATLAS_USB_PS            (1 << 7)
+#define ATLAS_VBUS_REG_EN       (1 << 8)
+#define ATLAS_VBUS_PD_ENB       (1 << 9)
+#define ATLAS_CURRLIM           (1 << 10)
+#define ATLAS_SE0_CONN          (1 << 11)
+#define ATLAS_DLP_SRP           (1 << 12)
+#define ATLAS_USB_XCVR_EN       (1 << 13)
+#define ATLAS_VBUS_REG_LVL      (1 << 14)
+
+#define ATLAS_DATA_MODE_MASK    (3 << 15)
+#define ATLAS_DATA_MODE_USE     (0 << 15)
+#define ATLAS_DATA_MODE_BSE     (1 << 15)
+#define ATLAS_DATA_MODE_DM      (2 << 15)
+#define ATLAS_DATA_MODE_NU      (3 << 15)
+
+#define ATLAS_RS232ENB          (1 << 17)
+#define ATLAS_ID_INTERRUPT      (1 << 20)
+#define ATLAS_AUDIO_EN          (1 << 21)
+#define ATLAS_STEREO_EN         (1 << 22)
+
+
diff -uNr linux/drivers/no-otg/otghw/bvd-hardware.h linux/drivers/otg/otghw/bvd-hardware.h
--- linux/drivers/no-otg/otghw/bvd-hardware.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otghw/bvd-hardware.h	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,601 @@
+/*
+ * otg/otghw/bvd-hardware.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ *
+ * TODO
+ *
+ * 1. see if using UDCCSR0_ACM/AREN will help
+ *
+ */
+/*!
+ * @file otghw/bvd-hardware.h
+ * @brief Hardware defines for Intel PXA-270 Hardware
+ *
+ * @ingroup BVD
+ */
+
+
+#ifndef UDCOTGICR
+#define UDCOTGICR       __REG(0x40600018) /* UDC On-The-Go interrupt control */
+#endif
+
+#ifndef UDCOTGISR
+#define UDCOTGISR       __REG(0x4060001c) 
+
+#define UDCOTGISR_IRSF  (1 << 24)       /* OTG SET_FEATURE command recvd */
+#define UDCOTGISR_IRXR  (1 << 17)       /* Extra Transciever Interrupt Rising Edge Interrupt Enable */
+#define UDCOTGISR_IRXF  (1 << 16)       /* Extra Transciever Interrupt Falling Edge Interrupt Enable */
+#define UDCOTGISR_IRVV40R (1 << 9)      /* OTG Vbus Valid 4.0V Rising Edge Interrupt Enable */
+#define UDCOTGISR_IRVV40F (1 << 8)      /* OTG Vbus Valid 4.0V Falling Edge Interrupt Enable */
+#define UDCOTGISR_IRVV44R (1 << 7)      /* OTG Vbus Valid 4.4V Rising Edge Interrupt Enable */
+#define UDCOTGISR_IRVV44F (1 << 6)      /* OTG Vbus Valid 4.4V Falling Edge Interrupt Enable */
+#define UDCOTGISR_IRSVR (1 << 5)        /* OTG Session Valid Rising Edge Interrupt Enable */
+#define UDCOTGISR_IRSVF (1 << 4)        /* OTG Session Valid Falling Edge Interrupt Enable */
+#define UDCOTGISR_IRSDR (1 << 3)        /* OTG A-Device SRP Detect Rising Edge Interrupt Enable */
+#define UDCOTGISR_IRSDF (1 << 2)        /* OTG A-Device SRP Detect Falling Edge Interrupt Enable */
+#define UDCOTGISR_IRIDR (1 << 1)        /* OTG ID Change Rising Edge Interrupt Enable */
+#define UDCOTGISR_IRIDF (1 << 0)        /* OTG ID Change Falling Edge */
+ 
+
+#endif
+
+
+#ifndef UP2OCR
+#define UP2OCR          __REG(0x40600020) 
+
+#define UP2OCR_SEOS_OFF         (0x00 << 24)
+#define UP2OCR_SEOS_DSEO        (0x02 << 24)
+#define UP2OCR_SEOS_HSEO        (0x03 << 24)
+#define UP2OCR_SEOS_DEXT        (0x04 << 24)
+#define UP2OCR_SEOS_HEXT        (0x05 << 24)
+#define UP2OCR_SEOS_DINT        (0x06 << 24)
+#define UP2OCR_SEOS_HINT        (0x07 << 24)
+
+#define UP2OCR_HXOE             (0x1 << 17)
+#define UP2OCR_HXS              (0x1 << 16)
+
+#define UP2OCR_IDON             (0x1 << 10)
+#define UP2OCR_EXSUS            (0x1 << 9)
+#define UP2OCR_EXSP             (0x1 << 8)
+#define UP2OCR_DMPUBE           (0x1 << 7)
+#define UP2OCR_DPPUBE           (0x1 << 6)
+#define UP2OCR_DMPUE            (0x1 << 5)
+#define UP2OCR_DPPUE            (0x1 << 4)
+#define UP2OCR_DMPDE            (0x1 << 3)
+#define UP2OCR_DPPDE            (0x1 << 2)
+#define UP2OCR_CPVPE            (0x1 << 1)
+#define UP2OCR_CPVEN            (0x1 << 0)
+
+#endif
+
+#ifndef UP3OCR
+#define UP3OCR          __REG(0x40600024)
+#endif
+
+/*
+ * UDCCSR0 Bit Definitions C.f. Sheet 1 or 3
+ */
+#define UDCCSR0_ACM             (1 << 9)
+#define UDCCSR0_AREN            (1 << 8)
+
+
+/*
+ * Mainstone Miscellanous Write Register (MSCWR2) C.f. 3.2.2.6 (DVK)
+ *
+ * USB_OTG_RST  enable external usb otg transceiver
+ * USB_OTG_SEL  enable usb otg (disables ffuart)
+ * nUSBC_SC     enable usb client detection
+ */
+#ifndef MSCWR2_USB_OTG_SEL
+#define MSCWR2_USB_OTG_SEL MST_MSCWR2_USB_OTG_SEL
+#endif
+#ifndef MSCWR2_USB_OTG_RST
+#define MSCWR2_USB_OTG_RST MST_MSCWR2_USB_OTG_RST
+#endif
+#ifndef MSCRD1_USB_CBL
+#define MSCRD1_USB_CBL MST_MSCRD_USB_CBL
+#endif
+#ifndef MSCWR2_nUSBC_SC
+#define MSCWR2_nUSBC_SC MST_MSCWR2_nUSBC_SC
+#endif
+
+/*
+ * USB_P2_N GPIO configuration - C.f. 24.2
+ *
+ * These should be in
+ */
+#define GPIO34_USB_P2_2   (34 | GPIO_ALT_FN_1_OUT)
+#define GPIO35_USB_P2_1   (35 | GPIO_ALT_FN_2_IN)
+#define GPIO36_USB_P2_4   (36 | GPIO_ALT_FN_1_OUT)
+#define GPIO37_USB_P2_8   (37 | GPIO_ALT_FN_1_OUT)
+#define GPIO38_USB_P2_3   (38 | GPIO_ALT_FN_3_IN)
+#define GPIO39_USB_P2_6   (39 | GPIO_ALT_FN_1_OUT)
+#define GPIO40_USB_P2_5   (40 | GPIO_ALT_FN_3_IN)
+#define GPIO41_USB_P2_7   (41 | GPIO_ALT_FN_2_IN)
+
+
+#if 0
+/* UDC endpiont0 states */
+#define EP0_WAIT_FOR_SETUP          0
+#define EP0_DATA_STATE_XMIT         1
+#define EP0_DATA_STATE_NEED_ZLP     2
+#define EP0_WAIT_FOR_OUT_STATUS     3
+
+/* UDC register definitions */
+#define UDCCR           __REG(0x40600000) /* UDC Control Register */
+#define UDCICR0         __REG(0x40600004) /* UDC Interrupt Control Register0 */
+#define UDCICR1         __REG(0x40600008) /* UDC Interrupt Control Register1 */
+#define UDCISR0         __REG(0x4060000C) /* UDC Interrupt Status Register 0 */
+#define UDCISR1         __REG(0x40600010) /* UDC Interrupt Status Register 1 */
+#define UDCFNR          __REG(0x40600014) /* UDC Frame Number Register */
+
+#define UDCCSR0         __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */
+#define UDCCSRA         __REG(0x40600104) /* UDC Control/Status register - Endpoint A */
+#define UDCCSRB         __REG(0x40600108) /* UDC Control/Status register - Endpoint B */
+#define UDCCSRC         __REG(0x4060010C) /* UDC Control/Status register - Endpoint C */
+#define UDCCSRD         __REG(0x40600110) /* UDC Control/Status register - Endpoint D */
+#define UDCCSRE         __REG(0x40600114) /* UDC Control/Status register - Endpoint E */
+#define UDCCSRF         __REG(0x40600118) /* UDC Control/Status register - Endpoint F */
+#define UDCCSRG         __REG(0x4060011C) /* UDC Control/Status register - Endpoint G */
+#define UDCCSRH         __REG(0x40600120) /* UDC Control/Status register - Endpoint H */
+#define UDCCSRI         __REG(0x40600124) /* UDC Control/Status register - Endpoint I */
+#define UDCCSRJ         __REG(0x40600128) /* UDC Control/Status register - Endpoint J */
+#define UDCCSRK         __REG(0x4060012C) /* UDC Control/Status register - Endpoint K */
+#define UDCCSRL         __REG(0x40600130) /* UDC Control/Status register - Endpoint L */
+#define UDCCSRM         __REG(0x40600134) /* UDC Control/Status register - Endpoint M */
+#define UDCCSRN         __REG(0x40600138) /* UDC Control/Status register - Endpoint N */
+#define UDCCSRP         __REG(0x4060013C) /* UDC Control/Status register - Endpoint P */
+#define UDCCSRQ         __REG(0x40600140) /* UDC Control/Status register - Endpoint Q */
+#define UDCCSRR         __REG(0x40600144) /* UDC Control/Status register - Endpoint R */
+#define UDCCSRS         __REG(0x40600148) /* UDC Control/Status register - Endpoint S */
+#define UDCCSRT         __REG(0x4060014C) /* UDC Control/Status register - Endpoint T */
+#define UDCCSRU         __REG(0x40600150) /* UDC Control/Status register - Endpoint U */
+#define UDCCSRV         __REG(0x40600154) /* UDC Control/Status register - Endpoint V */
+#define UDCCSRW         __REG(0x40600158) /* UDC Control/Status register - Endpoint W */
+#define UDCCSRX         __REG(0x4060015C) /* UDC Control/Status register - Endpoint X */
+
+#define UDCBCR0         __REG(0x40600200) /* Byte Count Register - EP0 */
+#define UDCBCRA         __REG(0x40600204) /* Byte Count Register - EPA */
+#define UDCBCRB         __REG(0x40600208) /* Byte Count Register - EPB */
+#define UDCBCRC         __REG(0x4060020C) /* Byte Count Register - EPC */
+#define UDCBCRD         __REG(0x40600210) /* Byte Count Register - EPD */
+#define UDCBCRE         __REG(0x40600214) /* Byte Count Register - EPE */
+#define UDCBCRF         __REG(0x40600218) /* Byte Count Register - EPF */
+#define UDCBCRG         __REG(0x4060021C) /* Byte Count Register - EPG */
+#define UDCBCRH         __REG(0x40600220) /* Byte Count Register - EPH */
+#define UDCBCRI         __REG(0x40600224) /* Byte Count Register - EPI */
+#define UDCBCRJ         __REG(0x40600228) /* Byte Count Register - EPJ */
+#define UDCBCRK         __REG(0x4060022C) /* Byte Count Register - EPK */
+#define UDCBCRL         __REG(0x40600230) /* Byte Count Register - EPL */
+#define UDCBCRM         __REG(0x40600234) /* Byte Count Register - EPM */
+#define UDCBCRN         __REG(0x40600238) /* Byte Count Register - EPN */
+#define UDCBCRP         __REG(0x4060023C) /* Byte Count Register - EPP */
+#define UDCBCRQ         __REG(0x40600240) /* Byte Count Register - EPQ */
+#define UDCBCRR         __REG(0x40600244) /* Byte Count Register - EPR */
+#define UDCBCRS         __REG(0x40600248) /* Byte Count Register - EPS */
+#define UDCBCRT         __REG(0x4060024C) /* Byte Count Register - EPT */
+#define UDCBCRU         __REG(0x40600250) /* Byte Count Register - EPU */
+#define UDCBCRV         __REG(0x40600254) /* Byte Count Register - EPV */
+#define UDCBCRW         __REG(0x40600258) /* Byte Count Register - EPW */
+#define UDCBCRX         __REG(0x4060025C) /* Byte Count Register - EPX */
+
+#define UDCDR0          __REG(0x40600300) /* Data Register - EP0 */
+#define UDCDRA          __REG(0x40600304) /* Data Register - EPA */
+#define UDCDRB          __REG(0x40600308) /* Data Register - EPB */
+#define UDCDRC          __REG(0x4060030C) /* Data Register - EPC */
+#define UDCDRD          __REG(0x40600310) /* Data Register - EPD */
+#define UDCDRE          __REG(0x40600314) /* Data Register - EPE */
+#define UDCDRF          __REG(0x40600318) /* Data Register - EPF */
+#define UDCDRG          __REG(0x4060031C) /* Data Register - EPG */
+#define UDCDRH          __REG(0x40600320) /* Data Register - EPH */
+#define UDCDRI          __REG(0x40600324) /* Data Register - EPI */
+#define UDCDRJ          __REG(0x40600328) /* Data Register - EPJ */
+#define UDCDRK          __REG(0x4060032C) /* Data Register - EPK */
+#define UDCDRL          __REG(0x40600330) /* Data Register - EPL */
+#define UDCDRM          __REG(0x40600334) /* Data Register - EPM */
+#define UDCDRN          __REG(0x40600338) /* Data Register - EPN */
+#define UDCDRP          __REG(0x4060033C) /* Data Register - EPP */
+#define UDCDRQ          __REG(0x40600340) /* Data Register - EPQ */
+#define UDCDRR          __REG(0x40600344) /* Data Register - EPR */
+#define UDCDRS          __REG(0x40600348) /* Data Register - EPS */
+#define UDCDRT          __REG(0x4060034C) /* Data Register - EPT */
+#define UDCDRU          __REG(0x40600350) /* Data Register - EPU */
+#define UDCDRV          __REG(0x40600354) /* Data Register - EPV */
+#define UDCDRW          __REG(0x40600358) /* Data Register - EPW */
+#define UDCDRX          __REG(0x4060035C) /* Data Register - EPX */
+
+#define UDCCRA          __REG(0x40600404) /* Configuration register EPA */
+#define UDCCRB          __REG(0x40600408) /* Configuration register EPB */
+#define UDCCRC          __REG(0x4060040C) /* Configuration register EPC */
+#define UDCCRD          __REG(0x40600410) /* Configuration register EPD */
+#define UDCCRE          __REG(0x40600414) /* Configuration register EPE */
+#define UDCCRF          __REG(0x40600418) /* Configuration register EPF */
+#define UDCCRG          __REG(0x4060041C) /* Configuration register EPG */
+#define UDCCRH          __REG(0x40600420) /* Configuration register EPH */
+#define UDCCRI          __REG(0x40600424) /* Configuration register EPI */
+#define UDCCRJ          __REG(0x40600428) /* Configuration register EPJ */
+#define UDCCRK          __REG(0x4060042C) /* Configuration register EPK */
+#define UDCCRL          __REG(0x40600430) /* Configuration register EPL */
+#define UDCCRM          __REG(0x40600434) /* Configuration register EPM */
+#define UDCCRN          __REG(0x40600438) /* Configuration register EPN */
+#define UDCCRP          __REG(0x4060043C) /* Configuration register EPP */
+#define UDCCRQ          __REG(0x40600440) /* Configuration register EPQ */
+#define UDCCRR          __REG(0x40600444) /* Configuration register EPR */
+#define UDCCRS          __REG(0x40600448) /* Configuration register EPS */
+#define UDCCRT          __REG(0x4060044C) /* Configuration register EPT */
+#define UDCCRU          __REG(0x40600450) /* Configuration register EPU */
+#define UDCCRV          __REG(0x40600454) /* Configuration register EPV */
+#define UDCCRW          __REG(0x40600458) /* Configuration register EPW */
+#define UDCCRX          __REG(0x4060045C) /* Configuration register EPX */
+
+/* UDC Control Register (UDCCR) */
+#define UDCCR_DWRE      (1 <<16)        /* Device Remote Wake-up Feature */
+#define UDCCR_ACN       (1 <<11)        /* Active UDC Configuration Number */
+#define UDCCR_AIN       (1 << 8)        /* Active UDC Interface Number */
+#define	UDCCR_AAISN     (1 << 5)        /* Active UDC Alternative Interface Setting Number */
+#define UDCCR_SMAC      (1 << 4)        /* Switch Endpoint Memory to Active Configuration */
+#define UDCCR_EMCE      (1 << 3)        /* Endpoint Meory Configuration Error */
+#define UDCCR_UDR       (1 << 2)        /* UDC Resume */
+#define UDCCR_UDA       (1 << 1)        /* UDC Active */
+#define UDCCR_UDE       (1 << 0)        /* UDC Enable */
+
+#define UDCCR_ACN_MASK       0x3
+#define UDCCR_AIN_MASK       0x7
+#define UDCCR_AAISN_MASK     0x7
+
+#define UDCICR0_IE0      (1<<0)       /* EP0 Interrupt Enable */
+#define UDCICR0_IEA      (1<<2)       /* EPA Interrupt Enable */
+#define UDCICR0_IEB      (1<<4)       /* EPB Interrupt Enable */
+#define UDCICR0_IEC      (1<<6)       /* EPC Interrupt Enable */
+#define UDCICR0_IED      (1<<8)       /* EPD Interrupt Enable */
+#define UDCICR0_IEE      (1<<10)       /* EPE Interrupt Enable */
+#define UDCICR0_IEF      (1<<12)       /* EPF Interrupt Enable */
+#define UDCICR0_IEG      (1<<14)       /* EPG Interrupt Enable */
+#define UDCICR0_IEH      (1<<16)       /* EPH Interrupt Enable */
+#define UDCICR0_IEI      (1<<18)       /* EPI Interrupt Enable */
+#define UDCICR0_IEJ      (1<<20)       /* EPJ Interrupt Enable */
+#define UDCICR0_IEK      (1<<22)       /* EPK Interrupt Enable */
+#define UDCICR0_IEL      (1<<24)       /* EPL Interrupt Enable */
+#define UDCICR0_IEM      (1<<26)       /* EPM Interrupt Enable */
+#define UDCICR0_IEN      (1<<28)       /* EPN Interrupt Enable */
+#define UDCICR0_IEP      (1<<30)       /* EPP Interrupt Enable */
+#define UDCICR1_IEQ      (1<<0)        /* EPQ Interrupt Enable */
+#define UDCICR1_IER      (1<<2)        /* EPR Interrupt Enable */
+#define UDCICR1_IES      (1<<4)        /* EPS Interrupt Enable */
+#define UDCICR1_IET      (1<<6)        /* EPT Interrupt Enable */
+#define UDCICR1_IEU      (1<<8)        /* EPU Interrupt Enable */
+#define UDCICR1_IEV      (1<<10)        /* EPV Interrupt Enable */
+#define UDCICR1_IEW      (1<<12)        /* EPW Interrupt Enable */
+#define UDCICR1_IEX      (1<<14)        /* EPX Interrupt Enable */
+#define UDCICR1_IERS     (1<<27)        /* Reset */
+#define UDCICR1_IESU     (1<<28)        /* Suspend */
+#define UDCICR1_IERU     (1<<29)        /* Resume */
+#define UDCICR1_IESOF    (1<<30)        /* Start Of Frame */
+#define UDCICR1_IECC     (1<<31)        /* Configuration Changed */
+
+#define UDCISR0_IE0      (1<<0)       /* EP0 Interrupt Enable */
+#define UDCISR0_IEA      (1<<2)       /* EPA Interrupt Enable */
+#define UDCISR0_IEB      (1<<4)       /* EPB Interrupt Enable */
+#define UDCISR0_IEC      (1<<6)       /* EPC Interrupt Enable */
+#define UDCISR0_IED      (1<<8)       /* EPD Interrupt Enable */
+#define UDCISR0_IEE      (1<<10)       /* EPE Interrupt Enable */
+#define UDCISR0_IEF      (1<<12)       /* EPF Interrupt Enable */
+#define UDCISR0_IEG      (1<<14)       /* EPG Interrupt Enable */
+#define UDCISR0_IEH      (1<<16)       /* EPH Interrupt Enable */
+#define UDCISR0_IEI      (1<<18)       /* EPI Interrupt Enable */
+#define UDCISR0_IEJ      (1<<20)       /* EPJ Interrupt Enable */
+#define UDCISR0_IEK      (1<<22)       /* EPK Interrupt Enable */
+#define UDCISR0_IEL      (1<<24)       /* EPL Interrupt Enable */
+#define UDCISR0_IEM      (1<<26)       /* EPM Interrupt Enable */
+#define UDCISR0_IEN      (1<<28)       /* EPN Interrupt Enable */
+#define UDCISR0_IEP      (1<<30)       /* EPP Interrupt Enable */
+#define UDCISR1_IEQ      (1<<0)        /* EPQ Interrupt Enable */
+#define UDCISR1_IER      (1<<2)        /* EPR Interrupt Enable */
+#define UDCISR1_IES      (1<<4)        /* EPS Interrupt Enable */
+#define UDCISR1_IET      (1<<6)        /* EPT Interrupt Enable */
+#define UDCISR1_IEU      (1<<8)        /* EPU Interrupt Enable */
+#define UDCISR1_IEV      (1<<10)        /* EPV Interrupt Enable */
+#define UDCISR1_IEW      (1<<12)        /* EPW Interrupt Enable */
+#define UDCISR1_IEX      (1<<14)        /* EPX Interrupt Enable */
+#define UDCISR1_IERS     (1<<27)        /* Reset */
+#define UDCISR1_IESU     (1<<28)        /* Suspend */
+#define UDCISR1_IERU     (1<<29)        /* Resume */
+#define UDCISR1_IESOF    (1<<30)        /* Start Of Frame */
+#define UDCISR1_IECC     (1<<31)        /* Configuration Changed */
+
+#define UDC_INT_FIFOERROR  (0x2)
+#define UDC_INT_PACKETCMP  (0x1)
+
+#define UDC_FNR_MASK     (0x7ff)
+
+/* UDC Endpoint 0 Control Status Register (UDCCS0) */
+#define	UDCCSR0_OPR      (1 << 0)	/* OUT packet ready */
+#define	UDCCSR0_IPR	(1 << 1)	/* IN packet ready */
+#define	UDCCSR0_FTF	(1 << 2)	/* Flush Tx FIFO */
+#define	UDCCSR0_DME	(1 << 3)	/* DMA Enable */
+#define	UDCCSR0_SST	(1 << 4)	/* Sent stall */
+#define	UDCCSR0_FST	(1 << 5)	/* Force stall */
+#define	UDCCSR0_RNE	(1 << 6)	/* Receive FIFO not empty */
+#define	UDCCSR0_SA	(1 << 7)	/* Setup Active */
+
+/* UDC Endpoint A-X */
+#define	UDCCSR_FS	(1 << 0)	/* FIFO service */
+#define	UDCCSR_PC	(1 << 1)	/* Packet complete */
+#define	UDCCSR_TRN	(1 << 2)	/* Tx/Rx NAK */
+#define	UDCCSR_DME	(1 << 3)	/* DMA Enable */
+#define	UDCCSR_SST	(1 << 4)	/* Sent STALL */
+#define	UDCCSR_FST	(1 << 5)	/* Force STALL */
+#define UDCCSR_BNE       (1 << 6)        /* Buffer Not Empty */
+#define UDCCSR_BNF       (1 << 6)        /* Buffer Not Full */
+#define	UDCCSR_SP	(1 << 7)	/* Short packet */
+#define	UDCCSR_FEF	(1 << 8)	/* Flush Endpoint FIFO */
+#define UDCCSR_DPE       (1 << 9)        /* Data Packet Error */
+
+#define UDCCSR_WR_MASK   (UDCCSR_DME|UDCCSR_FST)
+#define UDC_BCR_MASK    (0x3ff)
+
+#define UDCCONR_EE      (1 << 0)        /* Endpoint Enable */
+#define UDCCONR_DE      (1 << 1)        /* Double-buffering Enable */
+#define UDCCONR_MPS     (1 << 2)        /* Maximum Packet Size */
+#define UDCCONR_ED      (1 <<12)        /* USB Endpoint Direction */
+#define UDCCONR_ET      (1 <<13)        /* Endpoint Type */
+#define UDCCONR_EN      (1 <<15)        /* Endpoint Number */
+#define UDCCONR_AISN    (1 <<19)        /* Alternate Interface Number */
+#define UDCCONR_IN      (1 <<22)        /* Interface Number */
+#define UDCCONR_CN      (1 <<25)        /* Configuration Number */
+
+#define UDC_CON_CN_MASK       (0x3)
+#define UDC_CON_IN_MASK       (0x7)
+#define UDC_CON_AISN_MASK     (0x7)
+#define UDC_CON_EN_MASK       (0xf)
+#define UDC_CON_ET_MASK       (0x3)
+#define UDC_CON_MPS_MASK      (0x3ff)
+
+/* DMA Request to Channel Map Register */
+
+/* Endpoint 0 state definitions */
+#define WAIT_FOR_SETUP          0
+#define DATA_STATE_XMIT         1
+#define DATA_STATE_RECV         2
+#define DATA_STATE_PENDING_XMIT 3
+#define DATA_STATE_NEED_ZLP     4
+#define WAIT_FOR_OUT_STATUS     5
+
+#endif
+
+
+#define UDCCR           __REG(0x40600000) /* UDC Control Register */
+#define UDCCR_OEN	(1 << 31)	/* On-the-Go Enable */
+#define UDCCR_AALTHNP	(1 << 30)	/* A-device Alternate Host Negotiation
+					   Protocol Port Support */
+#define UDCCR_AHNP	(1 << 29)	/* A-device Host Negotiation Protocol
+					   Support */
+#define UDCCR_BHNP	(1 << 28)	/* B-device Host Negotiation Protocol
+					   Enable */
+#define UDCCR_DWRE	(1 << 16)	/* Device Remote Wake-up Enable */
+#define UDCCR_ACN	(0x03 << 11)	/* Active UDC configuration Number */
+#define UDCCR_ACN_S	11
+#define UDCCR_AIN	(0x07 << 8)	/* Active UDC interface Number */
+#define UDCCR_AIN_S	8
+#define UDCCR_AAISN	(0x07 << 5)	/* Active UDC Alternate Interface
+					   Setting Number */
+#define UDCCR_AAISN_S	5
+#define UDCCR_SMAC	(1 << 4)	/* Switch Endpoint Memory to Active
+					   Configuration */
+#define UDCCR_EMCE	(1 << 3)	/* Endpoint Memory Configuration
+					   Error */
+#define UDCCR_UDR	(1 << 2)	/* UDC Resume */
+#define UDCCR_UDA	(1 << 1)	/* UDC Active */
+#define UDCCR_UDE	(1 << 0)	/* UDC Enable */
+
+#define UDCICR0         __REG(0x40600004) /* UDC Interrupt Control Register0 */
+#define UDCICR1         __REG(0x40600008) /* UDC Interrupt Control Register1 */
+#define UDCICR_FIFOERR	(1 << 1)	/* FIFO Error interrupt for EP */
+#define UDCICR_PKTCOMPL (1 << 0)	/* Packet Complete interrupt for EP */
+
+#define UDC_INT_FIFOERROR  (0x2)
+#define UDC_INT_PACKETCMP  (0x1)
+
+#define UDCICR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
+#define UDCICR1_IECC	(1 << 31)	/* IntEn - Configuration Change */
+#define UDCICR1_IESOF	(1 << 30)	/* IntEn - Start of Frame */
+#define UDCICR1_IERU	(1 << 29)	/* IntEn - Resume */
+#define UDCICR1_IESU	(1 << 28)	/* IntEn - Suspend */
+#define UDCICR1_IERS	(1 << 27)	/* IntEn - Reset */
+
+#define UDCISR0         __REG(0x4060000C) /* UDC Interrupt Status Register 0 */
+#define UDCISR1         __REG(0x40600010) /* UDC Interrupt Status Register 1 */
+#define UDCISR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
+#define UDCISR1_IECC	(1 << 31)	/* IntEn - Configuration Change */
+#define UDCISR1_IESOF	(1 << 30)	/* IntEn - Start of Frame */
+#define UDCISR1_IERU	(1 << 29)	/* IntEn - Resume */
+#define UDCISR1_IESU	(1 << 28)	/* IntEn - Suspend */
+#define UDCISR1_IERS	(1 << 27)	/* IntEn - Reset */
+
+
+#define UDCFNR          __REG(0x40600014) /* UDC Frame Number Register */
+#define UDCOTGICR	__REG(0x40600018) /* UDC On-The-Go interrupt control */
+#define UDCOTGICR_IESF	(1 << 24)	/* OTG SET_FEATURE command recvd */
+#define UDCOTGICR_IEXR	(1 << 17)	/* Extra Transciever Interrupt
+					   Rising Edge Interrupt Enable */
+#define UDCOTGICR_IEXF	(1 << 16)	/* Extra Transciever Interrupt
+					   Falling Edge Interrupt Enable */
+#define UDCOTGICR_IEVV40R (1 << 9)	/* OTG Vbus Valid 4.0V Rising Edge
+					   Interrupt Enable */
+#define UDCOTGICR_IEVV40F (1 << 8)	/* OTG Vbus Valid 4.0V Falling Edge
+					   Interrupt Enable */
+#define UDCOTGICR_IEVV44R (1 << 7)	/* OTG Vbus Valid 4.4V Rising Edge
+					   Interrupt Enable */
+#define UDCOTGICR_IEVV44F (1 << 6)	/* OTG Vbus Valid 4.4V Falling Edge
+					   Interrupt Enable */
+#define UDCOTGICR_IESVR	(1 << 5)	/* OTG Session Valid Rising Edge
+					   Interrupt Enable */
+#define UDCOTGICR_IESVF	(1 << 4)	/* OTG Session Valid Falling Edge
+					   Interrupt Enable */
+#define UDCOTGICR_IESDR	(1 << 3)	/* OTG A-Device SRP Detect Rising
+					   Edge Interrupt Enable */
+#define UDCOTGICR_IESDF	(1 << 2)	/* OTG A-Device SRP Detect Falling
+					   Edge Interrupt Enable */
+#define UDCOTGICR_IEIDR	(1 << 1)	/* OTG ID Change Rising Edge
+					   Interrupt Enable */
+#define UDCOTGICR_IEIDF	(1 << 0)	/* OTG ID Change Falling Edge
+					   Interrupt Enable */
+
+#define UDCCSN(x)	__REG2(0x40600100, (x) << 2)
+#define UDCCSR0         __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */
+#define UDCCSR0_SA	(1 << 7)	/* Setup Active */
+#define UDCCSR0_RNE	(1 << 6)	/* Receive FIFO Not Empty */
+#define UDCCSR0_FST	(1 << 5)	/* Force Stall */
+#define UDCCSR0_SST	(1 << 4)	/* Sent Stall */
+#define UDCCSR0_DME	(1 << 3)	/* DMA Enable */
+#define UDCCSR0_FTF	(1 << 2)	/* Flush Transmit FIFO */
+#define UDCCSR0_IPR	(1 << 1)	/* IN Packet Ready */
+#define UDCCSR0_OPC	(1 << 0)	/* OUT Packet Complete */
+
+#define UDCCSRA         __REG(0x40600104) /* UDC Control/Status register - Endpoint A */
+#define UDCCSRB         __REG(0x40600108) /* UDC Control/Status register - Endpoint B */
+#define UDCCSRC         __REG(0x4060010C) /* UDC Control/Status register - Endpoint C */
+#define UDCCSRD         __REG(0x40600110) /* UDC Control/Status register - Endpoint D */
+#define UDCCSRE         __REG(0x40600114) /* UDC Control/Status register - Endpoint E */
+#define UDCCSRF         __REG(0x40600118) /* UDC Control/Status register - Endpoint F */
+#define UDCCSRG         __REG(0x4060011C) /* UDC Control/Status register - Endpoint G */
+#define UDCCSRH         __REG(0x40600120) /* UDC Control/Status register - Endpoint H */
+#define UDCCSRI         __REG(0x40600124) /* UDC Control/Status register - Endpoint I */
+#define UDCCSRJ         __REG(0x40600128) /* UDC Control/Status register - Endpoint J */
+#define UDCCSRK         __REG(0x4060012C) /* UDC Control/Status register - Endpoint K */
+#define UDCCSRL         __REG(0x40600130) /* UDC Control/Status register - Endpoint L */
+#define UDCCSRM         __REG(0x40600134) /* UDC Control/Status register - Endpoint M */
+#define UDCCSRN         __REG(0x40600138) /* UDC Control/Status register - Endpoint N */
+#define UDCCSRP         __REG(0x4060013C) /* UDC Control/Status register - Endpoint P */
+#define UDCCSRQ         __REG(0x40600140) /* UDC Control/Status register - Endpoint Q */
+#define UDCCSRR         __REG(0x40600144) /* UDC Control/Status register - Endpoint R */
+#define UDCCSRS         __REG(0x40600148) /* UDC Control/Status register - Endpoint S */
+#define UDCCSRT         __REG(0x4060014C) /* UDC Control/Status register - Endpoint T */
+#define UDCCSRU         __REG(0x40600150) /* UDC Control/Status register - Endpoint U */
+#define UDCCSRV         __REG(0x40600154) /* UDC Control/Status register - Endpoint V */
+#define UDCCSRW         __REG(0x40600158) /* UDC Control/Status register - Endpoint W */
+#define UDCCSRX         __REG(0x4060015C) /* UDC Control/Status register - Endpoint X */
+
+#define UDCCSR_DPE	(1 << 9)	/* Data Packet Error */
+#define UDCCSR_FEF	(1 << 8)	/* Flush Endpoint FIFO */
+#define UDCCSR_SP	(1 << 7)	/* Short Packet Control/Status */
+#define UDCCSR_BNE	(1 << 6)	/* Buffer Not Empty (IN endpoints) */
+#define UDCCSR_BNF	(1 << 6)	/* Buffer Not Full (OUT endpoints) */
+#define UDCCSR_FST	(1 << 5)	/* Force STALL */
+#define UDCCSR_SST	(1 << 4)	/* Sent STALL */
+#define UDCCSR_DME	(1 << 3)	/* DMA Enable */
+#define UDCCSR_TRN	(1 << 2)	/* Tx/Rx NAK */
+#define UDCCSR_PC	(1 << 1)	/* Packet Complete */
+#define UDCCSR_FS	(1 << 0)	/* FIFO needs service */
+
+#define UDCBCN(x)	__REG2(0x40600200, (x)<<2)
+#define UDCBCR0         __REG(0x40600200) /* Byte Count Register - EP0 */
+#define UDCBCRA         __REG(0x40600204) /* Byte Count Register - EPA */
+#define UDCBCRB         __REG(0x40600208) /* Byte Count Register - EPB */
+#define UDCBCRC         __REG(0x4060020C) /* Byte Count Register - EPC */
+#define UDCBCRD         __REG(0x40600210) /* Byte Count Register - EPD */
+#define UDCBCRE         __REG(0x40600214) /* Byte Count Register - EPE */
+#define UDCBCRF         __REG(0x40600218) /* Byte Count Register - EPF */
+#define UDCBCRG         __REG(0x4060021C) /* Byte Count Register - EPG */
+#define UDCBCRH         __REG(0x40600220) /* Byte Count Register - EPH */
+#define UDCBCRI         __REG(0x40600224) /* Byte Count Register - EPI */
+#define UDCBCRJ         __REG(0x40600228) /* Byte Count Register - EPJ */
+#define UDCBCRK         __REG(0x4060022C) /* Byte Count Register - EPK */
+#define UDCBCRL         __REG(0x40600230) /* Byte Count Register - EPL */
+#define UDCBCRM         __REG(0x40600234) /* Byte Count Register - EPM */
+#define UDCBCRN         __REG(0x40600238) /* Byte Count Register - EPN */
+#define UDCBCRP         __REG(0x4060023C) /* Byte Count Register - EPP */
+#define UDCBCRQ         __REG(0x40600240) /* Byte Count Register - EPQ */
+#define UDCBCRR         __REG(0x40600244) /* Byte Count Register - EPR */
+#define UDCBCRS         __REG(0x40600248) /* Byte Count Register - EPS */
+#define UDCBCRT         __REG(0x4060024C) /* Byte Count Register - EPT */
+#define UDCBCRU         __REG(0x40600250) /* Byte Count Register - EPU */
+#define UDCBCRV         __REG(0x40600254) /* Byte Count Register - EPV */
+#define UDCBCRW         __REG(0x40600258) /* Byte Count Register - EPW */
+#define UDCBCRX         __REG(0x4060025C) /* Byte Count Register - EPX */
+
+#define UDCDN(x)	__REG2(0x40600300, (x)<<2)
+#define PHYS_UDCDN(x)	(0x40600300 + ((x)<<2))
+#define PUDCDN(x)	(volatile u32 *)(io_p2v(PHYS_UDCDN((x))))
+#define UDCDR0          __REG(0x40600300) /* Data Register - EP0 */
+#define UDCDRA          __REG(0x40600304) /* Data Register - EPA */
+#define UDCDRB          __REG(0x40600308) /* Data Register - EPB */
+#define UDCDRC          __REG(0x4060030C) /* Data Register - EPC */
+#define UDCDRD          __REG(0x40600310) /* Data Register - EPD */
+#define UDCDRE          __REG(0x40600314) /* Data Register - EPE */
+#define UDCDRF          __REG(0x40600318) /* Data Register - EPF */
+#define UDCDRG          __REG(0x4060031C) /* Data Register - EPG */
+#define UDCDRH          __REG(0x40600320) /* Data Register - EPH */
+#define UDCDRI          __REG(0x40600324) /* Data Register - EPI */
+#define UDCDRJ          __REG(0x40600328) /* Data Register - EPJ */
+#define UDCDRK          __REG(0x4060032C) /* Data Register - EPK */
+#define UDCDRL          __REG(0x40600330) /* Data Register - EPL */
+#define UDCDRM          __REG(0x40600334) /* Data Register - EPM */
+#define UDCDRN          __REG(0x40600338) /* Data Register - EPN */
+#define UDCDRP          __REG(0x4060033C) /* Data Register - EPP */
+#define UDCDRQ          __REG(0x40600340) /* Data Register - EPQ */
+#define UDCDRR          __REG(0x40600344) /* Data Register - EPR */
+#define UDCDRS          __REG(0x40600348) /* Data Register - EPS */
+#define UDCDRT          __REG(0x4060034C) /* Data Register - EPT */
+#define UDCDRU          __REG(0x40600350) /* Data Register - EPU */
+#define UDCDRV          __REG(0x40600354) /* Data Register - EPV */
+#define UDCDRW          __REG(0x40600358) /* Data Register - EPW */
+#define UDCDRX          __REG(0x4060035C) /* Data Register - EPX */
+
+#define UDCCN(x)       __REG2(0x40600400, (x)<<2)
+#define UDCCRA          __REG(0x40600404) /* Configuration register EPA */
+#define UDCCRB          __REG(0x40600408) /* Configuration register EPB */
+#define UDCCRC          __REG(0x4060040C) /* Configuration register EPC */
+#define UDCCRD          __REG(0x40600410) /* Configuration register EPD */
+#define UDCCRE          __REG(0x40600414) /* Configuration register EPE */
+#define UDCCRF          __REG(0x40600418) /* Configuration register EPF */
+#define UDCCRG          __REG(0x4060041C) /* Configuration register EPG */
+#define UDCCRH          __REG(0x40600420) /* Configuration register EPH */
+#define UDCCRI          __REG(0x40600424) /* Configuration register EPI */
+#define UDCCRJ          __REG(0x40600428) /* Configuration register EPJ */
+#define UDCCRK          __REG(0x4060042C) /* Configuration register EPK */
+#define UDCCRL          __REG(0x40600430) /* Configuration register EPL */
+#define UDCCRM          __REG(0x40600434) /* Configuration register EPM */
+#define UDCCRN          __REG(0x40600438) /* Configuration register EPN */
+#define UDCCRP          __REG(0x4060043C) /* Configuration register EPP */
+#define UDCCRQ          __REG(0x40600440) /* Configuration register EPQ */
+#define UDCCRR          __REG(0x40600444) /* Configuration register EPR */
+#define UDCCRS          __REG(0x40600448) /* Configuration register EPS */
+#define UDCCRT          __REG(0x4060044C) /* Configuration register EPT */
+#define UDCCRU          __REG(0x40600450) /* Configuration register EPU */
+#define UDCCRV          __REG(0x40600454) /* Configuration register EPV */
+#define UDCCRW          __REG(0x40600458) /* Configuration register EPW */
+#define UDCCRX          __REG(0x4060045C) /* Configuration register EPX */
+
+#define UDCCONR_CN	(0x03 << 25)	/* Configuration Number */
+#define UDCCONR_CN_S	(25)
+#define UDCCONR_IN	(0x07 << 22)	/* Interface Number */
+#define UDCCONR_IN_S	(22)
+#define UDCCONR_AISN	(0x07 << 19)	/* Alternate Interface Number */
+#define UDCCONR_AISN_S	(19)
+#define UDCCONR_EN	(0x0f << 15)	/* Endpoint Number */
+#define UDCCONR_EN_S	(15)
+#define UDCCONR_ET	(0x03 << 13)	/* Endpoint Type: */
+#define UDCCONR_ET_S	(13)
+#define UDCCONR_ET_INT	(0x03 << 13)	/*   Interrupt */
+#define UDCCONR_ET_BULK	(0x02 << 13)	/*   Bulk */
+#define UDCCONR_ET_ISO	(0x01 << 13)	/*   Isochronous */
+#define UDCCONR_ET_NU	(0x00 << 13)	/*   Not used */
+#define UDCCONR_ED	(1 << 12)	/* Endpoint Direction */
+#define UDCCONR_MPS	(0x3ff << 2)	/* Maximum Packet Size */
+#define UDCCONR_MPS_S	(2)
+#define UDCCONR_DE	(1 << 1)	/* Double Buffering Enable */
+#define UDCCONR_EE	(1 << 0)	/* Endpoint Enable */
+
+
+#define UDC_INT_FIFOERROR  (0x2)
+#define UDC_INT_PACKETCMP  (0x1)
+
+#define UDC_FNR_MASK     (0x7ff)
+
+#define UDCCSR_WR_MASK   (UDCCSR_DME|UDCCSR_FST)
+#define UDC_BCR_MASK    (0x3ff)
+
+
diff -uNr linux/drivers/no-otg/otghw/cea-936.h linux/drivers/otg/otghw/cea-936.h
--- linux/drivers/no-otg/otghw/cea-936.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otghw/cea-936.h	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,148 @@
+/*
+ * otg/carkit.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ *
+ * Notes
+ *
+ * 1. Document references are to CEA-936a - Dec 12, 2003
+ *
+ */
+/*!
+ * @defgroup CEA
+ * @ingroup tcdgroup
+ */
+/*!
+ * @file otghw/cea-936.h
+ * @brief Hardware defines for CEA-936 Hardware
+ *
+ * @ingroup CEA
+ */
+
+
+/* 
+ * Command Descriptions - C.f. 10.3
+ */
+#define CARKIT_GET_DEVICE       0x01
+#define CARKIT_GET_CARKIT       0x02
+#define CARKIT_AUDIO_EN         0x03
+#define CARKIT_SET_CRNT         0x04
+#define CARKIT_SET_UART         0x05
+#define CARKIT_CARKIT_MASTER    0x06
+
+/* 
+ * generic get command
+ */
+struct carkit_get {
+        u8      strt;
+        u8      command_type;
+        u8      crc;
+        u8      terminator;
+};
+
+struct carkit_set {
+        u8      strt;
+        u8      command_type;
+        u8      command_value;
+        u8      crc;
+        u8      terminator;
+};
+
+struct carkit_get_carkit_ack {
+        u8      ack;
+        u8      terminator;
+};
+
+/*
+ * Get Device - C.f 10.3.1
+ */
+
+struct carkit_get_device_carkit {
+        u8      ack;
+        u8      device_id;
+        u16     vendor_id;
+        u16     product_id;
+        u8      crc;
+        u8      terminator;
+};
+
+#define CARKIT_DEVICE_ID_GENERIC        0x01
+#define CARKIT_DEVICE_ID_ENHANCED       0x02
+#define CARKIT_DEVICE_ID_PROPRIETARY    0x03
+
+
+/*
+ * Get CarKit - C.f. 10.3.2
+ */
+
+struct carkit_get_carkit_carkit {
+        u8      ack;
+        u16     cr_ftrs;
+        u8      cr_sts;
+        u8      crc;
+        u8      terminator;
+};
+
+#define CARKIT_CR_FTRS_0_STERO          (1 << 0)
+#define CARKIT_CR_FTRS_0_CRNT_ADJ       (1 << 1)
+#define CARKIT_CR_FTRS_0_UART_MAX       (7 << 2)
+#define CARKIT_CR_FTRS_0_UART_MSTR      (1 << 5)
+
+#define CARKIT_CR_FTRS_1_PH_REMOVE_FTR  (1 << 0)
+#define CARKIT_CR_FTRS_1_CAR_OFF_FTR    (1 << 1)
+#define CARKIT_CR_FTRS_1_CRDL_BTN_FTR   (1 << 2)
+
+#define CARKIT_CR_PH_REMOVE_STS         (1 << 0)
+#define CARKIT_CR_CAR_OFF_STS           (1 << 1)
+#define CARKIT_CR_CRDL_BTN_STS          (1 << 2)
+#define CARKIT_CR_PH_RMV_CHG            (1 << 4)
+#define CARKIT_CR_CAR_OFF_CHG           (1 << 5)
+#define CARKIT_CR_CRDL_BTN_CHG          (1 << 6)
+
+
+/*
+ * Set Carkit - C.f. 10.3.3
+ */
+#define CARKIT_CR_CTL_PH_RMV_IEN        (1 << 0)
+#define CARKIT_CR_CAR_OFF_IEN           (1 << 1)
+#define CARKIT_CR_CRDL_BTN_IEN          (1 << 2)
+#define CARKIT_CR_CARKIT_MSTR           (1 << 5)
+#define CARKIT_CR_PULSE_ID              (1 << 6)
+#define CARKIT_CR_ID_INT_EN             (1 << 7)
+
+
+/*
+ * Audio En - C.f. 10.3.4
+ */
+#define CARKIT_AUDIO_MODE_MONO          (1 << 0)
+#define CARKIT_AUDIO_MODE_STEREO        (1 << 1)
+
+/*
+ * Set Crnt - C.f. 10.3.5
+ */
+#define CARKIT_CRNT_LMT                 (0xf)
+
+
+/*
+ * Set UART - C.f. 10.3.6
+ */
+#define CARKIT_UART_SPEED_9600          (1 << 0)
+#define CARKIT_UART_SPEED_19200         (1 << 1)
+#define CARKIT_UART_SPEED_38400         (1 << 3)
+#define CARKIT_UART_SPEED_57600         (1 << 4)
+#define CARKIT_UART_SPEED_115200        (1 << 4)
+
+
+/*
+ * Special chars - C.f. 10.4
+ */
+#define CARKIT_STRT                     0x41
+#define CARKIT_ESC                      0x18
+#define CARKIT_ACK                      0x06
+#define CARKIT_NYET                     0x30
+#define CARKIT_NAK                      0x15
+#define CARKIT_NSUP                     0x1f
+#define CARKIT_CR                       0x0d
+
+
diff -uNr linux/drivers/no-otg/otghw/fsotg-hardware.h linux/drivers/otg/otghw/fsotg-hardware.h
--- linux/drivers/no-otg/otghw/fsotg-hardware.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otghw/fsotg-hardware.h	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,1054 @@
+/*
+ * otghw/fsotg-hardware.h
+ *
+ * Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+
+/*!
+ * @defgroup FSOTG Freescale USBOTG Support
+ * @ingroup libgroup
+ */
+/*!
+ * @file otghw/fsotg-hardware.h
+ * @brief Hardware defines for Freescale USBOTG Hardware
+ *
+ * This supports the Freescale implementation of the Trans Dimension 
+ * USBOTG.
+ *
+ * This is used on:
+ *
+ *      - i.MX21
+ *      - SCM-A11
+ *      - Argon+
+ *      - Zeus
+ *
+ * @ingroup FSOTG
+ */
+
+#if defined(CONFIG_ARCH_MX2ADS)
+#include <otghw/mx2ads.h>
+#include <otghw/mx2ads-hardware.h>
+#endif /* defined(CONFIG_ARCH_MX2ADS) */
+
+#if defined(CONFIG_ARCH_SCMA11EVB)
+#endif /* defined(CONFIG_ARCH_SCMA11EVB) */
+
+
+
+/*!
+ * @name OTG_SYS_CTRL
+ * C.f. 23.8 USB Control Register
+ */
+ /*! @{ */
+
+//#define OTG_SYS_CTRL                          (OTG_SYS_BASE+0x00)
+
+#define SYS_CTRL_I2C_WU_INT_STAT                (1 << 27)
+#define SYS_CTRL_OTG_WU_INT_STAT                (1 << 26)
+#define SYS_CTRL_HOST_WU_INT_STAT               (1 << 25)
+#define SYS_CTRL_FNT_WU_INT_STAT                (1 << 24)
+
+#define SYS_CTRL_I2C_WU_INT_EN                  (1 << 19)
+#define SYS_CTRL_OTG_WU_INT_EN                  (1 << 18)
+#define SYS_CTRL_HOST_WU_INT_EN                 (1 << 17)
+#define SYS_CTRL_FNT_WU_INT_EN                  (1 << 16)
+
+#define SYS_CTRL_OTG_BYP_VAL                    (0x3 << 11)
+#define SYS_CTRL_HOST1_BYP_VAL                  (0x3 << 9)
+
+#define SYS_CTRL_OTG_PWR_MASK                   (1 << 6)
+#define SYS_CTRL_HOST1_PWR_MASK                 (1 << 6)
+#define SYS_CTRL_HOST2_PWR_MASK                 (1 << 4)
+#define SYS_CTRL_USB_BYP                        (1 << 2)
+#define SYS_CTRL_HOST1_TXEN_OE                  (1 << 1)
+/*! @} */
+
+/*! 
+ * @name C.f. 23.9 USBOTG Module Registers
+ */
+ /*! @{ */
+
+#define OTG_CORE_HWMODE                         (OTG_CORE_BASE+0x00)            //  32bit core hardware mode reg
+
+#define XCVR_D_D                                0x00
+#define XCVR_SE_D                               0x01
+#define XCVR_D_SE                               0x02
+#define XCVR_SE_SE                              0x03
+
+#define MODULE_ANASDBEN                         (1 << 14)
+#define MODULE_OTGXCVR                          (0x3 << 6)
+#define MODULE_HOSTXCVR                         (0x3 << 4)
+#define MODULE_CRECFG                           (0x3)
+#define MODULE_CRECFG_HHNP                      (0x0)
+#define MODULE_CRECFG_HOST                      (0x1)
+#define MODULE_CRECFG_FUNC                      (0x2)
+#define MODULE_CRECFG_SHNP                      (0x3)
+
+#define OTG_CORE_CINT_STAT                      (OTG_CORE_BASE+0x04)            //  32bit core int status reg
+
+#define MODULE_FCINTDSPEN                       (1 << 6)
+
+#define MODULE_ASHNPINT                         (1 << 5)
+#define MODULE_ASFCINT                          (1 << 4)
+#define MODULE_ASHCINT                          (1 << 3)
+#define MODULE_HNPINT                           (1 << 2)
+#define MODULE_FCINT                            (1 << 1)
+#define MODULE_HCINT                            (1)
+
+#define OTG_CORE_CINT_STEN                      (OTG_CORE_BASE+0x08)            //  32bit core int enable reg
+
+#define MODULE_ASHNPINT_EN                      (1 << 5)
+#define MODULE_ASFCINT_EN                       (1 << 4)
+#define MODULE_ASHCINT_EN                       (1 << 3)
+#define MODULE_HNPINT_EN                        (1 << 2)
+#define MODULE_FCINT_EN                         (1 << 1)
+#define MODULE_HCINT_EN                         (1)
+
+#define OTG_CORE_CLK_CTRL                       (OTG_CORE_BASE+0x0C)            //  32bit core clock control reg
+
+#define MODULE_FUNC_CLK                         (1 << 2)
+#define MODULE_HOST_CLK                         (1 << 1)
+#define MODULE_MAIN_CLK                         (1)
+
+#define OTG_CORE_RST_CTRL                       (OTG_CORE_BASE+0x10)            // 32bit core reset control reg
+
+#define MODULE_RSTI2C                           (1 << 15)
+#define MODULE_RSTCTRL                          (1 << 5)
+#define MODULE_RSTFC                            (1 << 4)
+#define MODULE_RSTFSIE                          (1 << 3)
+#define MODULE_RSTRH                            (1 << 2)
+#define MODULE_RSTHSIE                          (1 << 1)
+#define MODULE_RSTHC                            (1)
+
+#define OTG_CORE_FRM_INTVL                      (OTG_CORE_BASE+0x14)            //  32bit core frame interval reg
+
+#define MODULE_RESET_FRAME                      (1 << 15)
+
+#define OTG_CORE_FRM_REMAIN                     (OTG_CORE_BASE+0x18)            //  32bit core frame remaining reg
+
+#define OTG_CORE_HNP_CSTAT                      (OTG_CORE_BASE+0x1C)            //  32bit core HNP current state reg
+
+#define MODULE_HNPDAT                           (1 << 30)
+#define MODULE_VBUSBSE                          (1 << 29)
+#define MODULE_VBUSABSV                         (1 << 28)
+#define MODULE_VBUSGTAVV                        (1 << 27)
+
+#define MODULE_ARMTHNPE                         (1 << 25)
+#define MODULE_BHNPEN                           (1 << 24)
+
+#define MODULE_SLAVE                            (1 << 22)
+#define MODULE_MASTER                           (1 << 21)
+#define MODULE_BGEN                             (1 << 20)
+#define MODULE_CMPEN                            (1 << 19)
+#define MODULE_ISBDEV                           (1 << 18)
+#define MODULE_ISADEV                           (1 << 17)
+
+#define MODULE_SWVBUSPUL                        (1 << 15)
+
+#define MODULE_SWAUTORST                        (1 << 12)
+#define MODULE_SWPUDP                           (1 << 11)
+
+#define MODULE_SWPDDM                           (1 << 9)
+#define MODULE_HNPSTATE                         (0x1f << 8)
+#define MODULE_CLRERROR                         (1 << 3)
+#define MODULE_ADROPBUS                         (1 << 2)
+#define MODULE_ABBUSREQ                         (1 << 1)
+
+#define HNP_A_IDLE                              (0x10 << 8)
+#define HNP_A_MASTER                            (0x11 << 8)
+#define HNP_A_SLAVE                             (0x12 << 8)
+#define HNP_A_WAIT_VPULSE                       (0x13 << 8)
+
+#define HNP_A_WAIT_DPULSE                       (0x14 << 8)
+#define HNP_A_WAIT_CONN_A                       (0x15 << 8)
+#define HNP_A_WAIT_CONN_B                       (0x16 << 8)
+#define HNP_A_WAIT_VRISE                        (0x17 << 8)
+#define HNP_A_SUSPEND                           (0x18 << 8)
+#define HNP_A_WAIT_VFALL                        (0x19 << 8)
+#define HNP_A_VBUS_ERR                          (0x1a << 8)
+#define HNP_CONN_DEBOUNCE                       (0x1b << 8)
+#define HNP_A_WAIT_ABREQ                        (0x1c << 8)
+#define HNP_B_IDLE                              (0x00 << 8)
+#define HNP_B_MASTER                            (0x01 << 8)
+#define HNP_B_SLAVE                             (0x02 << 8)
+#define HNP_B_SRP_INIT_V                        (0x03 << 8)
+#define HNP_B_SRP_INIT_D                        (0x04 << 8)
+#define HNP_B_PRE_WAIT_CONN_AB_SHORT_DB         (0x05 << 8)
+#define HNP_B_WAIT_CONN_A                       (0x06 << 8)
+#define HNP_B_PRE_SLAVE                         (0x0a << 8)
+
+
+#define OTG_CORE_HNP_TIMER1                     (OTG_CORE_BASE+0x20)            //  32bit core HNP timer 1 reg
+#define OTG_CORE_HNP_TIMER2                     (OTG_CORE_BASE+0x24)            //  32bit core HNP timer 2 reg
+#define OTG_CORE_HNP_T3PCR                      (OTG_CORE_BASE+0x28)            //  32bit core HNP timer 3 pulse ctrl
+
+#define HNP_DATAPULSE                           (1 << 5)
+#define HNP_VBUSPULSE                           (1 << 4)
+
+#define OTG_CORE_HINT_STAT                      (OTG_CORE_BASE+0x2C)            //  32bit core HNP int status reg
+
+#define HNP_I2COTGINT                           (1 << 15)
+#define HNP_AWAITBTO                            (1 << 8)                        // Hardware HNP Only
+#define HNP_AIDLEBDTO                           (1 << 7)                        // Hardware HNP Only
+#define HNP_SRPSUCFAIL                          (1 << 6)                        // Hardware HNP Only
+#define HNP_SRPINT                              (1 << 5)
+#define HNP_VBUSERROR                           (1 << 4)                        // Hardware HNP Only
+#define HNP_ABSEVAILD                           (1 << 3)
+#define HNP_ABUSVALID                           (1 << 2)
+#define HNP_MASSLVCHG                           (1 << 1)                        // Hardware HNP Only
+#define HNP_IDCHANGE                            (1)
+
+#define OTG_CORE_HINT_STEN                      (OTG_CORE_BASE+0x30)            //  32bit core HNP int enable reg
+
+#define HNP_I2COTGINT_EN                        (1 << 15)
+#define HNP_AWAITBTO_EN                         (1 << 8)
+#define HNP_AIDLEBDTO_EN                        (1 << 7)
+#define HNP_SRPSUCFAIL_EN                       (1 << 6)
+#define HNP_SRPINT_EN                           (1 << 5)
+#define HNP_VBUSERROR_EN                        (1 << 4)
+#define HNP_ABSEVAILD_EN                        (1 << 3)
+#define HNP_ABUSVALID_EN                        (1 << 2)
+#define HNP_MASSLVCHG_EN                        (1 << 1)
+#define HNP_IDCHANGE_EN                         (1)
+
+
+#define OTG_CORE_CPUEPSEL_STAT                  (OTG_CORE_BASE+0x34)
+#define OTG_CORE_INTERRUPT_STEN                 (OTG_CORE_BASE+0x3c)
+/*! @} */
+
+
+/*!
+ * @name C.f. 23.11.11 Host Registers
+ */
+ /*! @{ */
+
+
+#define OTG_HOST_CONTROL                        (OTG_HOST_BASE+0x00)     //  32bit host controller config reg
+
+#define HOST_CONTROL_HCRESET                    (1 << 31)
+#define HOST_CONTROL_RMTWUEN                    (1 << 4)
+
+#define HOST_CONTROL_HCUSBSTE_RESET             (0 << 2)
+#define HOST_CONTROL_HCUSBSTE_RESUME            (1 << 2)
+#define HOST_CONTROL_HCUSBSTE_OPERATIONAL       (2 << 2)
+#define HOST_CONTROL_HCUSBSTE_SUSPEND           (3 << 2)
+
+#define HOST_CONTROL_CTLBLKSR_11                (0)
+#define HOST_CONTROL_CTLBLKSR_21                (1)
+#define HOST_CONTROL_CTLBLKSR_41                (2)
+#define HOST_CONTROL_CTLBLKSR_81                (3)
+
+
+#define OTG_HOST_SINT_STAT                      (OTG_HOST_BASE+0x08)     //  32bit host system int status reg
+
+#define HOST_PSCINT                             (1 << 6)                // Port Status Change 
+#define HOST_FMOFINT                            (1 << 5)                // Frame Number Overflow
+#define HOST_HERRINT                            (1 << 4)                // Host Error
+#define HOST_RESDETINT                          (1 << 3)                // Resume Detected
+#define HOST_SOFINT                             (1 << 2)                // Start of Frame
+#define HOST_DONEINT                            (1 << 1)                // Done Register
+#define HOST_SORINT                             (1)                     // Schedule Overrun
+
+#define OTG_HOST_SINT_STEN                      (OTG_HOST_BASE+0x0C)     //  32bit host system int enable reg
+
+#define HOST_PSCINT_EN                          (1 << 6)                // Port Status Change 
+#define HOST_FMOFINT_EN                         (1 << 5)                // Frame Number Overflow
+#define HOST_HERRINT_EN                         (1 << 4)                // Host Error
+#define HOST_RESDETINT_EN                       (1 << 3)                // Resume Detected
+#define HOST_SOFINT_EN                          (1 << 2)                // Start of Frame
+#define HOST_DONEINT_EN                         (1 << 1)                // Done Register
+#define HOST_SORINT_EN                          (1)                     // Schedule Overrun
+
+#define OTG_HOST_XINT_STAT                      (OTG_HOST_BASE+0x18)     //  32bit host X buf int status reg
+#define OTG_HOST_YINT_STAT                      (OTG_HOST_BASE+0x1C)     //  32bit host Y buf int status reg
+
+#define OTG_HOST_XYINT_STEN                     (OTG_HOST_BASE+0x20)     //  32bit host XY buf int enable reg
+#define OTG_HOST_XFILL_STAT                     (OTG_HOST_BASE+0x28)     //  32bit host X filled status reg
+#define OTG_HOST_YFILL_STAT                     (OTG_HOST_BASE+0x2C)     //  32bit host Y filled status reg
+
+#define OTG_HOST_ETD_EN                         (OTG_HOST_BASE+0x40)     //  32bit host ETD enables reg
+#define OTG_HOST_DIR_ROUTE                      (OTG_HOST_BASE+0x48)     //  32bit host direct routing reg
+#define OTG_HOST_IINT                           (OTG_HOST_BASE+0x4C)     //  32bit host immediate interrupt reg
+
+#define OTG_HOST_EP_DSTAT                       (OTG_HOST_BASE+0x50)     //  32bit host endpoints done status
+#define OTG_HOST_ETD_DONE                       (OTG_HOST_BASE+0x54)     //  32bit host ETD done reg
+
+#define OTG_HOST_FRM_NUM                        (OTG_HOST_BASE+0x60)     //  32bit host frame number reg
+#define OTG_HOST_LSP_THRESH                     (OTG_HOST_BASE+0x64)     //  32bit host low speed threshold reg
+
+#define OTG_HOST_ROOTHUB_DESCA                  (OTG_HOST_BASE+0x68)     //  32bit host root hub descriptor A
+#define OTG_HOST_ROOTHUB_DESCB                  (OTG_HOST_BASE+0x6C)     //  32bit host root hub descriptor B
+/* @} */
+
+/*!
+ * @name C.f. 23.11.29
+ */
+/*! @{ */
+#define OTG_HOST_ROOTHUB_STATUS                 (OTG_HOST_BASE+0x70)     //  32bit host root hub status reg
+
+#define ROOTHUB_STATUS_CLRMTWUE                 (1 << 31)               // Clear Remote Wakeup Enable
+#define ROOTHUB_STATUS_OVRCURCHG                (1 << 17)               // Over Current Indicator Change
+#define ROOTHUB_STATUS_LOCPWRSC                 (1 << 16)               // Local Power Status Change
+#define ROOTHUB_STATUS_DEVCONWUE                (1 << 15)               // Device Connect Wakeup Enable
+#define ROOTHUB_STATUS_OVRCURI                  (1 << 1)                // Over Current Indicator
+#define ROOTHUB_STATUS_LOCPWRS                  (1)                     // Local Power Status
+/*! @} */
+
+
+/*!
+ * @name C.f. 23.11.30
+ */
+/*! @{ */
+#define OTG_HOST_PORT_STATUS_1                  (OTG_HOST_BASE+0x74)     //  32bit host port 1 status bits
+#define OTG_HOST_PORT_STATUS_2                  (OTG_HOST_BASE+0x78)     //  32bit host port 2 status bits
+#define OTG_HOST_PORT_STATUS_3                  (OTG_HOST_BASE+0x7c)     //  32bit host port 3 status bits
+
+#define PORT_STATUS_PRTRSTSC                    (1 << 20)               // Port Reset Status Change
+#define PORT_STATUS_OVRCURIC                    (1 << 19)               // Port Over Current Indicator Change
+#define PORT_STATUS_PRTSTATSC                   (1 << 18)               // Port Suspend Status Change
+#define PORT_STATUS_PRTENBLSC                   (1 << 17)               // Port Enable Status Change
+#define PORT_STATUS_CONNECTSC                   (1 << 16)               // Connect Status Change
+
+#define PORT_STATUS_LSDEVCON                    (1 << 9)                // Low Speed Device Attached
+#define PORT_STATUS_PRTPWRST                    (1 << 8)                // Port Power Status
+
+#define PORT_STATUS_PRTRSTST                    (1 << 4)                // Port Reset Status
+#define PORT_STATUS_PRTOVRCURI                  (1 << 3)                // Port Over Current Indicator
+#define PORT_STATUS_PRTSUSPST                   (1 << 2)                // Port Suspend Status
+#define PORT_STATUS_PRTENABST                   (1 << 1)                // Port Enable Status
+#define PORT_STATUS_CURCONST                    (1)                     // Current Connect Status
+
+
+/* flags are the same for the interrupt, control and bulk transfer descriptors */
+// R1: sec 23.11.10.2,3 pg 23-44,47
+#define ETD_GET_COMPCODE(flags)   ((flags >> 12) & 0xf)
+// R1: sec 23.11.10 Table 23-23 pg 23-40
+#define ETD_CC_NOERROR            0x0
+#define ETD_CC_CRCERR             0x1
+#define ETD_CC_BITSTUFFERR        0x2
+#define ETD_CC_DATATOGERR         0x3
+#define ETD_CC_STALL              0x4
+#define ETD_CC_DEVNOTRESPONDING   0x5
+#define ETD_CC_PIDFAILURE         0x6
+// Reserved                       0x7
+#define ETD_CC_DATAOVERRUN        0x8
+#define ETD_CC_DATAUNDERRUN       0x9
+#define ETD_CC_ACK                0xA
+#define ETD_CC_NAK                0xB
+#define ETD_CC_BUFFEROVERRUN      0xC
+#define ETD_CC_BUFFERUNDERRUN     0xD
+#define ETD_CC_SCHEDOVERRUN       0xE
+#define ETD_CC_NOTACCESSED        0xF
+
+// R1: sec 23.11.10.2,3 pg 23-44,47 (contd)
+#define ETD_GET_ERRORCNT(flags)   (((flags) >> 8) & 0xf)
+#define ETD_GET_DATATOGL(flags)   (((flags) >> 6) & 0x3)
+#define ETD_SET_DATATOGL(v)       (((v) & 0x3) << 6)
+#define ETD_GET_DELAYINT(flags)   (((flags) >> 3) & 0x7)
+#define ETD_SET_DELAYINT(v)       (((v) & 0x7) << 3)
+#define ETD_GET_BUFROUND(flags)   (((flags) >> 2) & 0x1)
+#define ETD_SET_BUFROUND(v)       (((v) & 0x1) << 2)
+#define ETD_GET_DIRPID(flags)     ((flags) & 0x3)
+#define ETD_SET_DIRPID(v)         ((v) & 0x3)
+#define ETD_FLIP_DIRPID(flags)    ((flags) ^ 0x3) /* xor with 0x3 flips 2<->1 (IN<->OUT) */
+#define ETD_DIRPID_SETUP          0x0  // OUT
+#define ETD_DIRPID_OUT            0x1
+#define ETD_DIRPID_IN             0x2
+#define ETD_DIRPID_RESERVED       0x3
+
+// For non-isoc td.w3.val -
+#define ETD_GET_BUFSIZE(w3)       (((w3) >> 21) & 0xfff)
+#define ETD_SET_BUFSIZE(v)        (((v) & 0xfff) << 21)
+#define ETD_GET_TOTBYECNT(w3)     ((w3) & 0xfffff)
+#define ETD_SET_TOTBYECNT(v)      ((v) & 0xfffff)
+
+/* isoc flags shares the COMPCODE and DELAYINT bitfields with the other TDs,
+   but the remaining bits are different. */
+#define ETD_GET_AUTOISO(flags)    (((flags) >> 11) & 0x1)
+#define ETD_SET_AUTOISO(v)        (((v) & 0x1) << 11)
+#define ETD_GET_FRAMECNT(flags)   (((flags) >> 8) & 0x1)
+#define ETD_SET_FRAMECNT(v)       (((v) & 0x1) << 8)
+// For isoc td.w3.val -
+/* pkt1 and pkt0 use the COMPCODE bitfield, and add a PKTLEN field. */
+#define ETD_GET_PKTLEN(pkt)       ((pkt) & 0x3ff)
+#define ETD_SET_PKTLEN(v)         ((v) & 0x3ff)
+
+
+// ETD endpoint descriptor (etd->epd) bitfield access
+// R1: sec 23.11.10.1 pg 23-41 (word0)
+#define ETD_GET_SNDNAK(epd)    (((epd) >> 30) & 0x1)
+#define ETD_SET_SNDNAK(v)      (((v) & 0x1) << 30)
+#define ETD_GET_TOGCRY(epd)    (((epd) >> 28) & 0x1)
+#define ETD_SET_TOGCRY(v)      (((v) & 0x1) << 28)
+#define ETD_GET_HALTED(epd)    (((epd) >> 27) & 0x1)
+#define ETD_SET_HALTED(v)      (((v) & 0x1) << 27)
+#define ETD_GET_MAXPKTSIZ(epd) (((epd) >> 16) & 0x3ff)
+#define ETD_SET_MAXPKTSIZ(v)   (((v) & 0x3ff) << 16)
+#define ETD_GET_FORMAT(epd)    (((epd) >> 14) & 0x3)
+#define ETD_SET_FORMAT(v)      (((v) & 0x3) << 14)
+#define ETD_FORMAT_CONTROL     0x0
+#define ETD_FORMAT_ISOC        0x1
+#define ETD_FORMAT_BULK        0x2
+#define ETD_FORMAT_INTERRUPT   0x3
+#define ETD_GET_SPEED(epd)     (((epd) >> 13) & 0x1)
+#define ETD_SET_SPEED(v)       (((v) & 0x1) << 13)
+#define ETD_SPEED_FULL         0x0
+#define ETD_SPEED_LOW          0x1
+#define ETD_GET_DIRECT(epd)    (((epd) >> 11) & 0x3)
+#define ETD_SET_DIRECT(v)      (((v) & 0x3) << 11)
+/* xor with 3 flips 2<->1 */
+#define ETD_FLIP_DIRECT(epd)   ((epd) ^ (0x3 << 11))
+#define ETD_DIRECT_TD00        0x0
+#define ETD_DIRECT_OUT         0x1
+#define ETD_DIRECT_IN          0x2
+#define ETD_DIRECT_TD11        0x3
+#define ETD_GET_ENDPNT(epd)    (((epd) >> 7) & 0xf)
+#define ETD_SET_ENDPNT(v)      (((v) & 0xf) << 7)
+#define ETD_GET_ADDRESS(epd)   ((epd) & 0x7f)
+#define ETD_SET_ADDRESS(v)     ((v) & 0x7f)
+
+// etd_urb_state[] values
+#define ETD_URB_COMPLETED       0
+#define ETD_URB_SETUP_STATUS    1
+#define ETD_URB_SETUP_DATA      2
+#define ETD_URB_SETUP_START     3
+#define ETD_URB_BULK_START      4
+#define ETD_URB_BULKWZLP        5
+#define ETD_URB_BULKWZLP_START  6
+#define ETD_URB_INTERRUPT_START 7
+#define ETD_URB_ISOC_START      8
+/*! @} */
+
+
+/*!
+ * @name C.f. 23.12.8 Function Registers
+ */
+/*! @{ */
+
+#define OTG_FUNC_CMD_STAT                       (OTG_FUNC_BASE+0x00)            //  32bit func command status reg
+
+#define COMMAND_SOFTRESET                       (1 << 7)
+#define COMMAND_BADISOAP                        (1 << 3)
+#define COMMAND_SUPDET                          (1 << 2)
+#define COMMAND_RSMINPROG                       (1 << 1)
+#define COMMAND_RESETDET                        (1)
+
+
+#define OTG_FUNC_DEV_ADDR                       (OTG_FUNC_BASE+0x04)            //  32bit func device address reg
+
+#define OTG_FUNC_SINT_STAT                      (OTG_FUNC_BASE+0x08)            //  32bit func system int status reg
+
+#define SYSTEM_DONEREGINTDS                     (1 << 5)
+#define SYSTEM_SOFDETINT                        (1 << 4)
+#define SYSTEM_DONEREGINT                       (1 << 3)
+#define SYSTEM_SUSPDETINT                       (1 << 2)
+#define SYSTEM_RSMFININT                        (1 << 1)
+#define SYSTEM_RESETINT                         (1)
+
+#define OTG_FUNC_SINT_STEN                      (OTG_FUNC_BASE+0x0C)            //  32bit func system int enable reg
+
+#define SYSTEM_DONEREGINTDS_EN                  (1 << 5)
+#define SYSTEM_SOFDETINT_EN                     (1 << 4)
+#define SYSTEM_DONEREGINT_EN                    (1 << 3)
+#define SYSTEM_SUSPDETINT_EN                    (1 << 2)
+#define SYSTEM_RSMFININT_EN                     (1 << 1)
+#define SYSTEM_RESETINT_EN                      (1)
+
+
+#define OTG_FUNC_XINT_STAT                      (OTG_FUNC_BASE+0x10)            //  32bit func X buf int status reg
+#define OTG_FUNC_YINT_STAT                      (OTG_FUNC_BASE+0x14)            //  32bit func Y buf int status reg
+#define OTG_FUNC_XYINT_STEN                     (OTG_FUNC_BASE+0x18)            //  32bit func XY buf int enable reg
+#define OTG_FUNC_XFILL_STAT                     (OTG_FUNC_BASE+0x1C)            //  32bit func X filled status reg
+
+#define OTG_FUNC_YFILL_STAT                     (OTG_FUNC_BASE+0x20)            //  32bit func Y filled status reg
+#define OTG_FUNC_EP_EN                          (OTG_FUNC_BASE+0x24)            //  32bit func endpoints enable reg
+#define OTG_FUNC_EP_RDY                         (OTG_FUNC_BASE+0x28)            //  32bit func endpoints ready reg
+#define OTG_FUNC_IINT                           (OTG_FUNC_BASE+0x2C)            //  32bit func immediate interrupt reg
+
+#define OTG_FUNC_EP_DSTAT                       (OTG_FUNC_BASE+0x30)            //  32bit func endpoints done status
+#define OTG_FUNC_EP_DEN                         (OTG_FUNC_BASE+0x34)            //  32bit func endpoints done enable
+#define OTG_FUNC_EP_TOGGLE                      (OTG_FUNC_BASE+0x38)            //  32bit func endpoints toggle bits
+#define OTG_FUNC_FRM_NUM                        (OTG_FUNC_BASE+0x3C)            //  32bit func frame number reg
+
+
+#define EP0_STALL                               (1 << 31)
+#define EP0_SETUP                               (1 << 30)
+#define EP0_OVERRUN                             (1 << 29)
+#define EP0_AUTOISO                             (1 << 27)
+
+
+/* generic endpoint register manipulations
+ */
+#define EP_OUT                                  0x1
+#define EP_IN                                   0x2
+#define EP_BOTH                                 0x3
+
+#define ETD_MASK(n)                             (1 << n)
+#define ep_num_both(n)                          (EP_BOTH << n)
+#define ep_num_dir(n, dir)                      ((dir ? EP_IN : EP_OUT) << (n*2))
+#define ep_num_out(n)                           ep_num_dir(n, USB_DIR_OUT)
+#define ep_num_in(n)                            ep_num_dir(n, USB_DIR_IN)
+
+
+/* ep descriptor access
+ */
+static __inline__ u32 etd_word(int n, int word)
+{
+        u32 offset = n * 16;
+        offset += word * 4;
+        return OTG_ETD_BASE + offset;
+}
+
+/* ep descriptor access
+ */
+static __inline__ u32 ep_word(int n, int dir, int word)
+{
+        u32 offset = n * 2;
+        offset += dir ? 1 : 0;
+        offset *= 16;
+        offset += word * 4;
+        return OTG_EP_BASE + offset;
+}
+
+/* endpoint data buffer access
+ * 
+ * This is a simplistic allocator, will do until we want to support ISO or host mode.
+ *
+ * This works because we are assuming a maximum of 16 allocate endpoints, and no
+ * overlapped endpoints (both in and out are allocated).
+ */
+
+static volatile __inline__ u16 data_x_buf(int n, int dir)
+{ 
+        return 0x40 * (n * 4 + 2 * (dir ? 1 : 0));
+}
+static volatile __inline__ u16 data_y_buf(int n, int dir)
+{ 
+        return 0x40 * (n * 4 + 2 * (dir ? 1 : 0) + 1);
+}
+
+static volatile __inline__ u8 * data_x_address(int n, int dir)
+{ 
+        return (volatile u8 *) IO_ADDRESS(OTG_DATA_BASE + data_x_buf(n, dir));
+}
+static volatile __inline__ u8 * data_y_address(int n, int dir)
+{ 
+        return (volatile u8 *) IO_ADDRESS(OTG_DATA_BASE + data_y_buf(n, dir));
+}
+/*! @} */
+
+/*!
+ * @name C.f. 23.13.3 DMA Registers
+ */
+/*! @{ */
+#define OTG_DMA_REV_NUM                         (OTG_DMA_BASE+0x000)     //  32bit dma revision number reg
+#define OTG_DMA_DINT_STAT                       (OTG_DMA_BASE+0x004)     //  32bit dma int status reg
+#define OTG_DMA_DINT_STEN                       (OTG_DMA_BASE+0x008)     //  32bit dma int enable reg
+#define OTG_DMA_ETD_ERR                         (OTG_DMA_BASE+0x00C)     //  32bit dma ETD error status reg
+#define OTG_DMA_EP_ERR                          (OTG_DMA_BASE+0x010)     //  32bit dma EP error status reg
+#define OTG_DMA_ETD_EN                          (OTG_DMA_BASE+0x020)     //  32bit dma ETD DMA enable reg
+#define OTG_DMA_EP_EN                           (OTG_DMA_BASE+0x024)     //  32bit dma EP DMA enable reg
+#define OTG_DMA_ETD_ENXREQ                      (OTG_DMA_BASE+0x028)     //  32bit dma ETD DMA enable Xtrig req
+#define OTG_DMA_EP_ENXREQ                       (OTG_DMA_BASE+0x02C)     //  32bit dma EP DMA enable Ytrig req
+#define OTG_DMA_ETD_ENXYREQ                     (OTG_DMA_BASE+0x030)     //  32bit dma ETD DMA enble XYtrig req
+#define OTG_DMA_EP_ENXYREQ                      (OTG_DMA_BASE+0x034)     //  32bit dma EP DMA enable XYtrig req
+#define OTG_DMA_ETD_BURST4                      (OTG_DMA_BASE+0x038)     //  32bit dma ETD DMA enble burst4 reg
+#define OTG_DMA_EP_BURST4                       (OTG_DMA_BASE+0x03C)     //  32bit dma EP DMA enable burst4 reg
+#define OTG_DMA_MISC_CTRL                       (OTG_DMA_BASE+0x040)     //  32bit dma EP misc control reg
+#define OTG_DMA_ETD_CH_CLR                      (OTG_DMA_BASE+0x044)     //  32bit dma ETD clear channel reg
+#define OTG_DMA_EP_CH_CLR                       (OTG_DMA_BASE+0x048)     //  32bit dma EP clear channel reg
+                        
+
+#define OTG_DMA_ETD_CH_CLR                      (OTG_DMA_BASE+0x044)     //  32bit dma ETD clear channel reg
+#define OTG_DMA_ETD_ERR                         (OTG_DMA_BASE+0x00C)     //  32bit dma ETD error status reg
+#define OTG_DMA_ETD_EN                          (OTG_DMA_BASE+0x020)     //  32bit dma ETD DMA enable reg
+#define OTG_DMA_ETD_ENXREQ                      (OTG_DMA_BASE+0x028)     //  32bit dma ETD DMA enable Xtrig req
+#define OTG_DMA_ETD_ENXYREQ                     (OTG_DMA_BASE+0x030)     //  32bit dma ETD DMA enble XYtrig req
+#define OTG_DMA_ETD_BURST4                      (OTG_DMA_BASE+0x038)     //  32bit dma ETD DMA enble burst4 reg
+
+
+
+#define OTG_DMA_EP_CH_CLR                       (OTG_DMA_BASE+0x048)     //  32bit dma EP clear channel reg
+#define OTG_DMA_EP_ERR                          (OTG_DMA_BASE+0x010)     //  32bit dma EP error status reg
+#define OTG_DMA_EP_EN                           (OTG_DMA_BASE+0x024)     //  32bit dma EP DMA enable reg
+#define OTG_DMA_EP_ENXREQ                       (OTG_DMA_BASE+0x02C)     //  32bit dma EP DMA enable Ytrig req
+#define OTG_DMA_EP_ENXYREQ                      (OTG_DMA_BASE+0x034)     //  32bit dma EP DMA enable XYtrig req
+#define OTG_DMA_EP_BURST4                       (OTG_DMA_BASE+0x03C)     //  32bit dma EP DMA enable burst4 reg
+
+
+#define dma_num_dir(n, dir) (n * 2 + (dir ? 1 : 0))
+#define dma_num_out(n) dma_num_dir(n, USB_DIR_OUT)
+#define dma_num_in(n) dma_num_dir(n, USB_DIR_IN)
+
+#define OTG_DMA_ETD_MSA(x)                      (OTG_DMA_BASE+0x100+x*4)
+#define OTG_DMA_EPN_MSA(x)                      (OTG_DMA_BASE+0x180+x*4)
+#define OTG_DMA_ETDN_BPTR(x)                    (OTG_DMA_BASE+0x280+x*4)
+#define OTG_DMA_EPN_BPTR(x)                     (OTG_DMA_BASE+0x284+x*4)
+
+/*! @} */
+
+/* ********************************************************************************************** */
+/*! 
+ * Warning: the MX21 memory mapped region appears to require 32-bit access only.
+ * As of this writing, only the ETD region has been tested, but it does show the
+ * following behavior:
+ *
+ * Step 1:   *(volatile u32 *)(void*)0xe40243f8  == 00000000
+ * Step 2:   *(volatile u16 *)(void*)0xe40243f8 = 0x0084;
+ * Step 3:   *(volatile u32 *)(void*)0xe40243f8  == 00840084
+ * Step 4:   *(volatile u8 *)(void*)(0xe40243f8+3) = 0x01;
+ * Step 5:   *(volatile u32 *)(void*)0xe40243f8  == 01010101
+ *
+ * Any access to less than 32 bits is replicated as many times as required
+ * to make 32 bits, and the surrounding 32-bit region is changed.
+ *
+ * Just to add insult to injury, gcc 3.2.3 wants to store constants
+ * that are small enough using byte instructions.  E.g.
+ *
+ *      mm->host.System_Interrupt_Enables = (SIEN_PSCIEN | SIEN_FMOFIEN | SIEN_HERRIEN | SIEN_RESDETIEN | 
+ *                                         SIEN_DONEIEN | SIEN_SORIEN);
+ *
+ * becomes:
+ *
+ *      ldrb    r2, [r3, #140]
+ *      mov     r2, #123
+ *      strb    r2, [r3, #140]
+ *      ldrb    r2, [r3, #141]
+ *      strb    r1, [r3, #141]
+ *      ldrb    r2, [r3, #142]
+ *      strb    r1, [r3, #142]
+ *      ldrb    r2, [r3, #143]
+ *      strb    r1, [r3, #143]
+ *
+ * which, given the 32-bit access restrictions above,
+ * is not going to work very well.  Changing the original assignment to:
+ *
+ *      *&(mm->host.System_Interrupt_Enables) = (SIEN_PSCIEN | SIEN_FMOFIEN | SIEN_HERRIEN | SIEN_RESDETIEN | 
+ *                                           SIEN_DONEIEN | SIEN_SORIEN);
+ *
+ * which should be identical, from a language definition point of view,
+ * produces:
+ *
+ *      mov     r2, #123
+ *      str     r2, [r3, #140]
+ *
+ */
+
+
+/*!
+ * @name TransferDescriptors
+ *
+ * Note that the MX21 needs to run in little-endian mode for OTG, but
+ * since the memory can only be accessed in 32-bit quantities, anything
+ * smaller will be built in regular memory, then transfered one word at
+ * a time to the memory-mapped registers, and that word access will flip
+ * the order of bytes.  u16 quantities survive this flipping because they
+ * get "pre-flipped" in regular memory.
+ * 
+ *
+ * An Endpoint Transfer Descriptor (ETD) consists of 4x32bit words.
+ * The first word is the Endpoint Descriptor, the last three are
+ * the transfer descriptor.  Transfer descriptors come in 3 formats,
+ * CONTROL/BULK, INTERRUPT, and ISOCRONOUS.  Becasue of the memory
+ * access restrictions to less than 32 bits described above, only
+ * the words are mapped directly,  The smaller fields are assembled
+ * into 32-bit words before being placed into the live ETD. 
+ *
+ */
+ /*! @{ */
+
+/*!
+ * @struct transfer_descriptor_w1 
+ * All three types of TD have the same format for w1.
+ */
+typedef struct transfer_descriptor_w1 {
+#if defined(LITTLE_ENDIAN)
+        u16 x;
+        u16 y;
+#else
+        u16 y;
+        u16 x;
+#endif
+} __attribute__ ((packed)) volatile transfer_descriptor_w1;
+
+/*!
+ * @struct control_bulk_transfer_descriptor_w2 
+ * There are 3 different formats for w2.
+ * C.f. R1: sec 23.11.10.2 pg 23-43
+ */
+typedef struct control_bulk_transfer_descriptor_w2 {
+#if defined(LITTLE_ENDIAN)
+        u8 rtrydelay;
+        u8 reserved;
+        u16 flags;
+#else
+        u16 flags;
+        u8 reserved;
+        u8 rtrydelay;
+#endif
+} __attribute__ ((packed)) volatile control_bulk_transfer_descriptor_w2;
+
+/*!
+ * @struct interrupt_transfer_descriptor_w2 
+ * C.f. R1: sec 23.11.10.3 pg 23-46
+ */
+typedef struct interrupt_transfer_descriptor_w2 {
+#if defined(LITTLE_ENDIAN)
+        u8 polinterv;
+        u8 relpolpos;
+        u16 flags;
+#else
+        u16 flags;
+        u8 relpolpos;
+        u8 polinterv;
+#endif
+} __attribute__ ((packed)) volatile interrupt_transfer_descriptor_w2;
+
+/*!
+ * @struct isoc_transfer_descriptor_w2 
+ * C.f. R1: sec 23.11.10.4 pg 23-48
+ */
+typedef struct isoc_transfer_descriptor_w2 {
+#if defined(LITTLE_ENDIAN)
+        u16 startfrm;
+        u16 flags;
+#else
+        u16 flags;
+        u16 startfrm;
+#endif
+} __attribute__ ((packed)) volatile isoc_transfer_descriptor_w2;
+
+
+
+/*!
+ * @struct isoc_transfer_descriptor_w3 
+ * There are 2 different formats for w3.
+ * All but isoc use a packet size and 20-bit bytecount, accessed through w3.val.
+ */
+typedef struct isoc_transfer_descriptor_w3 {
+#if defined(LITTLE_ENDIAN)
+        u16 pkt0;
+        u16 pkt1;
+#else
+        u16 pkt1;
+        u16 pkt0;
+#endif
+} __attribute__ ((packed)) volatile isoc_transfer_descriptor_w3;
+
+/*!
+ * @name transfer_descriptor
+ */
+/*! @{ */ 
+typedef struct transfer_descriptor {
+        union {
+                u32 val;
+                transfer_descriptor_w1 bufsrtad;
+        } volatile w1;
+        union {
+                u32 val;
+                control_bulk_transfer_descriptor_w2 cb;
+                interrupt_transfer_descriptor_w2 intr;
+                isoc_transfer_descriptor_w2 isoc;
+        } volatile w2;
+        union {
+                u32 val;
+                isoc_transfer_descriptor_w3 isoc;
+        } volatile w3;
+} __attribute__ ((packed)) volatile transfer_descriptor;
+
+/*! @} */
+
+/*!
+ * @name endpoint_transfer_descriptor 
+ * C.f. R1: sec 23.11.10 pg 23-41
+ */
+ /*! @{ */
+typedef struct endpoint_transfer_descriptor {
+        u32 epd;
+        transfer_descriptor td;
+} __attribute__ ((packed)) volatile endpoint_transfer_descriptor;  // ETD
+
+/*! @} */
+
+
+/*!
+ * @name DataBuffs
+ *
+ * There is no predetermined size for data buffers, so
+ * this structure was chosen as an arbitrary, but generally
+ * adequate size. 
+ */
+/*! @{ */
+
+/*!
+ * @struct fs_data_buff
+ */
+typedef struct fs_data_buff {
+        u32 data[DATA_BUFF_SIZE/sizeof(u32)]; // Cannot safely write less than 32-bit quantities
+} volatile fs_data_buff;
+
+
+/*! 
+ * @struct fs_hcpriv
+ */
+typedef struct fs_hcpriv {
+        struct bus_hcpriv *bus_hcpriv;
+        u32 sof_count;
+        u32 free_etds;
+        endpoint_transfer_descriptor sdp_etd[NUM_ETDS]; // Setup data phase save area
+        void *sdp_data[NUM_ETDS];
+        u8 etd_urb_state[NUM_ETDS];
+        u16 free_buffs;
+        u16 buff_list[NUM_DATA_BUFFS]; 
+} fs_hcpriv;
+
+
+/*!
+ * get_data_buff() - get data buff
+ */
+static __inline__ fs_data_buff *get_data_buff(fs_hcpriv *fs_hcpriv)
+{
+        // Get the next available free data_buff, return NULL if none available.
+        unsigned long flags;
+        fs_data_buff *db;
+        u16 ndx;
+        local_irq_save(flags);
+        if (0xffff != (ndx = fs_hcpriv->free_buffs)) {
+                fs_hcpriv->free_buffs = fs_hcpriv->buff_list[ndx];
+                db = ndx + (fs_data_buff *)OTG_DATA_BASE;
+        }
+        else 
+                db = NULL;
+        local_irq_restore(flags);
+        return(db);
+}
+
+/*!
+ * rel_data_buff() - release data buff
+ */
+static __inline__ fs_data_buff *rel_data_buff(fs_hcpriv *fs_hcpriv, fs_data_buff *db)
+{
+        // Release db to the pool of available data_buffs.
+        unsigned long flags;
+        u16 ndx;
+        if (NULL != db) {
+                local_irq_save(flags);
+                ndx = db - (fs_data_buff *)OTG_DATA_BASE;
+                fs_hcpriv->buff_list[ndx] = fs_hcpriv->free_buffs;
+                fs_hcpriv->free_buffs = ndx;
+#if 0
+                db->next = fs_hcpriv->free_buffs;
+                fs_hcpriv->free_buffs = db;
+#endif
+                local_irq_restore(flags);
+        }
+        return(NULL);
+}
+
+/*!
+ * data_buff_boff() - get data buffer offset given address
+ */
+static __inline__ u16 data_buff_boff(fs_data_buff *db)
+{
+        return((u16)(((void *) db) - ((void *) OTG_DATA_BASE)));
+}
+
+/*!
+ * data_buff_addr() - get data buffer address given offset
+ */
+static __inline__ fs_data_buff *data_buff_addr(u16 boff)
+{
+        // Return the address of the fs_data_buffer that is boff bytes from the start of data buffer memory.
+        return(boff + ((void *) OTG_DATA_BASE));
+}
+/*! @} */
+
+/* ********************************************************************************************** */
+
+/*!
+ * @name FSUSBOTGIO
+ * @brief Freescale USBOTG I/O support.
+ */
+ /*! @{ */
+
+/*!
+ * fs_rb() - read a byte
+ * @param port
+ * @return byte read
+ */ 
+static u8 __inline__ fs_rb(u32 port)
+{
+        return *(volatile u8 *) (IO_ADDRESS(port));
+}
+
+/*! 
+ * fs_rl() - read a long
+ * @param port
+ * @return word read
+ */
+static u32  __inline__ fs_rl(u32 port)
+{       
+        return *(volatile u32 *) (IO_ADDRESS(port));
+}       
+        
+/*! 
+ * fs_wb() - write a byte
+ * @param port
+ * @param val
+ */
+static void __inline__ fs_wb(u32 port, u8 val)
+{               
+        *(volatile u8 *)(IO_ADDRESS(port)) = val;
+}       
+
+/*!
+ * fs_orb() - or a byte
+ * @param port
+ * @param val
+ */     
+static void __inline__ fs_orb(u32 port, u8 val)
+{       
+        u8 set =  fs_rb(port) | val;                                   
+        *(volatile u8 *)(IO_ADDRESS(port)) = set;                   
+}       
+
+/*!
+ * fs_andb() - and a byte
+ * @param port
+ * @param val
+ */     
+static void __inline__ fs_andb(u32 port, u8 val)
+{       
+        u8 set =  fs_rb(port) & val;                                   
+        *(volatile u8 *)(IO_ADDRESS(port)) = set;                   
+}       
+
+/*!
+ * fs_wl() - write a long
+ * @param port
+ * @param val
+ */
+static void __inline__ fs_wl(u32 port, u32 val)
+{
+        u32 set;
+        *(volatile u32 *)(IO_ADDRESS(port)) = val;
+        set = fs_rl(port);
+}       
+
+/*!
+ * fs_orl() - or a long
+ * @param port
+ * @param val
+ */
+static void __inline__ fs_orl(u32 port, u32 val)
+{
+        u32 set = fs_rl(port);
+        *(volatile u32 *)(IO_ADDRESS(port)) = (set | val);
+}
+
+/*! 
+ * fs_andl() - and a long
+ * @param port
+ * @param val
+ */
+static void __inline__ fs_andl(u32 port, u32 val)
+{
+        u32 set = fs_rl(port);
+        *(volatile u32 *)(IO_ADDRESS(port)) = (set & val);
+}
+
+/*!
+ * fs_host_port_stat() - get host start port address for ports 1-3
+ * @param n
+ * @returns port address
+ */
+static u32 inline fs_host_port_stat(int n)
+{
+        switch (n) {
+        default:
+        case 1:
+                return OTG_HOST_PORT_STATUS_1;
+        case 2:
+                return OTG_HOST_PORT_STATUS_2;
+        case 3:
+                return OTG_HOST_PORT_STATUS_3;
+        }
+}
+
+
+/*!
+ * fs_wl_set() - set a word and verify
+ * @param tag
+ * @param port
+ * @param val
+ */
+static void inline fs_wl_set(otg_tag_t tag, u32 port, u32 val)
+{
+        u32 set;
+        *(volatile u32 *)(IO_ADDRESS(port)) = val;
+        set = fs_rl(port);
+        if ((set & val) != val) {
+                TRACE_MSG1(tag, "SET FAILED: %08x", set);
+        }
+}
+
+/*!
+ * fs_wl_clr() - clr a word and verify
+ * @param tag
+ * @param port
+ * @param clr
+ */
+static void inline fs_wl_clr(otg_tag_t tag, u32 port, u32 clr)
+{
+        u32 set;
+        *(volatile u32 *)(IO_ADDRESS(port)) = clr;
+        set = fs_rl(port);
+        if (set & clr) {
+                TRACE_MSG1(tag, "CLEAR FAILED 1: %08x", set);
+                *(volatile u32 *)(IO_ADDRESS(port)) = clr;
+                set = fs_rl(port);
+                if (set & clr)
+                        TRACE_MSG1(tag, "CLEAR FAILED 2: %08x", set);
+        }
+}
+
+
+/*!
+ * fs_memcpy32() - emulage memcpy using long copy
+ * @param dp destination pointer
+ * @param sp source pointer
+ * @param words number of 32bit words to copy
+ *
+ */
+static void inline fs_memcpy32(u32 *dp, u32 *sp, volatile int words)
+{
+        while (words--) *dp++ = *sp++;
+}
+/*!
+ * fs_memcpy() - emulage memcpy using byte copy
+ * @param dp destination pointer
+ * @param sp source pointer
+ * @param bytes number of 8bit bytes to copy
+ */
+static void inline fs_memcpy(u8 *dp, u8 *sp, volatile int bytes)
+{
+        while (bytes--) *dp++ = *sp++;
+}
+/*!
+ * fs_clear_words() - clear memory
+ * @param addr address to clear from
+ * @param words number of 32bit words to clear.
+ */
+static void inline fs_clear_words(volatile u32 *addr, int words)
+{
+        while (words--) *addr++ = 0;
+}
+
+/*! @} */
+
diff -uNr linux/drivers/no-otg/otghw/isp1301-hardware.h linux/drivers/otg/otghw/isp1301-hardware.h
--- linux/drivers/no-otg/otghw/isp1301-hardware.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otghw/isp1301-hardware.h	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,218 @@
+/*
+ * otg/otghw/isp1301-hardware.h -- ISP1301 hardware specific defines
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/otghw/isp1301-hardware.h
+ * @brief Public Structures And Defines For ISP1301 Hardware.
+ *
+ * The Phillips ISP1301 is an OTG Transceiver. There a additional
+ * compatible parts such as the Maxim MAX3301E
+ *
+ * @ingroup ISP1301TCD
+ */
+
+
+/*!
+ * @name ADR/PSW - C.f. 8.9.1
+ *
+ * The i2c address is either 0x2c or 0x2d depending on the level of the
+ * ADR/PSW pin after device reset. Note that this pin can be programmed as
+ * an output via the Mode Control 2 register, bit PSW_OE to enable an
+ * @{
+ */
+
+#define ISP1301_I2C_ADDR_LOW                    0x2c
+#define ISP1301_I2C_ADDR_HIGH                   0x2d
+/*! @} */
+
+/*!
+ * @name ISP1301 Registers C.f. 11.1
+ * @{
+ */
+
+#define ISP1301_VENDOR_ID                       0x00
+#define ISP1301_PRODUCT_ID                      0x02
+#define ISP1301_VERSION_ID                      0x14
+
+#define ISP1301_VENDOR_ID_LOW                   0x00
+#define ISP1301_PRODUCT_ID_LOW                  0x02
+#define ISP1301_VERSION_ID_LOW                  0x14
+#define ISP1301_VENDOR_ID_HIGH                  0x01
+#define ISP1301_PRODUCT_ID_HIGH                 0x03
+#define ISP1301_VERSION_ID_HIGH                 0x15
+
+/* these are all single byte registers
+ */
+#define ISP1301_MODE_CONTROL_1                  0x04
+#define ISP1301_MODE_CONTROL_1_SET              0x04
+#define ISP1301_MODE_CONTROL_1_CLR              0x05
+
+#define ISP1301_MODE_CONTROL_2                  0x12
+#define ISP1301_MODE_CONTROL_2_SET              0x12
+#define ISP1301_MODE_CONTROL_2_CLR              0x13
+
+#define ISP1301_OTG_CONTROL                     0x06
+#define ISP1301_OTG_CONTROL_SET                 0x06
+#define ISP1301_OTG_CONTROL_CLR                 0x07
+
+#define ISP1301_OTG_STATUS                      0x10
+
+#define ISP1301_INTERRUPT_SOURCE                0x08
+
+#define ISP1301_INTERRUPT_LATCH                 0x0a
+#define ISP1301_INTERRUPT_LATCH_SET             0x0a
+#define ISP1301_INTERRUPT_LATCH_CLR             0x0b
+
+#define ISP1301_INTERRUPT_ENABLE_LOW            0x0c
+#define ISP1301_INTERRUPT_ENABLE_LOW_SET        0x0c
+#define ISP1301_INTERRUPT_ENABLE_LOW_CLR        0x0d
+
+#define ISP1301_INTERRUPT_ENABLE_HIGH           0x0e
+#define ISP1301_INTERRUPT_ENABLE_HIGH_SET       0x0e
+#define ISP1301_INTERRUPT_ENABLE_HIGH_CLR       0x0f
+/*! @} */
+
+
+/*!
+ * @name Mode Control 1 register - C.f. Table 17 and Table 18
+ * @{
+ */
+#define ISP1301_UART_EN                         (1 << 6)
+#define ISP1301_OE_INT_EN                       (1 << 5)
+#define ISP1301_BDIS_ACON_EN                    (1 << 4)
+#define ISP1301_TRANSP_EN                       (1 << 3)
+#define ISP1301_DAT_SE0                         (1 << 2)
+#define ISP1301_SUSPEND_REG                     (1 << 1)
+#define ISP1301_SPEED_REG                       (1 << 0)
+/*! @} */
+
+
+/*!
+ * @name Mode Control 2 register - C.f. Table 19 and Table 20
+ * @{
+ */
+#define ISP1301_EN2V7                           (1 << 7)
+#define ISP1301_PSW_OE                          (1 << 6)
+#define ISP1301_AUDIO_EN                        (1 << 5)
+#define ISP1301_TRANSP_BDIR                     (3 << 3)
+#define ISP1301_BI_DI                           (1 << 2)
+#define ISP1301_SPD_SUSP_CTRL                   (1 << 1)
+#define ISP1301_GLOBAL_PWR_ON                   (1 << 0)
+/*! @} */
+
+
+/*!
+ * @name OTG Control register - C.f. Table 21 and Table 22
+ * @{
+ */
+#define ISP1301_VBUS_CHRG                       (1 << 7)
+#define ISP1301_VBUS_DISCHRG                    (1 << 6)
+#define ISP1301_VBUS_DRV                        (1 << 5)
+#define ISP1301_ID_PULLDOWN                     (1 << 4)
+#define ISP1301_DM_PULLDOWN                     (1 << 3)
+#define ISP1301_DP_PULLDOWN                     (1 << 2)
+#define ISP1301_DM_PULLUP                       (1 << 1)
+#define ISP1301_DP_PULLUP                       (1 << 0)
+
+#define ISP1301_VBUS_RESET (ISP1301_VBUS_CHRG | ISP1301_VBUS_DISCHRG | ISP1301_VBUS_DRV)
+
+/*! @} */
+
+
+/*!
+ * @name OTG Status register - C.f. Table 23 and Table 24
+ * @{
+ */
+#define ISP1301_B_SESS_VLD                      (1 << 7)
+#define ISP1301_B_SESS_END                      (1 << 6)
+/*! @} */
+
+
+/*!
+ * @name Interrupt Source Register
+ * Interrupt Source register - C.f. Table 25 and Table 26
+ * Interrupt Latch register - C.f. Table 27 and Table 28
+ * Interrupt Enable Low register - C.f. Table 29 and Table 30
+ * Interrupt Enable High register - C.f. Table 31 and Table 32
+ * @{
+ */
+#define ISP1301_CR_INT                          (1 << 7)
+#define ISP1301_BDIS_ACON                       (1 << 6)
+#define ISP1301_ID_FLOAT                        (1 << 5)
+#define ISP1301_DM_HI                           (1 << 4)
+#define ISP1301_ID_GND                          (1 << 3)
+#define ISP1301_DP_HI                           (1 << 2)
+#define ISP1301_SESS_VLD                        (1 << 1)
+#define ISP1301_VBUS_VLD                        (1 << 0)
+
+//#define ISP1301_SE1                             (ISP1301_DM_HI | ISP1301_DP_HI)
+
+/*! @} */
+
+/*!
+ * @name Maxim MAX3301E
+ *
+ * This part is compatible with the ISP1301 with minor differences:
+ *
+ * Mode Control 1 register is called Control Register 1. It is almost
+ * identical except for:
+ *
+ *      bit     isp1301         max3301e
+ *      3       transp_en       not used
+ * @{
+ */
+#define MAX3301E_CONTROL_REGISTER_1             0x04
+#define MAX3301E_CONTROL_REGISTER_1_SET         0x04
+#define MAX3301E_CONTROL_REGISTER_1_CLR         0x05
+/*! @} */
+
+/*!
+ * @name Mode Control 2
+ * Mode Control 2 is called Special Function Register 1. Mostly the same
+ * except for:
+ *
+ *      bit     isp1301         max3301e
+ *      7       en2v7           gp_en
+ *      6       psw_oe          sess_end
+ *      5       audio_en        int_source
+ * @{
+ */
+#define MAX3301E_SPECIAL_FUNCTION_1             0x12
+#define MAX3301E_SPECIAL_FUNCTION_1_SET         0x12
+#define MAX3301E_SPECIAL_FUNCTION_1_CLR         0x13
+#define MAX3301E_GP_EN                          (1 << 7)
+#define MAX3301E_SESS_END                       (1 << 6)
+#define MAX3301E_INT_SOURCE                     (1 << 5)
+/*! @} */
+
+/*!
+ * @name OTG Status
+ * The OTG Status is not present, but B_SESS_END seems to be available
+ * in the Mode Control 2 register bit 6.
+ *
+ * An additional register is available for MAX3301E specific features.
+ *
+ * Special Function Register 2 
+ * @{
+ */
+
+#define MAX3301E_SPECIAL_FUNCTION_2             0x16
+#define MAX3301E_SPECIAL_FUNCTION_2_SET         0x16
+#define MAX3301E_SPECIAL_FUNCTION_2_CLR         0x17
+#define MAX3301E_SDWN                           (1 << 0)
+#define MAX3301E_IRQ_MODE                       (1 << 1)
+#define MAX3301E_XCVR_INPUT_DISC                (1 << 2)
+#define MAX3301E_REQ_SET                        (1 << 3)
+/*! @} */
+
+
+
+
diff -uNr linux/drivers/no-otg/otghw/isp1301.h linux/drivers/otg/otghw/isp1301.h
--- linux/drivers/no-otg/otghw/isp1301.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otghw/isp1301.h	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,158 @@
+/*
+ * otg/otghw/isp1301/isp1301.h -- USB Transceiver Controller driver 
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @defgroup ISP1301TCD Phillips ISP1301 
+ * @ingroup tcdgroup
+ */
+/*!
+ * @file otg/otghw/isp1301.h
+ * @brief Private structures and defines for ISP1301 Transciever Controller Driver.
+ *
+ * This file contains the private defines and structures for the ISP1301 Transceiver 
+ * Driver. 
+ *
+ * @ingroup ISP1301TCD
+ */
+
+/*!
+ * @name ISP1301 ISP1301 configuration
+ * @{
+ */
+
+#ifdef CONFIG_OMAP_H2
+#define ISP1301_GPIO    	(2)
+#define	TCD_ISP1301_I2C_ADDR 	ISP1301_I2C_ADDR_HIGH;
+#endif
+
+#define ISP1301_NAME    "isp1301"
+
+#define ISP1301_LOC_CONN 0x01
+
+#define ISP1301_INT_SRC         0xeb
+
+/*!
+ * @enum otg_transceiver 
+ * Define ISP1301 compatible transceivers
+ */
+typedef enum otg_transceiver {
+        unknown_transceiver,    /*!< unknown */
+        isp1301,                /*!< Phillips ISP1301 */
+        max3301e                /*!< Maxim MAX3301e */
+} otg_transceiver_t;
+
+/*!
+ * @struct otg_transceiver_map 
+ * How to determine transceiver model and manufacturer
+ */
+struct otg_transceiver_map {
+        otg_transceiver_t transceiver_type;     /*!< transceiver type */
+        u16 vendor;                             /*!< vendor number */
+        u16 product;                            /*!< product number */
+        u16 revision;                           /*!< revision number */
+        char *name;                             /*!< name */
+};
+
+/*! 
+ * @struct isp1301_private
+ * Information required for operation
+ */
+struct isp1301_private {
+        WORK_STRUCT bh;                         /*!< work structure for bottom half handler */
+        u16 vendor;                             /*!< vendor number found */
+        u16 product;                            /*!< product number found */
+        u16 revision;                           /*!< revision number found */
+        u32 flags;                              /*!< flags */
+        u8  int_src;                            /*!< current interrupt source */
+        struct otg_transceiver_map *transceiver_map; /*! pointer to transceiver map for this transceiver */
+};
+
+/*! 
+ * @enum tx_mode
+ * This defines the various ways that the ISP1301 can be
+ * wired into the host USB. 
+ */
+typedef enum tx_mode {
+        dat_se0_bidirectional,          /*!< 3-Wire */
+        vp_vm_bidirectional,            /*!< 4-Wire */
+        dat_se0_unidirectional          /*!< 6-Wire */
+} tx_mode_t;
+
+/*! 
+ * @enum spd_ctrl
+ * This defines how the speed and suspend pins are controlled
+ * for this host.
+ */
+typedef enum spd_ctrl {
+        spd_susp_pins,                  /*!< controlled by SPEED and SUSPEND pins */
+        spd_susp_reg,                   /*!< controled by SPEED_REG and SUSPEND_REG in Mode Control 1 register */
+} spd_ctrl_t;
+
+
+extern struct tcd_ops tcd_ops;
+extern struct isp1301_private isp1301_private;
+extern struct tcd_instance *tcd_instance;
+
+/* isp1301.c */
+extern int isp1301_mod_init(WORK_PROC );
+extern int isp1301_mod_init__(void );
+extern void isp1301_mod_exit(void);
+extern void isp1301_tcd_en(struct otg_instance *, u8 );
+extern void isp1301_chrg_vbus(struct otg_instance *, u8 );
+extern void isp1301_drv_vbus(struct otg_instance *, u8 );
+extern void isp1301_dischrg_vbus(struct otg_instance *, u8 );
+extern void isp1301_dp_pullup_func(struct otg_instance *, u8 );
+extern void isp1301_dm_pullup_func(struct otg_instance *, u8 );
+extern void isp1301_dp_pulldown_func(struct otg_instance *, u8 );
+extern void isp1301_dm_pulldown_func(struct otg_instance *, u8 );
+extern void isp1301_peripheral_host_func(struct otg_instance *, u8 );
+extern void isp1301_dm_det_func(struct otg_instance *, u8 );
+extern void isp1301_dp_det_func(struct otg_instance *, u8 );
+extern void isp1301_cr_det_func(struct otg_instance *, u8 );
+extern void isp1301_bdis_acon_func(struct otg_instance *, u8 );
+extern void isp1301_mx21_vbus_drain_func(struct otg_instance *, u8 );
+extern void isp1301_id_pulldown_func(struct otg_instance *, u8 );
+extern void isp1301_audio_func(struct otg_instance *, u8 );
+extern void isp1301_uart_func(struct otg_instance *, u8 );
+extern void isp1301_mono_func(struct otg_instance *, u8 );
+
+extern void isp1301_otg_timer(struct otg_instance *, u8 );
+extern void isp1301_bh(void *);
+extern int isp1301_id (struct otg_instance *);
+extern int isp1301_vbus (struct otg_instance *);
+extern void  isp1301_configure(tx_mode_t, spd_ctrl_t );
+
+extern void isp1301_bh_wakeup(int);
+
+/* thread */
+extern int isp1301_thread_init (void (bh_proc)(void *));
+extern void isp1301_thread_exit (wait_queue_head_t *);
+extern void isp1301_thread_wakeup(int enabled, int first);
+
+
+
+/* i2c-xxx.c */
+int  i2c_configure(char *name, int addr);
+extern void  i2c_close(void);
+extern u8 i2c_readb(u8 );
+extern u16 i2c_readw(u8 );
+extern u32 i2c_readl(u8 );
+extern void i2c_writeb(u8 , u8 );
+
+
+/* ********************************************************************************************* */
+#define TRACE_I2CB(t,r) TRACE_MSG3(t, "%-40s[%02x] %02x", #r, r, i2c_readb(r))
+#define TRACE_I2CW(t,r) TRACE_MSG3(t, "%-40s[%02x] %04x", #r, r, i2c_readw(r))
+#define TRACE_GPIO(t,b,r) TRACE_MSG2(t, "%-40s %04x", #r, readw(b + r))
+#define TRACE_REGL(t,r) TRACE_MSG2(t, "%-40s %08x", #r, readl(r))
+
+/* @} */
+
diff -uNr linux/drivers/no-otg/otghw/max3353e-hardware.h linux/drivers/otg/otghw/max3353e-hardware.h
--- linux/drivers/no-otg/otghw/max3353e-hardware.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otghw/max3353e-hardware.h	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,141 @@
+/*
+ * otg/otg/max3353e-hardware.h -- MAX3353E hardware specific defines
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@lbelcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @file otg/otg/max3353e-hardware.h
+ * @brief Public structures and defines for MAX3353E Hardware.
+ *
+ * The Maxim MAX3353E is an OTG Charge Pump with controllable
+ * pullup resistors.
+ *
+ * @ingroup MAX3353ETCD
+ */
+
+
+/*!
+ * @name ADR/PSW - C.f. Slave Address
+ *
+ * The high/low address is selected with the ADD pin.
+ *
+ * @{
+ */
+
+#define MAX3353E_I2C_ADDR_LOW                    0x16
+#define MAX3353E_I2C_ADDR_HIGH                   0x2C
+
+/*! @} */
+
+
+
+/*!
+ * @name MAX3353E Registers C.f. Table 2 - Register Address Map
+ * @{
+ */
+
+#define MAX3353E_MANUFACTURER_REGISTER_0        0x00
+#define MAX3353E_MANUFACTURER_REGISTER_1        0x01
+#define MAX3353E_MANUFACTURER_REGISTER_2        0x02
+#define MAX3353E_MANUFACTURER_REGISTER_3        0x03
+
+#define MAX3353E_PRODUCT_ID_REGISTER_0          0x04
+#define MAX3353E_PRODUCT_ID_REGISTER_1          0x05
+#define MAX3353E_PRODUCT_ID_REGISTER_2          0x06
+#define MAX3353E_PRODUCT_ID_REGISTER_3          0x07
+
+#define MAX3353E_CONTROL_REGISTER_1             0x10
+#define MAX3353E_CONTROL_REGISTER_2             0x11
+
+#define MAX3353E_STATUS_REGISTER                0x13
+
+#define MAX3353E_INTERRUPT_MASK                 0x14
+#define MAX3353E_INTERRUPT_EDGE                 0x15
+#define MAX3353E_INTERRUPT_LATCH                0x16
+
+/*! @} */
+
+
+/*!
+ * @name Control Register 1
+ * @{
+ */
+#define MAX3353E_DM_PULLDOWN                    (1 << 7)
+#define MAX3353E_DP_PULLDOWN                    (1 << 6)
+#define MAX3353E_DM_PULLUP                      (1 << 5)
+#define MAX3353E_DP_PULLUP                      (1 << 4)
+
+#define MAX3353E_BDISC_ACONN                    (1 << 2)
+#define MAX3353E_IRQ_MODE                       (1 << 1)
+
+/*! @} */
+
+/*!
+ * @name Control Register 2
+ * @{
+ */
+#define MAX3353E_VBUS_DISCHG                    (1 << 4)
+#define MAX3353E_VBUS_DRV                       (1 << 3)
+#define MAX3353E_VBUS_CHG2                      (1 << 2)
+#define MAX3353E_VBUS_CHG1                      (1 << 1)
+#define MAX3353E_DSWIN                          (1 << 0)
+
+/*! @} */
+
+/*!
+ * @name Status Register
+ * @{
+ */
+#define MAX3353E_B_HNP                          (1 << 6)
+#define MAX3353E_A_HNP                          (1 << 5)
+#define MAX3353E_ID_FLOAT                       (1 << 4)
+#define MAX3353E_ID_GND                         (1 << 3)
+#define MAX3353E_SESSION_END                    (1 << 2)
+#define MAX3353E_SESSION_VALID_EN               (1 << 1)
+#define MAX3353E_VBUS_VALID                     (1 << 0)
+
+/*! @} */
+
+/*!
+ * @name Interrupt Mask
+ * @{
+ */
+#define MAX3353E_A_HNP_EN                       (1 << 5)
+#define MAX3353E_ID_FLOAT_EN                    (1 << 4)
+#define MAX3353E_ID_GND_EN                      (1 << 3)
+#define MAX3353E_SESSION_END_EN                 (1 << 2)
+#define MAX3353E_SESSION_VALID_EN               (1 << 1)
+#define MAX3353E_VBUS_VALID_EN                  (1 << 0)
+
+/*! @} */
+
+/*!
+ * @name Interrupt Edge
+ * @{
+ */
+#define MAX3353E_SESSION_VALID_ED               (1 << 1)
+#define MAX3353E_VBUS_VALID_ED                  (1 << 0)
+
+/*! @} */
+
+/*!
+ * @name Interrupt Latch
+ * @{
+ */
+#define MAX3353E_A_HNP_RQ                       (1 << 7)
+#define MAX3353E_ID_FLOAT_RQ                    (1 << 6)
+#define MAX3353E_ID_GND_RQ                      (1 << 5)
+#define MAX3353E_SESSION_END_RQ                 (1 << 4)
+#define MAX3353E_SESSION_VALID_RN               (1 << 3)
+#define MAX3353E_VBUS_VALID_RN                  (1 << 2)
+#define MAX3353E_SESSION_VALID_RP               (1 << 1)
+#define MAX3353E_VBUS_VALID_RP                  (1 << 0)
+
+/*! @} */
+
diff -uNr linux/drivers/no-otg/otghw/mx2ads-hardware.h linux/drivers/otg/otghw/mx2ads-hardware.h
--- linux/drivers/no-otg/otghw/mx2ads-hardware.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otghw/mx2ads-hardware.h	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,111 @@
+/*
+ * otghw/mx2ads-hardware.h
+ *
+ * Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*! 
+ * @file otghw/mx2ads-hardware.h
+ * @brief MX2ADS Hardware constants
+ *
+ * @ingroup MX2ADS
+ */
+
+
+/*!
+ * @name MX2ETDS
+ * R1 = i.MX21 Application Processor Reference Manual Rev 0.6 2003/11/01 TO 1.0
+ *      (aka "IMX21RM_TO1.pdf")
+ * R2 = "USBOTG_L3_Specification_v.C1.0.pdf"
+ * @{
+ */
+
+#define NUM_ETDS                32
+#define DATA_BUFF_SIZE          64
+#define DATA_BUFFER_TOTAL       4096
+#define NUM_DATA_BUFFS          (4096/DATA_BUFF_SIZE)
+//#define LITTLE_ENDIAN           1
+
+/* @} */
+
+
+/*!
+ * @name MX2Interrupts
+ * @{
+ */
+#define OTG_USBWKUP                 53
+#define OTG_USBDMA                  54
+#define OTG_USBHOST                 55
+#define OTG_USBFUNC                 56
+#define OTG_USBHNP                  57
+#define OTG_USBCTRL                 58
+/* @} */
+
+/*!
+ * @name AHBMemoryMap
+ * C.F. Table 23-5 AHB Memory Map
+ * @{
+ */
+#ifndef OTG_BASE_ADDR
+#define OTG_BASE_ADDR                           0x10024000      
+
+#define OTG_CORE_BASE                           (OTG_BASE_ADDR+0x000)   //  base location for core
+#define OTG_FUNC_BASE                           (OTG_BASE_ADDR+0x040)   //  base location for function
+#define OTG_HOST_BASE                           (OTG_BASE_ADDR+0x080)   //  base location for host
+#define OTG_I2C_BASE                            (OTG_BASE_ADDR+0x100)   //  base location for I2C
+
+#define OTG_ETD_BASE                            (OTG_BASE_ADDR+0x200)   //  base location for etd memory
+#define OTG_EP_BASE                             (OTG_BASE_ADDR+0x400)   //  base location for ep memory
+#define OTG_SYS_BASE                            (OTG_BASE_ADDR+0x600)   //  base location for system
+
+#define OTG_DMA_BASE                            (OTG_BASE_ADDR+0x800)   //  base location for dma
+
+#define OTG_DATA_BASE                           (OTG_BASE_ADDR+0x1000)  //  base location for data memory
+
+#define OTG_SYS_CTRL                            (OTG_SYS_BASE+0x000)    //  base location for system
+#endif
+/* @} */
+
+/*!
+ * @name I2CTransceiver
+ * C.f. 23.14.10 I2C OTG Transceiver Controller Registers
+ * These are the I2C controller and access registers.
+ *
+ * N.B. I2C_ERROR is not documented.
+ * @{
+ */
+
+
+#define I2C_BUSY                                (1 << 7)
+#define I2C_ERROR                               (1 << 2)
+#define I2C_HWSMODE                             (1 << 1)
+#define I2C_I2COE                               (1 << 0)
+
+#define I2C_SCLK_TO_SCL_DIVISION                (OTG_I2C_BASE+0x1E)
+
+#define I2C_INTERRUPT_AND_CONTROL               (OTG_I2C_BASE+0x1F)
+
+#define I2C_STATUS_MASK                         (0x7)
+
+#define I2C_NOACK_EN                            (1 << 6)
+#define I2C_RWREADY_EN                          (1 << 5)
+#define I2C_OTGXCVRINT_EN                       (1 << 4)
+
+#define I2C_NOACK                               (1 << 2)
+#define I2C_RWREADY                             (1 << 1)
+#define I2C_OTGXCVRINT                          (1 << 0)
+
+#define MX2_OTG_XCVR_DEVAD                      OTG_I2C_BASE+0x18
+#define MX2_SEQ_OP_REG                          OTG_I2C_BASE+0x19
+#define MX2_SEQ_RD_STARTAD                      OTG_I2C_BASE+0x1a
+#define MX2_I2C_OP_CTRL_REG                     OTG_I2C_BASE+0x1b
+#define MX2_SCLK_TO_SCL_HPER                    OTG_I2C_BASE+0x1e
+#define MX2_I2C_INTERRUPT_AND_CTRL              OTG_I2C_BASE+0x1f
+
+/* @} */
+
diff -uNr linux/drivers/no-otg/otghw/mx2ads.h linux/drivers/otg/otghw/mx2ads.h
--- linux/drivers/no-otg/otghw/mx2ads.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otghw/mx2ads.h	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,46 @@
+/*
+ * otghw/mx2ads.h
+ *
+ *      Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ */
+ 
+/*!
+ * @defgroup MX2ADS Freescale MX2ADS
+ * @ingroup platformgroup 
+ */
+/*! 
+ * @file otghw/mx2ads.h
+ * @brief MX2ADS Platform constants
+ *
+ * Notes
+ *
+ * 1. Interrupts - we seem to get all interrupts on the ctrl interrupt.
+ *
+ * 2. Clearing - it appears that clearing the status bits sometimes fails, This
+ * has been observed in SINT_STAT and XFILL_STAT.
+ *
+ * 3. Double buffer - without DMA it does not appear to be possible to use
+ * both X and Y buffers for OUT transfers because we can not apparantely guarantee
+ * the order that the X and Y buffers will be used. If we get an interrupt with
+ * both X and Y active we cannot determine which order to use them. As long as
+ * we get each interrupt fast enough this is not a problem as we can then just
+ * use whichever is active.
+ *
+ * 4. Remote Wakeup - cannot set RSMINPROG bit
+ *
+ * @ingroup MX2ADS
+ */
+
+
+#define UDC_NAME                "MX21"
+#define UDC_MAX_ENDPOINTS       32
+#define EP0_PACKETSIZE          64
+
+
+extern otg_tag_t MX2;
+
diff -uNr linux/drivers/no-otg/otghw/td243-hardware.h linux/drivers/otg/otghw/td243-hardware.h
--- linux/drivers/no-otg/otghw/td243-hardware.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/otg/otghw/td243-hardware.h	2006-09-01 21:41:35.000000000 +0200
@@ -0,0 +1,709 @@
+/*
+ * otg/pcd/mx2/td243-hardware.h
+ *
+ * Copyright (c) 2004 Belcarra
+ *
+ * By: 
+ *      Stuart Lynne <sl@belcarra.com>, 
+ *      Tom Rushworth <tbr@belcarra.com>, 
+ *      Bruce Balden <balden@belcarra.com>
+ *
+ */
+/*!
+ * @defgroup TD243 Transdimension USBOTG 
+ * @ingroup libgroup
+ */
+/*!
+ * @file /otg/otghw/td243-hardware.h
+ * @brief Hardware defines for Transimension USBOTG Hardware
+ *
+ * @ingroup TD243
+ */
+
+
+/*
+ * C.f. 23.8 USB Control Register
+ */
+
+#define SYS_CTRL_I2C_WU_INT_STAT                (1 << 27)
+#define SYS_CTRL_OTG_WU_INT_STAT                (1 << 26)
+#define SYS_CTRL_HOST_WU_INT_STAT               (1 << 25)
+#define SYS_CTRL_FNT_WU_INT_STAT                (1 << 24)
+
+#define SYS_CTRL_I2C_WU_INT_EN                  (1 << 19)
+#define SYS_CTRL_OTG_WU_INT_EN                  (1 << 18)
+#define SYS_CTRL_HOST_WU_INT_EN                 (1 << 17)
+#define SYS_CTRL_FNT_WU_INT_EN                  (1 << 16)
+
+#define SYS_CTRL_OTG_BYP_VAL                    (0x3 << 11)
+#define SYS_CTRL_HOST1_BYP_VAL                  (0x3 << 9)
+
+        
+
+#define SYS_CTRL_OTG_PWR_MASK                   (1 << 6)
+#define SYS_CTRL_HOST1_PWR_MASK                 (1 << 6)
+#define SYS_CTRL_HOST2_PWR_MASK                 (1 << 4)
+#define SYS_CTRL_USB_BYP                        (1 << 2)
+#define SYS_CTRL_HOST1_TXEN_OE                  (1 << 1)
+
+
+/*
+ * C.f. 23.9 USBOTG Module Registers
+ */
+
+#define OTG_CORE_HWMODE                         (OTG_CORE_BASE+0x00)            //  32bit core hardware mode reg
+
+#define XCVR_D_D                                0x00
+#define XCVR_SE_D                               0x01
+#define XCVR_D_SE                               0x02
+#define XCVR_SE_SE                              0x03
+
+#define MODULE_ANASDBEN                         (1 << 14)
+#define MODULE_OTGXCVR                          (0x3 << 6)
+#define MODULE_HOSTXCVR                         (0x3 << 4)
+#define MODULE_CRECFG                           (0x3)
+#define MODULE_CRECFG_HHNP                      (0x0)
+#define MODULE_CRECFG_HOST                      (0x1)
+#define MODULE_CRECFG_FUNC                      (0x2)
+#define MODULE_CRECFG_SHNP                      (0x3)
+
+#define OTG_CORE_CINT_STAT                      (OTG_CORE_BASE+0x04)            //  32bit core int status reg
+
+#define MODULE_FCINTDSPEN                       (1 << 6)
+
+#define MODULE_ASHNPINT                         (1 << 5)
+#define MODULE_ASFCINT                          (1 << 4)
+#define MODULE_ASHCINT                          (1 << 3)
+#define MODULE_HNPINT                           (1 << 2)
+#define MODULE_FCINT                            (1 << 1)
+#define MODULE_HCINT                            (1)
+
+#define OTG_CORE_CINT_STEN                      (OTG_CORE_BASE+0x08)            //  32bit core int enable reg
+
+#define MODULE_ASHNPINT_EN                      (1 << 5)
+#define MODULE_ASFCINT_EN                       (1 << 4)
+#define MODULE_ASHCINT_EN                       (1 << 3)
+#define MODULE_HNPINT_EN                        (1 << 2)
+#define MODULE_FCINT_EN                         (1 << 1)
+#define MODULE_HCINT_EN                         (1)
+
+#define OTG_CORE_CLK_CTRL                       (OTG_CORE_BASE+0x0C)            //  32bit core clock control reg
+
+#define MODULE_FUNC_CLK                         (1 << 2)
+#define MODULE_HOST_CLK                         (1 << 1)
+#define MODULE_MAIN_CLK                         (1)
+
+#define OTG_CORE_RST_CTRL                       (OTG_CORE_BASE+0x10)            // 32bit core reset control reg
+
+#define MODULE_RSTI2C                           (1 << 15)
+#define MODULE_RSTCTRL                          (1 << 5)
+#define MODULE_RSTFC                            (1 << 4)
+#define MODULE_RSTFSIE                          (1 << 3)
+#define MODULE_RSTRH                            (1 << 2)
+#define MODULE_RSTHSIE                          (1 << 1)
+#define MODULE_RSTHC                            (1)
+
+#define OTG_CORE_FRM_INTVL                      (OTG_CORE_BASE+0x14)            //  32bit core frame interval reg
+
+#define MODULE_RESET_FRAME                      (1 << 15)
+
+#define OTG_CORE_FRM_REMAIN                     (OTG_CORE_BASE+0x18)            //  32bit core frame remaining reg
+
+#define OTG_CORE_HNP_CSTAT                      (OTG_CORE_BASE+0x1C)            //  32bit core HNP current state reg
+
+#define MODULE_HNPDAT                           (1 << 30)
+#define MODULE_VBUSBSE                          (1 << 29)
+#define MODULE_VBUSABSV                         (1 << 28)
+#define MODULE_VBUSGTAVV                        (1 << 27)
+
+#define MODULE_ARMTHNPE                         (1 << 25)
+#define MODULE_BHNPEN                           (1 << 24)
+
+#define MODULE_SLAVE                            (1 << 22)
+#define MODULE_MASTER                           (1 << 21)
+#define MODULE_BGEN                             (1 << 20)
+#define MODULE_CMPEN                            (1 << 19)
+#define MODULE_ISBDEV                           (1 << 18)
+#define MODULE_ISADEV                           (1 << 17)
+
+#define MODULE_SWVBUSPUL                        (1 << 15)
+
+#define MODULE_SWAUTORST                        (1 << 12)
+#define MODULE_SWPUDP                           (1 << 11)
+
+#define MODULE_SWPDDM                           (1 << 9)
+#define MODULE_HNPSTATE                         (0x1f << 8)
+#define MODULE_CLRERROR                         (1 << 3)
+#define MODULE_ADROPBUS                         (1 << 2)
+#define MODULE_ABBUSREQ                         (1 << 1)
+
+#define HNP_A_IDLE                              (0x10 << 8)
+#define HNP_A_MASTER                            (0x11 << 8)
+#define HNP_A_SLAVE                             (0x12 << 8)
+#define HNP_A_WAIT_VPULSE                       (0x13 << 8)
+
+#define HNP_A_WAIT_DPULSE                       (0x14 << 8)
+#define HNP_A_WAIT_CONN_A                       (0x15 << 8)
+#define HNP_A_WAIT_CONN_B                       (0x16 << 8)
+#define HNP_A_WAIT_VRISE                        (0x17 << 8)
+#define HNP_A_SUSPEND                           (0x18 << 8)
+#define HNP_A_WAIT_VFALL                        (0x19 << 8)
+#define HNP_A_VBUS_ERR                          (0x1a << 8)
+#define HNP_CONN_DEBOUNCE                       (0x1b << 8)
+#define HNP_A_WAIT_ABREQ                        (0x1c << 8)
+#define HNP_B_IDLE                              (0x00 << 8)
+#define HNP_B_MASTER                            (0x01 << 8)
+#define HNP_B_SLAVE                             (0x02 << 8)
+#define HNP_B_SRP_INIT_V                        (0x03 << 8)
+#define HNP_B_SRP_INIT_D                        (0x04 << 8)
+#define HNP_B_PRE_WAIT_CONN_AB_SHORT_DB         (0x05 << 8)
+#define HNP_B_WAIT_CONN_A                       (0x06 << 8)
+#define HNP_B_PRE_SLAVE                         (0x0a << 8)
+
+
+#define OTG_CORE_HNP_TIMER1                     (OTG_CORE_BASE+0x20)            //  32bit core HNP timer 1 reg
+#define OTG_CORE_HNP_TIMER2                     (OTG_CORE_BASE+0x24)            //  32bit core HNP timer 2 reg
+#define OTG_CORE_HNP_T3PCR                      (OTG_CORE_BASE+0x28)            //  32bit core HNP timer 3 pulse ctrl
+
+#define HNP_DATAPULSE                           (1 << 5)
+#define HNP_VBUSPULSE                           (1 << 4)
+
+#define OTG_CORE_HINT_STAT                      (OTG_CORE_BASE+0x2C)            //  32bit core HNP int status reg
+
+#define HNP_I2COTGINT                           (1 << 15)
+#define HNP_AWAITBTO                            (1 << 8)                        // Hardware HNP Only
+#define HNP_AIDLEBDTO                           (1 << 7)                        // Hardware HNP Only
+#define HNP_SRPSUCFAIL                          (1 << 6)                        // Hardware HNP Only
+#define HNP_SRPINT                              (1 << 5)
+#define HNP_VBUSERROR                           (1 << 4)                        // Hardware HNP Only
+#define HNP_ABSEVAILD                           (1 << 3)
+#define HNP_ABUSVALID                           (1 << 2)
+#define HNP_MASSLVCHG                           (1 << 1)                        // Hardware HNP Only
+#define HNP_IDCHANGE                            (1)
+
+#define OTG_CORE_HINT_STEN                      (OTG_CORE_BASE+0x30)            //  32bit core HNP int enable reg
+
+#define HNP_I2COTGINT_EN                        (1 << 15)
+#define HNP_AWAITBTO_EN                         (1 << 8)
+#define HNP_AIDLEBDTO_EN                        (1 << 7)
+#define HNP_SRPSUCFAIL_EN                       (1 << 6)
+#define HNP_SRPINT_EN                           (1 << 5)
+#define HNP_VBUSERROR_EN                        (1 << 4)
+#define HNP_ABSEVAILD_EN                        (1 << 3)
+#define HNP_ABUSVALID_EN                        (1 << 2)
+#define HNP_MASSLVCHG_EN                        (1 << 1)
+#define HNP_IDCHANGE_EN                         (1)
+
+
+#define OTG_CORE_CPUEPSEL_STAT                  (OTG_CORE_BASE+0x34)
+#define OTG_CORE_INTERRUPT_STEN                 (OTG_CORE_BASE+0x3c)
+
+
+/*
+ * C.f. 23.11.11 Host Registers
+ */
+
+
+#define OTG_HOST_CONTROL                        (OTG_HOST_BASE+0x00)     //  32bit host controller config reg
+
+#define HOST_CONTROL_HCRESET                    (1 << 31)
+#define HOST_CONTROL_RMTWUEN                    (1 << 4)
+
+#define HOST_CONTROL_HCUSBSTE_RESET             (0 << 2)
+#define HOST_CONTROL_HCUSBSTE_RESUME            (1 << 2)
+#define HOST_CONTROL_HCUSBSTE_OPERATIONAL       (2 << 2)
+#define HOST_CONTROL_HCUSBSTE_SUSPEND           (3 << 2)
+
+#define HOST_CONTROL_CTLBLKSR_11                (0)
+#define HOST_CONTROL_CTLBLKSR_21                (1)
+#define HOST_CONTROL_CTLBLKSR_41                (2)
+#define HOST_CONTROL_CTLBLKSR_81                (3)
+
+
+#define OTG_HOST_SINT_STAT                      (OTG_HOST_BASE+0x08)     //  32bit host system int status reg
+
+#define HOST_PSCINT                             (1 << 6)                // Port Status Change 
+#define HOST_FMOFINT                            (1 << 5)                // Frame Number Overflow
+#define HOST_HERRINT                            (1 << 4)                // Host Error
+#define HOST_RESDETINT                          (1 << 3)                // Resume Detected
+#define HOST_SOFINT                             (1 << 2)                // Start of Frame
+#define HOST_DONEINT                            (1 << 1)                // Done Register
+#define HOST_SORINT                             (1)                     // Schedule Overrun
+
+#define OTG_HOST_SINT_STEN                      (OTG_HOST_BASE+0x0C)     //  32bit host system int enable reg
+
+#define HOST_PSCINT_EN                          (1 << 6)                // Port Status Change 
+#define HOST_FMOFINT_EN                         (1 << 5)                // Frame Number Overflow
+#define HOST_HERRINT_EN                         (1 << 4)                // Host Error
+#define HOST_RESDETINT_EN                       (1 << 3)                // Resume Detected
+#define HOST_SOFINT_EN                          (1 << 2)                // Start of Frame
+#define HOST_DONEINT_EN                         (1 << 1)                // Done Register
+#define HOST_SORINT_EN                          (1)                     // Schedule Overrun
+
+#define OTG_HOST_XINT_STAT                      (OTG_HOST_BASE+0x18)     //  32bit host X buf int status reg
+#define OTG_HOST_YINT_STAT                      (OTG_HOST_BASE+0x1C)     //  32bit host Y buf int status reg
+
+#define OTG_HOST_XYINT_STEN                     (OTG_HOST_BASE+0x20)     //  32bit host XY buf int enable reg
+#define OTG_HOST_XFILL_STAT                     (OTG_HOST_BASE+0x28)     //  32bit host X filled status reg
+#define OTG_HOST_YFILL_STAT                     (OTG_HOST_BASE+0x2C)     //  32bit host Y filled status reg
+
+#define OTG_HOST_ETD_EN                         (OTG_HOST_BASE+0x40)     //  32bit host ETD enables reg
+#define OTG_HOST_DIR_ROUTE                      (OTG_HOST_BASE+0x48)     //  32bit host direct routing reg
+#define OTG_HOST_IINT                           (OTG_HOST_BASE+0x4C)     //  32bit host immediate interrupt reg
+
+#define OTG_HOST_EP_DSTAT                       (OTG_HOST_BASE+0x50)     //  32bit host endpoints done status
+#define OTG_HOST_ETD_DONE                       (OTG_HOST_BASE+0x54)     //  32bit host ETD done reg
+
+#define OTG_HOST_FRM_NUM                        (OTG_HOST_BASE+0x60)     //  32bit host frame number reg
+#define OTG_HOST_LSP_THRESH                     (OTG_HOST_BASE+0x64)     //  32bit host low speed threshold reg
+
+#define OTG_HOST_ROOTHUB_DESCA                  (OTG_HOST_BASE+0x68)     //  32bit host root hub descriptor A
+#define OTG_HOST_ROOTHUB_DESCB                  (OTG_HOST_BASE+0x6C)     //  32bit host root hub descriptor B
+
+/*
+ * C.f. 23.11.29
+ */
+#define OTG_HOST_ROOTHUB_STATUS                 (OTG_HOST_BASE+0x70)     //  32bit host root hub status reg
+
+#define ROOTHUB_STATUS_CLRMTWUE                 (1 << 31)               // Clear Remote Wakeup Enable
+#define ROOTHUB_STATUS_OVRCURCHG                (1 << 17)               // Over Current Indicator Change
+#define ROOTHUB_STATUS_LOCPWRSC                 (1 << 16)               // Local Power Status Change
+#define ROOTHUB_STATUS_DEVCONWUE                (1 << 15)               // Device Connect Wakeup Enable
+#define ROOTHUB_STATUS_OVRCURI                  (1 << 1)                // Over Current Indicator
+#define ROOTHUB_STATUS_LOCPWRS                  (1)                     // Local Power Status
+
+
+/*
+ * C.f. 23.11.30
+ */
+#define OTG_HOST_PORT_STATUS_1                  (OTG_HOST_BASE+0x74)     //  32bit host port 1 status bits
+#define OTG_HOST_PORT_STATUS_2                  (OTG_HOST_BASE+0x78)     //  32bit host port 2 status bits
+#define OTG_HOST_PORT_STATUS_3                  (OTG_HOST_BASE+0x7c)     //  32bit host port 3 status bits
+
+#define PORT_STATUS_PRTRSTSC                    (1 << 20)               // Port Reset Status Change
+#define PORT_STATUS_OVRCURIC                    (1 << 19)               // Port Over Current Indicator Change
+#define PORT_STATUS_PRTSTATSC                   (1 << 18)               // Port Suspend Status Change
+#define PORT_STATUS_PRTENBLSC                   (1 << 17)               // Port Enable Status Change
+#define PORT_STATUS_CONNECTSC                   (1 << 16)               // Connect Status Change
+
+#define PORT_STATUS_LSDEVCON                    (1 << 9)                // Low Speed Device Attached
+#define PORT_STATUS_PRTPWRST                    (1 << 8)                // Port Power Status
+
+#define PORT_STATUS_PRTRSTST                    (1 << 4)                // Port Reset Status
+#define PORT_STATUS_PRTOVRCURI                  (1 << 3)                // Port Over Current Indicator
+#define PORT_STATUS_PRTSUSPST                   (1 << 2)                // Port Suspend Status
+#define PORT_STATUS_PRTENABST                   (1 << 1)                // Port Enable Status
+#define PORT_STATUS_CURCONST                    (1)                     // Current Connect Status
+
+
+/* flags are the same for the interrupt, control and bulk transfer descriptors */
+// R1: sec 23.11.10.2,3 pg 23-44,47
+#define ETD_GET_COMPCODE(flags)   ((flags >> 12) & 0xf)
+// R1: sec 23.11.10 Table 23-23 pg 23-40
+#define ETD_CC_NOERROR            0x0
+#define ETD_CC_CRCERR             0x1
+#define ETD_CC_BITSTUFFERR        0x2
+#define ETD_CC_DATATOGERR         0x3
+#define ETD_CC_STALL              0x4
+#define ETD_CC_DEVNOTRESPONDING   0x5
+#define ETD_CC_PIDFAILURE         0x6
+// Reserved                       0x7
+#define ETD_CC_DATAOVERRUN        0x8
+#define ETD_CC_DATAUNDERRUN       0x9
+#define ETD_CC_ACK                0xA
+#define ETD_CC_NAK                0xB
+#define ETD_CC_BUFFEROVERRUN      0xC
+#define ETD_CC_BUFFERUNDERRUN     0xD
+#define ETD_CC_SCHEDOVERRUN       0xE
+#define ETD_CC_NOTACCESSED        0xF
+
+// R1: sec 23.11.10.2,3 pg 23-44,47 (contd)
+#define ETD_GET_ERRORCNT(flags)   (((flags) >> 8) & 0xf)
+#define ETD_GET_DATATOGL(flags)   (((flags) >> 6) & 0x3)
+#define ETD_SET_DATATOGL(v)       (((v) & 0x3) << 6)
+#define ETD_GET_DELAYINT(flags)   (((flags) >> 3) & 0x7)
+#define ETD_SET_DELAYINT(v)       (((v) & 0x7) << 3)
+#define ETD_GET_BUFROUND(flags)   (((flags) >> 2) & 0x1)
+#define ETD_SET_BUFROUND(v)       (((v) & 0x1) << 2)
+#define ETD_GET_DIRPID(flags)     ((flags) & 0x3)
+#define ETD_SET_DIRPID(v)         ((v) & 0x3)
+#define ETD_FLIP_DIRPID(flags)    ((flags) ^ 0x3) /* xor with 0x3 flips 2<->1 (IN<->OUT) */
+#define ETD_DIRPID_SETUP          0x0  // OUT
+#define ETD_DIRPID_OUT            0x1
+#define ETD_DIRPID_IN             0x2
+#define ETD_DIRPID_RESERVED       0x3
+
+// For non-isoc td.w3.val -
+#define ETD_GET_BUFSIZE(w3)       (((w3) >> 21) & 0xfff)
+#define ETD_SET_BUFSIZE(v)        (((v) & 0xfff) << 21)
+#define ETD_GET_TOTBYECNT(w3)     ((w3) & 0xfffff)
+#define ETD_SET_TOTBYECNT(v)      ((v) & 0xfffff)
+
+/* isoc flags shares the COMPCODE and DELAYINT bitfields with the other TDs,
+   but the remaining bits are different. */
+#define ETD_GET_AUTOISO(flags)    (((flags) >> 11) & 0x1)
+#define ETD_SET_AUTOISO(v)        (((v) & 0x1) << 11)
+#define ETD_GET_FRAMECNT(flags)   (((flags) >> 8) & 0x1)
+#define ETD_SET_FRAMECNT(v)       (((v) & 0x1) << 8)
+// For isoc td.w3.val -
+/* pkt1 and pkt0 use the COMPCODE bitfield, and add a PKTLEN field. */
+#define ETD_GET_PKTLEN(pkt)       ((pkt) & 0x3ff)
+#define ETD_SET_PKTLEN(v)         ((v) & 0x3ff)
+
+
+// ETD endpoint descriptor (etd->epd) bitfield access
+// R1: sec 23.11.10.1 pg 23-41 (word0)
+#define ETD_GET_SNDNAK(epd)    (((epd) >> 30) & 0x1)
+#define ETD_SET_SNDNAK(v)      (((v) & 0x1) << 30)
+#define ETD_GET_TOGCRY(epd)    (((epd) >> 28) & 0x1)
+#define ETD_SET_TOGCRY(v)      (((v) & 0x1) << 28)
+#define ETD_GET_HALTED(epd)    (((epd) >> 27) & 0x1)
+#define ETD_SET_HALTED(v)      (((v) & 0x1) << 27)
+#define ETD_GET_MAXPKTSIZ(epd) (((epd) >> 16) & 0x3ff)
+#define ETD_SET_MAXPKTSIZ(v)   (((v) & 0x3ff) << 16)
+#define ETD_GET_FORMAT(epd)    (((epd) >> 14) & 0x3)
+#define ETD_SET_FORMAT(v)      (((v) & 0x3) << 14)
+#define ETD_FORMAT_CONTROL     0x0
+#define ETD_FORMAT_ISOC        0x1
+#define ETD_FORMAT_BULK        0x2
+#define ETD_FORMAT_INTERRUPT   0x3
+#define ETD_GET_SPEED(epd)     (((epd) >> 13) & 0x1)
+#define ETD_SET_SPEED(v)       (((v) & 0x1) << 13)
+#define ETD_SPEED_FULL         0x0
+#define ETD_SPEED_LOW          0x1
+#define ETD_GET_DIRECT(epd)    (((epd) >> 11) & 0x3)
+#define ETD_SET_DIRECT(v)      (((v) & 0x3) << 11)
+/* xor with 3 flips 2<->1 */
+#define ETD_FLIP_DIRECT(epd)   ((epd) ^ (0x3 << 11))
+#define ETD_DIRECT_TD00        0x0
+#define ETD_DIRECT_OUT         0x1
+#define ETD_DIRECT_IN          0x2
+#define ETD_DIRECT_TD11        0x3
+#define ETD_GET_ENDPNT(epd)    (((epd) >> 7) & 0xf)
+#define ETD_SET_ENDPNT(v)      (((v) & 0xf) << 7)
+#define ETD_GET_ADDRESS(epd)   ((epd) & 0x7f)
+#define ETD_SET_ADDRESS(v)     ((v) & 0x7f)
+
+// etd_urb_state[] values
+#define ETD_URB_COMPLETED       0
+#define ETD_URB_SETUP_STATUS    1
+#define ETD_URB_SETUP_DATA      2
+#define ETD_URB_SETUP_START     3
+#define ETD_URB_BULK_START      4
+#define ETD_URB_BULKWZLP        5
+#define ETD_URB_BULKWZLP_START  6
+#define ETD_URB_INTERRUPT_START 7
+#define ETD_URB_ISOC_START      8
+
+
+/*
+ * C.f. 23.12.8 Function Registers
+ */
+
+#define OTG_FUNC_CMD_STAT                       (OTG_FUNC_BASE+0x00)            //  32bit func command status reg
+
+#define COMMAND_SOFTRESET                       (1 << 7)
+#define COMMAND_BADISOAP                        (1 << 3)
+#define COMMAND_SUPDET                          (1 << 2)
+#define COMMAND_RSMINPROG                       (1 << 1)
+#define COMMAND_RESETDET                        (1)
+
+
+#define OTG_FUNC_DEV_ADDR                       (OTG_FUNC_BASE+0x04)            //  32bit func device address reg
+
+#define OTG_FUNC_SINT_STAT                      (OTG_FUNC_BASE+0x08)            //  32bit func system int status reg
+
+#define SYSTEM_DONEREGINTDS                     (1 << 5)
+#define SYSTEM_SOFDETINT                        (1 << 4)
+#define SYSTEM_DONEREGINT                       (1 << 3)
+#define SYSTEM_SUSPDETINT                       (1 << 2)
+#define SYSTEM_RSMFININT                        (1 << 1)
+#define SYSTEM_RESETINT                         (1)
+
+#define OTG_FUNC_SINT_STEN                      (OTG_FUNC_BASE+0x0C)            //  32bit func system int enable reg
+
+#define SYSTEM_DONEREGINTDS_EN                  (1 << 5)
+#define SYSTEM_SOFDETINT_EN                     (1 << 4)
+#define SYSTEM_DONEREGINT_EN                    (1 << 3)
+#define SYSTEM_SUSPDETINT_EN                    (1 << 2)
+#define SYSTEM_RSMFININT_EN                     (1 << 1)
+#define SYSTEM_RESETINT_EN                      (1)
+
+
+#define OTG_FUNC_XINT_STAT                      (OTG_FUNC_BASE+0x10)            //  32bit func X buf int status reg
+#define OTG_FUNC_YINT_STAT                      (OTG_FUNC_BASE+0x14)            //  32bit func Y buf int status reg
+#define OTG_FUNC_XYINT_STEN                     (OTG_FUNC_BASE+0x18)            //  32bit func XY buf int enable reg
+#define OTG_FUNC_XFILL_STAT                     (OTG_FUNC_BASE+0x1C)            //  32bit func X filled status reg
+
+#define OTG_FUNC_YFILL_STAT                     (OTG_FUNC_BASE+0x20)            //  32bit func Y filled status reg
+#define OTG_FUNC_EP_EN                          (OTG_FUNC_BASE+0x24)            //  32bit func endpoints enable reg
+#define OTG_FUNC_EP_RDY                         (OTG_FUNC_BASE+0x28)            //  32bit func endpoints ready reg
+#define OTG_FUNC_IINT                           (OTG_FUNC_BASE+0x2C)            //  32bit func immediate interrupt reg
+
+#define OTG_FUNC_EP_DSTAT                       (OTG_FUNC_BASE+0x30)            //  32bit func endpoints done status
+#define OTG_FUNC_EP_DEN                         (OTG_FUNC_BASE+0x34)            //  32bit func endpoints done enable
+#define OTG_FUNC_EP_TOGGLE                      (OTG_FUNC_BASE+0x38)            //  32bit func endpoints toggle bits
+#define OTG_FUNC_FRM_NUM                        (OTG_FUNC_BASE+0x3C)            //  32bit func frame number reg
+
+
+#define EP0_STALL                               (1 << 31)
+#define EP0_SETUP                               (1 << 30)
+#define EP0_OVERRUN                             (1 << 29)
+#define EP0_AUTOISO                             (1 << 27)
+
+
+/* generic endpoint register manipulations
+ */
+#define EP_OUT                                  0x1
+#define EP_IN                                   0x2
+#define EP_BOTH                                 0x3
+
+#define ETD_MASK(n)                             (1 << n)
+#define ep_num_both(n)                          (EP_BOTH << n)
+#define ep_num_dir(n, dir)                      ((dir ? EP_IN : EP_OUT) << (n*2))
+#define ep_num_out(n)                           ep_num_dir(n, USB_DIR_OUT)
+#define ep_num_in(n)                            ep_num_dir(n, USB_DIR_IN)
+
+
+/* ep descriptor access
+ */
+static __inline__ u32 etd_word(int n, int word)
+{
+        u32 offset = n * 16;
+        offset += word * 4;
+        return OTG_ETD_BASE + offset;
+}
+
+/* ep descriptor access
+ */
+static __inline__ u32 ep_word(int n, int dir, int word)
+{
+        u32 offset = n * 2;
+        offset += dir ? 1 : 0;
+        offset *= 16;
+        offset += word * 4;
+        return OTG_EP_BASE + offset;
+}
+
+/* endpoint data buffer access
+ * 
+ * This is a simplistic allocator, will do until we want to support ISO or host mode.
+ *
+ * This works because we are assuming a maximum of 16 allocate endpoints, and no
+ * overlapped endpoints (both in and out are allocated).
+ */
+
+static volatile __inline__ u16 data_x_buf(int n, int dir)
+{ 
+        return 0x40 * (n * 4 + 2 * (dir ? 1 : 0));
+}
+static volatile __inline__ u16 data_y_buf(int n, int dir)
+{ 
+        return 0x40 * (n * 4 + 2 * (dir ? 1 : 0) + 1);
+}
+
+static volatile __inline__ u8 * data_x_address(int n, int dir)
+{ 
+        return (volatile u8 *) IO_ADDRESS(OTG_DATA_BASE + data_x_buf(n, dir));
+}
+static volatile __inline__ u8 * data_y_address(int n, int dir)
+{ 
+        return (volatile u8 *) IO_ADDRESS(OTG_DATA_BASE + data_y_buf(n, dir));
+}
+
+/*
+ * C.f. 23.13.3 DMA Registers
+ */
+#define OTG_DMA_REV_NUM                         (OTG_DMA_BASE+0x000)     //  32bit dma revision number reg
+#define OTG_DMA_DINT_STAT                       (OTG_DMA_BASE+0x004)     //  32bit dma int status reg
+#define OTG_DMA_DINT_STEN                       (OTG_DMA_BASE+0x008)     //  32bit dma int enable reg
+#define OTG_DMA_ETD_ERR                         (OTG_DMA_BASE+0x00C)     //  32bit dma ETD error status reg
+#define OTG_DMA_EP_ERR                          (OTG_DMA_BASE+0x010)     //  32bit dma EP error status reg
+#define OTG_DMA_ETD_EN                          (OTG_DMA_BASE+0x020)     //  32bit dma ETD DMA enable reg
+#define OTG_DMA_EP_EN                           (OTG_DMA_BASE+0x024)     //  32bit dma EP DMA enable reg
+#define OTG_DMA_ETD_ENXREQ                      (OTG_DMA_BASE+0x028)     //  32bit dma ETD DMA enable Xtrig req
+#define OTG_DMA_EP_ENXREQ                       (OTG_DMA_BASE+0x02C)     //  32bit dma EP DMA enable Ytrig req
+#define OTG_DMA_ETD_ENXYREQ                     (OTG_DMA_BASE+0x030)     //  32bit dma ETD DMA enble XYtrig req
+#define OTG_DMA_EP_ENXYREQ                      (OTG_DMA_BASE+0x034)     //  32bit dma EP DMA enable XYtrig req
+#define OTG_DMA_ETD_BURST4                      (OTG_DMA_BASE+0x038)     //  32bit dma ETD DMA enble burst4 reg
+#define OTG_DMA_EP_BURST4                       (OTG_DMA_BASE+0x03C)     //  32bit dma EP DMA enable burst4 reg
+#define OTG_DMA_MISC_CTRL                       (OTG_DMA_BASE+0x040)     //  32bit dma EP misc control reg
+#define OTG_DMA_ETD_CH_CLR                      (OTG_DMA_BASE+0x044)     //  32bit dma ETD clear channel reg
+#define OTG_DMA_EP_CH_CLR                       (OTG_DMA_BASE+0x048)     //  32bit dma EP clear channel reg
+                        
+
+#define OTG_DMA_ETD_CH_CLR                      (OTG_DMA_BASE+0x044)     //  32bit dma ETD clear channel reg
+#define OTG_DMA_ETD_ERR                         (OTG_DMA_BASE+0x00C)     //  32bit dma ETD error status reg
+#define OTG_DMA_ETD_EN                          (OTG_DMA_BASE+0x020)     //  32bit dma ETD DMA enable reg
+#define OTG_DMA_ETD_ENXREQ                      (OTG_DMA_BASE+0x028)     //  32bit dma ETD DMA enable Xtrig req
+#define OTG_DMA_ETD_ENXYREQ                     (OTG_DMA_BASE+0x030)     //  32bit dma ETD DMA enble XYtrig req
+#define OTG_DMA_ETD_BURST4                      (OTG_DMA_BASE+0x038)     //  32bit dma ETD DMA enble burst4 reg
+
+
+
+#define OTG_DMA_EP_CH_CLR                       (OTG_DMA_BASE+0x048)     //  32bit dma EP clear channel reg
+#define OTG_DMA_EP_ERR                          (OTG_DMA_BASE+0x010)     //  32bit dma EP error status reg
+#define OTG_DMA_EP_EN                           (OTG_DMA_BASE+0x024)     //  32bit dma EP DMA enable reg
+#define OTG_DMA_EP_ENXREQ                       (OTG_DMA_BASE+0x02C)     //  32bit dma EP DMA enable Ytrig req
+#define OTG_DMA_EP_ENXYREQ                      (OTG_DMA_BASE+0x034)     //  32bit dma EP DMA enable XYtrig req
+#define OTG_DMA_EP_BURST4                       (OTG_DMA_BASE+0x03C)     //  32bit dma EP DMA enable burst4 reg
+
+
+#define dma_num_dir(n, dir) (n * 2 + (dir ? 1 : 0))
+#define dma_num_out(n) dma_num_dir(n, USB_DIR_OUT)
+#define dma_num_in(n) dma_num_dir(n, USB_DIR_IN)
+
+#define OTG_DMA_ETD_MSA(x)                      (OTG_DMA_BASE+0x100+x*4)
+#define OTG_DMA_EPN_MSA(x)                      (OTG_DMA_BASE+0x180+x*4)
+#define OTG_DMA_ETDN_BPTR(x)                    (OTG_DMA_BASE+0x280+x*4)
+#define OTG_DMA_EPN_BPTR(x)                     (OTG_DMA_BASE+0x284+x*4)
+
+
+/*
+ * C.f. 23.14.10 I2C OTG Transceiver Controller Registers
+ * These are the ISP1301 shadow registers.
+ *
+ * See isp1301-hardware.h for register bit defines.
+ */
+#if 1
+#define MX2_VENDOR_ID_LOW                       OTG_I2C_BASE+0x00
+#define MX2_VENDOR_ID_HIGH                      OTG_I2C_BASE+0x01
+#define MX2_PRODUCT_ID_LOW                      OTG_I2C_BASE+0x02
+#define MX2_PRODUCT_ID_HIGH                     OTG_I2C_BASE+0x03
+
+#define MX2_MODE_CONTROL_1_SET                  OTG_I2C_BASE+0x04
+#define MX2_MODE_CONTROL_1_CLR                  OTG_I2C_BASE+0x05
+#define MX2_OTG_CONTROL_SET                     OTG_I2C_BASE+0x06
+#define MX2_OTG_CONTROL_CLR                     OTG_I2C_BASE+0x07
+
+#define MX2_INTERRUPT_SOURCE                    OTG_I2C_BASE+0x08
+
+#define MX2_INT_LAT_REG_SET                     OTG_I2C_BASE+0x0a
+#define MX2_INT_LAT_REG_CLR                     OTG_I2C_BASE+0x0b
+
+#define MX2_INT_FALSE_REG_SET                   OTG_I2C_BASE+0x0c
+#define MX2_INT_FALSE_REG_CLR                   OTG_I2C_BASE+0x0d
+#define MX2_INT_TRUE_REG_SET                    OTG_I2C_BASE+0x0e
+#define MX2_INT_TRUE_REG_CLR                    OTG_I2C_BASE+0x0f
+
+#define MX2_OTG_STATUS_REG                      OTG_I2C_BASE+0x10
+
+#define MX2_MODE_CONTROL_2_SET                  OTG_I2C_BASE+0x12
+#define MX2_MODE_CONTROL_2_CLR                  OTG_I2C_BASE+0x13
+
+#define MX2_BCD_DEV_LOW                         OTG_I2C_BASE+0x14
+#define MX2_BCD_DEV_HIGH                        OTG_I2C_BASE+0x15
+#endif
+
+/*
+ * C.f. 23.14.10 I2C OTG Transceiver Controller Registers
+ * These are the I2C controller and access registers.
+ *
+ * N.B. I2C_ERROR is not documented.
+ */
+
+
+#define I2C_BUSY                                (1 << 7)
+#define I2C_ERROR                               (1 << 2)
+#define I2C_HWSMODE                             (1 << 1)
+#define I2C_I2COE                               (1 << 0)
+
+#define I2C_SCLK_TO_SCL_DIVISION                (OTG_I2C_BASE+0x1E)
+
+#define I2C_INTERRUPT_AND_CONTROL               (OTG_I2C_BASE+0x1F)
+
+#define I2C_STATUS_MASK                         (0x7)
+
+#define I2C_NOACK_EN                            (1 << 6)
+#define I2C_RWREADY_EN                          (1 << 5)
+#define I2C_OTGXCVRINT_EN                       (1 << 4)
+
+#define I2C_NOACK                               (1 << 2)
+#define I2C_RWREADY                             (1 << 1)
+#define I2C_OTGXCVRINT                          (1 << 0)
+
+#define MX2_OTG_XCVR_DEVAD                      OTG_I2C_BASE+0x18
+#define MX2_SEQ_OP_REG                          OTG_I2C_BASE+0x19
+#define MX2_SEQ_RD_STARTAD                      OTG_I2C_BASE+0x1a
+#define MX2_I2C_OP_CTRL_REG                     OTG_I2C_BASE+0x1b
+#define MX2_SCLK_TO_SCL_HPER                    OTG_I2C_BASE+0x1e
+#define MX2_I2C_INTERRUPT_AND_CTRL              OTG_I2C_BASE+0x1f
+
+
+/* ********************************************************************************************** */
+
+/*! mx2_rb
+ */ 
+static u8 __inline__ mx2_rb(u32 port)
+{
+        return *(volatile u8 *) (IO_ADDRESS(port));
+}
+
+/*! mx2_rl
+ */
+static u32  __inline__ mx2_rl(u32 port)
+{       
+        return *(volatile u32 *) (IO_ADDRESS(port));
+}       
+        
+/*! mx2_wb
+ */
+static void __inline__ mx2_wb(u32 port, u8 val)
+{               
+        *(volatile u8 *)(IO_ADDRESS(port)) = val;
+}       
+
+/*! mx2_orb 
+ */     
+static void __inline__ mx2_orb(u32 port, u8 val)
+{       
+        u8 set =  mx2_rb(port) | val;                                   
+        *(volatile u8 *)(IO_ADDRESS(port)) = set;                   
+}       
+
+/*! mx2_andb 
+ */     
+static void __inline__ mx2_andb(u32 port, u8 val)
+{       
+        u8 set =  mx2_rb(port) & val;                                   
+        *(volatile u8 *)(IO_ADDRESS(port)) = set;                   
+}       
+
+/*! mx2_wl
+ */
+static void __inline__ mx2_wl(u32 port, u32 val) 
+{
+        u32 set;
+        *(volatile u32 *)(IO_ADDRESS(port)) = val;
+        set = mx2_rl(port);
+}       
+
+/*! mx2_orl
+ */
+static void __inline__ mx2_orl(u32 port, u32 val)
+{
+        u32 set = mx2_rl(port);
+        *(volatile u32 *)(IO_ADDRESS(port)) = (set | val);
+}
+
+/*! mx2_andl
+ */
+static void __inline__ mx2_andl(u32 port, u32 val)
+{
+        u32 set = mx2_rl(port);
+        *(volatile u32 *)(IO_ADDRESS(port)) = (set & val);
+}
+
+static u32 inline mx2_host_port_stat(int n)
+{
+        switch (n) {
+        default:
+        case 1:
+                return OTG_HOST_PORT_STATUS_1;
+        case 2:
+                return OTG_HOST_PORT_STATUS_2;
+        case 3:
+                return OTG_HOST_PORT_STATUS_3;
+        }
+}
+