Merge branch 'opendreambox' of /home/tmbinc/openembedded.git/ into opendreambox
authorAndreas Oberritter <obi@saftware.de>
Wed, 22 Oct 2008 15:07:03 +0000 (17:07 +0200)
committerAndreas Oberritter <obi@saftware.de>
Wed, 22 Oct 2008 15:07:03 +0000 (17:07 +0200)
122 files changed:
MAINTAINERS
classes/base.bbclass
classes/java-library.bbclass
classes/java.bbclass
classes/native.bbclass
conf/bitbake.conf
conf/checksums.ini
conf/machine/acern30.conf
conf/machine/amsdelta.conf
conf/machine/asus620.conf
conf/machine/asus730.conf
conf/machine/at91-l9260.conf
conf/machine/at91sam9260ek.conf
conf/machine/at91sam9261ek.conf
conf/machine/at91sam9263ek.conf
conf/machine/aximx50.conf
conf/machine/bd-neon.conf
conf/machine/beagleboard.conf
conf/machine/chumby.conf
conf/machine/cm-x270.conf
conf/machine/cs-e9302.conf
conf/machine/davinci-dvevm.conf
conf/machine/davinci-sffsdr.conf
conf/machine/devkitidp-pxa255.conf
conf/machine/em-x270.conf
conf/machine/ep93xx.conf
conf/machine/er0100.conf
conf/machine/eseries.conf
conf/machine/eteng500.conf
conf/machine/fsg3be.conf
conf/machine/gesbc-9302.conf
conf/machine/ghi270.conf
conf/machine/h1910.conf
conf/machine/h1940.conf
conf/machine/h2200.conf
conf/machine/h3900.conf
conf/machine/h4000.conf
conf/machine/h5000.conf
conf/machine/h6300.conf
conf/machine/htcalpine.conf
conf/machine/htcapache.conf
conf/machine/htcblueangel.conf
conf/machine/htchimalaya.conf
conf/machine/htckaiser.conf
conf/machine/hx4700.conf
conf/machine/include/motorola-ezx-base.inc
conf/machine/include/tune-arm1136jf-s.inc
conf/machine/include/tune-arm920t.inc
conf/machine/include/tune-arm926ejs.inc
conf/machine/include/tune-arm9tdmi.inc
conf/machine/include/tune-armv7.inc
conf/machine/include/tune-athlonmp.inc
conf/machine/include/tune-c3.inc
conf/machine/include/tune-cortexa8.inc
conf/machine/include/tune-ep9312.inc
conf/machine/include/tune-iwmmxt.inc
conf/machine/include/tune-pentium.inc
conf/machine/include/tune-pentiumpro.inc
conf/machine/include/tune-xscale.inc
conf/machine/include/zaurus-2.6.inc
conf/machine/neuros-osd.conf
conf/machine/neuros-osd2.conf
conf/machine/nokia770.conf
conf/machine/nokia800.conf
contrib/weekly-changelog-report.py [new file with mode: 0755]
packages/classpath/classpath-native.inc
packages/dsplink/dsplink.inc
packages/dsplink/dsplink_1.51.00.08.bb
packages/dsplink/dsplink_1.60.00.04.bb [new file with mode: 0644]
packages/dsplink/files/Makefile.dsplink [new file with mode: 0755]
packages/dsplink/files/c64xx_5.xx_linux.mk
packages/dsplink/ti-paths.inc
packages/enigma2/enigma2-plugins.bb
packages/enigma2/enigma2-streamproxy.bb
packages/enigma2/enigma2.bb
packages/enigma2/enigma2/tuxtxt_caching.patch
packages/fswebcam/fswebcam_20070108.bb [new file with mode: 0644]
packages/giflib/giflib_4.1.6.bb [new file with mode: 0644]
packages/gstreamer/gst-plugins-bad_0.10.8.bb [new file with mode: 0644]
packages/gstreamer/gst-plugins-base_0.10.20.bb [new file with mode: 0644]
packages/gstreamer/gst-plugins-good_0.10.10.bb [new file with mode: 0644]
packages/gstreamer/gst-plugins-ugly_0.10.9.bb [new file with mode: 0644]
packages/gstreamer/gst-plugins.inc
packages/gstreamer/gstreamer_0.10.20.bb [new file with mode: 0644]
packages/gtk+/gdk-pixbuf-csource-native_2.12.11.bb
packages/lesstif/files/000_bootstrap_script.diff [new file with mode: 0644]
packages/lesstif/files/000_libtool_linking.diff [new file with mode: 0644]
packages/lesstif/files/010_rebootstrap-small.diff [new file with mode: 0644]
packages/lesstif/files/020_bad_integer_cast.diff [new file with mode: 0644]
packages/lesstif/files/020_missing_xm_h.diff [new file with mode: 0644]
packages/lesstif/files/020_render_table_crash.diff [new file with mode: 0644]
packages/lesstif/files/020_unsigned_int.diff [new file with mode: 0644]
packages/lesstif/files/020_xpmpipethrough.diff [new file with mode: 0644]
packages/lesstif/files/021_xim_chained_list_crash.diff [new file with mode: 0644]
packages/lesstif/files/030_manpage.diff [new file with mode: 0644]
packages/lesstif/files/ac_debug.m4.diff [new file with mode: 0644]
packages/lesstif/files/ac_find_xft.m4.diff [new file with mode: 0644]
packages/lesstif/files/ac_have_libxp.m4.diff [new file with mode: 0644]
packages/lesstif/files/aclocal.m4.diff [new file with mode: 0644]
packages/lesstif/files/disable-docs.patch [new file with mode: 0644]
packages/lesstif/lesstif_0.95.0.bb [new file with mode: 0644]
packages/libffi/libffi_2.0+gcc4.3.2.bb [new file with mode: 0644]
packages/linux/linux-dm8000.bb
packages/linux/linux-dm8000/dm8000_defconfig
packages/linux/linux-omap2-git/beagleboard/defconfig
packages/linux/linux-rp-2.6.26/defconfig-collie
packages/linux/linux-rp-2.6.26/usb-gadget27bp.patch [new file with mode: 0644]
packages/linux/linux-rp_2.6.25+2.6.26-rc4.bb
packages/linux/linux-rp_2.6.26.bb
packages/mozilla/fennec_hg.bb
packages/python/python-2.5.2/autohell.patch
packages/python/python-2.5.2/fix_pthread_site.patch [new file with mode: 0644]
packages/python/python-2.5.2/forced_largefile_support.patch [new file with mode: 0644]
packages/python/python-2.5.2/some_configure_fixes.patch [new file with mode: 0644]
packages/python/python-2.5.2/strict_aliasing_site.patch [new file with mode: 0644]
packages/python/python_2.5.2.bb
packages/sysvinit/sysvinit_2.86.bb.orig [deleted file]
packages/unicap/unicap_0.9.3.bb
packages/xorg-driver/xf86-video-omapfb_git.bb
packages/xorg-xserver/xserver-kdrive-1.4.0.90/xorg-1.4-kdrive-rotation.patch [new file with mode: 0644]
packages/xorg-xserver/xserver-kdrive_1.4.0.90.bb
site/mipsel-linux

index 8d86392..3e271f6 100644 (file)
@@ -213,6 +213,13 @@ Machines:   akita
 Recipes:    aircrack-ng, kismet, lorcon, mdk, rfakeap, rglueap, 
 Recipes:    rt2570-k2wrlz, void11
 
+Person:     Rodrigo 'vivijim' Vivi
+Mail:       rodrigo.vivi@openbossa.org
+Website:    http://blog.vivi.eng.br
+Interests:  Embedded Linux, Mamona, Nokia Tablets, Emulation
+Distros:    mamona
+Recipes:    bash-noemu, binutils-noemu, gcc-noemu, mamona-sound, usbnet
+
 Person:            Rolf 'Laibsch' Leggewie
 Mail:       OE-recipes@rolf.leggewie.biz
 Website:    http://oz.leggewie.org
index b50bc86..93a76aa 100644 (file)
@@ -157,6 +157,23 @@ def base_both_contain(variable1, variable2, checkvalue, d):
 
 DEPENDS_prepend="${@base_dep_prepend(d)} "
 
+# Returns PN with various suffixes removed
+# or PN if no matching suffix was found.
+def base_package_name(d):
+  import bb;
+
+  pn = bb.data.getVar('PN', d, 1)
+  if pn.endswith("-native"):
+               pn = pn[0:-7]
+  elif pn.endswith("-cross"):
+               pn = pn[0:-6]
+  elif pn.endswith("-initial"):
+               pn = pn[0:-8]
+  elif pn.endswith("-intermediate"):
+               pn = pn[0:-13]
+
+  return pn
+
 def base_set_filespath(path, d):
        import os, bb
        filespath = []
@@ -167,7 +184,7 @@ def base_set_filespath(path, d):
                        filespath.append(os.path.join(p, o))
        return ":".join(filespath)
 
-FILESPATH = "${@base_set_filespath([ "${FILE_DIRNAME}/${PF}", "${FILE_DIRNAME}/${P}", "${FILE_DIRNAME}/${PN}", "${FILE_DIRNAME}/files", "${FILE_DIRNAME}" ], d)}"
+FILESPATH = "${@base_set_filespath([ "${FILE_DIRNAME}/${PF}", "${FILE_DIRNAME}/${P}", "${FILE_DIRNAME}/${PN}", "${FILE_DIRNAME}/${BP}", "${FILE_DIRNAME}/${BPN}", "${FILE_DIRNAME}/files", "${FILE_DIRNAME}" ], d)}"
 
 def oe_filter(f, str, d):
        from re import match
index eced939..06c3170 100644 (file)
@@ -10,6 +10,9 @@
 
 inherit java
 
+# use java_stage for native packages
+JAVA_NATIVE_STAGE_INSTALL = "1"
+
 def java_package_name(d):
   import bb;
 
@@ -25,18 +28,6 @@ def java_package_name(d):
 
   return pre + pn + post
 
-def java_base_package_name(d):
-  import bb;
-
-  pre=""
-  post=""
-
-  pn = bb.data.getVar('PN', d, 1)
-  if pn.endswith("-native"):
-               pn = pn[0:-7]
-
-  return pn
-
 JPN ?= "${@java_package_name(d)}"
 
 DEPENDS_prepend = "virtual/javac-native fastjar-native "
@@ -47,12 +38,6 @@ PACKAGE_ARCH_${JPN} = "all"
 
 FILES_${JPN} = "${datadir_java}"
 
-# Base package name
-# Automatically derives "foo" from "foo-native"
-BPN ?= ""${@java_base_package_name(d)}""
-
-BP ?= "${BPN}-${PV}"
-
 # File name of the libraries' main Jar file
 JARFILENAME = "${BP}.jar"
 
index 32415d5..7b67bcd 100644 (file)
@@ -84,32 +84,32 @@ oe_makeclasspath() {
   #
   # oe_makeclasspath cp foo baz bar
   # Stores ${datadir_java}/foo.jar:${datadir_java}/baz.jar:${datadir_java}/bar.jar
-       # in variable "cp".
+  # in variable "cp".
   #
   # oe_makeclasspath bootcp -s foo baz bar
   # Stores ${STAGING_DATADIR_JAVA}/foo.jar:${STAGING_DATADIR_JAVA}/baz.jar:${STAGING_DATADIR_JAVA}/bar.jar
-       # in variable "bootcp".
-       
+  # in variable "bootcp".
+  # 
   # Provide the -s at the beginning otherwise strange things happen.
-       # If -s is given the function checks whether the requested jar file exists
-       #       and exits with an error message if it cannot be found.
-       #
+  # If -s is given the function checks whether the requested jar file exists
+  #    and exits with an error message if it cannot be found.
+  #
   dir=${datadir_java}
-       classpath=
-       delimiter=
-       retval=$1
+  classpath=
+  delimiter=
+  retval=$1
 
-       shift
+  shift
 
   while [ "$#" -gt 0 ]; do
     case "$1" in
     -s)
-                       # take jar files from native staging if this is a -native recipe
-                       if [ ${PACKAGE_ARCH} = ${BUILD_ARCH} ]; then
+               # take jar files from native staging if this is a -native recipe
+               if [ ${PACKAGE_ARCH} = ${BUILD_ARCH} ]; then
              dir=${STAGING_DATADIR_JAVA_NATIVE}
-                       else
+               else
              dir=${STAGING_DATADIR_JAVA}
-                       fi
+               fi
       ;;
     -*)
       oefatal "oe_makeclasspath: unknown option: $1"
@@ -117,9 +117,9 @@ oe_makeclasspath() {
     *)
       file=$dir/$1.jar
 
-                       if [ -z "$dir" -a ! -f $file ]; then
-                               oefatal "oe_makeclasspath: Jar file for '$1' not found at $file"
-                       fi
+         if [ -z "$dir" -a ! -f $file ]; then
+           oefatal "oe_makeclasspath: Jar file for '$1' not found at $file"
+         fi
 
       classpath=$classpath$delimiter$file
       delimiter=":"
@@ -128,7 +128,7 @@ oe_makeclasspath() {
     shift
   done
 
-       eval $retval="$classpath"
+  eval $retval="$classpath"
 }
 
 # Creates a simple wrapper script for your Java program.
index 8f79935..61048b6 100644 (file)
@@ -80,11 +80,14 @@ export oldincludedir = "${STAGING_DIR_NATIVE}${layout_includedir}"
 do_stage () {
        if [ "${INHIBIT_NATIVE_STAGE_INSTALL}" != "1" ]
        then
-               if [ "${AUTOTOOLS_NATIVE_STAGE_INSTALL}" != "1" ]
+               if [ "${JAVA_NATIVE_STAGE_INSTALL}" = "1" ]
+               then
+                       java_stage
+               elif [ "${AUTOTOOLS_NATIVE_STAGE_INSTALL}" = "1" ]
                then
-                       oe_runmake install
-               else
                        autotools_stage_all
+               else
+                       oe_runmake install
                fi
        fi
 }
index 071c1ef..93064b0 100644 (file)
@@ -143,10 +143,11 @@ EXTENDPEVER = "${@['','${PE\x7d:'][bb.data.getVar('PE',d,1) > 0]}"
 DEBPV = "${EXTENDPEVER}${PV}-${PR}"
 P = "${PN}-${PV}"
 
-##################################################################
-# Distro default 
-##################################################################
-DISTRO_PR ?= ""
+# Base package name
+# Automatically derives "foo" from "foo-native", "foo-cross" or "foo-initial"
+# otherwise it is the same as PN and P
+BPN = "${@base_package_name(d)}"
+BP = "${BPN}-${PV}"
 
 # Package info.
 
@@ -217,7 +218,7 @@ FILES_${PN}-locale = "${datadir}/locale"
 export MANIFEST = "${FILESDIR}/manifest"
 
 FILE_DIRNAME = "${@os.path.dirname(bb.data.getVar('FILE', d))}"
-FILESPATH = "${FILE_DIRNAME}/${PF}:${FILE_DIRNAME}/${P}:${FILE_DIRNAME}/${PN}:${FILE_DIRNAME}/files:${FILE_DIRNAME}"
+FILESPATH = "${FILE_DIRNAME}/${PF}:${FILE_DIRNAME}/${P}:${FILE_DIRNAME}/${PN}:${FILE_DIRNAME}/${BP}:${FILE_DIRNAME}/${BPN}:${FILE_DIRNAME}/files:${FILE_DIRNAME}"
 FILESDIR = "${@bb.which(bb.data.getVar('FILESPATH', d, 1), '.')}"
 
 ##################################################################
@@ -237,7 +238,7 @@ STAMP = "${TMPDIR}/stamps/${MULTIMACH_TARGET_SYS}/${PF}"
 WORKDIR = "${TMPDIR}/work/${MULTIMACH_TARGET_SYS}/${PF}"
 T = "${WORKDIR}/temp"
 D = "${WORKDIR}/image"
-S = "${WORKDIR}/${P}"
+S = "${WORKDIR}/${BP}"
 B = "${S}"
 
 STAGING_DIR = "${TMPDIR}/staging"
index c040acf..27d201e 100644 (file)
@@ -34,6 +34,10 @@ sha256=f09d4ae3365b876da9f40f49178ab7241bb7e4c1d67db9e2f310f9c76d5834a6
 md5=333b0e9328194f28af83c26d3717e4ac
 sha256=8930ebfdc8a606d8cb26f073d4700460c3289fb79e943e12948329e17336ca47
 
+[http://www.ralinktech.com.tw/data/drivers/2008_0506_RT73_Linux_STA_Drv1.1.0.1.tar.bz2]
+md5=3e08bf734b740e83391fda571c8e9ecd
+sha256=932b9c127992fd7985e4054d91120164e54f7132fa457b06fdcd30307e5b70f9
+
 [http://www.amd.com/files/connectivitysolutions/geode/geode_lx/AES_Linux_LX_02.01.0100.tar.gz]
 md5=12cb241a9037fffe31ba7c68a48ed614
 sha256=a6068b4aa0e2330eed6e4741bad3191dc9ca7d7326f7bfab578ac55e2b8b91a2
@@ -638,6 +642,10 @@ sha256=f274a4bc969ae192994a856b7f786c6fce96bae77f96c1c2b71dd97599e06e43
 md5=4be042a043ec520074b0ab6f7ca0bded
 sha256=fa668e8f01fe43fdddb33f0c5e294698818f37519000b9f782f504ece071c740
 
+[http://www.reactivated.net/software/zd1211-vendor/releases/ZD1211LnxDrv_2_22_0_0.tar.gz]
+md5=0ac1145f1f30d883694b4a1317f142c4
+sha256=262f44f0d1274d2baf6548e53df96c6664b076f39e3aaeeb022bbd5caccbe3e3
+
 [http://zope.org/Products/Zope/2.7.1/Zope-2.7.1.tgz]
 md5=ae9d4bb3f7220dfffb6e91b42503b16c
 sha256=341f56aa4ece9001a118be8ff9675bfad6410dc1df86dd86aeb726adc732341b
@@ -1114,6 +1122,10 @@ sha256=2bbf2b8fdf6e12dabb0cc751a973d9040f7ed9123cf87a7f794044f3429b0de0
 md5=3b27365772d918050b2251d98a9c7c82
 sha256=9c548c44d3cfdf259118d9fd4e468e1fe4567456dbff8ff59838c5f70ef62ea3
 
+[http://sources.dreamboxupdate.com/download/snapshots/ath_hal-20080815.tgz]
+md5=f88c708bbc6ce971f170499110098604
+sha256=eb1dd7529fccb17c59f4ae027d5c4d60dfe89e399a97be72b378e2ba646cd54d
+
 [ftp://ftp.gtk.org/pub/gtk/v2.8/atk-1.10.3.tar.bz2]
 md5=c84a01fea567b365c0d44b227fead948
 sha256=c596baf95f6a6cd7748b1018336b2ac45ca2ef668816e6c703b01691e09b8a89
@@ -1274,6 +1286,10 @@ sha256=dedf5325105f071e5d9f898fdb7337a7fe88a3a8a1f832a6056ba00477b8cc3d
 md5=3cb3be404950ef08e51adbe59c7b811e
 sha256=c3648f02dd7d4dc8c0ef9a48089fda4ca47b81a977c838b17f55e6abf7f51447
 
+[http://sources.dreamboxupdate.com/download/7020/backdrop_dm8000.mvi]
+md5=404ecdfe1f291ef64079c463fe699ac2
+sha256=bd486f5434eaa7fd5f39fb67c8dc0394e2d08c2505419c72c5a5a563463658fd
+
 [http://heanet.dl.sourceforge.net/sourceforge/bacula/bacula-1.38.11.tar.gz]
 md5=0d6d6614afdc468d214de4e66f9f5a26
 sha256=d095165d256771c918b80f836feaf837aedc1362b2d67171013d3ab7ac5ee47f
@@ -1834,6 +1850,22 @@ sha256=e721987d891ce97ba7a4fc17115a1b48d7659b261d12e886b614999ab12246d2
 md5=4be91177d19069e21beeb106f2f77dff
 sha256=7738399ecfcfb2242e9f99a316b13a5f59e89052de05074dbf705ccf4edc327d
 
+[http://sources.dreamboxupdate.com/download/7020/bootlogo_dm8000.elf]
+md5=8ab6ead17f2d51e9b93f968b027cb3a9
+sha256=d5b517b85c2d346cacaef3fd1833f4aaccf9ba37785fcca94a3bd33563c040c8
+
+[http://sources.dreamboxupdate.com/download/7020/bootlogo_dm8000.jpg]
+md5=017abc2244931c14464ae6d4ad8c2296
+sha256=5f8ea9e76a10c28282425cb1fccbcfd5897da1e83adeaa9d89744c3597f49f02
+
+[http://sources.dreamboxupdate.com/download/7020/bootlogo_dm8000.mvi]
+md5=c1a99cb9ab8248faaf273cd5d9f16cfd
+sha256=0c02c791020c5d230fafc226f2282f42434a0b4db66e6aa7eda56f23cec01578
+
+[http://sources.dreamboxupdate.com/download/7020/bootlogo_wait_dm8000.mvi]
+md5=4c3eba94a7092c8ad9adeaa90ed40673
+sha256=b8057f51a1317294e4feab663ded9652491bcfbaaaf7e141f06129452ad36e6d
+
 [http://www.cosmicpenguin.net/pub/bootmenu/bootmenu-0.6.tar.gz]
 md5=d7d8343f90a149c1604e5a14ea2f967d
 sha256=3ff618bcbf9926f356aec2a604b1f1d617e3f87ad545b1d96c066ed712675845
@@ -2046,6 +2078,10 @@ sha256=7f0ce28c358706913bc39e6930a18ae89f3b9a6aa17998faa2b59d1e0e2b4f42
 md5=c612f581b18903b0751a171685fc38dd
 sha256=5268faa116a48a68dd74abb245b26b20f1729d3bd56a8414e429904eb1bae124
 
+[http://cairographics.org/releases/cairomm-1.2.4.tar.gz]
+md5=5d862facfbd0098c9bae618b61f7c8e6
+sha256=a137ccd4a6cde6c9e9553966534702d2e7f6f44c755dfe128d9fb26ed2697fe7
+
 [http://gpephone.linuxtogo.org/download/gpephone/calendar-1.0/calendar-1.0.tar.gz]
 md5=eb7be3b85955a1bbe7a0154cbf2f70f9
 sha256=7e6425b688a2d4bbeef0904cac52737b232d03fdc4d35866fd03359f2d5f1794
@@ -2718,6 +2754,10 @@ sha256=e34e30a4c0ea405f9e830aa0026e9c0632f526f242e90526ff0a7da8dd7f5e2e
 md5=562c78876219bf458d79a041af18293d
 sha256=89dd1d5aa5c2ba04677d1aa2616caa50274d8c08f3d6bc164e6f7b9930776191
 
+[http://sources.dreamboxupdate.com/download/7020/dccamd-dm8000-1.1]
+md5=d0439fec02ef37e4896d65c1605f3982
+sha256=b2457ff8d8355baa8dfb2a1ed30847668af6fdf16bcfc1bf89a3b0e672e4ef02
+
 [http://packetstormsecurity.org/UNIX/scanners/dcetest-2.0.tar.gz]
 md5=74ee7617c8b01cc641992c1d13dc394b
 sha256=4a319a08ae0838234f5b6fbd0b4d2e0fac7560a7553a4e1b043527cc17032aa3
@@ -3006,6 +3046,18 @@ sha256=a525f321e875a8c16f5b6942bc02ac66b0d284cc6c61704f93e74789ef89d817
 md5=dad1a4a08c475b31a6b62e7dc92fe9d2
 sha256=5287e943265b9efe5bd59cd1f3145d3fbf9e266df28938ad78e2107fde3c1587
 
+[http://sources.dreamboxupdate.com/download/opendreambox/dreambox-blindscan-utils-dm8000-1.0.tar.bz2]
+md5=4e540e321fb76df423fc166ddfd83773
+sha256=167494f7617d2f8d8c25d9dab7a4ab5ec26b91bbe06413365f31ddedabc3bed6
+
+[http://sources.dreamboxupdate.com/snapshots/dreambox-dvb-modules-dm8000-2.6.12-5.1-brcmstb-dm8000-20080920.tar.bz2]
+md5=a508ee35044989c41e7f49664496cedf
+sha256=47e7132ed5ec55bbaec2348cd5b61cc610a762a247cb4d3aebc9e47ff19fc9be
+
+[http://sources.dreamboxupdate.com/download/opendreambox/dreambox-dvb-tools-v3-1.5.tar.gz]
+md5=da705f04302e87c7b4e83903ce4b5707
+sha256=d2005e7b8ea9d8d8b4503117daf18a642bbabd0e013d41302c5f80e3333c67ef
+
 [http://xorg.freedesktop.org/releases/individual/proto/dri2proto-1.1.tar.bz2]
 md5=1d70f0653b0b3a837853262dc5d34da4
 sha256=69def6d1f64b3699ec9c729596d8b096623a62bdda6bbea78ed690421d174c11
@@ -3054,6 +3106,10 @@ sha256=677a8cd27d05b1401ddef152270a498fc4d34cb9ba94779c571f2f2794b20811
 md5=a2d7803976f82db3edeb374109cba6df
 sha256=8ae0026054fb9f437d59a3bb932628fc2915af6697e430325e0950e960ca6c34
 
+[http://install.tarball.in.source.dir/dsplink_1_60_00_04.tar.gz]
+md5=2b53c067c683266379dddbb38e65cb45
+sha256=b1a0508444241c61585321eaadc32f476ef441f267636fbd0fb2f0c7ebf0fcbb
+
 [http://www.jdl.com/pub/software/dtc-20070216.tgz]
 md5=8762121262ead127171c4fce40ccc289
 sha256=dd687b4f691bf9970f53ca2c84d8481b9f82d857de347375d29bacf648b8da71
@@ -3218,6 +3274,10 @@ sha256=c493b9a22c9580d49fd90d2bb6955435ccba9304ecb382411864041d914c94d6
 md5=74c7255a56ffa8e37147a1a0cfe40565
 sha256=51eab13f16c48433035e84b8eb6c66afbbf3e48199323d25f4f9a09c8047d078
 
+[http://ftp.gnome.org/pub/GNOME/sources/empathy/2.24/empathy-2.24.0.tar.bz2]
+md5=89e6dc430ad198c8044f261645d8bc6c
+sha256=5e73cfe9bbe862391386b4d60776a22fc765c48fe9f2bfad17ebd691571da2b9
+
 [http://download.berlios.de/emul/emul-1.0.5.tar.gz]
 md5=f713b4d3c6a733b429de2673e4427483
 sha256=b91c7fb6420f6787d34b88b1e0d2e705e1006b5bce17235356f84a3c14329612
@@ -3462,6 +3522,10 @@ sha256=990cd830ea362ba2cb88ca7b59cd3f4d115a054621450b5cf211cadebed23ee0
 md5=55220ebadef5f541d705b72fe222b5b1
 sha256=4b891e1d58c8cdf397737ac81a9328d8c663743b41f835bb2267831866d75a3e
 
+[http://sources.dreamboxupdate.com/download/opendreambox/fakelocale.tar.gz]
+md5=d11a901c9e4dc2947cbc560044de2b67
+sha256=b424804aff7a23efaa1fa25d27a55ac25173d0e7e95d07fe31096250bb498cc6
+
 [http://openzaurus.org/mirror/fakeroot_1.2.13.tar.gz]
 md5=cf25d5d4c943ebf2293fe6f23ecba0fd
 sha256=6f51ebdf0e18bea58d18f79e8ffebb797fe57bdf44b96dff9d84b70467af7841
@@ -3978,6 +4042,10 @@ sha256=bcf668c1123f4d73a4c503ff189446cf4b30d64466fea49628999cdce8661c67
 md5=5eaf8e8d1978ca4bbead5b3f163b23a1
 sha256=b8e60157a14739da9382e23e296a0236b0c246b486b4803a1baaa4a73c5bf8d9
 
+[http://downloads.sourceforge.net/free42/free42.tgz]
+md5=1fc21e04b3b77150846027dc7cb5210d
+sha256=9d348a9d2d5bf8eabc7e7bb6f0907e611403e4abe6dc1e11b1b2ad1118b3088a
+
 [ftp://ftp.freeciv.org/freeciv/stable/freeciv-1.14.1.tar.bz2]
 md5=d328f65e7fca5252f27161f5f9e97a03
 sha256=8a963570e5c4ea432b0e31d77d3605705bda91a9f97ff377c5c3204ca768e342
@@ -4410,6 +4478,10 @@ sha256=176611c4d88d742ea4013991ad54c2f9d2feefbc97a28434c0f48922ebaa8bac
 md5=85bb8ee345fc41c218de19dda0164806
 sha256=90825b05b675890bd405767a973d3c8c90eae36d22a7be6307e07a2e3c760d89
 
+[http://downloads.sourceforge.net/giflib/giflib-4.1.6.tar.bz2]
+md5=7125644155ae6ad33dbc9fc15a14735f
+sha256=e1c1ced9c5bc8f93ef0faf0a8c7717abf784d10a7b270d2285e8e1f3b93f2bed
+
 [http://downloads.sourceforge.net/gift/gift-0.11.4.tar.bz2]
 md5=decc82159c6723be999b1306a808077f
 sha256=68149059b807b2fac505e376c18320e64104fbe0190e359f98059e73a63693dc
@@ -4686,6 +4758,10 @@ sha256=d094028bc6d6691f56b4efeff7cd7e1c7ca10733e0cb5efc36e8fb08d8324bf1
 md5=eaeb8527b8fa286c2d887157214f9998
 sha256=3e481996259af87c3581da23481970a27de679e3c87cfa9a5a59751cd20c7b44
 
+[ftp://ftp.gnome.org/pub/GNOME/sources/glibmm/2.18/glibmm-2.18.0.tar.bz2]
+md5=1a0df362e15e7f850b8361b5102f1f16
+sha256=ca6c46b87748cabd61e7d5ef892f09f433eaea324e63637f7de1f0217465cd31
+
 [ftp://ftp.gnome.org/pub/GNOME/sources/glibmm/2.8/glibmm-2.8.4.tar.bz2]
 md5=952cdde2d6aef201c528d431036d71e1
 sha256=7ff592b6687caefa367b33d8cb8f66f3c0273fa86d4b688c0758d0d9fee7a2cb
@@ -4914,6 +4990,10 @@ sha256=78f7dc6946e178513202f06afc19496c8ac1e3ac6c43c56c40f4db1a23762179
 md5=d8f8e61d99402e8b0a82d3c8d6e873be
 sha256=7ad66f99a1bad1ae0bbb02bd7a7cf8ed17fdc3fd104fa5c68e04961459ad5c50
 
+[http://ftp.gnome.org/pub/GNOME/sources/gnome-system-monitor/2.24/gnome-system-monitor-2.24.0.tar.bz2]
+md5=edd7f02e30683054b94a89aa62c74d1e
+sha256=cf2f96f3c91749fdcec39d3eb89273f6d3a47cc7bc0c5faa0915808409c9d563
+
 [http://ftp.gnome.org/pub/GNOME/sources/gnome-themes/2.6/gnome-themes-2.6.2.tar.bz2]
 md5=4aae39232d77e1497f3180202b501adf
 sha256=471191e942fdd1d691095c71fb22c0a645b3644c3b2b1c58a6d6f1a2435fb818
@@ -6286,6 +6366,10 @@ sha256=4b104ab94774ca429aa639a1a6f0adec1ca1443bfd444f2100c063e3cf70e6bb
 md5=b53564e553728d4b69f7d366dfeb5299
 sha256=1dc30175da6a3c560a7d62d1abe1c2f9829d988e6f1a7c5e766544575c558c43
 
+[http://ftp.gnome.org/pub/GNOME/sources/gtkmm/2.14/gtkmm-2.14.1.tar.bz2]
+md5=0209b424987a74c956ea6b70fddaaa37
+sha256=f8675340d929346333b5a58cd4d05482dd8b76cf8606fed85b526022bf9c5e47
+
 [http://ftp.gnome.org/pub/GNOME/sources/gtkmm/2.4/gtkmm-2.4.8.tar.bz2]
 md5=c2aee4c259a75fa0dc766d402bef253b
 sha256=218420f1c091846fa5f860e5f12c57650d8719f6cf9b922e7c6a69e0505aac32
@@ -6390,6 +6474,14 @@ sha256=ba261a21539e1f204ba74590d313c501007e546b54aa9ae7210a99eaf3c097be
 md5=9e6a16b7d074782d1c62f1f7316e56ab
 sha256=e2db8d3383cd8eca6a18ebee85875de895f3ac7414eab091a87f052d79a87b09
 
+[http://www.guzu.net/files/hddtemp-0.3-beta15.tar.bz2]
+md5=8b829339e1ae9df701684ec239021bb8
+sha256=618541584054093d53be8a2d9e81c97174f30f00af91cb8700a97e442d79ef5b
+
+[http://www.guzu.net/linux/hddtemp.db]
+md5=7b2651d53d10808e270bc386b6db89dd
+sha256=ca43f8ab1e4fb3919af940a2fe6a95feb03939f685450a48666763a3edc326bb
+
 [http://downloads.sourceforge.net/hdparm/hdparm-6.3.tar.gz]
 md5=0c12672f3a09c14ad0b0882f15fc9389
 sha256=08688a6a46ba495494bf838f8f26103e797584c1888eca94e43a171e1b37246d
@@ -6838,6 +6930,10 @@ sha256=beb929f4ceff865375a9e56c0156ffbfb197dff82299071bdb641bb60299f84b
 md5=5bcaa0fe3fec26840c8f1ecefc891887
 sha256=53b67c08477623bb03436f79bf2ca859d7cd9684c57775ea539e1db449658236
 
+[http://sources.dreamboxupdate.com/snapshots/include2.tar.gz]
+md5=9d236095a88d7ce9f3bf0503ee5237d6
+sha256=739bc35bccdb1e4c6e14b77ab86808354eb6fd75434d3bd6236f3b3346805e02
+
 [ftp://ftp.gnu.org/gnu/inetutils/inetutils-1.4.2.tar.gz]
 md5=df0909a586ddac2b7a0d62795eea4206
 sha256=9f001daa0f3d571ae35aac88f04d5dd982a14e90257e4dfb535c143fa18d5830
@@ -7426,6 +7522,10 @@ sha256=f532fcd61b012379d3258196a8588fd9d51ecdfb5c795485ab2f78d439b103b4
 md5=b6d7ca9e9740286f0ce918da9fb8438b
 sha256=0ee6a3caee4812827b8e167d4a07dbf859cb08a00a20f09568c3baae379d6ce8
 
+[http://downloads.sourceforge.net/lesstif/lesstif-0.95.0.tar.bz2]
+md5=ab895165c149d7f95843c7584b1c7ad4
+sha256=2a6f20d3bd525e6066ba2be22d8a47bf4bcd0425
+
 [ftp://ftp.wiretapped.net/pub/mirrors/lftp/old/lftp-3.5.1.tar.bz2]
 md5=c6d48782cdad4759000bf7cd24555723
 sha256=463f0b46ce3a0fc09ef9ad7a5429959034d50a1eadbed5dfeae36c25dca31130
@@ -9270,6 +9370,10 @@ sha256=83e82b9afe296584a6c9f1f8b3e3a70d324209021e0049f68d28bd1de8c18136
 md5=4f75fc9901c724b712c371c9a1e782d3
 sha256=912a1fdb12d31af757e7881db49321e5b5240bd8bd4199e9fb0ce16d66568160
 
+[http://critical.ch/distfiles/libsidplay-1.36.59.tgz]
+md5=37c51ba4bd57164b1b0bb7b43b9adece
+sha256=3da9b38d4eb5bf9e936b9604ba92da0594ef38047d50cf806a8e11c400008024
+
 [http://www.geocities.com/SiliconValley/Lakes/5147/sidplay/packages/libsidplay-1.36.59.tgz]
 md5=37c51ba4bd57164b1b0bb7b43b9adece
 sha256=3da9b38d4eb5bf9e936b9604ba92da0594ef38047d50cf806a8e11c400008024
@@ -9678,6 +9782,10 @@ sha256=06e4be5214166e1de11715c8b58c61d1a1930df1b6bea035ee6b6a227054ae5b
 md5=dc43ff7ae6aded45f578c87b7b0c8766
 sha256=c01bd621f771cdee349877f55cc841a1bdfb206b2cf5c9aa62aa6a9680e61980
 
+[http://www.ant.uni-bremen.de/whomes/rinas/libxmlccwrap/download/libxmlccwrap-0.0.12.tar.gz]
+md5=9f8bbad3452d704603246273b2dda758
+sha256=38fb5f75f8b7dad1c8d535cc7b18ea9f1603e14a8b9256a2f60cf721513dc299
+
 [http://gpe.linuxtogo.org/download/source/libxsettings-0.11.tar.gz]
 md5=ea623deae839c41ef68c9a31233157ef
 sha256=4cae17ea07445660cedb34a8a0222055954ed67de3d5a527850d8b9e923e3543
@@ -9782,6 +9890,26 @@ sha256=877af8ed89e56af004bb0662c1a9cfc785b40c602f71a8bf81521991026cf2f0
 md5=f00fd1b5a80f52baf9d1d83acddfa325
 sha256=1fa39c202efe168bfeb0ddd74c8e4814f77da7dc78993e47826bad9173b95808
 
+[http://sources.dreamboxupdate.com/download/kernel-patches/linux-2.6.12-add-ioprio.patch.bz2]
+md5=9af26454c10261c099865fa8008e898f
+sha256=af680b4c40128e1e63bb7bff7a67ff813bc4741a0c8a95ddfb13ed9b9ed4782b
+
+[http://sources.dreamboxupdate.com/download/kernel-patches/linux-2.6.12-brcm-5.1.patch.bz2]
+md5=dd3c40f0f02153efa817808a0a2f687e
+sha256=c609eb3c63de0cd63f54607e744f04f267f069ba5eeabff294c769e857bcf3bb
+
+[http://sources.dreamboxupdate.com/download/kernel-patches/linux-2.6.12-dvb-core-fix-several-locking-problems.patch.bz2]
+md5=c395c813ec87b603169f56d9b9dc84d8
+sha256=8b8172b65e9032935f49f38984a76aea4eb4dba4a3c5c7bb441172cc9d4a1331
+
+[http://sources.dreamboxupdate.com/download/kernel-patches/linux-2.6.12-dvb-multipid-r4.patch.bz2]
+md5=7b3a8555190f7e6370459b058f4a3bb6
+sha256=17d706ec6f16ecaa135bb6bb81ad14f9757f2835099a19f74ab676f23026b217
+
+[http://sources.dreamboxupdate.com/download/kernel-patches/linux-2.6.12-dvbapi-pilot-rolloff-extension-r0.patch.bz2]
+md5=d93c88a6ef7ca15eb46d9767563eaae4
+sha256=b79086627a13f84c2a38eeb8039045d4577fb2c851faff7f8509acbf6b835773
+
 [http://kernel.org/pub/linux/kernel/v2.6/testing/linux-2.6.12-rc2.tar.bz2]
 md5=b8b75ddeca0f48221f085703f2f72692
 sha256=2e36150665e7268d5dd03b70621a0e80c4f7abb04584694dba540774030f6a54
@@ -9790,6 +9918,14 @@ sha256=2e36150665e7268d5dd03b70621a0e80c4f7abb04584694dba540774030f6a54
 md5=0f9afd619a10872b3383362d55c892c3
 sha256=4cc5ca6e2ea8583f026620169e5d6eceb6c620181ba0633efbeb74cdb8c2fc59
 
+[http://sources.dreamboxupdate.com/download/kernel-patches/linux-2.6.12-update-wireless.patch.bz2]
+md5=8f39722809d9e10698d691372ac69dab
+sha256=326aba0a5d7c41496a88cc9855e842e49b0d8153c66eeb39d6b15b3afd165a86
+
+[http://sources.dreamboxupdate.com/download/kernel-patches/linux-2.6.12-update_dvbapi-r1.patch.bz2]
+md5=0d3899252651474f91aebba1b760acb5
+sha256=8a3047b7c9dfcb84735e9eaed0ea3fc6e028bb3d8ed82756a8ce2b0d3bd18e46
+
 [http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.12.6.tar.bz2]
 md5=1592bb2a8ec0deb1ff32e8238f25ecc5
 sha256=d8bbdd8064c3564e6ec74fec3332776733e7982e67af66c5311fd1955bf309dd
@@ -10302,6 +10438,10 @@ sha256=46a30f2cd62c66099d4b87a32fb82751598758c213a1486ec7f44c23a33f5529
 md5=fe1758398de89fce57f05f9c1d1bb923
 sha256=70cfa5eacd27d46a5e6f562b01769c64794d20ce4636cf133def7db7f0715efb
 
+[http://www.angstrom-distribution.org/unstable/sources/madwifi-ng-r3314-20080131.tar.gz]
+md5=2c7352cbbdac995de8c3bce5b80db5f2
+sha256=0599c75b95ba63bdc554cb8124192e62c75fbeb71b9e8a5a7bc351c8e0666758
+
 [http://snapshots.madwifi.org/madwifi-trunk/madwifi-trunk-r3837-20080802.tar.gz]
 md5=d6e04fa7fb0bea5079f24a753633fb29
 sha256=d504e1e7b8f0d01b5441a86d1086aa4088c8896d87d8aabd6dabace76997467a
@@ -10970,6 +11110,10 @@ sha256=db0c299592b8f1f704f41bd3fc3a2bf138658108588d51af61638c551af1b0d4
 md5=d605b6068b6c9aa2bc7550f49c60958c
 sha256=7e5e1768db0201981f90256fa94db3f09f23285ffd60dc60a51a753825084848
 
+[ftp://archive.debian.org/debian-archive/pool/non-free/m/mrouted/mrouted_3.9-beta3.orig.tar.gz]
+md5=96067b571622ac232dab42a5c56dcedc
+sha256=8d38a1feadf9298dd554b352fd6cc247207c930ef0c7df736deb5b44e5c58fb6
+
 [http://downloads.sourceforge.net/materm/mrxvt-0.5.2.tar.gz]
 md5=ed87b7dd9f4fb482de0f14f085085027
 sha256=558491d1f112362780abaf7429d14216e658b7768dd30f82f102ce646d3065cf
@@ -11162,6 +11306,10 @@ sha256=76472e51576b42bfc129e487ae7dd3a5e1f1f380105b422fc14ee408e3a881df
 md5=516c576c0ca5c0a01ad24d018093cfee
 sha256=8a29457052b73ac0139e3b2824a74323256dd7631b1691239ddb18124e231a71
 
+[http://www.webdav.org/neon/neon-0.28.2.tar.gz]
+md5=b99b3f44e8507ae2d17362f1b34aaf02
+sha256=d9cd601613db6affb25655e0908b0bf8c266669cef31999b6b4121d585ff9094
+
 [http://downloads.sourceforge.net/net-snmp/net-snmp-5.1.2.tar.gz]
 md5=8080555ab3f90011f25d5122042d9a8d
 sha256=1fca69e934c3d526e308450cc5af2478d440e012922dd0bb10388fcf093ef32e
@@ -11518,6 +11666,10 @@ sha256=347c551e7c88affc1f4b7a4b715080253c9298dcc512ed29fe8ca5cd26d015d9
 md5=7401faebc6baee9add32608709c54eec
 sha256=063f00d5b889beee910eb113c8cfbb4fc85cd404693494bcaaf79dd09a98335c
 
+[http://sources.dreamboxupdate.com/download/snapshots/openwrt_madwifi_patches_20080829.tar.bz2]
+md5=f5cef7c338bd09d2e6774033e8509c34
+sha256=e48847244e137cdba469f1937fc3dc0c4a399a1b8dc8a1563dac654135d650c8
+
 [http://downloads.sourceforge.net/oprofile/oprofile-0.9.2.tar.gz]
 md5=9af4e1e1aab89131516736bb60e9efba
 sha256=4b3780ee09efe665a69151c994e0e5f01a56c57338660c18df30916904df83a6
@@ -11770,6 +11922,10 @@ sha256=4cf04489ff291f3f1835783b8cfa8347d99f6a05d7d9da21c8d737f441bea3ac
 md5=91f386893ff483e14dc4571e352150e4
 sha256=97cc77b93ce65e4f138e284f799c9ae7153b6f81720553c3c120b7317692b537
 
+[ftp://ftp.gnome.org/pub/GNOME/sources/pangomm/2.14/pangomm-2.14.0.tar.bz2]
+md5=85be0a654ed521e5594f64efdb3fa7d8
+sha256=211a0092cfd50923eaad75c20630c0a1818e56605d4b6fbc10702d5a34ea7107
+
 [http://xlibs.freedesktop.org/release/panoramixext-1.1.tar.bz2]
 md5=129f8623dc4f70188a015e3cbd7eae82
 sha256=74188aff5f2e5b77515a8cf3979199a598d58da8e4f573462b59cbf94cf1c99d
@@ -12690,6 +12846,10 @@ sha256=fad4e6ca8e9e2a9e4bcddc96194db69827164f65b8a35cb326d0c8cd3a870238
 md5=d2aa74615aa9cf23413975a68613ffc1
 sha256=12527f130dd695184c44c6197deb619c26c9b5b31ce7699a5dd97e0ad2dd7bd1
 
+[http://downloads.sourceforge.net/pyopenssl/pyOpenSSL-0.6.tar.gz]
+md5=af67fda6d2125cae9c56ee50430a40c7
+sha256=58ee9dd10fbd97d65347626f60a38aafdcb05d19ad90c883c4284266ba7ec959
+
 [http://www.andrewchatham.com/pyogg/download/pyao-0.82.tar.gz]
 md5=8e00f5154401a6f6d99efd20606e2819
 sha256=9a444518252f6d747e76a219e5efbc05b4e1742260a7419da9ddf93a519b30c5
@@ -12722,6 +12882,10 @@ sha256=2a9fbef7d953e1fc1eec837a4087cd518e465226b060b5cb3ea67bcef1760269
 md5=cdcebdfd63e74754f57b9e9b0db4ea20
 sha256=a6d7db68c87699e283a1f58b637a7e730c350899fd7b35b88e63caa0e85a9ab9
 
+[http://www.amk.ca/files/python/crypto/pycrypto-2.0.1.tar.gz]
+md5=4d5674f3898a573691ffb335e8d749cd
+sha256=b08d4ed54c9403c77778a3803e53a4f33f359b42d94f6f3e14abb1bf4941e6ea
+
 [http://pycurl.sourceforge.net/download/pycurl-7.14.0.tar.gz]
 md5=6f73d518fb520af14634a06ee1b7ddce
 sha256=a60e08b01fc3355ec18ec0e447349b6f8bff3f9628eb42891cff1eb51b9618b1
@@ -13682,6 +13846,10 @@ sha256=114f8be9b73d75811cac866650a64cdbc88348353d281dda3b6aff4c1e109337
 md5=6465dc6545970352dfa6305c36c2403d
 sha256=097882b4613c87303dd068c41c95e77675da790cab63c7b440e70643d1741035
 
+[http://sources.dreamboxupdate.com/download/7020/secondstage-dm8000-65.bin]
+md5=18f6363a45a2fd708e1e91cc1bcad25b
+sha256=c47212f4a24a16e2fbb90bc6c8e16c0cb9489b68be83542f2df8f26dcb62528c
+
 [ftp://ftp.gnu.org/gnu/sed/sed-4.0.8.tar.gz]
 md5=fb7fa2a7336afc358012763b292e2124
 sha256=a02d8c006bc0531bd646cae3082b7db8c7a1969084411cb129ec105fd12c0a13
@@ -14322,6 +14490,10 @@ sha256=d5b4d8a69bf72abcea74a3d02d9bed470abff0d5252c601b73ce8fe933822aea
 md5=da9effc847d13f9725b6db043d8283a5
 sha256=567a50863c04dc9ccf5def3c62bb9f0494e995357620603dd00bbe035ca7500e
 
+[http://downloads.sourceforge.net/synergy2/synergy-1.3.1.tar.gz]
+md5=a6e09d6b71cb217f23069980060abf27
+sha256=4a15e26456498dda5f3aa7d688a4892e0c50394a2f01685136fbc954bacc9691
+
 [http://downloads.sourceforge.net/linux-diag/sysfsutils-1.3.0.tar.gz]
 md5=d11c99271531be3c1e6d36b53968cd2b
 sha256=03e3dc79fd7b36266372de0d331d792c04d185e57495c6fb1d46a0ea0ed0b04d
@@ -14522,6 +14694,10 @@ sha256=c7cbaa8edec5c9be78aa954938c64b57e6c2c0f13de260c88fefdbf849e94d4d
 md5=8b9de30643f759bf2e40ccc833dd2633
 sha256=76009d233a69b2d12c2aff94770dfe9fc0558e07071f941b738bab357f8fb7b9
 
+[http://downloads.sourceforge.net/mission-control/telepathy-mission-control-4.67.tar.gz]
+md5=0a547e7af4a33355bac3638dd2e40859
+sha256=326b82519a49a238a476c028097bde5820c4b58af500dbb5b715cdfd6fe0bfcd
+
 [http://telepathy.freedesktop.org/releases/telepathy-python/telepathy-python-0.15.1.tar.gz]
 md5=b3e9bd31393c4cebbd8077b62b2bcd8c
 sha256=02a5c752201e016905c75503217af5a25eebe3f6a4e02a75173ed34021401296
@@ -14822,6 +14998,10 @@ sha256=d91b4addcbb241b04b6cf795447163ed890a436b10205d2cd9cc1885ea3d9433
 md5=ee74158c6c55ae16327595c70369ef83
 sha256=ef5e9bf276b65bb831f9c2554cd8784bd5b4ee65353808f82b7e2aef851587ec
 
+[http://dreamboxupdate.com/download/opendreambox/tuxbox-common-r8.tar.gz]
+md5=032d3f766e803555d9e3ca5aaba34858
+sha256=e1d06c75136152c78f07cb37b81e624270c95a457fbc86b2608bcc1b3cbd108b
+
 [http://heanet.dl.sourceforge.net/sourceforge/tuxnes/tuxnes-0.75.tar.gz]
 md5=5db0cd42dfdff3e681805e93b4867c43
 sha256=217fc57fdd2a5ec360c197ea36110ec929d3f27c88cf875f0f4723b3496ed7c2
@@ -15434,10 +15614,18 @@ sha256=acd218148d7f92ee7bd0539d6aabd0b42cca8ae4ffe241bfa8760d30605b28c9
 md5=67a48fd9b69db8818a4dca5375c7993a
 sha256=cb4909d8753dff7f6ac90a62a61ed1ae68e49ead2dbc60c22673c55bb0e14a36
 
+[http://sources.dreamboxupdate.com/download/7020/wdog-dm8000]
+md5=dc7c1a43733033e0bebfe57cf06a4562
+sha256=82d626e85a0b63d715b79a79e6ebacc25dd3b739320dbcdafd79cbb7ed0cc351
+
 [http://downloads.sourceforge.net/webcamserver/webcam_server-0.50.tar.gz]
 md5=96830836f64edbb12c248eb84e6b0d18
 sha256=b8e200ae66c20897c9aaa80b0044e638a0016d3bdb6e67560fd61f1ef162f305
 
+[http://downloads.sourceforge.net/wesnoth/wesnoth-1.4.5.tar.bz2]
+md5=09b7b76d4a4eedf502f38df9d551d827
+sha256=6abc3f0c9bee10dfe890c3691542ecae053908da
+
 [ftp://ftp.gnu.org/gnu/wget/wget-1.9.1.tar.gz]
 md5=e6051f1e1487ec0ebfdbda72bedc70ad
 sha256=69044b87c517b986dbc17a5f7e4de430cb56e605330c19c6bb0d384d5c37e638
@@ -17138,6 +17326,10 @@ sha256=77f3bf12ce006eb06fc79d9c60a13ff69403ca6c28cc2babafb0ae35a2240ead
 md5=e0f356e0a7b310b0d4b2976e6b7b74fd
 sha256=bb797a384b9acb8209fea572934d1b1484c5de41f062fe152ae99962f52f98ea
 
+[http://xournal.sourceforge.net/xournal-0.4.1.tar.gz]
+md5=b3d352d08e71606383c31da5790b8d60
+sha256=dff617ca33dc263caecb6afc5d42c109166ef2a1c0fe0afa070ff6691ea0e8d7
+
 [http://repository.maemo.org/pool/maemo/ossw/source/x/xpext/xpext_1.0-5.tar.gz]
 md5=1b0cb67b6f2bd7c4abef17648b062896
 sha256=a3b06f5188fd9effd0799ae31352b3cd65cb913b964e2c1a923ffa9d3c08abbe
@@ -17590,6 +17782,14 @@ sha256=81a5c8b74f100d7444356895f745321de53398f70e83b69f8284b0bf63c99ad0
 md5=ae1f9198544d1585f44dab7bab110ae3
 sha256=28e73da5403faad322022e8fb327f99677841d26396a1a1f1e854c768b47cf7c
 
+[http://sources.dreamboxupdate.com/zoneinfo.tar.bz2]
+md5=ac244d186fd829699c781b9ee8f40f22
+sha256=51d8b034902ea2a54c7b0bc4482af8c9460bb76f6b9fd41baa7254b388690f8e
+
+[http://www.zope.org/Products/ZopeInterface/3.3.0/zope.interface-3.3.0.tar.gz]
+md5=93668855e37b4691c5c956665c33392c
+sha256=c049ef6f0748a2db26c7d01de1566e52f048e5fa6fbbb8da90c43e55597a5075
+
 [http://downloads.sourceforge.net/zrally/zrally_0.90_src.tar.gz]
 md5=7084c0d2b28108563ca45e5ec1533ba1
 sha256=c4fb0477fdc110b63d867ae2a46cca7913fa6a0ca8bf574c7189329bea91dcdf
@@ -17645,3 +17845,4 @@ sha256=12f5b654f6b91953391d2492a09d2c9586d5b7af419f0eeb306e1d30245659d3
 [http://downloads.sourceforge.net/zziplib/zziplib-0.10.82.tar.bz2]
 md5=a6538f6c44ceeed0ed7e8e356f444168
 sha256=f684397ce39ec400ba3369521892b7c3a8711d3ef1be59115db9f8d57707bbb8
+
index 22718b8..add59a4 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t"
 
 # Samsung S3C2xxx CPU
 require conf/machine/include/tune-arm920t.inc
index 349dd8e..e1ad289 100644 (file)
@@ -3,7 +3,6 @@
 #@DESCRIPTION: Machine configuration for the Amstrad E3
 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4t"
 
 PREFERRED_PROVIDER_xserver = "xserver-kdrive"
 XSERVER = "xserver-kdrive-fbdev"
index ef7e8a2..8ec0d9a 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5e armv5te "
 
 require conf/machine/include/tune-xscale.inc
 
index 814641d..d471203 100644 (file)
@@ -6,7 +6,7 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te iwmmxt"
+PACKAGE_EXTRA_ARCHS = "iwmmxt"
 
 # Use tune-xscale per default. Machine independent feeds should be built with tune-strongarm.
 require conf/machine/include/tune-xscale.inc
index 16d0705..f95fb2d 100644 (file)
@@ -3,7 +3,6 @@
 #@DESCRIPTION: Machine.inciguration for the AT91SAM9260 development board with a at91sam9260 processor
 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4t armv5te"
 
 PREFERRED_PROVIDER_virtual/kernel = "linux"
 PREFERRED_VERSION_linux = "2.6.25"
index ba0c9f9..59ef577 100644 (file)
@@ -3,7 +3,6 @@
 #@DESCRIPTION: Machine.inciguration for the at91sam9260ek development board with a at91sam9260 processor
 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4t armv5te"
 
 PREFERRED_PROVIDER_virtual/kernel = "linux"
 PREFERRED_PROVIDER_xserver = "xserver-kdrive"
index 3b9d518..570ff16 100644 (file)
@@ -3,7 +3,6 @@
 #@DESCRIPTION: Machine.inciguration for the at91sam9261ek development board with a at91sam9261 processor
 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4t armv5te"
 
 PREFERRED_PROVIDER_virtual/kernel = "linux"
 PREFERRED_PROVIDER_xserver = "xserver-kdrive"
index 95c7626..9fd34f9 100644 (file)
@@ -3,7 +3,6 @@
 #@DESCRIPTION: Machine configuration for the at91sam9263ek development board with a at91sam9263 processor
 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4t armv5te"
 
 PREFERRED_PROVIDER_virtual/kernel = "linux"
 PREFERRED_PROVIDER_xserver = "xserver-kdrive"
index b119a24..6247c83 100644 (file)
@@ -6,7 +6,7 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te iwmmxt  "
+PACKAGE_EXTRA_ARCHS = " iwmmxt "
 
 # Use tune-xscale per default. Machine independent feeds should be built with tune-strongarm.
 require conf/machine/include/tune-xscale.inc
index f875d43..9578389 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te"
 
 # Use tune-xscale per default. Machine independent feeds should be built with tune-strongarm.
 require conf/machine/include/tune-xscale.inc
index 5d88ade..548cf76 100644 (file)
@@ -2,7 +2,6 @@
 #@NAME: Beagleboard machine
 #@DESCRIPTION: Machine configuration for the http://beagleboard.org/ board 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te armv6 armv7 armv7a"
 
 PREFERRED_PROVIDER_virtual/xserver = "xserver-xorg"
 XSERVER = "xserver-xorg \
index a1d6d43..cef6dbc 100644 (file)
@@ -7,7 +7,6 @@ TARGET_ARCH = "arm"
 MACHINE_FEATURES = "kernel26 apm alsa bluetooth ext2 vfat touchscreen usbhost usbgadget wifi"
 
 GUI_MACHINE_CLASS = "smallscreen"
-PACKAGE_EXTRA_ARCHS = "arm armv4t armv5te"
 
 PREFERRED_PROVIDER_virtual/kernel = "${MACHINE}-kernel"
 
index aadbea4..e01b37d 100644 (file)
@@ -7,7 +7,7 @@ GUI_MACHINE_CLASS ?= "bigscreen"
 
 PREFERRED_PROVIDER_virtual/kernel = "linux"
 
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te iwmmxt"
+PACKAGE_EXTRA_ARCHS = " iwmmxt"
 
 require conf/machine/include/tune-xscale.inc
 
index b99b137..838dbce 100644 (file)
@@ -3,7 +3,6 @@
 #@DESCRIPTION: Machine configuration for Olimex CS-E9302 Development Platform
 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4t"
 
 PREFERRED_PROVIDER_virtual/kernel = "linux"
 
index b279338..c926c6f 100644 (file)
@@ -3,7 +3,6 @@
 #@DESCRIPTION: Machine configuration for the TI Davinci EVM board
 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4t armv5te"
 
 HOTPLUG = "udev"
 
index efaffb0..4ead8c1 100644 (file)
@@ -3,7 +3,6 @@
 #@DESCRIPTION: Machine configuration for the Lyrtech Small Form Factor SDR board
 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4t armv5te"
 
 HOTPLUG = "udev"
 
index db9f268..65f6584 100644 (file)
@@ -5,7 +5,6 @@
 TARGET_ARCH = "arm"
 
 GUI_MACHINE_CLASS = "bigscreen"
-PACKAGE_EXTRA_ARCHS = "armv4 armv5te"
 
 PREFERRED_PROVIDER_virtual/bootloader = "u-boot"
 PREFERRED_PROVIDER_virtual/kernel = "${MACHINE}"
index 3cf0a7f..f8a5c95 100644 (file)
@@ -8,7 +8,7 @@
 TARGET_ARCH = "arm"
 GUI_MACHINE_CLASS ?= "bigscreen"
 
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te iwmmxt  "
+PACKAGE_EXTRA_ARCHS = "iwmmxt "
 PREFERRED_PROVIDER_virtual/kernel = "${MACHINE}"
 
 # Use tune-xscale per default. Machine independent feeds should be built with tune-strongarm.
index 16d8c70..268ed52 100644 (file)
@@ -4,7 +4,6 @@
 
 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4t"
 
 PREFERRED_PROVIDER_virtual/kernel = "linux"
 PREFERRED_PROVIDER_xserver = "xserver-kdrive"
index 211091d..f20d6ae 100644 (file)
@@ -9,7 +9,6 @@
 # CPU: Intel (now Marvell) PXA255
 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te"
 
 # Use tune-xscale per default. Machine independent feeds should be built with tune-strongarm.
 require conf/machine/include/tune-xscale.inc
index e6552b5..48beedd 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5e armv5te "
 
 #Compile with armv5te optimizations, incompatible with armv4(t) cpus
 require conf/machine/include/tune-xscale.inc
index 91e3dbb..e362bde 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t"
 
 # Samsung S3C2xxx CPU
 require conf/machine/include/tune-arm920t.inc
index c685922..a2ca95b 100644 (file)
@@ -4,7 +4,7 @@
 
 TARGET_ARCH = "armeb"
 
-PACKAGE_EXTRA_ARCHS = "armv4b armv4tb armv5eb armv5teb ixp4xxbe"
+PACKAGE_EXTRA_ARCHS = "ixp4xxbe"
 
 MACHINE_ARCH = "ixp4xxbe"
 
index ac4c1ef..db255a6 100644 (file)
@@ -3,7 +3,6 @@
 #@DESCRIPTION: Low cost SBC based on Cirrus Logic EP9302 CPU
 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4t"
 
 PREFERRED_PROVIDER_virtual/kernel = "linux"
 PREFERRED_VERSION_linux ?= "2.6.24"
index 3536485..af4ddea 100644 (file)
@@ -6,7 +6,7 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te iwmmxt  "
+PACKAGE_EXTRA_ARCHS = " iwmmxt "
 
 # Use tune-xscale per default. Machine independent feeds should be built with tune-strongarm.
 require conf/machine/include/tune-xscale.inc
index 439c484..43d23d8 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5e armv5te "
 
 require conf/machine/include/tune-xscale.inc
 
index 99e82d2..eec87a3 100644 (file)
@@ -2,7 +2,6 @@
 #@NAME: h1940
 #@DESCRIPTION: Machine configuration for the HP iPAQ h1930 and h1940
 
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t"
 TARGET_ARCH = "arm"
 
 # Set preferred providers
index 4c7e413..abc1772 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5e armv5te "
 
 #Compile with armv5te optimizations, incompatible with armv4(t) cpus
 require conf/machine/include/tune-xscale.inc
index 8b9b7ee..a403008 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5e armv5te "
 
 require conf/machine/include/tune-xscale.inc
 
index 03dcced..f85b2a1 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5e armv5te "
 
 require conf/machine/include/tune-xscale.inc
 
index a55b75c..73fbf17 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5e armv5te"
 
 require conf/machine/include/tune-xscale.inc
 
index 4657d48..08f61b8 100644 (file)
@@ -7,7 +7,6 @@
 #
 TARGET_ARCH = "arm"
 BASE_PACKAGE_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "arm armv4 armv4t"
 
 #Use OMAP 1510 cpu specifig arm9tdmi options for gcc
 require conf/machine/include/tune-arm9tdmi.inc
index f7f0254..a9791dd 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5e armv5te "
 
 require conf/machine/include/tune-xscale.inc
 
index b3debb6..d4a0bd1 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5e armv5te "
 
 require conf/machine/include/tune-xscale.inc
 
index f95cb70..a5178d8 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5e armv5te "
 
 require conf/machine/include/tune-xscale.inc
 
index 472e5d6..384f1f9 100644 (file)
@@ -6,7 +6,6 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5e armv5te "
 
 require conf/machine/include/tune-xscale.inc
 
index eba677f..1d6cde4 100644 (file)
@@ -2,7 +2,6 @@
 #@NAME: HTC Kaiser phone
 #@DESCRIPTION: Machine configuration for HTC Kaiser phone
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te armv6"
  
 PREFERRED_PROVIDER_virtual/xserver = "xserver-kdrive"
 XSERVER = "xserver-kdrive-fbdev"
@@ -11,10 +10,7 @@ GUI_MACHINE_CLASS = "smallscreen"
 MACHINE_DISPLAY_WIDTH_PIXELS = "240"
 MACHINE_DISPLAY_HEIGHT_PIXELS = "320"
  
-TARGET_CC_ARCH = "-march=armv6j -mtune=arm1136jf-s"
-FEED_ARCH = "armv6"
-BASE_PACKAGE_ARCH = "armv6"
+require conf/machine/include/tune-arm1136jf-s.inc
 
 IMAGE_FSTYPES ?= "tar.gz cpio.gz"
  
index 7852144..ab532e3 100644 (file)
@@ -6,7 +6,7 @@
 # Hardware-based properties
 #
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te iwmmxt  "
+PACKAGE_EXTRA_ARCHS = " iwmmxt  "
 
 IMAGE_FSTYPES += "jffs2"
 
index 52c2b04..296ce6a 100644 (file)
@@ -1,5 +1,4 @@
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te iwmmxt"
 
 PREFERRED_PROVIDER_xserver = "xserver-kdrive"
 PREFERRED_PROVIDER_virtual/kernel ?= "linux-ezx"
index 0f5aef5..e7b8f71 100644 (file)
@@ -1,3 +1,5 @@
 TARGET_CC_ARCH = "-march=armv6j -mtune=arm1136jf-s -mfpu=vfp -mfloat-abi=softfp"
 FEED_ARCH = "armv6"
 BASE_PACKAGE_ARCH = "armv6"
+PACKAGE_EXTRA_ARCHS += "armv4 armv4t armv5te armv6"
+
index 1f7a04b..47275b8 100644 (file)
@@ -1,4 +1,5 @@
 FEED_ARCH = "armv4t"
 BASE_PACKAGE_ARCH = "armv4t" 
 TARGET_CC_ARCH = "-march=armv4t -mtune=arm920t"
+PACKAGE_EXTRA_ARCHS += "armv4 armv4t"
 
index e80ef10..f41e460 100644 (file)
@@ -1,5 +1,5 @@
 FEED_ARCH = "armv5te"
-
+PACKAGE_EXTRA_ARCHS += "armv4 armv4t armv5te"
 # For gcc 3.x you need:
 #TARGET_CC_ARCH = "-march=armv5te -mtune=arm926ejs"
 # For gcc 4.x you need:
index 50aaec1..d788b53 100644 (file)
@@ -1,3 +1,4 @@
 FEED_ARCH = "armv4t"
 BASE_PACKAGE_ARCH = "armv4t"
+PACKAGE_EXTRA_ARCHS += "armv4 armv4t"
 TARGET_CC_ARCH = "-mcpu=arm9tdmi -mtune=arm9tdmi"
index 96c8c64..379a3eb 100644 (file)
@@ -3,4 +3,5 @@
 # This will NOT compile programs in 'ARM' mode, which is what you really want
 TARGET_CC_ARCH = "-march=armv7 -mfpu=vfp -mfloat-abi=softfp"
 FEED_ARCH = "armv7"
+PACKAGE_EXTRA_ARCHS += "armv4 armv4t armv5te armv6 armv7"
 BASE_PACKAGE_ARCH = "armv7"
index 313300d..9526faa 100644 (file)
@@ -1,3 +1,4 @@
 TARGET_CC_ARCH = "-march=i686"
+PACKAGE_EXTRA_ARCHS += "i386 i486 i586"
 BASE_PACKAGE_ARCH = "i686"
 FEED_ARCH = "i686"
index 4384908..136efa2 100644 (file)
@@ -1,3 +1,4 @@
 TARGET_CC_ARCH = "-march=c3 -mtune=c3"
+PACKAGE_EXTRA_ARCHS += "i386 i486"
 BASE_PACKAGE_ARCH = "i586"
 FEED_ARCH = "i586"
index 4216255..a2ce7de 100644 (file)
@@ -5,4 +5,5 @@
 
 TARGET_CC_ARCH = "-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp"
 FEED_ARCH = "armv7a"
+PACKAGE_EXTRA_ARCHS += "armv4 armv4t armv5te armv6 armv7 armv7a"
 BASE_PACKAGE_ARCH = "armv7a"
index 7da1cb5..39d7f9b 100644 (file)
@@ -2,6 +2,7 @@ TARGET_CC_ARCH = "-march=ep9312 -mtune=ep9312 -mcpu=ep9312"
 # add "-mfp=maverick" for newer gcc versions > 4.0
 
 #set arch to ep9312 for all generated packages
+PACKAGE_EXTRA_ARCHS += "armv4 armv4t ep9312"
 BASE_PACKAGE_ARCH = "ep9312"
 FEED_ARCH = "ep9312"
 
index aa5aaee..f7291be 100644 (file)
@@ -2,6 +2,6 @@
 # Please use tune-xscale for PXA255/PXA26x based processors.
 TARGET_CC_ARCH = "-march=iwmmxt -mcpu=iwmmxt -mtune=iwmmxt"
 BASE_PACKAGE_ARCH = "iwmmxt"
-PACKAGE_EXTRA_ARCHS += "iwmmxt"
+PACKAGE_EXTRA_ARCHS += "armv4 armv4t armv5te iwmmxt"
 FEED_ARCH = "iwmmxt"
 
index 6b8c9b5..4e5be15 100644 (file)
@@ -1,4 +1,4 @@
 TARGET_CC_ARCH = "-march=pentium"
 BASE_PACKAGE_ARCH = "i586"
 FEED_ARCH = "i586"
-
+PACKAGE_EXTRA_ARCHS += "i386 i486"
index 88fe7d7..63dda25 100644 (file)
@@ -1,4 +1,4 @@
 TARGET_CC_ARCH = "-march=pentiumpro"
 BASE_PACKAGE_ARCH = "i686"
 FEED_ARCH = "i686"
-
+PACKAGE_EXTRA_ARCHS += "i386 i486 i586"
index eb16651..bd445c6 100644 (file)
@@ -2,4 +2,5 @@ FEED_ARCH =  "${@['armv5teb', 'armv5te'][bb.data.getVar('SITEINFO_ENDIANESS', d,
 
 TARGET_CC_ARCH = "-march=armv5te -mtune=xscale"
 TARGET_CC_KERNEL_ARCH = "-march=armv5te -mtune=xscale"
+PACKAGE_EXTRA_ARCHS += "${@['armv4b armv4tb armv5teb', 'armv4 armv4t armv5te'][bb.data.getVar('SITEINFO_ENDIANESS', d, 1) == 'le']}"
 BASE_PACKAGE_ARCH = "${@['armv5teb', 'armv5te'][bb.data.getVar('SITEINFO_ENDIANESS', d, 1) == 'le']}"
index a688f2f..a861195 100644 (file)
@@ -2,7 +2,6 @@
 # Additionally, clamshell specific stuff in zaurus-clamshell.inc
 
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5e armv5te"
 PACKAGE_EXTRA_ARCHS_collie = ""
 
 MACHINE_KERNEL_VERSION = "2.6"
index 09a7153..5f96528 100644 (file)
@@ -4,8 +4,6 @@
 
 TARGET_ARCH = "arm"
 
-PACKAGE_EXTRA_ARCHS = "armv4t armv5te"
-
 PREFERRED_PROVIDER_xserver = "xserver-kdrive"
 PREFERRED_PROVIDER_virtual/kernel = "linux-neuros"
 
index 05fb2e1..f852a9e 100644 (file)
@@ -4,8 +4,6 @@
 
 TARGET_ARCH = "arm"
 
-PACKAGE_EXTRA_ARCHS = "armv4t armv5te"
-
 PREFERRED_PROVIDER_xserver = "xserver-kdrive"
 PREFERRED_PROVIDER_virtual/kernel = "linux-neuros"
 
index 15126d5..8d60733 100644 (file)
@@ -2,7 +2,6 @@
 #@NAME: Nokia 770 internet tablet
 #@DESCRIPTION: Machine configuration for the Nokia 770, an omap 1710 based tablet
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te"
 
 PREFERRED_PROVIDER_virtual/xserver = "xserver-kdrive-xomap"
 PREFERRED_PROVIDER_virtual/bootloader = ""
index afdf0ac..69b9430 100644 (file)
@@ -2,7 +2,6 @@
 #@NAME: Nokia 800 internet tablet
 #@DESCRIPTION: Machine configuration for the Nokia 800
 TARGET_ARCH = "arm"
-PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te armv6"
 
 PREFERRED_PROVIDER_virtual/xserver = "xserver-kdrive-xomap"
 XSERVER = "xserver-kdrive-xomap"
diff --git a/contrib/weekly-changelog-report.py b/contrib/weekly-changelog-report.py
new file mode 100755 (executable)
index 0000000..b5e70cb
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+
+
+# generates an OE changelog for last weeks activity (Mon-Sun) assuming it is run on
+# any day of the following week
+
+# TODO
+# - remove patch count as it does not match after we remove "Merge branch" statements
+# - add bugzilla info
+
+import datetime
+import os
+
+today = datetime.date.today()
+
+# 0 = Mon, 6 = Sun
+today_weekday = today.weekday()
+
+# find Mon of this week
+end_day = today - datetime.timedelta(today_weekday)
+
+start_day = end_day - datetime.timedelta(7)
+
+print "OE weekly changelog %s to %s\n" % (start_day.isoformat(), end_day.isoformat())
+
+os.system("git-shortlog --since=%s --until=%s | grep -v \"Merge branch\"" % (start_day.isoformat(), end_day.isoformat()))
+
+
index d178ce6..31015b3 100644 (file)
@@ -8,10 +8,6 @@ DEPENDS = "ecj-initial fastjar-native zip-native gettext-native"
 
 SRC_URI = "${GNU_MIRROR}/classpath/classpath-${PV}.tar.gz"
 
-S = "${WORKDIR}/classpath-${PV}"
-
-FILESDIR = "${@os.path.dirname(bb.data.getVar('FILE',d,1))}/classpath-${PV}"
-
 do_configure_prepend () {
 
        cp ${STAGING_DATADIR_NATIVE}/gettext/config.rpath ${S}
index f303b6e..780ea43 100644 (file)
@@ -16,7 +16,7 @@ require ti-paths.inc
 DSPLINKPLATFORM ?= "Davinci"
 
 DSPLINKPLATFORM_omap5912osk = "OMAP"
-DSPLINKPLATFORM_beagleboard = "OMAP"
+DSPLINKPLATFORM_beagleboard = "OMAP3530"
 DSPLINKPLATFORM_davinci-sffsdr = "Davinci"
 DSPLINKPLATFORM_davinci-dvevm = "Davinci"
 
@@ -32,21 +32,21 @@ KERNELARMFLAGS = "-include linux/autoconf.h -c -iwithprefix include -Iinclude -W
                    -fno-omit-frame-pointer -mapcs -mno-sched-prolog            \
                    -mlittle-endian \
                    -D__LINUX_ARM_ARCH__=5 -march=armv5t -mtune=arm9tdmi \
-                   -msoft-float -Uarm -mapcs                  \
+                   -Uarm                  \
                    -Wdeclaration-after-statement -Os -marm  -mabi=aapcs-linux"
 KERNELARMFLAGS_armv6 = "-include linux/autoconf.h -c -iwithprefix include -Iinclude -Wall  -Wstrict-prototypes \
                    -Wno-trigraphs -fno-strict-aliasing -fno-common             \
                    -fno-omit-frame-pointer -mapcs -mno-sched-prolog            \
                    -mlittle-endian \
                    -D__LINUX_ARM_ARCH__=6 -march=armv6j -mtune=arm1136jf-s \
-                   -msoft-float -Uarm -mapcs                  \                   
+                   -Uarm                  \                   
                    -Wdeclaration-after-statement -Os -marm  -mabi=aapcs-linux"
 KERNELARMFLAGS_armv7a = "-c -nostdinc -include $(BASE_OSINC)/linux/autoconf.h -isystem $(OSINC_PLATFORM)  -iwithprefix include -Iinclude -Wall  -Wstrict-prototypes \
                    -Wno-trigraphs -fno-strict-aliasing -fno-common             \
                    -fno-omit-frame-pointer -mapcs -mno-sched-prolog            \                                      
                    -mlittle-endian \
                    -D__LINUX_ARM_ARCH__=7 -march=armv7-a -mtune=cortex-a8 \
-                   -msoft-float -Uarm -mapcs                  \ 
+                   -Uarm                  \ 
                    -Wdeclaration-after-statement -Os -marm  -mabi=aapcs-linux \
                    -D__KERNEL__ -mno-thumb-interwork   -msoft-float -fno-optimize-sibling-calls -g  -fno-stack-protector -Wno-pointer-sign -g -DUSE_UDEV=1 -DOS_LINUX -DLINUX_KERNEL"
 
@@ -54,56 +54,38 @@ DSPFLAGS = "-q -pdr -pdv -pden -ml3 -mv64+ "
 
 export DSPLINKPLATFORM 
 export DSPLINKDSP
+export DSPLINKSOC
 
 do_configure () {
-       cp ${WORKDIR}/CURRENTCFG.MK ${S}/config
-       cp ${WORKDIR}/openembedded.mk ${S}/make/Linux
-       cp ${WORKDIR}/c64xx_5.xx_linux.mk ${S}/make/DspBios
-
-       sed -i  -e s:SED_ME_SOURCEDIR:${S}:g \
-               -e s:SED_ME_GPPDISTRO:openembedded:g \
-               -e s:SED_ME_KERNELVERSION:${KERNEL_VERSION}:g \
-               -e s:SED_ME_DSPDISTRO:c64xx_5.xx_linux:g \
-               -e s:SED_ME_PLATFORM:${DSPLINKPLATFORM}:g \
-               -e s:SED_ME_DSP:${DSPLINKDSP}:g \
-               -e s:SED_ME_SOC:${DSPLINKSOC}:g \       
-       ${S}/config/CURRENTCFG.MK       
-
-       sed -i  -e s:SED_ME_CROSS:${STAGING_INCDIR}:g \
-               -e s:SED_ME_STAGINGDIR:${STAGING_DIR_TARGET}:g \
-               -e s:SED_ME_TARGET_PREFIX:${TARGET_PREFIX}:g \
-               -e s:SED_ME_KERNELDIR:${STAGING_KERNEL_DIR}:g \
-               -e 's:SEDME_KERNEL_ARMFLAGS:${KERNELARMFLAGS}:g' \
-               -e 's:SEDME_USER_ARMFLAGS:${USERARMFLAGS}:g' \
-               ${S}/make/Linux/openembedded.mk 
-
-       sed -i -e s:SEDME_TITOOLS_BASEPATH:${TITOOLSDIR}:g \
-               -e s:SEDME_BIOSUNPACKDIR:${TIBIOSDIR}:g \       
-               -e s:SEDME_CGTOOLSDIR:${TICGTOOLSDIR}:g \       
-               -e 's:SEDME_DSPFLAGS:${DSPFLAGS}:g' \
-               ${S}/make/DspBios/c64xx_5.xx_linux.mk
+
+# Run perl script to create appropriate makefiles (v1.60 and up)
+DSPLINK=${S} perl config/bin/dsplinkcfg.pl --platform=${DSPLINKPLATFORM} --nodsp=1 --dspcfg_0=OMAP3530SHMEM --dspos_0=DSPBIOS5XX  --gppos=OMAPLSP --comps=ponslrmc
+
 }
 
 PARALLEL_MAKE = ""
 
 do_compile () {
-       ln -sf ${S}/gpp/src/api/*h ${S}/gpp/inc/
-       ln -sf ${S}/gpp/src/pmgr/Linux/2.6.18 ${S}/gpp/src/pmgr/Linux/${KERNEL_VERSION}
-       ln -sf ${S}/gpp/src/api/Linux/2.6.18 ${S}/gpp/src/api/Linux/${KERNEL_VERSION}
-       ln -sf ${S}/gpp/src/osal/Linux/2.6.18 ${S}/gpp/src/osal/Linux/${KERNEL_VERSION}
-       ln -sf ${S}/gpp/src/pmgr/Linux/drv_pmgr.h ${S}/gpp/inc/drv_pmgr.h
-       ln -sf ${S}/gpp/src/pmgr/pmgr_proc.h ${S}/gpp/inc/pmgr_proc.h
-
        unset DISPLAY
+       sed -i -e s:armv7a:armv7-a:g make/Linux/omap3530_2.6.mk || true
+
+       # export various settings to override the defaults in the makefiles     
+       export DSP_BASE_CGTOOLS=${TITOOLSDIR}/${TICGTOOLSDIR}
+       export DSP_BASE_BIOS=${TITOOLSDIR}/${TIBIOSDIR}
+       export DSP_BASE_RTDX=${TITOOLSDIR}/${TIBIOSDIR}/packages/ti/rtdx
+       export GPPTOOL_DIR=${CROSS_DIR}
+       export LINUXKERNEL_INSTALL_DIR=${STAGING_KERNEL_DIR}
+       export LINK_INSTALL_DIR=${S}
+       export VARIANT=${DSPLINKSOC}
+       export PLATFORM=${DSPLINKPLATFORM}
+       export BASE_TOOLCHAIN=${CROSS_DIR}
+       export BASE_CGTOOLS=${BASE_TOOLCHAIN}/bin
+       export OSINC_PLATFORM1=${CROSS_DIR}/lib/gcc/${TARGET_SYS}/$(${TARGET_PREFIX}gcc -dumpversion)/include
+       export OSINC_TARGET=${BASE_TOOLCHAIN}/target/usr/include
+       export ARCHIVER_AR=${TARGET_PREFIX}ar
+       export BASE_SABIOS=${DSP_BASE_BIOS}
        
-       sed -i -e 's:gcc:gcc${KERNEL_CCSUFFIX}:' ${S}/make/Linux/openembedded.mk
-       oe_runmake CC="${KERNEL_CC}" LD="${KERNEL_LD}" -C ${S}/gpp/src all targets
-       
-       sed -i -e 's:gcc${KERNEL_CCSUFFIX}:gcc:' ${S}/make/Linux/openembedded.mk
-       oe_runmake -C ${S}/gpp/src/samples
-
-       oe_runmake -C ${S}/dsp/src
-       oe_runmake -C ${S}/dsp/src/samples
+       make -e -f ${WORKDIR}/Makefile.dsplink
 }
 
 do_install () {
@@ -121,14 +103,9 @@ do_install () {
        install ${S}/gpp/BUILD/EXPORT/RELEASE/scalegpp          ${D}/${bindir}
 
        install -d ${D}/${datadir}/dsplink
-       install ${S}/dsp/BUILD/EXPORT/RELEASE/loop.out          ${D}/${datadir}/dsplink
-       install ${S}/dsp/BUILD/EXPORT/RELEASE/messagemulti.out  ${D}/${datadir}/dsplink
-       install ${S}/dsp/BUILD/EXPORT/RELEASE/message.out       ${D}/${datadir}/dsplink
-       install ${S}/dsp/BUILD/EXPORT/RELEASE/mpcsxfer.out      ${D}/${datadir}/dsplink
-       install ${S}/dsp/BUILD/EXPORT/RELEASE/mplist.out        ${D}/${datadir}/dsplink
-       install ${S}/dsp/BUILD/EXPORT/RELEASE/readwrite.out     ${D}/${datadir}/dsplink
-       install ${S}/dsp/BUILD/EXPORT/RELEASE/ringio.out        ${D}/${datadir}/dsplink
-       install ${S}/dsp/BUILD/EXPORT/RELEASE/scale.out         ${D}/${datadir}/dsplink
+       for i in $(find ${S}/dsp/BUILD/ -name "*.out") ; do
+               install ${i}  ${D}/${datadir}/dsplink
+       done    
 
        install -d ${D}/${libdir}
        install -m 0755 ${S}/gpp/BUILD/EXPORT/RELEASE/dsplink.lib  ${D}/${libdir}
index 756ce3e..40f65e5 100644 (file)
@@ -17,10 +17,11 @@ SRC_URI = "http://install.tarball.in.source.dir/dsplink_1_51_00_08.tar.gz \
            file://c64xx_5.xx_linux.mk \
            file://openembedded.mk \
           file://prcs-fix-include.patch;patch=1;pnum=2 \
+               file://Makefile.dsplink \
 "
 
 SRC_URI_append_beagleboard = " \
-           file://dsplink-128M.patch;patch=1;pnum=2 \
+#           file://dsplink-128M.patch;patch=1;pnum=2 \
 "
 
 S = "${WORKDIR}/dsplink_1_51_00_08/dsplink"
diff --git a/packages/dsplink/dsplink_1.60.00.04.bb b/packages/dsplink/dsplink_1.60.00.04.bb
new file mode 100644 (file)
index 0000000..2e0de85
--- /dev/null
@@ -0,0 +1,21 @@
+require dsplink.inc
+
+
+DEFAULT_PREFERENCE = "-1"
+DEFAULT_PREFERENCE_armv7a = "1"
+
+# The tconf tool breaks if there is a '.' in your pwd
+PR = "r0"
+PE = "1"
+PV = "160"
+
+# Get dsplink tarball from TI website, place in sources and calculate
+# md5sum
+# Look for tarball at https://www-a.ti.com/downloads/sds_support/targetcontent/link/index.html
+
+SRC_URI = "http://install.tarball.in.source.dir/dsplink_1_60_00_04.tar.gz \
+               file://Makefile.dsplink \
+"
+
+S = "${WORKDIR}/dsplink_1_60_00_04/dsplink"
+
diff --git a/packages/dsplink/files/Makefile.dsplink b/packages/dsplink/files/Makefile.dsplink
new file mode 100755 (executable)
index 0000000..7156bcb
--- /dev/null
@@ -0,0 +1,106 @@
+#
+#  ======== makeunix ========
+#
+
+# Import Tools Path from Rules.make
+#include Rules.make
+
+PROJECT_BASE_DIR = $(shell pwd)
+LINUXKERNEL_INSTALL_DIR:=/home/rmonklocal/oe/angstrom-davinci-dvevm-tmp/staging/davinci-dvevm-angstrom-linux-gnueabi/kernel
+LINK_INSTALL_DIR := /home/rmonklocal/dsplink_1_51/dsplink
+
+# The prefix to be added before the GNU compiler tools (optionally including
+# path), i.e. "arm_v5t_le-" or "/opt/bin/arm_v5t_le-".
+GPPTOOL_DIR:=/home/rmonklocal/oe/angstrom-davinci-dvevm-tmp/cross
+
+# ---- DSP tools ----
+DSP_BASE_CGTOOLS    := /home/rmonklocal/opt/cg6x_6_0_19
+DSP_BASE_BIOS      := /home/rmonklocal/opt/bios_5_32_03
+DSP_BASE_RTDX      := /home/rmonklocal/opt/bios_5_32_03/packages/ti/rtdx
+OSINC_PLATFORM1     := something
+ARCHIVER_AR         := something
+
+# ---- get build host OS ----
+UNAME=$(shell uname)
+ifeq "$(UNAME)" "Linux"
+       BUILD_HOST_OS=Linux
+else
+       BUILD_HOST_OS=Solaris
+endif
+
+# ---- construct Link build make vars ----
+GPP_MAKE_OPTS :=  COMPILER=$(GPPTOOL_DIR)/bin/arm-angstrom-linux-gnueabi-gcc \
+                 LINKER=$(GPPTOOL_DIR)/bin/arm-angstrom-linux-gnueabi-gcc \
+                 LD=$(GPPTOOL_DIR)/bin/arm-angstrom-linux-gnueabi-ld \
+                 ARCHIVER1=$(GPPTOOL_DIR)/bin/arm-angstrom-linux-gnueabi-ld \
+                 ARCHIVER2=$(GPPTOOL_DIR)/bin/arm-angstrom-linux-gnueabi-ld \
+                 CROSS_COMPILE=arm-angstrom-linux-gnueabi- \
+                 DSPLINK=$(LINK_INSTALL_DIR) \
+                 BASE_TOOLCHAIN=$(GPPTOOL_DIR) \
+                 BASE_BUILDOS=$(LINUXKERNEL_INSTALL_DIR) \
+                 ARCHIVER=$(ARCHIVER_AR) OSINC_PLATFORM=$(OSINC_PLATFORM1) \
+                 #STD_KRNL_FLAGS=\
+                  -include linux/autoconf.h -c -iwithprefix include -Iinclude -Wall  -Wstrict-prototypes \
+                   -Wno-trigraphs -fno-strict-aliasing -fno-common             \
+                   -fno-omit-frame-pointer -mapcs -mno-sched-prolog            \
+                   -mlittle-endian \
+                   -D__LINUX_ARM_ARCH__=5 -march=armv5t -mtune=arm9tdmi \
+                   -msoft-float -Uarm -mapcs                  \
+                   -Wdeclaration-after-statement -Os -marm  -mabi=aapcs-linux
+
+                 #STD_KRNL_FLAGS=\
+                       -nostdinc \
+                       -isystem /home/rmonklocal/oe/angstrom-davinci-dvevm-tmp/cross/lib/gcc/arm-angstrom-linux-gnueabi/4.2.4/include \
+                       -D__KERNEL__ \
+                       -Iinclude -include include/linux/autoconf.h \
+                       -mlittle-endian \
+                       -Wall \
+                       -Wundef \
+                       -Wstrict-prototypes \
+                       -Wno-trigraphs \
+                       -fno-strict-aliasing \
+                       -fno-common \
+                       -Werror-implicit-function-declaration \
+                       -Os \
+                       -fno-stack-protector \
+                       -marm \
+                       -fno-omit-frame-pointer \
+                       -mapcs \
+                       -mno-sched-prolog \
+                       -mabi=aapcs-linux \
+                       -mno-thumb-interwork \
+                       -D__LINUX_ARM_ARCH__=5 \
+                       -march=armv5te \
+                       -mtune=arm9tdmi \
+                       -msoft-float \
+                       -Uarm \
+                       -fno-omit-frame-pointer \
+                       -fno-optimize-sibling-calls \
+                       -Wdeclaration-after-statement \
+                       -Wno-pointer-sign \
+                       -c
+
+DSP_MAKE_OPTS :=  DSPLINK=$(DSPLINK) \
+                  DPPROOT=$(DSPLINK)/dsp \
+                  BASE_SABIOS=$(DSP_BASE_BIOS) \
+                  BASE_CGTOOLS=$(DSP_BASE_CGTOOLS) \
+                  BASE_RTDX=$(DSP_BASE_RTDX)
+                  
+
+#  ======== all ========
+all: $(LINK_INSTALL_DIR)/packages/dsplink/gpp/export/BIN/Linux/Davinci/RELEASE/dsplinkk.ko
+
+$(LINK_INSTALL_DIR)/packages/dsplink/gpp/export/BIN/Linux/Davinci/RELEASE/dsplinkk.ko:
+       @echo Building DSPLINK GPP driver, libs
+       make -s -C $(LINK_INSTALL_DIR)/gpp/src $(GPP_MAKE_OPTS) 
+       make -s -C $(DSPLINK)/gpp/src/samples $(GPP_MAKE_OPTS) 
+       @echo Building DSPLINK DSP libs and message sample for DaVinci...
+       make -C $(DSPLINK)/dsp/src $(DSP_MAKE_OPTS) 
+       make -C $(DSPLINK)/dsp/src/samples $(DSP_MAKE_OPTS) 
+
+#  clean rules
+clean:
+       @echo Cleaning DSPLINK GPP driver, libs
+       make -s -C $(LINK_INSTALL_DIR)/gpp/src $(GPP_MAKE_OPTS) clean
+       @rm -rf $(LINK_INSTALL_DIR)/gpp/export/BIN/*
+       @rm -rf $(LINK_INSTALL_DIR)/gpp/export/INCLUDE/*
index ea806ff..0a75c14 100644 (file)
@@ -135,7 +135,7 @@ CC_SW_REL       := -o3
 #   ----------------------------------------------------------------------------
 #   Standard flags for the compiler
 #   ----------------------------------------------------------------------------
-STD_CC_FLAGS    := SEDME_DSPFLAGS -d"CHIP_DM642"
+STD_CC_FLAGS    := SEDME_DSPFLAGS 
 
 #   ----------------------------------------------------------------------------
 #   Standard flags for the compiler when building an executable
index 83cbe68..3657d54 100644 (file)
@@ -1,8 +1,8 @@
 # Path to the dir where the TI tools are unpacked
 TITOOLSDIR ?= "/OE/TI"
 # Path under TITOOLSDIR where dspbios is unpacked
-TIBIOSDIR ?= "bios_5_32_03"
+TIBIOSDIR ?= "bios_5_32_04"
 TIXDCTOOLSDIR ?= "${TIBIOSDIR}/xdctools"
 # Path under TITOOLSDIR where the dsp toolchain is unpacked
-TICGTOOLSDIR ?= "cg6x_6_1_2"
+TICGTOOLSDIR ?= "cg6x_6_0_19"
 
index 5b39d8b..e5ff487 100644 (file)
@@ -1,7 +1,7 @@
 DESCRIPTION = "Additional plugins for Enigma2"
 MAINTAINER = "Felix Domke <tmbinc@elitedvb.net>"
 
-SRCDATE = "20080926"
+SRCDATE = "20081022"
 
 PACKAGES_DYNAMIC = "enigma2-plugin-*"
 
index bd66f10..22a9b59 100644 (file)
@@ -1,7 +1,7 @@
 DESCRIPTION = "streamproxy manages streaming data to a PC using enigma2"
 MAINTAINER = "Felix Domke <tmbinc@elitedvb.net>"
 
-SRCDATE = "20080214"
+SRCDATE = "20080728"
 PV = "1.0cvs${SRCDATE}"
 
 SRC_URI = "cvs://anonymous@cvs.schwerkraft.elitedvb.net/cvsroot/streamproxy;module=enigma2-streamproxy;method=pserver"
index 9be698f..932ebee 100644 (file)
@@ -8,11 +8,13 @@ RDEPENDS = "python-codecs python-core python-lang python-re python-threading \
        python-xml python-fcntl gst-plugin-decodebin python-stringold \
        gst-plugin-id3demux gst-plugin-mad gst-plugin-ogg gst-plugin-playbin \
        gst-plugin-typefindfunctions gst-plugin-ivorbis gst-plugin-audioconvert \
-       gst-plugin-wavparse python-netclient gst-plugin-mpegstream"
+       gst-plugin-wavparse python-netclient gst-plugin-mpegstream gst-plugin-selector \
+       gst-plugin-flac"
 
 RDEPENDS_append_dm7020 = " gst-plugin-ossaudio"
 RDEPENDS_append_dm7025 = " gst-plugin-alsa alsa-conf"
-RDEPENDS_append_dm8000 = " gst-plugin-alsa alsa-conf gst-plugin-avi gst-plugin-matroska"
+RDEPENDS_append_dm8000 = " gst-plugin-alsa alsa-conf gst-plugin-avi gst-plugin-matroska \
+       gst-plugin-subparse eglibc-gconv-iso8859-15 gst-plugin-cdxaparse"
 RDEPENDS_append_dm800 = " gst-plugin-alsa alsa-conf"
 
 DESCRIPTION_append_enigma2-plugin-extensions-cutlisteditor = "enables you to cut your movies."
@@ -30,8 +32,8 @@ RDEPENDS_enigma2-plugin-extensions-dvdplayer = "libdreamdvd0"
 export LD="${CXX}"
 
 PN = "enigma2"
-PR = "r4"
-SRCDATE = "20080926"
+PR = "r0"
+SRCDATE = "20081022"
 
 # if you want experimental, use:
 REL_MAJOR="2"
index 477a03d..daf2d68 100644 (file)
@@ -18,10 +18,12 @@ Index: enigma2/lib/python/Components/UsageConfig.py
        config.usage.hdd_standby = ConfigSelection(default = "120", choices = [
                ("0", _("no standby")), ("2", "10 " + _("seconds")), ("6", "30 " + _("seconds")),
                ("12", "1 " + _("minute")), ("24", "2 " + _("minutes")),
-@@ -56,6 +57,10 @@
+@@ -56,7 +56,11 @@
  
        config.usage.blinking_display_clock_during_recording = ConfigYesNo(default = False)
+       config.usage.load_length_of_movies_in_moviellist = ConfigYesNo(default = True)
+-      
++
 +      def EnableTtCachingChanged(configElement):
 +              setEnableTtCachingOnOff(int(configElement.value))
 +      config.usage.enable_tt_caching.addNotifier(EnableTtCachingChanged)
@@ -139,14 +141,17 @@ Index: enigma2/lib/dvb/decoder.cpp
        finishShowSinglePic();
        m_vpid = m_apid = m_pcrpid = m_textpid = pidNone;
        m_changed = -1;
-Index: enigma2/data/setup.xml
+Index: data/setup.xml
 ===================================================================
---- enigma2/data/setup.xml     (revision 5639)
-+++ enigma2/data/setup.xml     (working copy)
-@@ -22,6 +22,7 @@
-                       <item level="0" text="Margin before record (minutes)">config.recording.margin_before</item>
+RCS file: /cvs/enigma2/data/setup.xml,v
+retrieving revision 1.48
+diff -u -r1.48 setup.xml
+--- enigma2/data/setup.xml     5 Oct 2008 22:37:19 -0000       1.48
++++ enigma2/data/setup.xml     21 Oct 2008 22:54:10 -0000
+@@ -23,6 +23,7 @@
                        <item level="0" text="Margin after record">config.recording.margin_after</item>
                        <item level="0" text="Show blinking clock in display during recording">config.usage.blinking_display_clock_during_recording</item>
+                       <item level="2" text="Load Length of Movies in Movielist">config.usage.load_length_of_movies_in_moviellist</item>
 +                      <item level="1" text="Enable teletext caching">config.usage.enable_tt_caching</item>
                        <item level="1" text="Show positioner movement">config.usage.showdish</item>
                        <item level="1" text="Enable multiple bouquets">config.usage.multibouquet</item>
diff --git a/packages/fswebcam/fswebcam_20070108.bb b/packages/fswebcam/fswebcam_20070108.bb
new file mode 100644 (file)
index 0000000..e24dbf3
--- /dev/null
@@ -0,0 +1,10 @@
+DESCRIPTION = "Webcam imaage grabber and manipulation application."
+SECTION = "graphics"
+DEPENDS = "gd"
+LICENSE = "GPL"
+
+PR = "r0"
+
+inherit autotools
+
+SRC_URI = "http://www.firestorm.cx/fswebcam/files/${P}.tar.gz"
diff --git a/packages/giflib/giflib_4.1.6.bb b/packages/giflib/giflib_4.1.6.bb
new file mode 100644 (file)
index 0000000..0f4223c
--- /dev/null
@@ -0,0 +1,18 @@
+SECTION = "libs"
+DESCRIPTION = "shared library for GIF images"
+SRC_URI = "${SOURCEFORGE_MIRROR}/giflib/${BP}.tar.bz2"
+LICENSE = "MIT"
+PR = "r1"
+
+PACKAGES += "${PN}-utils"
+
+FILES_${PN} = "${libdir}"
+FILES_${PN}-utils = "${bindir}"
+
+inherit autotools
+
+do_stage() {
+       oe_libinstall -so -C lib/.libs libgif ${STAGING_LIBDIR}
+
+       install -m 0644 lib/gif_lib.h ${STAGING_INCDIR}/
+}
diff --git a/packages/gstreamer/gst-plugins-bad_0.10.8.bb b/packages/gstreamer/gst-plugins-bad_0.10.8.bb
new file mode 100644 (file)
index 0000000..bd2180f
--- /dev/null
@@ -0,0 +1,4 @@
+require gst-plugins.inc
+
+SRC_URI += "file://gst-plugins-directfb-fix.patch;patch=1;pnum=2"
+DEPENDS += "gst-plugins-base"
diff --git a/packages/gstreamer/gst-plugins-base_0.10.20.bb b/packages/gstreamer/gst-plugins-base_0.10.20.bb
new file mode 100644 (file)
index 0000000..f1e012f
--- /dev/null
@@ -0,0 +1,12 @@
+require gst-plugins.inc
+
+PROVIDES += "gst-plugins"
+
+# gst-plugins-base only builds the alsa plugin
+# if alsa has been built and is present.  You will
+# not get an error if this is not present, just 
+# a missing alsa plugin
+DEPENDS += "alsa-lib"
+
+FILE_PR = "r0"
+
diff --git a/packages/gstreamer/gst-plugins-good_0.10.10.bb b/packages/gstreamer/gst-plugins-good_0.10.10.bb
new file mode 100644 (file)
index 0000000..86391c6
--- /dev/null
@@ -0,0 +1,5 @@
+require gst-plugins.inc
+FILE_PR = "r0"
+
+EXTRA_OECONF += "--with-check=no"
+DEPENDS += "gst-plugins-base"
diff --git a/packages/gstreamer/gst-plugins-ugly_0.10.9.bb b/packages/gstreamer/gst-plugins-ugly_0.10.9.bb
new file mode 100644 (file)
index 0000000..6f68925
--- /dev/null
@@ -0,0 +1,16 @@
+require gst-plugins.inc
+FILE_PR = "r0"
+
+DEPENDS += "gst-plugins-base ${@get_depends(bb, d)}"
+SRC_URI += "${@get_src_uri(bb, d)}"
+
+def get_src_uri(bb, d):
+       if bb.data.getVar('DISTRO', d, 1) in [ 'opendreambox' ]:
+               return ""
+       return "file://gstmad_16bit.patch;patch=1 " \
+               "file://gstsid_autofoo_HACK.patch;patch=1"
+
+def get_depends(bb, d):
+       if bb.data.getVar('DISTRO', d, 1) in [ 'opendreambox' ]:
+               return ""
+       return "libsidplay"
index e506e09..16f590b 100644 (file)
@@ -1,6 +1,6 @@
 require gst-common.inc
 DESCRIPTION = "Plugins for GStreamer"
-DEPENDS = "gstreamer libmikmod libmad liboil libogg tremor libvorbis libid3tag neon"
+DEPENDS = "gstreamer libmikmod libmad liboil libogg tremor libvorbis libid3tag neon flac libmatroska"
 
 PACKAGES_DYNAMIC = "gst-plugin-*"
 
diff --git a/packages/gstreamer/gstreamer_0.10.20.bb b/packages/gstreamer/gstreamer_0.10.20.bb
new file mode 100644 (file)
index 0000000..2ead8ce
--- /dev/null
@@ -0,0 +1,6 @@
+require gstreamer.inc
+
+FILE_PR = "r0"
+
+SRC_URI += "file://po-makefile-fix.patch;patch=1"
+
index 2af16a3..c7abc18 100644 (file)
@@ -1,6 +1,6 @@
 require gtk+_${PV}.bb
 inherit native
-DEPENDS = "jpeg-native libpng-native gettext-native glib-2.0-native"
+DEPENDS = "jpeg-native libpng-native gettext-native glib-2.0-native libx11-native"
 S = "${WORKDIR}/gtk+-${PV}"
 FILESPATH = "${FILE_DIRNAME}/gdk-pixbuf-csource:${FILE_DIRNAME}/gtk+-${PV}:${FILE_DIRNAME}/files"
 SRC_URI += "file://reduce-dependencies.patch;patch=1"
diff --git a/packages/lesstif/files/000_bootstrap_script.diff b/packages/lesstif/files/000_bootstrap_script.diff
new file mode 100644 (file)
index 0000000..ca1a998
--- /dev/null
@@ -0,0 +1,30 @@
+Index: lesstif1-1-0.93.94/bootstrap
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ lesstif1-1-0.93.94/bootstrap       2006-05-26 17:36:58.000000000 +0200
+@@ -0,0 +1,25 @@
++#! /bin/sh
++
++for x in aclocal.m4 configure config.guess config.log config.sub config.cache config.h.in config.h compile libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 ltmain.sh libtool ltconfig missing mkinstalldirs depcomp install-sh; do rm -f $x test/$x; done
++rm -Rf autom4te.cache
++
++# Explain what we are doing from now
++set -x
++
++libtoolize --copy --force
++aclocal-1.9 -I .
++autoconf
++autoheader
++automake-1.9 --foreign --add-missing --copy
++
++cd test
++
++libtoolize --copy --force
++aclocal-1.9 -I ..
++autoconf
++autoheader
++automake-1.9 --foreign --add-missing --copy
++
++# Remove cruft that we no longer want
++rm -Rf autom4te.cache
++
diff --git a/packages/lesstif/files/000_libtool_linking.diff b/packages/lesstif/files/000_libtool_linking.diff
new file mode 100644 (file)
index 0000000..18a5bc5
--- /dev/null
@@ -0,0 +1,11 @@
+--- lesstif2-0.94.4.orig/clients/Motif-2.1/mwm/Makefile.am
++++ lesstif2-0.94.4/clients/Motif-2.1/mwm/Makefile.am
+@@ -37,7 +37,7 @@
+ appdir=               $(libdir)/X11/app-defaults
+-mwmddir=      $(libdir)/X11/mwm
++mwmddir=      /etc/X11/mwm
+ mwmd_DATA=    system.mwmrc alt.map README
diff --git a/packages/lesstif/files/010_rebootstrap-small.diff b/packages/lesstif/files/010_rebootstrap-small.diff
new file mode 100644 (file)
index 0000000..8bf355f
--- /dev/null
@@ -0,0 +1,456 @@
+Index: lesstif2-0.95.0/ac_debug.m4
+===================================================================
+--- lesstif2-0.95.0.orig/ac_debug.m4   2004-02-01 16:49:40.000000000 +0100
++++ lesstif2-0.95.0/ac_debug.m4        2006-07-11 11:11:36.000000000 +0200
+@@ -4,6 +4,90 @@
+ dnl Source code which depends on this is mostly in
+ dnl DebugUtil.c/.h
+ dnl
++AC_DEFUN(LT_WITH_DMALLOC,
++[AC_MSG_CHECKING(if malloc debugging is wanted)
++AC_ARG_WITH(dmalloc,
++[  --with-dmalloc[=path]   use dmalloc, see INSTALL(.html) for reference],
++[if test "$withval" = no; then
++  AC_MSG_RESULT(no)
++else
++dnl We overwrite the variables since we won't continue in
++dnl case of an error!
++dnl We modify CFLAGS, and also link libs (LDFLAGS) and programs (LIBS)
++  if test "$withval" != yes; then
++dnl  a path was given
++     CFLAGS="$CFLAGS -I$withval/include -DDMALLOC_FUNC_CHECK"
++
++     LDFLAGS="$LDFLAGS -L$withval/lib -ldmalloc"
++     LIBS="$LIBS -L$withval/lib -ldmalloc"
++  else
++dnl  no path was given
++     CFLAGS="$CFLAGS -DDMALLOC_FUNC_CHECK"
++     LDFLAGS="$LDFLAGS -ldmalloc"
++     LIBS="$LIBS -ldmalloc"
++  fi
++  AC_TRY_LINK(
++  [#include <dmalloc.h>],
++  [char *ptr;
++  ptr=malloc(1);
++  free(ptr);
++  ],
++  [AC_DEFINE(WITH_DMALLOC,1,
++            [Define if using the dmalloc debugging malloc package])
++  AC_MSG_RESULT(Using dmalloc)],
++  AC_MSG_ERROR(dmalloc not found)
++  )
++fi],
++[AC_MSG_RESULT(no)])
++])
++
++
++dnl
++dnl Enable another malloc checker for debugging purposes
++dnl Source code which depends on this is mostly in
++dnl DebugUtil.c/.h
++dnl
++AC_DEFUN(LT_WITH_DBMALLOC,
++[AC_MSG_CHECKING(if malloc debugging is wanted)
++AC_ARG_WITH(dbmalloc,
++[  --with-dbmalloc[=path]   use dbmalloc, see INSTALL(.html) for reference],
++[if test "$withval" = no; then
++  AC_MSG_RESULT(no)
++else
++dnl We overwrite the variables since we won't continue in
++dnl case of an error!
++dnl We modify CFLAGS, and also link libs (LDFLAGS) and programs (LIBS)
++  if test "$withval" != yes; then
++dnl  a path was given
++     CFLAGS="$CFLAGS -I$withval/include"
++
++     LDFLAGS="$LDFLAGS -L$withval/lib -ldbmalloc"
++     LIBS="$LIBS -L$withval/lib -ldbmalloc"
++  else
++dnl  no path was given
++     LDFLAGS="$LDFLAGS -ldbmalloc"
++     LIBS="$LIBS -ldbmalloc"
++  fi
++  AC_TRY_LINK(
++  [#include <dbmalloc.h>],
++  [char *ptr;
++  ptr=malloc(1);
++  free(ptr);
++  ],
++  [AC_DEFINE(WITH_DBMALLOC,1,
++            [Define if using the dbmalloc debugging malloc package])
++  AC_MSG_RESULT(Using dbmalloc)],
++  AC_MSG_ERROR(dbmalloc not found)
++  )
++fi],
++[AC_MSG_RESULT(no)])
++])
++dnl
++dnl Enable malloc checker for debugging purposes
++dnl See http://dmalloc.com, INSTALL(.html) for references to this.
++dnl Source code which depends on this is mostly in
++dnl DebugUtil.c/.h
++dnl
+ AC_DEFUN([LT_WITH_DMALLOC],
+ [AC_MSG_CHECKING(if malloc debugging is wanted)
+ AC_ARG_WITH(dmalloc,
+Index: lesstif2-0.95.0/ac_find_xft.m4
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ lesstif2-0.95.0/ac_find_xft.m4     2006-07-11 11:11:44.000000000 +0200
+@@ -0,0 +1,299 @@
++dnl
++dnl $Header: /home/kobras/cvsroot/debian/lesstif1-1/ac_find_xft.m4,v 1.1 2004/05/27 10:48:25 kobras Exp $
++dnl
++dnl $XFree86: xc/lib/fontconfig/configure.in,v 1.7 2002/08/01 15:57:25 keithp Exp $
++dnl
++dnl Copyright Â© 2002 Keith Packard, member of The XFree86 Project, Inc.
++dnl Manipulated into AC_FIND_XFT macro by Danny Backx (also Â© 2002).
++dnl
++dnl Permission to use, copy, modify, distribute, and sell this software and its
++dnl documentation for any purpose is hereby granted without fee, provided that
++dnl the above copyright notice appear in all copies and that both that
++dnl copyright notice and this permission notice appear in supporting
++dnl documentation, and that the name of Keith Packard not be used in
++dnl advertising or publicity pertaining to distribution of the software without
++dnl specific, written prior permission.  Keith Packard makes no
++dnl representations about the suitability of this software for any purpose.  It
++dnl is provided "as is" without express or implied warranty.
++dnl
++dnl KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++dnl INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++dnl EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++dnl CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++dnl DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++dnl TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++dnl PERFORMANCE OF THIS SOFTWARE.
++dnl
++
++AC_DEFUN(AC_FIND_XFT,
++[
++AH_TEMPLATE([HAVE_FREETYPE], [We have the FreeType library])
++AH_TEMPLATE([HAVE_FONTCONFIG], [We have the fontconfig library])
++AH_TEMPLATE([HAVE_XRENDER], [We have the fontconfig library])
++AH_TEMPLATE([FC_DEFAULT_FONTS], [We have the fontconfig library])
++AH_TEMPLATE([X_FONT_DIR], [We have the fontconfig library])
++AH_TEMPLATE([CONFDIR], [We have the fontconfig library])
++AH_TEMPLATE([USE_XFT], [We have the fontconfig library])
++
++AC_ARG_WITH(freetype_includes, [  --with-freetype-includes=DIR  Use FreeType includes in DIR], freetype_includes=$withval, freetype_includes=yes)
++AC_ARG_WITH(freetype_lib,      [  --with-freetype-lib=DIR       Use FreeType library in DIR], freetype_lib=$withval, freetype_lib=yes)
++AC_ARG_WITH(freetype_config,   [  --with-freetype-config=PROG   Use FreeType configuration program PROG], freetype_config=$withval, freetype_config=yes)
++dnl AC_ARG_WITH(expat,             [  --with-expat=DIR              Use Expat in DIR], expat=$withval, expat=yes)
++dnl AC_ARG_WITH(expat_includes,    [  --with-expat-includes=DIR     Use Expat includes in DIR], expat_includes=$withval, expat_includes=yes)
++dnl AC_ARG_WITH(expat_lib,         [  --with-expat-lib=DIR          Use Expat library in DIR], expat_lib=$withval, expat_lib=yes)
++AC_ARG_WITH(default_fonts,     [  --with-default-fonts=DIR      Use fonts from DIR when config is busted], defaultfonts="$withval", default_fonts=yes)
++dnl AC_ARG_WITH(confdir,           [  --with-confdir=DIR            Use DIR to store configuration files (default /etc/fonts)], confdir="$withval", confdir=yes)
++AC_ARG_WITH(fontconfig_includes, [  --with-fontconfig-includes=DIR  Use Fontconfig includes in DIR], fontconfig_includes=$withval, fontconfig_includes=yes)
++AC_ARG_WITH(fontconfig_lib,      [  --with-fontconfig-lib=DIR       Use Fontconfig library in DIR], fontconfig_lib=$withval, fontconfig_lib=yes)
++AC_ARG_WITH(fontconfig_config,   [  --with-fontconfig-config=PROG  Use Fontconfig configuration program PROG], fontconfig_config=$withval, fontconfig_config=yes)
++AC_ARG_ENABLE(xrender,   [  --enable-xrender  Enable Xrender])
++
++# Using x libraries, set X font directory
++case "$no_x" in
++yes)
++      ;;
++*)
++      X_FONT_DIR="$x_libraries/X11/fonts"
++      AC_DEFINE_UNQUOTED(X_FONT_DIR,$X_FONT_DIR)
++      ;;
++esac
++AC_SUBST(X_FONT_DIR)
++
++#
++# Check freetype configuration
++#
++case "$freetype_config" in
++no)
++      ;;
++yes)
++      AC_CHECK_PROG(ft_config,freetype-config,freetype-config,no)
++      ;;
++*)
++      ft_config="$freetype_config"
++      ;;
++esac
++
++case "$freetype_includes" in
++no)
++      FREETYPE_CFLAGS=""
++      ;;
++yes)
++      case "$ft_config" in
++      no)
++              FREETYPE_CFLAGS=""
++              ;;
++      *)
++              FREETYPE_CFLAGS="`$ft_config --cflags`"
++              ;;
++      esac
++      ;;
++*)
++      FREETYPE_CFLAGS="-I$freetype_includes"
++      ;;
++esac
++
++case "$freetype_lib" in
++no)
++      freetype_lib=""
++      ;;
++yes)
++      case "$ft_config" in
++      no)
++              freetype_lib=""
++              ;;
++      *)
++              freetype_lib="`$ft_config --libs`"
++              ;;
++      esac
++      ;;
++*)
++      freetype_lib="-L$freetype_lib -lfreetype"
++      ;;
++esac
++
++saved_LIBS="$LIBS"
++LIBS="$LIBS $freetype_lib"
++saved_CPPFLAGS="$CPPFLAGS"
++CPPFLAGS="$CPPFLAGS $FREETYPE_CFLAGS"
++AC_CHECK_HEADERS(freetype/freetype.h)
++
++HAVEFREETYPE="no"
++case "$ac_cv_header_freetype_freetype_h" in
++no)
++      CPPFLAGS="$saved_CPPFLAGS"
++      LIBS="$saved_LIBS"
++      ;;
++yes)
++      AC_CHECK_FUNCS(FT_Init_FreeType)
++      case "$ac_cv_func_FT_Init_FreeType" in
++      no)
++              CPPFLAGS="$saved_CPPFLAGS"
++              LIBS="$saved_LIBS"
++              ;;
++      yes)
++              HAVEFREETYPE="yes"
++              AC_DEFINE(HAVE_FREETYPE)
++              AC_SUBST(FREETYPE_CFLAGS)
++              ;;
++      esac
++      ;;
++esac
++
++case "$default_fonts" in
++yes)
++      FC_DEFAULT_FONTS="/usr/share/fonts"
++      AC_DEFINE_UNQUOTED(FC_DEFAULT_FONTS, "/usr/share/fonts")
++      ;;
++*)
++      FC_DEFAULT_FONTS="$default_fonts"
++      AC_DEFINE_UNQUOTED(FC_DEFAULT_FONTS, "$default_fonts")
++      ;;
++esac
++
++AC_SUBST(FC_DEFAULT_FONTS)
++
++#
++# Set CONFDIR and FONTCONFIG_PATH
++#
++
++case "$confdir" in
++no|yes)
++      confdir=/etc/fonts
++      ;;
++*)
++      ;;
++esac
++AC_SUBST(confdir)
++CONFDIR='${confdir}'
++AC_DEFINE_UNQUOTED(CONFDIR, "$CONFDIR")
++AC_SUBST(CONFDIR)
++
++#
++# Check X configuration
++#
++HAVEXRENDER="no"
++case "$enable_xrender" in
++no)
++      ;;
++*)
++      XRENDER_CFLAGS="-I$x_includes"
++      XRENDER_LIBS="-L$x_libraries -lXft -lXrender"
++
++      saved_LIBS="$LIBS"
++      LIBS="$LIBS $XRENDER_LIBS"
++      saved_CPPFLAGS="$CPPFLAGS"
++      CPPFLAGS="$CPPFLAGS $XRENDER_CFLAGS"
++      AC_CHECK_HEADERS(X11/extensions/Xrender.h)
++
++      case "$ac_cv_header_X11_extensions_Xrender_h" in
++      no)
++              CPPFLAGS="$saved_CPPFLAGS"
++              LIBS="$saved_LIBS"
++              ;;
++      yes)
++              AC_CHECK_FUNCS(XRenderParseColor)
++              case "$ac_cv_func_XRenderParseColor" in
++              no)
++                      CPPFLAGS="$saved_CPPFLAGS"
++                      LIBS="$saved_LIBS"
++                      ;;
++              yes)
++                      HAVEXRENDER="yes"
++                      AC_DEFINE(HAVE_XRENDER)
++                      AC_SUBST(XRENDER_CFLAGS)
++                      AC_SUBST(XRENDER_LIBS)
++                      ;;
++              esac
++              ;;
++      esac
++
++      ;;
++esac
++
++#
++# Check fontconfig configuration
++#
++case "$fontconfig_config" in
++no)
++      ;;
++yes)
++      AC_CHECK_PROG(fc_config,fontconfig-config,fontconfig-config,no)
++      ;;
++*)
++      fc_config="$fontconfig_config"
++      ;;
++esac
++
++case "$fontconfig_includes" in
++no)
++      FONTCONFIG_CFLAGS=""
++      ;;
++yes)
++      case "$fc_config" in
++      no)
++              FONTCONFIG_CFLAGS=""
++              ;;
++      *)
++              FONTCONFIG_CFLAGS="`$fc_config --cflags`"
++              ;;
++      esac
++      ;;
++*)
++      FONTCONFIG_CFLAGS="-I$fontconfig_includes"
++      ;;
++esac
++
++case "$fontconfig_lib" in
++no)
++      fontconfig_lib=""
++      ;;
++yes)
++      case "$fc_config" in
++      no)
++              fontconfig_lib=""
++              ;;
++      *)
++              FONTCONFIG_LIBS="`$fc_config --libs`"
++              ;;
++      esac
++      ;;
++*)
++      FONTCONFIG_LIBS="-L$fontconfig_lib -lfontconfig"
++      ;;
++esac
++
++saved_LIBS="$LIBS"
++LIBS="$LIBS $FONTCONFIG_LIBS"
++saved_CPPFLAGS="$CPPFLAGS"
++CPPFLAGS="$CPPFLAGS $FONTCONFIG_CFLAGS"
++AC_CHECK_HEADERS(fontconfig/fontconfig.h)
++
++case "$ac_cv_header_fontconfig_fontconfig_h" in
++no)
++      CPPFLAGS="$saved_CPPFLAGS"
++      LIBS="$saved_LIBS"
++      ;;
++yes)
++      AC_CHECK_FUNCS(FcInit)
++      case "$ac_cv_func_FcInit" in
++      no)
++              CPPFLAGS="$saved_CPPFLAGS"
++              LIBS="$saved_LIBS"
++              ;;
++      yes)
++              AC_DEFINE(HAVE_FONTCONFIG)
++              AC_SUBST(FONTCONFIG_CFLAGS)
++              AC_SUBST(FONTCONFIG_LIBS)
++              ;;
++      esac
++      ;;
++esac
++
++dnl
++dnl Should this be conditionally defined ?
++dnl
++if test "$HAVEXRENDER" = "yes" -a "$HAVEFREETYPE" = "yes"
++then
++      AC_DEFINE(USE_XFT)
++fi
++])
+Index: lesstif2-0.95.0/ac_have_libxp.m4
+===================================================================
+--- lesstif2-0.95.0.orig/ac_have_libxp.m4      2004-02-01 16:49:40.000000000 +0100
++++ lesstif2-0.95.0/ac_have_libxp.m4   2006-07-11 11:11:36.000000000 +0200
+@@ -11,6 +11,52 @@
+ dnl Makefiles. Perhaps one should immediately add those libs
+ dnl to link commands which include libXm version2.1?!
+ dnl
++AC_DEFUN(LT_HAVE_LIBXP,
++[AC_REQUIRE([AC_PATH_X])
++AC_CACHE_CHECK(whether libXp is available, lt_cv_libxp,
++[lt_save_CFLAGS="$CFLAGS"
++lt_save_CPPFLAGS="$CPPFLAGS"
++lt_save_LIBS="$LIBS"
++LIBS="$X_LIBS -lXp -lXext -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $LIBS"
++CFLAGS="$X_CFLAGS $CFLAGS"
++CPPFLAGS="$X_CFLAGS $CPPFLAGS"
++AC_TRY_LINK([
++#include <X11/Intrinsic.h>
++#include <X11/extensions/Print.h>
++],[
++Display *display=NULL;
++short   major_version, minor_version;
++Status rc;
++rc=XpQueryVersion(display, &major_version, &minor_version);
++],
++lt_cv_libxp=yes,
++lt_cv_libxp=no)
++])
++if test $lt_cv_libxp = yes; then
++  AC_DEFINE(HAVE_LIB_XP)
++  LT_HAVELIBXP=1
++else
++  LT_HAVELIBXP=0 
++fi
++AM_CONDITIONAL(Have_Libxp, test "$lt_cv_libxp" = "yes")
++AC_SUBST(LT_HAVELIBXP)
++CFLAGS="$lt_save_CFLAGS"
++CPPFLAGS="$lt_save_CPPFLAGS"
++LIBS="$lt_save_LIBS"
++])
++dnl
++dnl Check for libXp
++dnl In fact this check ensures that
++dnl  - <X11/extensions/Print.h> and
++dnl  - both libXp and libXext
++dnl are in place
++dnl Perhaps AC_CHECK_LIB() could be used as well, but
++dnl requires the same amount of work to get all linker
++dnl flags and additional libraries specified.
++dnl If the test succeeds 'Have_Libxp' will be defined within our 
++dnl Makefiles. Perhaps one should immediately add those libs
++dnl to link commands which include libXm version2.1?!
++dnl
+ AC_DEFUN([LT_HAVE_LIBXP],
+ [AC_REQUIRE([AC_PATH_X])
+ AC_CACHE_CHECK(whether libXp is available, lt_cv_libxp,
diff --git a/packages/lesstif/files/020_bad_integer_cast.diff b/packages/lesstif/files/020_bad_integer_cast.diff
new file mode 100644 (file)
index 0000000..620d702
--- /dev/null
@@ -0,0 +1,13 @@
+--- lesstif2-0.94.4.orig/include/Motif-2.1/XmI/XpmI.h
++++ lesstif2-0.94.4/include/Motif-2.1/XmI/XpmI.h
+@@ -217,8 +217,8 @@
+ FUNC(xpmHashSlot, xpmHashAtom *, (xpmHashTable *table, char *s));
+ FUNC(xpmHashIntern, int, (xpmHashTable *table, char *tag, void *data));
+-#define HashAtomData(i) ((void *)i)
+-#define HashColorIndex(slot) ((unsigned int)((*slot)->data))
++#define HashAtomData(i) ((void *)(uintptr_t)i)
++#define HashColorIndex(slot) ((uintptr_t)((*slot)->data))
+ #define USE_HASHTABLE (cpp > 2 && ncolors > 4)
+ /* I/O utility */
diff --git a/packages/lesstif/files/020_missing_xm_h.diff b/packages/lesstif/files/020_missing_xm_h.diff
new file mode 100644 (file)
index 0000000..2d298d5
--- /dev/null
@@ -0,0 +1,11 @@
+--- lesstif2-0.94.4.orig/include/Motif-2.1/Xm/XmStrDefs.h
++++ lesstif2-0.94.4/include/Motif-2.1/Xm/XmStrDefs.h
+@@ -28,6 +28,8 @@
+ #include <X11/StringDefs.h>
++#include <Xm/Xm.h>
++
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
diff --git a/packages/lesstif/files/020_render_table_crash.diff b/packages/lesstif/files/020_render_table_crash.diff
new file mode 100644 (file)
index 0000000..1699dbe
--- /dev/null
@@ -0,0 +1,11 @@
+--- lesstif2-0.95.0.orig/lib/Xm-2.1/RenderTable.c
++++ lesstif2-0.95.0/lib/Xm-2.1/RenderTable.c
+@@ -465,7 +465,7 @@
+       DEBUGOUT(_LtDebug(__FILE__, w, "_XmRenderTableFinaliseTag(%s)\n", tag));
+ #if 1
+       /* Experimental start */
+-      if (r->dpy == 0)
++      if (r->dpy == 0  &&  w)
+               r->dpy = XtDisplay(w);
+       /* Experimental end */
+ #endif
diff --git a/packages/lesstif/files/020_unsigned_int.diff b/packages/lesstif/files/020_unsigned_int.diff
new file mode 100644 (file)
index 0000000..a682d97
--- /dev/null
@@ -0,0 +1,38 @@
+--- lesstif2-0.94.4.orig/lib/Xm-2.1/Xpmcreate.c
++++ lesstif2-0.94.4/lib/Xm-2.1/Xpmcreate.c
+@@ -1265,10 +1265,10 @@
+     register char *src;
+     register char *dst;
+     register unsigned int *iptr;
+-    register unsigned int x, y, i;
++    register unsigned int x, y;
+     register char *data;
+     Pixel pixel, px;
+-    int nbytes, depth, ibu, ibpp;
++    int nbytes, depth, ibu, ibpp, i;
+     data = image->data;
+     iptr = pixelindex;
+--- lesstif2-0.94.4.orig/lib/Xm-2.1/Xpmscan.c
++++ lesstif2-0.94.4/lib/Xm-2.1/Xpmscan.c
+@@ -672,8 +672,8 @@
+     char *dst;
+     unsigned int *iptr;
+     char *data;
+-    unsigned int x, y, i;
+-    int bits, depth, ibu, ibpp, offset;
++    unsigned int x, y;
++    int bits, depth, ibu, ibpp, offset, i;
+     unsigned long lbt;
+     Pixel pixel, px;
+@@ -684,6 +684,9 @@
+     ibpp = image->bits_per_pixel;
+     offset = image->xoffset;
++    if (image->bitmap_unit < 0)
++          return (XpmNoMemory);
++
+     if ((image->bits_per_pixel | image->depth) == 1) {
+       ibu = image->bitmap_unit;
+       for (y = 0; y < height; y++)
diff --git a/packages/lesstif/files/020_xpmpipethrough.diff b/packages/lesstif/files/020_xpmpipethrough.diff
new file mode 100644 (file)
index 0000000..69f9a24
--- /dev/null
@@ -0,0 +1,381 @@
+Index: lesstif2-0.95.0/lib/Xm-2.1/XpmRdFToI.c
+===================================================================
+--- lesstif2-0.95.0.orig/lib/Xm-2.1/XpmRdFToI.c        2004-11-18 22:00:58.000000000 +0100
++++ lesstif2-0.95.0/lib/Xm-2.1/XpmRdFToI.c     2006-07-11 11:13:29.000000000 +0200
+@@ -44,11 +44,15 @@
+    DebugUtil.h! */
+ #include <stdio.h>
+ #include <string.h>
++#include <errno.h>
+ #include <ctype.h>
+ #ifdef HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+ #endif
++#ifdef HAVE_SYS_WAIT_H
++#include <sys/wait.h>
++#endif
+ #ifdef HAVE_SYS_STAT_H
+ #include <sys/stat.h>
+ #endif
+@@ -87,16 +91,6 @@
+           strcpy(dst, src); \
+       else return (XpmFileInvalid); }
+ #endif
+-#include <sys/stat.h>
+-#if !defined(NO_ZPIPE) && defined(WIN32)
+-# define popen _popen
+-# define pclose _pclose
+-# if defined(STAT_ZFILE)
+-#  include <io.h>
+-#  define stat _stat
+-#  define fstat _fstat
+-# endif
+-#endif
+ LFUNC(OpenReadFile, int, (char *filename, xpmData *mdata));
+ LFUNC(xpmDataClose, void, (xpmData *mdata));
+@@ -173,90 +167,131 @@
+ }
+ #endif /* CXPMPROG */
+-/*
+- * open the given file to be read as an xpmData which is returned.
+- */
+ #ifndef NO_ZPIPE
+-      FILE *s_popen(char *cmd, const char *type);
+-#else
+-#     define s_popen popen
++/* Do not depend on errno after read_through */
++FILE*
++xpmPipeThrough(fd, cmd, arg1, mode)
++    int fd;
++    const char* cmd;
++    const char* arg1;
++    const char* mode;
++{
++    FILE* fp;
++    int status, fds[2], in = 0, out = 1;
++    pid_t pid;
++    if ( 'w' == *mode )
++      out = 0, in = 1;
++    if ( pipe(fds) < 0 )
++      return NULL;
++    pid = fork();
++    if ( pid < 0 )
++      goto fail1;
++    if ( 0 == pid )
++    {
++      close(fds[in]);
++      if ( dup2(fds[out], out) < 0 )
++          goto err;
++      close(fds[out]);
++      if ( dup2(fd, in) < 0 )
++          goto err;
++      close(fd);
++      pid = fork();
++      if ( pid < 0 )
++          goto err;
++      if ( 0 == pid )
++      {
++          execlp(cmd, cmd, arg1, NULL);
++          perror(cmd);
++          goto err;
++      }
++      _exit(0);
++    err:
++      _exit(1);
++    }
++    close(fds[out]);
++    /* calling process: wait for first child */
++    while ( waitpid(pid, &status, 0) < 0 && EINTR == errno )
++      ;
++    if ( WIFSIGNALED(status) ||
++       (WIFEXITED(status) && WEXITSTATUS(status) != 0) )
++      goto fail2;
++    fp = fdopen(fds[in], mode);
++    if ( !fp )
++      goto fail2;
++    close(fd); /* still open in 2nd child */
++    return fp;
++fail1:
++    close(fds[out]);
++fail2:
++    close(fds[in]);
++    return NULL;
++}
+ #endif
++/*
++ * open the given file to be read as an xpmData which is returned.
++ */
+ static int
+ OpenReadFile(filename, mdata)
+     char *filename;
+     xpmData *mdata;
+ {
+-#ifndef NO_ZPIPE
+-    char buf[BUFSIZ];
+-# ifdef STAT_ZFILE
+-    char *compressfile;
+-    struct stat status;
+-# endif
+-#endif
+-
+     if (!filename) {
+       mdata->stream.file = (stdin);
+       mdata->type = XPMFILE;
+     } else {
+-#ifndef NO_ZPIPE
+-      size_t len = strlen(filename);
+-
+-      if(len == 0                        ||
+-         filename[len-1] == '/')
+-              return(XpmOpenFailed);
+-      if ((len > 2) && !strcmp(".Z", filename + (len - 2))) {
+-          mdata->type = XPMPIPE;
+-          snprintf(buf, sizeof(buf), "uncompress -c \"%s\"", filename);
+-          if (!(mdata->stream.file = s_popen(buf, "r")))
+-              return (XpmOpenFailed);
+-
+-      } else if ((len > 3) && !strcmp(".gz", filename + (len - 3))) {
+-          mdata->type = XPMPIPE;
+-          snprintf(buf, sizeof(buf), "gunzip -qc \"%s\"", filename);
+-          if (!(mdata->stream.file = s_popen(buf, "r")))
+-              return (XpmOpenFailed);
+-
+-      } else {
+-# ifdef STAT_ZFILE
+-          if (!(compressfile = (char *) XpmMalloc(len + 4)))
++      int fd = open(filename, O_RDONLY);
++#if defined(NO_ZPIPE)
++      if ( fd < 0 )
++          return XpmOpenFailed;
++#else
++      const char* ext = NULL;
++      if ( fd >= 0 )
++          ext = strrchr(filename, '.');
++#ifdef STAT_ZFILE /* searching for z-files if the given name not found */
++      else
++      {
++          size_t len = strlen(filename);
++          char *compressfile = (char *) XpmMalloc(len + 4);
++          if ( !compressfile )
+               return (XpmNoMemory);
+-
+-          snprintf(compressfile, len+4, "%s.Z", filename);
+-          if (!stat(compressfile, &status)) {
+-              snprintf(buf, sizeof(buf), "uncompress -c \"%s\"", compressfile);
+-              if (!(mdata->stream.file = s_popen(buf, "r"))) {
++          strcpy(compressfile, filename);
++          strcpy(compressfile + len, ext = ".Z");
++          fd = open(compressfile, O_RDONLY);
++          if ( fd < 0 )
++          {
++              strcpy(compressfile + len, ext = ".gz");
++              fd = open(compressfile, O_RDONLY);
++              if ( fd < 0 )
++              {
+                   XpmFree(compressfile);
+-                  return (XpmOpenFailed);
+-              }
+-              mdata->type = XPMPIPE;
+-          } else {
+-              snprintf(compressfile, len+4, "%s.gz", filename);
+-              if (!stat(compressfile, &status)) {
+-                  snprintf(buf, sizeof(buf), "gunzip -c \"%s\"", compressfile);
+-                  if (!(mdata->stream.file = s_popen(buf, "r"))) {
+-                      XpmFree(compressfile);
+-                      return (XpmOpenFailed);
+-                  }
+-                  mdata->type = XPMPIPE;
+-              } else {
+-# endif
+-#endif
+-                  if (!(mdata->stream.file = fopen(filename, "r"))) {
+-#if !defined(NO_ZPIPE) && defined(STAT_ZFILE)
+-                      XpmFree(compressfile);
+-#endif
+-                      return (XpmOpenFailed);
+-                  }
+-                  mdata->type = XPMFILE;
+-#ifndef NO_ZPIPE
+-# ifdef STAT_ZFILE
++                  return XpmOpenFailed;
+               }
+           }
+           XpmFree(compressfile);
+-# endif
+       }
+ #endif
++      if ( ext && !strcmp(ext, ".Z") )
++      {
++          mdata->type = XPMPIPE;
++          mdata->stream.file = xpmPipeThrough(fd, "uncompress", "-c", "r");
++      }
++      else if ( ext && !strcmp(ext, ".gz") )
++      {
++          mdata->type = XPMPIPE;
++          mdata->stream.file = xpmPipeThrough(fd, "gunzip", "-qc", "r");
++      }
++      else
++#endif /* z-files */
++      {
++          mdata->type = XPMFILE;
++          mdata->stream.file = fdopen(fd, "r");
++      }
++      if (!mdata->stream.file)
++      {
++          close(fd);
++          return (XpmOpenFailed);
++      }
+     }
+     mdata->CommentLength = 0;
+ #ifdef CXPMPROG
+@@ -273,15 +308,6 @@
+ xpmDataClose(mdata)
+     xpmData *mdata;
+ {
+-    switch (mdata->type) {
+-    case XPMFILE:
+-      if (mdata->stream.file != (stdin))
+-          fclose(mdata->stream.file);
+-      break;
+-#ifndef NO_ZPIPE
+-    case XPMPIPE:
++    if (mdata->stream.file != (stdin))
+       fclose(mdata->stream.file);
+-      break;
+-#endif
+-    }
+ }
+Index: lesstif2-0.95.0/lib/Xm-2.1/XpmWrFFrI.c
+===================================================================
+--- lesstif2-0.95.0.orig/lib/Xm-2.1/XpmWrFFrI.c        2005-04-13 20:03:27.000000000 +0200
++++ lesstif2-0.95.0/lib/Xm-2.1/XpmWrFFrI.c     2006-07-11 11:13:29.000000000 +0200
+@@ -50,11 +50,15 @@
+    DebugUtil.h! */
+ #include <stdio.h>
+ #include <string.h>
++#include <errno.h>
+ #include <ctype.h>
+ #ifdef HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+ #endif
++#ifdef HAVE_SYS_WAIT_H
++#include <sys/wait.h>
++#endif
+ #ifdef HAVE_SYS_STAT_H
+ #include <sys/stat.h>
+ #endif
+@@ -94,11 +98,6 @@
+       else return (XpmFileInvalid); }
+ #endif
+-#if !defined(NO_ZPIPE) && defined(WIN32)
+-# define popen _popen
+-# define pclose _pclose
+-#endif
+-
+ /* MS Windows define a function called WriteFile @#%#&!!! */
+ LFUNC(xpmWriteFile, int, (FILE *file, XpmImage *image, char *name,
+                         XpmInfo *info));
+@@ -354,58 +353,48 @@
+     fprintf(file, ",\n\"XPMENDEXT\"");
+ }
++
++#ifndef NO_ZPIPE
++FUNC(xpmPipeThrough, FILE*, (int fd,
++                           const char* cmd,
++                           const char* arg1,
++                           const char* mode));
++#endif
++
+ /*
+  * open the given file to be written as an xpmData which is returned
+  */
+-#ifndef NO_ZPIPE
+-      FILE *s_popen(char *cmd, const char *type);
+-#else
+-#     define s_popen popen
+-#endif
+ static int
+ OpenWriteFile(filename, mdata)
+     char *filename;
+     xpmData *mdata;
+ {
+-#ifndef NO_ZPIPE
+-    char buf[BUFSIZ];
+-
+-#endif
+-
+     if (!filename) {
+       mdata->stream.file = (stdout);
+       mdata->type = XPMFILE;
+     } else {
+ #ifndef NO_ZPIPE
+-      size_t len = strlen(filename);
+-
+-      if(len == 0                        ||
+-         filename[0] == '/'              ||
+-         strstr(filename, "../") != NULL ||
+-         filename[len-1] == '/')
+-              return(XpmOpenFailed);
+-
++      size_t len;
++#endif
++      int fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
++      if ( fd < 0 )
++          return(XpmOpenFailed);
++#ifndef NO_ZPIPE
++      len = strlen(filename);
+       if (len > 2 && !strcmp(".Z", filename + (len - 2))) {
+-          snprintf(buf, sizeof(buf), "compress > \"%s\"", filename);
+-          if (!(mdata->stream.file = s_popen(buf, "w")))
+-              return (XpmOpenFailed);
+-
++          mdata->stream.file = xpmPipeThrough(fd, "compress", NULL, "w");
+           mdata->type = XPMPIPE;
+       } else if (len > 3 && !strcmp(".gz", filename + (len - 3))) {
+-          snprintf(buf, sizeof(buf), "gzip -q > \"%s\"", filename);
+-          if (!(mdata->stream.file = s_popen(buf, "w")))
+-              return (XpmOpenFailed);
+-
++          mdata->stream.file = xpmPipeThrough(fd, "gzip", "-q", "w");
+           mdata->type = XPMPIPE;
+-      } else {
++      } else
+ #endif
+-          if (!(mdata->stream.file = fopen(filename, "w")))
+-              return (XpmOpenFailed);
+-
++      {
++          mdata->stream.file = fdopen(fd, "w");
+           mdata->type = XPMFILE;
+-#ifndef NO_ZPIPE
+       }
+-#endif
++      if (!mdata->stream.file)
++          return (XpmOpenFailed);
+     }
+     return (XpmSuccess);
+ }
+@@ -417,15 +406,6 @@
+ xpmDataClose(mdata)
+     xpmData *mdata;
+ {
+-    switch (mdata->type) {
+-    case XPMFILE:
+-      if (mdata->stream.file != (stdout))
+-          fclose(mdata->stream.file);
+-      break;
+-#ifndef NO_ZPIPE
+-    case XPMPIPE:
++    if (mdata->stream.file != (stdout))
+       fclose(mdata->stream.file);
+-      break;
+-#endif
+-    }
+ }
diff --git a/packages/lesstif/files/021_xim_chained_list_crash.diff b/packages/lesstif/files/021_xim_chained_list_crash.diff
new file mode 100644 (file)
index 0000000..10bdf8d
--- /dev/null
@@ -0,0 +1,24 @@
+diff -ru lesstif2-0.94.4-old/lib/Xm-2.1/XmIm.c lesstif2-0.94.4/lib/Xm-2.1/XmIm.c
+--- lesstif2-0.94.4-old/lib/Xm-2.1/XmIm.c      2004-10-20 21:32:11.000000000 +0200
++++ lesstif2-0.94.4/lib/Xm-2.1/XmIm.c  2007-03-28 14:39:27.000000000 +0200
+@@ -133,7 +133,10 @@
+               p->next = q->next;
+       }
+-      XtFree((char *)stuff);
++      /* if count!=0 then someone uses the stuff as orig_xim
++         so unlink it but not free it */
++      if (!stuff->count)
++              XtFree((char *)stuff);
+ }
+ /*
+@@ -1060,6 +1063,8 @@
+                  XCloseIM(stuff->xim);
+               DEBUGOUT(_LtDebug(__FILE__, w, "XCloseIM(%p)\n", stuff->xim));
+               stuff->orig_xim->xim = NULL;
++              /* stuff->orig_xim is now useless */
++              XtFree(stuff->orig_xim);
+       } else {
+               DEBUGOUT(_LtDebug(__FILE__, w, "XmImCloseXIM(%p), count -> %d\n",
+                       stuff->xim, stuff->orig_xim->count));
diff --git a/packages/lesstif/files/030_manpage.diff b/packages/lesstif/files/030_manpage.diff
new file mode 100644 (file)
index 0000000..da63632
--- /dev/null
@@ -0,0 +1,11 @@
+--- lesstif2-0.94.4.orig/doc/lessdox/clients/mwm.1
++++ lesstif2-0.94.4/doc/lessdox/clients/mwm.1
+@@ -88,7 +88,7 @@
+ The resources are documented in the app defaults file for
+ .BR mwm ,
+-.I usr/X11R6/lib/X11/app-defaults/Mwm .
++.IR /etc/X11/app-defaults/Mwm .
+ .SH COPYING
+ See the file COPYING which accompanies this distribution of mwm.
diff --git a/packages/lesstif/files/ac_debug.m4.diff b/packages/lesstif/files/ac_debug.m4.diff
new file mode 100644 (file)
index 0000000..3fe6e83
--- /dev/null
@@ -0,0 +1,95 @@
+Index: lesstif2-0.95.0/ac_debug.m4
+===================================================================
+--- lesstif2-0.95.0.orig/ac_debug.m4   2004-02-01 16:49:40.000000000 +0100
++++ lesstif2-0.95.0/ac_debug.m4        2006-07-11 11:11:36.000000000 +0200
+@@ -4,6 +4,90 @@
+ dnl Source code which depends on this is mostly in
+ dnl DebugUtil.c/.h
+ dnl
++AC_DEFUN(LT_WITH_DMALLOC,
++[AC_MSG_CHECKING(if malloc debugging is wanted)
++AC_ARG_WITH(dmalloc,
++[  --with-dmalloc[=path]   use dmalloc, see INSTALL(.html) for reference],
++[if test "$withval" = no; then
++  AC_MSG_RESULT(no)
++else
++dnl We overwrite the variables since we won't continue in
++dnl case of an error!
++dnl We modify CFLAGS, and also link libs (LDFLAGS) and programs (LIBS)
++  if test "$withval" != yes; then
++dnl  a path was given
++     CFLAGS="$CFLAGS -I$withval/include -DDMALLOC_FUNC_CHECK"
++
++     LDFLAGS="$LDFLAGS -L$withval/lib -ldmalloc"
++     LIBS="$LIBS -L$withval/lib -ldmalloc"
++  else
++dnl  no path was given
++     CFLAGS="$CFLAGS -DDMALLOC_FUNC_CHECK"
++     LDFLAGS="$LDFLAGS -ldmalloc"
++     LIBS="$LIBS -ldmalloc"
++  fi
++  AC_TRY_LINK(
++  [#include <dmalloc.h>],
++  [char *ptr;
++  ptr=malloc(1);
++  free(ptr);
++  ],
++  [AC_DEFINE(WITH_DMALLOC,1,
++            [Define if using the dmalloc debugging malloc package])
++  AC_MSG_RESULT(Using dmalloc)],
++  AC_MSG_ERROR(dmalloc not found)
++  )
++fi],
++[AC_MSG_RESULT(no)])
++])
++
++
++dnl
++dnl Enable another malloc checker for debugging purposes
++dnl Source code which depends on this is mostly in
++dnl DebugUtil.c/.h
++dnl
++AC_DEFUN(LT_WITH_DBMALLOC,
++[AC_MSG_CHECKING(if malloc debugging is wanted)
++AC_ARG_WITH(dbmalloc,
++[  --with-dbmalloc[=path]   use dbmalloc, see INSTALL(.html) for reference],
++[if test "$withval" = no; then
++  AC_MSG_RESULT(no)
++else
++dnl We overwrite the variables since we won't continue in
++dnl case of an error!
++dnl We modify CFLAGS, and also link libs (LDFLAGS) and programs (LIBS)
++  if test "$withval" != yes; then
++dnl  a path was given
++     CFLAGS="$CFLAGS -I$withval/include"
++
++     LDFLAGS="$LDFLAGS -L$withval/lib -ldbmalloc"
++     LIBS="$LIBS -L$withval/lib -ldbmalloc"
++  else
++dnl  no path was given
++     LDFLAGS="$LDFLAGS -ldbmalloc"
++     LIBS="$LIBS -ldbmalloc"
++  fi
++  AC_TRY_LINK(
++  [#include <dbmalloc.h>],
++  [char *ptr;
++  ptr=malloc(1);
++  free(ptr);
++  ],
++  [AC_DEFINE(WITH_DBMALLOC,1,
++            [Define if using the dbmalloc debugging malloc package])
++  AC_MSG_RESULT(Using dbmalloc)],
++  AC_MSG_ERROR(dbmalloc not found)
++  )
++fi],
++[AC_MSG_RESULT(no)])
++])
++dnl
++dnl Enable malloc checker for debugging purposes
++dnl See http://dmalloc.com, INSTALL(.html) for references to this.
++dnl Source code which depends on this is mostly in
++dnl DebugUtil.c/.h
++dnl
+ AC_DEFUN([LT_WITH_DMALLOC],
+ [AC_MSG_CHECKING(if malloc debugging is wanted)
+ AC_ARG_WITH(dmalloc,
diff --git a/packages/lesstif/files/ac_find_xft.m4.diff b/packages/lesstif/files/ac_find_xft.m4.diff
new file mode 100644 (file)
index 0000000..69529b8
--- /dev/null
@@ -0,0 +1,304 @@
+Index: lesstif2-0.95.0/ac_find_xft.m4
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ lesstif2-0.95.0/ac_find_xft.m4     2006-07-11 11:11:44.000000000 +0200
+@@ -0,0 +1,299 @@
++dnl
++dnl $Header: /home/kobras/cvsroot/debian/lesstif1-1/ac_find_xft.m4,v 1.1 2004/05/27 10:48:25 kobras Exp $
++dnl
++dnl $XFree86: xc/lib/fontconfig/configure.in,v 1.7 2002/08/01 15:57:25 keithp Exp $
++dnl
++dnl Copyright Â© 2002 Keith Packard, member of The XFree86 Project, Inc.
++dnl Manipulated into AC_FIND_XFT macro by Danny Backx (also Â© 2002).
++dnl
++dnl Permission to use, copy, modify, distribute, and sell this software and its
++dnl documentation for any purpose is hereby granted without fee, provided that
++dnl the above copyright notice appear in all copies and that both that
++dnl copyright notice and this permission notice appear in supporting
++dnl documentation, and that the name of Keith Packard not be used in
++dnl advertising or publicity pertaining to distribution of the software without
++dnl specific, written prior permission.  Keith Packard makes no
++dnl representations about the suitability of this software for any purpose.  It
++dnl is provided "as is" without express or implied warranty.
++dnl
++dnl KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++dnl INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++dnl EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++dnl CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++dnl DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++dnl TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++dnl PERFORMANCE OF THIS SOFTWARE.
++dnl
++
++AC_DEFUN(AC_FIND_XFT,
++[
++AH_TEMPLATE([HAVE_FREETYPE], [We have the FreeType library])
++AH_TEMPLATE([HAVE_FONTCONFIG], [We have the fontconfig library])
++AH_TEMPLATE([HAVE_XRENDER], [We have the fontconfig library])
++AH_TEMPLATE([FC_DEFAULT_FONTS], [We have the fontconfig library])
++AH_TEMPLATE([X_FONT_DIR], [We have the fontconfig library])
++AH_TEMPLATE([CONFDIR], [We have the fontconfig library])
++AH_TEMPLATE([USE_XFT], [We have the fontconfig library])
++
++AC_ARG_WITH(freetype_includes, [  --with-freetype-includes=DIR  Use FreeType includes in DIR], freetype_includes=$withval, freetype_includes=yes)
++AC_ARG_WITH(freetype_lib,      [  --with-freetype-lib=DIR       Use FreeType library in DIR], freetype_lib=$withval, freetype_lib=yes)
++AC_ARG_WITH(freetype_config,   [  --with-freetype-config=PROG   Use FreeType configuration program PROG], freetype_config=$withval, freetype_config=yes)
++dnl AC_ARG_WITH(expat,             [  --with-expat=DIR              Use Expat in DIR], expat=$withval, expat=yes)
++dnl AC_ARG_WITH(expat_includes,    [  --with-expat-includes=DIR     Use Expat includes in DIR], expat_includes=$withval, expat_includes=yes)
++dnl AC_ARG_WITH(expat_lib,         [  --with-expat-lib=DIR          Use Expat library in DIR], expat_lib=$withval, expat_lib=yes)
++AC_ARG_WITH(default_fonts,     [  --with-default-fonts=DIR      Use fonts from DIR when config is busted], defaultfonts="$withval", default_fonts=yes)
++dnl AC_ARG_WITH(confdir,           [  --with-confdir=DIR            Use DIR to store configuration files (default /etc/fonts)], confdir="$withval", confdir=yes)
++AC_ARG_WITH(fontconfig_includes, [  --with-fontconfig-includes=DIR  Use Fontconfig includes in DIR], fontconfig_includes=$withval, fontconfig_includes=yes)
++AC_ARG_WITH(fontconfig_lib,      [  --with-fontconfig-lib=DIR       Use Fontconfig library in DIR], fontconfig_lib=$withval, fontconfig_lib=yes)
++AC_ARG_WITH(fontconfig_config,   [  --with-fontconfig-config=PROG  Use Fontconfig configuration program PROG], fontconfig_config=$withval, fontconfig_config=yes)
++AC_ARG_ENABLE(xrender,   [  --enable-xrender  Enable Xrender])
++
++# Using x libraries, set X font directory
++case "$no_x" in
++yes)
++      ;;
++*)
++      X_FONT_DIR="$x_libraries/X11/fonts"
++      AC_DEFINE_UNQUOTED(X_FONT_DIR,$X_FONT_DIR)
++      ;;
++esac
++AC_SUBST(X_FONT_DIR)
++
++#
++# Check freetype configuration
++#
++case "$freetype_config" in
++no)
++      ;;
++yes)
++      AC_CHECK_PROG(ft_config,freetype-config,freetype-config,no)
++      ;;
++*)
++      ft_config="$freetype_config"
++      ;;
++esac
++
++case "$freetype_includes" in
++no)
++      FREETYPE_CFLAGS=""
++      ;;
++yes)
++      case "$ft_config" in
++      no)
++              FREETYPE_CFLAGS=""
++              ;;
++      *)
++              FREETYPE_CFLAGS="`$ft_config --cflags`"
++              ;;
++      esac
++      ;;
++*)
++      FREETYPE_CFLAGS="-I$freetype_includes"
++      ;;
++esac
++
++case "$freetype_lib" in
++no)
++      freetype_lib=""
++      ;;
++yes)
++      case "$ft_config" in
++      no)
++              freetype_lib=""
++              ;;
++      *)
++              freetype_lib="`$ft_config --libs`"
++              ;;
++      esac
++      ;;
++*)
++      freetype_lib="-L$freetype_lib -lfreetype"
++      ;;
++esac
++
++saved_LIBS="$LIBS"
++LIBS="$LIBS $freetype_lib"
++saved_CPPFLAGS="$CPPFLAGS"
++CPPFLAGS="$CPPFLAGS $FREETYPE_CFLAGS"
++AC_CHECK_HEADERS(freetype/freetype.h)
++
++HAVEFREETYPE="no"
++case "$ac_cv_header_freetype_freetype_h" in
++no)
++      CPPFLAGS="$saved_CPPFLAGS"
++      LIBS="$saved_LIBS"
++      ;;
++yes)
++      AC_CHECK_FUNCS(FT_Init_FreeType)
++      case "$ac_cv_func_FT_Init_FreeType" in
++      no)
++              CPPFLAGS="$saved_CPPFLAGS"
++              LIBS="$saved_LIBS"
++              ;;
++      yes)
++              HAVEFREETYPE="yes"
++              AC_DEFINE(HAVE_FREETYPE)
++              AC_SUBST(FREETYPE_CFLAGS)
++              ;;
++      esac
++      ;;
++esac
++
++case "$default_fonts" in
++yes)
++      FC_DEFAULT_FONTS="/usr/share/fonts"
++      AC_DEFINE_UNQUOTED(FC_DEFAULT_FONTS, "/usr/share/fonts")
++      ;;
++*)
++      FC_DEFAULT_FONTS="$default_fonts"
++      AC_DEFINE_UNQUOTED(FC_DEFAULT_FONTS, "$default_fonts")
++      ;;
++esac
++
++AC_SUBST(FC_DEFAULT_FONTS)
++
++#
++# Set CONFDIR and FONTCONFIG_PATH
++#
++
++case "$confdir" in
++no|yes)
++      confdir=/etc/fonts
++      ;;
++*)
++      ;;
++esac
++AC_SUBST(confdir)
++CONFDIR='${confdir}'
++AC_DEFINE_UNQUOTED(CONFDIR, "$CONFDIR")
++AC_SUBST(CONFDIR)
++
++#
++# Check X configuration
++#
++HAVEXRENDER="no"
++case "$enable_xrender" in
++no)
++      ;;
++*)
++      XRENDER_CFLAGS="-I$x_includes"
++      XRENDER_LIBS="-L$x_libraries -lXft -lXrender"
++
++      saved_LIBS="$LIBS"
++      LIBS="$LIBS $XRENDER_LIBS"
++      saved_CPPFLAGS="$CPPFLAGS"
++      CPPFLAGS="$CPPFLAGS $XRENDER_CFLAGS"
++      AC_CHECK_HEADERS(X11/extensions/Xrender.h)
++
++      case "$ac_cv_header_X11_extensions_Xrender_h" in
++      no)
++              CPPFLAGS="$saved_CPPFLAGS"
++              LIBS="$saved_LIBS"
++              ;;
++      yes)
++              AC_CHECK_FUNCS(XRenderParseColor)
++              case "$ac_cv_func_XRenderParseColor" in
++              no)
++                      CPPFLAGS="$saved_CPPFLAGS"
++                      LIBS="$saved_LIBS"
++                      ;;
++              yes)
++                      HAVEXRENDER="yes"
++                      AC_DEFINE(HAVE_XRENDER)
++                      AC_SUBST(XRENDER_CFLAGS)
++                      AC_SUBST(XRENDER_LIBS)
++                      ;;
++              esac
++              ;;
++      esac
++
++      ;;
++esac
++
++#
++# Check fontconfig configuration
++#
++case "$fontconfig_config" in
++no)
++      ;;
++yes)
++      AC_CHECK_PROG(fc_config,fontconfig-config,fontconfig-config,no)
++      ;;
++*)
++      fc_config="$fontconfig_config"
++      ;;
++esac
++
++case "$fontconfig_includes" in
++no)
++      FONTCONFIG_CFLAGS=""
++      ;;
++yes)
++      case "$fc_config" in
++      no)
++              FONTCONFIG_CFLAGS=""
++              ;;
++      *)
++              FONTCONFIG_CFLAGS="`$fc_config --cflags`"
++              ;;
++      esac
++      ;;
++*)
++      FONTCONFIG_CFLAGS="-I$fontconfig_includes"
++      ;;
++esac
++
++case "$fontconfig_lib" in
++no)
++      fontconfig_lib=""
++      ;;
++yes)
++      case "$fc_config" in
++      no)
++              fontconfig_lib=""
++              ;;
++      *)
++              FONTCONFIG_LIBS="`$fc_config --libs`"
++              ;;
++      esac
++      ;;
++*)
++      FONTCONFIG_LIBS="-L$fontconfig_lib -lfontconfig"
++      ;;
++esac
++
++saved_LIBS="$LIBS"
++LIBS="$LIBS $FONTCONFIG_LIBS"
++saved_CPPFLAGS="$CPPFLAGS"
++CPPFLAGS="$CPPFLAGS $FONTCONFIG_CFLAGS"
++AC_CHECK_HEADERS(fontconfig/fontconfig.h)
++
++case "$ac_cv_header_fontconfig_fontconfig_h" in
++no)
++      CPPFLAGS="$saved_CPPFLAGS"
++      LIBS="$saved_LIBS"
++      ;;
++yes)
++      AC_CHECK_FUNCS(FcInit)
++      case "$ac_cv_func_FcInit" in
++      no)
++              CPPFLAGS="$saved_CPPFLAGS"
++              LIBS="$saved_LIBS"
++              ;;
++      yes)
++              AC_DEFINE(HAVE_FONTCONFIG)
++              AC_SUBST(FONTCONFIG_CFLAGS)
++              AC_SUBST(FONTCONFIG_LIBS)
++              ;;
++      esac
++      ;;
++esac
++
++dnl
++dnl Should this be conditionally defined ?
++dnl
++if test "$HAVEXRENDER" = "yes" -a "$HAVEFREETYPE" = "yes"
++then
++      AC_DEFINE(USE_XFT)
++fi
++])
diff --git a/packages/lesstif/files/ac_have_libxp.m4.diff b/packages/lesstif/files/ac_have_libxp.m4.diff
new file mode 100644 (file)
index 0000000..577bd5d
--- /dev/null
@@ -0,0 +1,57 @@
+Index: lesstif2-0.95.0/ac_have_libxp.m4
+===================================================================
+--- lesstif2-0.95.0.orig/ac_have_libxp.m4      2004-02-01 16:49:40.000000000 +0100
++++ lesstif2-0.95.0/ac_have_libxp.m4   2006-07-11 11:11:36.000000000 +0200
+@@ -11,6 +11,52 @@
+ dnl Makefiles. Perhaps one should immediately add those libs
+ dnl to link commands which include libXm version2.1?!
+ dnl
++AC_DEFUN(LT_HAVE_LIBXP,
++[AC_REQUIRE([AC_PATH_X])
++AC_CACHE_CHECK(whether libXp is available, lt_cv_libxp,
++[lt_save_CFLAGS="$CFLAGS"
++lt_save_CPPFLAGS="$CPPFLAGS"
++lt_save_LIBS="$LIBS"
++LIBS="$X_LIBS -lXp -lXext -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $LIBS"
++CFLAGS="$X_CFLAGS $CFLAGS"
++CPPFLAGS="$X_CFLAGS $CPPFLAGS"
++AC_TRY_LINK([
++#include <X11/Intrinsic.h>
++#include <X11/extensions/Print.h>
++],[
++Display *display=NULL;
++short   major_version, minor_version;
++Status rc;
++rc=XpQueryVersion(display, &major_version, &minor_version);
++],
++lt_cv_libxp=yes,
++lt_cv_libxp=no)
++])
++if test $lt_cv_libxp = yes; then
++  AC_DEFINE(HAVE_LIB_XP)
++  LT_HAVELIBXP=1
++else
++  LT_HAVELIBXP=0 
++fi
++AM_CONDITIONAL(Have_Libxp, test "$lt_cv_libxp" = "yes")
++AC_SUBST(LT_HAVELIBXP)
++CFLAGS="$lt_save_CFLAGS"
++CPPFLAGS="$lt_save_CPPFLAGS"
++LIBS="$lt_save_LIBS"
++])
++dnl
++dnl Check for libXp
++dnl In fact this check ensures that
++dnl  - <X11/extensions/Print.h> and
++dnl  - both libXp and libXext
++dnl are in place
++dnl Perhaps AC_CHECK_LIB() could be used as well, but
++dnl requires the same amount of work to get all linker
++dnl flags and additional libraries specified.
++dnl If the test succeeds 'Have_Libxp' will be defined within our 
++dnl Makefiles. Perhaps one should immediately add those libs
++dnl to link commands which include libXm version2.1?!
++dnl
+ AC_DEFUN([LT_HAVE_LIBXP],
+ [AC_REQUIRE([AC_PATH_X])
+ AC_CACHE_CHECK(whether libXp is available, lt_cv_libxp,
diff --git a/packages/lesstif/files/aclocal.m4.diff b/packages/lesstif/files/aclocal.m4.diff
new file mode 100644 (file)
index 0000000..6ce3f8a
--- /dev/null
@@ -0,0 +1,2746 @@
+Index: lesstif2-0.95.0/aclocal.m4
+===================================================================
+--- lesstif2-0.95.0.orig/aclocal.m4    2006-06-10 11:35:23.000000000 +0200
++++ lesstif2-0.95.0/aclocal.m4 2006-07-11 11:11:59.000000000 +0200
+@@ -1,7 +1,7 @@
+-# generated automatically by aclocal 1.9.4 -*- Autoconf -*-
++# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
+-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+-# Free Software Foundation, Inc.
++# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
++# 2005  Free Software Foundation, Inc.
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+@@ -13,7 +13,7 @@
+ # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+-# serial 47 AC_PROG_LIBTOOL
++# serial 48 Debian 1.5.22-4 AC_PROG_LIBTOOL
+ # AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED)
+@@ -143,7 +143,7 @@
+ default_ofile=libtool
+ can_build_shared=yes
+-# All known linkers require a `.a' archive for static linking (except M$VC,
++# All known linkers require a `.a' archive for static linking (except MSVC,
+ # which needs '.lib').
+ libext=a
+ ltmain="$ac_aux_dir/ltmain.sh"
+@@ -163,6 +163,7 @@
+ test -z "$AS" && AS=as
+ test -z "$CC" && CC=cc
+ test -z "$LTCC" && LTCC=$CC
++test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+ test -z "$DLLTOOL" && DLLTOOL=dlltool
+ test -z "$LD" && LD=ld
+ test -z "$LN_S" && LN_S="ln -s"
+@@ -182,10 +183,10 @@
+ if test -n "$RANLIB"; then
+   case $host_os in
+   openbsd*)
+-    old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
++    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+     ;;
+   *)
+-    old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
++    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+     ;;
+   esac
+   old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+@@ -233,6 +234,9 @@
+ # If no C compiler was specified, use CC.
+ LTCC=${LTCC-"$CC"}
++# If no C compiler flags were specified, use CFLAGS.
++LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
++
+ # Allow CC to be a program name with arguments.
+ compiler=$CC
+ ])# _LT_AC_SYS_COMPILER
+@@ -261,7 +265,7 @@
+ AC_DEFUN([_LT_COMPILER_BOILERPLATE],
+ [ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" >conftest.$ac_ext
+-eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d' >conftest.err
++eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+ _lt_compiler_boilerplate=`cat conftest.err`
+ $rm conftest*
+ ])# _LT_COMPILER_BOILERPLATE
+@@ -274,7 +278,7 @@
+ AC_DEFUN([_LT_LINKER_BOILERPLATE],
+ [ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_link_test_code" >conftest.$ac_ext
+-eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d' >conftest.err
++eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+ _lt_linker_boilerplate=`cat conftest.err`
+ $rm conftest*
+ ])# _LT_LINKER_BOILERPLATE
+@@ -359,8 +363,8 @@
+ # find a string as large as possible, as long as the shell can cope with it
+   for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
+     # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+-    if (echo_test_string="`eval $cmd`") 2>/dev/null &&
+-       echo_test_string="`eval $cmd`" &&
++    if (echo_test_string=`eval $cmd`) 2>/dev/null &&
++       echo_test_string=`eval $cmd` &&
+        (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+     then
+       break
+@@ -529,7 +533,7 @@
+   # Find out which ABI we are using.
+   echo 'int i;' > conftest.$ac_ext
+   if AC_TRY_EVAL(ac_compile); then
+-    case "`/usr/bin/file conftest.o`" in
++    case `/usr/bin/file conftest.o` in
+     *32-bit*)
+       case $host in
+         x86_64-*linux*)
+@@ -580,6 +584,22 @@
+     CFLAGS="$SAVE_CFLAGS"
+   fi
+   ;;
++sparc*-*solaris*)
++  # Find out which ABI we are using.
++  echo 'int i;' > conftest.$ac_ext
++  if AC_TRY_EVAL(ac_compile); then
++    case `/usr/bin/file conftest.o` in
++    *64-bit*)
++      case $lt_cv_prog_gnu_ld in
++      yes*) LD="${LD-ld} -m elf64_sparc" ;;
++      *)    LD="${LD-ld} -64" ;;
++      esac
++      ;;
++    esac
++  fi
++  rm -rf conftest*
++  ;;
++
+ AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+ [*-*-cygwin* | *-*-mingw* | *-*-pw32*)
+   AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+@@ -611,7 +631,7 @@
+    # with a dollar sign (not a hyphen), so the echo should work correctly.
+    # The option is referenced via a variable to avoid confusing sed.
+    lt_compile=`echo "$ac_compile" | $SED \
+-   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
++   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+    -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+    -e 's:$: $lt_compiler_flag:'`
+    (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+@@ -622,9 +642,9 @@
+    if (exit $ac_status) && test -s "$ac_outfile"; then
+      # The compiler can only warn and ignore the option if not recognized
+      # So say no if there are warnings other than the usual output.
+-     $echo "X$_lt_compiler_boilerplate" | $Xsed >conftest.exp
+-     $SED '/^$/d' conftest.err >conftest.er2
+-     if test ! -s conftest.err || diff conftest.exp conftest.er2 >/dev/null; then
++     $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
++     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
++     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+        $2=yes
+      fi
+    fi
+@@ -650,13 +670,13 @@
+    LDFLAGS="$LDFLAGS $3"
+    printf "$lt_simple_link_test_code" > conftest.$ac_ext
+    if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+-     # The compiler can only warn and ignore the option if not recognized
++     # The linker can only warn and ignore the option if not recognized
+      # So say no if there are warnings
+      if test -s conftest.err; then
+        # Append any errors to the config.log.
+        cat conftest.err 1>&AS_MESSAGE_LOG_FD
+-       $echo "X$_lt_linker_boilerplate" | $Xsed > conftest.exp
+-       $SED '/^$/d' conftest.err >conftest.er2
++       $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
++       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+        if diff conftest.exp conftest.er2 >/dev/null; then
+          $2=yes
+        fi
+@@ -725,25 +745,42 @@
+     elif test -x /usr/sbin/sysctl; then
+       lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+     else
+-      lt_cv_sys_max_cmd_len=65536 # usable default for *BSD
++      lt_cv_sys_max_cmd_len=65536     # usable default for all BSDs
+     fi
+     # And add a safety zone
+     lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+     lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+     ;;
++
++  interix*)
++    # We know the value 262144 and hardcode it with a safety zone (like BSD)
++    lt_cv_sys_max_cmd_len=196608
++    ;;
++
+   osf*)
+     # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+     # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+     # nice to cause kernel panics so lets avoid the loop below.
+     # First set a reasonable default.
+     lt_cv_sys_max_cmd_len=16384
+-    # 
++    #
+     if test -x /sbin/sysconfig; then
+       case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+         *1*) lt_cv_sys_max_cmd_len=-1 ;;
+       esac
+     fi
+     ;;
++  sco3.2v5*)
++    lt_cv_sys_max_cmd_len=102400
++    ;;
++  sysv5* | sco5v6* | sysv4.2uw2*)
++    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
++    if test -n "$kargmax"; then
++      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[      ]]//'`
++    else
++      lt_cv_sys_max_cmd_len=32768
++    fi
++    ;;
+   *)
+     # If test is not a shell built-in, we'll probably end up computing a
+     # maximum length that is only half of the actual maximum length, but
+@@ -775,7 +812,7 @@
+ # _LT_AC_CHECK_DLFCN
+-# --------------------
++# ------------------
+ AC_DEFUN([_LT_AC_CHECK_DLFCN],
+ [AC_CHECK_HEADERS(dlfcn.h)dnl
+ ])# _LT_AC_CHECK_DLFCN
+@@ -783,7 +820,7 @@
+ # _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+ #                           ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+-# ------------------------------------------------------------------
++# ---------------------------------------------------------------------
+ AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
+ [AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+ if test "$cross_compiling" = yes; then :
+@@ -849,17 +886,19 @@
+       else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+       /* dlclose (self); */
+     }
++  else
++    puts (dlerror ());
+     exit (status);
+ }]
+ EOF
+   if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+-    (./conftest; exit; ) 2>/dev/null
++    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+     lt_status=$?
+     case x$lt_status in
+       x$lt_dlno_uscore) $1 ;;
+       x$lt_dlneed_uscore) $2 ;;
+-      x$lt_unknown|x*) $3 ;;
++      x$lt_dlunknown|x*) $3 ;;
+     esac
+   else :
+     # compilation failed
+@@ -871,7 +910,7 @@
+ # AC_LIBTOOL_DLOPEN_SELF
+-# -------------------
++# ----------------------
+ AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
+ [AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+ if test "x$enable_dlopen" != xyes; then
+@@ -942,7 +981,7 @@
+     test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+     save_LDFLAGS="$LDFLAGS"
+-    eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
++    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+     save_LIBS="$LIBS"
+     LIBS="$lt_cv_dlopen_libs $LIBS"
+@@ -955,7 +994,7 @@
+     ])
+     if test "x$lt_cv_dlopen_self" = xyes; then
+-      LDFLAGS="$LDFLAGS $link_static_flag"
++      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+       AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+         lt_cv_dlopen_self_static, [dnl
+         _LT_AC_TRY_DLOPEN_SELF(
+@@ -1003,7 +1042,7 @@
+    # Note that $ac_compile itself does not contain backslashes and begins
+    # with a dollar sign (not a hyphen), so the echo should work correctly.
+    lt_compile=`echo "$ac_compile" | $SED \
+-   -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
++   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+    -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+    -e 's:$: $lt_compiler_flag:'`
+    (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+@@ -1015,13 +1054,13 @@
+    then
+      # The compiler can only warn and ignore the option if not recognized
+      # So say no if there are warnings
+-     $echo "X$_lt_compiler_boilerplate" | $Xsed > out/conftest.exp
+-     $SED '/^$/d' out/conftest.err >out/conftest.er2
+-     if test ! -s out/conftest.err || diff out/conftest.exp out/conftest.er2 >/dev/null; then
++     $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
++     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
++     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+        _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+      fi
+    fi
+-   chmod u+w .
++   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+    $rm conftest*
+    # SGI C++ compiler will create directory out/ii_files/ for
+    # template instantiation
+@@ -1281,7 +1320,8 @@
+       dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+       dldir=$destdir/`dirname \$dlpath`~
+       test -d \$dldir || mkdir -p \$dldir~
+-      $install_prog $dir/$dlname \$dldir/$dlname'
++      $install_prog $dir/$dlname \$dldir/$dlname~
++      chmod a+x \$dldir/$dlname'
+     postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+       dlpath=$dir/\$dldll~
+        $rm \$dlpath'
+@@ -1334,7 +1374,7 @@
+   soname_spec='${libname}${release}${major}$shared_ext'
+   shlibpath_overrides_runpath=yes
+   shlibpath_var=DYLD_LIBRARY_PATH
+-  shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
++  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+   # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+   if test "$GCC" = yes; then
+     sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+@@ -1357,22 +1397,17 @@
+   dynamic_linker=no
+   ;;
+-kfreebsd*-gnu)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=no
+-  hardcode_into_libs=yes
+-  dynamic_linker='GNU ld.so'
+-  ;;
+-
+ freebsd* | dragonfly*)
+   # DragonFly does not have aout.  When/if they implement a new
+   # versioning mechanism, adjust this.
+-  objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
++  if test -x /usr/bin/objformat; then
++    objformat=`/usr/bin/objformat`
++  else
++    case $host_os in
++    freebsd[[123]]*) objformat=aout ;;
++    *) objformat=elf ;;
++    esac
++  fi
+   version_type=freebsd-$objformat
+   case $version_type in
+     freebsd-elf*)
+@@ -1394,10 +1429,15 @@
+     shlibpath_overrides_runpath=yes
+     hardcode_into_libs=yes
+     ;;
+-  *) # from 3.2 on
++  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
++  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+     shlibpath_overrides_runpath=no
+     hardcode_into_libs=yes
+     ;;
++  freebsd*) # from 4.6 on
++    shlibpath_overrides_runpath=yes
++    hardcode_into_libs=yes
++    ;;
+   esac
+   ;;
+@@ -1417,7 +1457,7 @@
+   version_type=sunos
+   need_lib_prefix=no
+   need_version=no
+-  case "$host_cpu" in
++  case $host_cpu in
+   ia64*)
+     shrext_cmds='.so'
+     hardcode_into_libs=yes
+@@ -1457,6 +1497,18 @@
+   postinstall_cmds='chmod 555 $lib'
+   ;;
++interix3*)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=no
++  hardcode_into_libs=yes
++  ;;
++
+ irix5* | irix6* | nonstopux*)
+   case $host_os in
+     nonstopux*) version_type=nonstopux ;;
+@@ -1500,7 +1552,7 @@
+   ;;
+ # This must be Linux ELF.
+-linux*)
++linux* | k*bsd*-gnu)
+   version_type=linux
+   need_lib_prefix=no
+   need_version=no
+@@ -1514,27 +1566,10 @@
+   # before this can be enabled.
+   hardcode_into_libs=yes
+-  # find out which ABI we are using
+-  libsuff=
+-  case "$host_cpu" in
+-  x86_64*|s390x*|powerpc64*)
+-    echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+-    if AC_TRY_EVAL(ac_compile); then
+-      case `/usr/bin/file conftest.$ac_objext` in
+-      *64-bit*)
+-        libsuff=64
+-        sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}"
+-        ;;
+-      esac
+-    fi
+-    rm -rf conftest*
+-    ;;
+-  esac
+-
+   # Append ld.so.conf contents to the search path
+   if test -f /etc/ld.so.conf; then
+     lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:,  ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+-    sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra"
++    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+   fi
+   # We used to test for /lib/ld.so.1 and disable shared libraries on
+@@ -1546,7 +1581,7 @@
+   dynamic_linker='GNU/Linux ld.so'
+   ;;
+-knetbsd*-gnu)
++netbsdelf*-gnu)
+   version_type=linux
+   need_lib_prefix=no
+   need_version=no
+@@ -1555,7 +1590,7 @@
+   shlibpath_var=LD_LIBRARY_PATH
+   shlibpath_overrides_runpath=no
+   hardcode_into_libs=yes
+-  dynamic_linker='GNU ld.so'
++  dynamic_linker='NetBSD ld.elf_so'
+   ;;
+ netbsd*)
+@@ -1595,6 +1630,7 @@
+ openbsd*)
+   version_type=sunos
++  sys_lib_dlsearch_path_spec="/usr/lib"
+   need_lib_prefix=no
+   # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+   case $host_os in
+@@ -1638,13 +1674,6 @@
+   sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+   ;;
+-sco3.2v5*)
+-  version_type=osf
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  ;;
+-
+ solaris*)
+   version_type=linux
+   need_lib_prefix=no
+@@ -1670,7 +1699,7 @@
+   need_version=yes
+   ;;
+-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
++sysv4 | sysv4.3*)
+   version_type=linux
+   library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+   soname_spec='${libname}${release}${shared_ext}$major'
+@@ -1703,6 +1732,29 @@
+   fi
+   ;;
++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
++  version_type=freebsd-elf
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  hardcode_into_libs=yes
++  if test "$with_gnu_ld" = yes; then
++    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
++    shlibpath_overrides_runpath=no
++  else
++    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
++    shlibpath_overrides_runpath=yes
++    case $host_os in
++      sco3.2v5*)
++        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
++      ;;
++    esac
++  fi
++  sys_lib_dlsearch_path_spec='/usr/lib'
++  ;;
++
+ uts4*)
+   version_type=linux
+   library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+@@ -1716,6 +1768,11 @@
+ esac
+ AC_MSG_RESULT([$dynamic_linker])
+ test "$dynamic_linker" = no && can_build_shared=no
++
++variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
++if test "$GCC" = yes; then
++  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
++fi
+ ])# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+@@ -1740,6 +1797,9 @@
+       AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile'])
+     fi
+   fi
++  if test -z "$LTCFLAGS"; then
++    eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`"
++  fi
+   # Extract list of available tagged configurations in $ofile.
+   # Note that this assumes the entire list is on one line.
+@@ -1830,7 +1890,7 @@
+ # AC_LIBTOOL_WIN32_DLL
+ # --------------------
+-# declare package support for building win32 dll's
++# declare package support for building win32 DLLs
+ AC_DEFUN([AC_LIBTOOL_WIN32_DLL],
+ [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])
+ ])# AC_LIBTOOL_WIN32_DLL
+@@ -1868,7 +1928,7 @@
+ # AC_DISABLE_SHARED
+ # -----------------
+-#- set the default shared flag to --disable-shared
++# set the default shared flag to --disable-shared
+ AC_DEFUN([AC_DISABLE_SHARED],
+ [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+ AC_ENABLE_SHARED(no)
+@@ -2004,7 +2064,7 @@
+       if test -n "$file_magic_test_file"; then
+       case $deplibs_check_method in
+       "file_magic "*)
+-        file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
++        file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+         MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+           $EGREP "$file_magic_regex" > /dev/null; then
+@@ -2114,7 +2174,7 @@
+     if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+       lt_cv_path_LD="$ac_dir/$ac_prog"
+       # Check to see if the program is GNU ld.  I'd rather use --version,
+-      # but apparently some GNU ld's only accept -v.
++      # but apparently some variants of GNU ld only accept -v.
+       # Break only if it was the GNU/non-GNU ld that we prefer.
+       case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+       *GNU* | *'with BFD'*)
+@@ -2146,7 +2206,7 @@
+ AC_DEFUN([AC_PROG_LD_GNU],
+ [AC_REQUIRE([AC_PROG_EGREP])dnl
+ AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+-[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
++[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+ case `$LD -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+   lt_cv_prog_gnu_ld=yes
+@@ -2176,7 +2236,7 @@
+ case $host_os in
+   darwin*)
+     if test "$GCC" = yes; then
+-      reload_cmds='$CC -nostdlib ${wl}-r -o $output$reload_objs'
++      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+     else
+       reload_cmds='$LD$reload_flag -o $output$reload_objs'
+     fi
+@@ -2238,7 +2298,7 @@
+   lt_cv_deplibs_check_method=pass_all
+   ;;
+-freebsd* | kfreebsd*-gnu | dragonfly*)
++freebsd* | dragonfly*)
+   if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+     case $host_cpu in
+     i*86 )
+@@ -2260,7 +2320,7 @@
+ hpux10.20* | hpux11*)
+   lt_cv_file_magic_cmd=/usr/bin/file
+-  case "$host_cpu" in
++  case $host_cpu in
+   ia64*)
+     lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+     lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+@@ -2276,6 +2336,11 @@
+   esac
+   ;;
++interix3*)
++  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
++  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
++  ;;
++
+ irix5* | irix6* | nonstopux*)
+   case $LD in
+   *-32|*"-32 ") libmagic=32-bit;;
+@@ -2287,11 +2352,11 @@
+   ;;
+ # This must be Linux ELF.
+-linux*)
++linux* | k*bsd*-gnu)
+   lt_cv_deplibs_check_method=pass_all
+   ;;
+-netbsd*)
++netbsd* | netbsdelf*-gnu)
+   if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+     lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+   else
+@@ -2321,15 +2386,11 @@
+   lt_cv_deplibs_check_method=pass_all
+   ;;
+-sco3.2v5*)
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
+-
+ solaris*)
+   lt_cv_deplibs_check_method=pass_all
+   ;;
+-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
++sysv4 | sysv4.3*)
+   case $host_vendor in
+   motorola)
+     lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+@@ -2350,10 +2411,13 @@
+   siemens)
+     lt_cv_deplibs_check_method=pass_all
+     ;;
++  pc)
++    lt_cv_deplibs_check_method=pass_all
++    ;;
+   esac
+   ;;
+-sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*)
++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+   lt_cv_deplibs_check_method=pass_all
+   ;;
+ esac
+@@ -2373,36 +2437,43 @@
+   # Let the user override the test.
+   lt_cv_path_NM="$NM"
+ else
+-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+-  for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
+-    IFS="$lt_save_ifs"
+-    test -z "$ac_dir" && ac_dir=.
+-    tmp_nm="$ac_dir/${ac_tool_prefix}nm"
+-    if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+-      # Check to see if the nm accepts a BSD-compat flag.
+-      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+-      #   nm: unknown option "B" ignored
+-      # Tru64's nm complains that /dev/null is an invalid object file
+-      case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+-      */dev/null* | *'Invalid file or object type'*)
+-      lt_cv_path_NM="$tmp_nm -B"
+-      break
+-        ;;
+-      *)
+-      case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+-      */dev/null*)
+-        lt_cv_path_NM="$tmp_nm -p"
++  lt_nm_to_check="${ac_tool_prefix}nm"
++  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then 
++    lt_nm_to_check="$lt_nm_to_check nm"
++  fi
++  for lt_tmp_nm in $lt_nm_to_check; do
++    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
++      IFS="$lt_save_ifs"
++      test -z "$ac_dir" && ac_dir=.
++      tmp_nm="$ac_dir/$lt_tmp_nm"
++      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
++      # Check to see if the nm accepts a BSD-compat flag.
++      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
++      #   nm: unknown option "B" ignored
++      # Tru64's nm complains that /dev/null is an invalid object file
++      case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
++      */dev/null* | *'Invalid file or object type'*)
++        lt_cv_path_NM="$tmp_nm -B"
+         break
+         ;;
+       *)
+-        lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+-        continue # so that we can try to find one that supports BSD flags
++        case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
++        */dev/null*)
++          lt_cv_path_NM="$tmp_nm -p"
++          break
++          ;;
++        *)
++          lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
++          continue # so that we can try to find one that supports BSD flags
++          ;;
++        esac
+         ;;
+       esac
+-      esac
+-    fi
++      fi
++    done
++    IFS="$lt_save_ifs"
+   done
+-  IFS="$lt_save_ifs"
+   test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+ fi])
+ NM="$lt_cv_path_NM"
+@@ -2434,13 +2505,13 @@
+ # -----------------------------------
+ # sets LIBLTDL to the link flags for the libltdl convenience library and
+ # LTDLINCL to the include flags for the libltdl header and adds
+-# --enable-ltdl-convenience to the configure arguments.  Note that LIBLTDL
+-# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called.  If
+-# DIRECTORY is not provided, it is assumed to be `libltdl'.  LIBLTDL will
+-# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with
+-# '${top_srcdir}/' (note the single quotes!).  If your package is not
+-# flat and you're not using automake, define top_builddir and
+-# top_srcdir appropriately in the Makefiles.
++# --enable-ltdl-convenience to the configure arguments.  Note that
++# AC_CONFIG_SUBDIRS is not called here.  If DIRECTORY is not provided,
++# it is assumed to be `libltdl'.  LIBLTDL will be prefixed with
++# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/'
++# (note the single quotes!).  If your package is not flat and you're not
++# using automake, define top_builddir and top_srcdir appropriately in
++# the Makefiles.
+ AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
+ [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+   case $enable_ltdl_convenience in
+@@ -2459,13 +2530,13 @@
+ # -----------------------------------
+ # sets LIBLTDL to the link flags for the libltdl installable library and
+ # LTDLINCL to the include flags for the libltdl header and adds
+-# --enable-ltdl-install to the configure arguments.  Note that LIBLTDL
+-# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called.  If
+-# DIRECTORY is not provided and an installed libltdl is not found, it is
+-# assumed to be `libltdl'.  LIBLTDL will be prefixed with '${top_builddir}/'
+-# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single
+-# quotes!).  If your package is not flat and you're not using automake,
+-# define top_builddir and top_srcdir appropriately in the Makefiles.
++# --enable-ltdl-install to the configure arguments.  Note that
++# AC_CONFIG_SUBDIRS is not called here.  If DIRECTORY is not provided,
++# and an installed libltdl is not found, it is assumed to be `libltdl'.
++# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with
++# '${top_srcdir}/' (note the single quotes!).  If your package is not
++# flat and you're not using automake, define top_builddir and top_srcdir
++# appropriately in the Makefiles.
+ # In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+ AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
+ [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+@@ -2508,7 +2579,7 @@
+ ])# _LT_AC_LANG_CXX
+ # _LT_AC_PROG_CXXCPP
+-# ---------------
++# ------------------
+ AC_DEFUN([_LT_AC_PROG_CXXCPP],
+ [
+ AC_REQUIRE([AC_PROG_CXX])
+@@ -2557,7 +2628,7 @@
+ # AC_LIBTOOL_RC
+-# --------------
++# -------------
+ # enable support for Windows resource files
+ AC_DEFUN([AC_LIBTOOL_RC],
+ [AC_REQUIRE([LT_AC_PROG_RC])
+@@ -2594,37 +2665,6 @@
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+-#
+-# Check for any special shared library compilation flags.
+-#
+-_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)=
+-if test "$GCC" = no; then
+-  case $host_os in
+-  sco3.2v5*)
+-    _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf'
+-    ;;
+-  esac
+-fi
+-if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then
+-  AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries])
+-  if echo "$old_CC $old_CFLAGS " | grep "[[   ]]$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[        ]]" >/dev/null; then :
+-  else
+-    AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure])
+-    _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no
+-  fi
+-fi
+-
+-
+-#
+-# Check to make sure the static flag actually works.
+-#
+-AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works],
+-  _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1),
+-  $_LT_AC_TAGVAR(lt_prog_compiler_static, $1),
+-  [],
+-  [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
+-
+-
+ AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+ AC_LIBTOOL_PROG_COMPILER_PIC($1)
+ AC_LIBTOOL_PROG_CC_C_O($1)
+@@ -2633,9 +2673,9 @@
+ AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+ AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+ AC_LIBTOOL_SYS_LIB_STRIP
+-AC_LIBTOOL_DLOPEN_SELF($1)
++AC_LIBTOOL_DLOPEN_SELF
+-# Report which librarie types wil actually be built
++# Report which library types will actually be built
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+@@ -2644,7 +2684,7 @@
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+-case "$host_os" in
++case $host_os in
+ aix3*)
+   test "$enable_shared" = yes && enable_static=no
+   if test -n "$RANLIB"; then
+@@ -2694,6 +2734,7 @@
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
++_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_AC_TAGVAR(hardcode_automatic, $1)=no
+ _LT_AC_TAGVAR(module_cmds, $1)=
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)=
+@@ -2711,7 +2752,7 @@
+ _LT_AC_TAGVAR(compiler_lib_search_path, $1)=
+ # Source file extension for C++ test sources.
+-ac_ext=cc
++ac_ext=cpp
+ # Object file extension for compiled C++ test sources.
+ objext=o
+@@ -2721,7 +2762,7 @@
+ lt_simple_compile_test_code="int some_variable = 0;\n"
+ # Code to be used in simple link tests
+-lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n'
++lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }\n'
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_AC_SYS_COMPILER
+@@ -2740,12 +2781,12 @@
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+   lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+-  unset lt_cv_prog_gnu_ld
++  $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+   lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+-  unset lt_cv_path_LD
++  $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+@@ -2840,6 +2881,7 @@
+           ;;
+         esac
+       done
++      ;;
+       esac
+       exp_sym_flag='-bexport'
+@@ -2877,6 +2919,7 @@
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+       fi
++      ;;
+       esac
+       shared_flag='-shared'
+       if test "$aix_use_runtimelinking" = yes; then
+@@ -2908,12 +2951,12 @@
+       _LT_AC_SYS_LIBPATH_AIX
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+       if test "$host_cpu" = ia64; then
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+       else
+       # Determine the default libpath from the value encoded in an empty executable.
+       _LT_AC_SYS_LIBPATH_AIX
+@@ -2922,16 +2965,26 @@
+       # -berok will link without error, but may produce a broken library.
+       _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+-      # -bexpall does not export symbols beginning with underscore (_)
+-      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+       # Exported symbols can be pulled into shared objects from archives
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' '
++      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+       _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+-      # This is similar to how AIX traditionally builds it's shared libraries.
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
++      # This is similar to how AIX traditionally builds its shared libraries.
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+       fi
+     fi
+     ;;
++
++  beos*)
++    if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
++      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
++      # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
++      # support --undefined.  This deserves some investigation.  FIXME
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++    else
++      _LT_AC_TAGVAR(ld_shlibs, $1)=no
++    fi
++    ;;
++
+   chorus*)
+     case $cc_basename in
+       *)
+@@ -2941,7 +2994,6 @@
+     esac
+     ;;
+-
+   cygwin* | mingw* | pw32*)
+     # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+     # as there is no search path for DLLs.
+@@ -2951,7 +3003,7 @@
+     _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+     if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+       # If the export-symbols file already is a .def file (1st line
+       # is EXPORTS), use it as is; otherwise, prepend...
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+@@ -2960,13 +3012,13 @@
+       echo EXPORTS > $output_objdir/$soname.def;
+       cat $export_symbols >> $output_objdir/$soname.def;
+       fi~
+-      $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
++      $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+     else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+     fi
+   ;;
+       darwin* | rhapsody*)
+-        case "$host_os" in
++        case $host_os in
+         rhapsody* | darwin1.[[012]])
+          _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+          ;;
+@@ -3004,7 +3056,7 @@
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+         fi
+         _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+-        # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
++        # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+           if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+             _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+           else
+@@ -3017,7 +3069,7 @@
+          output_verbose_link_cmd='echo'
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+           _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+-          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
++          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+           _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+           _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+           ;;
+@@ -3052,7 +3104,7 @@
+   freebsd-elf*)
+     _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+     ;;
+-  freebsd* | kfreebsd*-gnu | dragonfly*)
++  freebsd* | dragonfly*)
+     # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+     # conventions
+     _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+@@ -3097,33 +3149,22 @@
+     ;;
+   hpux10*|hpux11*)
+     if test $with_gnu_ld = no; then
+-      case "$host_cpu" in
+-      hppa*64*)
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
++
++      case $host_cpu in
++      hppa*64*|ia64*)
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-        ;;
+-      ia64*)
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         ;;
+       *)
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+         ;;
+       esac
+     fi
+-    case "$host_cpu" in
+-    hppa*64*)
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
+-    ia64*)
++    case $host_cpu in
++    hppa*64*|ia64*)
+       _LT_AC_TAGVAR(hardcode_direct, $1)=no
+       _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+-                                            # but as the default
+-                                            # location of the library.
+       ;;
+     *)
+       _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+@@ -3139,9 +3180,12 @@
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+       aCC*)
+-      case "$host_cpu" in
+-      hppa*64*|ia64*)
+-        _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
++      case $host_cpu in
++      hppa*64*)
++        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++        ;;
++      ia64*)
++        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+         ;;
+       *)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+@@ -3160,9 +3204,12 @@
+       *)
+       if test "$GXX" = yes; then
+         if test $with_gnu_ld = no; then
+-          case "$host_cpu" in
+-          ia64*|hppa*64*)
+-            _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
++          case $host_cpu in
++          hppa*64*)
++            _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++            ;;
++          ia64*)
++            _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+             ;;
+           *)
+             _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+@@ -3176,6 +3223,20 @@
+       ;;
+     esac
+     ;;
++  interix3*)
++    _LT_AC_TAGVAR(hardcode_direct, $1)=no
++    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
++    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++    # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
++    # Instead, shared libraries are loaded at an image base (0x10000000 by
++    # default) and relocated if they conflict, which is a slow very memory
++    # consuming and fragmenting process.  To avoid this, we pick a random,
++    # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
++    # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
++    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++    ;;
+   irix5* | irix6*)
+     case $cc_basename in
+       CC*)
+@@ -3202,7 +3263,7 @@
+     _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+     _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+     ;;
+-  linux*)
++  linux* | k*bsd*-gnu)
+     case $cc_basename in
+       KCC*)
+       # Kuck and Associates, Inc. (KAI) C++ Compiler
+@@ -3261,7 +3322,7 @@
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive,`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
++      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+         ;;
+       cxx*)
+       # Compaq C++
+@@ -3304,7 +3365,7 @@
+       ;;
+     esac
+     ;;
+-  netbsd*)
++  netbsd* | netbsdelf*-gnu)
+     if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+       wlarc=
+@@ -3458,19 +3519,6 @@
+     # FIXME: insert proper C++ library support
+     _LT_AC_TAGVAR(ld_shlibs, $1)=no
+     ;;
+-  sco*)
+-    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-    case $cc_basename in
+-      CC*)
+-      # FIXME: insert proper C++ library support
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      ;;
+-      *)
+-      # FIXME: insert proper C++ library support
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      ;;
+-    esac
+-    ;;
+   sunos4*)
+     case $cc_basename in
+       CC*)
+@@ -3493,10 +3541,11 @@
+     case $cc_basename in
+       CC*)
+       # Sun C++ 4.2, 5.x and Centerline C++
++        _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes
+       _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-      $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
++      $CC -G${allow_undefined_flag}  ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+       _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+@@ -3516,15 +3565,7 @@
+       esac
+       _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-      # Commands to make compiler produce verbose output that lists
+-      # what "hidden" libraries, object files and flags are used when
+-      # linking a shared library.
+-      #
+-      # There doesn't appear to be a way to prevent this compiler from
+-      # explicitly linking system object files so we need to strip them
+-      # from the output so that they don't get included in the library
+-      # dependencies.
+-      output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
++      output_verbose_link_cmd='echo'
+       # Archives containing C++ object files must be created using
+       # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+@@ -3570,8 +3611,59 @@
+       ;;
+     esac
+     ;;
+-  sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*)
++  sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
++    _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
++    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
++    runpath_var='LD_RUN_PATH'
++
++    case $cc_basename in
++      CC*)
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      ;;
++      *)
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      ;;
++    esac
++    ;;
++  sysv5* | sco3.2v5* | sco5v6*)
++    # Note: We can NOT use -z defs as we might desire, because we do not
++    # link with -lc, and that would cause any symbols used from libc to
++    # always be unresolved, which means just about no library would
++    # ever link correctly.  If we're not using GNU ld we use -z text
++    # though, which does catch some bad symbols but isn't as heavy-handed
++    # as -z defs.
++    # For security reasons, it is highly recommended that you always
++    # use absolute paths for naming shared libraries, and exclude the
++    # DT_RUNPATH tag from executables and libraries.  But doing so
++    # requires that you compile everything twice, which is a pain.
++    # So that behaviour is only enabled if SCOABSPATH is set to a
++    # non-empty value in the environment.  Most likely only useful for
++    # creating official distributions of packages.
++    # This is a hack until libtool officially supports absolute path
++    # names for shared libraries.
++    _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++    _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+     _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
++    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
++    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
++    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
++    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
++    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
++    runpath_var='LD_RUN_PATH'
++
++    case $cc_basename in
++      CC*)
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
++      ;;
++      *)
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
++      ;;
++    esac
+     ;;
+   tandem*)
+     case $cc_basename in
+@@ -3608,8 +3700,6 @@
+ AC_LIBTOOL_PROG_LD_SHLIBS($1)
+ AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+ AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+-AC_LIBTOOL_SYS_LIB_STRIP
+-AC_LIBTOOL_DLOPEN_SELF($1)
+ AC_LIBTOOL_CONFIG($1)
+@@ -3627,7 +3717,7 @@
+ ])# AC_LIBTOOL_LANG_CXX_CONFIG
+ # AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME])
+-# ------------------------
++# ------------------------------------
+ # Figure out "hidden" library dependencies from verbose
+ # compiler output when linking a shared library.
+ # Parse the compiler output and extract the necessary
+@@ -3681,7 +3771,7 @@
+   # The `*' in the case matches for architectures that use `case' in
+   # $output_verbose_cmd can trigger glob expansion during the loop
+   # eval without this substitution.
+-  output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`"
++  output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"`
+   for p in `eval $output_verbose_link_cmd`; do
+     case $p in
+@@ -3757,13 +3847,37 @@
+ $rm -f confest.$objext
++# PORTME: override above test on systems where it is broken
++ifelse([$1],[CXX],
++[case $host_os in
++interix3*)
++  # Interix 3.5 installs completely hosed .la files for C++, so rather than
++  # hack all around it, let's just trust "g++" to DTRT.
++  _LT_AC_TAGVAR(predep_objects,$1)=
++  _LT_AC_TAGVAR(postdep_objects,$1)=
++  _LT_AC_TAGVAR(postdeps,$1)=
++  ;;
++
++solaris*)
++  case $cc_basename in
++  CC*)
++    # Adding this requires a known-good setup of shared libraries for
++    # Sun compiler versions before 5.6, else PIC objects from an old
++    # archive will be linked into the output, leading to subtle bugs.
++    _LT_AC_TAGVAR(postdeps,$1)='-lCstd -lCrun'
++    ;;
++  esac
++  ;;
++esac
++])
++
+ case " $_LT_AC_TAGVAR(postdeps, $1) " in
+ *" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+ esac
+ ])# AC_LIBTOOL_POSTDEP_PREDEP
+ # AC_LIBTOOL_LANG_F77_CONFIG
+-# ------------------------
++# --------------------------
+ # Ensure that the configuration vars for the C compiler are
+ # suitably defined.  Those variables are subsequently used by
+ # AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+@@ -3826,7 +3940,7 @@
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+-case "$host_os" in
++case $host_os in
+ aix3*)
+   test "$enable_shared" = yes && enable_static=no
+   if test -n "$RANLIB"; then
+@@ -3847,8 +3961,6 @@
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+-test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+-
+ _LT_AC_TAGVAR(GCC, $1)="$G77"
+ _LT_AC_TAGVAR(LD, $1)="$LD"
+@@ -3858,8 +3970,6 @@
+ AC_LIBTOOL_PROG_LD_SHLIBS($1)
+ AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+ AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+-AC_LIBTOOL_SYS_LIB_STRIP
+-
+ AC_LIBTOOL_CONFIG($1)
+@@ -3916,8 +4026,6 @@
+ AC_LIBTOOL_PROG_LD_SHLIBS($1)
+ AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+ AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+-AC_LIBTOOL_SYS_LIB_STRIP
+-AC_LIBTOOL_DLOPEN_SELF($1)
+ AC_LIBTOOL_CONFIG($1)
+@@ -3927,7 +4035,7 @@
+ # AC_LIBTOOL_LANG_RC_CONFIG
+-# --------------------------
++# -------------------------
+ # Ensure that the configuration vars for the Windows resource compiler are
+ # suitably defined.  Those variables are subsequently used by
+ # AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+@@ -3990,7 +4098,7 @@
+   # Now quote all the things that may contain metacharacters while being
+   # careful not to overquote the AC_SUBSTed values.  We take copies of the
+   # variables and quote the copies for generation of the libtool script.
+-  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
++  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
+     SED SHELL STRIP \
+     libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+     old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+@@ -4159,6 +4267,9 @@
+ # A C compiler.
+ LTCC=$lt_LTCC
++# LTCC compiler flags.
++LTCFLAGS=$lt_LTCFLAGS
++
+ # A language-specific compiler.
+ CC=$lt_[]_LT_AC_TAGVAR(compiler, $1)
+@@ -4519,7 +4630,7 @@
+   lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+   lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+   ;;
+-linux*)
++linux* | k*bsd*-gnu)
+   if test "$host_cpu" = ia64; then
+     symcode='[[ABCDGIRSTW]]'
+     lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+@@ -4532,9 +4643,18 @@
+ osf*)
+   symcode='[[BCDEGQRST]]'
+   ;;
+-solaris* | sysv5*)
++solaris*)
+   symcode='[[BDRT]]'
+   ;;
++sco3.2v5*)
++  symcode='[[DT]]'
++  ;;
++sysv4.2uw2*)
++  symcode='[[DT]]'
++  ;;
++sysv5* | sco5v6* | unixware* | OpenUNIX*)
++  symcode='[[ABDT]]'
++  ;;
+ sysv4)
+   symcode='[[DFNSTU]]'
+   ;;
+@@ -4717,6 +4837,10 @@
+       # DJGPP does not support shared libraries at all
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+       ;;
++    interix3*)
++      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
++      # Instead, we relocate shared libraries at runtime.
++      ;;
+     sysv4*MP*)
+       if test -d /usr/nec; then
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+@@ -4725,7 +4849,7 @@
+     hpux*)
+       # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+       # not for PA HP-UX.
+-      case "$host_cpu" in
++      case $host_cpu in
+       hppa*64*|ia64*)
+       ;;
+       *)
+@@ -4779,22 +4903,22 @@
+           ;;
+       esac
+       ;;
+-      freebsd* | kfreebsd*-gnu | dragonfly*)
++      freebsd* | dragonfly*)
+       # FreeBSD uses GNU C++
+       ;;
+       hpux9* | hpux10* | hpux11*)
+       case $cc_basename in
+         CC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-          _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
++          _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+           if test "$host_cpu" != ia64; then
+             _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+           fi
+           ;;
+         aCC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-          _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+-          case "$host_cpu" in
++          _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
++          case $host_cpu in
+           hppa*64*|ia64*)
+             # +Z the default
+             ;;
+@@ -4807,6 +4931,10 @@
+           ;;
+       esac
+       ;;
++      interix*)
++      # This is c89, which is MS Visual C++ (no shared libs)
++      # Anyone wants to do a port?
++      ;;
+       irix5* | irix6* | nonstopux*)
+       case $cc_basename in
+         CC*)
+@@ -4818,7 +4946,7 @@
+           ;;
+       esac
+       ;;
+-      linux*)
++      linux* | k*bsd*-gnu)
+       case $cc_basename in
+         KCC*)
+           # KAI C++ Compiler
+@@ -4835,7 +4963,7 @@
+           # Portland Group C++ compiler.
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+-          _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
++          _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+         cxx*)
+           # Compaq C++
+@@ -4861,7 +4989,7 @@
+           ;;
+       esac
+       ;;
+-      netbsd*)
++      netbsd* | netbsdelf*-gnu)
+       ;;
+       osf3* | osf4* | osf5*)
+       case $cc_basename in
+@@ -4886,16 +5014,7 @@
+       ;;
+       psos*)
+       ;;
+-      sco*)
+-      case $cc_basename in
+-        CC*)
+-          _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+-          ;;
+-        *)
+-          ;;
+-      esac
+-      ;;
+-      solaris*)
++      solaris*)
+       case $cc_basename in
+         CC*)
+           # Sun C++ 4.2, 5.x and Centerline C++
+@@ -4936,7 +5055,14 @@
+           ;;
+       esac
+       ;;
+-      unixware*)
++      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
++      case $cc_basename in
++        CC*)
++          _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++          _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++          _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++          ;;
++      esac
+       ;;
+       vxworks*)
+       ;;
+@@ -4983,6 +5109,11 @@
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+       ;;
++    interix3*)
++      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
++      # Instead, we relocate shared libraries at runtime.
++      ;;
++
+     msdosdjgpp*)
+       # Just because we use GCC doesn't mean we suddenly get shared libraries
+       # on systems that don't support them.
+@@ -4999,7 +5130,7 @@
+     hpux*)
+       # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+       # not for PA HP-UX.
+-      case "$host_cpu" in
++      case $host_cpu in
+       hppa*64*|ia64*)
+       # +Z the default
+       ;;
+@@ -5046,7 +5177,7 @@
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+       # not for PA HP-UX.
+-      case "$host_cpu" in
++      case $host_cpu in
+       hppa*64*|ia64*)
+       # +Z the default
+       ;;
+@@ -5069,19 +5200,19 @@
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+       ;;
+-    linux*)
++    linux* | k*bsd*-gnu)
+       case $cc_basename in
+       icc* | ecc*)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+         ;;
+-      pgcc* | pgf77* | pgf90*)
++      pgcc* | pgf77* | pgf90* | pgf95*)
+         # Portland Group compilers (*not* the Pentium gcc compiler,
+       # which looks to be a dead project)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
++      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+         ;;
+       ccc*)
+         _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+@@ -5097,11 +5228,6 @@
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+       ;;
+-    sco3.2v5*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn'
+-      ;;
+-
+     solaris*)
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+@@ -5119,7 +5245,7 @@
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+       ;;
+-    sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
++    sysv4 | sysv4.2uw2* | sysv4.3*)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+@@ -5132,6 +5258,12 @@
+       fi
+       ;;
++    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
++      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      ;;
++
+     unicos*)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+@@ -5164,7 +5296,7 @@
+     [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+ fi
+-case "$host_os" in
++case $host_os in
+   # For platforms which do not support PIC, -DPIC is meaningless:
+   *djgpp*)
+     _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+@@ -5173,6 +5305,16 @@
+     _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])"
+     ;;
+ esac
++
++#
++# Check to make sure the static flag actually works.
++#
++wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\"
++AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
++  _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1),
++  $lt_tmp_static_flag,
++  [],
++  [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
+ ])
+@@ -5199,6 +5341,9 @@
+   cygwin* | mingw*)
+     _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+   ;;
++  linux* | k*bsd*-gnu)
++    _LT_AC_TAGVAR(link_all_deplibs, $1)=no
++  ;;
+   *)
+     _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+   ;;
+@@ -5251,6 +5396,10 @@
+       with_gnu_ld=no
+     fi
+     ;;
++  interix*)
++    # we just hope/assume this is gcc and not c89 (= MSVC++)
++    with_gnu_ld=yes
++    ;;
+   openbsd*)
+     with_gnu_ld=no
+     ;;
+@@ -5260,7 +5409,7 @@
+   if test "$with_gnu_ld" = yes; then
+     # If archive_cmds runs LD, not CC, wlarc should be empty
+     wlarc='${wl}'
+-    
++
+     # Set some defaults for GNU ld with shared library support. These
+     # are reset later if shared libraries are not supported. Putting them
+     # here allows them to be overridden if necessary.
+@@ -5281,7 +5430,7 @@
+       *\ 2.11.*) ;; # other 2.11 versions
+       *) supports_anon_versioning=yes ;;
+     esac
+-    
++
+     # See if GNU ld supports shared libraries.
+     case $host_os in
+     aix3* | aix4* | aix5*)
+@@ -5335,7 +5484,7 @@
+       _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+       if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+-        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
++        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+       # If the export-symbols file already is a .def file (1st line
+       # is EXPORTS), use it as is; otherwise, prepend...
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+@@ -5344,22 +5493,37 @@
+         echo EXPORTS > $output_objdir/$soname.def;
+         cat $export_symbols >> $output_objdir/$soname.def;
+       fi~
+-      $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000  ${wl}--out-implib,$lib'
++      $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+       else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+-    linux*)
++    interix3*)
++      _LT_AC_TAGVAR(hardcode_direct, $1)=no
++      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
++      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
++      # Instead, shared libraries are loaded at an image base (0x10000000 by
++      # default) and relocated if they conflict, which is a slow very memory
++      # consuming and fragmenting process.  To avoid this, we pick a random,
++      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
++      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++      ;;
++
++    linux* | k*bsd*-gnu)
+       if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       tmp_addflag=
+       case $cc_basename,$host_cpu in
+       pgcc*)                          # Portland Group C compiler
+-        _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive,`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
++        _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag'
+         ;;
+-      pgf77* | pgf90* )                       # Portland Group f77 and f90 compilers
+-        _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive,`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
++      pgf77* | pgf90* | pgf95*)       # Portland Group f77 and f90 compilers
++        _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag -Mnomain' ;;
+       ecc*,ia64* | icc*,ia64*)                # Intel C compiler on ia64
+         tmp_addflag=' -i_dynamic' ;;
+@@ -5376,12 +5540,13 @@
+   $echo "local: *; };" >> $output_objdir/$libname.ver~
+         $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+       fi
++      _LT_AC_TAGVAR(link_all_deplibs, $1)=no
+       else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+-    netbsd*)
++    netbsd* | netbsdelf*-gnu)
+       if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+       wlarc=
+@@ -5391,7 +5556,7 @@
+       fi
+       ;;
+-    solaris* | sysv5*)
++    solaris*)
+       if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       cat <<EOF 1>&2
+@@ -5412,6 +5577,33 @@
+       fi
+       ;;
++    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
++      case `$LD -v 2>&1` in
++        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) 
++      _LT_AC_TAGVAR(ld_shlibs, $1)=no
++      cat <<_LT_EOF 1>&2
++
++*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
++*** reliably create shared libraries on SCO systems.  Therefore, libtool
++*** is disabling shared libraries support.  We urge you to upgrade GNU
++*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
++*** your PATH or compiler configuration so that the native linker is
++*** used, and then restart.
++
++_LT_EOF
++      ;;
++      *)
++        if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
++          _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
++          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib'
++          _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib'
++        else
++          _LT_AC_TAGVAR(ld_shlibs, $1)=no
++        fi
++      ;;
++      esac
++      ;;
++
+     sunos4*)
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+       wlarc=
+@@ -5445,7 +5637,7 @@
+       # Note: this linker hardcodes the directories in LIBPATH if there
+       # are no directories specified by -L.
+       _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      if test "$GCC" = yes && test -z "$link_static_flag"; then
++      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+       # Neither direct hardcoding nor static linking is supported with a
+       # broken collect2.
+       _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+@@ -5479,6 +5671,7 @@
+           break
+         fi
+         done
++        ;;
+       esac
+       exp_sym_flag='-bexport'
+@@ -5516,6 +5709,7 @@
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+         fi
++        ;;
+       esac
+       shared_flag='-shared'
+       if test "$aix_use_runtimelinking" = yes; then
+@@ -5528,11 +5722,11 @@
+       # chokes on -Wl,-G. The following line is correct:
+         shared_flag='-G'
+       else
+-      if test "$aix_use_runtimelinking" = yes; then
++        if test "$aix_use_runtimelinking" = yes; then
+           shared_flag='${wl}-G'
+         else
+           shared_flag='${wl}-bM:SRE'
+-      fi
++        fi
+       fi
+       fi
+@@ -5546,12 +5740,12 @@
+        # Determine the default libpath from the value encoded in an empty executable.
+        _LT_AC_SYS_LIBPATH_AIX
+        _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        else
+       if test "$host_cpu" = ia64; then
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+-        _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
++        _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+       else
+        # Determine the default libpath from the value encoded in an empty executable.
+        _LT_AC_SYS_LIBPATH_AIX
+@@ -5560,13 +5754,11 @@
+         # -berok will link without error, but may produce a broken library.
+         _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+-        # -bexpall does not export symbols beginning with underscore (_)
+-        _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+         # Exported symbols can be pulled into shared objects from archives
+-        _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' '
++        _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+         _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+-        # This is similar to how AIX traditionally builds it's shared libraries.
+-        _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
++        # This is similar to how AIX traditionally builds its shared libraries.
++        _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+       fi
+       fi
+       ;;
+@@ -5605,7 +5797,7 @@
+       ;;
+     darwin* | rhapsody*)
+-      case "$host_os" in
++      case $host_os in
+         rhapsody* | darwin1.[[012]])
+          _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+          ;;
+@@ -5634,7 +5826,7 @@
+       output_verbose_link_cmd='echo'
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+       _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+-      # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
++      # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+       _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+     else
+@@ -5643,7 +5835,7 @@
+          output_verbose_link_cmd='echo'
+          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+          _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+-          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
++          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+          _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+           _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+           ;;
+@@ -5684,7 +5876,7 @@
+       ;;
+     # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+-    freebsd* | kfreebsd*-gnu | dragonfly*)
++    freebsd* | dragonfly*)
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+       _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+@@ -5707,47 +5899,62 @@
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+       ;;
+-    hpux10* | hpux11*)
++    hpux10*)
+       if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+-      case "$host_cpu" in
+-      hppa*64*|ia64*)
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
++      else
++      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
++      fi
++      if test "$with_gnu_ld" = no; then
++      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
++
++      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
++      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++
++      # hardcode_minus_L: Not really in the search PATH,
++      # but as the default location of the library.
++      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
++      fi
++      ;;
++
++    hpux11*)
++      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
++      case $host_cpu in
++      hppa*64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
++      ia64*)
++        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
++        ;;
+       *)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       esac
+       else
+-      case "$host_cpu" in
+-      hppa*64*|ia64*)
+-        _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
++      case $host_cpu in
++      hppa*64*)
++        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++        ;;
++      ia64*)
++        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+-        _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
++        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       esac
+       fi
+       if test "$with_gnu_ld" = no; then
+-      case "$host_cpu" in
+-      hppa*64*)
+-        _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
++
++      case $host_cpu in
++      hppa*64*|ia64*)
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+-        _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-        _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-        _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-        ;;
+-      ia64*)
+-        _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=no
+         _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-
+-        # hardcode_minus_L: Not really in the search PATH,
+-        # but as the default location of the library.
+-        _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+         ;;
+       *)
+-        _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+-        _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+         _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+@@ -5771,7 +5978,7 @@
+       _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+       ;;
+-    netbsd*)
++    netbsd* | netbsdelf*-gnu)
+       if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+       else
+@@ -5849,14 +6056,6 @@
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+       ;;
+-    sco3.2v5*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+-      runpath_var=LD_RUN_PATH
+-      hardcode_runpath_var=yes
+-      ;;
+-
+     solaris*)
+       _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+       if test "$GCC" = yes; then
+@@ -5942,36 +6141,45 @@
+       fi
+       ;;
+-    sysv4.2uw2*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
++    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7*)
++      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+       _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      hardcode_runpath_var=yes
+-      runpath_var=LD_RUN_PATH
+-      ;;
++      runpath_var='LD_RUN_PATH'
+-   sysv5OpenUNIX8* | sysv5UnixWare7* |  sysv5uw[[78]]* | unixware7*)
+-      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text'
+       if test "$GCC" = yes; then
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       else
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       fi
+-      runpath_var='LD_RUN_PATH'
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+       ;;
+-    sysv5*)
+-      _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+-      # $CC -shared without GNU ld will not create a library from C++
+-      # object files and a static libstdc++, better avoid it by now
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-              $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
++    sysv5* | sco3.2v5* | sco5v6*)
++      # Note: We can NOT use -z defs as we might desire, because we do not
++      # link with -lc, and that would cause any symbols used from libc to
++      # always be unresolved, which means just about no library would
++      # ever link correctly.  If we're not using GNU ld we use -z text
++      # though, which does catch some bad symbols but isn't as heavy-handed
++      # as -z defs.
++      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++      _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
++      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+       _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
++      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
++      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
++      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
++      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+       runpath_var='LD_RUN_PATH'
++
++      if test "$GCC" = yes; then
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
++      else
++      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
++      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
++      fi
+       ;;
+     uts4*)
+@@ -5989,11 +6197,6 @@
+ AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+ test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+-if test "$GCC" = yes; then
+-  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+-fi
+-
+ #
+ # Do we need to explicitly link libc?
+ #
+@@ -6021,6 +6224,7 @@
+         libobjs=conftest.$ac_objext
+         deplibs=
+         wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
++      pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+         compiler_flags=-v
+         linker_flags=-v
+         verstring=
+@@ -6176,23 +6380,11 @@
+ AC_MSG_RESULT([$SED])
+ ])
+-#                                                        -*- Autoconf -*-
+-# Copyright (C) 2002, 2003  Free Software Foundation, Inc.
+-# Generated from amversion.in; do not edit by hand.
+-
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++# Copyright (C) 2002, 2003, 2005  Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+ # AM_AUTOMAKE_VERSION(VERSION)
+ # ----------------------------
+@@ -6205,26 +6397,15 @@
+ # Call AM_AUTOMAKE_VERSION so it can be traced.
+ # This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+ AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+-       [AM_AUTOMAKE_VERSION([1.9.4])])
++       [AM_AUTOMAKE_VERSION([1.9.6])])
+-# AM_AUX_DIR_EXPAND
++# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+-# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+-
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
++# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+ # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+ # $ac_aux_dir to `$srcdir/foo'.  In other projects, it is set to
+@@ -6272,25 +6453,14 @@
+ ])
+-# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003
++# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2005
+ # Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
+-
+-# serial 3
++# serial 4
+ # This was merged into AC_PROG_CC in Autoconf.
+@@ -6305,26 +6475,16 @@
+ ])
+ AU_DEFUN([fp_PROG_CC_STDC])
+-# AM_CONDITIONAL                                              -*- Autoconf -*-
+-
+-# Copyright (C) 1997, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
+-
+-# 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, 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.
++# AM_CONDITIONAL                                            -*- Autoconf -*-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
++# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
++# Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-# serial 6
++# serial 7
+ # AM_CONDITIONAL(NAME, SHELL-CONDITION)
+ # -------------------------------------
+@@ -6348,26 +6508,15 @@
+ Usually this means the macro was only invoked conditionally.]])
+ fi])])
+-# serial 7                                            -*- Autoconf -*-
+-# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
++# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ # Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
+-
++# serial 8
+ # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+ # written in clear, in which case automake, when reading aclocal.m4,
+@@ -6376,7 +6525,6 @@
+ # CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+-
+ # _AM_DEPENDENCIES(NAME)
+ # ----------------------
+ # See how the compiler implements dependency checking.
+@@ -6516,27 +6664,16 @@
+ AC_SUBST([AMDEPBACKSLASH])
+ ])
+-# Generate code to set up dependency tracking.   -*- Autoconf -*-
+-
+-# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+-#   Free Software Foundation, Inc.
+-
+-# 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, 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.
++# Generate code to set up dependency tracking.              -*- Autoconf -*-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
++# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
++# Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-#serial 2
++#serial 3
+ # _AM_OUTPUT_DEPENDENCY_COMMANDS
+ # ------------------------------
+@@ -6595,54 +6732,31 @@
+      [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+ ])
+-# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*-
+-
+-# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc.
+-
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
++# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
++# Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-# serial 7
++# serial 8
+ # AM_CONFIG_HEADER is obsolete.  It has been replaced by AC_CONFIG_HEADERS.
+ AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
+-# Do all the work for Automake.                            -*- Autoconf -*-
+-
+-# This macro actually does too much some checks are only needed if
+-# your package does certain things.  But this isn't really a big deal.
++# Do all the work for Automake.                             -*- Autoconf -*-
+-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
++# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ # Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
++# serial 12
+-# serial 11
++# This macro actually does too much.  Some checks are only needed if
++# your package does certain things.  But this isn't really a big deal.
+ # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+ # AM_INIT_AUTOMAKE([OPTIONS])
+@@ -6744,51 +6858,27 @@
+ done
+ echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
++# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
+ # AM_PROG_INSTALL_SH
+ # ------------------
+ # Define $install_sh.
+-
+-# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+-
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
+-
+ AC_DEFUN([AM_PROG_INSTALL_SH],
+ [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+ install_sh=${install_sh-"$am_aux_dir/install-sh"}
+ AC_SUBST(install_sh)])
+-#                                                          -*- Autoconf -*-
+-# Copyright (C) 2003  Free Software Foundation, Inc.
+-
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
++# Copyright (C) 2003, 2005  Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-# serial 1
++# serial 2
+ # Check whether the underlying file-system supports filenames
+ # with a leading dot.  For instance MS-DOS doesn't.
+@@ -6803,26 +6893,14 @@
+ rmdir .tst 2>/dev/null
+ AC_SUBST([am__leading_dot])])
+-
+-# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
++# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005
+ # Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
+-
+-# serial 4
++# serial 5
+ # AM_PROG_LEX
+ # -----------
+@@ -6836,28 +6914,17 @@
+   LEX=${am_missing_run}flex
+ fi])
+-# Add --enable-maintainer-mode option to configure.
++# Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
+ # From Jim Meyering
+-# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004
++# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005
+ # Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
+-
+-# serial 3
++# serial 4
+ AC_DEFUN([AM_MAINTAINER_MODE],
+ [AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+@@ -6876,26 +6943,15 @@
+ AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+-# Check to see how 'make' treats includes.    -*- Autoconf -*-
+-
+-# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+-
+-# 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, 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.
++# Check to see how 'make' treats includes.                -*- Autoconf -*-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
++# Copyright (C) 2001, 2002, 2003, 2005  Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-# serial 2
++# serial 3
+ # AM_MAKE_INCLUDE()
+ # -----------------
+@@ -6939,27 +6995,16 @@
+ rm -f confinc confmf
+ ])
+-#  -*- Autoconf -*-
+-
+-
+-# Copyright (C) 1997, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+-
+-# 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, 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.
++# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
++# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
++# Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-# serial 3
++# serial 4
+ # AM_MISSING_PROG(NAME, PROGRAM)
+ # ------------------------------
+@@ -6985,27 +7030,16 @@
+ fi
+ ])
++# Copyright (C) 2003, 2004, 2005  Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
+ # AM_PROG_MKDIR_P
+ # ---------------
+ # Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
+-
+-# Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+-
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
+-
++#
+ # Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
+ # created by `make install' are always world readable, even if the
+ # installer happens to have an overly restrictive umask (e.g. 077).
+@@ -7059,26 +7093,15 @@
+ fi
+ AC_SUBST([mkdir_p])])
+-# Helper functions for option handling.                    -*- Autoconf -*-
+-
+-# Copyright (C) 2001, 2002, 2003  Free Software Foundation, Inc.
+-
+-# 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, 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.
++# Helper functions for option handling.                     -*- Autoconf -*-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
++# Copyright (C) 2001, 2002, 2003, 2005  Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-# serial 2
++# serial 3
+ # _AM_MANGLE_OPTION(NAME)
+ # -----------------------
+@@ -7103,28 +7126,16 @@
+ AC_DEFUN([_AM_IF_OPTION],
+ [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+-#
+-# Check to make sure that the build environment is sane.
+-#
+-
+-# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc.
++# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
++# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
++# Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
+-# serial 3
++# serial 4
+ # AM_SANITY_CHECK
+ # ---------------
+@@ -7167,25 +7178,14 @@
+ fi
+ AC_MSG_RESULT(yes)])
+-# AM_PROG_INSTALL_STRIP
+-
+-# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+-
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
++# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++# AM_PROG_INSTALL_STRIP
++# ---------------------
+ # One issue with vendor `install' (even GNU) is that you can't
+ # specify the program used to strip binaries.  This is especially
+ # annoying in cross-compiling environments, where the build's strip
+@@ -7208,25 +7208,13 @@
+ # Check how to create a tarball.                            -*- Autoconf -*-
+-# Copyright (C) 2004  Free Software Foundation, Inc.
+-
+-# 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, or (at your option)
+-# any later version.
+-
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-# 02111-1307, USA.
+-
+-# serial 1
++# Copyright (C) 2004, 2005  Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++# serial 2
+ # _AM_PROG_TAR(FORMAT)
+ # --------------------
diff --git a/packages/lesstif/files/disable-docs.patch b/packages/lesstif/files/disable-docs.patch
new file mode 100644 (file)
index 0000000..f603837
--- /dev/null
@@ -0,0 +1,29 @@
+Index: lesstif-0.95.0/Makefile.am
+===================================================================
+--- lesstif-0.95.0.orig/Makefile.am
++++ lesstif-0.95.0/Makefile.am
+@@ -7,9 +7,9 @@ MAINTAINERCLEANFILES=Makefile.in configu
+                    missing mkinstalldirs \
+                    BUG-REPORTING INSTALL.txt ReleaseNotes.txt
+-SUBDIRS            = . scripts include lib clients doc @BuildTestDir@ autopackage
++SUBDIRS            = . scripts include lib clients @BuildTestDir@ autopackage
+-DIST_SUBDIRS = scripts include lib clients doc test autopackage
++DIST_SUBDIRS = scripts include lib clients test autopackage
+ #
+ # Install some information files
+Index: lesstif-0.95.0/scripts/Makefile.am
+===================================================================
+--- lesstif-0.95.0.orig/scripts/Makefile.am
++++ lesstif-0.95.0/scripts/Makefile.am
+@@ -4,7 +4,7 @@
+ MAINTAINERCLEANFILES=Makefile.in typedefs.c
+-SUBDIRS= . FreeBSD RedHat Slackware autoconf OS2
++SUBDIRS= . FreeBSD RedHat Slackware OS2
+ EXTRA_DIST = LTsysinfo
diff --git a/packages/lesstif/lesstif_0.95.0.bb b/packages/lesstif/lesstif_0.95.0.bb
new file mode 100644 (file)
index 0000000..6a01a9c
--- /dev/null
@@ -0,0 +1,49 @@
+SECTION = "libs"
+DESCRIPTION = "Free OSM/Motif implementation."
+LICENSE = "LGPL"
+PR = "r0"
+
+SRC_URI = "\
+       ${SOURCEFORGE_MIRROR}/lesstif/${BP}.tar.bz2 \
+       file://000_bootstrap_script.diff;patch=1 \
+       file://000_libtool_linking.diff;patch=1 \
+       file://010_rebootstrap-small.diff;patch=1 \
+       file://020_bad_integer_cast.diff;patch=1 \
+       file://020_missing_xm_h.diff;patch=1 \
+       file://020_render_table_crash.diff;patch=1 \
+       file://020_unsigned_int.diff;patch=1 \
+       file://020_xpmpipethrough.diff;patch=1 \
+       file://021_xim_chained_list_crash.diff;patch=1 \
+       file://030_manpage.diff;patch=1 \
+       file://disable-docs.patch;patch=1 \
+       "
+
+DEPENDS = "flex-native bison-native libice libsm libx11 libxext libxp libxt libxrender libxft fontconfig freetype"
+
+inherit autotools
+
+do_preconfigure() {
+       mkdir -p m4
+       mv ac_debug.m4 m4/
+       mv ac_have_libxp.m4 m4/
+       mv ac_find_xft.m4 m4/
+       mv acinclude.m4 m4/
+
+       rm aclocal.m4
+
+       sed -i -e "s|LT_HAVE_FREETYPE|HAVEFREETYPE|" m4/acinclude.m4
+       sed -i -e "s|LT_HAVE_XRENDER|HAVEXRENDER|" m4/acinclude.m4
+}
+
+addtask preconfigure after do_patch before do_configure
+
+EXTRA_OECONF = "\
+       --with-gnu-ld --disable-verbose --disable-build-12 --disable-build-20 \
+       --enable-build-21 --enable-xrender --enable-production \
+"
+
+PACKAGES += "${PN}-bin"
+
+FILES_${PN} = "${libdir}"
+FILES_${PN}-bin = "${bindir}"
+
diff --git a/packages/libffi/libffi_2.0+gcc4.3.2.bb b/packages/libffi/libffi_2.0+gcc4.3.2.bb
new file mode 100644 (file)
index 0000000..300df81
--- /dev/null
@@ -0,0 +1,64 @@
+SECTION = "libs"
+DESCRIPTION = "Foreign Function Interface library"
+LICENSE = "libffi"
+PRIORITY = "optional"
+
+inherit autotools gettext
+
+PACKAGES = "${PN}-dbg ${PN} ${PN}-dev"
+
+FILES_${PN} = "${libdir}/libffi.so.*"
+
+FILES_${PN}-dev = "${includedir}/ffi* \
+                  ${libdir}/libffi.a \
+                  ${libdir}/libffi.la \
+                  ${libdir}/libffi.so"
+
+GCC_VER = "${@bb.data.getVar('PV',d,1).split('gcc')[1]}"
+
+SRC_URI = "${GNU_MIRROR}/gcc/gcc-${GCC_VER}/gcc-${GCC_VER}.tar.bz2 \
+          "
+
+MIRRORS_prepend () {
+${GNU_MIRROR}/gcc/     http://gcc.get-software.com/releases/
+${GNU_MIRROR}/gcc/     http://mirrors.rcn.net/pub/sourceware/gcc/releases/
+}
+
+S = "${WORKDIR}/gcc-${GCC_VER}/libffi"
+B = "${S}/build.${HOST_SYS}.${TARGET_SYS}"
+
+EXTRA_OECONF = "--with-gnu-ld \
+                --enable-shared \
+                --enable-target-optspace \
+                --enable-languages=c,c++,f77 \
+                --enable-threads=posix \
+                --enable-multilib \
+                --enable-c99 \
+                --enable-long-long \
+                --enable-symvers=gnu \
+                --program-prefix=${TARGET_PREFIX} \
+                ${EXTRA_OECONF_PATHS}"
+
+EXTRA_OECONF_PATHS = "--with-local-prefix=${prefix}/local \
+                      --with-gxx-include-dir=${includedir}/c++/${PV}"
+
+do_configure () {
+       (cd ${S}/.. && gnu-configize) || die "failure running gnu-configize"
+       oe_runconf
+}
+
+do_install_append() {
+       # follow debian and move this to $includedir
+       mv ${D}${libdir}/gcc/${TARGET_SYS}/${GCC_VER}/include/libffi/ffitarget.h ${D}${includedir}/
+}
+
+ffi_include = "ffi.h ffitarget.h"
+
+do_stage () {
+       oe_libinstall -so -C .libs libffi ${STAGING_LIBDIR}
+
+       mkdir -p ${STAGING_INCDIR}/
+       for i in ${ffi_include}; do
+               install -m 0644 include/$i ${STAGING_INCDIR}/
+       done
+}
index fe72ec9..4787242 100644 (file)
@@ -3,7 +3,7 @@ LICENSE = "GPL"
 PN = "linux-dm8000"
 KV = "2.6.12"
 PV = "2.6.12"
-PR = "r5"
+PR = "r6"
 
 # note, the rX in the filename is *NOT* the packet revision - it's the patch revision.
 SRC_URI += "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-${KV}.tar.bz2 \
@@ -28,7 +28,8 @@ SRC_URI += "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-${KV}.tar.bz2 \
        file://linuxmips-2.6.12-fix-futex.patch;patch=1;pnum=1 \
        file://linuxmips-2.6.12-gcc4-compile-fix.patch;patch=1;pnum=1 \
        file://linuxmips-2.6.12-gdb-fix.patch;patch=1;pnum=1 \
-       file://linux-2.6.12-brcm-fix-minipci.patch;patch=1;pnum=1"
+       file://linux-2.6.12-brcm-fix-minipci.patch;patch=1;pnum=1 \
+       http://trappist.elis.ugent.be/~mronsse/cdfs/download/cdfs-2.6.12.tar.bz2"
 
 S = "${WORKDIR}/stblinux-2.6.12"
 
@@ -52,6 +53,10 @@ addtask munge before do_patch after do_unpack
 
 do_configure_prepend() {
        oe_machinstall -m 0644 ${WORKDIR}/dm8000_defconfig ${S}/.config
+       if [ -d ${WORKDIR}/cdfs-${PV} ]; then
+               mv ${WORKDIR}/cdfs-${PV} ${S}/fs/cdfs
+               cd ${S} & patch -p0 < ${S}/fs/cdfs/patch.cdfs
+       fi;
        oe_runmake oldconfig
 }
 
index 324a3fe..4cd9c09 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.12-5.1-brcmstb-dm8000
-# Tue Oct  7 23:38:32 2008
+# Mon Oct 20 18:29:26 2008
 #
 CONFIG_MIPS=y
 
@@ -1004,7 +1004,9 @@ CONFIG_SERIO_LIBPS2=y
 #
 # Character devices
 #
-# CONFIG_VT is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -1266,6 +1268,13 @@ CONFIG_FB_SOFT_CURSOR=y
 # CONFIG_FB_VIRTUAL is not set
 
 #
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
 # Logo configuration
 #
 # CONFIG_LOGO is not set
@@ -1546,6 +1555,7 @@ CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
 CONFIG_UDF_FS=m
 CONFIG_UDF_NLS=y
+CONFIG_CDFS_FS=y
 
 #
 # DOS/FAT/NT Filesystems
index c726740..413167d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.26-omap1
-# Thu Sep 25 07:42:19 2008
+# Wed Oct 22 12:01:26 2008
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -97,7 +97,7 @@ CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
-# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_FORCE_LOAD=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_MODVERSIONS=y
index e21cc21..e80885f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.26
-# Fri Oct 17 18:46:51 2008
+# Mon Oct 20 01:48:37 2008
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -845,7 +845,13 @@ CONFIG_INPUT_TOUCHSCREEN=y
 # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
 # CONFIG_TOUCHSCREEN_TOUCHWIN is not set
 # CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
 CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
 CONFIG_INPUT_UINPUT=m
 
 #
@@ -954,11 +960,11 @@ CONFIG_SSB_POSSIBLE=y
 #
 # Multimedia Capabilities Port drivers
 #
-CONFIG_MCP=m
-CONFIG_MCP_SA11X0=m
-CONFIG_MCP_UCB1200=m
+CONFIG_MCP=y
+CONFIG_MCP_SA11X0=y
+CONFIG_MCP_UCB1200=y
 # CONFIG_MCP_UCB1200_TS is not set
-CONFIG_MCP_COLLIE_TS=m
+CONFIG_MCP_COLLIE_TS=y
 
 #
 # Multimedia devices
@@ -1044,7 +1050,47 @@ CONFIG_FONT_8x8=y
 # CONFIG_SOUND is not set
 # CONFIG_HID_SUPPORT is not set
 CONFIG_HID=m
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+CONFIG_USB_GADGET_SA1100=y
+CONFIG_USB_SA1100=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=m
+# CONFIG_USB_ETH_RNDIS is not set
+# CONFIG_USB_ETH_NO_MDLM is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_USB_G_PRINTER=m
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
 CONFIG_MMC_UNSAFE_RESUME=y
diff --git a/packages/linux/linux-rp-2.6.26/usb-gadget27bp.patch b/packages/linux/linux-rp-2.6.26/usb-gadget27bp.patch
new file mode 100644 (file)
index 0000000..3c86f1a
--- /dev/null
@@ -0,0 +1,26674 @@
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index 6e784d2..117d0c7 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -118,10 +118,10 @@ config USB_AMD5536UDC
+ config USB_GADGET_ATMEL_USBA
+       boolean "Atmel USBA"
+       select USB_GADGET_DUALSPEED
+-      depends on AVR32 || ARCH_AT91CAP9
++      depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL
+       help
+         USBA is the integrated high-speed USB Device controller on
+-        the AT32AP700x and AT91CAP9 processors from Atmel.
++        the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
+ config USB_ATMEL_USBA
+       tristate
+@@ -172,7 +172,7 @@ config USB_NET2280
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+-config USB_GADGET_PXA2XX
++config USB_GADGET_PXA25X
+       boolean "PXA 25x or IXP 4xx"
+       depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
+       help
+@@ -184,19 +184,19 @@ config USB_GADGET_PXA2XX
+          zero (for control transfers).
+          Say "y" to link the driver statically, or "m" to build a
+-         dynamically linked module called "pxa2xx_udc" and force all
++         dynamically linked module called "pxa25x_udc" and force all
+          gadget drivers to also be dynamically linked.
+-config USB_PXA2XX
++config USB_PXA25X
+       tristate
+-      depends on USB_GADGET_PXA2XX
++      depends on USB_GADGET_PXA25X
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+ # if there's only one gadget driver, using only two bulk endpoints,
+ # don't waste memory for the other endpoints
+-config USB_PXA2XX_SMALL
+-      depends on USB_GADGET_PXA2XX
++config USB_PXA25X_SMALL
++      depends on USB_GADGET_PXA25X
+       bool
+       default n if USB_ETH_RNDIS
+       default y if USB_ZERO
+@@ -284,6 +284,16 @@ config USB_LH7A40X
+       default USB_GADGET
+       select USB_GADGET_SELECTED
++# built in ../musb along with host support
++config USB_GADGET_MUSB_HDRC
++      boolean "Inventra HDRC USB Peripheral (TI, ...)"
++      depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
++      select USB_GADGET_DUALSPEED
++      select USB_GADGET_SELECTED
++      help
++        This OTG-capable silicon IP is used in dual designs including
++        the TI DaVinci, OMAP 243x, OMAP 343x, and TUSB 6010.
++
+ config USB_GADGET_OMAP
+       boolean "OMAP USB Device Controller"
+       depends on ARCH_OMAP
+@@ -355,6 +365,20 @@ config USB_AT91
+       depends on USB_GADGET_AT91
+       default USB_GADGET
++config USB_GADGET_SA1100
++      boolean "SA1100 USB Device Port"
++      depends on ARCH_SA1100
++      help
++         Say "y" to link the driver statically, or "m" to build a
++         dynamically linked module called "sa1100_udc" and force all
++         gadget drivers to also be dynamically linked.
++
++config USB_SA1100
++      tristate
++      depends on USB_GADGET_SA1100
++      default USB_GADGET
++      select USB_GADGET_SELECTED
++
+ config USB_GADGET_DUMMY_HCD
+       boolean "Dummy HCD (DEVELOPMENT)"
+       depends on USB=y || (USB=m && USB_GADGET=m)
+@@ -504,6 +528,20 @@ config USB_ETH_RNDIS
+          XP, you'll need to download drivers from Microsoft's website; a URL
+          is given in comments found in that info file.
++config USB_ETH_NO_MDLM
++      bool "Disable MDLM support for CDC_SUBSET"
++      depends on USB_ETH
++      default n
++      help
++         A variation on CDC_SUBSET support is used in newer kernel 
++         implementations for use with a proprietary Microsoft Windows driver
++         used for example with the Zaurus linux distribution.
++         However, the MDLM extensions break the older host side drivers making
++         g_ether incompatible with older kernels.
++
++         If you say "y" here, the Ethernet gadget driver will use the older
++         pre-MDLM extensions.
++         
+ config USB_GADGETFS
+       tristate "Gadget Filesystem (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+@@ -586,6 +624,20 @@ config USB_G_PRINTER
+         For more information, see Documentation/usb/gadget_printer.txt
+         which includes sample code for accessing the device file.
++config USB_CDC_COMPOSITE
++      tristate "CDC Composite Device (Ethernet and ACM)"
++      depends on NET
++      help
++        This driver provides two functions in one configuration:
++        a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link.
++
++        This driver requires four bulk and two interrupt endpoints,
++        plus the ability to handle altsettings.  Not all peripheral
++        controllers are that capable.
++
++        Say "y" to link the driver statically, or "m" to build a
++        dynamically linked module.
++
+ # put drivers that need isochronous transfer support (for audio
+ # or video class gadget drivers), or specific hardware, here.
+diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
+index 1235725..79a69ae 100644
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -8,7 +8,7 @@ endif
+ obj-$(CONFIG_USB_DUMMY_HCD)   += dummy_hcd.o
+ obj-$(CONFIG_USB_NET2280)     += net2280.o
+ obj-$(CONFIG_USB_AMD5536UDC)  += amd5536udc.o
+-obj-$(CONFIG_USB_PXA2XX)      += pxa2xx_udc.o
++obj-$(CONFIG_USB_PXA25X)      += pxa25x_udc.o
+ obj-$(CONFIG_USB_PXA27X)      += pxa27x_udc.o
+ obj-$(CONFIG_USB_GOKU)                += goku_udc.o
+ obj-$(CONFIG_USB_OMAP)                += omap_udc.o
+@@ -18,22 +18,27 @@ obj-$(CONFIG_USB_AT91)             += at91_udc.o
+ obj-$(CONFIG_USB_ATMEL_USBA)  += atmel_usba_udc.o
+ obj-$(CONFIG_USB_FSL_USB2)    += fsl_usb2_udc.o
+ obj-$(CONFIG_USB_M66592)      += m66592-udc.o
++obj-$(CONFIG_USB_SA1100)      += sa1100_udc.o
+ #
+ # USB gadget drivers
+ #
+-g_zero-objs                   := zero.o usbstring.o config.o epautoconf.o
+-g_ether-objs                  := ether.o usbstring.o config.o epautoconf.o
+-g_serial-objs                 := serial.o usbstring.o config.o epautoconf.o
++C_UTILS =     composite.o usbstring.o config.o epautoconf.o
++
++g_zero-objs                   := zero.o f_sourcesink.o f_loopback.o $(C_UTILS)
++g_ether-objs                  := ether.o u_ether.o f_subset.o f_ecm.o $(C_UTILS)
++g_serial-objs                 := serial.o u_serial.o f_acm.o f_serial.o $(C_UTILS)
+ g_midi-objs                   := gmidi.o usbstring.o config.o epautoconf.o
+ gadgetfs-objs                 := inode.o
+ g_file_storage-objs           := file_storage.o usbstring.o config.o \
+                                       epautoconf.o
+ g_printer-objs                        := printer.o usbstring.o config.o \
+                                       epautoconf.o
++g_cdc-objs                    := cdc2.o u_ether.o f_ecm.o \
++                                      u_serial.o f_acm.o $(C_UTILS)
+ ifeq ($(CONFIG_USB_ETH_RNDIS),y)
+-      g_ether-objs            += rndis.o
++      g_ether-objs            += f_rndis.o rndis.o
+ endif
+  
+ obj-$(CONFIG_USB_ZERO)                += g_zero.o
+@@ -43,4 +48,5 @@ obj-$(CONFIG_USB_FILE_STORAGE)       += g_file_storage.o
+ obj-$(CONFIG_USB_G_SERIAL)    += g_serial.o
+ obj-$(CONFIG_USB_G_PRINTER)   += g_printer.o
+ obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
++obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
+diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
+index f261d2a..abf8192 100644
+--- a/drivers/usb/gadget/amd5536udc.c
++++ b/drivers/usb/gadget/amd5536udc.c
+@@ -44,7 +44,6 @@
+ #include <linux/module.h>
+ #include <linux/pci.h>
+ #include <linux/kernel.h>
+-#include <linux/version.h>
+ #include <linux/delay.h>
+ #include <linux/ioport.h>
+ #include <linux/sched.h>
+@@ -3342,7 +3341,7 @@ static int udc_probe(struct udc *dev)
+       spin_lock_init(&dev->lock);
+       dev->gadget.ops = &udc_ops;
+-      strcpy(dev->gadget.dev.bus_id, "gadget");
++      dev_set_name(&dev->gadget.dev, "gadget");
+       dev->gadget.dev.release = gadget_release;
+       dev->gadget.name = name;
+       dev->gadget.name = name;
+diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
+index 274c60a..a8a1de4 100644
+--- a/drivers/usb/gadget/at91_udc.c
++++ b/drivers/usb/gadget/at91_udc.c
+@@ -40,16 +40,15 @@
+ #include <linux/usb/gadget.h>
+ #include <asm/byteorder.h>
+-#include <asm/hardware.h>
++#include <mach/hardware.h>
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/system.h>
+-#include <asm/mach-types.h>
+ #include <asm/gpio.h>
+-#include <asm/arch/board.h>
+-#include <asm/arch/cpu.h>
+-#include <asm/arch/at91sam9261_matrix.h>
++#include <mach/board.h>
++#include <mach/cpu.h>
++#include <mach/at91sam9261_matrix.h>
+ #include "at91_udc.h"
+@@ -888,7 +887,7 @@ static void pullup(struct at91_udc *udc, int is_on)
+               at91_udp_write(udc, AT91_UDP_TXVC, 0);
+               if (cpu_is_at91rm9200())
+                       gpio_set_value(udc->board.pullup_pin, active);
+-              else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
++              else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
+                       u32     txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+                       txvc |= AT91_UDP_TXVC_PUON;
+@@ -906,7 +905,7 @@ static void pullup(struct at91_udc *udc, int is_on)
+               at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+               if (cpu_is_at91rm9200())
+                       gpio_set_value(udc->board.pullup_pin, !active);
+-              else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
++              else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
+                       u32     txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+                       txvc &= ~AT91_UDP_TXVC_PUON;
+@@ -1687,6 +1686,19 @@ static int __init at91udc_probe(struct platform_device *pdev)
+                               udc->board.pullup_active_low);
+       }
++      /* newer chips have more FIFO memory than rm9200 */
++      if (cpu_is_at91sam9260()) {
++              udc->ep[0].maxpacket = 64;
++              udc->ep[3].maxpacket = 64;
++              udc->ep[4].maxpacket = 512;
++              udc->ep[5].maxpacket = 512;
++      } else if (cpu_is_at91sam9261()) {
++              udc->ep[3].maxpacket = 64;
++      } else if (cpu_is_at91sam9263()) {
++              udc->ep[0].maxpacket = 64;
++              udc->ep[3].maxpacket = 64;
++      }
++
+       udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
+       if (!udc->udp_baseaddr) {
+               retval = -ENOMEM;
+diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
+index a973f2a..c65d622 100644
+--- a/drivers/usb/gadget/at91_udc.h
++++ b/drivers/usb/gadget/at91_udc.h
+@@ -171,7 +171,7 @@ struct at91_request {
+ #endif
+ #define ERR(stuff...)         pr_err("udc: " stuff)
+-#define WARN(stuff...)                pr_warning("udc: " stuff)
++#define WARNING(stuff...)     pr_warning("udc: " stuff)
+ #define INFO(stuff...)                pr_info("udc: " stuff)
+ #define DBG(stuff...)         pr_debug("udc: " stuff)
+diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
+index 07e5a0b..ae30ab1 100644
+--- a/drivers/usb/gadget/atmel_usba_udc.c
++++ b/drivers/usb/gadget/atmel_usba_udc.c
+@@ -22,7 +22,7 @@
+ #include <linux/delay.h>
+ #include <asm/gpio.h>
+-#include <asm/arch/board.h>
++#include <mach/board.h>
+ #include "atmel_usba_udc.h"
+@@ -334,7 +334,7 @@ static void toggle_bias(int is_on)
+ #elif defined(CONFIG_ARCH_AT91)
+-#include <asm/arch/at91_pmc.h>
++#include <mach/at91_pmc.h>
+ static void toggle_bias(int is_on)
+ {
+diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c
+new file mode 100644
+index 0000000..a39a4b9
+--- /dev/null
++++ b/drivers/usb/gadget/cdc2.c
+@@ -0,0 +1,246 @@
++/*
++ * cdc2.c -- CDC Composite driver, with ECM and ACM support
++ *
++ * Copyright (C) 2008 David Brownell
++ * Copyright (C) 2008 Nokia Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/kernel.h>
++#include <linux/utsname.h>
++
++#include "u_ether.h"
++#include "u_serial.h"
++
++
++#define DRIVER_DESC           "CDC Composite Gadget"
++#define DRIVER_VERSION                "King Kamehameha Day 2008"
++
++/*-------------------------------------------------------------------------*/
++
++/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
++ * Instead:  allocate your own, using normal USB-IF procedures.
++ */
++
++/* Thanks to NetChip Technologies for donating this product ID.
++ * It's for devices with only this composite CDC configuration.
++ */
++#define CDC_VENDOR_NUM                0x0525  /* NetChip */
++#define CDC_PRODUCT_NUM               0xa4aa  /* CDC Composite: ECM + ACM */
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_device_descriptor device_desc = {
++      .bLength =              sizeof device_desc,
++      .bDescriptorType =      USB_DT_DEVICE,
++
++      .bcdUSB =               __constant_cpu_to_le16(0x0200),
++
++      .bDeviceClass =         USB_CLASS_COMM,
++      .bDeviceSubClass =      0,
++      .bDeviceProtocol =      0,
++      /* .bMaxPacketSize0 = f(hardware) */
++
++      /* Vendor and product id can be overridden by module parameters.  */
++      .idVendor =             __constant_cpu_to_le16(CDC_VENDOR_NUM),
++      .idProduct =            __constant_cpu_to_le16(CDC_PRODUCT_NUM),
++      /* .bcdDevice = f(hardware) */
++      /* .iManufacturer = DYNAMIC */
++      /* .iProduct = DYNAMIC */
++      /* NO SERIAL NUMBER */
++      .bNumConfigurations =   1,
++};
++
++static struct usb_otg_descriptor otg_descriptor = {
++      .bLength =              sizeof otg_descriptor,
++      .bDescriptorType =      USB_DT_OTG,
++
++      /* REVISIT SRP-only hardware is possible, although
++       * it would not be called "OTG" ...
++       */
++      .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
++};
++
++static const struct usb_descriptor_header *otg_desc[] = {
++      (struct usb_descriptor_header *) &otg_descriptor,
++      NULL,
++};
++
++
++/* string IDs are assigned dynamically */
++
++#define STRING_MANUFACTURER_IDX               0
++#define STRING_PRODUCT_IDX            1
++
++static char manufacturer[50];
++
++static struct usb_string strings_dev[] = {
++      [STRING_MANUFACTURER_IDX].s = manufacturer,
++      [STRING_PRODUCT_IDX].s = DRIVER_DESC,
++      {  } /* end of list */
++};
++
++static struct usb_gadget_strings stringtab_dev = {
++      .language       = 0x0409,       /* en-us */
++      .strings        = strings_dev,
++};
++
++static struct usb_gadget_strings *dev_strings[] = {
++      &stringtab_dev,
++      NULL,
++};
++
++static u8 hostaddr[ETH_ALEN];
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * We _always_ have both CDC ECM and CDC ACM functions.
++ */
++static int __init cdc_do_config(struct usb_configuration *c)
++{
++      int     status;
++
++      if (gadget_is_otg(c->cdev->gadget)) {
++              c->descriptors = otg_desc;
++              c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++      }
++
++      status = ecm_bind_config(c, hostaddr);
++      if (status < 0)
++              return status;
++
++      status = acm_bind_config(c, 0);
++      if (status < 0)
++              return status;
++
++      return 0;
++}
++
++static struct usb_configuration cdc_config_driver = {
++      .label                  = "CDC Composite (ECM + ACM)",
++      .bind                   = cdc_do_config,
++      .bConfigurationValue    = 1,
++      /* .iConfiguration = DYNAMIC */
++      .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
++      .bMaxPower              = 1,    /* 2 mA, minimal */
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int __init cdc_bind(struct usb_composite_dev *cdev)
++{
++      int                     gcnum;
++      struct usb_gadget       *gadget = cdev->gadget;
++      int                     status;
++
++      if (!can_support_ecm(cdev->gadget)) {
++              ERROR(cdev, "controller '%s' not usable\n", gadget->name);
++              return -EINVAL;
++      }
++
++      /* set up network link layer */
++      status = gether_setup(cdev->gadget, hostaddr);
++      if (status < 0)
++              return status;
++
++      /* set up serial link layer */
++      status = gserial_setup(cdev->gadget, 1);
++      if (status < 0)
++              goto fail0;
++
++      gcnum = usb_gadget_controller_number(gadget);
++      if (gcnum >= 0)
++              device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
++      else {
++              /* We assume that can_support_ecm() tells the truth;
++               * but if the controller isn't recognized at all then
++               * that assumption is a bit more likely to be wrong.
++               */
++              WARNING(cdev, "controller '%s' not recognized; trying %s\n",
++                              gadget->name,
++                              cdc_config_driver.label);
++              device_desc.bcdDevice =
++                      __constant_cpu_to_le16(0x0300 | 0x0099);
++      }
++
++
++      /* Allocate string descriptor numbers ... note that string
++       * contents can be overridden by the composite_dev glue.
++       */
++
++      /* device descriptor strings: manufacturer, product */
++      snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
++              init_utsname()->sysname, init_utsname()->release,
++              gadget->name);
++      status = usb_string_id(cdev);
++      if (status < 0)
++              goto fail1;
++      strings_dev[STRING_MANUFACTURER_IDX].id = status;
++      device_desc.iManufacturer = status;
++
++      status = usb_string_id(cdev);
++      if (status < 0)
++              goto fail1;
++      strings_dev[STRING_PRODUCT_IDX].id = status;
++      device_desc.iProduct = status;
++
++      /* register our configuration */
++      status = usb_add_config(cdev, &cdc_config_driver);
++      if (status < 0)
++              goto fail1;
++
++      INFO(cdev, "%s, version: " DRIVER_VERSION "\n", DRIVER_DESC);
++
++      return 0;
++
++fail1:
++      gserial_cleanup();
++fail0:
++      gether_cleanup();
++      return status;
++}
++
++static int __exit cdc_unbind(struct usb_composite_dev *cdev)
++{
++      gserial_cleanup();
++      gether_cleanup();
++      return 0;
++}
++
++static struct usb_composite_driver cdc_driver = {
++      .name           = "g_cdc",
++      .dev            = &device_desc,
++      .strings        = dev_strings,
++      .bind           = cdc_bind,
++      .unbind         = __exit_p(cdc_unbind),
++};
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR("David Brownell");
++MODULE_LICENSE("GPL");
++
++static int __init init(void)
++{
++      return usb_composite_register(&cdc_driver);
++}
++module_init(init);
++
++static void __exit cleanup(void)
++{
++      usb_composite_unregister(&cdc_driver);
++}
++module_exit(cleanup);
+diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
+new file mode 100644
+index 0000000..85c876c
+--- /dev/null
++++ b/drivers/usb/gadget/composite.c
+@@ -0,0 +1,1041 @@
++/*
++ * composite.c - infrastructure for Composite USB Gadgets
++ *
++ * Copyright (C) 2006-2008 David Brownell
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kallsyms.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/device.h>
++
++#include <linux/usb/composite.h>
++
++
++/*
++ * The code in this file is utility code, used to build a gadget driver
++ * from one or more "function" drivers, one or more "configuration"
++ * objects, and a "usb_composite_driver" by gluing them together along
++ * with the relevant device-wide data.
++ */
++
++/* big enough to hold our biggest descriptor */
++#define USB_BUFSIZ    512
++
++static struct usb_composite_driver *composite;
++
++/* Some systems will need runtime overrides for the  product identifers
++ * published in the device descriptor, either numbers or strings or both.
++ * String parameters are in UTF-8 (superset of ASCII's 7 bit characters).
++ */
++
++static ushort idVendor;
++module_param(idVendor, ushort, 0);
++MODULE_PARM_DESC(idVendor, "USB Vendor ID");
++
++static ushort idProduct;
++module_param(idProduct, ushort, 0);
++MODULE_PARM_DESC(idProduct, "USB Product ID");
++
++static ushort bcdDevice;
++module_param(bcdDevice, ushort, 0);
++MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
++
++static char *iManufacturer;
++module_param(iManufacturer, charp, 0);
++MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
++
++static char *iProduct;
++module_param(iProduct, charp, 0);
++MODULE_PARM_DESC(iProduct, "USB Product string");
++
++static char *iSerialNumber;
++module_param(iSerialNumber, charp, 0);
++MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
++
++/*-------------------------------------------------------------------------*/
++
++/**
++ * usb_add_function() - add a function to a configuration
++ * @config: the configuration
++ * @function: the function being added
++ * Context: single threaded during gadget setup
++ *
++ * After initialization, each configuration must have one or more
++ * functions added to it.  Adding a function involves calling its @bind()
++ * method to allocate resources such as interface and string identifiers
++ * and endpoints.
++ *
++ * This function returns the value of the function's bind(), which is
++ * zero for success else a negative errno value.
++ */
++int __init usb_add_function(struct usb_configuration *config,
++              struct usb_function *function)
++{
++      int     value = -EINVAL;
++
++      DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
++                      function->name, function,
++                      config->label, config);
++
++      if (!function->set_alt || !function->disable)
++              goto done;
++
++      function->config = config;
++      list_add_tail(&function->list, &config->functions);
++
++      /* REVISIT *require* function->bind? */
++      if (function->bind) {
++              value = function->bind(config, function);
++              if (value < 0) {
++                      list_del(&function->list);
++                      function->config = NULL;
++              }
++      } else
++              value = 0;
++
++      /* We allow configurations that don't work at both speeds.
++       * If we run into a lowspeed Linux system, treat it the same
++       * as full speed ... it's the function drivers that will need
++       * to avoid bulk and ISO transfers.
++       */
++      if (!config->fullspeed && function->descriptors)
++              config->fullspeed = true;
++      if (!config->highspeed && function->hs_descriptors)
++              config->highspeed = true;
++
++done:
++      if (value)
++              DBG(config->cdev, "adding '%s'/%p --> %d\n",
++                              function->name, function, value);
++      return value;
++}
++
++/**
++ * usb_interface_id() - allocate an unused interface ID
++ * @config: configuration associated with the interface
++ * @function: function handling the interface
++ * Context: single threaded during gadget setup
++ *
++ * usb_interface_id() is called from usb_function.bind() callbacks to
++ * allocate new interface IDs.  The function driver will then store that
++ * ID in interface, association, CDC union, and other descriptors.  It
++ * will also handle any control requests targetted at that interface,
++ * particularly changing its altsetting via set_alt().  There may
++ * also be class-specific or vendor-specific requests to handle.
++ *
++ * All interface identifier should be allocated using this routine, to
++ * ensure that for example different functions don't wrongly assign
++ * different meanings to the same identifier.  Note that since interface
++ * identifers are configuration-specific, functions used in more than
++ * one configuration (or more than once in a given configuration) need
++ * multiple versions of the relevant descriptors.
++ *
++ * Returns the interface ID which was allocated; or -ENODEV if no
++ * more interface IDs can be allocated.
++ */
++int __init usb_interface_id(struct usb_configuration *config,
++              struct usb_function *function)
++{
++      unsigned id = config->next_interface_id;
++
++      if (id < MAX_CONFIG_INTERFACES) {
++              config->interface[id] = function;
++              config->next_interface_id = id + 1;
++              return id;
++      }
++      return -ENODEV;
++}
++
++static int config_buf(struct usb_configuration *config,
++              enum usb_device_speed speed, void *buf, u8 type)
++{
++      struct usb_config_descriptor    *c = buf;
++      void                            *next = buf + USB_DT_CONFIG_SIZE;
++      int                             len = USB_BUFSIZ - USB_DT_CONFIG_SIZE;
++      struct usb_function             *f;
++      int                             status;
++
++      /* write the config descriptor */
++      c = buf;
++      c->bLength = USB_DT_CONFIG_SIZE;
++      c->bDescriptorType = type;
++      /* wTotalLength is written later */
++      c->bNumInterfaces = config->next_interface_id;
++      c->bConfigurationValue = config->bConfigurationValue;
++      c->iConfiguration = config->iConfiguration;
++      c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
++      c->bMaxPower = config->bMaxPower;
++
++      /* There may be e.g. OTG descriptors */
++      if (config->descriptors) {
++              status = usb_descriptor_fillbuf(next, len,
++                              config->descriptors);
++              if (status < 0)
++                      return status;
++              len -= status;
++              next += status;
++      }
++
++      /* add each function's descriptors */
++      list_for_each_entry(f, &config->functions, list) {
++              struct usb_descriptor_header **descriptors;
++
++              if (speed == USB_SPEED_HIGH)
++                      descriptors = f->hs_descriptors;
++              else
++                      descriptors = f->descriptors;
++              if (!descriptors)
++                      continue;
++              status = usb_descriptor_fillbuf(next, len,
++                      (const struct usb_descriptor_header **) descriptors);
++              if (status < 0)
++                      return status;
++              len -= status;
++              next += status;
++      }
++
++      len = next - buf;
++      c->wTotalLength = cpu_to_le16(len);
++      return len;
++}
++
++static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
++{
++      struct usb_gadget               *gadget = cdev->gadget;
++      struct usb_configuration        *c;
++      u8                              type = w_value >> 8;
++      enum usb_device_speed           speed = USB_SPEED_UNKNOWN;
++
++      if (gadget_is_dualspeed(gadget)) {
++              int                     hs = 0;
++
++              if (gadget->speed == USB_SPEED_HIGH)
++                      hs = 1;
++              if (type == USB_DT_OTHER_SPEED_CONFIG)
++                      hs = !hs;
++              if (hs)
++                      speed = USB_SPEED_HIGH;
++
++      }
++
++      /* This is a lookup by config *INDEX* */
++      w_value &= 0xff;
++      list_for_each_entry(c, &cdev->configs, list) {
++              /* ignore configs that won't work at this speed */
++              if (speed == USB_SPEED_HIGH) {
++                      if (!c->highspeed)
++                              continue;
++              } else {
++                      if (!c->fullspeed)
++                              continue;
++              }
++              if (w_value == 0)
++                      return config_buf(c, speed, cdev->req->buf, type);
++              w_value--;
++      }
++      return -EINVAL;
++}
++
++static int count_configs(struct usb_composite_dev *cdev, unsigned type)
++{
++      struct usb_gadget               *gadget = cdev->gadget;
++      struct usb_configuration        *c;
++      unsigned                        count = 0;
++      int                             hs = 0;
++
++      if (gadget_is_dualspeed(gadget)) {
++              if (gadget->speed == USB_SPEED_HIGH)
++                      hs = 1;
++              if (type == USB_DT_DEVICE_QUALIFIER)
++                      hs = !hs;
++      }
++      list_for_each_entry(c, &cdev->configs, list) {
++              /* ignore configs that won't work at this speed */
++              if (hs) {
++                      if (!c->highspeed)
++                              continue;
++              } else {
++                      if (!c->fullspeed)
++                              continue;
++              }
++              count++;
++      }
++      return count;
++}
++
++static void device_qual(struct usb_composite_dev *cdev)
++{
++      struct usb_qualifier_descriptor *qual = cdev->req->buf;
++
++      qual->bLength = sizeof(*qual);
++      qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
++      /* POLICY: same bcdUSB and device type info at both speeds */
++      qual->bcdUSB = cdev->desc.bcdUSB;
++      qual->bDeviceClass = cdev->desc.bDeviceClass;
++      qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
++      qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
++      /* ASSUME same EP0 fifo size at both speeds */
++      qual->bMaxPacketSize0 = cdev->desc.bMaxPacketSize0;
++      qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
++      qual->bRESERVED = 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void reset_config(struct usb_composite_dev *cdev)
++{
++      struct usb_function             *f;
++
++      DBG(cdev, "reset config\n");
++
++      list_for_each_entry(f, &cdev->config->functions, list) {
++              if (f->disable)
++                      f->disable(f);
++      }
++      cdev->config = NULL;
++}
++
++static int set_config(struct usb_composite_dev *cdev,
++              const struct usb_ctrlrequest *ctrl, unsigned number)
++{
++      struct usb_gadget       *gadget = cdev->gadget;
++      struct usb_configuration *c = NULL;
++      int                     result = -EINVAL;
++      unsigned                power = gadget_is_otg(gadget) ? 8 : 100;
++      int                     tmp;
++
++      if (cdev->config)
++              reset_config(cdev);
++
++      if (number) {
++              list_for_each_entry(c, &cdev->configs, list) {
++                      if (c->bConfigurationValue == number) {
++                              result = 0;
++                              break;
++                      }
++              }
++              if (result < 0)
++                      goto done;
++      } else
++              result = 0;
++
++      INFO(cdev, "%s speed config #%d: %s\n",
++              ({ char *speed;
++              switch (gadget->speed) {
++              case USB_SPEED_LOW:     speed = "low"; break;
++              case USB_SPEED_FULL:    speed = "full"; break;
++              case USB_SPEED_HIGH:    speed = "high"; break;
++              default:                speed = "?"; break;
++              } ; speed; }), number, c ? c->label : "unconfigured");
++
++      if (!c)
++              goto done;
++
++      cdev->config = c;
++
++      /* Initialize all interfaces by setting them to altsetting zero. */
++      for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
++              struct usb_function     *f = c->interface[tmp];
++
++              if (!f)
++                      break;
++
++              result = f->set_alt(f, tmp, 0);
++              if (result < 0) {
++                      DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n",
++                                      tmp, f->name, f, result);
++
++                      reset_config(cdev);
++                      goto done;
++              }
++      }
++
++      /* when we return, be sure our power usage is valid */
++      power = 2 * c->bMaxPower;
++done:
++      usb_gadget_vbus_draw(gadget, power);
++      return result;
++}
++
++/**
++ * usb_add_config() - add a configuration to a device.
++ * @cdev: wraps the USB gadget
++ * @config: the configuration, with bConfigurationValue assigned
++ * Context: single threaded during gadget setup
++ *
++ * One of the main tasks of a composite driver's bind() routine is to
++ * add each of the configurations it supports, using this routine.
++ *
++ * This function returns the value of the configuration's bind(), which
++ * is zero for success else a negative errno value.  Binding configurations
++ * assigns global resources including string IDs, and per-configuration
++ * resources such as interface IDs and endpoints.
++ */
++int __init usb_add_config(struct usb_composite_dev *cdev,
++              struct usb_configuration *config)
++{
++      int                             status = -EINVAL;
++      struct usb_configuration        *c;
++
++      DBG(cdev, "adding config #%u '%s'/%p\n",
++                      config->bConfigurationValue,
++                      config->label, config);
++
++      if (!config->bConfigurationValue || !config->bind)
++              goto done;
++
++      /* Prevent duplicate configuration identifiers */
++      list_for_each_entry(c, &cdev->configs, list) {
++              if (c->bConfigurationValue == config->bConfigurationValue) {
++                      status = -EBUSY;
++                      goto done;
++              }
++      }
++
++      config->cdev = cdev;
++      list_add_tail(&config->list, &cdev->configs);
++
++      INIT_LIST_HEAD(&config->functions);
++      config->next_interface_id = 0;
++
++      status = config->bind(config);
++      if (status < 0) {
++              list_del(&config->list);
++              config->cdev = NULL;
++      } else {
++              unsigned        i;
++
++              DBG(cdev, "cfg %d/%p speeds:%s%s\n",
++                      config->bConfigurationValue, config,
++                      config->highspeed ? " high" : "",
++                      config->fullspeed
++                              ? (gadget_is_dualspeed(cdev->gadget)
++                                      ? " full"
++                                      : " full/low")
++                              : "");
++
++              for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
++                      struct usb_function     *f = config->interface[i];
++
++                      if (!f)
++                              continue;
++                      DBG(cdev, "  interface %d = %s/%p\n",
++                              i, f->name, f);
++              }
++      }
++
++      /* set_alt(), or next config->bind(), sets up
++       * ep->driver_data as needed.
++       */
++      usb_ep_autoconfig_reset(cdev->gadget);
++
++done:
++      if (status)
++              DBG(cdev, "added config '%s'/%u --> %d\n", config->label,
++                              config->bConfigurationValue, status);
++      return status;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* We support strings in multiple languages ... string descriptor zero
++ * says which languages are supported.  The typical case will be that
++ * only one language (probably English) is used, with I18N handled on
++ * the host side.
++ */
++
++static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf)
++{
++      const struct usb_gadget_strings *s;
++      u16                             language;
++      __le16                          *tmp;
++
++      while (*sp) {
++              s = *sp;
++              language = cpu_to_le16(s->language);
++              for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) {
++                      if (*tmp == language)
++                              goto repeat;
++              }
++              *tmp++ = language;
++repeat:
++              sp++;
++      }
++}
++
++static int lookup_string(
++      struct usb_gadget_strings       **sp,
++      void                            *buf,
++      u16                             language,
++      int                             id
++)
++{
++      struct usb_gadget_strings       *s;
++      int                             value;
++
++      while (*sp) {
++              s = *sp++;
++              if (s->language != language)
++                      continue;
++              value = usb_gadget_get_string(s, id, buf);
++              if (value > 0)
++                      return value;
++      }
++      return -EINVAL;
++}
++
++static int get_string(struct usb_composite_dev *cdev,
++              void *buf, u16 language, int id)
++{
++      struct usb_configuration        *c;
++      struct usb_function             *f;
++      int                             len;
++
++      /* Yes, not only is USB's I18N support probably more than most
++       * folk will ever care about ... also, it's all supported here.
++       * (Except for UTF8 support for Unicode's "Astral Planes".)
++       */
++
++      /* 0 == report all available language codes */
++      if (id == 0) {
++              struct usb_string_descriptor    *s = buf;
++              struct usb_gadget_strings       **sp;
++
++              memset(s, 0, 256);
++              s->bDescriptorType = USB_DT_STRING;
++
++              sp = composite->strings;
++              if (sp)
++                      collect_langs(sp, s->wData);
++
++              list_for_each_entry(c, &cdev->configs, list) {
++                      sp = c->strings;
++                      if (sp)
++                              collect_langs(sp, s->wData);
++
++                      list_for_each_entry(f, &c->functions, list) {
++                              sp = f->strings;
++                              if (sp)
++                                      collect_langs(sp, s->wData);
++                      }
++              }
++
++              for (len = 0; s->wData[len] && len <= 126; len++)
++                      continue;
++              if (!len)
++                      return -EINVAL;
++
++              s->bLength = 2 * (len + 1);
++              return s->bLength;
++      }
++
++      /* Otherwise, look up and return a specified string.  String IDs
++       * are device-scoped, so we look up each string table we're told
++       * about.  These lookups are infrequent; simpler-is-better here.
++       */
++      if (composite->strings) {
++              len = lookup_string(composite->strings, buf, language, id);
++              if (len > 0)
++                      return len;
++      }
++      list_for_each_entry(c, &cdev->configs, list) {
++              if (c->strings) {
++                      len = lookup_string(c->strings, buf, language, id);
++                      if (len > 0)
++                              return len;
++              }
++              list_for_each_entry(f, &c->functions, list) {
++                      if (!f->strings)
++                              continue;
++                      len = lookup_string(f->strings, buf, language, id);
++                      if (len > 0)
++                              return len;
++              }
++      }
++      return -EINVAL;
++}
++
++/**
++ * usb_string_id() - allocate an unused string ID
++ * @cdev: the device whose string descriptor IDs are being allocated
++ * Context: single threaded during gadget setup
++ *
++ * @usb_string_id() is called from bind() callbacks to allocate
++ * string IDs.  Drivers for functions, configurations, or gadgets will
++ * then store that ID in the appropriate descriptors and string table.
++ *
++ * All string identifier should be allocated using this routine, to
++ * ensure that for example different functions don't wrongly assign
++ * different meanings to the same identifier.
++ */
++int __init usb_string_id(struct usb_composite_dev *cdev)
++{
++      if (cdev->next_string_id < 254) {
++              /* string id 0 is reserved */
++              cdev->next_string_id++;
++              return cdev->next_string_id;
++      }
++      return -ENODEV;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      if (req->status || req->actual != req->length)
++              DBG((struct usb_composite_dev *) ep->driver_data,
++                              "setup complete --> %d, %d/%d\n",
++                              req->status, req->actual, req->length);
++}
++
++/*
++ * The setup() callback implements all the ep0 functionality that's
++ * not handled lower down, in hardware or the hardware driver(like
++ * device and endpoint feature flags, and their status).  It's all
++ * housekeeping for the gadget function we're implementing.  Most of
++ * the work is in config and function specific setup.
++ */
++static int
++composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
++{
++      struct usb_composite_dev        *cdev = get_gadget_data(gadget);
++      struct usb_request              *req = cdev->req;
++      int                             value = -EOPNOTSUPP;
++      u16                             w_index = le16_to_cpu(ctrl->wIndex);
++      u16                             w_value = le16_to_cpu(ctrl->wValue);
++      u16                             w_length = le16_to_cpu(ctrl->wLength);
++      struct usb_function             *f = NULL;
++
++      /* partial re-init of the response message; the function or the
++       * gadget might need to intercept e.g. a control-OUT completion
++       * when we delegate to it.
++       */
++      req->zero = 0;
++      req->complete = composite_setup_complete;
++      req->length = USB_BUFSIZ;
++      gadget->ep0->driver_data = cdev;
++
++      switch (ctrl->bRequest) {
++
++      /* we handle all standard USB descriptors */
++      case USB_REQ_GET_DESCRIPTOR:
++              if (ctrl->bRequestType != USB_DIR_IN)
++                      goto unknown;
++              switch (w_value >> 8) {
++
++              case USB_DT_DEVICE:
++                      cdev->desc.bNumConfigurations =
++                              count_configs(cdev, USB_DT_DEVICE);
++                      value = min(w_length, (u16) sizeof cdev->desc);
++                      memcpy(req->buf, &cdev->desc, value);
++                      break;
++              case USB_DT_DEVICE_QUALIFIER:
++                      if (!gadget_is_dualspeed(gadget))
++                              break;
++                      device_qual(cdev);
++                      value = min_t(int, w_length,
++                              sizeof(struct usb_qualifier_descriptor));
++                      break;
++              case USB_DT_OTHER_SPEED_CONFIG:
++                      if (!gadget_is_dualspeed(gadget))
++                              break;
++                      /* FALLTHROUGH */
++              case USB_DT_CONFIG:
++                      value = config_desc(cdev, w_value);
++                      if (value >= 0)
++                              value = min(w_length, (u16) value);
++                      break;
++              case USB_DT_STRING:
++                      value = get_string(cdev, req->buf,
++                                      w_index, w_value & 0xff);
++                      if (value >= 0)
++                              value = min(w_length, (u16) value);
++                      break;
++              }
++              break;
++
++      /* any number of configs can work */
++      case USB_REQ_SET_CONFIGURATION:
++              if (ctrl->bRequestType != 0)
++                      goto unknown;
++              if (gadget_is_otg(gadget)) {
++                      if (gadget->a_hnp_support)
++                              DBG(cdev, "HNP available\n");
++                      else if (gadget->a_alt_hnp_support)
++                              DBG(cdev, "HNP on another port\n");
++                      else
++                              VDBG(cdev, "HNP inactive\n");
++              }
++              spin_lock(&cdev->lock);
++              value = set_config(cdev, ctrl, w_value);
++              spin_unlock(&cdev->lock);
++              break;
++      case USB_REQ_GET_CONFIGURATION:
++              if (ctrl->bRequestType != USB_DIR_IN)
++                      goto unknown;
++              if (cdev->config)
++                      *(u8 *)req->buf = cdev->config->bConfigurationValue;
++              else
++                      *(u8 *)req->buf = 0;
++              value = min(w_length, (u16) 1);
++              break;
++
++      /* function drivers must handle get/set altsetting; if there's
++       * no get() method, we know only altsetting zero works.
++       */
++      case USB_REQ_SET_INTERFACE:
++              if (ctrl->bRequestType != USB_RECIP_INTERFACE)
++                      goto unknown;
++              if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
++                      break;
++              f = cdev->config->interface[w_index];
++              if (!f)
++                      break;
++              if (w_value && !f->get_alt)
++                      break;
++              value = f->set_alt(f, w_index, w_value);
++              break;
++      case USB_REQ_GET_INTERFACE:
++              if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
++                      goto unknown;
++              if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
++                      break;
++              f = cdev->config->interface[w_index];
++              if (!f)
++                      break;
++              /* lots of interfaces only need altsetting zero... */
++              value = f->get_alt ? f->get_alt(f, w_index) : 0;
++              if (value < 0)
++                      break;
++              *((u8 *)req->buf) = value;
++              value = min(w_length, (u16) 1);
++              break;
++      default:
++unknown:
++              VDBG(cdev,
++                      "non-core control req%02x.%02x v%04x i%04x l%d\n",
++                      ctrl->bRequestType, ctrl->bRequest,
++                      w_value, w_index, w_length);
++
++              /* functions always handle their interfaces ... punt other
++               * recipients (endpoint, other, WUSB, ...) to the current
++               * configuration code.
++               *
++               * REVISIT it could make sense to let the composite device
++               * take such requests too, if that's ever needed:  to work
++               * in config 0, etc.
++               */
++              if ((ctrl->bRequestType & USB_RECIP_MASK)
++                              == USB_RECIP_INTERFACE) {
++                      f = cdev->config->interface[w_index];
++                      if (f && f->setup)
++                              value = f->setup(f, ctrl);
++                      else
++                              f = NULL;
++              }
++              if (value < 0 && !f) {
++                      struct usb_configuration        *c;
++
++                      c = cdev->config;
++                      if (c && c->setup)
++                              value = c->setup(c, ctrl);
++              }
++
++              goto done;
++      }
++
++      /* respond with data transfer before status phase? */
++      if (value >= 0) {
++              req->length = value;
++              req->zero = value < w_length;
++              value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
++              if (value < 0) {
++                      DBG(cdev, "ep_queue --> %d\n", value);
++                      req->status = 0;
++                      composite_setup_complete(gadget->ep0, req);
++              }
++      }
++
++done:
++      /* device either stalls (value < 0) or reports success */
++      return value;
++}
++
++static void composite_disconnect(struct usb_gadget *gadget)
++{
++      struct usb_composite_dev        *cdev = get_gadget_data(gadget);
++      unsigned long                   flags;
++
++      /* REVISIT:  should we have config and device level
++       * disconnect callbacks?
++       */
++      spin_lock_irqsave(&cdev->lock, flags);
++      if (cdev->config)
++              reset_config(cdev);
++      spin_unlock_irqrestore(&cdev->lock, flags);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void /* __init_or_exit */
++composite_unbind(struct usb_gadget *gadget)
++{
++      struct usb_composite_dev        *cdev = get_gadget_data(gadget);
++
++      /* composite_disconnect() must already have been called
++       * by the underlying peripheral controller driver!
++       * so there's no i/o concurrency that could affect the
++       * state protected by cdev->lock.
++       */
++      WARN_ON(cdev->config);
++
++      while (!list_empty(&cdev->configs)) {
++              struct usb_configuration        *c;
++
++              c = list_first_entry(&cdev->configs,
++                              struct usb_configuration, list);
++              while (!list_empty(&c->functions)) {
++                      struct usb_function             *f;
++
++                      f = list_first_entry(&c->functions,
++                                      struct usb_function, list);
++                      list_del(&f->list);
++                      if (f->unbind) {
++                              DBG(cdev, "unbind function '%s'/%p\n",
++                                              f->name, f);
++                              f->unbind(c, f);
++                              /* may free memory for "f" */
++                      }
++              }
++              list_del(&c->list);
++              if (c->unbind) {
++                      DBG(cdev, "unbind config '%s'/%p\n", c->label, c);
++                      c->unbind(c);
++                      /* may free memory for "c" */
++              }
++      }
++      if (composite->unbind)
++              composite->unbind(cdev);
++
++      if (cdev->req) {
++              kfree(cdev->req->buf);
++              usb_ep_free_request(gadget->ep0, cdev->req);
++      }
++      kfree(cdev);
++      set_gadget_data(gadget, NULL);
++      composite = NULL;
++}
++
++static void __init
++string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s)
++{
++      struct usb_string               *str = tab->strings;
++
++      for (str = tab->strings; str->s; str++) {
++              if (str->id == id) {
++                      str->s = s;
++                      return;
++              }
++      }
++}
++
++static void __init
++string_override(struct usb_gadget_strings **tab, u8 id, const char *s)
++{
++      while (*tab) {
++              string_override_one(*tab, id, s);
++              tab++;
++      }
++}
++
++static int __init composite_bind(struct usb_gadget *gadget)
++{
++      struct usb_composite_dev        *cdev;
++      int                             status = -ENOMEM;
++
++      cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
++      if (!cdev)
++              return status;
++
++      spin_lock_init(&cdev->lock);
++      cdev->gadget = gadget;
++      set_gadget_data(gadget, cdev);
++      INIT_LIST_HEAD(&cdev->configs);
++
++      /* preallocate control response and buffer */
++      cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
++      if (!cdev->req)
++              goto fail;
++      cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
++      if (!cdev->req->buf)
++              goto fail;
++      cdev->req->complete = composite_setup_complete;
++      gadget->ep0->driver_data = cdev;
++
++      cdev->bufsiz = USB_BUFSIZ;
++      cdev->driver = composite;
++
++      usb_gadget_set_selfpowered(gadget);
++
++      /* interface and string IDs start at zero via kzalloc.
++       * we force endpoints to start unassigned; few controller
++       * drivers will zero ep->driver_data.
++       */
++      usb_ep_autoconfig_reset(cdev->gadget);
++
++      /* composite gadget needs to assign strings for whole device (like
++       * serial number), register function drivers, potentially update
++       * power state and consumption, etc
++       */
++      status = composite->bind(cdev);
++      if (status < 0)
++              goto fail;
++
++      cdev->desc = *composite->dev;
++      cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
++
++      /* standardized runtime overrides for device ID data */
++      if (idVendor)
++              cdev->desc.idVendor = cpu_to_le16(idVendor);
++      if (idProduct)
++              cdev->desc.idProduct = cpu_to_le16(idProduct);
++      if (bcdDevice)
++              cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
++
++      /* strings can't be assigned before bind() allocates the
++       * releavnt identifiers
++       */
++      if (cdev->desc.iManufacturer && iManufacturer)
++              string_override(composite->strings,
++                      cdev->desc.iManufacturer, iManufacturer);
++      if (cdev->desc.iProduct && iProduct)
++              string_override(composite->strings,
++                      cdev->desc.iProduct, iProduct);
++      if (cdev->desc.iSerialNumber && iSerialNumber)
++              string_override(composite->strings,
++                      cdev->desc.iSerialNumber, iSerialNumber);
++
++      INFO(cdev, "%s ready\n", composite->name);
++      return 0;
++
++fail:
++      composite_unbind(gadget);
++      return status;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void
++composite_suspend(struct usb_gadget *gadget)
++{
++      struct usb_composite_dev        *cdev = get_gadget_data(gadget);
++      struct usb_function             *f;
++
++      /* REVISIT:  should we have config and device level
++       * suspend/resume callbacks?
++       */
++      DBG(cdev, "suspend\n");
++      if (cdev->config) {
++              list_for_each_entry(f, &cdev->config->functions, list) {
++                      if (f->suspend)
++                              f->suspend(f);
++              }
++      }
++}
++
++static void
++composite_resume(struct usb_gadget *gadget)
++{
++      struct usb_composite_dev        *cdev = get_gadget_data(gadget);
++      struct usb_function             *f;
++
++      /* REVISIT:  should we have config and device level
++       * suspend/resume callbacks?
++       */
++      DBG(cdev, "resume\n");
++      if (cdev->config) {
++              list_for_each_entry(f, &cdev->config->functions, list) {
++                      if (f->resume)
++                              f->resume(f);
++              }
++      }
++}
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_gadget_driver composite_driver = {
++      .speed          = USB_SPEED_HIGH,
++
++      .bind           = composite_bind,
++      .unbind         = __exit_p(composite_unbind),
++
++      .setup          = composite_setup,
++      .disconnect     = composite_disconnect,
++
++      .suspend        = composite_suspend,
++      .resume         = composite_resume,
++
++      .driver = {
++              .owner          = THIS_MODULE,
++      },
++};
++
++/**
++ * usb_composite_register() - register a composite driver
++ * @driver: the driver to register
++ * Context: single threaded during gadget setup
++ *
++ * This function is used to register drivers using the composite driver
++ * framework.  The return value is zero, or a negative errno value.
++ * Those values normally come from the driver's @bind method, which does
++ * all the work of setting up the driver to match the hardware.
++ *
++ * On successful return, the gadget is ready to respond to requests from
++ * the host, unless one of its components invokes usb_gadget_disconnect()
++ * while it was binding.  That would usually be done in order to wait for
++ * some userspace participation.
++ */
++int __init usb_composite_register(struct usb_composite_driver *driver)
++{
++      if (!driver || !driver->dev || !driver->bind || composite)
++              return -EINVAL;
++
++      if (!driver->name)
++              driver->name = "composite";
++      composite_driver.function =  (char *) driver->name;
++      composite_driver.driver.name = driver->name;
++      composite = driver;
++
++      return usb_gadget_register_driver(&composite_driver);
++}
++
++/**
++ * usb_composite_unregister() - unregister a composite driver
++ * @driver: the driver to unregister
++ *
++ * This function is used to unregister drivers using the composite
++ * driver framework.
++ */
++void __exit usb_composite_unregister(struct usb_composite_driver *driver)
++{
++      if (composite != driver)
++              return;
++      usb_gadget_unregister_driver(&composite_driver);
++}
+diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
+index a4e54b2..1ca1c32 100644
+--- a/drivers/usb/gadget/config.c
++++ b/drivers/usb/gadget/config.c
+@@ -96,7 +96,7 @@ int usb_gadget_config_buf(
+       /* config descriptor first */
+       if (length < USB_DT_CONFIG_SIZE || !desc)
+               return -EINVAL;
+-      *cp = *config; 
++      *cp = *config;
+       /* then interface/endpoint/class/vendor/... */
+       len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
+@@ -115,3 +115,77 @@ int usb_gadget_config_buf(
+       return len;
+ }
++/**
++ * usb_copy_descriptors - copy a vector of USB descriptors
++ * @src: null-terminated vector to copy
++ * Context: initialization code, which may sleep
++ *
++ * This makes a copy of a vector of USB descriptors.  Its primary use
++ * is to support usb_function objects which can have multiple copies,
++ * each needing different descriptors.  Functions may have static
++ * tables of descriptors, which are used as templates and customized
++ * with identifiers (for interfaces, strings, endpoints, and more)
++ * as needed by a given function instance.
++ */
++struct usb_descriptor_header **__init
++usb_copy_descriptors(struct usb_descriptor_header **src)
++{
++      struct usb_descriptor_header **tmp;
++      unsigned bytes;
++      unsigned n_desc;
++      void *mem;
++      struct usb_descriptor_header **ret;
++
++      /* count descriptors and their sizes; then add vector size */
++      for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++)
++              bytes += (*tmp)->bLength;
++      bytes += (n_desc + 1) * sizeof(*tmp);
++
++      mem = kmalloc(bytes, GFP_KERNEL);
++      if (!mem)
++              return NULL;
++
++      /* fill in pointers starting at "tmp",
++       * to descriptors copied starting at "mem";
++       * and return "ret"
++       */
++      tmp = mem;
++      ret = mem;
++      mem += (n_desc + 1) * sizeof(*tmp);
++      while (*src) {
++              memcpy(mem, *src, (*src)->bLength);
++              *tmp = mem;
++              tmp++;
++              mem += (*src)->bLength;
++              src++;
++      }
++      *tmp = NULL;
++
++      return ret;
++}
++
++/**
++ * usb_find_endpoint - find a copy of an endpoint descriptor
++ * @src: original vector of descriptors
++ * @copy: copy of @src
++ * @ep: endpoint descriptor found in @src
++ *
++ * This returns the copy of the @match descriptor made for @copy.  Its
++ * intended use is to help remembering the endpoint descriptor to use
++ * when enabling a given endpoint.
++ */
++struct usb_endpoint_descriptor *__init
++usb_find_endpoint(
++      struct usb_descriptor_header **src,
++      struct usb_descriptor_header **copy,
++      struct usb_endpoint_descriptor *match
++)
++{
++      while (*src) {
++              if (*src == (void *) match)
++                      return (void *)*copy;
++              src++;
++              copy++;
++      }
++      return NULL;
++}
+diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
+index 4203619..7600a0c 100644
+--- a/drivers/usb/gadget/dummy_hcd.c
++++ b/drivers/usb/gadget/dummy_hcd.c
+@@ -542,13 +542,14 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
+               req->req.context = dum;
+               req->req.complete = fifo_complete;
++              list_add_tail(&req->queue, &ep->queue);
+               spin_unlock (&dum->lock);
+               _req->actual = _req->length;
+               _req->status = 0;
+               _req->complete (_ep, _req);
+               spin_lock (&dum->lock);
+-      }
+-      list_add_tail (&req->queue, &ep->queue);
++      }  else
++              list_add_tail(&req->queue, &ep->queue);
+       spin_unlock_irqrestore (&dum->lock, flags);
+       /* real hardware would likely enable transfers here, in case
+@@ -862,7 +863,7 @@ static int dummy_udc_probe (struct platform_device *pdev)
+       /* maybe claim OTG support, though we won't complete HNP */
+       dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
+-      strcpy (dum->gadget.dev.bus_id, "gadget");
++      dev_set_name(&dum->gadget.dev, "gadget");
+       dum->gadget.dev.parent = &pdev->dev;
+       dum->gadget.dev.release = dummy_gadget_release;
+       rc = device_register (&dum->gadget.dev);
+@@ -1865,7 +1866,7 @@ static int dummy_hcd_probe(struct platform_device *pdev)
+       dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
+-      hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, pdev->dev.bus_id);
++      hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
+       if (!hcd)
+               return -ENOMEM;
+       the_controller = hcd_to_dummy (hcd);
+diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
+index 8bdad22..9462e30 100644
+--- a/drivers/usb/gadget/epautoconf.c
++++ b/drivers/usb/gadget/epautoconf.c
+@@ -159,6 +159,7 @@ ep_matches (
+       /* MATCH!! */
+       /* report address */
++      desc->bEndpointAddress &= USB_DIR_IN;
+       if (isdigit (ep->name [2])) {
+               u8      num = simple_strtol (&ep->name [2], NULL, 10);
+               desc->bEndpointAddress |= num;
+diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
+index 8d61ea6..bcac2e6 100644
+--- a/drivers/usb/gadget/ether.c
++++ b/drivers/usb/gadget/ether.c
+@@ -1,8 +1,9 @@
+ /*
+  * ether.c -- Ethernet gadget driver, with CDC and non-CDC options
+  *
+- * Copyright (C) 2003-2005 David Brownell
++ * Copyright (C) 2003-2005,2008 David Brownell
+  * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
++ * Copyright (C) 2008 Nokia Corporation
+  *
+  * 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
+@@ -23,18 +24,9 @@
+ #include <linux/kernel.h>
+ #include <linux/utsname.h>
+-#include <linux/device.h>
+-#include <linux/ctype.h>
+-#include <linux/etherdevice.h>
+-#include <linux/ethtool.h>
+-#include <linux/usb/ch9.h>
+-#include <linux/usb/cdc.h>
+-#include <linux/usb/gadget.h>
++#include "u_ether.h"
+-#include "gadget_chips.h"
+-
+-/*-------------------------------------------------------------------------*/
+ /*
+  * Ethernet gadget driver -- with CDC and non-CDC options
+@@ -46,7 +38,11 @@
+  * this USB-IF standard as its open-systems interoperability solution;
+  * most host side USB stacks (except from Microsoft) support it.
+  *
+- * There's some hardware that can't talk CDC.  We make that hardware
++ * This is sometimes called "CDC ECM" (Ethernet Control Model) to support
++ * TLA-soup.  "CDC ACM" (Abstract Control Model) is for modems, and a new
++ * "CDC EEM" (Ethernet Emulation Model) is starting to spread.
++ *
++ * There's some hardware that can't talk CDC ECM.  We make that hardware
+  * implement a "minimalist" vendor-agnostic CDC core:  same framing, but
+  * link-level setup only requires activating the configuration.  Only the
+  * endpoint descriptors, and product/vendor IDs, are relevant; no control
+@@ -64,70 +60,40 @@
+  * A third option is also in use.  Rather than CDC Ethernet, or something
+  * simpler, Microsoft pushes their own approach: RNDIS.  The published
+  * RNDIS specs are ambiguous and appear to be incomplete, and are also
+- * needlessly complex.
++ * needlessly complex.  They borrow more from CDC ACM than CDC ECM.
+  */
+ #define DRIVER_DESC           "Ethernet Gadget"
+-#define DRIVER_VERSION                "May Day 2005"
+-
+-static const char shortname [] = "ether";
+-static const char driver_desc [] = DRIVER_DESC;
+-
+-#define RX_EXTRA      20              /* guard against rx overflows */
+-
+-#include "rndis.h"
++#define DRIVER_VERSION                "Memorial Day 2008"
+-#ifndef       CONFIG_USB_ETH_RNDIS
+-#define rndis_uninit(x)               do{}while(0)
+-#define rndis_deregister(c)   do{}while(0)
+-#define rndis_exit()          do{}while(0)
++#ifdef CONFIG_USB_ETH_RNDIS
++#define PREFIX                        "RNDIS/"
++#else
++#define PREFIX                        ""
+ #endif
+-/* CDC and RNDIS support the same host-chosen outgoing packet filters. */
+-#define       DEFAULT_FILTER  (USB_CDC_PACKET_TYPE_BROADCAST \
+-                      |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+-                      |USB_CDC_PACKET_TYPE_PROMISCUOUS \
+-                      |USB_CDC_PACKET_TYPE_DIRECTED)
+-
+-
+-/*-------------------------------------------------------------------------*/
+-
+-struct eth_dev {
+-      spinlock_t              lock;
+-      struct usb_gadget       *gadget;
+-      struct usb_request      *req;           /* for control responses */
+-      struct usb_request      *stat_req;      /* for cdc & rndis status */
+-
+-      u8                      config;
+-      struct usb_ep           *in_ep, *out_ep, *status_ep;
+-      const struct usb_endpoint_descriptor
+-                              *in, *out, *status;
+-
+-      spinlock_t              req_lock;
+-      struct list_head        tx_reqs, rx_reqs;
+-
+-      struct net_device       *net;
+-      struct net_device_stats stats;
+-      atomic_t                tx_qlen;
+-
+-      struct work_struct      work;
+-      unsigned                zlp:1;
+-      unsigned                cdc:1;
+-      unsigned                rndis:1;
+-      unsigned                suspended:1;
+-      u16                     cdc_filter;
+-      unsigned long           todo;
+-#define       WORK_RX_MEMORY          0
+-      int                     rndis_config;
+-      u8                      host_mac [ETH_ALEN];
+-};
+-
+-/* This version autoconfigures as much as possible at run-time.
++/*
++ * This driver aims for interoperability by using CDC ECM unless
++ *
++ *            can_support_ecm()
++ *
++ * returns false, in which case it supports the CDC Subset.  By default,
++ * that returns true; most hardware has no problems with CDC ECM, that's
++ * a good default.  Previous versions of this driver had no default; this
++ * version changes that, removing overhead for new controller support.
+  *
+- * It also ASSUMES a self-powered device, without remote wakeup,
+- * although remote wakeup support would make sense.
++ *    IF YOUR HARDWARE CAN'T SUPPORT CDC ECM, UPDATE THAT ROUTINE!
+  */
++static inline bool has_rndis(void)
++{
++#ifdef        CONFIG_USB_ETH_RNDIS
++      return true;
++#else
++      return false;
++#endif
++}
++
+ /*-------------------------------------------------------------------------*/
+ /* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+@@ -137,8 +103,8 @@ struct eth_dev {
+ /* Thanks to NetChip Technologies for donating this product ID.
+  * It's for devices with only CDC Ethernet configurations.
+  */
+-#define CDC_VENDOR_NUM        0x0525          /* NetChip */
+-#define CDC_PRODUCT_NUM       0xa4a1          /* Linux-USB Ethernet Gadget */
++#define CDC_VENDOR_NUM                0x0525  /* NetChip */
++#define CDC_PRODUCT_NUM               0xa4a1  /* Linux-USB Ethernet Gadget */
+ /* For hardware that can't talk CDC, we use the same vendor ID that
+  * ARM Linux has used for ethernet-over-usb, both with sa1100 and
+@@ -162,274 +128,9 @@ struct eth_dev {
+ #define RNDIS_VENDOR_NUM      0x0525  /* NetChip */
+ #define RNDIS_PRODUCT_NUM     0xa4a2  /* Ethernet/RNDIS Gadget */
+-
+-/* Some systems will want different product identifers published in the
+- * device descriptor, either numbers or strings or both.  These string
+- * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
+- */
+-
+-static ushort idVendor;
+-module_param(idVendor, ushort, S_IRUGO);
+-MODULE_PARM_DESC(idVendor, "USB Vendor ID");
+-
+-static ushort idProduct;
+-module_param(idProduct, ushort, S_IRUGO);
+-MODULE_PARM_DESC(idProduct, "USB Product ID");
+-
+-static ushort bcdDevice;
+-module_param(bcdDevice, ushort, S_IRUGO);
+-MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
+-
+-static char *iManufacturer;
+-module_param(iManufacturer, charp, S_IRUGO);
+-MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
+-
+-static char *iProduct;
+-module_param(iProduct, charp, S_IRUGO);
+-MODULE_PARM_DESC(iProduct, "USB Product string");
+-
+-static char *iSerialNumber;
+-module_param(iSerialNumber, charp, S_IRUGO);
+-MODULE_PARM_DESC(iSerialNumber, "SerialNumber");
+-
+-/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
+-static char *dev_addr;
+-module_param(dev_addr, charp, S_IRUGO);
+-MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
+-
+-/* this address is invisible to ifconfig */
+-static char *host_addr;
+-module_param(host_addr, charp, S_IRUGO);
+-MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
+-
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/* Include CDC support if we could run on CDC-capable hardware. */
+-
+-#ifdef CONFIG_USB_GADGET_NET2280
+-#define       DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_DUMMY_HCD
+-#define       DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_GOKU
+-#define       DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_LH7A40X
+-#define DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_MQ11XX
+-#define       DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_OMAP
+-#define       DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_N9604
+-#define       DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_S3C2410
+-#define DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_AT91
+-#define DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_MUSBHSFC
+-#define DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+-#define DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_ATMEL_USBA
+-#define DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_FSL_USB2
+-#define DEV_CONFIG_CDC
+-#endif
+-
+-/* For CDC-incapable hardware, choose the simple cdc subset.
+- * Anything that talks bulk (without notable bugs) can do this.
+- */
+-#ifdef CONFIG_USB_GADGET_PXA2XX
+-#define       DEV_CONFIG_SUBSET
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_PXA27X
+-#define       DEV_CONFIG_SUBSET
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_SUPERH
+-#define       DEV_CONFIG_SUBSET
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_SA1100
+-/* use non-CDC for backwards compatibility */
+-#define       DEV_CONFIG_SUBSET
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_M66592
+-#define DEV_CONFIG_CDC
+-#endif
+-
+-#ifdef CONFIG_USB_GADGET_AMD5536UDC
+-#define       DEV_CONFIG_CDC
+-#endif
+-
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/* "main" config is either CDC, or its simple subset */
+-static inline int is_cdc(struct eth_dev *dev)
+-{
+-#if   !defined(DEV_CONFIG_SUBSET)
+-      return 1;               /* only cdc possible */
+-#elif !defined (DEV_CONFIG_CDC)
+-      return 0;               /* only subset possible */
+-#else
+-      return dev->cdc;        /* depends on what hardware we found */
+-#endif
+-}
+-
+-/* "secondary" RNDIS config may sometimes be activated */
+-static inline int rndis_active(struct eth_dev *dev)
+-{
+-#ifdef        CONFIG_USB_ETH_RNDIS
+-      return dev->rndis;
+-#else
+-      return 0;
+-#endif
+-}
+-
+-#define       subset_active(dev)      (!is_cdc(dev) && !rndis_active(dev))
+-#define       cdc_active(dev)         ( is_cdc(dev) && !rndis_active(dev))
+-
+-
+-
+-#define DEFAULT_QLEN  2       /* double buffering by default */
+-
+-/* peak bulk transfer bits-per-second */
+-#define       HS_BPS          (13 * 512 * 8 * 1000 * 8)
+-#define       FS_BPS          (19 *  64 * 1 * 1000 * 8)
+-
+-#ifdef CONFIG_USB_GADGET_DUALSPEED
+-#define       DEVSPEED        USB_SPEED_HIGH
+-
+-static unsigned qmult = 5;
+-module_param (qmult, uint, S_IRUGO|S_IWUSR);
+-
+-
+-/* for dual-speed hardware, use deeper queues at highspeed */
+-#define qlen(gadget) \
+-      (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
+-
+-static inline int BITRATE(struct usb_gadget *g)
+-{
+-      return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
+-}
+-
+-#else /* full speed (low speed doesn't do bulk) */
+-
+-#define qmult         1
+-
+-#define       DEVSPEED        USB_SPEED_FULL
+-
+-#define qlen(gadget) DEFAULT_QLEN
+-
+-static inline int BITRATE(struct usb_gadget *g)
+-{
+-      return FS_BPS;
+-}
+-#endif
+-
+-
+-/*-------------------------------------------------------------------------*/
+-
+-#define xprintk(d,level,fmt,args...) \
+-      printk(level "%s: " fmt , (d)->net->name , ## args)
+-
+-#ifdef DEBUG
+-#undef DEBUG
+-#define DEBUG(dev,fmt,args...) \
+-      xprintk(dev , KERN_DEBUG , fmt , ## args)
+-#else
+-#define DEBUG(dev,fmt,args...) \
+-      do { } while (0)
+-#endif /* DEBUG */
+-
+-#ifdef VERBOSE_DEBUG
+-#define VDEBUG        DEBUG
+-#else
+-#define VDEBUG(dev,fmt,args...) \
+-      do { } while (0)
+-#endif /* DEBUG */
+-
+-#define ERROR(dev,fmt,args...) \
+-      xprintk(dev , KERN_ERR , fmt , ## args)
+-#define WARN(dev,fmt,args...) \
+-      xprintk(dev , KERN_WARNING , fmt , ## args)
+-#define INFO(dev,fmt,args...) \
+-      xprintk(dev , KERN_INFO , fmt , ## args)
+-
+ /*-------------------------------------------------------------------------*/
+-/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly
+- * ep0 implementation:  descriptors, config management, setup().
+- * also optional class-specific notification interrupt transfer.
+- */
+-
+-/*
+- * DESCRIPTORS ... most are static, but strings and (full) configuration
+- * descriptors are built on demand.  For now we do either full CDC, or
+- * our simple subset, with RNDIS as an optional second configuration.
+- *
+- * RNDIS includes some CDC ACM descriptors ... like CDC Ethernet.  But
+- * the class descriptors match a modem (they're ignored; it's really just
+- * Ethernet functionality), they don't need the NOP altsetting, and the
+- * status transfer endpoint isn't optional.
+- */
+-
+-#define STRING_MANUFACTURER           1
+-#define STRING_PRODUCT                        2
+-#define STRING_ETHADDR                        3
+-#define STRING_DATA                   4
+-#define STRING_CONTROL                        5
+-#define STRING_RNDIS_CONTROL          6
+-#define STRING_CDC                    7
+-#define STRING_SUBSET                 8
+-#define STRING_RNDIS                  9
+-#define STRING_SERIALNUMBER           10
+-
+-/* holds our biggest descriptor (or RNDIS response) */
+-#define USB_BUFSIZ    256
+-
+-/*
+- * This device advertises one configuration, eth_config, unless RNDIS
+- * is enabled (rndis_config) on hardware supporting at least two configs.
+- *
+- * NOTE:  Controllers like superh_udc should probably be able to use
+- * an RNDIS-only configuration.
+- *
+- * FIXME define some higher-powered configurations to make it easier
+- * to recharge batteries ...
+- */
+-
+-#define DEV_CONFIG_VALUE      1       /* cdc or subset */
+-#define DEV_RNDIS_CONFIG_VALUE        2       /* rndis; optional */
+-
+-static struct usb_device_descriptor
+-device_desc = {
++static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+@@ -438,2220 +139,234 @@ device_desc = {
+       .bDeviceClass =         USB_CLASS_COMM,
+       .bDeviceSubClass =      0,
+       .bDeviceProtocol =      0,
++      /* .bMaxPacketSize0 = f(hardware) */
++      /* Vendor and product id defaults change according to what configs
++       * we support.  (As does bNumConfigurations.)  These values can
++       * also be overridden by module parameters.
++       */
+       .idVendor =             __constant_cpu_to_le16 (CDC_VENDOR_NUM),
+       .idProduct =            __constant_cpu_to_le16 (CDC_PRODUCT_NUM),
+-      .iManufacturer =        STRING_MANUFACTURER,
+-      .iProduct =             STRING_PRODUCT,
++      /* .bcdDevice = f(hardware) */
++      /* .iManufacturer = DYNAMIC */
++      /* .iProduct = DYNAMIC */
++      /* NO SERIAL NUMBER */
+       .bNumConfigurations =   1,
+ };
+-static struct usb_otg_descriptor
+-otg_descriptor = {
++static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+-      .bmAttributes =         USB_OTG_SRP,
+-};
+-
+-static struct usb_config_descriptor
+-eth_config = {
+-      .bLength =              sizeof eth_config,
+-      .bDescriptorType =      USB_DT_CONFIG,
+-
+-      /* compute wTotalLength on the fly */
+-      .bNumInterfaces =       2,
+-      .bConfigurationValue =  DEV_CONFIG_VALUE,
+-      .iConfiguration =       STRING_CDC,
+-      .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+-      .bMaxPower =            50,
+-};
+-
+-#ifdef        CONFIG_USB_ETH_RNDIS
+-static struct usb_config_descriptor
+-rndis_config = {
+-      .bLength =              sizeof rndis_config,
+-      .bDescriptorType =      USB_DT_CONFIG,
+-
+-      /* compute wTotalLength on the fly */
+-      .bNumInterfaces =       2,
+-      .bConfigurationValue =  DEV_RNDIS_CONFIG_VALUE,
+-      .iConfiguration =       STRING_RNDIS,
+-      .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+-      .bMaxPower =            50,
+-};
+-#endif
+-
+-/*
+- * Compared to the simple CDC subset, the full CDC Ethernet model adds
+- * three class descriptors, two interface descriptors, optional status
+- * endpoint.  Both have a "data" interface and two bulk endpoints.
+- * There are also differences in how control requests are handled.
+- *
+- * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the
+- * CDC-ACM (modem) spec.  Unfortunately MSFT's RNDIS driver is buggy; it
+- * may hang or oops.  Since bugfixes (or accurate specs, letting Linux
+- * work around those bugs) are unlikely to ever come from MSFT, you may
+- * wish to avoid using RNDIS.
+- *
+- * MCCI offers an alternative to RNDIS if you need to connect to Windows
+- * but have hardware that can't support CDC Ethernet.   We add descriptors
+- * to present the CDC Subset as a (nonconformant) CDC MDLM variant called
+- * "SAFE".  That borrows from both CDC Ethernet and CDC MDLM.  You can
+- * get those drivers from MCCI, or bundled with various products.
+- */
+-
+-#ifdef        DEV_CONFIG_CDC
+-static struct usb_interface_descriptor
+-control_intf = {
+-      .bLength =              sizeof control_intf,
+-      .bDescriptorType =      USB_DT_INTERFACE,
+-
+-      .bInterfaceNumber =     0,
+-      /* status endpoint is optional; this may be patched later */
+-      .bNumEndpoints =        1,
+-      .bInterfaceClass =      USB_CLASS_COMM,
+-      .bInterfaceSubClass =   USB_CDC_SUBCLASS_ETHERNET,
+-      .bInterfaceProtocol =   USB_CDC_PROTO_NONE,
+-      .iInterface =           STRING_CONTROL,
+-};
+-#endif
+-
+-#ifdef        CONFIG_USB_ETH_RNDIS
+-static const struct usb_interface_descriptor
+-rndis_control_intf = {
+-      .bLength =              sizeof rndis_control_intf,
+-      .bDescriptorType =      USB_DT_INTERFACE,
+-
+-      .bInterfaceNumber =     0,
+-      .bNumEndpoints =        1,
+-      .bInterfaceClass =      USB_CLASS_COMM,
+-      .bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
+-      .bInterfaceProtocol =   USB_CDC_ACM_PROTO_VENDOR,
+-      .iInterface =           STRING_RNDIS_CONTROL,
+-};
+-#endif
+-
+-static const struct usb_cdc_header_desc header_desc = {
+-      .bLength =              sizeof header_desc,
+-      .bDescriptorType =      USB_DT_CS_INTERFACE,
+-      .bDescriptorSubType =   USB_CDC_HEADER_TYPE,
+-
+-      .bcdCDC =               __constant_cpu_to_le16 (0x0110),
+-};
+-
+-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+-
+-static const struct usb_cdc_union_desc union_desc = {
+-      .bLength =              sizeof union_desc,
+-      .bDescriptorType =      USB_DT_CS_INTERFACE,
+-      .bDescriptorSubType =   USB_CDC_UNION_TYPE,
+-
+-      .bMasterInterface0 =    0,      /* index of control interface */
+-      .bSlaveInterface0 =     1,      /* index of DATA interface */
+-};
+-
+-#endif        /* CDC || RNDIS */
+-
+-#ifdef        CONFIG_USB_ETH_RNDIS
+-
+-static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
+-      .bLength =              sizeof call_mgmt_descriptor,
+-      .bDescriptorType =      USB_DT_CS_INTERFACE,
+-      .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
+-
+-      .bmCapabilities =       0x00,
+-      .bDataInterface =       0x01,
+-};
+-
+-static const struct usb_cdc_acm_descriptor acm_descriptor = {
+-      .bLength =              sizeof acm_descriptor,
+-      .bDescriptorType =      USB_DT_CS_INTERFACE,
+-      .bDescriptorSubType =   USB_CDC_ACM_TYPE,
+-
+-      .bmCapabilities =       0x00,
+-};
+-
+-#endif
+-
+-#ifndef DEV_CONFIG_CDC
+-
+-/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
+- * ways:  data endpoints live in the control interface, there's no data
+- * interface, and it's not used to talk to a cell phone radio.
+- */
+-
+-static const struct usb_cdc_mdlm_desc mdlm_desc = {
+-      .bLength =              sizeof mdlm_desc,
+-      .bDescriptorType =      USB_DT_CS_INTERFACE,
+-      .bDescriptorSubType =   USB_CDC_MDLM_TYPE,
+-
+-      .bcdVersion =           __constant_cpu_to_le16(0x0100),
+-      .bGUID = {
+-              0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+-              0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+-      },
+-};
+-
+-/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
+- * can't really use its struct.  All we do here is say that we're using
+- * the submode of "SAFE" which directly matches the CDC Subset.
+- */
+-static const u8 mdlm_detail_desc[] = {
+-      6,
+-      USB_DT_CS_INTERFACE,
+-      USB_CDC_MDLM_DETAIL_TYPE,
+-
+-      0,      /* "SAFE" */
+-      0,      /* network control capabilities (none) */
+-      0,      /* network data capabilities ("raw" encapsulation) */
+-};
+-
+-#endif
+-
+-static const struct usb_cdc_ether_desc ether_desc = {
+-      .bLength =              sizeof ether_desc,
+-      .bDescriptorType =      USB_DT_CS_INTERFACE,
+-      .bDescriptorSubType =   USB_CDC_ETHERNET_TYPE,
+-
+-      /* this descriptor actually adds value, surprise! */
+-      .iMACAddress =          STRING_ETHADDR,
+-      .bmEthernetStatistics = __constant_cpu_to_le32 (0), /* no statistics */
+-      .wMaxSegmentSize =      __constant_cpu_to_le16 (ETH_FRAME_LEN),
+-      .wNumberMCFilters =     __constant_cpu_to_le16 (0),
+-      .bNumberPowerFilters =  0,
+-};
+-
+-
+-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+-
+-/* include the status endpoint if we can, even where it's optional.
+- * use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
+- * packet, to simplify cancellation; and a big transfer interval, to
+- * waste less bandwidth.
+- *
+- * some drivers (like Linux 2.4 cdc-ether!) "need" it to exist even
+- * if they ignore the connect/disconnect notifications that real aether
+- * can provide.  more advanced cdc configurations might want to support
+- * encapsulated commands (vendor-specific, using control-OUT).
+- *
+- * RNDIS requires the status endpoint, since it uses that encapsulation
+- * mechanism for its funky RPC scheme.
+- */
+-
+-#define LOG2_STATUS_INTERVAL_MSEC     5       /* 1 << 5 == 32 msec */
+-#define STATUS_BYTECOUNT              16      /* 8 byte header + data */
+-
+-static struct usb_endpoint_descriptor
+-fs_status_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-
+-      .bEndpointAddress =     USB_DIR_IN,
+-      .bmAttributes =         USB_ENDPOINT_XFER_INT,
+-      .wMaxPacketSize =       __constant_cpu_to_le16 (STATUS_BYTECOUNT),
+-      .bInterval =            1 << LOG2_STATUS_INTERVAL_MSEC,
+-};
+-#endif
+-
+-#ifdef        DEV_CONFIG_CDC
+-
+-/* the default data interface has no endpoints ... */
+-
+-static const struct usb_interface_descriptor
+-data_nop_intf = {
+-      .bLength =              sizeof data_nop_intf,
+-      .bDescriptorType =      USB_DT_INTERFACE,
+-
+-      .bInterfaceNumber =     1,
+-      .bAlternateSetting =    0,
+-      .bNumEndpoints =        0,
+-      .bInterfaceClass =      USB_CLASS_CDC_DATA,
+-      .bInterfaceSubClass =   0,
+-      .bInterfaceProtocol =   0,
+-};
+-
+-/* ... but the "real" data interface has two bulk endpoints */
+-
+-static const struct usb_interface_descriptor
+-data_intf = {
+-      .bLength =              sizeof data_intf,
+-      .bDescriptorType =      USB_DT_INTERFACE,
+-
+-      .bInterfaceNumber =     1,
+-      .bAlternateSetting =    1,
+-      .bNumEndpoints =        2,
+-      .bInterfaceClass =      USB_CLASS_CDC_DATA,
+-      .bInterfaceSubClass =   0,
+-      .bInterfaceProtocol =   0,
+-      .iInterface =           STRING_DATA,
+-};
+-
+-#endif
+-
+-#ifdef        CONFIG_USB_ETH_RNDIS
+-
+-/* RNDIS doesn't activate by changing to the "real" altsetting */
+-
+-static const struct usb_interface_descriptor
+-rndis_data_intf = {
+-      .bLength =              sizeof rndis_data_intf,
+-      .bDescriptorType =      USB_DT_INTERFACE,
+-
+-      .bInterfaceNumber =     1,
+-      .bAlternateSetting =    0,
+-      .bNumEndpoints =        2,
+-      .bInterfaceClass =      USB_CLASS_CDC_DATA,
+-      .bInterfaceSubClass =   0,
+-      .bInterfaceProtocol =   0,
+-      .iInterface =           STRING_DATA,
+-};
+-
+-#endif
+-
+-#ifdef DEV_CONFIG_SUBSET
+-
+-/*
+- * "Simple" CDC-subset option is a simple vendor-neutral model that most
+- * full speed controllers can handle:  one interface, two bulk endpoints.
+- *
+- * To assist host side drivers, we fancy it up a bit, and add descriptors
+- * so some host side drivers will understand it as a "SAFE" variant.
+- */
+-
+-static const struct usb_interface_descriptor
+-subset_data_intf = {
+-      .bLength =              sizeof subset_data_intf,
+-      .bDescriptorType =      USB_DT_INTERFACE,
+-
+-      .bInterfaceNumber =     0,
+-      .bAlternateSetting =    0,
+-      .bNumEndpoints =        2,
+-      .bInterfaceClass =      USB_CLASS_COMM,
+-      .bInterfaceSubClass =   USB_CDC_SUBCLASS_MDLM,
+-      .bInterfaceProtocol =   0,
+-      .iInterface =           STRING_DATA,
+-};
+-
+-#endif        /* SUBSET */
+-
+-
+-static struct usb_endpoint_descriptor
+-fs_source_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-
+-      .bEndpointAddress =     USB_DIR_IN,
+-      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+-};
+-
+-static struct usb_endpoint_descriptor
+-fs_sink_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-
+-      .bEndpointAddress =     USB_DIR_OUT,
+-      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      /* REVISIT SRP-only hardware is possible, although
++       * it would not be called "OTG" ...
++       */
++      .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+ };
+-static const struct usb_descriptor_header *fs_eth_function [11] = {
++static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+-#ifdef DEV_CONFIG_CDC
+-      /* "cdc" mode descriptors */
+-      (struct usb_descriptor_header *) &control_intf,
+-      (struct usb_descriptor_header *) &header_desc,
+-      (struct usb_descriptor_header *) &union_desc,
+-      (struct usb_descriptor_header *) &ether_desc,
+-      /* NOTE: status endpoint may need to be removed */
+-      (struct usb_descriptor_header *) &fs_status_desc,
+-      /* data interface, with altsetting */
+-      (struct usb_descriptor_header *) &data_nop_intf,
+-      (struct usb_descriptor_header *) &data_intf,
+-      (struct usb_descriptor_header *) &fs_source_desc,
+-      (struct usb_descriptor_header *) &fs_sink_desc,
+       NULL,
+-#endif /* DEV_CONFIG_CDC */
+ };
+-static inline void __init fs_subset_descriptors(void)
+-{
+-#ifdef DEV_CONFIG_SUBSET
+-      /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
+-      fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
+-      fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+-      fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+-      fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+-      fs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+-      fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc;
+-      fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc;
+-      fs_eth_function[8] = NULL;
+-#else
+-      fs_eth_function[1] = NULL;
+-#endif
+-}
+-#ifdef        CONFIG_USB_ETH_RNDIS
+-static const struct usb_descriptor_header *fs_rndis_function [] = {
+-      (struct usb_descriptor_header *) &otg_descriptor,
+-      /* control interface matches ACM, not Ethernet */
+-      (struct usb_descriptor_header *) &rndis_control_intf,
+-      (struct usb_descriptor_header *) &header_desc,
+-      (struct usb_descriptor_header *) &call_mgmt_descriptor,
+-      (struct usb_descriptor_header *) &acm_descriptor,
+-      (struct usb_descriptor_header *) &union_desc,
+-      (struct usb_descriptor_header *) &fs_status_desc,
+-      /* data interface has no altsetting */
+-      (struct usb_descriptor_header *) &rndis_data_intf,
+-      (struct usb_descriptor_header *) &fs_source_desc,
+-      (struct usb_descriptor_header *) &fs_sink_desc,
+-      NULL,
+-};
+-#endif
+-
+-/*
+- * usb 2.0 devices need to expose both high speed and full speed
+- * descriptors, unless they only run at full speed.
+- */
+-
+-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+-static struct usb_endpoint_descriptor
+-hs_status_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-
+-      .bmAttributes =         USB_ENDPOINT_XFER_INT,
+-      .wMaxPacketSize =       __constant_cpu_to_le16 (STATUS_BYTECOUNT),
+-      .bInterval =            LOG2_STATUS_INTERVAL_MSEC + 4,
+-};
+-#endif /* DEV_CONFIG_CDC */
+-
+-static struct usb_endpoint_descriptor
+-hs_source_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-
+-      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+-      .wMaxPacketSize =       __constant_cpu_to_le16 (512),
+-};
+-
+-static struct usb_endpoint_descriptor
+-hs_sink_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-
+-      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+-      .wMaxPacketSize =       __constant_cpu_to_le16 (512),
+-};
++/* string IDs are assigned dynamically */
+-static struct usb_qualifier_descriptor
+-dev_qualifier = {
+-      .bLength =              sizeof dev_qualifier,
+-      .bDescriptorType =      USB_DT_DEVICE_QUALIFIER,
++#define STRING_MANUFACTURER_IDX               0
++#define STRING_PRODUCT_IDX            1
+-      .bcdUSB =               __constant_cpu_to_le16 (0x0200),
+-      .bDeviceClass =         USB_CLASS_COMM,
++static char manufacturer[50];
+-      .bNumConfigurations =   1,
++static struct usb_string strings_dev[] = {
++      [STRING_MANUFACTURER_IDX].s = manufacturer,
++      [STRING_PRODUCT_IDX].s = PREFIX DRIVER_DESC,
++      {  } /* end of list */
+ };
+-static const struct usb_descriptor_header *hs_eth_function [11] = {
+-      (struct usb_descriptor_header *) &otg_descriptor,
+-#ifdef DEV_CONFIG_CDC
+-      /* "cdc" mode descriptors */
+-      (struct usb_descriptor_header *) &control_intf,
+-      (struct usb_descriptor_header *) &header_desc,
+-      (struct usb_descriptor_header *) &union_desc,
+-      (struct usb_descriptor_header *) &ether_desc,
+-      /* NOTE: status endpoint may need to be removed */
+-      (struct usb_descriptor_header *) &hs_status_desc,
+-      /* data interface, with altsetting */
+-      (struct usb_descriptor_header *) &data_nop_intf,
+-      (struct usb_descriptor_header *) &data_intf,
+-      (struct usb_descriptor_header *) &hs_source_desc,
+-      (struct usb_descriptor_header *) &hs_sink_desc,
+-      NULL,
+-#endif /* DEV_CONFIG_CDC */
++static struct usb_gadget_strings stringtab_dev = {
++      .language       = 0x0409,       /* en-us */
++      .strings        = strings_dev,
+ };
+-static inline void __init hs_subset_descriptors(void)
+-{
+-#ifdef DEV_CONFIG_SUBSET
+-      /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
+-      hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
+-      hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+-      hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+-      hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+-      hs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+-      hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc;
+-      hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc;
+-      hs_eth_function[8] = NULL;
+-#else
+-      hs_eth_function[1] = NULL;
+-#endif
+-}
+-
+-#ifdef        CONFIG_USB_ETH_RNDIS
+-static const struct usb_descriptor_header *hs_rndis_function [] = {
+-      (struct usb_descriptor_header *) &otg_descriptor,
+-      /* control interface matches ACM, not Ethernet */
+-      (struct usb_descriptor_header *) &rndis_control_intf,
+-      (struct usb_descriptor_header *) &header_desc,
+-      (struct usb_descriptor_header *) &call_mgmt_descriptor,
+-      (struct usb_descriptor_header *) &acm_descriptor,
+-      (struct usb_descriptor_header *) &union_desc,
+-      (struct usb_descriptor_header *) &hs_status_desc,
+-      /* data interface has no altsetting */
+-      (struct usb_descriptor_header *) &rndis_data_intf,
+-      (struct usb_descriptor_header *) &hs_source_desc,
+-      (struct usb_descriptor_header *) &hs_sink_desc,
++static struct usb_gadget_strings *dev_strings[] = {
++      &stringtab_dev,
+       NULL,
+ };
+-#endif
+-
+-
+-/* maxpacket and other transfer characteristics vary by speed. */
+-static inline struct usb_endpoint_descriptor *
+-ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+-              struct usb_endpoint_descriptor *fs)
+-{
+-      if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+-              return hs;
+-      return fs;
+-}
++static u8 hostaddr[ETH_ALEN];
+ /*-------------------------------------------------------------------------*/
+-/* descriptors that are built on-demand */
+-
+-static char                           manufacturer [50];
+-static char                           product_desc [40] = DRIVER_DESC;
+-static char                           serial_number [20];
+-
+-/* address that the host will use ... usually assigned at random */
+-static char                           ethaddr [2 * ETH_ALEN + 1];
+-
+-/* static strings, in UTF-8 */
+-static struct usb_string              strings [] = {
+-      { STRING_MANUFACTURER,  manufacturer, },
+-      { STRING_PRODUCT,       product_desc, },
+-      { STRING_SERIALNUMBER,  serial_number, },
+-      { STRING_DATA,          "Ethernet Data", },
+-      { STRING_ETHADDR,       ethaddr, },
+-#ifdef        DEV_CONFIG_CDC
+-      { STRING_CDC,           "CDC Ethernet", },
+-      { STRING_CONTROL,       "CDC Communications Control", },
+-#endif
+-#ifdef        DEV_CONFIG_SUBSET
+-      { STRING_SUBSET,        "CDC Ethernet Subset", },
+-#endif
+-#ifdef        CONFIG_USB_ETH_RNDIS
+-      { STRING_RNDIS,         "RNDIS", },
+-      { STRING_RNDIS_CONTROL, "RNDIS Communications Control", },
+-#endif
+-      {  }            /* end of list */
+-};
+-
+-static struct usb_gadget_strings      stringtab = {
+-      .language       = 0x0409,       /* en-us */
+-      .strings        = strings,
+-};
+-
+ /*
+- * one config, two interfaces:  control, data.
+- * complications: class descriptors, and an altsetting.
+- */
+-static int
+-config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
+-{
+-      int                                     len;
+-      const struct usb_config_descriptor      *config;
+-      const struct usb_descriptor_header      **function;
+-      int                                     hs = 0;
+-
+-      if (gadget_is_dualspeed(g)) {
+-              hs = (g->speed == USB_SPEED_HIGH);
+-              if (type == USB_DT_OTHER_SPEED_CONFIG)
+-                      hs = !hs;
+-      }
+-#define which_fn(t)   (hs ? hs_ ## t ## _function : fs_ ## t ## _function)
+-
+-      if (index >= device_desc.bNumConfigurations)
+-              return -EINVAL;
+-
+-#ifdef        CONFIG_USB_ETH_RNDIS
+-      /* list the RNDIS config first, to make Microsoft's drivers
+-       * happy. DOCSIS 1.0 needs this too.
+-       */
+-      if (device_desc.bNumConfigurations == 2 && index == 0) {
+-              config = &rndis_config;
+-              function = which_fn (rndis);
+-      } else
+-#endif
+-      {
+-              config = &eth_config;
+-              function = which_fn (eth);
+-      }
+-
+-      /* for now, don't advertise srp-only devices */
+-      if (!is_otg)
+-              function++;
+-
+-      len = usb_gadget_config_buf (config, buf, USB_BUFSIZ, function);
+-      if (len < 0)
+-              return len;
+-      ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
+-      return len;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static void eth_start (struct eth_dev *dev, gfp_t gfp_flags);
+-static int alloc_requests (struct eth_dev *dev, unsigned n, gfp_t gfp_flags);
+-
+-static int
+-set_ether_config (struct eth_dev *dev, gfp_t gfp_flags)
+-{
+-      int                                     result = 0;
+-      struct usb_gadget                       *gadget = dev->gadget;
+-
+-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+-      /* status endpoint used for RNDIS and (optionally) CDC */
+-      if (!subset_active(dev) && dev->status_ep) {
+-              dev->status = ep_desc (gadget, &hs_status_desc,
+-                                              &fs_status_desc);
+-              dev->status_ep->driver_data = dev;
+-
+-              result = usb_ep_enable (dev->status_ep, dev->status);
+-              if (result != 0) {
+-                      DEBUG (dev, "enable %s --> %d\n",
+-                              dev->status_ep->name, result);
+-                      goto done;
+-              }
+-      }
+-#endif
+-
+-      dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+-      dev->in_ep->driver_data = dev;
+-
+-      dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+-      dev->out_ep->driver_data = dev;
+-
+-      /* With CDC,  the host isn't allowed to use these two data
+-       * endpoints in the default altsetting for the interface.
+-       * so we don't activate them yet.  Reset from SET_INTERFACE.
+-       *
+-       * Strictly speaking RNDIS should work the same: activation is
+-       * a side effect of setting a packet filter.  Deactivation is
+-       * from REMOTE_NDIS_HALT_MSG, reset from REMOTE_NDIS_RESET_MSG.
+-       */
+-      if (!cdc_active(dev)) {
+-              result = usb_ep_enable (dev->in_ep, dev->in);
+-              if (result != 0) {
+-                      DEBUG(dev, "enable %s --> %d\n",
+-                              dev->in_ep->name, result);
+-                      goto done;
+-              }
+-
+-              result = usb_ep_enable (dev->out_ep, dev->out);
+-              if (result != 0) {
+-                      DEBUG (dev, "enable %s --> %d\n",
+-                              dev->out_ep->name, result);
+-                      goto done;
+-              }
+-      }
+-
+-done:
+-      if (result == 0)
+-              result = alloc_requests (dev, qlen (gadget), gfp_flags);
+-
+-      /* on error, disable any endpoints  */
+-      if (result < 0) {
+-              if (!subset_active(dev) && dev->status_ep)
+-                      (void) usb_ep_disable (dev->status_ep);
+-              dev->status = NULL;
+-              (void) usb_ep_disable (dev->in_ep);
+-              (void) usb_ep_disable (dev->out_ep);
+-              dev->in = NULL;
+-              dev->out = NULL;
+-      }
+-
+-      /* activate non-CDC configs right away
+-       * this isn't strictly according to the RNDIS spec
+-       */
+-      else if (!cdc_active (dev)) {
+-              netif_carrier_on (dev->net);
+-              if (netif_running (dev->net)) {
+-                      spin_unlock (&dev->lock);
+-                      eth_start (dev, GFP_ATOMIC);
+-                      spin_lock (&dev->lock);
+-              }
+-      }
+-
+-      if (result == 0)
+-              DEBUG (dev, "qlen %d\n", qlen (gadget));
+-
+-      /* caller is responsible for cleanup on error */
+-      return result;
+-}
+-
+-static void eth_reset_config (struct eth_dev *dev)
+-{
+-      struct usb_request      *req;
+-
+-      if (dev->config == 0)
+-              return;
+-
+-      DEBUG (dev, "%s\n", __func__);
+-
+-      netif_stop_queue (dev->net);
+-      netif_carrier_off (dev->net);
+-      rndis_uninit(dev->rndis_config);
+-
+-      /* disable endpoints, forcing (synchronous) completion of
+-       * pending i/o.  then free the requests.
+-       */
+-      if (dev->in) {
+-              usb_ep_disable (dev->in_ep);
+-              spin_lock(&dev->req_lock);
+-              while (likely (!list_empty (&dev->tx_reqs))) {
+-                      req = container_of (dev->tx_reqs.next,
+-                                              struct usb_request, list);
+-                      list_del (&req->list);
+-
+-                      spin_unlock(&dev->req_lock);
+-                      usb_ep_free_request (dev->in_ep, req);
+-                      spin_lock(&dev->req_lock);
+-              }
+-              spin_unlock(&dev->req_lock);
+-      }
+-      if (dev->out) {
+-              usb_ep_disable (dev->out_ep);
+-              spin_lock(&dev->req_lock);
+-              while (likely (!list_empty (&dev->rx_reqs))) {
+-                      req = container_of (dev->rx_reqs.next,
+-                                              struct usb_request, list);
+-                      list_del (&req->list);
+-
+-                      spin_unlock(&dev->req_lock);
+-                      usb_ep_free_request (dev->out_ep, req);
+-                      spin_lock(&dev->req_lock);
+-              }
+-              spin_unlock(&dev->req_lock);
+-      }
+-
+-      if (dev->status) {
+-              usb_ep_disable (dev->status_ep);
+-      }
+-      dev->rndis = 0;
+-      dev->cdc_filter = 0;
+-      dev->config = 0;
+-}
+-
+-/* change our operational config.  must agree with the code
+- * that returns config descriptors, and altsetting code.
++ * We may not have an RNDIS configuration, but if we do it needs to be
++ * the first one present.  That's to make Microsoft's drivers happy,
++ * and to follow DOCSIS 1.0 (cable modem standard).
+  */
+-static int
+-eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags)
++static int __init rndis_do_config(struct usb_configuration *c)
+ {
+-      int                     result = 0;
+-      struct usb_gadget       *gadget = dev->gadget;
+-
+-      if (gadget_is_sa1100 (gadget)
+-                      && dev->config
+-                      && atomic_read (&dev->tx_qlen) != 0) {
+-              /* tx fifo is full, but we can't clear it...*/
+-              INFO (dev, "can't change configurations\n");
+-              return -ESPIPE;
+-      }
+-      eth_reset_config (dev);
+-
+-      switch (number) {
+-      case DEV_CONFIG_VALUE:
+-              result = set_ether_config (dev, gfp_flags);
+-              break;
+-#ifdef        CONFIG_USB_ETH_RNDIS
+-      case DEV_RNDIS_CONFIG_VALUE:
+-              dev->rndis = 1;
+-              result = set_ether_config (dev, gfp_flags);
+-              break;
+-#endif
+-      default:
+-              result = -EINVAL;
+-              /* FALL THROUGH */
+-      case 0:
+-              break;
+-      }
+-
+-      if (result) {
+-              if (number)
+-                      eth_reset_config (dev);
+-              usb_gadget_vbus_draw(dev->gadget,
+-                              gadget_is_otg(dev->gadget) ? 8 : 100);
+-      } else {
+-              char *speed;
+-              unsigned power;
+-
+-              power = 2 * eth_config.bMaxPower;
+-              usb_gadget_vbus_draw(dev->gadget, power);
++      /* FIXME alloc iConfiguration string, set it in c->strings */
+-              switch (gadget->speed) {
+-              case USB_SPEED_FULL:    speed = "full"; break;
+-#ifdef CONFIG_USB_GADGET_DUALSPEED
+-              case USB_SPEED_HIGH:    speed = "high"; break;
+-#endif
+-              default:                speed = "?"; break;
+-              }
+-
+-              dev->config = number;
+-              INFO (dev, "%s speed config #%d: %d mA, %s, using %s\n",
+-                              speed, number, power, driver_desc,
+-                              rndis_active(dev)
+-                                      ? "RNDIS"
+-                                      : (cdc_active(dev)
+-                                              ? "CDC Ethernet"
+-                                              : "CDC Ethernet Subset"));
++      if (gadget_is_otg(c->cdev->gadget)) {
++              c->descriptors = otg_desc;
++              c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+-      return result;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-#ifdef        DEV_CONFIG_CDC
+-/* The interrupt endpoint is used in CDC networking models (Ethernet, ATM)
+- * only to notify the host about link status changes (which we support) or
+- * report completion of some encapsulated command (as used in RNDIS).  Since
+- * we want this CDC Ethernet code to be vendor-neutral, we don't use that
+- * command mechanism; and only one status request is ever queued.
+- */
+-
+-static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
+-{
+-      struct usb_cdc_notification     *event = req->buf;
+-      int                             value = req->status;
+-      struct eth_dev                  *dev = ep->driver_data;
+-
+-      /* issue the second notification if host reads the first */
+-      if (event->bNotificationType == USB_CDC_NOTIFY_NETWORK_CONNECTION
+-                      && value == 0) {
+-              __le32  *data = req->buf + sizeof *event;
+-
+-              event->bmRequestType = 0xA1;
+-              event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
+-              event->wValue = __constant_cpu_to_le16 (0);
+-              event->wIndex = __constant_cpu_to_le16 (1);
+-              event->wLength = __constant_cpu_to_le16 (8);
+-
+-              /* SPEED_CHANGE data is up/down speeds in bits/sec */
+-              data [0] = data [1] = cpu_to_le32 (BITRATE (dev->gadget));
+-
+-              req->length = STATUS_BYTECOUNT;
+-              value = usb_ep_queue (ep, req, GFP_ATOMIC);
+-              DEBUG (dev, "send SPEED_CHANGE --> %d\n", value);
+-              if (value == 0)
+-                      return;
+-      } else if (value != -ECONNRESET)
+-              DEBUG (dev, "event %02x --> %d\n",
+-                      event->bNotificationType, value);
+-      req->context = NULL;
++      return rndis_bind_config(c, hostaddr);
+ }
+-static void issue_start_status (struct eth_dev *dev)
+-{
+-      struct usb_request              *req = dev->stat_req;
+-      struct usb_cdc_notification     *event;
+-      int                             value;
+-
+-      DEBUG (dev, "%s, flush old status first\n", __func__);
+-
+-      /* flush old status
+-       *
+-       * FIXME ugly idiom, maybe we'd be better with just
+-       * a "cancel the whole queue" primitive since any
+-       * unlink-one primitive has way too many error modes.
+-       * here, we "know" toggle is already clear...
+-       *
+-       * FIXME iff req->context != null just dequeue it
+-       */
+-      usb_ep_disable (dev->status_ep);
+-      usb_ep_enable (dev->status_ep, dev->status);
+-
+-      /* 3.8.1 says to issue first NETWORK_CONNECTION, then
+-       * a SPEED_CHANGE.  could be useful in some configs.
+-       */
+-      event = req->buf;
+-      event->bmRequestType = 0xA1;
+-      event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
+-      event->wValue = __constant_cpu_to_le16 (1);     /* connected */
+-      event->wIndex = __constant_cpu_to_le16 (1);
+-      event->wLength = 0;
+-
+-      req->length = sizeof *event;
+-      req->complete = eth_status_complete;
+-      req->context = dev;
+-
+-      value = usb_ep_queue (dev->status_ep, req, GFP_ATOMIC);
+-      if (value < 0)
+-              DEBUG (dev, "status buf queue --> %d\n", value);
+-}
+-
+-#endif
++static struct usb_configuration rndis_config_driver = {
++      .label                  = "RNDIS",
++      .bind                   = rndis_do_config,
++      .bConfigurationValue    = 2,
++      /* .iConfiguration = DYNAMIC */
++      .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
++      .bMaxPower              = 1,    /* 2 mA, minimal */
++};
+ /*-------------------------------------------------------------------------*/
+-static void eth_setup_complete (struct usb_ep *ep, struct usb_request *req)
+-{
+-      if (req->status || req->actual != req->length)
+-              DEBUG ((struct eth_dev *) ep->driver_data,
+-                              "setup complete --> %d, %d/%d\n",
+-                              req->status, req->actual, req->length);
+-}
+-
+-#ifdef CONFIG_USB_ETH_RNDIS
+-
+-static void rndis_response_complete (struct usb_ep *ep, struct usb_request *req)
+-{
+-      if (req->status || req->actual != req->length)
+-              DEBUG ((struct eth_dev *) ep->driver_data,
+-                      "rndis response complete --> %d, %d/%d\n",
+-                      req->status, req->actual, req->length);
+-
+-      /* done sending after USB_CDC_GET_ENCAPSULATED_RESPONSE */
+-}
+-
+-static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req)
+-{
+-      struct eth_dev          *dev = ep->driver_data;
+-      int                     status;
+-
+-      /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
+-      spin_lock(&dev->lock);
+-      status = rndis_msg_parser (dev->rndis_config, (u8 *) req->buf);
+-      if (status < 0)
+-              ERROR(dev, "%s: rndis parse error %d\n", __func__, status);
+-      spin_unlock(&dev->lock);
+-}
+-
+-#endif        /* RNDIS */
+-
+ /*
+- * The setup() callback implements all the ep0 functionality that's not
+- * handled lower down.  CDC has a number of less-common features:
+- *
+- *  - two interfaces:  control, and ethernet data
+- *  - Ethernet data interface has two altsettings:  default, and active
+- *  - class-specific descriptors for the control interface
+- *  - class-specific control requests
++ * We _always_ have an ECM or CDC Subset configuration.
+  */
+-static int
+-eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
++static int __init eth_do_config(struct usb_configuration *c)
+ {
+-      struct eth_dev          *dev = get_gadget_data (gadget);
+-      struct usb_request      *req = dev->req;
+-      int                     value = -EOPNOTSUPP;
+-      u16                     wIndex = le16_to_cpu(ctrl->wIndex);
+-      u16                     wValue = le16_to_cpu(ctrl->wValue);
+-      u16                     wLength = le16_to_cpu(ctrl->wLength);
+-
+-      /* descriptors just go into the pre-allocated ep0 buffer,
+-       * while config change events may enable network traffic.
+-       */
+-      req->complete = eth_setup_complete;
+-      switch (ctrl->bRequest) {
+-
+-      case USB_REQ_GET_DESCRIPTOR:
+-              if (ctrl->bRequestType != USB_DIR_IN)
+-                      break;
+-              switch (wValue >> 8) {
+-
+-              case USB_DT_DEVICE:
+-                      value = min (wLength, (u16) sizeof device_desc);
+-                      memcpy (req->buf, &device_desc, value);
+-                      break;
+-              case USB_DT_DEVICE_QUALIFIER:
+-                      if (!gadget_is_dualspeed(gadget))
+-                              break;
+-                      value = min (wLength, (u16) sizeof dev_qualifier);
+-                      memcpy (req->buf, &dev_qualifier, value);
+-                      break;
+-
+-              case USB_DT_OTHER_SPEED_CONFIG:
+-                      if (!gadget_is_dualspeed(gadget))
+-                              break;
+-                      // FALLTHROUGH
+-              case USB_DT_CONFIG:
+-                      value = config_buf(gadget, req->buf,
+-                                      wValue >> 8,
+-                                      wValue & 0xff,
+-                                      gadget_is_otg(gadget));
+-                      if (value >= 0)
+-                              value = min (wLength, (u16) value);
+-                      break;
+-
+-              case USB_DT_STRING:
+-                      value = usb_gadget_get_string (&stringtab,
+-                                      wValue & 0xff, req->buf);
+-                      if (value >= 0)
+-                              value = min (wLength, (u16) value);
+-                      break;
+-              }
+-              break;
+-
+-      case USB_REQ_SET_CONFIGURATION:
+-              if (ctrl->bRequestType != 0)
+-                      break;
+-              if (gadget->a_hnp_support)
+-                      DEBUG (dev, "HNP available\n");
+-              else if (gadget->a_alt_hnp_support)
+-                      DEBUG (dev, "HNP needs a different root port\n");
+-              spin_lock (&dev->lock);
+-              value = eth_set_config (dev, wValue, GFP_ATOMIC);
+-              spin_unlock (&dev->lock);
+-              break;
+-      case USB_REQ_GET_CONFIGURATION:
+-              if (ctrl->bRequestType != USB_DIR_IN)
+-                      break;
+-              *(u8 *)req->buf = dev->config;
+-              value = min (wLength, (u16) 1);
+-              break;
+-
+-      case USB_REQ_SET_INTERFACE:
+-              if (ctrl->bRequestType != USB_RECIP_INTERFACE
+-                              || !dev->config
+-                              || wIndex > 1)
+-                      break;
+-              if (!cdc_active(dev) && wIndex != 0)
+-                      break;
+-              spin_lock (&dev->lock);
+-
+-              /* PXA hardware partially handles SET_INTERFACE;
+-               * we need to kluge around that interference.
+-               */
+-              if (gadget_is_pxa (gadget)) {
+-                      value = eth_set_config (dev, DEV_CONFIG_VALUE,
+-                                              GFP_ATOMIC);
+-                      goto done_set_intf;
+-              }
+-
+-#ifdef DEV_CONFIG_CDC
+-              switch (wIndex) {
+-              case 0:         /* control/master intf */
+-                      if (wValue != 0)
+-                              break;
+-                      if (dev->status) {
+-                              usb_ep_disable (dev->status_ep);
+-                              usb_ep_enable (dev->status_ep, dev->status);
+-                      }
+-                      value = 0;
+-                      break;
+-              case 1:         /* data intf */
+-                      if (wValue > 1)
+-                              break;
+-                      usb_ep_disable (dev->in_ep);
+-                      usb_ep_disable (dev->out_ep);
+-
+-                      /* CDC requires the data transfers not be done from
+-                       * the default interface setting ... also, setting
+-                       * the non-default interface resets filters etc.
+-                       */
+-                      if (wValue == 1) {
+-                              if (!cdc_active (dev))
+-                                      break;
+-                              usb_ep_enable (dev->in_ep, dev->in);
+-                              usb_ep_enable (dev->out_ep, dev->out);
+-                              dev->cdc_filter = DEFAULT_FILTER;
+-                              netif_carrier_on (dev->net);
+-                              if (dev->status)
+-                                      issue_start_status (dev);
+-                              if (netif_running (dev->net)) {
+-                                      spin_unlock (&dev->lock);
+-                                      eth_start (dev, GFP_ATOMIC);
+-                                      spin_lock (&dev->lock);
+-                              }
+-                      } else {
+-                              netif_stop_queue (dev->net);
+-                              netif_carrier_off (dev->net);
+-                      }
+-                      value = 0;
+-                      break;
+-              }
+-#else
+-              /* FIXME this is wrong, as is the assumption that
+-               * all non-PXA hardware talks real CDC ...
+-               */
+-              dev_warn (&gadget->dev, "set_interface ignored!\n");
+-#endif /* DEV_CONFIG_CDC */
+-
+-done_set_intf:
+-              spin_unlock (&dev->lock);
+-              break;
+-      case USB_REQ_GET_INTERFACE:
+-              if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
+-                              || !dev->config
+-                              || wIndex > 1)
+-                      break;
+-              if (!(cdc_active(dev) || rndis_active(dev)) && wIndex != 0)
+-                      break;
+-
+-              /* for CDC, iff carrier is on, data interface is active. */
+-              if (rndis_active(dev) || wIndex != 1)
+-                      *(u8 *)req->buf = 0;
+-              else
+-                      *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0;
+-              value = min (wLength, (u16) 1);
+-              break;
+-
+-#ifdef DEV_CONFIG_CDC
+-      case USB_CDC_SET_ETHERNET_PACKET_FILTER:
+-              /* see 6.2.30: no data, wIndex = interface,
+-               * wValue = packet filter bitmap
+-               */
+-              if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
+-                              || !cdc_active(dev)
+-                              || wLength != 0
+-                              || wIndex > 1)
+-                      break;
+-              DEBUG (dev, "packet filter %02x\n", wValue);
+-              dev->cdc_filter = wValue;
+-              value = 0;
+-              break;
+-
+-      /* and potentially:
+-       * case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
+-       * case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER:
+-       * case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER:
+-       * case USB_CDC_GET_ETHERNET_STATISTIC:
+-       */
+-
+-#endif /* DEV_CONFIG_CDC */
++      /* FIXME alloc iConfiguration string, set it in c->strings */
+-#ifdef CONFIG_USB_ETH_RNDIS
+-      /* RNDIS uses the CDC command encapsulation mechanism to implement
+-       * an RPC scheme, with much getting/setting of attributes by OID.
+-       */
+-      case USB_CDC_SEND_ENCAPSULATED_COMMAND:
+-              if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
+-                              || !rndis_active(dev)
+-                              || wLength > USB_BUFSIZ
+-                              || wValue
+-                              || rndis_control_intf.bInterfaceNumber
+-                                      != wIndex)
+-                      break;
+-              /* read the request, then process it */
+-              value = wLength;
+-              req->complete = rndis_command_complete;
+-              /* later, rndis_control_ack () sends a notification */
+-              break;
+-
+-      case USB_CDC_GET_ENCAPSULATED_RESPONSE:
+-              if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)
+-                                      == ctrl->bRequestType
+-                              && rndis_active(dev)
+-                              // && wLength >= 0x0400
+-                              && !wValue
+-                              && rndis_control_intf.bInterfaceNumber
+-                                      == wIndex) {
+-                      u8 *buf;
+-                      u32 n;
+-
+-                      /* return the result */
+-                      buf = rndis_get_next_response(dev->rndis_config, &n);
+-                      if (buf) {
+-                              memcpy(req->buf, buf, n);
+-                              req->complete = rndis_response_complete;
+-                              rndis_free_response(dev->rndis_config, buf);
+-                              value = n;
+-                      }
+-                      /* else stalls ... spec says to avoid that */
+-              }
+-              break;
+-#endif        /* RNDIS */
+-
+-      default:
+-              VDEBUG (dev,
+-                      "unknown control req%02x.%02x v%04x i%04x l%d\n",
+-                      ctrl->bRequestType, ctrl->bRequest,
+-                      wValue, wIndex, wLength);
++      if (gadget_is_otg(c->cdev->gadget)) {
++              c->descriptors = otg_desc;
++              c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+-      /* respond with data transfer before status phase? */
+-      if (value >= 0) {
+-              req->length = value;
+-              req->zero = value < wLength
+-                              && (value % gadget->ep0->maxpacket) == 0;
+-              value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+-              if (value < 0) {
+-                      DEBUG (dev, "ep_queue --> %d\n", value);
+-                      req->status = 0;
+-                      eth_setup_complete (gadget->ep0, req);
+-              }
+-      }
+-
+-      /* host either stalls (value < 0) or reports success */
+-      return value;
+-}
+-
+-static void
+-eth_disconnect (struct usb_gadget *gadget)
+-{
+-      struct eth_dev          *dev = get_gadget_data (gadget);
+-      unsigned long           flags;
+-
+-      spin_lock_irqsave (&dev->lock, flags);
+-      netif_stop_queue (dev->net);
+-      netif_carrier_off (dev->net);
+-      eth_reset_config (dev);
+-      spin_unlock_irqrestore (&dev->lock, flags);
+-
+-      /* FIXME RNDIS should enter RNDIS_UNINITIALIZED */
+-
+-      /* next we may get setup() calls to enumerate new connections;
+-       * or an unbind() during shutdown (including removing module).
+-       */
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/* NETWORK DRIVER HOOKUP (to the layer above this driver) */
+-
+-static int eth_change_mtu (struct net_device *net, int new_mtu)
+-{
+-      struct eth_dev  *dev = netdev_priv(net);
+-
+-      if (dev->rndis)
+-              return -EBUSY;
+-
+-      if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
+-              return -ERANGE;
+-      /* no zero-length packet read wanted after mtu-sized packets */
+-      if (((new_mtu + sizeof (struct ethhdr)) % dev->in_ep->maxpacket) == 0)
+-              return -EDOM;
+-      net->mtu = new_mtu;
+-      return 0;
+-}
+-
+-static struct net_device_stats *eth_get_stats (struct net_device *net)
+-{
+-      return &((struct eth_dev *)netdev_priv(net))->stats;
+-}
+-
+-static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
+-{
+-      struct eth_dev  *dev = netdev_priv(net);
+-      strlcpy(p->driver, shortname, sizeof p->driver);
+-      strlcpy(p->version, DRIVER_VERSION, sizeof p->version);
+-      strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version);
+-      strlcpy (p->bus_info, dev->gadget->dev.bus_id, sizeof p->bus_info);
+-}
+-
+-static u32 eth_get_link(struct net_device *net)
+-{
+-      struct eth_dev  *dev = netdev_priv(net);
+-      return dev->gadget->speed != USB_SPEED_UNKNOWN;
+-}
+-
+-static struct ethtool_ops ops = {
+-      .get_drvinfo = eth_get_drvinfo,
+-      .get_link = eth_get_link
+-};
+-
+-static void defer_kevent (struct eth_dev *dev, int flag)
+-{
+-      if (test_and_set_bit (flag, &dev->todo))
+-              return;
+-      if (!schedule_work (&dev->work))
+-              ERROR (dev, "kevent %d may have been dropped\n", flag);
++      if (can_support_ecm(c->cdev->gadget))
++              return ecm_bind_config(c, hostaddr);
+       else
+-              DEBUG (dev, "kevent %d scheduled\n", flag);
+-}
+-
+-static void rx_complete (struct usb_ep *ep, struct usb_request *req);
+-
+-static int
+-rx_submit (struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
+-{
+-      struct sk_buff          *skb;
+-      int                     retval = -ENOMEM;
+-      size_t                  size;
+-
+-      /* Padding up to RX_EXTRA handles minor disagreements with host.
+-       * Normally we use the USB "terminate on short read" convention;
+-       * so allow up to (N*maxpacket), since that memory is normally
+-       * already allocated.  Some hardware doesn't deal well with short
+-       * reads (e.g. DMA must be N*maxpacket), so for now don't trim a
+-       * byte off the end (to force hardware errors on overflow).
+-       *
+-       * RNDIS uses internal framing, and explicitly allows senders to
+-       * pad to end-of-packet.  That's potentially nice for speed,
+-       * but means receivers can't recover synch on their own.
+-       */
+-      size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA);
+-      size += dev->out_ep->maxpacket - 1;
+-      if (rndis_active(dev))
+-              size += sizeof (struct rndis_packet_msg_type);
+-      size -= size % dev->out_ep->maxpacket;
+-
+-      skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
+-      if (skb == NULL) {
+-              DEBUG (dev, "no rx skb\n");
+-              goto enomem;
+-      }
+-
+-      /* Some platforms perform better when IP packets are aligned,
+-       * but on at least one, checksumming fails otherwise.  Note:
+-       * RNDIS headers involve variable numbers of LE32 values.
+-       */
+-      skb_reserve(skb, NET_IP_ALIGN);
+-
+-      req->buf = skb->data;
+-      req->length = size;
+-      req->complete = rx_complete;
+-      req->context = skb;
+-
+-      retval = usb_ep_queue (dev->out_ep, req, gfp_flags);
+-      if (retval == -ENOMEM)
+-enomem:
+-              defer_kevent (dev, WORK_RX_MEMORY);
+-      if (retval) {
+-              DEBUG (dev, "rx submit --> %d\n", retval);
+-              if (skb)
+-                      dev_kfree_skb_any(skb);
+-              spin_lock(&dev->req_lock);
+-              list_add (&req->list, &dev->rx_reqs);
+-              spin_unlock(&dev->req_lock);
+-      }
+-      return retval;
+-}
+-
+-static void rx_complete (struct usb_ep *ep, struct usb_request *req)
+-{
+-      struct sk_buff  *skb = req->context;
+-      struct eth_dev  *dev = ep->driver_data;
+-      int             status = req->status;
+-
+-      switch (status) {
+-
+-      /* normal completion */
+-      case 0:
+-              skb_put (skb, req->actual);
+-              /* we know MaxPacketsPerTransfer == 1 here */
+-              if (rndis_active(dev))
+-                      status = rndis_rm_hdr (skb);
+-              if (status < 0
+-                              || ETH_HLEN > skb->len
+-                              || skb->len > ETH_FRAME_LEN) {
+-                      dev->stats.rx_errors++;
+-                      dev->stats.rx_length_errors++;
+-                      DEBUG (dev, "rx length %d\n", skb->len);
+-                      break;
+-              }
+-
+-              skb->protocol = eth_type_trans (skb, dev->net);
+-              dev->stats.rx_packets++;
+-              dev->stats.rx_bytes += skb->len;
+-
+-              /* no buffer copies needed, unless hardware can't
+-               * use skb buffers.
+-               */
+-              status = netif_rx (skb);
+-              skb = NULL;
+-              break;
+-
+-      /* software-driven interface shutdown */
+-      case -ECONNRESET:               // unlink
+-      case -ESHUTDOWN:                // disconnect etc
+-              VDEBUG (dev, "rx shutdown, code %d\n", status);
+-              goto quiesce;
+-
+-      /* for hardware automagic (such as pxa) */
+-      case -ECONNABORTED:             // endpoint reset
+-              DEBUG (dev, "rx %s reset\n", ep->name);
+-              defer_kevent (dev, WORK_RX_MEMORY);
+-quiesce:
+-              dev_kfree_skb_any (skb);
+-              goto clean;
+-
+-      /* data overrun */
+-      case -EOVERFLOW:
+-              dev->stats.rx_over_errors++;
+-              // FALLTHROUGH
+-
+-      default:
+-              dev->stats.rx_errors++;
+-              DEBUG (dev, "rx status %d\n", status);
+-              break;
+-      }
+-
+-      if (skb)
+-              dev_kfree_skb_any (skb);
+-      if (!netif_running (dev->net)) {
+-clean:
+-              spin_lock(&dev->req_lock);
+-              list_add (&req->list, &dev->rx_reqs);
+-              spin_unlock(&dev->req_lock);
+-              req = NULL;
+-      }
+-      if (req)
+-              rx_submit (dev, req, GFP_ATOMIC);
+-}
+-
+-static int prealloc (struct list_head *list, struct usb_ep *ep,
+-                      unsigned n, gfp_t gfp_flags)
+-{
+-      unsigned                i;
+-      struct usb_request      *req;
+-
+-      if (!n)
+-              return -ENOMEM;
+-
+-      /* queue/recycle up to N requests */
+-      i = n;
+-      list_for_each_entry (req, list, list) {
+-              if (i-- == 0)
+-                      goto extra;
+-      }
+-      while (i--) {
+-              req = usb_ep_alloc_request (ep, gfp_flags);
+-              if (!req)
+-                      return list_empty (list) ? -ENOMEM : 0;
+-              list_add (&req->list, list);
+-      }
+-      return 0;
+-
+-extra:
+-      /* free extras */
+-      for (;;) {
+-              struct list_head        *next;
+-
+-              next = req->list.next;
+-              list_del (&req->list);
+-              usb_ep_free_request (ep, req);
+-
+-              if (next == list)
+-                      break;
+-
+-              req = container_of (next, struct usb_request, list);
+-      }
+-      return 0;
+-}
+-
+-static int alloc_requests (struct eth_dev *dev, unsigned n, gfp_t gfp_flags)
+-{
+-      int status;
+-
+-      spin_lock(&dev->req_lock);
+-      status = prealloc (&dev->tx_reqs, dev->in_ep, n, gfp_flags);
+-      if (status < 0)
+-              goto fail;
+-      status = prealloc (&dev->rx_reqs, dev->out_ep, n, gfp_flags);
+-      if (status < 0)
+-              goto fail;
+-      goto done;
+-fail:
+-      DEBUG (dev, "can't alloc requests\n");
+-done:
+-      spin_unlock(&dev->req_lock);
+-      return status;
+-}
+-
+-static void rx_fill (struct eth_dev *dev, gfp_t gfp_flags)
+-{
+-      struct usb_request      *req;
+-      unsigned long           flags;
+-
+-      /* fill unused rxq slots with some skb */
+-      spin_lock_irqsave(&dev->req_lock, flags);
+-      while (!list_empty (&dev->rx_reqs)) {
+-              req = container_of (dev->rx_reqs.next,
+-                              struct usb_request, list);
+-              list_del_init (&req->list);
+-              spin_unlock_irqrestore(&dev->req_lock, flags);
+-
+-              if (rx_submit (dev, req, gfp_flags) < 0) {
+-                      defer_kevent (dev, WORK_RX_MEMORY);
+-                      return;
+-              }
+-
+-              spin_lock_irqsave(&dev->req_lock, flags);
+-      }
+-      spin_unlock_irqrestore(&dev->req_lock, flags);
+-}
+-
+-static void eth_work (struct work_struct *work)
+-{
+-      struct eth_dev  *dev = container_of(work, struct eth_dev, work);
+-
+-      if (test_and_clear_bit (WORK_RX_MEMORY, &dev->todo)) {
+-              if (netif_running (dev->net))
+-                      rx_fill (dev, GFP_KERNEL);
+-      }
+-
+-      if (dev->todo)
+-              DEBUG (dev, "work done, flags = 0x%lx\n", dev->todo);
+-}
+-
+-static void tx_complete (struct usb_ep *ep, struct usb_request *req)
+-{
+-      struct sk_buff  *skb = req->context;
+-      struct eth_dev  *dev = ep->driver_data;
+-
+-      switch (req->status) {
+-      default:
+-              dev->stats.tx_errors++;
+-              VDEBUG (dev, "tx err %d\n", req->status);
+-              /* FALLTHROUGH */
+-      case -ECONNRESET:               // unlink
+-      case -ESHUTDOWN:                // disconnect etc
+-              break;
+-      case 0:
+-              dev->stats.tx_bytes += skb->len;
+-      }
+-      dev->stats.tx_packets++;
+-
+-      spin_lock(&dev->req_lock);
+-      list_add (&req->list, &dev->tx_reqs);
+-      spin_unlock(&dev->req_lock);
+-      dev_kfree_skb_any (skb);
+-
+-      atomic_dec (&dev->tx_qlen);
+-      if (netif_carrier_ok (dev->net))
+-              netif_wake_queue (dev->net);
+-}
+-
+-static inline int eth_is_promisc (struct eth_dev *dev)
+-{
+-      /* no filters for the CDC subset; always promisc */
+-      if (subset_active (dev))
+-              return 1;
+-      return dev->cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
+-}
+-
+-static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
+-{
+-      struct eth_dev          *dev = netdev_priv(net);
+-      int                     length = skb->len;
+-      int                     retval;
+-      struct usb_request      *req = NULL;
+-      unsigned long           flags;
+-
+-      /* apply outgoing CDC or RNDIS filters */
+-      if (!eth_is_promisc (dev)) {
+-              u8              *dest = skb->data;
+-
+-              if (is_multicast_ether_addr(dest)) {
+-                      u16     type;
+-
+-                      /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host
+-                       * SET_ETHERNET_MULTICAST_FILTERS requests
+-                       */
+-                      if (is_broadcast_ether_addr(dest))
+-                              type = USB_CDC_PACKET_TYPE_BROADCAST;
+-                      else
+-                              type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
+-                      if (!(dev->cdc_filter & type)) {
+-                              dev_kfree_skb_any (skb);
+-                              return 0;
+-                      }
+-              }
+-              /* ignores USB_CDC_PACKET_TYPE_DIRECTED */
+-      }
+-
+-      spin_lock_irqsave(&dev->req_lock, flags);
+-      /*
+-       * this freelist can be empty if an interrupt triggered disconnect()
+-       * and reconfigured the gadget (shutting down this queue) after the
+-       * network stack decided to xmit but before we got the spinlock.
+-       */
+-      if (list_empty(&dev->tx_reqs)) {
+-              spin_unlock_irqrestore(&dev->req_lock, flags);
+-              return 1;
+-      }
+-
+-      req = container_of (dev->tx_reqs.next, struct usb_request, list);
+-      list_del (&req->list);
+-
+-      /* temporarily stop TX queue when the freelist empties */
+-      if (list_empty (&dev->tx_reqs))
+-              netif_stop_queue (net);
+-      spin_unlock_irqrestore(&dev->req_lock, flags);
+-
+-      /* no buffer copies needed, unless the network stack did it
+-       * or the hardware can't use skb buffers.
+-       * or there's not enough space for any RNDIS headers we need
+-       */
+-      if (rndis_active(dev)) {
+-              struct sk_buff  *skb_rndis;
+-
+-              skb_rndis = skb_realloc_headroom (skb,
+-                              sizeof (struct rndis_packet_msg_type));
+-              if (!skb_rndis)
+-                      goto drop;
+-
+-              dev_kfree_skb_any (skb);
+-              skb = skb_rndis;
+-              rndis_add_hdr (skb);
+-              length = skb->len;
+-      }
+-      req->buf = skb->data;
+-      req->context = skb;
+-      req->complete = tx_complete;
+-
+-      /* use zlp framing on tx for strict CDC-Ether conformance,
+-       * though any robust network rx path ignores extra padding.
+-       * and some hardware doesn't like to write zlps.
+-       */
+-      req->zero = 1;
+-      if (!dev->zlp && (length % dev->in_ep->maxpacket) == 0)
+-              length++;
+-
+-      req->length = length;
+-
+-      /* throttle highspeed IRQ rate back slightly */
+-      if (gadget_is_dualspeed(dev->gadget))
+-              req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+-                      ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+-                      : 0;
+-
+-      retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
+-      switch (retval) {
+-      default:
+-              DEBUG (dev, "tx queue err %d\n", retval);
+-              break;
+-      case 0:
+-              net->trans_start = jiffies;
+-              atomic_inc (&dev->tx_qlen);
+-      }
+-
+-      if (retval) {
+-drop:
+-              dev->stats.tx_dropped++;
+-              dev_kfree_skb_any (skb);
+-              spin_lock_irqsave(&dev->req_lock, flags);
+-              if (list_empty (&dev->tx_reqs))
+-                      netif_start_queue (net);
+-              list_add (&req->list, &dev->tx_reqs);
+-              spin_unlock_irqrestore(&dev->req_lock, flags);
+-      }
+-      return 0;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-#ifdef CONFIG_USB_ETH_RNDIS
+-
+-/* The interrupt endpoint is used in RNDIS to notify the host when messages
+- * other than data packets are available ... notably the REMOTE_NDIS_*_CMPLT
+- * messages, but also REMOTE_NDIS_INDICATE_STATUS_MSG and potentially even
+- * REMOTE_NDIS_KEEPALIVE_MSG.
+- *
+- * The RNDIS control queue is processed by GET_ENCAPSULATED_RESPONSE, and
+- * normally just one notification will be queued.
+- */
+-
+-static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, gfp_t);
+-static void eth_req_free (struct usb_ep *ep, struct usb_request *req);
+-
+-static void
+-rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
+-{
+-      struct eth_dev          *dev = ep->driver_data;
+-
+-      if (req->status || req->actual != req->length)
+-              DEBUG (dev,
+-                      "rndis control ack complete --> %d, %d/%d\n",
+-                      req->status, req->actual, req->length);
+-      req->context = NULL;
+-
+-      if (req != dev->stat_req)
+-              eth_req_free(ep, req);
+-}
+-
+-static int rndis_control_ack (struct net_device *net)
+-{
+-      struct eth_dev          *dev = netdev_priv(net);
+-      int                     length;
+-      struct usb_request      *resp = dev->stat_req;
+-
+-      /* in case RNDIS calls this after disconnect */
+-      if (!dev->status) {
+-              DEBUG (dev, "status ENODEV\n");
+-              return -ENODEV;
+-      }
+-
+-      /* in case queue length > 1 */
+-      if (resp->context) {
+-              resp = eth_req_alloc (dev->status_ep, 8, GFP_ATOMIC);
+-              if (!resp)
+-                      return -ENOMEM;
+-      }
+-
+-      /* Send RNDIS RESPONSE_AVAILABLE notification;
+-       * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too
+-       */
+-      resp->length = 8;
+-      resp->complete = rndis_control_ack_complete;
+-      resp->context = dev;
+-
+-      *((__le32 *) resp->buf) = __constant_cpu_to_le32 (1);
+-      *((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0);
+-
+-      length = usb_ep_queue (dev->status_ep, resp, GFP_ATOMIC);
+-      if (length < 0) {
+-              resp->status = 0;
+-              rndis_control_ack_complete (dev->status_ep, resp);
+-      }
+-
+-      return 0;
+-}
+-
+-#else
+-
+-#define       rndis_control_ack       NULL
+-
+-#endif        /* RNDIS */
+-
+-static void eth_start (struct eth_dev *dev, gfp_t gfp_flags)
+-{
+-      DEBUG (dev, "%s\n", __func__);
+-
+-      /* fill the rx queue */
+-      rx_fill (dev, gfp_flags);
+-
+-      /* and open the tx floodgates */
+-      atomic_set (&dev->tx_qlen, 0);
+-      netif_wake_queue (dev->net);
+-      if (rndis_active(dev)) {
+-              rndis_set_param_medium (dev->rndis_config,
+-                                      NDIS_MEDIUM_802_3,
+-                                      BITRATE(dev->gadget)/100);
+-              (void) rndis_signal_connect (dev->rndis_config);
+-      }
+-}
+-
+-static int eth_open (struct net_device *net)
+-{
+-      struct eth_dev          *dev = netdev_priv(net);
+-
+-      DEBUG (dev, "%s\n", __func__);
+-      if (netif_carrier_ok (dev->net))
+-              eth_start (dev, GFP_KERNEL);
+-      return 0;
++              return geth_bind_config(c, hostaddr);
+ }
+-static int eth_stop (struct net_device *net)
+-{
+-      struct eth_dev          *dev = netdev_priv(net);
+-
+-      VDEBUG (dev, "%s\n", __func__);
+-      netif_stop_queue (net);
+-
+-      DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
+-              dev->stats.rx_packets, dev->stats.tx_packets,
+-              dev->stats.rx_errors, dev->stats.tx_errors
+-              );
+-
+-      /* ensure there are no more active requests */
+-      if (dev->config) {
+-              usb_ep_disable (dev->in_ep);
+-              usb_ep_disable (dev->out_ep);
+-              if (netif_carrier_ok (dev->net)) {
+-                      DEBUG (dev, "host still using in/out endpoints\n");
+-                      // FIXME idiom may leave toggle wrong here
+-                      usb_ep_enable (dev->in_ep, dev->in);
+-                      usb_ep_enable (dev->out_ep, dev->out);
+-              }
+-              if (dev->status_ep) {
+-                      usb_ep_disable (dev->status_ep);
+-                      usb_ep_enable (dev->status_ep, dev->status);
+-              }
+-      }
+-
+-      if (rndis_active(dev)) {
+-              rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
+-              (void) rndis_signal_disconnect (dev->rndis_config);
+-      }
+-
+-      return 0;
+-}
++static struct usb_configuration eth_config_driver = {
++      /* .label = f(hardware) */
++      .bind                   = eth_do_config,
++      .bConfigurationValue    = 1,
++      /* .iConfiguration = DYNAMIC */
++      .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
++      .bMaxPower              = 1,    /* 2 mA, minimal */
++};
+ /*-------------------------------------------------------------------------*/
+-static struct usb_request *
+-eth_req_alloc (struct usb_ep *ep, unsigned size, gfp_t gfp_flags)
++static int __init eth_bind(struct usb_composite_dev *cdev)
+ {
+-      struct usb_request      *req;
+-
+-      req = usb_ep_alloc_request (ep, gfp_flags);
+-      if (!req)
+-              return NULL;
+-
+-      req->buf = kmalloc (size, gfp_flags);
+-      if (!req->buf) {
+-              usb_ep_free_request (ep, req);
+-              req = NULL;
+-      }
+-      return req;
+-}
+-
+-static void
+-eth_req_free (struct usb_ep *ep, struct usb_request *req)
+-{
+-      kfree (req->buf);
+-      usb_ep_free_request (ep, req);
+-}
+-
+-
+-static void /* __init_or_exit */
+-eth_unbind (struct usb_gadget *gadget)
+-{
+-      struct eth_dev          *dev = get_gadget_data (gadget);
+-
+-      DEBUG (dev, "unbind\n");
+-      rndis_deregister (dev->rndis_config);
+-      rndis_exit ();
+-
+-      /* we've already been disconnected ... no i/o is active */
+-      if (dev->req) {
+-              eth_req_free (gadget->ep0, dev->req);
+-              dev->req = NULL;
+-      }
+-      if (dev->stat_req) {
+-              eth_req_free (dev->status_ep, dev->stat_req);
+-              dev->stat_req = NULL;
+-      }
+-
+-      unregister_netdev (dev->net);
+-      free_netdev(dev->net);
+-
+-      /* assuming we used keventd, it must quiesce too */
+-      flush_scheduled_work ();
+-      set_gadget_data (gadget, NULL);
+-}
+-
+-static u8 __init nibble (unsigned char c)
+-{
+-      if (likely (isdigit (c)))
+-              return c - '0';
+-      c = toupper (c);
+-      if (likely (isxdigit (c)))
+-              return 10 + c - 'A';
+-      return 0;
+-}
++      int                     gcnum;
++      struct usb_gadget       *gadget = cdev->gadget;
++      int                     status;
+-static int __init get_ether_addr(const char *str, u8 *dev_addr)
+-{
+-      if (str) {
+-              unsigned        i;
++      /* set up network link layer */
++      status = gether_setup(cdev->gadget, hostaddr);
++      if (status < 0)
++              return status;
+-              for (i = 0; i < 6; i++) {
+-                      unsigned char num;
++      /* set up main config label and device descriptor */
++      if (can_support_ecm(cdev->gadget)) {
++              /* ECM */
++              eth_config_driver.label = "CDC Ethernet (ECM)";
++      } else {
++              /* CDC Subset */
++              eth_config_driver.label = "CDC Subset/SAFE";
+-                      if((*str == '.') || (*str == ':'))
+-                              str++;
+-                      num = nibble(*str++) << 4;
+-                      num |= (nibble(*str++));
+-                      dev_addr [i] = num;
+-              }
+-              if (is_valid_ether_addr (dev_addr))
+-                      return 0;
++              device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM),
++              device_desc.idProduct = cpu_to_le16(SIMPLE_PRODUCT_NUM),
++              device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+       }
+-      random_ether_addr(dev_addr);
+-      return 1;
+-}
+-
+-static int __init
+-eth_bind (struct usb_gadget *gadget)
+-{
+-      struct eth_dev          *dev;
+-      struct net_device       *net;
+-      u8                      cdc = 1, zlp = 1, rndis = 1;
+-      struct usb_ep           *in_ep, *out_ep, *status_ep = NULL;
+-      int                     status = -ENOMEM;
+-      int                     gcnum;
+-
+-      /* these flags are only ever cleared; compiler take note */
+-#ifndef       DEV_CONFIG_CDC
+-      cdc = 0;
+-#endif
+-#ifndef       CONFIG_USB_ETH_RNDIS
+-      rndis = 0;
+-#endif
+-      /* Because most host side USB stacks handle CDC Ethernet, that
+-       * standard protocol is _strongly_ preferred for interop purposes.
+-       * (By everyone except Microsoft.)
+-       */
+-      if (gadget_is_pxa (gadget)) {
+-              /* pxa doesn't support altsettings */
+-              cdc = 0;
+-      } else if (gadget_is_musbhdrc(gadget)) {
+-              /* reduce tx dma overhead by avoiding special cases */
+-              zlp = 0;
+-      } else if (gadget_is_sh(gadget)) {
+-              /* sh doesn't support multiple interfaces or configs */
+-              cdc = 0;
+-              rndis = 0;
+-      } else if (gadget_is_sa1100 (gadget)) {
+-              /* hardware can't write zlps */
+-              zlp = 0;
+-              /* sa1100 CAN do CDC, without status endpoint ... we use
+-               * non-CDC to be compatible with ARM Linux-2.4 "usb-eth".
+-               */
+-              cdc = 0;
++      if (has_rndis()) {
++              /* RNDIS plus ECM-or-Subset */
++              device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM),
++              device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM),
++              device_desc.bNumConfigurations = 2;
+       }
+-      gcnum = usb_gadget_controller_number (gadget);
++      gcnum = usb_gadget_controller_number(gadget);
+       if (gcnum >= 0)
+-              device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
++              device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
+       else {
+-              /* can't assume CDC works.  don't want to default to
+-               * anything less functional on CDC-capable hardware,
+-               * so we fail in this case.
++              /* We assume that can_support_ecm() tells the truth;
++               * but if the controller isn't recognized at all then
++               * that assumption is a bit more likely to be wrong.
+                */
+-              dev_err (&gadget->dev,
+-                      "controller '%s' not recognized\n",
+-                      gadget->name);
+-              return -ENODEV;
+-      }
+-      snprintf (manufacturer, sizeof manufacturer, "%s %s/%s",
+-              init_utsname()->sysname, init_utsname()->release,
+-              gadget->name);
+-
+-      /* If there's an RNDIS configuration, that's what Windows wants to
+-       * be using ... so use these product IDs here and in the "linux.inf"
+-       * needed to install MSFT drivers.  Current Linux kernels will use
+-       * the second configuration if it's CDC Ethernet, and need some help
+-       * to choose the right configuration otherwise.
+-       */
+-      if (rndis) {
+-              device_desc.idVendor =
+-                      __constant_cpu_to_le16(RNDIS_VENDOR_NUM);
+-              device_desc.idProduct =
+-                      __constant_cpu_to_le16(RNDIS_PRODUCT_NUM);
+-              snprintf (product_desc, sizeof product_desc,
+-                      "RNDIS/%s", driver_desc);
+-
+-      /* CDC subset ... recognized by Linux since 2.4.10, but Windows
+-       * drivers aren't widely available.  (That may be improved by
+-       * supporting one submode of the "SAFE" variant of MDLM.)
+-       */
+-      } else if (!cdc) {
+-              device_desc.idVendor =
+-                      __constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
+-              device_desc.idProduct =
+-                      __constant_cpu_to_le16(SIMPLE_PRODUCT_NUM);
+-      }
+-
+-      /* support optional vendor/distro customization */
+-      if (idVendor) {
+-              if (!idProduct) {
+-                      dev_err (&gadget->dev, "idVendor needs idProduct!\n");
+-                      return -ENODEV;
+-              }
+-              device_desc.idVendor = cpu_to_le16(idVendor);
+-              device_desc.idProduct = cpu_to_le16(idProduct);
+-              if (bcdDevice)
+-                      device_desc.bcdDevice = cpu_to_le16(bcdDevice);
+-      }
+-      if (iManufacturer)
+-              strlcpy (manufacturer, iManufacturer, sizeof manufacturer);
+-      if (iProduct)
+-              strlcpy (product_desc, iProduct, sizeof product_desc);
+-      if (iSerialNumber) {
+-              device_desc.iSerialNumber = STRING_SERIALNUMBER,
+-              strlcpy(serial_number, iSerialNumber, sizeof serial_number);
+-      }
+-
+-      /* all we really need is bulk IN/OUT */
+-      usb_ep_autoconfig_reset (gadget);
+-      in_ep = usb_ep_autoconfig (gadget, &fs_source_desc);
+-      if (!in_ep) {
+-autoconf_fail:
+-              dev_err (&gadget->dev,
+-                      "can't autoconfigure on %s\n",
+-                      gadget->name);
+-              return -ENODEV;
+-      }
+-      in_ep->driver_data = in_ep;     /* claim */
+-
+-      out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
+-      if (!out_ep)
+-              goto autoconf_fail;
+-      out_ep->driver_data = out_ep;   /* claim */
+-
+-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+-      /* CDC Ethernet control interface doesn't require a status endpoint.
+-       * Since some hosts expect one, try to allocate one anyway.
+-       */
+-      if (cdc || rndis) {
+-              status_ep = usb_ep_autoconfig (gadget, &fs_status_desc);
+-              if (status_ep) {
+-                      status_ep->driver_data = status_ep;     /* claim */
+-              } else if (rndis) {
+-                      dev_err (&gadget->dev,
+-                              "can't run RNDIS on %s\n",
+-                              gadget->name);
+-                      return -ENODEV;
+-#ifdef DEV_CONFIG_CDC
+-              /* pxa25x only does CDC subset; often used with RNDIS */
+-              } else if (cdc) {
+-                      control_intf.bNumEndpoints = 0;
+-                      /* FIXME remove endpoint from descriptor list */
+-#endif
+-              }
+-      }
+-#endif
+-
+-      /* one config:  cdc, else minimal subset */
+-      if (!cdc) {
+-              eth_config.bNumInterfaces = 1;
+-              eth_config.iConfiguration = STRING_SUBSET;
+-
+-              /* use functions to set these up, in case we're built to work
+-               * with multiple controllers and must override CDC Ethernet.
+-               */
+-              fs_subset_descriptors();
+-              hs_subset_descriptors();
+-      }
+-
+-      device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+-      usb_gadget_set_selfpowered (gadget);
+-
+-      /* For now RNDIS is always a second config */
+-      if (rndis)
+-              device_desc.bNumConfigurations = 2;
+-
+-      if (gadget_is_dualspeed(gadget)) {
+-              if (rndis)
+-                      dev_qualifier.bNumConfigurations = 2;
+-              else if (!cdc)
+-                      dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+-
+-              /* assumes ep0 uses the same value for both speeds ... */
+-              dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+-
+-              /* and that all endpoints are dual-speed */
+-              hs_source_desc.bEndpointAddress =
+-                              fs_source_desc.bEndpointAddress;
+-              hs_sink_desc.bEndpointAddress =
+-                              fs_sink_desc.bEndpointAddress;
+-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+-              if (status_ep)
+-                      hs_status_desc.bEndpointAddress =
+-                                      fs_status_desc.bEndpointAddress;
+-#endif
++              WARNING(cdev, "controller '%s' not recognized; trying %s\n",
++                              gadget->name,
++                              eth_config_driver.label);
++              device_desc.bcdDevice =
++                      __constant_cpu_to_le16(0x0300 | 0x0099);
+       }
+-      if (gadget_is_otg(gadget)) {
+-              otg_descriptor.bmAttributes |= USB_OTG_HNP,
+-              eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+-              eth_config.bMaxPower = 4;
+-#ifdef        CONFIG_USB_ETH_RNDIS
+-              rndis_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+-              rndis_config.bMaxPower = 4;
+-#endif
+-      }
+-
+-      net = alloc_etherdev (sizeof *dev);
+-      if (!net)
+-              return status;
+-      dev = netdev_priv(net);
+-      spin_lock_init (&dev->lock);
+-      spin_lock_init (&dev->req_lock);
+-      INIT_WORK (&dev->work, eth_work);
+-      INIT_LIST_HEAD (&dev->tx_reqs);
+-      INIT_LIST_HEAD (&dev->rx_reqs);
+-
+-      /* network device setup */
+-      dev->net = net;
+-      strcpy (net->name, "usb%d");
+-      dev->cdc = cdc;
+-      dev->zlp = zlp;
+-      dev->in_ep = in_ep;
+-      dev->out_ep = out_ep;
+-      dev->status_ep = status_ep;
+-
+-      /* Module params for these addresses should come from ID proms.
+-       * The host side address is used with CDC and RNDIS, and commonly
+-       * ends up in a persistent config database.  It's not clear if
+-       * host side code for the SAFE thing cares -- its original BLAN
+-       * thing didn't, Sharp never assigned those addresses on Zaurii.
++      /* Allocate string descriptor numbers ... note that string
++       * contents can be overridden by the composite_dev glue.
+        */
+-      if (get_ether_addr(dev_addr, net->dev_addr))
+-              dev_warn(&gadget->dev,
+-                      "using random %s ethernet address\n", "self");
+-      if (get_ether_addr(host_addr, dev->host_mac))
+-              dev_warn(&gadget->dev,
+-                      "using random %s ethernet address\n", "host");
+-      snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
+-              dev->host_mac [0], dev->host_mac [1],
+-              dev->host_mac [2], dev->host_mac [3],
+-              dev->host_mac [4], dev->host_mac [5]);
+-
+-      if (rndis) {
+-              status = rndis_init();
+-              if (status < 0) {
+-                      dev_err (&gadget->dev, "can't init RNDIS, %d\n",
+-                              status);
+-                      goto fail;
+-              }
+-      }
+-      net->change_mtu = eth_change_mtu;
+-      net->get_stats = eth_get_stats;
+-      net->hard_start_xmit = eth_start_xmit;
+-      net->open = eth_open;
+-      net->stop = eth_stop;
+-      // watchdog_timeo, tx_timeout ...
+-      // set_multicast_list
+-      SET_ETHTOOL_OPS(net, &ops);
++      /* device descriptor strings: manufacturer, product */
++      snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
++              init_utsname()->sysname, init_utsname()->release,
++              gadget->name);
++      status = usb_string_id(cdev);
++      if (status < 0)
++              goto fail;
++      strings_dev[STRING_MANUFACTURER_IDX].id = status;
++      device_desc.iManufacturer = status;
+-      /* preallocate control message data and buffer */
+-      dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ, GFP_KERNEL);
+-      if (!dev->req)
++      status = usb_string_id(cdev);
++      if (status < 0)
+               goto fail;
+-      dev->req->complete = eth_setup_complete;
++      strings_dev[STRING_PRODUCT_IDX].id = status;
++      device_desc.iProduct = status;
+-      /* ... and maybe likewise for status transfer */
+-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+-      if (dev->status_ep) {
+-              dev->stat_req = eth_req_alloc (dev->status_ep,
+-                                      STATUS_BYTECOUNT, GFP_KERNEL);
+-              if (!dev->stat_req) {
+-                      eth_req_free (gadget->ep0, dev->req);
++      /* register our configuration(s); RNDIS first, if it's used */
++      if (has_rndis()) {
++              status = usb_add_config(cdev, &rndis_config_driver);
++              if (status < 0)
+                       goto fail;
+-              }
+-              dev->stat_req->context = NULL;
+       }
+-#endif
+-
+-      /* finish hookup to lower layer ... */
+-      dev->gadget = gadget;
+-      set_gadget_data (gadget, dev);
+-      gadget->ep0->driver_data = dev;
+-      /* two kinds of host-initiated state changes:
+-       *  - iff DATA transfer is active, carrier is "on"
+-       *  - tx queueing enabled if open *and* carrier is "on"
+-       */
+-      netif_stop_queue (dev->net);
+-      netif_carrier_off (dev->net);
+-
+-      SET_NETDEV_DEV (dev->net, &gadget->dev);
+-      status = register_netdev (dev->net);
++      status = usb_add_config(cdev, &eth_config_driver);
+       if (status < 0)
+-              goto fail1;
+-
+-      INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
+-      INFO (dev, "using %s, OUT %s IN %s%s%s\n", gadget->name,
+-              out_ep->name, in_ep->name,
+-              status_ep ? " STATUS " : "",
+-              status_ep ? status_ep->name : ""
+-              );
+-      INFO (dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+-              net->dev_addr [0], net->dev_addr [1],
+-              net->dev_addr [2], net->dev_addr [3],
+-              net->dev_addr [4], net->dev_addr [5]);
+-
+-      if (cdc || rndis)
+-              INFO (dev, "HOST MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+-                      dev->host_mac [0], dev->host_mac [1],
+-                      dev->host_mac [2], dev->host_mac [3],
+-                      dev->host_mac [4], dev->host_mac [5]);
+-
+-      if (rndis) {
+-              u32     vendorID = 0;
+-
+-              /* FIXME RNDIS vendor id == "vendor NIC code" == ? */
+-
+-              dev->rndis_config = rndis_register (rndis_control_ack);
+-              if (dev->rndis_config < 0) {
+-fail0:
+-                      unregister_netdev (dev->net);
+-                      status = -ENODEV;
+-                      goto fail;
+-              }
++              goto fail;
+-              /* these set up a lot of the OIDs that RNDIS needs */
+-              rndis_set_host_mac (dev->rndis_config, dev->host_mac);
+-              if (rndis_set_param_dev (dev->rndis_config, dev->net,
+-                                       &dev->stats, &dev->cdc_filter))
+-                      goto fail0;
+-              if (rndis_set_param_vendor(dev->rndis_config, vendorID,
+-                                      manufacturer))
+-                      goto fail0;
+-              if (rndis_set_param_medium(dev->rndis_config,
+-                                      NDIS_MEDIUM_802_3, 0))
+-                      goto fail0;
+-              INFO (dev, "RNDIS ready\n");
+-      }
++      INFO(cdev, "%s, version: " DRIVER_VERSION "\n", DRIVER_DESC);
+-      return status;
++      return 0;
+-fail1:
+-      dev_dbg(&gadget->dev, "register_netdev failed, %d\n", status);
+ fail:
+-      eth_unbind (gadget);
++      gether_cleanup();
+       return status;
+ }
+-/*-------------------------------------------------------------------------*/
+-
+-static void
+-eth_suspend (struct usb_gadget *gadget)
+-{
+-      struct eth_dev          *dev = get_gadget_data (gadget);
+-
+-      DEBUG (dev, "suspend\n");
+-      dev->suspended = 1;
+-}
+-
+-static void
+-eth_resume (struct usb_gadget *gadget)
++static int __exit eth_unbind(struct usb_composite_dev *cdev)
+ {
+-      struct eth_dev          *dev = get_gadget_data (gadget);
+-
+-      DEBUG (dev, "resume\n");
+-      dev->suspended = 0;
++      gether_cleanup();
++      return 0;
+ }
+-/*-------------------------------------------------------------------------*/
+-
+-static struct usb_gadget_driver eth_driver = {
+-      .speed          = DEVSPEED,
+-
+-      .function       = (char *) driver_desc,
++static struct usb_composite_driver eth_driver = {
++      .name           = "g_ether",
++      .dev            = &device_desc,
++      .strings        = dev_strings,
+       .bind           = eth_bind,
+-      .unbind         = eth_unbind,
+-
+-      .setup          = eth_setup,
+-      .disconnect     = eth_disconnect,
+-
+-      .suspend        = eth_suspend,
+-      .resume         = eth_resume,
+-
+-      .driver = {
+-              .name           = (char *) shortname,
+-              .owner          = THIS_MODULE,
+-      },
++      .unbind         = __exit_p(eth_unbind),
+ };
+-MODULE_DESCRIPTION (DRIVER_DESC);
+-MODULE_AUTHOR ("David Brownell, Benedikt Spanger");
+-MODULE_LICENSE ("GPL");
++MODULE_DESCRIPTION(PREFIX DRIVER_DESC);
++MODULE_AUTHOR("David Brownell, Benedikt Spanger");
++MODULE_LICENSE("GPL");
+-
+-static int __init init (void)
++static int __init init(void)
+ {
+-      return usb_gadget_register_driver (&eth_driver);
++      return usb_composite_register(&eth_driver);
+ }
+-module_init (init);
++module_init(init);
+-static void __exit cleanup (void)
++static void __exit cleanup(void)
+ {
+-      usb_gadget_unregister_driver (&eth_driver);
++      usb_composite_unregister(&eth_driver);
+ }
+-module_exit (cleanup);
+-
++module_exit(cleanup);
+diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
+new file mode 100644
+index 0000000..5ee1590
+--- /dev/null
++++ b/drivers/usb/gadget/f_acm.c
+@@ -0,0 +1,759 @@
++/*
++ * f_acm.c -- USB CDC serial (ACM) function driver
++ *
++ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
++ * Copyright (C) 2008 by David Brownell
++ * Copyright (C) 2008 by Nokia Corporation
++ *
++ * This software is distributed under the terms of the GNU General
++ * Public License ("GPL") as published by the Free Software Foundation,
++ * either version 2 of that License or (at your option) any later version.
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kernel.h>
++#include <linux/device.h>
++
++#include "u_serial.h"
++#include "gadget_chips.h"
++
++
++/*
++ * This CDC ACM function support just wraps control functions and
++ * notifications around the generic serial-over-usb code.
++ *
++ * Because CDC ACM is standardized by the USB-IF, many host operating
++ * systems have drivers for it.  Accordingly, ACM is the preferred
++ * interop solution for serial-port type connections.  The control
++ * models are often not necessary, and in any case don't do much in
++ * this bare-bones implementation.
++ *
++ * Note that even MS-Windows has some support for ACM.  However, that
++ * support is somewhat broken because when you use ACM in a composite
++ * device, having multiple interfaces confuses the poor OS.  It doesn't
++ * seem to understand CDC Union descriptors.  The new "association"
++ * descriptors (roughly equivalent to CDC Unions) may sometimes help.
++ */
++
++struct acm_ep_descs {
++      struct usb_endpoint_descriptor  *in;
++      struct usb_endpoint_descriptor  *out;
++      struct usb_endpoint_descriptor  *notify;
++};
++
++struct f_acm {
++      struct gserial                  port;
++      u8                              ctrl_id, data_id;
++      u8                              port_num;
++
++      u8                              pending;
++
++      /* lock is mostly for pending and notify_req ... they get accessed
++       * by callbacks both from tty (open/close/break) under its spinlock,
++       * and notify_req.complete() which can't use that lock.
++       */
++      spinlock_t                      lock;
++
++      struct acm_ep_descs             fs;
++      struct acm_ep_descs             hs;
++
++      struct usb_ep                   *notify;
++      struct usb_endpoint_descriptor  *notify_desc;
++      struct usb_request              *notify_req;
++
++      struct usb_cdc_line_coding      port_line_coding;       /* 8-N-1 etc */
++
++      /* SetControlLineState request -- CDC 1.1 section 6.2.14 (INPUT) */
++      u16                             port_handshake_bits;
++#define ACM_CTRL_RTS  (1 << 1)        /* unused with full duplex */
++#define ACM_CTRL_DTR  (1 << 0)        /* host is ready for data r/w */
++
++      /* SerialState notification -- CDC 1.1 section 6.3.5 (OUTPUT) */
++      u16                             serial_state;
++#define ACM_CTRL_OVERRUN      (1 << 6)
++#define ACM_CTRL_PARITY               (1 << 5)
++#define ACM_CTRL_FRAMING      (1 << 4)
++#define ACM_CTRL_RI           (1 << 3)
++#define ACM_CTRL_BRK          (1 << 2)
++#define ACM_CTRL_DSR          (1 << 1)
++#define ACM_CTRL_DCD          (1 << 0)
++};
++
++static inline struct f_acm *func_to_acm(struct usb_function *f)
++{
++      return container_of(f, struct f_acm, port.func);
++}
++
++static inline struct f_acm *port_to_acm(struct gserial *p)
++{
++      return container_of(p, struct f_acm, port);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* notification endpoint uses smallish and infrequent fixed-size messages */
++
++#define GS_LOG2_NOTIFY_INTERVAL               5       /* 1 << 5 == 32 msec */
++#define GS_NOTIFY_MAXPACKET           10      /* notification + 2 bytes */
++
++/* interface and class descriptors: */
++
++static struct usb_interface_descriptor acm_control_interface_desc __initdata = {
++      .bLength =              USB_DT_INTERFACE_SIZE,
++      .bDescriptorType =      USB_DT_INTERFACE,
++      /* .bInterfaceNumber = DYNAMIC */
++      .bNumEndpoints =        1,
++      .bInterfaceClass =      USB_CLASS_COMM,
++      .bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
++      .bInterfaceProtocol =   USB_CDC_ACM_PROTO_AT_V25TER,
++      /* .iInterface = DYNAMIC */
++};
++
++static struct usb_interface_descriptor acm_data_interface_desc __initdata = {
++      .bLength =              USB_DT_INTERFACE_SIZE,
++      .bDescriptorType =      USB_DT_INTERFACE,
++      /* .bInterfaceNumber = DYNAMIC */
++      .bNumEndpoints =        2,
++      .bInterfaceClass =      USB_CLASS_CDC_DATA,
++      .bInterfaceSubClass =   0,
++      .bInterfaceProtocol =   0,
++      /* .iInterface = DYNAMIC */
++};
++
++static struct usb_cdc_header_desc acm_header_desc __initdata = {
++      .bLength =              sizeof(acm_header_desc),
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_HEADER_TYPE,
++      .bcdCDC =               __constant_cpu_to_le16(0x0110),
++};
++
++static struct usb_cdc_call_mgmt_descriptor
++acm_call_mgmt_descriptor __initdata = {
++      .bLength =              sizeof(acm_call_mgmt_descriptor),
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
++      .bmCapabilities =       0,
++      /* .bDataInterface = DYNAMIC */
++};
++
++static struct usb_cdc_acm_descriptor acm_descriptor __initdata = {
++      .bLength =              sizeof(acm_descriptor),
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_ACM_TYPE,
++      .bmCapabilities =       USB_CDC_CAP_LINE,
++};
++
++static struct usb_cdc_union_desc acm_union_desc __initdata = {
++      .bLength =              sizeof(acm_union_desc),
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_UNION_TYPE,
++      /* .bMasterInterface0 = DYNAMIC */
++      /* .bSlaveInterface0 =  DYNAMIC */
++};
++
++/* full speed support: */
++
++static struct usb_endpoint_descriptor acm_fs_notify_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_INT,
++      .wMaxPacketSize =       __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
++      .bInterval =            1 << GS_LOG2_NOTIFY_INTERVAL,
++};
++
++static struct usb_endpoint_descriptor acm_fs_in_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor acm_fs_out_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++      .bEndpointAddress =     USB_DIR_OUT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_descriptor_header *acm_fs_function[] __initdata = {
++      (struct usb_descriptor_header *) &acm_control_interface_desc,
++      (struct usb_descriptor_header *) &acm_header_desc,
++      (struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
++      (struct usb_descriptor_header *) &acm_descriptor,
++      (struct usb_descriptor_header *) &acm_union_desc,
++      (struct usb_descriptor_header *) &acm_fs_notify_desc,
++      (struct usb_descriptor_header *) &acm_data_interface_desc,
++      (struct usb_descriptor_header *) &acm_fs_in_desc,
++      (struct usb_descriptor_header *) &acm_fs_out_desc,
++      NULL,
++};
++
++/* high speed support: */
++
++static struct usb_endpoint_descriptor acm_hs_notify_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_INT,
++      .wMaxPacketSize =       __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
++      .bInterval =            GS_LOG2_NOTIFY_INTERVAL+4,
++};
++
++static struct usb_endpoint_descriptor acm_hs_in_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor acm_hs_out_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_descriptor_header *acm_hs_function[] __initdata = {
++      (struct usb_descriptor_header *) &acm_control_interface_desc,
++      (struct usb_descriptor_header *) &acm_header_desc,
++      (struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
++      (struct usb_descriptor_header *) &acm_descriptor,
++      (struct usb_descriptor_header *) &acm_union_desc,
++      (struct usb_descriptor_header *) &acm_hs_notify_desc,
++      (struct usb_descriptor_header *) &acm_data_interface_desc,
++      (struct usb_descriptor_header *) &acm_hs_in_desc,
++      (struct usb_descriptor_header *) &acm_hs_out_desc,
++      NULL,
++};
++
++/* string descriptors: */
++
++#define ACM_CTRL_IDX  0
++#define ACM_DATA_IDX  1
++
++/* static strings, in UTF-8 */
++static struct usb_string acm_string_defs[] = {
++      [ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
++      [ACM_DATA_IDX].s = "CDC ACM Data",
++      {  /* ZEROES END LIST */ },
++};
++
++static struct usb_gadget_strings acm_string_table = {
++      .language =             0x0409, /* en-us */
++      .strings =              acm_string_defs,
++};
++
++static struct usb_gadget_strings *acm_strings[] = {
++      &acm_string_table,
++      NULL,
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* ACM control ... data handling is delegated to tty library code.
++ * The main task of this function is to activate and deactivate
++ * that code based on device state; track parameters like line
++ * speed, handshake state, and so on; and issue notifications.
++ */
++
++static void acm_complete_set_line_coding(struct usb_ep *ep,
++              struct usb_request *req)
++{
++      struct f_acm    *acm = ep->driver_data;
++      struct usb_composite_dev *cdev = acm->port.func.config->cdev;
++
++      if (req->status != 0) {
++              DBG(cdev, "acm ttyGS%d completion, err %d\n",
++                              acm->port_num, req->status);
++              return;
++      }
++
++      /* normal completion */
++      if (req->actual != sizeof(acm->port_line_coding)) {
++              DBG(cdev, "acm ttyGS%d short resp, len %d\n",
++                              acm->port_num, req->actual);
++              usb_ep_set_halt(ep);
++      } else {
++              struct usb_cdc_line_coding      *value = req->buf;
++
++              /* REVISIT:  we currently just remember this data.
++               * If we change that, (a) validate it first, then
++               * (b) update whatever hardware needs updating,
++               * (c) worry about locking.  This is information on
++               * the order of 9600-8-N-1 ... most of which means
++               * nothing unless we control a real RS232 line.
++               */
++              acm->port_line_coding = *value;
++      }
++}
++
++static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
++{
++      struct f_acm            *acm = func_to_acm(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++      struct usb_request      *req = cdev->req;
++      int                     value = -EOPNOTSUPP;
++      u16                     w_index = le16_to_cpu(ctrl->wIndex);
++      u16                     w_value = le16_to_cpu(ctrl->wValue);
++      u16                     w_length = le16_to_cpu(ctrl->wLength);
++
++      /* composite driver infrastructure handles everything except
++       * CDC class messages; interface activation uses set_alt().
++       *
++       * Note CDC spec table 4 lists the ACM request profile.  It requires
++       * encapsulated command support ... we don't handle any, and respond
++       * to them by stalling.  Options include get/set/clear comm features
++       * (not that useful) and SEND_BREAK.
++       */
++      switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
++
++      /* SET_LINE_CODING ... just read and save what the host sends */
++      case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
++                      | USB_CDC_REQ_SET_LINE_CODING:
++              if (w_length != sizeof(struct usb_cdc_line_coding)
++                              || w_index != acm->ctrl_id)
++                      goto invalid;
++
++              value = w_length;
++              cdev->gadget->ep0->driver_data = acm;
++              req->complete = acm_complete_set_line_coding;
++              break;
++
++      /* GET_LINE_CODING ... return what host sent, or initial value */
++      case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
++                      | USB_CDC_REQ_GET_LINE_CODING:
++              if (w_index != acm->ctrl_id)
++                      goto invalid;
++
++              value = min_t(unsigned, w_length,
++                              sizeof(struct usb_cdc_line_coding));
++              memcpy(req->buf, &acm->port_line_coding, value);
++              break;
++
++      /* SET_CONTROL_LINE_STATE ... save what the host sent */
++      case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
++                      | USB_CDC_REQ_SET_CONTROL_LINE_STATE:
++              if (w_index != acm->ctrl_id)
++                      goto invalid;
++
++              value = 0;
++
++              /* FIXME we should not allow data to flow until the
++               * host sets the ACM_CTRL_DTR bit; and when it clears
++               * that bit, we should return to that no-flow state.
++               */
++              acm->port_handshake_bits = w_value;
++              break;
++
++      default:
++invalid:
++              VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
++                      ctrl->bRequestType, ctrl->bRequest,
++                      w_value, w_index, w_length);
++      }
++
++      /* respond with data transfer or status phase? */
++      if (value >= 0) {
++              DBG(cdev, "acm ttyGS%d req%02x.%02x v%04x i%04x l%d\n",
++                      acm->port_num, ctrl->bRequestType, ctrl->bRequest,
++                      w_value, w_index, w_length);
++              req->zero = 0;
++              req->length = value;
++              value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
++              if (value < 0)
++                      ERROR(cdev, "acm response on ttyGS%d, err %d\n",
++                                      acm->port_num, value);
++      }
++
++      /* device either stalls (value < 0) or reports success */
++      return value;
++}
++
++static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
++{
++      struct f_acm            *acm = func_to_acm(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      /* we know alt == 0, so this is an activation or a reset */
++
++      if (intf == acm->ctrl_id) {
++              if (acm->notify->driver_data) {
++                      VDBG(cdev, "reset acm control interface %d\n", intf);
++                      usb_ep_disable(acm->notify);
++              } else {
++                      VDBG(cdev, "init acm ctrl interface %d\n", intf);
++                      acm->notify_desc = ep_choose(cdev->gadget,
++                                      acm->hs.notify,
++                                      acm->fs.notify);
++              }
++              usb_ep_enable(acm->notify, acm->notify_desc);
++              acm->notify->driver_data = acm;
++
++      } else if (intf == acm->data_id) {
++              if (acm->port.in->driver_data) {
++                      DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
++                      gserial_disconnect(&acm->port);
++              } else {
++                      DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
++                      acm->port.in_desc = ep_choose(cdev->gadget,
++                                      acm->hs.in, acm->fs.in);
++                      acm->port.out_desc = ep_choose(cdev->gadget,
++                                      acm->hs.out, acm->fs.out);
++              }
++              gserial_connect(&acm->port, acm->port_num);
++
++      } else
++              return -EINVAL;
++
++      return 0;
++}
++
++static void acm_disable(struct usb_function *f)
++{
++      struct f_acm    *acm = func_to_acm(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      DBG(cdev, "acm ttyGS%d deactivated\n", acm->port_num);
++      gserial_disconnect(&acm->port);
++      usb_ep_disable(acm->notify);
++      acm->notify->driver_data = NULL;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/**
++ * acm_cdc_notify - issue CDC notification to host
++ * @acm: wraps host to be notified
++ * @type: notification type
++ * @value: Refer to cdc specs, wValue field.
++ * @data: data to be sent
++ * @length: size of data
++ * Context: irqs blocked, acm->lock held, acm_notify_req non-null
++ *
++ * Returns zero on sucess or a negative errno.
++ *
++ * See section 6.3.5 of the CDC 1.1 specification for information
++ * about the only notification we issue:  SerialState change.
++ */
++static int acm_cdc_notify(struct f_acm *acm, u8 type, u16 value,
++              void *data, unsigned length)
++{
++      struct usb_ep                   *ep = acm->notify;
++      struct usb_request              *req;
++      struct usb_cdc_notification     *notify;
++      const unsigned                  len = sizeof(*notify) + length;
++      void                            *buf;
++      int                             status;
++
++      req = acm->notify_req;
++      acm->notify_req = NULL;
++      acm->pending = false;
++
++      req->length = len;
++      notify = req->buf;
++      buf = notify + 1;
++
++      notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
++                      | USB_RECIP_INTERFACE;
++      notify->bNotificationType = type;
++      notify->wValue = cpu_to_le16(value);
++      notify->wIndex = cpu_to_le16(acm->ctrl_id);
++      notify->wLength = cpu_to_le16(length);
++      memcpy(buf, data, length);
++
++      status = usb_ep_queue(ep, req, GFP_ATOMIC);
++      if (status < 0) {
++              ERROR(acm->port.func.config->cdev,
++                              "acm ttyGS%d can't notify serial state, %d\n",
++                              acm->port_num, status);
++              acm->notify_req = req;
++      }
++
++      return status;
++}
++
++static int acm_notify_serial_state(struct f_acm *acm)
++{
++      struct usb_composite_dev *cdev = acm->port.func.config->cdev;
++      int                     status;
++
++      spin_lock(&acm->lock);
++      if (acm->notify_req) {
++              DBG(cdev, "acm ttyGS%d serial state %04x\n",
++                              acm->port_num, acm->serial_state);
++              status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE,
++                              0, &acm->serial_state, sizeof(acm->serial_state));
++      } else {
++              acm->pending = true;
++              status = 0;
++      }
++      spin_unlock(&acm->lock);
++      return status;
++}
++
++static void acm_cdc_notify_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct f_acm            *acm = req->context;
++      u8                      doit = false;
++
++      /* on this call path we do NOT hold the port spinlock,
++       * which is why ACM needs its own spinlock
++       */
++      spin_lock(&acm->lock);
++      if (req->status != -ESHUTDOWN)
++              doit = acm->pending;
++      acm->notify_req = req;
++      spin_unlock(&acm->lock);
++
++      if (doit)
++              acm_notify_serial_state(acm);
++}
++
++/* connect == the TTY link is open */
++
++static void acm_connect(struct gserial *port)
++{
++      struct f_acm            *acm = port_to_acm(port);
++
++      acm->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD;
++      acm_notify_serial_state(acm);
++}
++
++static void acm_disconnect(struct gserial *port)
++{
++      struct f_acm            *acm = port_to_acm(port);
++
++      acm->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD);
++      acm_notify_serial_state(acm);
++}
++
++static int acm_send_break(struct gserial *port, int duration)
++{
++      struct f_acm            *acm = port_to_acm(port);
++      u16                     state;
++
++      state = acm->serial_state;
++      state &= ~ACM_CTRL_BRK;
++      if (duration)
++              state |= ACM_CTRL_BRK;
++
++      acm->serial_state = state;
++      return acm_notify_serial_state(acm);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* ACM function driver setup/binding */
++static int __init
++acm_bind(struct usb_configuration *c, struct usb_function *f)
++{
++      struct usb_composite_dev *cdev = c->cdev;
++      struct f_acm            *acm = func_to_acm(f);
++      int                     status;
++      struct usb_ep           *ep;
++
++      /* allocate instance-specific interface IDs, and patch descriptors */
++      status = usb_interface_id(c, f);
++      if (status < 0)
++              goto fail;
++      acm->ctrl_id = status;
++
++      acm_control_interface_desc.bInterfaceNumber = status;
++      acm_union_desc .bMasterInterface0 = status;
++
++      status = usb_interface_id(c, f);
++      if (status < 0)
++              goto fail;
++      acm->data_id = status;
++
++      acm_data_interface_desc.bInterfaceNumber = status;
++      acm_union_desc.bSlaveInterface0 = status;
++      acm_call_mgmt_descriptor.bDataInterface = status;
++
++      status = -ENODEV;
++
++      /* allocate instance-specific endpoints */
++      ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc);
++      if (!ep)
++              goto fail;
++      acm->port.in = ep;
++      ep->driver_data = cdev; /* claim */
++
++      ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
++      if (!ep)
++              goto fail;
++      acm->port.out = ep;
++      ep->driver_data = cdev; /* claim */
++
++      ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
++      if (!ep)
++              goto fail;
++      acm->notify = ep;
++      ep->driver_data = cdev; /* claim */
++
++      /* allocate notification */
++      acm->notify_req = gs_alloc_req(ep,
++                      sizeof(struct usb_cdc_notification) + 2,
++                      GFP_KERNEL);
++      if (!acm->notify_req)
++              goto fail;
++
++      acm->notify_req->complete = acm_cdc_notify_complete;
++      acm->notify_req->context = acm;
++
++      /* copy descriptors, and track endpoint copies */
++      f->descriptors = usb_copy_descriptors(acm_fs_function);
++      if (!f->descriptors)
++              goto fail;
++
++      acm->fs.in = usb_find_endpoint(acm_fs_function,
++                      f->descriptors, &acm_fs_in_desc);
++      acm->fs.out = usb_find_endpoint(acm_fs_function,
++                      f->descriptors, &acm_fs_out_desc);
++      acm->fs.notify = usb_find_endpoint(acm_fs_function,
++                      f->descriptors, &acm_fs_notify_desc);
++
++      /* support all relevant hardware speeds... we expect that when
++       * hardware is dual speed, all bulk-capable endpoints work at
++       * both speeds
++       */
++      if (gadget_is_dualspeed(c->cdev->gadget)) {
++              acm_hs_in_desc.bEndpointAddress =
++                              acm_fs_in_desc.bEndpointAddress;
++              acm_hs_out_desc.bEndpointAddress =
++                              acm_fs_out_desc.bEndpointAddress;
++              acm_hs_notify_desc.bEndpointAddress =
++                              acm_fs_notify_desc.bEndpointAddress;
++
++              /* copy descriptors, and track endpoint copies */
++              f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
++
++              acm->hs.in = usb_find_endpoint(acm_hs_function,
++                              f->hs_descriptors, &acm_hs_in_desc);
++              acm->hs.out = usb_find_endpoint(acm_hs_function,
++                              f->hs_descriptors, &acm_hs_out_desc);
++              acm->hs.notify = usb_find_endpoint(acm_hs_function,
++                              f->hs_descriptors, &acm_hs_notify_desc);
++      }
++
++      DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
++                      acm->port_num,
++                      gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++                      acm->port.in->name, acm->port.out->name,
++                      acm->notify->name);
++      return 0;
++
++fail:
++      if (acm->notify_req)
++              gs_free_req(acm->notify, acm->notify_req);
++
++      /* we might as well release our claims on endpoints */
++      if (acm->notify)
++              acm->notify->driver_data = NULL;
++      if (acm->port.out)
++              acm->port.out->driver_data = NULL;
++      if (acm->port.in)
++              acm->port.in->driver_data = NULL;
++
++      ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
++
++      return status;
++}
++
++static void
++acm_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++      struct f_acm            *acm = func_to_acm(f);
++
++      if (gadget_is_dualspeed(c->cdev->gadget))
++              usb_free_descriptors(f->hs_descriptors);
++      usb_free_descriptors(f->descriptors);
++      gs_free_req(acm->notify, acm->notify_req);
++      kfree(acm);
++}
++
++/* Some controllers can't support CDC ACM ... */
++static inline bool can_support_cdc(struct usb_configuration *c)
++{
++      /* SH3 doesn't support multiple interfaces */
++      if (gadget_is_sh(c->cdev->gadget))
++              return false;
++
++      /* sa1100 doesn't have a third interrupt endpoint */
++      if (gadget_is_sa1100(c->cdev->gadget))
++              return false;
++
++      /* everything else is *probably* fine ... */
++      return true;
++}
++
++/**
++ * acm_bind_config - add a CDC ACM function to a configuration
++ * @c: the configuration to support the CDC ACM instance
++ * @port_num: /dev/ttyGS* port this interface will use
++ * Context: single threaded during gadget setup
++ *
++ * Returns zero on success, else negative errno.
++ *
++ * Caller must have called @gserial_setup() with enough ports to
++ * handle all the ones it binds.  Caller is also responsible
++ * for calling @gserial_cleanup() before module unload.
++ */
++int __init acm_bind_config(struct usb_configuration *c, u8 port_num)
++{
++      struct f_acm    *acm;
++      int             status;
++
++      if (!can_support_cdc(c))
++              return -EINVAL;
++
++      /* REVISIT might want instance-specific strings to help
++       * distinguish instances ...
++       */
++
++      /* maybe allocate device-global string IDs, and patch descriptors */
++      if (acm_string_defs[ACM_CTRL_IDX].id == 0) {
++              status = usb_string_id(c->cdev);
++              if (status < 0)
++                      return status;
++              acm_string_defs[ACM_CTRL_IDX].id = status;
++
++              acm_control_interface_desc.iInterface = status;
++
++              status = usb_string_id(c->cdev);
++              if (status < 0)
++                      return status;
++              acm_string_defs[ACM_DATA_IDX].id = status;
++
++              acm_data_interface_desc.iInterface = status;
++      }
++
++      /* allocate and initialize one new instance */
++      acm = kzalloc(sizeof *acm, GFP_KERNEL);
++      if (!acm)
++              return -ENOMEM;
++
++      spin_lock_init(&acm->lock);
++
++      acm->port_num = port_num;
++
++      acm->port.connect = acm_connect;
++      acm->port.disconnect = acm_disconnect;
++      acm->port.send_break = acm_send_break;
++
++      acm->port.func.name = "acm";
++      acm->port.func.strings = acm_strings;
++      /* descriptors are per-instance copies */
++      acm->port.func.bind = acm_bind;
++      acm->port.func.unbind = acm_unbind;
++      acm->port.func.set_alt = acm_set_alt;
++      acm->port.func.setup = acm_setup;
++      acm->port.func.disable = acm_disable;
++
++      status = usb_add_function(c, &acm->port.func);
++      if (status)
++              kfree(acm);
++      return status;
++}
+diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
+new file mode 100644
+index 0000000..a2b5c09
+--- /dev/null
++++ b/drivers/usb/gadget/f_ecm.c
+@@ -0,0 +1,831 @@
++/*
++ * f_ecm.c -- USB CDC Ethernet (ECM) link function driver
++ *
++ * Copyright (C) 2003-2005,2008 David Brownell
++ * Copyright (C) 2008 Nokia Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/etherdevice.h>
++
++#include "u_ether.h"
++
++
++/*
++ * This function is a "CDC Ethernet Networking Control Model" (CDC ECM)
++ * Ethernet link.  The data transfer model is simple (packets sent and
++ * received over bulk endpoints using normal short packet termination),
++ * and the control model exposes various data and optional notifications.
++ *
++ * ECM is well standardized and (except for Microsoft) supported by most
++ * operating systems with USB host support.  It's the preferred interop
++ * solution for Ethernet over USB, at least for firmware based solutions.
++ * (Hardware solutions tend to be more minimalist.)  A newer and simpler
++ * "Ethernet Emulation Model" (CDC EEM) hasn't yet caught on.
++ *
++ * Note that ECM requires the use of "alternate settings" for its data
++ * interface.  This means that the set_alt() method has real work to do,
++ * and also means that a get_alt() method is required.
++ */
++
++struct ecm_ep_descs {
++      struct usb_endpoint_descriptor  *in;
++      struct usb_endpoint_descriptor  *out;
++      struct usb_endpoint_descriptor  *notify;
++};
++
++enum ecm_notify_state {
++      ECM_NOTIFY_NONE,                /* don't notify */
++      ECM_NOTIFY_CONNECT,             /* issue CONNECT next */
++      ECM_NOTIFY_SPEED,               /* issue SPEED_CHANGE next */
++};
++
++struct f_ecm {
++      struct gether                   port;
++      u8                              ctrl_id, data_id;
++
++      char                            ethaddr[14];
++
++      struct ecm_ep_descs             fs;
++      struct ecm_ep_descs             hs;
++
++      struct usb_ep                   *notify;
++      struct usb_endpoint_descriptor  *notify_desc;
++      struct usb_request              *notify_req;
++      u8                              notify_state;
++      bool                            is_open;
++
++      /* FIXME is_open needs some irq-ish locking
++       * ... possibly the same as port.ioport
++       */
++};
++
++static inline struct f_ecm *func_to_ecm(struct usb_function *f)
++{
++      return container_of(f, struct f_ecm, port.func);
++}
++
++/* peak (theoretical) bulk transfer rate in bits-per-second */
++static inline unsigned bitrate(struct usb_gadget *g)
++{
++      if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
++              return 13 * 512 * 8 * 1000 * 8;
++      else
++              return 19 *  64 * 1 * 1000 * 8;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * Include the status endpoint if we can, even though it's optional.
++ *
++ * Use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
++ * packet, to simplify cancellation; and a big transfer interval, to
++ * waste less bandwidth.
++ *
++ * Some drivers (like Linux 2.4 cdc-ether!) "need" it to exist even
++ * if they ignore the connect/disconnect notifications that real aether
++ * can provide.  More advanced cdc configurations might want to support
++ * encapsulated commands (vendor-specific, using control-OUT).
++ */
++
++#define LOG2_STATUS_INTERVAL_MSEC     5       /* 1 << 5 == 32 msec */
++#define STATUS_BYTECOUNT              16      /* 8 byte header + data */
++
++
++/* interface descriptor: */
++
++static struct usb_interface_descriptor ecm_control_intf __initdata = {
++      .bLength =              sizeof ecm_control_intf,
++      .bDescriptorType =      USB_DT_INTERFACE,
++
++      /* .bInterfaceNumber = DYNAMIC */
++      /* status endpoint is optional; this could be patched later */
++      .bNumEndpoints =        1,
++      .bInterfaceClass =      USB_CLASS_COMM,
++      .bInterfaceSubClass =   USB_CDC_SUBCLASS_ETHERNET,
++      .bInterfaceProtocol =   USB_CDC_PROTO_NONE,
++      /* .iInterface = DYNAMIC */
++};
++
++static struct usb_cdc_header_desc header_desc __initdata = {
++      .bLength =              sizeof header_desc,
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_HEADER_TYPE,
++
++      .bcdCDC =               __constant_cpu_to_le16(0x0110),
++};
++
++static struct usb_cdc_union_desc ecm_union_desc __initdata = {
++      .bLength =              sizeof(ecm_union_desc),
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_UNION_TYPE,
++      /* .bMasterInterface0 = DYNAMIC */
++      /* .bSlaveInterface0 =  DYNAMIC */
++};
++
++static struct usb_cdc_ether_desc ether_desc __initdata = {
++      .bLength =              sizeof ether_desc,
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_ETHERNET_TYPE,
++
++      /* this descriptor actually adds value, surprise! */
++      /* .iMACAddress = DYNAMIC */
++      .bmEthernetStatistics = __constant_cpu_to_le32(0), /* no statistics */
++      .wMaxSegmentSize =      __constant_cpu_to_le16(ETH_FRAME_LEN),
++      .wNumberMCFilters =     __constant_cpu_to_le16(0),
++      .bNumberPowerFilters =  0,
++};
++
++/* the default data interface has no endpoints ... */
++
++static struct usb_interface_descriptor ecm_data_nop_intf __initdata = {
++      .bLength =              sizeof ecm_data_nop_intf,
++      .bDescriptorType =      USB_DT_INTERFACE,
++
++      .bInterfaceNumber =     1,
++      .bAlternateSetting =    0,
++      .bNumEndpoints =        0,
++      .bInterfaceClass =      USB_CLASS_CDC_DATA,
++      .bInterfaceSubClass =   0,
++      .bInterfaceProtocol =   0,
++      /* .iInterface = DYNAMIC */
++};
++
++/* ... but the "real" data interface has two bulk endpoints */
++
++static struct usb_interface_descriptor ecm_data_intf __initdata = {
++      .bLength =              sizeof ecm_data_intf,
++      .bDescriptorType =      USB_DT_INTERFACE,
++
++      .bInterfaceNumber =     1,
++      .bAlternateSetting =    1,
++      .bNumEndpoints =        2,
++      .bInterfaceClass =      USB_CLASS_CDC_DATA,
++      .bInterfaceSubClass =   0,
++      .bInterfaceProtocol =   0,
++      /* .iInterface = DYNAMIC */
++};
++
++/* full speed support: */
++
++static struct usb_endpoint_descriptor fs_notify_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_INT,
++      .wMaxPacketSize =       __constant_cpu_to_le16(STATUS_BYTECOUNT),
++      .bInterval =            1 << LOG2_STATUS_INTERVAL_MSEC,
++};
++
++static struct usb_endpoint_descriptor fs_in_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor fs_out_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_OUT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_descriptor_header *eth_fs_function[] __initdata = {
++      /* CDC ECM control descriptors */
++      (struct usb_descriptor_header *) &ecm_control_intf,
++      (struct usb_descriptor_header *) &header_desc,
++      (struct usb_descriptor_header *) &ecm_union_desc,
++      (struct usb_descriptor_header *) &ether_desc,
++      /* NOTE: status endpoint might need to be removed */
++      (struct usb_descriptor_header *) &fs_notify_desc,
++      /* data interface, altsettings 0 and 1 */
++      (struct usb_descriptor_header *) &ecm_data_nop_intf,
++      (struct usb_descriptor_header *) &ecm_data_intf,
++      (struct usb_descriptor_header *) &fs_in_desc,
++      (struct usb_descriptor_header *) &fs_out_desc,
++      NULL,
++};
++
++/* high speed support: */
++
++static struct usb_endpoint_descriptor hs_notify_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_INT,
++      .wMaxPacketSize =       __constant_cpu_to_le16(STATUS_BYTECOUNT),
++      .bInterval =            LOG2_STATUS_INTERVAL_MSEC + 4,
++};
++static struct usb_endpoint_descriptor hs_in_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor hs_out_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_OUT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_descriptor_header *eth_hs_function[] __initdata = {
++      /* CDC ECM control descriptors */
++      (struct usb_descriptor_header *) &ecm_control_intf,
++      (struct usb_descriptor_header *) &header_desc,
++      (struct usb_descriptor_header *) &ecm_union_desc,
++      (struct usb_descriptor_header *) &ether_desc,
++      /* NOTE: status endpoint might need to be removed */
++      (struct usb_descriptor_header *) &hs_notify_desc,
++      /* data interface, altsettings 0 and 1 */
++      (struct usb_descriptor_header *) &ecm_data_nop_intf,
++      (struct usb_descriptor_header *) &ecm_data_intf,
++      (struct usb_descriptor_header *) &hs_in_desc,
++      (struct usb_descriptor_header *) &hs_out_desc,
++      NULL,
++};
++
++/* string descriptors: */
++
++static struct usb_string ecm_string_defs[] = {
++      [0].s = "CDC Ethernet Control Model (ECM)",
++      [1].s = NULL /* DYNAMIC */,
++      [2].s = "CDC Ethernet Data",
++      {  } /* end of list */
++};
++
++static struct usb_gadget_strings ecm_string_table = {
++      .language =             0x0409, /* en-us */
++      .strings =              ecm_string_defs,
++};
++
++static struct usb_gadget_strings *ecm_strings[] = {
++      &ecm_string_table,
++      NULL,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static void ecm_do_notify(struct f_ecm *ecm)
++{
++      struct usb_request              *req = ecm->notify_req;
++      struct usb_cdc_notification     *event;
++      struct usb_composite_dev        *cdev = ecm->port.func.config->cdev;
++      __le32                          *data;
++      int                             status;
++
++      /* notification already in flight? */
++      if (!req)
++              return;
++
++      event = req->buf;
++      switch (ecm->notify_state) {
++      case ECM_NOTIFY_NONE:
++              return;
++
++      case ECM_NOTIFY_CONNECT:
++              event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
++              if (ecm->is_open)
++                      event->wValue = cpu_to_le16(1);
++              else
++                      event->wValue = cpu_to_le16(0);
++              event->wLength = 0;
++              req->length = sizeof *event;
++
++              DBG(cdev, "notify connect %s\n",
++                              ecm->is_open ? "true" : "false");
++              ecm->notify_state = ECM_NOTIFY_SPEED;
++              break;
++
++      case ECM_NOTIFY_SPEED:
++              event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
++              event->wValue = cpu_to_le16(0);
++              event->wLength = cpu_to_le16(8);
++              req->length = STATUS_BYTECOUNT;
++
++              /* SPEED_CHANGE data is up/down speeds in bits/sec */
++              data = req->buf + sizeof *event;
++              data[0] = cpu_to_le32(bitrate(cdev->gadget));
++              data[1] = data[0];
++
++              DBG(cdev, "notify speed %d\n", bitrate(cdev->gadget));
++              ecm->notify_state = ECM_NOTIFY_NONE;
++              break;
++      }
++      event->bmRequestType = 0xA1;
++      event->wIndex = cpu_to_le16(ecm->ctrl_id);
++
++      ecm->notify_req = NULL;
++      status = usb_ep_queue(ecm->notify, req, GFP_ATOMIC);
++      if (status < 0) {
++              ecm->notify_req = req;
++              DBG(cdev, "notify --> %d\n", status);
++      }
++}
++
++static void ecm_notify(struct f_ecm *ecm)
++{
++      /* NOTE on most versions of Linux, host side cdc-ethernet
++       * won't listen for notifications until its netdevice opens.
++       * The first notification then sits in the FIFO for a long
++       * time, and the second one is queued.
++       */
++      ecm->notify_state = ECM_NOTIFY_CONNECT;
++      ecm_do_notify(ecm);
++}
++
++static void ecm_notify_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct f_ecm                    *ecm = req->context;
++      struct usb_composite_dev        *cdev = ecm->port.func.config->cdev;
++      struct usb_cdc_notification     *event = req->buf;
++
++      switch (req->status) {
++      case 0:
++              /* no fault */
++              break;
++      case -ECONNRESET:
++      case -ESHUTDOWN:
++              ecm->notify_state = ECM_NOTIFY_NONE;
++              break;
++      default:
++              DBG(cdev, "event %02x --> %d\n",
++                      event->bNotificationType, req->status);
++              break;
++      }
++      ecm->notify_req = req;
++      ecm_do_notify(ecm);
++}
++
++static int ecm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
++{
++      struct f_ecm            *ecm = func_to_ecm(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++      struct usb_request      *req = cdev->req;
++      int                     value = -EOPNOTSUPP;
++      u16                     w_index = le16_to_cpu(ctrl->wIndex);
++      u16                     w_value = le16_to_cpu(ctrl->wValue);
++      u16                     w_length = le16_to_cpu(ctrl->wLength);
++
++      /* composite driver infrastructure handles everything except
++       * CDC class messages; interface activation uses set_alt().
++       */
++      switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
++      case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
++                      | USB_CDC_SET_ETHERNET_PACKET_FILTER:
++              /* see 6.2.30: no data, wIndex = interface,
++               * wValue = packet filter bitmap
++               */
++              if (w_length != 0 || w_index != ecm->ctrl_id)
++                      goto invalid;
++              DBG(cdev, "packet filter %02x\n", w_value);
++              /* REVISIT locking of cdc_filter.  This assumes the UDC
++               * driver won't have a concurrent packet TX irq running on
++               * another CPU; or that if it does, this write is atomic...
++               */
++              ecm->port.cdc_filter = w_value;
++              value = 0;
++              break;
++
++      /* and optionally:
++       * case USB_CDC_SEND_ENCAPSULATED_COMMAND:
++       * case USB_CDC_GET_ENCAPSULATED_RESPONSE:
++       * case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
++       * case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER:
++       * case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER:
++       * case USB_CDC_GET_ETHERNET_STATISTIC:
++       */
++
++      default:
++invalid:
++              DBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
++                      ctrl->bRequestType, ctrl->bRequest,
++                      w_value, w_index, w_length);
++      }
++
++      /* respond with data transfer or status phase? */
++      if (value >= 0) {
++              DBG(cdev, "ecm req%02x.%02x v%04x i%04x l%d\n",
++                      ctrl->bRequestType, ctrl->bRequest,
++                      w_value, w_index, w_length);
++              req->zero = 0;
++              req->length = value;
++              value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
++              if (value < 0)
++                      ERROR(cdev, "ecm req %02x.%02x response err %d\n",
++                                      ctrl->bRequestType, ctrl->bRequest,
++                                      value);
++      }
++
++      /* device either stalls (value < 0) or reports success */
++      return value;
++}
++
++
++static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
++{
++      struct f_ecm            *ecm = func_to_ecm(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      /* Control interface has only altsetting 0 */
++      if (intf == ecm->ctrl_id) {
++              if (alt != 0)
++                      goto fail;
++
++              if (ecm->notify->driver_data) {
++                      VDBG(cdev, "reset ecm control %d\n", intf);
++                      usb_ep_disable(ecm->notify);
++              } else {
++                      VDBG(cdev, "init ecm ctrl %d\n", intf);
++                      ecm->notify_desc = ep_choose(cdev->gadget,
++                                      ecm->hs.notify,
++                                      ecm->fs.notify);
++              }
++              usb_ep_enable(ecm->notify, ecm->notify_desc);
++              ecm->notify->driver_data = ecm;
++
++      /* Data interface has two altsettings, 0 and 1 */
++      } else if (intf == ecm->data_id) {
++              if (alt > 1)
++                      goto fail;
++
++              if (ecm->port.in_ep->driver_data) {
++                      DBG(cdev, "reset ecm\n");
++                      gether_disconnect(&ecm->port);
++              }
++
++              if (!ecm->port.in) {
++                      DBG(cdev, "init ecm\n");
++                      ecm->port.in = ep_choose(cdev->gadget,
++                                      ecm->hs.in, ecm->fs.in);
++                      ecm->port.out = ep_choose(cdev->gadget,
++                                      ecm->hs.out, ecm->fs.out);
++              }
++
++              /* CDC Ethernet only sends data in non-default altsettings.
++               * Changing altsettings resets filters, statistics, etc.
++               */
++              if (alt == 1) {
++                      struct net_device       *net;
++
++                      /* Enable zlps by default for ECM conformance;
++                       * override for musb_hdrc (avoids txdma ovhead)
++                       * and sa1100 (can't).
++                       */
++                      ecm->port.is_zlp_ok = !(
++                                 gadget_is_sa1100(cdev->gadget)
++                              || gadget_is_musbhdrc(cdev->gadget)
++                              );
++                      ecm->port.cdc_filter = DEFAULT_FILTER;
++                      DBG(cdev, "activate ecm\n");
++                      net = gether_connect(&ecm->port);
++                      if (IS_ERR(net))
++                              return PTR_ERR(net);
++              }
++
++              /* NOTE this can be a minor disagreement with the ECM spec,
++               * which says speed notifications will "always" follow
++               * connection notifications.  But we allow one connect to
++               * follow another (if the first is in flight), and instead
++               * just guarantee that a speed notification is always sent.
++               */
++              ecm_notify(ecm);
++      } else
++              goto fail;
++
++      return 0;
++fail:
++      return -EINVAL;
++}
++
++/* Because the data interface supports multiple altsettings,
++ * this ECM function *MUST* implement a get_alt() method.
++ */
++static int ecm_get_alt(struct usb_function *f, unsigned intf)
++{
++      struct f_ecm            *ecm = func_to_ecm(f);
++
++      if (intf == ecm->ctrl_id)
++              return 0;
++      return ecm->port.in_ep->driver_data ? 1 : 0;
++}
++
++static void ecm_disable(struct usb_function *f)
++{
++      struct f_ecm            *ecm = func_to_ecm(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      DBG(cdev, "ecm deactivated\n");
++
++      if (ecm->port.in_ep->driver_data)
++              gether_disconnect(&ecm->port);
++
++      if (ecm->notify->driver_data) {
++              usb_ep_disable(ecm->notify);
++              ecm->notify->driver_data = NULL;
++              ecm->notify_desc = NULL;
++      }
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * Callbacks let us notify the host about connect/disconnect when the
++ * net device is opened or closed.
++ *
++ * For testing, note that link states on this side include both opened
++ * and closed variants of:
++ *
++ *   - disconnected/unconfigured
++ *   - configured but inactive (data alt 0)
++ *   - configured and active (data alt 1)
++ *
++ * Each needs to be tested with unplug, rmmod, SET_CONFIGURATION, and
++ * SET_INTERFACE (altsetting).  Remember also that "configured" doesn't
++ * imply the host is actually polling the notification endpoint, and
++ * likewise that "active" doesn't imply it's actually using the data
++ * endpoints for traffic.
++ */
++
++static void ecm_open(struct gether *geth)
++{
++      struct f_ecm            *ecm = func_to_ecm(&geth->func);
++
++      DBG(ecm->port.func.config->cdev, "%s\n", __func__);
++
++      ecm->is_open = true;
++      ecm_notify(ecm);
++}
++
++static void ecm_close(struct gether *geth)
++{
++      struct f_ecm            *ecm = func_to_ecm(&geth->func);
++
++      DBG(ecm->port.func.config->cdev, "%s\n", __func__);
++
++      ecm->is_open = false;
++      ecm_notify(ecm);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* ethernet function driver setup/binding */
++
++static int __init
++ecm_bind(struct usb_configuration *c, struct usb_function *f)
++{
++      struct usb_composite_dev *cdev = c->cdev;
++      struct f_ecm            *ecm = func_to_ecm(f);
++      int                     status;
++      struct usb_ep           *ep;
++
++      /* allocate instance-specific interface IDs */
++      status = usb_interface_id(c, f);
++      if (status < 0)
++              goto fail;
++      ecm->ctrl_id = status;
++
++      ecm_control_intf.bInterfaceNumber = status;
++      ecm_union_desc.bMasterInterface0 = status;
++
++      status = usb_interface_id(c, f);
++      if (status < 0)
++              goto fail;
++      ecm->data_id = status;
++
++      ecm_data_nop_intf.bInterfaceNumber = status;
++      ecm_data_intf.bInterfaceNumber = status;
++      ecm_union_desc.bSlaveInterface0 = status;
++
++      status = -ENODEV;
++
++      /* allocate instance-specific endpoints */
++      ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc);
++      if (!ep)
++              goto fail;
++      ecm->port.in_ep = ep;
++      ep->driver_data = cdev; /* claim */
++
++      ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc);
++      if (!ep)
++              goto fail;
++      ecm->port.out_ep = ep;
++      ep->driver_data = cdev; /* claim */
++
++      /* NOTE:  a status/notification endpoint is *OPTIONAL* but we
++       * don't treat it that way.  It's simpler, and some newer CDC
++       * profiles (wireless handsets) no longer treat it as optional.
++       */
++      ep = usb_ep_autoconfig(cdev->gadget, &fs_notify_desc);
++      if (!ep)
++              goto fail;
++      ecm->notify = ep;
++      ep->driver_data = cdev; /* claim */
++
++      status = -ENOMEM;
++
++      /* allocate notification request and buffer */
++      ecm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
++      if (!ecm->notify_req)
++              goto fail;
++      ecm->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
++      if (!ecm->notify_req->buf)
++              goto fail;
++      ecm->notify_req->context = ecm;
++      ecm->notify_req->complete = ecm_notify_complete;
++
++      /* copy descriptors, and track endpoint copies */
++      f->descriptors = usb_copy_descriptors(eth_fs_function);
++      if (!f->descriptors)
++              goto fail;
++
++      ecm->fs.in = usb_find_endpoint(eth_fs_function,
++                      f->descriptors, &fs_in_desc);
++      ecm->fs.out = usb_find_endpoint(eth_fs_function,
++                      f->descriptors, &fs_out_desc);
++      ecm->fs.notify = usb_find_endpoint(eth_fs_function,
++                      f->descriptors, &fs_notify_desc);
++
++      /* support all relevant hardware speeds... we expect that when
++       * hardware is dual speed, all bulk-capable endpoints work at
++       * both speeds
++       */
++      if (gadget_is_dualspeed(c->cdev->gadget)) {
++              hs_in_desc.bEndpointAddress =
++                              fs_in_desc.bEndpointAddress;
++              hs_out_desc.bEndpointAddress =
++                              fs_out_desc.bEndpointAddress;
++              hs_notify_desc.bEndpointAddress =
++                              fs_notify_desc.bEndpointAddress;
++
++              /* copy descriptors, and track endpoint copies */
++              f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
++              if (!f->hs_descriptors)
++                      goto fail;
++
++              ecm->hs.in = usb_find_endpoint(eth_hs_function,
++                              f->hs_descriptors, &hs_in_desc);
++              ecm->hs.out = usb_find_endpoint(eth_hs_function,
++                              f->hs_descriptors, &hs_out_desc);
++              ecm->hs.notify = usb_find_endpoint(eth_hs_function,
++                              f->hs_descriptors, &hs_notify_desc);
++      }
++
++      /* NOTE:  all that is done without knowing or caring about
++       * the network link ... which is unavailable to this code
++       * until we're activated via set_alt().
++       */
++
++      ecm->port.open = ecm_open;
++      ecm->port.close = ecm_close;
++
++      DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n",
++                      gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++                      ecm->port.in_ep->name, ecm->port.out_ep->name,
++                      ecm->notify->name);
++      return 0;
++
++fail:
++      if (f->descriptors)
++              usb_free_descriptors(f->descriptors);
++
++      if (ecm->notify_req) {
++              kfree(ecm->notify_req->buf);
++              usb_ep_free_request(ecm->notify, ecm->notify_req);
++      }
++
++      /* we might as well release our claims on endpoints */
++      if (ecm->notify)
++              ecm->notify->driver_data = NULL;
++      if (ecm->port.out)
++              ecm->port.out_ep->driver_data = NULL;
++      if (ecm->port.in)
++              ecm->port.in_ep->driver_data = NULL;
++
++      ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
++
++      return status;
++}
++
++static void
++ecm_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++      struct f_ecm            *ecm = func_to_ecm(f);
++
++      DBG(c->cdev, "ecm unbind\n");
++
++      if (gadget_is_dualspeed(c->cdev->gadget))
++              usb_free_descriptors(f->hs_descriptors);
++      usb_free_descriptors(f->descriptors);
++
++      kfree(ecm->notify_req->buf);
++      usb_ep_free_request(ecm->notify, ecm->notify_req);
++
++      ecm_string_defs[1].s = NULL;
++      kfree(ecm);
++}
++
++/**
++ * ecm_bind_config - add CDC Ethernet network link to a configuration
++ * @c: the configuration to support the network link
++ * @ethaddr: a buffer in which the ethernet address of the host side
++ *    side of the link was recorded
++ * Context: single threaded during gadget setup
++ *
++ * Returns zero on success, else negative errno.
++ *
++ * Caller must have called @gether_setup().  Caller is also responsible
++ * for calling @gether_cleanup() before module unload.
++ */
++int __init ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
++{
++      struct f_ecm    *ecm;
++      int             status;
++
++      if (!can_support_ecm(c->cdev->gadget) || !ethaddr)
++              return -EINVAL;
++
++      /* maybe allocate device-global string IDs */
++      if (ecm_string_defs[0].id == 0) {
++
++              /* control interface label */
++              status = usb_string_id(c->cdev);
++              if (status < 0)
++                      return status;
++              ecm_string_defs[0].id = status;
++              ecm_control_intf.iInterface = status;
++
++              /* data interface label */
++              status = usb_string_id(c->cdev);
++              if (status < 0)
++                      return status;
++              ecm_string_defs[2].id = status;
++              ecm_data_intf.iInterface = status;
++
++              /* MAC address */
++              status = usb_string_id(c->cdev);
++              if (status < 0)
++                      return status;
++              ecm_string_defs[1].id = status;
++              ether_desc.iMACAddress = status;
++      }
++
++      /* allocate and initialize one new instance */
++      ecm = kzalloc(sizeof *ecm, GFP_KERNEL);
++      if (!ecm)
++              return -ENOMEM;
++
++      /* export host's Ethernet address in CDC format */
++      snprintf(ecm->ethaddr, sizeof ecm->ethaddr,
++              "%02X%02X%02X%02X%02X%02X",
++              ethaddr[0], ethaddr[1], ethaddr[2],
++              ethaddr[3], ethaddr[4], ethaddr[5]);
++      ecm_string_defs[1].s = ecm->ethaddr;
++
++      ecm->port.cdc_filter = DEFAULT_FILTER;
++
++      ecm->port.func.name = "cdc_ethernet";
++      ecm->port.func.strings = ecm_strings;
++      /* descriptors are per-instance copies */
++      ecm->port.func.bind = ecm_bind;
++      ecm->port.func.unbind = ecm_unbind;
++      ecm->port.func.set_alt = ecm_set_alt;
++      ecm->port.func.get_alt = ecm_get_alt;
++      ecm->port.func.setup = ecm_setup;
++      ecm->port.func.disable = ecm_disable;
++
++      status = usb_add_function(c, &ecm->port.func);
++      if (status) {
++              ecm_string_defs[1].s = NULL;
++              kfree(ecm);
++      }
++      return status;
++}
+diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
+new file mode 100644
+index 0000000..eda4cde
+--- /dev/null
++++ b/drivers/usb/gadget/f_loopback.c
+@@ -0,0 +1,381 @@
++/*
++ * f_loopback.c - USB peripheral loopback configuration driver
++ *
++ * Copyright (C) 2003-2008 David Brownell
++ * Copyright (C) 2008 by Nokia Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kernel.h>
++#include <linux/utsname.h>
++#include <linux/device.h>
++
++#include "g_zero.h"
++#include "gadget_chips.h"
++
++
++/*
++ * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals,
++ *
++ * This takes messages of various sizes written OUT to a device, and loops
++ * them back so they can be read IN from it.  It has been used by certain
++ * test applications.  It supports limited testing of data queueing logic.
++ *
++ *
++ * This is currently packaged as a configuration driver, which can't be
++ * combined with other functions to make composite devices.  However, it
++ * can be combined with other independent configurations.
++ */
++struct f_loopback {
++      struct usb_function     function;
++
++      struct usb_ep           *in_ep;
++      struct usb_ep           *out_ep;
++};
++
++static inline struct f_loopback *func_to_loop(struct usb_function *f)
++{
++      return container_of(f, struct f_loopback, function);
++}
++
++static unsigned qlen = 32;
++module_param(qlen, uint, 0);
++MODULE_PARM_DESC(qlenn, "depth of loopback queue");
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_interface_descriptor loopback_intf = {
++      .bLength =              sizeof loopback_intf,
++      .bDescriptorType =      USB_DT_INTERFACE,
++
++      .bNumEndpoints =        2,
++      .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
++      /* .iInterface = DYNAMIC */
++};
++
++/* full speed support: */
++
++static struct usb_endpoint_descriptor fs_source_desc = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor fs_sink_desc = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_OUT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_descriptor_header *fs_loopback_descs[] = {
++      (struct usb_descriptor_header *) &loopback_intf,
++      (struct usb_descriptor_header *) &fs_sink_desc,
++      (struct usb_descriptor_header *) &fs_source_desc,
++      NULL,
++};
++
++/* high speed support: */
++
++static struct usb_endpoint_descriptor hs_source_desc = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor hs_sink_desc = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_descriptor_header *hs_loopback_descs[] = {
++      (struct usb_descriptor_header *) &loopback_intf,
++      (struct usb_descriptor_header *) &hs_source_desc,
++      (struct usb_descriptor_header *) &hs_sink_desc,
++      NULL,
++};
++
++/* function-specific strings: */
++
++static struct usb_string strings_loopback[] = {
++      [0].s = "loop input to output",
++      {  }                    /* end of list */
++};
++
++static struct usb_gadget_strings stringtab_loop = {
++      .language       = 0x0409,       /* en-us */
++      .strings        = strings_loopback,
++};
++
++static struct usb_gadget_strings *loopback_strings[] = {
++      &stringtab_loop,
++      NULL,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int __init
++loopback_bind(struct usb_configuration *c, struct usb_function *f)
++{
++      struct usb_composite_dev *cdev = c->cdev;
++      struct f_loopback       *loop = func_to_loop(f);
++      int                     id;
++
++      /* allocate interface ID(s) */
++      id = usb_interface_id(c, f);
++      if (id < 0)
++              return id;
++      loopback_intf.bInterfaceNumber = id;
++
++      /* allocate endpoints */
++
++      loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
++      if (!loop->in_ep) {
++autoconf_fail:
++              ERROR(cdev, "%s: can't autoconfigure on %s\n",
++                      f->name, cdev->gadget->name);
++              return -ENODEV;
++      }
++      loop->in_ep->driver_data = cdev;        /* claim */
++
++      loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
++      if (!loop->out_ep)
++              goto autoconf_fail;
++      loop->out_ep->driver_data = cdev;       /* claim */
++
++      /* support high speed hardware */
++      if (gadget_is_dualspeed(c->cdev->gadget)) {
++              hs_source_desc.bEndpointAddress =
++                              fs_source_desc.bEndpointAddress;
++              hs_sink_desc.bEndpointAddress =
++                              fs_sink_desc.bEndpointAddress;
++              f->hs_descriptors = hs_loopback_descs;
++      }
++
++      DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
++                      gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++                      f->name, loop->in_ep->name, loop->out_ep->name);
++      return 0;
++}
++
++static void
++loopback_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++      kfree(func_to_loop(f));
++}
++
++static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct f_loopback       *loop = ep->driver_data;
++      struct usb_composite_dev *cdev = loop->function.config->cdev;
++      int                     status = req->status;
++
++      switch (status) {
++
++      case 0:                         /* normal completion? */
++              if (ep == loop->out_ep) {
++                      /* loop this OUT packet back IN to the host */
++                      req->zero = (req->actual < req->length);
++                      req->length = req->actual;
++                      status = usb_ep_queue(loop->in_ep, req, GFP_ATOMIC);
++                      if (status == 0)
++                              return;
++
++                      /* "should never get here" */
++                      ERROR(cdev, "can't loop %s to %s: %d\n",
++                              ep->name, loop->in_ep->name,
++                              status);
++              }
++
++              /* queue the buffer for some later OUT packet */
++              req->length = buflen;
++              status = usb_ep_queue(loop->out_ep, req, GFP_ATOMIC);
++              if (status == 0)
++                      return;
++
++              /* "should never get here" */
++              /* FALLTHROUGH */
++
++      default:
++              ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name,
++                              status, req->actual, req->length);
++              /* FALLTHROUGH */
++
++      /* NOTE:  since this driver doesn't maintain an explicit record
++       * of requests it submitted (just maintains qlen count), we
++       * rely on the hardware driver to clean up on disconnect or
++       * endpoint disable.
++       */
++      case -ECONNABORTED:             /* hardware forced ep reset */
++      case -ECONNRESET:               /* request dequeued */
++      case -ESHUTDOWN:                /* disconnect from host */
++              free_ep_req(ep, req);
++              return;
++      }
++}
++
++static void disable_loopback(struct f_loopback *loop)
++{
++      struct usb_composite_dev        *cdev;
++
++      cdev = loop->function.config->cdev;
++      disable_endpoints(cdev, loop->in_ep, loop->out_ep);
++      VDBG(cdev, "%s disabled\n", loop->function.name);
++}
++
++static int
++enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
++{
++      int                                     result = 0;
++      const struct usb_endpoint_descriptor    *src, *sink;
++      struct usb_ep                           *ep;
++      struct usb_request                      *req;
++      unsigned                                i;
++
++      src = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
++      sink = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
++
++      /* one endpoint writes data back IN to the host */
++      ep = loop->in_ep;
++      result = usb_ep_enable(ep, src);
++      if (result < 0)
++              return result;
++      ep->driver_data = loop;
++
++      /* one endpoint just reads OUT packets */
++      ep = loop->out_ep;
++      result = usb_ep_enable(ep, sink);
++      if (result < 0) {
++fail0:
++              ep = loop->in_ep;
++              usb_ep_disable(ep);
++              ep->driver_data = NULL;
++              return result;
++      }
++      ep->driver_data = loop;
++
++      /* allocate a bunch of read buffers and queue them all at once.
++       * we buffer at most 'qlen' transfers; fewer if any need more
++       * than 'buflen' bytes each.
++       */
++      for (i = 0; i < qlen && result == 0; i++) {
++              req = alloc_ep_req(ep);
++              if (req) {
++                      req->complete = loopback_complete;
++                      result = usb_ep_queue(ep, req, GFP_ATOMIC);
++                      if (result)
++                              ERROR(cdev, "%s queue req --> %d\n",
++                                              ep->name, result);
++              } else {
++                      usb_ep_disable(ep);
++                      ep->driver_data = NULL;
++                      result = -ENOMEM;
++                      goto fail0;
++              }
++      }
++
++      DBG(cdev, "%s enabled\n", loop->function.name);
++      return result;
++}
++
++static int loopback_set_alt(struct usb_function *f,
++              unsigned intf, unsigned alt)
++{
++      struct f_loopback       *loop = func_to_loop(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      /* we know alt is zero */
++      if (loop->in_ep->driver_data)
++              disable_loopback(loop);
++      return enable_loopback(cdev, loop);
++}
++
++static void loopback_disable(struct usb_function *f)
++{
++      struct f_loopback       *loop = func_to_loop(f);
++
++      disable_loopback(loop);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int __init loopback_bind_config(struct usb_configuration *c)
++{
++      struct f_loopback       *loop;
++      int                     status;
++
++      loop = kzalloc(sizeof *loop, GFP_KERNEL);
++      if (!loop)
++              return -ENOMEM;
++
++      loop->function.name = "loopback";
++      loop->function.descriptors = fs_loopback_descs;
++      loop->function.bind = loopback_bind;
++      loop->function.unbind = loopback_unbind;
++      loop->function.set_alt = loopback_set_alt;
++      loop->function.disable = loopback_disable;
++
++      status = usb_add_function(c, &loop->function);
++      if (status)
++              kfree(loop);
++      return status;
++}
++
++static struct usb_configuration loopback_driver = {
++      .label          = "loopback",
++      .strings        = loopback_strings,
++      .bind           = loopback_bind_config,
++      .bConfigurationValue = 2,
++      .bmAttributes   = USB_CONFIG_ATT_SELFPOWER,
++      .bMaxPower      = 1,    /* 2 mA, minimal */
++      /* .iConfiguration = DYNAMIC */
++};
++
++/**
++ * loopback_add - add a loopback testing configuration to a device
++ * @cdev: the device to support the loopback configuration
++ */
++int __init loopback_add(struct usb_composite_dev *cdev)
++{
++      int id;
++
++      /* allocate string ID(s) */
++      id = usb_string_id(cdev);
++      if (id < 0)
++              return id;
++      strings_loopback[0].id = id;
++
++      loopback_intf.iInterface = id;
++      loopback_driver.iConfiguration = id;
++
++      /* support OTG systems */
++      if (gadget_is_otg(cdev->gadget)) {
++              loopback_driver.descriptors = otg_desc;
++              loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++      }
++
++      return usb_add_config(cdev, &loopback_driver);
++}
+diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
+new file mode 100644
+index 0000000..659b3d9
+--- /dev/null
++++ b/drivers/usb/gadget/f_rndis.c
+@@ -0,0 +1,825 @@
++/*
++ * f_rndis.c -- RNDIS link function driver
++ *
++ * Copyright (C) 2003-2005,2008 David Brownell
++ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
++ * Copyright (C) 2008 Nokia Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/etherdevice.h>
++
++#include <asm/atomic.h>
++
++#include "u_ether.h"
++#include "rndis.h"
++
++
++/*
++ * This function is an RNDIS Ethernet port -- a Microsoft protocol that's
++ * been promoted instead of the standard CDC Ethernet.  The published RNDIS
++ * spec is ambiguous, incomplete, and needlessly complex.  Variants such as
++ * ActiveSync have even worse status in terms of specification.
++ *
++ * In short:  it's a protocol controlled by (and for) Microsoft, not for an
++ * Open ecosystem or markets.  Linux supports it *only* because Microsoft
++ * doesn't support the CDC Ethernet standard.
++ *
++ * The RNDIS data transfer model is complex, with multiple Ethernet packets
++ * per USB message, and out of band data.  The control model is built around
++ * what's essentially an "RNDIS RPC" protocol.  It's all wrapped in a CDC ACM
++ * (modem, not Ethernet) veneer, with those ACM descriptors being entirely
++ * useless (they're ignored).  RNDIS expects to be the only function in its
++ * configuration, so it's no real help if you need composite devices; and
++ * it expects to be the first configuration too.
++ *
++ * There is a single technical advantage of RNDIS over CDC Ethernet, if you
++ * discount the fluff that its RPC can be made to deliver: it doesn't need
++ * a NOP altsetting for the data interface.  That lets it work on some of the
++ * "so smart it's stupid" hardware which takes over configuration changes
++ * from the software, and adds restrictions like "no altsettings".
++ *
++ * Unfortunately MSFT's RNDIS drivers are buggy.  They hang or oops, and
++ * have all sorts of contrary-to-specification oddities that can prevent
++ * them from working sanely.  Since bugfixes (or accurate specs, letting
++ * Linux work around those bugs) are unlikely to ever come from MSFT, you
++ * may want to avoid using RNDIS on purely operational grounds.
++ *
++ * Omissions from the RNDIS 1.0 specification include:
++ *
++ *   - Power management ... references data that's scattered around lots
++ *     of other documentation, which is incorrect/incomplete there too.
++ *
++ *   - There are various undocumented protocol requirements, like the need
++ *     to send garbage in some control-OUT messages.
++ *
++ *   - MS-Windows drivers sometimes emit undocumented requests.
++ */
++
++struct rndis_ep_descs {
++      struct usb_endpoint_descriptor  *in;
++      struct usb_endpoint_descriptor  *out;
++      struct usb_endpoint_descriptor  *notify;
++};
++
++struct f_rndis {
++      struct gether                   port;
++      u8                              ctrl_id, data_id;
++      u8                              ethaddr[ETH_ALEN];
++      int                             config;
++
++      struct rndis_ep_descs           fs;
++      struct rndis_ep_descs           hs;
++
++      struct usb_ep                   *notify;
++      struct usb_endpoint_descriptor  *notify_desc;
++      struct usb_request              *notify_req;
++      atomic_t                        notify_count;
++};
++
++static inline struct f_rndis *func_to_rndis(struct usb_function *f)
++{
++      return container_of(f, struct f_rndis, port.func);
++}
++
++/* peak (theoretical) bulk transfer rate in bits-per-second */
++static unsigned int bitrate(struct usb_gadget *g)
++{
++      if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
++              return 13 * 512 * 8 * 1000 * 8;
++      else
++              return 19 *  64 * 1 * 1000 * 8;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ */
++
++#define LOG2_STATUS_INTERVAL_MSEC     5       /* 1 << 5 == 32 msec */
++#define STATUS_BYTECOUNT              8       /* 8 bytes data */
++
++
++/* interface descriptor: */
++
++static struct usb_interface_descriptor rndis_control_intf __initdata = {
++      .bLength =              sizeof rndis_control_intf,
++      .bDescriptorType =      USB_DT_INTERFACE,
++
++      /* .bInterfaceNumber = DYNAMIC */
++      /* status endpoint is optional; this could be patched later */
++      .bNumEndpoints =        1,
++      .bInterfaceClass =      USB_CLASS_COMM,
++      .bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
++      .bInterfaceProtocol =   USB_CDC_ACM_PROTO_VENDOR,
++      /* .iInterface = DYNAMIC */
++};
++
++static struct usb_cdc_header_desc header_desc __initdata = {
++      .bLength =              sizeof header_desc,
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_HEADER_TYPE,
++
++      .bcdCDC =               __constant_cpu_to_le16(0x0110),
++};
++
++static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor __initdata = {
++      .bLength =              sizeof call_mgmt_descriptor,
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
++
++      .bmCapabilities =       0x00,
++      .bDataInterface =       0x01,
++};
++
++static struct usb_cdc_acm_descriptor acm_descriptor __initdata = {
++      .bLength =              sizeof acm_descriptor,
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_ACM_TYPE,
++
++      .bmCapabilities =       0x00,
++};
++
++static struct usb_cdc_union_desc rndis_union_desc __initdata = {
++      .bLength =              sizeof(rndis_union_desc),
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_UNION_TYPE,
++      /* .bMasterInterface0 = DYNAMIC */
++      /* .bSlaveInterface0 =  DYNAMIC */
++};
++
++/* the data interface has two bulk endpoints */
++
++static struct usb_interface_descriptor rndis_data_intf __initdata = {
++      .bLength =              sizeof rndis_data_intf,
++      .bDescriptorType =      USB_DT_INTERFACE,
++
++      /* .bInterfaceNumber = DYNAMIC */
++      .bAlternateSetting =    1,
++      .bNumEndpoints =        2,
++      .bInterfaceClass =      USB_CLASS_CDC_DATA,
++      .bInterfaceSubClass =   0,
++      .bInterfaceProtocol =   0,
++      /* .iInterface = DYNAMIC */
++};
++
++/* full speed support: */
++
++static struct usb_endpoint_descriptor fs_notify_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_INT,
++      .wMaxPacketSize =       __constant_cpu_to_le16(STATUS_BYTECOUNT),
++      .bInterval =            1 << LOG2_STATUS_INTERVAL_MSEC,
++};
++
++static struct usb_endpoint_descriptor fs_in_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor fs_out_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_OUT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_descriptor_header *eth_fs_function[] __initdata = {
++      /* control interface matches ACM, not Ethernet */
++      (struct usb_descriptor_header *) &rndis_control_intf,
++      (struct usb_descriptor_header *) &header_desc,
++      (struct usb_descriptor_header *) &call_mgmt_descriptor,
++      (struct usb_descriptor_header *) &acm_descriptor,
++      (struct usb_descriptor_header *) &rndis_union_desc,
++      (struct usb_descriptor_header *) &fs_notify_desc,
++      /* data interface has no altsetting */
++      (struct usb_descriptor_header *) &rndis_data_intf,
++      (struct usb_descriptor_header *) &fs_in_desc,
++      (struct usb_descriptor_header *) &fs_out_desc,
++      NULL,
++};
++
++/* high speed support: */
++
++static struct usb_endpoint_descriptor hs_notify_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_INT,
++      .wMaxPacketSize =       __constant_cpu_to_le16(STATUS_BYTECOUNT),
++      .bInterval =            LOG2_STATUS_INTERVAL_MSEC + 4,
++};
++static struct usb_endpoint_descriptor hs_in_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor hs_out_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_OUT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_descriptor_header *eth_hs_function[] __initdata = {
++      /* control interface matches ACM, not Ethernet */
++      (struct usb_descriptor_header *) &rndis_control_intf,
++      (struct usb_descriptor_header *) &header_desc,
++      (struct usb_descriptor_header *) &call_mgmt_descriptor,
++      (struct usb_descriptor_header *) &acm_descriptor,
++      (struct usb_descriptor_header *) &rndis_union_desc,
++      (struct usb_descriptor_header *) &hs_notify_desc,
++      /* data interface has no altsetting */
++      (struct usb_descriptor_header *) &rndis_data_intf,
++      (struct usb_descriptor_header *) &hs_in_desc,
++      (struct usb_descriptor_header *) &hs_out_desc,
++      NULL,
++};
++
++/* string descriptors: */
++
++static struct usb_string rndis_string_defs[] = {
++      [0].s = "RNDIS Communications Control",
++      [1].s = "RNDIS Ethernet Data",
++      {  } /* end of list */
++};
++
++static struct usb_gadget_strings rndis_string_table = {
++      .language =             0x0409, /* en-us */
++      .strings =              rndis_string_defs,
++};
++
++static struct usb_gadget_strings *rndis_strings[] = {
++      &rndis_string_table,
++      NULL,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static struct sk_buff *rndis_add_header(struct sk_buff *skb)
++{
++      skb = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
++      if (skb)
++              rndis_add_hdr(skb);
++      return skb;
++}
++
++static void rndis_response_available(void *_rndis)
++{
++      struct f_rndis                  *rndis = _rndis;
++      struct usb_request              *req = rndis->notify_req;
++      struct usb_composite_dev        *cdev = rndis->port.func.config->cdev;
++      __le32                          *data = req->buf;
++      int                             status;
++
++      if (atomic_inc_return(&rndis->notify_count))
++              return;
++
++      /* Send RNDIS RESPONSE_AVAILABLE notification; a
++       * USB_CDC_NOTIFY_RESPONSE_AVAILABLE "should" work too
++       *
++       * This is the only notification defined by RNDIS.
++       */
++      data[0] = cpu_to_le32(1);
++      data[1] = cpu_to_le32(0);
++
++      status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
++      if (status) {
++              atomic_dec(&rndis->notify_count);
++              DBG(cdev, "notify/0 --> %d\n", status);
++      }
++}
++
++static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct f_rndis                  *rndis = req->context;
++      struct usb_composite_dev        *cdev = rndis->port.func.config->cdev;
++      int                             status = req->status;
++
++      /* after TX:
++       *  - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
++       *  - RNDIS_RESPONSE_AVAILABLE (status/irq)
++       */
++      switch (status) {
++      case -ECONNRESET:
++      case -ESHUTDOWN:
++              /* connection gone */
++              atomic_set(&rndis->notify_count, 0);
++              break;
++      default:
++              DBG(cdev, "RNDIS %s response error %d, %d/%d\n",
++                      ep->name, status,
++                      req->actual, req->length);
++              /* FALLTHROUGH */
++      case 0:
++              if (ep != rndis->notify)
++                      break;
++
++              /* handle multiple pending RNDIS_RESPONSE_AVAILABLE
++               * notifications by resending until we're done
++               */
++              if (atomic_dec_and_test(&rndis->notify_count))
++                      break;
++              status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
++              if (status) {
++                      atomic_dec(&rndis->notify_count);
++                      DBG(cdev, "notify/1 --> %d\n", status);
++              }
++              break;
++      }
++}
++
++static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct f_rndis                  *rndis = req->context;
++      struct usb_composite_dev        *cdev = rndis->port.func.config->cdev;
++      int                             status;
++
++      /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
++//    spin_lock(&dev->lock);
++      status = rndis_msg_parser(rndis->config, (u8 *) req->buf);
++      if (status < 0)
++              ERROR(cdev, "RNDIS command error %d, %d/%d\n",
++                      status, req->actual, req->length);
++//    spin_unlock(&dev->lock);
++}
++
++static int
++rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
++{
++      struct f_rndis          *rndis = func_to_rndis(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++      struct usb_request      *req = cdev->req;
++      int                     value = -EOPNOTSUPP;
++      u16                     w_index = le16_to_cpu(ctrl->wIndex);
++      u16                     w_value = le16_to_cpu(ctrl->wValue);
++      u16                     w_length = le16_to_cpu(ctrl->wLength);
++
++      /* composite driver infrastructure handles everything except
++       * CDC class messages; interface activation uses set_alt().
++       */
++      switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
++
++      /* RNDIS uses the CDC command encapsulation mechanism to implement
++       * an RPC scheme, with much getting/setting of attributes by OID.
++       */
++      case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
++                      | USB_CDC_SEND_ENCAPSULATED_COMMAND:
++              if (w_length > req->length || w_value
++                              || w_index != rndis->ctrl_id)
++                      goto invalid;
++              /* read the request; process it later */
++              value = w_length;
++              req->complete = rndis_command_complete;
++              req->context = rndis;
++              /* later, rndis_response_available() sends a notification */
++              break;
++
++      case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
++                      | USB_CDC_GET_ENCAPSULATED_RESPONSE:
++              if (w_value || w_index != rndis->ctrl_id)
++                      goto invalid;
++              else {
++                      u8 *buf;
++                      u32 n;
++
++                      /* return the result */
++                      buf = rndis_get_next_response(rndis->config, &n);
++                      if (buf) {
++                              memcpy(req->buf, buf, n);
++                              req->complete = rndis_response_complete;
++                              rndis_free_response(rndis->config, buf);
++                              value = n;
++                      }
++                      /* else stalls ... spec says to avoid that */
++              }
++              break;
++
++      default:
++invalid:
++              VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
++                      ctrl->bRequestType, ctrl->bRequest,
++                      w_value, w_index, w_length);
++      }
++
++      /* respond with data transfer or status phase? */
++      if (value >= 0) {
++              DBG(cdev, "rndis req%02x.%02x v%04x i%04x l%d\n",
++                      ctrl->bRequestType, ctrl->bRequest,
++                      w_value, w_index, w_length);
++              req->zero = 0;
++              req->length = value;
++              value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
++              if (value < 0)
++                      ERROR(cdev, "rndis response on err %d\n", value);
++      }
++
++      /* device either stalls (value < 0) or reports success */
++      return value;
++}
++
++
++static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
++{
++      struct f_rndis          *rndis = func_to_rndis(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      /* we know alt == 0 */
++
++      if (intf == rndis->ctrl_id) {
++              if (rndis->notify->driver_data) {
++                      VDBG(cdev, "reset rndis control %d\n", intf);
++                      usb_ep_disable(rndis->notify);
++              } else {
++                      VDBG(cdev, "init rndis ctrl %d\n", intf);
++                      rndis->notify_desc = ep_choose(cdev->gadget,
++                                      rndis->hs.notify,
++                                      rndis->fs.notify);
++              }
++              usb_ep_enable(rndis->notify, rndis->notify_desc);
++              rndis->notify->driver_data = rndis;
++
++      } else if (intf == rndis->data_id) {
++              struct net_device       *net;
++
++              if (rndis->port.in_ep->driver_data) {
++                      DBG(cdev, "reset rndis\n");
++                      gether_disconnect(&rndis->port);
++              } else {
++                      DBG(cdev, "init rndis\n");
++                      rndis->port.in = ep_choose(cdev->gadget,
++                                      rndis->hs.in, rndis->fs.in);
++                      rndis->port.out = ep_choose(cdev->gadget,
++                                      rndis->hs.out, rndis->fs.out);
++              }
++
++              /* Avoid ZLPs; they can be troublesome. */
++              rndis->port.is_zlp_ok = false;
++
++              /* RNDIS should be in the "RNDIS uninitialized" state,
++               * either never activated or after rndis_uninit().
++               *
++               * We don't want data to flow here until a nonzero packet
++               * filter is set, at which point it enters "RNDIS data
++               * initialized" state ... but we do want the endpoints
++               * to be activated.  It's a strange little state.
++               *
++               * REVISIT the RNDIS gadget code has done this wrong for a
++               * very long time.  We need another call to the link layer
++               * code -- gether_updown(...bool) maybe -- to do it right.
++               */
++              rndis->port.cdc_filter = 0;
++
++              DBG(cdev, "RNDIS RX/TX early activation ... \n");
++              net = gether_connect(&rndis->port);
++              if (IS_ERR(net))
++                      return PTR_ERR(net);
++
++              rndis_set_param_dev(rndis->config, net,
++                              &rndis->port.cdc_filter);
++      } else
++              goto fail;
++
++      return 0;
++fail:
++      return -EINVAL;
++}
++
++static void rndis_disable(struct usb_function *f)
++{
++      struct f_rndis          *rndis = func_to_rndis(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      if (!rndis->notify->driver_data)
++              return;
++
++      DBG(cdev, "rndis deactivated\n");
++
++      rndis_uninit(rndis->config);
++      gether_disconnect(&rndis->port);
++
++      usb_ep_disable(rndis->notify);
++      rndis->notify->driver_data = NULL;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * This isn't quite the same mechanism as CDC Ethernet, since the
++ * notification scheme passes less data, but the same set of link
++ * states must be tested.  A key difference is that altsettings are
++ * not used to tell whether the link should send packets or not.
++ */
++
++static void rndis_open(struct gether *geth)
++{
++      struct f_rndis          *rndis = func_to_rndis(&geth->func);
++      struct usb_composite_dev *cdev = geth->func.config->cdev;
++
++      DBG(cdev, "%s\n", __func__);
++
++      rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3,
++                              bitrate(cdev->gadget) / 100);
++      rndis_signal_connect(rndis->config);
++}
++
++static void rndis_close(struct gether *geth)
++{
++      struct f_rndis          *rndis = func_to_rndis(&geth->func);
++
++      DBG(geth->func.config->cdev, "%s\n", __func__);
++
++      rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0);
++      rndis_signal_disconnect(rndis->config);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* ethernet function driver setup/binding */
++
++static int __init
++rndis_bind(struct usb_configuration *c, struct usb_function *f)
++{
++      struct usb_composite_dev *cdev = c->cdev;
++      struct f_rndis          *rndis = func_to_rndis(f);
++      int                     status;
++      struct usb_ep           *ep;
++
++      /* allocate instance-specific interface IDs */
++      status = usb_interface_id(c, f);
++      if (status < 0)
++              goto fail;
++      rndis->ctrl_id = status;
++
++      rndis_control_intf.bInterfaceNumber = status;
++      rndis_union_desc.bMasterInterface0 = status;
++
++      status = usb_interface_id(c, f);
++      if (status < 0)
++              goto fail;
++      rndis->data_id = status;
++
++      rndis_data_intf.bInterfaceNumber = status;
++      rndis_union_desc.bSlaveInterface0 = status;
++
++      status = -ENODEV;
++
++      /* allocate instance-specific endpoints */
++      ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc);
++      if (!ep)
++              goto fail;
++      rndis->port.in_ep = ep;
++      ep->driver_data = cdev; /* claim */
++
++      ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc);
++      if (!ep)
++              goto fail;
++      rndis->port.out_ep = ep;
++      ep->driver_data = cdev; /* claim */
++
++      /* NOTE:  a status/notification endpoint is, strictly speaking,
++       * optional.  We don't treat it that way though!  It's simpler,
++       * and some newer profiles don't treat it as optional.
++       */
++      ep = usb_ep_autoconfig(cdev->gadget, &fs_notify_desc);
++      if (!ep)
++              goto fail;
++      rndis->notify = ep;
++      ep->driver_data = cdev; /* claim */
++
++      status = -ENOMEM;
++
++      /* allocate notification request and buffer */
++      rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
++      if (!rndis->notify_req)
++              goto fail;
++      rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
++      if (!rndis->notify_req->buf)
++              goto fail;
++      rndis->notify_req->length = STATUS_BYTECOUNT;
++      rndis->notify_req->context = rndis;
++      rndis->notify_req->complete = rndis_response_complete;
++
++      /* copy descriptors, and track endpoint copies */
++      f->descriptors = usb_copy_descriptors(eth_fs_function);
++      if (!f->descriptors)
++              goto fail;
++
++      rndis->fs.in = usb_find_endpoint(eth_fs_function,
++                      f->descriptors, &fs_in_desc);
++      rndis->fs.out = usb_find_endpoint(eth_fs_function,
++                      f->descriptors, &fs_out_desc);
++      rndis->fs.notify = usb_find_endpoint(eth_fs_function,
++                      f->descriptors, &fs_notify_desc);
++
++      /* support all relevant hardware speeds... we expect that when
++       * hardware is dual speed, all bulk-capable endpoints work at
++       * both speeds
++       */
++      if (gadget_is_dualspeed(c->cdev->gadget)) {
++              hs_in_desc.bEndpointAddress =
++                              fs_in_desc.bEndpointAddress;
++              hs_out_desc.bEndpointAddress =
++                              fs_out_desc.bEndpointAddress;
++
++              /* copy descriptors, and track endpoint copies */
++              f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
++
++              if (!f->hs_descriptors)
++                      goto fail;
++
++              rndis->hs.in = usb_find_endpoint(eth_hs_function,
++                              f->hs_descriptors, &hs_in_desc);
++              rndis->hs.out = usb_find_endpoint(eth_hs_function,
++                              f->hs_descriptors, &hs_out_desc);
++      }
++
++      rndis->port.open = rndis_open;
++      rndis->port.close = rndis_close;
++
++      status = rndis_register(rndis_response_available, rndis);
++      if (status < 0)
++              goto fail;
++      rndis->config = status;
++
++      rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0);
++      rndis_set_host_mac(rndis->config, rndis->ethaddr);
++
++#if 0
++// FIXME
++      if (rndis_set_param_vendor(rndis->config, vendorID,
++                              manufacturer))
++              goto fail0;
++#endif
++
++      /* NOTE:  all that is done without knowing or caring about
++       * the network link ... which is unavailable to this code
++       * until we're activated via set_alt().
++       */
++
++      DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
++                      gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++                      rndis->port.in_ep->name, rndis->port.out_ep->name,
++                      rndis->notify->name);
++      return 0;
++
++fail:
++      if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
++              usb_free_descriptors(f->hs_descriptors);
++      if (f->descriptors)
++              usb_free_descriptors(f->descriptors);
++
++      if (rndis->notify_req) {
++              kfree(rndis->notify_req->buf);
++              usb_ep_free_request(rndis->notify, rndis->notify_req);
++      }
++
++      /* we might as well release our claims on endpoints */
++      if (rndis->notify)
++              rndis->notify->driver_data = NULL;
++      if (rndis->port.out)
++              rndis->port.out_ep->driver_data = NULL;
++      if (rndis->port.in)
++              rndis->port.in_ep->driver_data = NULL;
++
++      ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
++
++      return status;
++}
++
++static void
++rndis_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++      struct f_rndis          *rndis = func_to_rndis(f);
++
++      rndis_deregister(rndis->config);
++      rndis_exit();
++
++      if (gadget_is_dualspeed(c->cdev->gadget))
++              usb_free_descriptors(f->hs_descriptors);
++      usb_free_descriptors(f->descriptors);
++
++      kfree(rndis->notify_req->buf);
++      usb_ep_free_request(rndis->notify, rndis->notify_req);
++
++      kfree(rndis);
++}
++
++/* Some controllers can't support RNDIS ... */
++static inline bool can_support_rndis(struct usb_configuration *c)
++{
++      /* only two endpoints on sa1100 */
++      if (gadget_is_sa1100(c->cdev->gadget))
++              return false;
++
++      /* everything else is *presumably* fine */
++      return true;
++}
++
++/**
++ * rndis_bind_config - add RNDIS network link to a configuration
++ * @c: the configuration to support the network link
++ * @ethaddr: a buffer in which the ethernet address of the host side
++ *    side of the link was recorded
++ * Context: single threaded during gadget setup
++ *
++ * Returns zero on success, else negative errno.
++ *
++ * Caller must have called @gether_setup().  Caller is also responsible
++ * for calling @gether_cleanup() before module unload.
++ */
++int __init rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
++{
++      struct f_rndis  *rndis;
++      int             status;
++
++      if (!can_support_rndis(c) || !ethaddr)
++              return -EINVAL;
++
++      /* maybe allocate device-global string IDs */
++      if (rndis_string_defs[0].id == 0) {
++
++              /* ... and setup RNDIS itself */
++              status = rndis_init();
++              if (status < 0)
++                      return status;
++
++              /* control interface label */
++              status = usb_string_id(c->cdev);
++              if (status < 0)
++                      return status;
++              rndis_string_defs[0].id = status;
++              rndis_control_intf.iInterface = status;
++
++              /* data interface label */
++              status = usb_string_id(c->cdev);
++              if (status < 0)
++                      return status;
++              rndis_string_defs[1].id = status;
++              rndis_data_intf.iInterface = status;
++      }
++
++      /* allocate and initialize one new instance */
++      status = -ENOMEM;
++      rndis = kzalloc(sizeof *rndis, GFP_KERNEL);
++      if (!rndis)
++              goto fail;
++
++      memcpy(rndis->ethaddr, ethaddr, ETH_ALEN);
++
++      /* RNDIS activates when the host changes this filter */
++      rndis->port.cdc_filter = 0;
++
++      /* RNDIS has special (and complex) framing */
++      rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
++      rndis->port.wrap = rndis_add_header;
++      rndis->port.unwrap = rndis_rm_hdr;
++
++      rndis->port.func.name = "rndis";
++      rndis->port.func.strings = rndis_strings;
++      /* descriptors are per-instance copies */
++      rndis->port.func.bind = rndis_bind;
++      rndis->port.func.unbind = rndis_unbind;
++      rndis->port.func.set_alt = rndis_set_alt;
++      rndis->port.func.setup = rndis_setup;
++      rndis->port.func.disable = rndis_disable;
++
++      status = usb_add_function(c, &rndis->port.func);
++      if (status) {
++              kfree(rndis);
++fail:
++              rndis_exit();
++      }
++      return status;
++}
+diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
+new file mode 100644
+index 0000000..fe5674d
+--- /dev/null
++++ b/drivers/usb/gadget/f_serial.c
+@@ -0,0 +1,294 @@
++/*
++ * f_serial.c - generic USB serial function driver
++ *
++ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
++ * Copyright (C) 2008 by David Brownell
++ * Copyright (C) 2008 by Nokia Corporation
++ *
++ * This software is distributed under the terms of the GNU General
++ * Public License ("GPL") as published by the Free Software Foundation,
++ * either version 2 of that License or (at your option) any later version.
++ */
++
++#include <linux/kernel.h>
++#include <linux/device.h>
++
++#include "u_serial.h"
++#include "gadget_chips.h"
++
++
++/*
++ * This function packages a simple "generic serial" port with no real
++ * control mechanisms, just raw data transfer over two bulk endpoints.
++ *
++ * Because it's not standardized, this isn't as interoperable as the
++ * CDC ACM driver.  However, for many purposes it's just as functional
++ * if you can arrange appropriate host side drivers.
++ */
++
++struct gser_descs {
++      struct usb_endpoint_descriptor  *in;
++      struct usb_endpoint_descriptor  *out;
++};
++
++struct f_gser {
++      struct gserial                  port;
++      u8                              data_id;
++      u8                              port_num;
++
++      struct gser_descs               fs;
++      struct gser_descs               hs;
++};
++
++static inline struct f_gser *func_to_gser(struct usb_function *f)
++{
++      return container_of(f, struct f_gser, port.func);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* interface descriptor: */
++
++static struct usb_interface_descriptor gser_interface_desc __initdata = {
++      .bLength =              USB_DT_INTERFACE_SIZE,
++      .bDescriptorType =      USB_DT_INTERFACE,
++      /* .bInterfaceNumber = DYNAMIC */
++      .bNumEndpoints =        2,
++      .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
++      .bInterfaceSubClass =   0,
++      .bInterfaceProtocol =   0,
++      /* .iInterface = DYNAMIC */
++};
++
++/* full speed support: */
++
++static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++      .bEndpointAddress =     USB_DIR_OUT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_descriptor_header *gser_fs_function[] __initdata = {
++      (struct usb_descriptor_header *) &gser_interface_desc,
++      (struct usb_descriptor_header *) &gser_fs_in_desc,
++      (struct usb_descriptor_header *) &gser_fs_out_desc,
++      NULL,
++};
++
++/* high speed support: */
++
++static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_descriptor_header *gser_hs_function[] __initdata = {
++      (struct usb_descriptor_header *) &gser_interface_desc,
++      (struct usb_descriptor_header *) &gser_hs_in_desc,
++      (struct usb_descriptor_header *) &gser_hs_out_desc,
++      NULL,
++};
++
++/* string descriptors: */
++
++static struct usb_string gser_string_defs[] = {
++      [0].s = "Generic Serial",
++      {  } /* end of list */
++};
++
++static struct usb_gadget_strings gser_string_table = {
++      .language =             0x0409, /* en-us */
++      .strings =              gser_string_defs,
++};
++
++static struct usb_gadget_strings *gser_strings[] = {
++      &gser_string_table,
++      NULL,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
++{
++      struct f_gser           *gser = func_to_gser(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      /* we know alt == 0, so this is an activation or a reset */
++
++      if (gser->port.in->driver_data) {
++              DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);
++              gserial_disconnect(&gser->port);
++      } else {
++              DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
++              gser->port.in_desc = ep_choose(cdev->gadget,
++                              gser->hs.in, gser->fs.in);
++              gser->port.out_desc = ep_choose(cdev->gadget,
++                              gser->hs.out, gser->fs.out);
++      }
++      gserial_connect(&gser->port, gser->port_num);
++      return 0;
++}
++
++static void gser_disable(struct usb_function *f)
++{
++      struct f_gser   *gser = func_to_gser(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      DBG(cdev, "generic ttyGS%d deactivated\n", gser->port_num);
++      gserial_disconnect(&gser->port);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* serial function driver setup/binding */
++
++static int __init
++gser_bind(struct usb_configuration *c, struct usb_function *f)
++{
++      struct usb_composite_dev *cdev = c->cdev;
++      struct f_gser           *gser = func_to_gser(f);
++      int                     status;
++      struct usb_ep           *ep;
++
++      /* allocate instance-specific interface IDs */
++      status = usb_interface_id(c, f);
++      if (status < 0)
++              goto fail;
++      gser->data_id = status;
++      gser_interface_desc.bInterfaceNumber = status;
++
++      status = -ENODEV;
++
++      /* allocate instance-specific endpoints */
++      ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc);
++      if (!ep)
++              goto fail;
++      gser->port.in = ep;
++      ep->driver_data = cdev; /* claim */
++
++      ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
++      if (!ep)
++              goto fail;
++      gser->port.out = ep;
++      ep->driver_data = cdev; /* claim */
++
++      /* copy descriptors, and track endpoint copies */
++      f->descriptors = usb_copy_descriptors(gser_fs_function);
++
++      gser->fs.in = usb_find_endpoint(gser_fs_function,
++                      f->descriptors, &gser_fs_in_desc);
++      gser->fs.out = usb_find_endpoint(gser_fs_function,
++                      f->descriptors, &gser_fs_out_desc);
++
++
++      /* support all relevant hardware speeds... we expect that when
++       * hardware is dual speed, all bulk-capable endpoints work at
++       * both speeds
++       */
++      if (gadget_is_dualspeed(c->cdev->gadget)) {
++              gser_hs_in_desc.bEndpointAddress =
++                              gser_fs_in_desc.bEndpointAddress;
++              gser_hs_out_desc.bEndpointAddress =
++                              gser_fs_out_desc.bEndpointAddress;
++
++              /* copy descriptors, and track endpoint copies */
++              f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
++
++              gser->hs.in = usb_find_endpoint(gser_hs_function,
++                              f->hs_descriptors, &gser_hs_in_desc);
++              gser->hs.out = usb_find_endpoint(gser_hs_function,
++                              f->hs_descriptors, &gser_hs_out_desc);
++      }
++
++      DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
++                      gser->port_num,
++                      gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++                      gser->port.in->name, gser->port.out->name);
++      return 0;
++
++fail:
++      /* we might as well release our claims on endpoints */
++      if (gser->port.out)
++              gser->port.out->driver_data = NULL;
++      if (gser->port.in)
++              gser->port.in->driver_data = NULL;
++
++      ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
++
++      return status;
++}
++
++static void
++gser_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++      if (gadget_is_dualspeed(c->cdev->gadget))
++              usb_free_descriptors(f->hs_descriptors);
++      usb_free_descriptors(f->descriptors);
++      kfree(func_to_gser(f));
++}
++
++/**
++ * gser_bind_config - add a generic serial function to a configuration
++ * @c: the configuration to support the serial instance
++ * @port_num: /dev/ttyGS* port this interface will use
++ * Context: single threaded during gadget setup
++ *
++ * Returns zero on success, else negative errno.
++ *
++ * Caller must have called @gserial_setup() with enough ports to
++ * handle all the ones it binds.  Caller is also responsible
++ * for calling @gserial_cleanup() before module unload.
++ */
++int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
++{
++      struct f_gser   *gser;
++      int             status;
++
++      /* REVISIT might want instance-specific strings to help
++       * distinguish instances ...
++       */
++
++      /* maybe allocate device-global string ID */
++      if (gser_string_defs[0].id == 0) {
++              status = usb_string_id(c->cdev);
++              if (status < 0)
++                      return status;
++              gser_string_defs[0].id = status;
++      }
++
++      /* allocate and initialize one new instance */
++      gser = kzalloc(sizeof *gser, GFP_KERNEL);
++      if (!gser)
++              return -ENOMEM;
++
++      gser->port_num = port_num;
++
++      gser->port.func.name = "gser";
++      gser->port.func.strings = gser_strings;
++      gser->port.func.bind = gser_bind;
++      gser->port.func.unbind = gser_unbind;
++      gser->port.func.set_alt = gser_set_alt;
++      gser->port.func.disable = gser_disable;
++
++      status = usb_add_function(c, &gser->port.func);
++      if (status)
++              kfree(gser);
++      return status;
++}
+diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
+new file mode 100644
+index 0000000..f18c3a1
+--- /dev/null
++++ b/drivers/usb/gadget/f_sourcesink.c
+@@ -0,0 +1,587 @@
++/*
++ * f_sourcesink.c - USB peripheral source/sink configuration driver
++ *
++ * Copyright (C) 2003-2008 David Brownell
++ * Copyright (C) 2008 by Nokia Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kernel.h>
++#include <linux/utsname.h>
++#include <linux/device.h>
++
++#include "g_zero.h"
++#include "gadget_chips.h"
++
++
++/*
++ * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral
++ * controller drivers.
++ *
++ * This just sinks bulk packets OUT to the peripheral and sources them IN
++ * to the host, optionally with specific data patterns for integrity tests.
++ * As such it supports basic functionality and load tests.
++ *
++ * In terms of control messaging, this supports all the standard requests
++ * plus two that support control-OUT tests.  If the optional "autoresume"
++ * mode is enabled, it provides good functional coverage for the "USBCV"
++ * test harness from USB-IF.
++ *
++ * Note that because this doesn't queue more than one request at a time,
++ * some other function must be used to test queueing logic.  The network
++ * link (g_ether) is the best overall option for that, since its TX and RX
++ * queues are relatively independent, will receive a range of packet sizes,
++ * and can often be made to run out completely.  Those issues are important
++ * when stress testing peripheral controller drivers.
++ *
++ *
++ * This is currently packaged as a configuration driver, which can't be
++ * combined with other functions to make composite devices.  However, it
++ * can be combined with other independent configurations.
++ */
++struct f_sourcesink {
++      struct usb_function     function;
++
++      struct usb_ep           *in_ep;
++      struct usb_ep           *out_ep;
++      struct timer_list       resume;
++};
++
++static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
++{
++      return container_of(f, struct f_sourcesink, function);
++}
++
++static unsigned autoresume;
++module_param(autoresume, uint, 0);
++MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");
++
++static unsigned pattern;
++module_param(pattern, uint, 0);
++MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63 ");
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_interface_descriptor source_sink_intf = {
++      .bLength =              sizeof source_sink_intf,
++      .bDescriptorType =      USB_DT_INTERFACE,
++
++      .bNumEndpoints =        2,
++      .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
++      /* .iInterface = DYNAMIC */
++};
++
++/* full speed support: */
++
++static struct usb_endpoint_descriptor fs_source_desc = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor fs_sink_desc = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_OUT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_descriptor_header *fs_source_sink_descs[] = {
++      (struct usb_descriptor_header *) &source_sink_intf,
++      (struct usb_descriptor_header *) &fs_sink_desc,
++      (struct usb_descriptor_header *) &fs_source_desc,
++      NULL,
++};
++
++/* high speed support: */
++
++static struct usb_endpoint_descriptor hs_source_desc = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor hs_sink_desc = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_descriptor_header *hs_source_sink_descs[] = {
++      (struct usb_descriptor_header *) &source_sink_intf,
++      (struct usb_descriptor_header *) &hs_source_desc,
++      (struct usb_descriptor_header *) &hs_sink_desc,
++      NULL,
++};
++
++/* function-specific strings: */
++
++static struct usb_string strings_sourcesink[] = {
++      [0].s = "source and sink data",
++      {  }                    /* end of list */
++};
++
++static struct usb_gadget_strings stringtab_sourcesink = {
++      .language       = 0x0409,       /* en-us */
++      .strings        = strings_sourcesink,
++};
++
++static struct usb_gadget_strings *sourcesink_strings[] = {
++      &stringtab_sourcesink,
++      NULL,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static void sourcesink_autoresume(unsigned long _c)
++{
++      struct usb_composite_dev *cdev = (void *)_c;
++      struct usb_gadget       *g = cdev->gadget;
++
++      /* Normally the host would be woken up for something
++       * more significant than just a timer firing; likely
++       * because of some direct user request.
++       */
++      if (g->speed != USB_SPEED_UNKNOWN) {
++              int status = usb_gadget_wakeup(g);
++              DBG(cdev, "%s --> %d\n", __func__, status);
++      }
++}
++
++static int __init
++sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
++{
++      struct usb_composite_dev *cdev = c->cdev;
++      struct f_sourcesink     *ss = func_to_ss(f);
++      int     id;
++
++      /* allocate interface ID(s) */
++      id = usb_interface_id(c, f);
++      if (id < 0)
++              return id;
++      source_sink_intf.bInterfaceNumber = id;
++
++      /* allocate endpoints */
++      ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
++      if (!ss->in_ep) {
++autoconf_fail:
++              ERROR(cdev, "%s: can't autoconfigure on %s\n",
++                      f->name, cdev->gadget->name);
++              return -ENODEV;
++      }
++      ss->in_ep->driver_data = cdev;  /* claim */
++
++      ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
++      if (!ss->out_ep)
++              goto autoconf_fail;
++      ss->out_ep->driver_data = cdev; /* claim */
++
++      setup_timer(&ss->resume, sourcesink_autoresume,
++                      (unsigned long) c->cdev);
++
++      /* support high speed hardware */
++      if (gadget_is_dualspeed(c->cdev->gadget)) {
++              hs_source_desc.bEndpointAddress =
++                              fs_source_desc.bEndpointAddress;
++              hs_sink_desc.bEndpointAddress =
++                              fs_sink_desc.bEndpointAddress;
++              f->hs_descriptors = hs_source_sink_descs;
++      }
++
++      DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
++                      gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++                      f->name, ss->in_ep->name, ss->out_ep->name);
++      return 0;
++}
++
++static void
++sourcesink_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++      kfree(func_to_ss(f));
++}
++
++/* optionally require specific source/sink data patterns  */
++static int check_read_data(struct f_sourcesink *ss, struct usb_request *req)
++{
++      unsigned                i;
++      u8                      *buf = req->buf;
++      struct usb_composite_dev *cdev = ss->function.config->cdev;
++
++      for (i = 0; i < req->actual; i++, buf++) {
++              switch (pattern) {
++
++              /* all-zeroes has no synchronization issues */
++              case 0:
++                      if (*buf == 0)
++                              continue;
++                      break;
++
++              /* "mod63" stays in sync with short-terminated transfers,
++               * OR otherwise when host and gadget agree on how large
++               * each usb transfer request should be.  Resync is done
++               * with set_interface or set_config.  (We *WANT* it to
++               * get quickly out of sync if controllers or their drivers
++               * stutter for any reason, including buffer duplcation...)
++               */
++              case 1:
++                      if (*buf == (u8)(i % 63))
++                              continue;
++                      break;
++              }
++              ERROR(cdev, "bad OUT byte, buf[%d] = %d\n", i, *buf);
++              usb_ep_set_halt(ss->out_ep);
++              return -EINVAL;
++      }
++      return 0;
++}
++
++static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
++{
++      unsigned        i;
++      u8              *buf = req->buf;
++
++      switch (pattern) {
++      case 0:
++              memset(req->buf, 0, req->length);
++              break;
++      case 1:
++              for  (i = 0; i < req->length; i++)
++                      *buf++ = (u8) (i % 63);
++              break;
++      }
++}
++
++static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct f_sourcesink     *ss = ep->driver_data;
++      struct usb_composite_dev *cdev = ss->function.config->cdev;
++      int                     status = req->status;
++
++      switch (status) {
++
++      case 0:                         /* normal completion? */
++              if (ep == ss->out_ep) {
++                      check_read_data(ss, req);
++                      memset(req->buf, 0x55, req->length);
++              } else
++                      reinit_write_data(ep, req);
++              break;
++
++      /* this endpoint is normally active while we're configured */
++      case -ECONNABORTED:             /* hardware forced ep reset */
++      case -ECONNRESET:               /* request dequeued */
++      case -ESHUTDOWN:                /* disconnect from host */
++              VDBG(cdev, "%s gone (%d), %d/%d\n", ep->name, status,
++                              req->actual, req->length);
++              if (ep == ss->out_ep)
++                      check_read_data(ss, req);
++              free_ep_req(ep, req);
++              return;
++
++      case -EOVERFLOW:                /* buffer overrun on read means that
++                                       * we didn't provide a big enough
++                                       * buffer.
++                                       */
++      default:
++#if 1
++              DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name,
++                              status, req->actual, req->length);
++#endif
++      case -EREMOTEIO:                /* short read */
++              break;
++      }
++
++      status = usb_ep_queue(ep, req, GFP_ATOMIC);
++      if (status) {
++              ERROR(cdev, "kill %s:  resubmit %d bytes --> %d\n",
++                              ep->name, req->length, status);
++              usb_ep_set_halt(ep);
++              /* FIXME recover later ... somehow */
++      }
++}
++
++static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in)
++{
++      struct usb_ep           *ep;
++      struct usb_request      *req;
++      int                     status;
++
++      ep = is_in ? ss->in_ep : ss->out_ep;
++      req = alloc_ep_req(ep);
++      if (!req)
++              return -ENOMEM;
++
++      req->complete = source_sink_complete;
++      if (is_in)
++              reinit_write_data(ep, req);
++      else
++              memset(req->buf, 0x55, req->length);
++
++      status = usb_ep_queue(ep, req, GFP_ATOMIC);
++      if (status) {
++              struct usb_composite_dev        *cdev;
++
++              cdev = ss->function.config->cdev;
++              ERROR(cdev, "start %s %s --> %d\n",
++                              is_in ? "IN" : "OUT",
++                              ep->name, status);
++              free_ep_req(ep, req);
++      }
++
++      return status;
++}
++
++static void disable_source_sink(struct f_sourcesink *ss)
++{
++      struct usb_composite_dev        *cdev;
++
++      cdev = ss->function.config->cdev;
++      disable_endpoints(cdev, ss->in_ep, ss->out_ep);
++      del_timer(&ss->resume);
++      VDBG(cdev, "%s disabled\n", ss->function.name);
++}
++
++static int
++enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
++{
++      int                                     result = 0;
++      const struct usb_endpoint_descriptor    *src, *sink;
++      struct usb_ep                           *ep;
++
++      src = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
++      sink = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
++
++      /* one endpoint writes (sources) zeroes IN (to the host) */
++      ep = ss->in_ep;
++      result = usb_ep_enable(ep, src);
++      if (result < 0)
++              return result;
++      ep->driver_data = ss;
++
++      result = source_sink_start_ep(ss, true);
++      if (result < 0) {
++fail:
++              ep = ss->in_ep;
++              usb_ep_disable(ep);
++              ep->driver_data = NULL;
++              return result;
++      }
++
++      /* one endpoint reads (sinks) anything OUT (from the host) */
++      ep = ss->out_ep;
++      result = usb_ep_enable(ep, sink);
++      if (result < 0)
++              goto fail;
++      ep->driver_data = ss;
++
++      result = source_sink_start_ep(ss, false);
++      if (result < 0) {
++              usb_ep_disable(ep);
++              ep->driver_data = NULL;
++              goto fail;
++      }
++
++      DBG(cdev, "%s enabled\n", ss->function.name);
++      return result;
++}
++
++static int sourcesink_set_alt(struct usb_function *f,
++              unsigned intf, unsigned alt)
++{
++      struct f_sourcesink     *ss = func_to_ss(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      /* we know alt is zero */
++      if (ss->in_ep->driver_data)
++              disable_source_sink(ss);
++      return enable_source_sink(cdev, ss);
++}
++
++static void sourcesink_disable(struct usb_function *f)
++{
++      struct f_sourcesink     *ss = func_to_ss(f);
++
++      disable_source_sink(ss);
++}
++
++static void sourcesink_suspend(struct usb_function *f)
++{
++      struct f_sourcesink     *ss = func_to_ss(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      if (cdev->gadget->speed == USB_SPEED_UNKNOWN)
++              return;
++
++      if (autoresume) {
++              mod_timer(&ss->resume, jiffies + (HZ * autoresume));
++              DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume);
++      } else
++              DBG(cdev, "%s\n", __func__);
++}
++
++static void sourcesink_resume(struct usb_function *f)
++{
++      struct f_sourcesink     *ss = func_to_ss(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      DBG(cdev, "%s\n", __func__);
++      del_timer(&ss->resume);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int __init sourcesink_bind_config(struct usb_configuration *c)
++{
++      struct f_sourcesink     *ss;
++      int                     status;
++
++      ss = kzalloc(sizeof *ss, GFP_KERNEL);
++      if (!ss)
++              return -ENOMEM;
++
++      ss->function.name = "source/sink";
++      ss->function.descriptors = fs_source_sink_descs;
++      ss->function.bind = sourcesink_bind;
++      ss->function.unbind = sourcesink_unbind;
++      ss->function.set_alt = sourcesink_set_alt;
++      ss->function.disable = sourcesink_disable;
++      ss->function.suspend = sourcesink_suspend;
++      ss->function.resume = sourcesink_resume;
++
++      status = usb_add_function(c, &ss->function);
++      if (status)
++              kfree(ss);
++      return status;
++}
++
++static int sourcesink_setup(struct usb_configuration *c,
++              const struct usb_ctrlrequest *ctrl)
++{
++      struct usb_request      *req = c->cdev->req;
++      int                     value = -EOPNOTSUPP;
++      u16                     w_index = le16_to_cpu(ctrl->wIndex);
++      u16                     w_value = le16_to_cpu(ctrl->wValue);
++      u16                     w_length = le16_to_cpu(ctrl->wLength);
++
++      /* composite driver infrastructure handles everything except
++       * the two control test requests.
++       */
++      switch (ctrl->bRequest) {
++
++      /*
++       * These are the same vendor-specific requests supported by
++       * Intel's USB 2.0 compliance test devices.  We exceed that
++       * device spec by allowing multiple-packet requests.
++       *
++       * NOTE:  the Control-OUT data stays in req->buf ... better
++       * would be copying it into a scratch buffer, so that other
++       * requests may safely intervene.
++       */
++      case 0x5b:      /* control WRITE test -- fill the buffer */
++              if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
++                      goto unknown;
++              if (w_value || w_index)
++                      break;
++              /* just read that many bytes into the buffer */
++              if (w_length > req->length)
++                      break;
++              value = w_length;
++              break;
++      case 0x5c:      /* control READ test -- return the buffer */
++              if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
++                      goto unknown;
++              if (w_value || w_index)
++                      break;
++              /* expect those bytes are still in the buffer; send back */
++              if (w_length > req->length)
++                      break;
++              value = w_length;
++              break;
++
++      default:
++unknown:
++              VDBG(c->cdev,
++                      "unknown control req%02x.%02x v%04x i%04x l%d\n",
++                      ctrl->bRequestType, ctrl->bRequest,
++                      w_value, w_index, w_length);
++      }
++
++      /* respond with data transfer or status phase? */
++      if (value >= 0) {
++              VDBG(c->cdev, "source/sink req%02x.%02x v%04x i%04x l%d\n",
++                      ctrl->bRequestType, ctrl->bRequest,
++                      w_value, w_index, w_length);
++              req->zero = 0;
++              req->length = value;
++              value = usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC);
++              if (value < 0)
++                      ERROR(c->cdev, "source/sinkc response, err %d\n",
++                                      value);
++      }
++
++      /* device either stalls (value < 0) or reports success */
++      return value;
++}
++
++static struct usb_configuration sourcesink_driver = {
++      .label          = "source/sink",
++      .strings        = sourcesink_strings,
++      .bind           = sourcesink_bind_config,
++      .setup          = sourcesink_setup,
++      .bConfigurationValue = 3,
++      .bmAttributes   = USB_CONFIG_ATT_SELFPOWER,
++      .bMaxPower      = 1,    /* 2 mA, minimal */
++      /* .iConfiguration = DYNAMIC */
++};
++
++/**
++ * sourcesink_add - add a source/sink testing configuration to a device
++ * @cdev: the device to support the configuration
++ */
++int __init sourcesink_add(struct usb_composite_dev *cdev)
++{
++      int id;
++
++      /* allocate string ID(s) */
++      id = usb_string_id(cdev);
++      if (id < 0)
++              return id;
++      strings_sourcesink[0].id = id;
++
++      source_sink_intf.iInterface = id;
++      sourcesink_driver.iConfiguration = id;
++
++      /* support autoresume for remote wakeup testing */
++      if (autoresume)
++              sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++
++      /* support OTG systems */
++      if (gadget_is_otg(cdev->gadget)) {
++              sourcesink_driver.descriptors = otg_desc;
++              sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++      }
++
++      return usb_add_config(cdev, &sourcesink_driver);
++}
+diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
+new file mode 100644
+index 0000000..acb8d23
+--- /dev/null
++++ b/drivers/usb/gadget/f_subset.c
+@@ -0,0 +1,421 @@
++/*
++ * f_subset.c -- "CDC Subset" Ethernet link function driver
++ *
++ * Copyright (C) 2003-2005,2008 David Brownell
++ * Copyright (C) 2008 Nokia Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/etherdevice.h>
++
++#include "u_ether.h"
++
++
++/*
++ * This function packages a simple "CDC Subset" Ethernet port with no real
++ * control mechanisms; just raw data transfer over two bulk endpoints.
++ * The data transfer model is exactly that of CDC Ethernet, which is
++ * why we call it the "CDC Subset".
++ *
++ * Because it's not standardized, this has some interoperability issues.
++ * They mostly relate to driver binding, since the data transfer model is
++ * so simple (CDC Ethernet).  The original versions of this protocol used
++ * specific product/vendor IDs:  byteswapped IDs for Digital Equipment's
++ * SA-1100 "Itsy" board, which could run Linux 2.4 kernels and supported
++ * daughtercards with USB peripheral connectors.  (It was used more often
++ * with other boards, using the Itsy identifiers.)  Linux hosts recognized
++ * this with CONFIG_USB_ARMLINUX; these devices have only one configuration
++ * and one interface.
++ *
++ * At some point, MCCI defined a (nonconformant) CDC MDLM variant called
++ * "SAFE", which happens to have a mode which is identical to the "CDC
++ * Subset" in terms of data transfer and lack of control model.  This was
++ * adopted by later Sharp Zaurus models, and by some other software which
++ * Linux hosts recognize with CONFIG_USB_NET_ZAURUS.
++ *
++ * Because Microsoft's RNDIS drivers are far from robust, we added a few
++ * descriptors to the CDC Subset code, making this code look like a SAFE
++ * implementation.  This lets you use MCCI's host side MS-Windows drivers
++ * if you get fed up with RNDIS.  It also makes it easier for composite
++ * drivers to work, since they can use class based binding instead of
++ * caring about specific product and vendor IDs.
++ */
++
++struct geth_descs {
++      struct usb_endpoint_descriptor  *in;
++      struct usb_endpoint_descriptor  *out;
++};
++
++struct f_gether {
++      struct gether                   port;
++
++      char                            ethaddr[14];
++
++      struct geth_descs               fs;
++      struct geth_descs               hs;
++};
++
++static inline struct f_gether *func_to_geth(struct usb_function *f)
++{
++      return container_of(f, struct f_gether, port.func);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * "Simple" CDC-subset option is a simple vendor-neutral model that most
++ * full speed controllers can handle:  one interface, two bulk endpoints.
++ * To assist host side drivers, we fancy it up a bit, and add descriptors so
++ * some host side drivers will understand it as a "SAFE" variant.
++ *
++ * "SAFE" loosely follows CDC WMC MDLM, violating the spec in various ways.
++ * Data endpoints live in the control interface, there's no data interface.
++ * And it's not used to talk to a cell phone radio.
++ */
++
++/* interface descriptor: */
++
++static struct usb_interface_descriptor subset_data_intf __initdata = {
++      .bLength =              sizeof subset_data_intf,
++      .bDescriptorType =      USB_DT_INTERFACE,
++
++      /* .bInterfaceNumber = DYNAMIC */
++      .bAlternateSetting =    0,
++      .bNumEndpoints =        2,
++      .bInterfaceClass =      USB_CLASS_COMM,
++      .bInterfaceSubClass =   USB_CDC_SUBCLASS_MDLM,
++      .bInterfaceProtocol =   0,
++      /* .iInterface = DYNAMIC */
++};
++
++static struct usb_cdc_header_desc header_desc __initdata = {
++      .bLength =              sizeof header_desc,
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_HEADER_TYPE,
++
++      .bcdCDC =               __constant_cpu_to_le16(0x0110),
++};
++
++static struct usb_cdc_mdlm_desc mdlm_desc __initdata = {
++      .bLength =              sizeof mdlm_desc,
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_MDLM_TYPE,
++
++      .bcdVersion =           __constant_cpu_to_le16(0x0100),
++      .bGUID = {
++              0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
++              0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
++      },
++};
++
++/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
++ * can't really use its struct.  All we do here is say that we're using
++ * the submode of "SAFE" which directly matches the CDC Subset.
++ */
++static u8 mdlm_detail_desc[] __initdata = {
++      6,
++      USB_DT_CS_INTERFACE,
++      USB_CDC_MDLM_DETAIL_TYPE,
++
++      0,      /* "SAFE" */
++      0,      /* network control capabilities (none) */
++      0,      /* network data capabilities ("raw" encapsulation) */
++};
++
++static struct usb_cdc_ether_desc ether_desc __initdata = {
++      .bLength =              sizeof ether_desc,
++      .bDescriptorType =      USB_DT_CS_INTERFACE,
++      .bDescriptorSubType =   USB_CDC_ETHERNET_TYPE,
++
++      /* this descriptor actually adds value, surprise! */
++      /* .iMACAddress = DYNAMIC */
++      .bmEthernetStatistics = __constant_cpu_to_le32(0), /* no statistics */
++      .wMaxSegmentSize =      __constant_cpu_to_le16(ETH_FRAME_LEN),
++      .wNumberMCFilters =     __constant_cpu_to_le16(0),
++      .bNumberPowerFilters =  0,
++};
++
++/* full speed support: */
++
++static struct usb_endpoint_descriptor fs_in_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_IN,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor fs_out_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bEndpointAddress =     USB_DIR_OUT,
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_descriptor_header *fs_eth_function[] __initdata = {
++      (struct usb_descriptor_header *) &subset_data_intf,
++      (struct usb_descriptor_header *) &header_desc,
++      (struct usb_descriptor_header *) &mdlm_desc,
++      (struct usb_descriptor_header *) &mdlm_detail_desc,
++      (struct usb_descriptor_header *) &ether_desc,
++      (struct usb_descriptor_header *) &fs_in_desc,
++      (struct usb_descriptor_header *) &fs_out_desc,
++      NULL,
++};
++
++/* high speed support: */
++
++static struct usb_endpoint_descriptor hs_in_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor hs_out_desc __initdata = {
++      .bLength =              USB_DT_ENDPOINT_SIZE,
++      .bDescriptorType =      USB_DT_ENDPOINT,
++
++      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
++      .wMaxPacketSize =       __constant_cpu_to_le16(512),
++};
++
++static struct usb_descriptor_header *hs_eth_function[] __initdata = {
++      (struct usb_descriptor_header *) &subset_data_intf,
++      (struct usb_descriptor_header *) &header_desc,
++      (struct usb_descriptor_header *) &mdlm_desc,
++      (struct usb_descriptor_header *) &mdlm_detail_desc,
++      (struct usb_descriptor_header *) &ether_desc,
++      (struct usb_descriptor_header *) &hs_in_desc,
++      (struct usb_descriptor_header *) &hs_out_desc,
++      NULL,
++};
++
++/* string descriptors: */
++
++static struct usb_string geth_string_defs[] = {
++      [0].s = "CDC Ethernet Subset/SAFE",
++      [1].s = NULL /* DYNAMIC */,
++      {  } /* end of list */
++};
++
++static struct usb_gadget_strings geth_string_table = {
++      .language =             0x0409, /* en-us */
++      .strings =              geth_string_defs,
++};
++
++static struct usb_gadget_strings *geth_strings[] = {
++      &geth_string_table,
++      NULL,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
++{
++      struct f_gether         *geth = func_to_geth(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++      struct net_device       *net;
++
++      /* we know alt == 0, so this is an activation or a reset */
++
++      if (geth->port.in_ep->driver_data) {
++              DBG(cdev, "reset cdc subset\n");
++              gether_disconnect(&geth->port);
++      }
++
++      DBG(cdev, "init + activate cdc subset\n");
++      geth->port.in = ep_choose(cdev->gadget,
++                      geth->hs.in, geth->fs.in);
++      geth->port.out = ep_choose(cdev->gadget,
++                      geth->hs.out, geth->fs.out);
++
++      net = gether_connect(&geth->port);
++      return IS_ERR(net) ? PTR_ERR(net) : 0;
++}
++
++static void geth_disable(struct usb_function *f)
++{
++      struct f_gether *geth = func_to_geth(f);
++      struct usb_composite_dev *cdev = f->config->cdev;
++
++      DBG(cdev, "net deactivated\n");
++      gether_disconnect(&geth->port);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* serial function driver setup/binding */
++
++static int __init
++geth_bind(struct usb_configuration *c, struct usb_function *f)
++{
++      struct usb_composite_dev *cdev = c->cdev;
++      struct f_gether         *geth = func_to_geth(f);
++      int                     status;
++      struct usb_ep           *ep;
++
++      /* allocate instance-specific interface IDs */
++      status = usb_interface_id(c, f);
++      if (status < 0)
++              goto fail;
++      subset_data_intf.bInterfaceNumber = status;
++
++      status = -ENODEV;
++
++      /* allocate instance-specific endpoints */
++      ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc);
++      if (!ep)
++              goto fail;
++      geth->port.in_ep = ep;
++      ep->driver_data = cdev; /* claim */
++
++      ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc);
++      if (!ep)
++              goto fail;
++      geth->port.out_ep = ep;
++      ep->driver_data = cdev; /* claim */
++
++      /* copy descriptors, and track endpoint copies */
++      f->descriptors = usb_copy_descriptors(fs_eth_function);
++
++      geth->fs.in = usb_find_endpoint(fs_eth_function,
++                      f->descriptors, &fs_in_desc);
++      geth->fs.out = usb_find_endpoint(fs_eth_function,
++                      f->descriptors, &fs_out_desc);
++
++
++      /* support all relevant hardware speeds... we expect that when
++       * hardware is dual speed, all bulk-capable endpoints work at
++       * both speeds
++       */
++      if (gadget_is_dualspeed(c->cdev->gadget)) {
++              hs_in_desc.bEndpointAddress =
++                              fs_in_desc.bEndpointAddress;
++              hs_out_desc.bEndpointAddress =
++                              fs_out_desc.bEndpointAddress;
++
++              /* copy descriptors, and track endpoint copies */
++              f->hs_descriptors = usb_copy_descriptors(hs_eth_function);
++
++              geth->hs.in = usb_find_endpoint(hs_eth_function,
++                              f->hs_descriptors, &hs_in_desc);
++              geth->hs.out = usb_find_endpoint(hs_eth_function,
++                              f->hs_descriptors, &hs_out_desc);
++      }
++
++      /* NOTE:  all that is done without knowing or caring about
++       * the network link ... which is unavailable to this code
++       * until we're activated via set_alt().
++       */
++
++      DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n",
++                      gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++                      geth->port.in_ep->name, geth->port.out_ep->name);
++      return 0;
++
++fail:
++      /* we might as well release our claims on endpoints */
++      if (geth->port.out)
++              geth->port.out_ep->driver_data = NULL;
++      if (geth->port.in)
++              geth->port.in_ep->driver_data = NULL;
++
++      ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
++
++      return status;
++}
++
++static void
++geth_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++      if (gadget_is_dualspeed(c->cdev->gadget))
++              usb_free_descriptors(f->hs_descriptors);
++      usb_free_descriptors(f->descriptors);
++      geth_string_defs[1].s = NULL;
++      kfree(func_to_geth(f));
++}
++
++/**
++ * geth_bind_config - add CDC Subset network link to a configuration
++ * @c: the configuration to support the network link
++ * @ethaddr: a buffer in which the ethernet address of the host side
++ *    side of the link was recorded
++ * Context: single threaded during gadget setup
++ *
++ * Returns zero on success, else negative errno.
++ *
++ * Caller must have called @gether_setup().  Caller is also responsible
++ * for calling @gether_cleanup() before module unload.
++ */
++int __init geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
++{
++      struct f_gether *geth;
++      int             status;
++
++      if (!ethaddr)
++              return -EINVAL;
++
++      /* maybe allocate device-global string IDs */
++      if (geth_string_defs[0].id == 0) {
++
++              /* interface label */
++              status = usb_string_id(c->cdev);
++              if (status < 0)
++                      return status;
++              geth_string_defs[0].id = status;
++              subset_data_intf.iInterface = status;
++
++              /* MAC address */
++              status = usb_string_id(c->cdev);
++              if (status < 0)
++                      return status;
++              geth_string_defs[1].id = status;
++              ether_desc.iMACAddress = status;
++      }
++
++      /* allocate and initialize one new instance */
++      geth = kzalloc(sizeof *geth, GFP_KERNEL);
++      if (!geth)
++              return -ENOMEM;
++
++      /* export host's Ethernet address in CDC format */
++      snprintf(geth->ethaddr, sizeof geth->ethaddr,
++              "%02X%02X%02X%02X%02X%02X",
++              ethaddr[0], ethaddr[1], ethaddr[2],
++              ethaddr[3], ethaddr[4], ethaddr[5]);
++      geth_string_defs[1].s = geth->ethaddr;
++
++      geth->port.cdc_filter = DEFAULT_FILTER;
++
++      geth->port.func.name = "cdc_subset";
++      geth->port.func.strings = geth_strings;
++      geth->port.func.bind = geth_bind;
++      geth->port.func.unbind = geth_unbind;
++      geth->port.func.set_alt = geth_set_alt;
++      geth->port.func.disable = geth_disable;
++
++      status = usb_add_function(c, &geth->port.func);
++      if (status) {
++              geth_string_defs[1].s = NULL;
++              kfree(geth);
++      }
++      return status;
++}
+diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
+index 47bb9f0..ea2c31d 100644
+--- a/drivers/usb/gadget/file_storage.c
++++ b/drivers/usb/gadget/file_storage.c
+@@ -308,7 +308,7 @@ MODULE_LICENSE("Dual BSD/GPL");
+       dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+ #define ERROR(d, fmt, args...) \
+       dev_err(&(d)->gadget->dev , fmt , ## args)
+-#define WARN(d, fmt, args...) \
++#define WARNING(d, fmt, args...) \
+       dev_warn(&(d)->gadget->dev , fmt , ## args)
+ #define INFO(d, fmt, args...) \
+       dev_info(&(d)->gadget->dev , fmt , ## args)
+@@ -1091,7 +1091,7 @@ static int ep0_queue(struct fsg_dev *fsg)
+       if (rc != 0 && rc != -ESHUTDOWN) {
+               /* We can't do much more than wait for a reset */
+-              WARN(fsg, "error in submission: %s --> %d\n",
++              WARNING(fsg, "error in submission: %s --> %d\n",
+                               fsg->ep0->name, rc);
+       }
+       return rc;
+@@ -1227,7 +1227,7 @@ static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+       /* Save the command for later */
+       if (fsg->cbbuf_cmnd_size)
+-              WARN(fsg, "CB[I] overwriting previous command\n");
++              WARNING(fsg, "CB[I] overwriting previous command\n");
+       fsg->cbbuf_cmnd_size = req->actual;
+       memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size);
+@@ -1506,7 +1506,7 @@ static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
+                * submissions if DMA is enabled. */
+               if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
+                                               req->length == 0))
+-                      WARN(fsg, "error in submission: %s --> %d\n",
++                      WARNING(fsg, "error in submission: %s --> %d\n",
+                                       ep->name, rc);
+       }
+ }
+@@ -2294,7 +2294,7 @@ static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
+               VDBG(fsg, "delayed bulk-in endpoint halt\n");
+       while (rc != 0) {
+               if (rc != -EAGAIN) {
+-                      WARN(fsg, "usb_ep_set_halt -> %d\n", rc);
++                      WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
+                       rc = 0;
+                       break;
+               }
+@@ -2317,7 +2317,7 @@ static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
+               VDBG(fsg, "delayed bulk-in endpoint wedge\n");
+       while (rc != 0) {
+               if (rc != -EAGAIN) {
+-                      WARN(fsg, "usb_ep_set_wedge -> %d\n", rc);
++                      WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
+                       rc = 0;
+                       break;
+               }
+@@ -3755,7 +3755,7 @@ static int __init check_parameters(struct fsg_dev *fsg)
+               if (gcnum >= 0)
+                       mod_data.release = 0x0300 + gcnum;
+               else {
+-                      WARN(fsg, "controller '%s' not recognized\n",
++                      WARNING(fsg, "controller '%s' not recognized\n",
+                               fsg->gadget->name);
+                       mod_data.release = 0x0399;
+               }
+@@ -3867,8 +3867,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+               curlun->dev.parent = &gadget->dev;
+               curlun->dev.driver = &fsg_driver.driver;
+               dev_set_drvdata(&curlun->dev, fsg);
+-              snprintf(curlun->dev.bus_id, BUS_ID_SIZE,
+-                              "%s-lun%d", gadget->dev.bus_id, i);
++              dev_set_name(&curlun->dev,"%s-lun%d",
++                           dev_name(&gadget->dev), i);
+               if ((rc = device_register(&curlun->dev)) != 0) {
+                       INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
+diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
+index 1868754..45ad556 100644
+--- a/drivers/usb/gadget/fsl_usb2_udc.c
++++ b/drivers/usb/gadget/fsl_usb2_udc.c
+@@ -223,7 +223,7 @@ static int dr_controller_setup(struct fsl_udc *udc)
+       fsl_writel(tmp, &dr_regs->endpointlistaddr);
+       VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
+-              (int)udc->ep_qh, (int)tmp,
++              udc->ep_qh, (int)tmp,
+               fsl_readl(&dr_regs->endpointlistaddr));
+       /* Config PHY interface */
+@@ -1538,7 +1538,7 @@ static void dtd_complete_irq(struct fsl_udc *udc)
+               /* If the ep is configured */
+               if (curr_ep->name == NULL) {
+-                      WARN("Invalid EP?");
++                      WARNING("Invalid EP?");
+                       continue;
+               }
+@@ -2331,7 +2331,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
+       udc_controller->gadget.name = driver_name;
+       /* Setup gadget.dev and register with kernel */
+-      strcpy(udc_controller->gadget.dev.bus_id, "gadget");
++      dev_set_name(&udc_controller->gadget.dev, "gadget");
+       udc_controller->gadget.dev.release = fsl_udc_release;
+       udc_controller->gadget.dev.parent = &pdev->dev;
+       ret = device_register(&udc_controller->gadget.dev);
+diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
+index 98b1483..6131752 100644
+--- a/drivers/usb/gadget/fsl_usb2_udc.h
++++ b/drivers/usb/gadget/fsl_usb2_udc.h
+@@ -552,7 +552,7 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)
+ #endif
+ #define ERR(stuff...)         pr_err("udc: " stuff)
+-#define WARN(stuff...)                pr_warning("udc: " stuff)
++#define WARNING(stuff...)             pr_warning("udc: " stuff)
+ #define INFO(stuff...)                pr_info("udc: " stuff)
+ /*-------------------------------------------------------------------------*/
+diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h
+new file mode 100644
+index 0000000..dd2f16a
+--- /dev/null
++++ b/drivers/usb/gadget/g_zero.h
+@@ -0,0 +1,25 @@
++/*
++ * This header declares the utility functions used by "Gadget Zero", plus
++ * interfaces to its two single-configuration function drivers.
++ */
++
++#ifndef __G_ZERO_H
++#define __G_ZERO_H
++
++#include <linux/usb/composite.h>
++
++/* global state */
++extern unsigned buflen;
++extern const struct usb_descriptor_header *otg_desc[];
++
++/* common utilities */
++struct usb_request *alloc_ep_req(struct usb_ep *ep);
++void free_ep_req(struct usb_ep *ep, struct usb_request *req);
++void disable_endpoints(struct usb_composite_dev *cdev,
++              struct usb_ep *in, struct usb_ep *out);
++
++/* configuration-specific linkup */
++int sourcesink_add(struct usb_composite_dev *cdev);
++int loopback_add(struct usb_composite_dev *cdev);
++
++#endif /* __G_ZERO_H */
+diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
+index f7f159c..17d9905 100644
+--- a/drivers/usb/gadget/gadget_chips.h
++++ b/drivers/usb/gadget/gadget_chips.h
+@@ -11,6 +11,10 @@
+  * Some are available on 2.4 kernels; several are available, but not
+  * yet pushed in the 2.6 mainline tree.
+  */
++
++#ifndef __GADGET_CHIPS_H
++#define __GADGET_CHIPS_H
++
+ #ifdef CONFIG_USB_GADGET_NET2280
+ #define       gadget_is_net2280(g)    !strcmp("net2280", (g)->name)
+ #else
+@@ -29,8 +33,8 @@
+ #define       gadget_is_dummy(g)      0
+ #endif
+-#ifdef CONFIG_USB_GADGET_PXA2XX
+-#define       gadget_is_pxa(g)        !strcmp("pxa2xx_udc", (g)->name)
++#ifdef CONFIG_USB_GADGET_PXA25X
++#define       gadget_is_pxa(g)        !strcmp("pxa25x_udc", (g)->name)
+ #else
+ #define       gadget_is_pxa(g)        0
+ #endif
+@@ -214,3 +218,28 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
+               return 0x21;
+       return -ENOENT;
+ }
++
++
++/**
++ * gadget_supports_altsettings - return true if altsettings work
++ * @gadget: the gadget in question
++ */
++static inline bool gadget_supports_altsettings(struct usb_gadget *gadget)
++{
++      /* PXA 21x/25x/26x has no altsettings at all */
++      if (gadget_is_pxa(gadget))
++              return false;
++
++      /* PXA 27x and 3xx have *broken* altsetting support */
++      if (gadget_is_pxa27x(gadget))
++              return false;
++
++      /* SH3 hardware just doesn't do altsettings */
++      if (gadget_is_sh(gadget))
++              return false;
++
++      /* Everything else is *presumably* fine ... */
++      return true;
++}
++
++#endif /* __GADGET_CHIPS_H */
+diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
+index 7f4d482..ea8651e 100644
+--- a/drivers/usb/gadget/gmidi.c
++++ b/drivers/usb/gadget/gmidi.c
+@@ -138,8 +138,6 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
+       dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+ #define ERROR(d, fmt, args...) \
+       dev_err(&(d)->gadget->dev , fmt , ## args)
+-#define WARN(d, fmt, args...) \
+-      dev_warn(&(d)->gadget->dev , fmt , ## args)
+ #define INFO(d, fmt, args...) \
+       dev_info(&(d)->gadget->dev , fmt , ## args)
+diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
+index be6613a..60aa048 100644
+--- a/drivers/usb/gadget/goku_udc.c
++++ b/drivers/usb/gadget/goku_udc.c
+@@ -1768,7 +1768,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+        * usb_gadget_driver_{register,unregister}() must change.
+        */
+       if (the_controller) {
+-              WARN(dev, "ignoring %s\n", pci_name(pdev));
++              WARNING(dev, "ignoring %s\n", pci_name(pdev));
+               return -EBUSY;
+       }
+       if (!pdev->irq) {
+@@ -1790,7 +1790,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+       dev->gadget.ops = &goku_ops;
+       /* the "gadget" abstracts/virtualizes the controller */
+-      strcpy(dev->gadget.dev.bus_id, "gadget");
++      dev_set_name(&dev->gadget.dev, "gadget");
+       dev->gadget.dev.parent = &pdev->dev;
+       dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+       dev->gadget.dev.release = gadget_release;
+diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h
+index bc4eb1e..566cb23 100644
+--- a/drivers/usb/gadget/goku_udc.h
++++ b/drivers/usb/gadget/goku_udc.h
+@@ -285,7 +285,7 @@ struct goku_udc {
+ #define ERROR(dev,fmt,args...) \
+       xprintk(dev , KERN_ERR , fmt , ## args)
+-#define WARN(dev,fmt,args...) \
++#define WARNING(dev,fmt,args...) \
+       xprintk(dev , KERN_WARNING , fmt , ## args)
+ #define INFO(dev,fmt,args...) \
+       xprintk(dev , KERN_INFO , fmt , ## args)
+diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
+index 69b0a27..f4585d3 100644
+--- a/drivers/usb/gadget/inode.c
++++ b/drivers/usb/gadget/inode.c
+@@ -32,6 +32,7 @@
+ #include <asm/uaccess.h>
+ #include <linux/slab.h>
+ #include <linux/poll.h>
++#include <linux/smp_lock.h>
+ #include <linux/device.h>
+ #include <linux/moduleparam.h>
+@@ -261,8 +262,6 @@ static const char *CHIP;
+ #define ERROR(dev,fmt,args...) \
+       xprintk(dev , KERN_ERR , fmt , ## args)
+-#define WARN(dev,fmt,args...) \
+-      xprintk(dev , KERN_WARNING , fmt , ## args)
+ #define INFO(dev,fmt,args...) \
+       xprintk(dev , KERN_INFO , fmt , ## args)
+@@ -483,8 +482,7 @@ ep_release (struct inode *inode, struct file *fd)
+       return 0;
+ }
+-static int ep_ioctl (struct inode *inode, struct file *fd,
+-              unsigned code, unsigned long value)
++static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
+ {
+       struct ep_data          *data = fd->private_data;
+       int                     status;
+@@ -740,7 +738,7 @@ static const struct file_operations ep_io_operations = {
+       .read =         ep_read,
+       .write =        ep_write,
+-      .ioctl =        ep_ioctl,
++      .unlocked_ioctl = ep_ioctl,
+       .release =      ep_release,
+       .aio_read =     ep_aio_read,
+@@ -1294,15 +1292,18 @@ out:
+        return mask;
+ }
+-static int dev_ioctl (struct inode *inode, struct file *fd,
+-              unsigned code, unsigned long value)
++static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
+ {
+       struct dev_data         *dev = fd->private_data;
+       struct usb_gadget       *gadget = dev->gadget;
++      long ret = -ENOTTY;
+-      if (gadget->ops->ioctl)
+-              return gadget->ops->ioctl (gadget, code, value);
+-      return -ENOTTY;
++      if (gadget->ops->ioctl) {
++              lock_kernel();
++              ret = gadget->ops->ioctl (gadget, code, value);
++              unlock_kernel();
++      }
++      return ret;
+ }
+ /* used after device configuration */
+@@ -1314,7 +1315,7 @@ static const struct file_operations ep0_io_operations = {
+       .write =        ep0_write,
+       .fasync =       ep0_fasync,
+       .poll =         ep0_poll,
+-      .ioctl =        dev_ioctl,
++      .unlocked_ioctl =       dev_ioctl,
+       .release =      dev_release,
+ };
+@@ -1501,7 +1502,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+               }
+               break;
+-#ifndef       CONFIG_USB_GADGET_PXA2XX
++#ifndef       CONFIG_USB_GADGET_PXA25X
+       /* PXA automagically handles this request too */
+       case USB_REQ_GET_CONFIGURATION:
+               if (ctrl->bRequestType != 0x80)
+@@ -1964,7 +1965,7 @@ static const struct file_operations dev_init_operations = {
+       .open =         dev_open,
+       .write =        dev_config,
+       .fasync =       ep0_fasync,
+-      .ioctl =        dev_ioctl,
++      .unlocked_ioctl = dev_ioctl,
+       .release =      dev_release,
+ };
+diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
+index 825abd2..c6e7df0 100644
+--- a/drivers/usb/gadget/lh7a40x_udc.c
++++ b/drivers/usb/gadget/lh7a40x_udc.c
+@@ -1970,7 +1970,7 @@ static const struct usb_gadget_ops lh7a40x_udc_ops = {
+ static void nop_release(struct device *dev)
+ {
+-      DEBUG("%s %s\n", __func__, dev->bus_id);
++      DEBUG("%s %s\n", __func__, dev_name(dev));
+ }
+ static struct lh7a40x_udc memory = {
+diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
+index 1ecfd63..ca86120 100644
+--- a/drivers/usb/gadget/lh7a40x_udc.h
++++ b/drivers/usb/gadget/lh7a40x_udc.h
+@@ -47,7 +47,7 @@
+ #include <asm/irq.h>
+ #include <asm/system.h>
+ #include <asm/unaligned.h>
+-#include <asm/hardware.h>
++#include <mach/hardware.h>
+ #include <linux/usb/ch9.h>
+ #include <linux/usb/gadget.h>
+diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
+index ee6b35f..77b44fb 100644
+--- a/drivers/usb/gadget/m66592-udc.c
++++ b/drivers/usb/gadget/m66592-udc.c
+@@ -1593,7 +1593,7 @@ static int __init m66592_probe(struct platform_device *pdev)
+       m66592->gadget.ops = &m66592_gadget_ops;
+       device_initialize(&m66592->gadget.dev);
+-      strcpy(m66592->gadget.dev.bus_id, "gadget");
++      dev_set_name(&m66592->gadget.dev, "gadget");
+       m66592->gadget.is_dualspeed = 1;
+       m66592->gadget.dev.parent = &pdev->dev;
+       m66592->gadget.dev.dma_mask = pdev->dev.dma_mask;
+diff --git a/drivers/usb/gadget/ndis.h b/drivers/usb/gadget/ndis.h
+index 09e3ee4..df886ce 100644
+--- a/drivers/usb/gadget/ndis.h
++++ b/drivers/usb/gadget/ndis.h
+@@ -1,11 +1,11 @@
+ /*
+- * ndis.h 
+- * 
++ * ndis.h
++ *
+  * ntddndis.h modified by Benedikt Spranger <b.spranger@pengutronix.de>
+- * 
+- * Thanks to the cygwin development team, 
++ *
++ * Thanks to the cygwin development team,
+  * espacially to Casper S. Hornstrup <chorns@users.sourceforge.net>
+- * 
++ *
+  * THIS SOFTWARE IS NOT COPYRIGHTED
+  *
+  * This source code is offered for use in the public domain. You may
+diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
+index e018623..5cfb5eb 100644
+--- a/drivers/usb/gadget/net2280.c
++++ b/drivers/usb/gadget/net2280.c
+@@ -1007,7 +1007,7 @@ static void scan_dma_completions (struct net2280_ep *ep)
+                        * 0122, and 0124; not all cases trigger the warning.
+                        */
+                       if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) {
+-                              WARN (ep->dev, "%s lost packet sync!\n",
++                              WARNING (ep->dev, "%s lost packet sync!\n",
+                                               ep->ep.name);
+                               req->req.status = -EOVERFLOW;
+                       } else if ((tmp = readl (&ep->regs->ep_avail)) != 0) {
+@@ -2768,7 +2768,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
+       dev->gadget.is_dualspeed = 1;
+       /* the "gadget" abstracts/virtualizes the controller */
+-      strcpy (dev->gadget.dev.bus_id, "gadget");
++      dev_set_name(&dev->gadget.dev, "gadget");
+       dev->gadget.dev.parent = &pdev->dev;
+       dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+       dev->gadget.dev.release = gadget_release;
+diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h
+index 1f2af39..81a71db 100644
+--- a/drivers/usb/gadget/net2280.h
++++ b/drivers/usb/gadget/net2280.h
+@@ -272,7 +272,7 @@ static inline void net2280_led_shutdown (struct net2280 *dev)
+ #define ERROR(dev,fmt,args...) \
+       xprintk(dev , KERN_ERR , fmt , ## args)
+-#define WARN(dev,fmt,args...) \
++#define WARNING(dev,fmt,args...) \
+       xprintk(dev , KERN_WARNING , fmt , ## args)
+ #define INFO(dev,fmt,args...) \
+       xprintk(dev , KERN_INFO , fmt , ## args)
+diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
+index 881d74c..bb54cca 100644
+--- a/drivers/usb/gadget/omap_udc.c
++++ b/drivers/usb/gadget/omap_udc.c
+@@ -52,8 +52,9 @@
+ #include <asm/unaligned.h>
+ #include <asm/mach-types.h>
+-#include <asm/arch/dma.h>
+-#include <asm/arch/usb.h>
++#include <mach/dma.h>
++#include <mach/usb.h>
++#include <mach/control.h>
+ #include "omap_udc.h"
+@@ -135,13 +136,17 @@ static void use_ep(struct omap_ep *ep, u16 select)
+       if (ep->bEndpointAddress & USB_DIR_IN)
+               num |= UDC_EP_DIR;
+-      UDC_EP_NUM_REG = num | select;
++      omap_writew(num | select, UDC_EP_NUM);
+       /* when select, MUST deselect later !! */
+ }
+ static inline void deselect_ep(void)
+ {
+-      UDC_EP_NUM_REG &= ~UDC_EP_SEL;
++      u16 w;
++
++      w = omap_readw(UDC_EP_NUM);
++      w &= ~UDC_EP_SEL;
++      omap_writew(w, UDC_EP_NUM);
+       /* 6 wait states before TX will happen */
+ }
+@@ -216,7 +221,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
+       ep->has_dma = 0;
+       ep->lch = -1;
+       use_ep(ep, UDC_EP_SEL);
+-      UDC_CTRL_REG = udc->clr_halt;
++      omap_writew(udc->clr_halt, UDC_CTRL);
+       ep->ackwait = 0;
+       deselect_ep();
+@@ -232,7 +237,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
+       if (desc->bmAttributes != USB_ENDPOINT_XFER_ISOC
+                       && !ep->has_dma
+                       && !(ep->bEndpointAddress & USB_DIR_IN)) {
+-              UDC_CTRL_REG = UDC_SET_FIFO_EN;
++              omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
+               ep->ackwait = 1 + ep->double_buf;
+       }
+@@ -259,7 +264,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
+       nuke (ep, -ESHUTDOWN);
+       ep->ep.maxpacket = ep->maxpacket;
+       ep->has_dma = 0;
+-      UDC_CTRL_REG = UDC_SET_HALT;
++      omap_writew(UDC_SET_HALT, UDC_CTRL);
+       list_del_init(&ep->iso);
+       del_timer(&ep->timer);
+@@ -360,13 +365,13 @@ write_packet(u8 *buf, struct omap_req *req, unsigned max)
+       if (likely((((int)buf) & 1) == 0)) {
+               wp = (u16 *)buf;
+               while (max >= 2) {
+-                      UDC_DATA_REG = *wp++;
++                      omap_writew(*wp++, UDC_DATA);
+                       max -= 2;
+               }
+               buf = (u8 *)wp;
+       }
+       while (max--)
+-              *(volatile u8 *)&UDC_DATA_REG = *buf++;
++              omap_writeb(*buf++, UDC_DATA);
+       return len;
+ }
+@@ -385,13 +390,13 @@ static int write_fifo(struct omap_ep *ep, struct omap_req *req)
+       prefetch(buf);
+       /* PIO-IN isn't double buffered except for iso */
+-      ep_stat = UDC_STAT_FLG_REG;
++      ep_stat = omap_readw(UDC_STAT_FLG);
+       if (ep_stat & UDC_FIFO_UNWRITABLE)
+               return 0;
+       count = ep->ep.maxpacket;
+       count = write_packet(buf, req, count);
+-      UDC_CTRL_REG = UDC_SET_FIFO_EN;
++      omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
+       ep->ackwait = 1;
+       /* last packet is often short (sometimes a zlp) */
+@@ -425,13 +430,13 @@ read_packet(u8 *buf, struct omap_req *req, unsigned avail)
+       if (likely((((int)buf) & 1) == 0)) {
+               wp = (u16 *)buf;
+               while (avail >= 2) {
+-                      *wp++ = UDC_DATA_REG;
++                      *wp++ = omap_readw(UDC_DATA);
+                       avail -= 2;
+               }
+               buf = (u8 *)wp;
+       }
+       while (avail--)
+-              *buf++ = *(volatile u8 *)&UDC_DATA_REG;
++              *buf++ = omap_readb(UDC_DATA);
+       return len;
+ }
+@@ -446,7 +451,7 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
+       prefetchw(buf);
+       for (;;) {
+-              u16     ep_stat = UDC_STAT_FLG_REG;
++              u16     ep_stat = omap_readw(UDC_STAT_FLG);
+               is_last = 0;
+               if (ep_stat & FIFO_EMPTY) {
+@@ -460,7 +465,7 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
+               if (ep_stat & UDC_FIFO_FULL)
+                       avail = ep->ep.maxpacket;
+               else  {
+-                      avail = UDC_RXFSTAT_REG;
++                      avail = omap_readw(UDC_RXFSTAT);
+                       ep->fnf = ep->double_buf;
+               }
+               count = read_packet(buf, req, avail);
+@@ -473,7 +478,7 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
+                               req->req.status = -EOVERFLOW;
+                               avail -= count;
+                               while (avail--)
+-                                      (void) *(volatile u8 *)&UDC_DATA_REG;
++                                      omap_readw(UDC_DATA);
+                       }
+               } else if (req->req.length == req->req.actual)
+                       is_last = 1;
+@@ -491,32 +496,6 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
+ /*-------------------------------------------------------------------------*/
+-static inline dma_addr_t dma_csac(unsigned lch)
+-{
+-      dma_addr_t      csac;
+-
+-      /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
+-       * read before the DMA controller finished disabling the channel.
+-       */
+-      csac = OMAP_DMA_CSAC_REG(lch);
+-      if (csac == 0)
+-              csac = OMAP_DMA_CSAC_REG(lch);
+-      return csac;
+-}
+-
+-static inline dma_addr_t dma_cdac(unsigned lch)
+-{
+-      dma_addr_t      cdac;
+-
+-      /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
+-       * read before the DMA controller finished disabling the channel.
+-       */
+-      cdac = OMAP_DMA_CDAC_REG(lch);
+-      if (cdac == 0)
+-              cdac = OMAP_DMA_CDAC_REG(lch);
+-      return cdac;
+-}
+-
+ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
+ {
+       dma_addr_t      end;
+@@ -527,7 +506,7 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
+       if (cpu_is_omap15xx())
+               return 0;
+-      end = dma_csac(ep->lch);
++      end = omap_get_dma_src_pos(ep->lch);
+       if (end == ep->dma_counter)
+               return 0;
+@@ -537,15 +516,11 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
+       return end - start;
+ }
+-#define DMA_DEST_LAST(x) (cpu_is_omap15xx() \
+-              ? OMAP_DMA_CSAC_REG(x) /* really: CPC */ \
+-              : dma_cdac(x))
+-
+ static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
+ {
+       dma_addr_t      end;
+-      end = DMA_DEST_LAST(ep->lch);
++      end = omap_get_dma_dst_pos(ep->lch);
+       if (end == ep->dma_counter)
+               return 0;
+@@ -565,7 +540,7 @@ static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
+ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
+ {
+-      u16             txdma_ctrl;
++      u16             txdma_ctrl, w;
+       unsigned        length = req->req.length - req->req.actual;
+       const int       sync_mode = cpu_is_omap15xx()
+                               ? OMAP_DMA_SYNC_FRAME
+@@ -596,14 +571,18 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
+               0, 0);
+       omap_start_dma(ep->lch);
+-      ep->dma_counter = dma_csac(ep->lch);
+-      UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel);
+-      UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl;
++      ep->dma_counter = omap_get_dma_src_pos(ep->lch);
++      w = omap_readw(UDC_DMA_IRQ_EN);
++      w |= UDC_TX_DONE_IE(ep->dma_channel);
++      omap_writew(w, UDC_DMA_IRQ_EN);
++      omap_writew(UDC_TXN_START | txdma_ctrl, UDC_TXDMA(ep->dma_channel));
+       req->dma_bytes = length;
+ }
+ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
+ {
++      u16 w;
++
+       if (status == 0) {
+               req->req.actual += req->dma_bytes;
+@@ -620,7 +599,9 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
+       /* tx completion */
+       omap_stop_dma(ep->lch);
+-      UDC_DMA_IRQ_EN_REG &= ~UDC_TX_DONE_IE(ep->dma_channel);
++      w = omap_readw(UDC_DMA_IRQ_EN);
++      w &= ~UDC_TX_DONE_IE(ep->dma_channel);
++      omap_writew(w, UDC_DMA_IRQ_EN);
+       done(ep, req, status);
+ }
+@@ -628,6 +609,7 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
+ {
+       unsigned packets = req->req.length - req->req.actual;
+       int dma_trigger = 0;
++      u16 w;
+       if (cpu_is_omap24xx())
+               dma_trigger = OMAP24XX_DMA(USB_W2FC_RX0, ep->dma_channel);
+@@ -654,12 +636,14 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
+       omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
+               OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
+               0, 0);
+-      ep->dma_counter = DMA_DEST_LAST(ep->lch);
++      ep->dma_counter = omap_get_dma_dst_pos(ep->lch);
+-      UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
+-      UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel);
+-      UDC_EP_NUM_REG = (ep->bEndpointAddress & 0xf);
+-      UDC_CTRL_REG = UDC_SET_FIFO_EN;
++      omap_writew(UDC_RXN_STOP | (packets - 1), UDC_RXDMA(ep->dma_channel));
++      w = omap_readw(UDC_DMA_IRQ_EN);
++      w |= UDC_RX_EOT_IE(ep->dma_channel);
++      omap_writew(w, UDC_DMA_IRQ_EN);
++      omap_writew(ep->bEndpointAddress & 0xf, UDC_EP_NUM);
++      omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
+       omap_start_dma(ep->lch);
+ }
+@@ -667,7 +651,7 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
+ static void
+ finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status, int one)
+ {
+-      u16     count;
++      u16     count, w;
+       if (status == 0)
+               ep->dma_counter = (u16) (req->req.dma + req->req.actual);
+@@ -686,13 +670,15 @@ finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status, int one)
+               return;
+       /* rx completion */
+-      UDC_DMA_IRQ_EN_REG &= ~UDC_RX_EOT_IE(ep->dma_channel);
++      w = omap_readw(UDC_DMA_IRQ_EN);
++      w &= ~UDC_RX_EOT_IE(ep->dma_channel);
++      omap_writew(w, UDC_DMA_IRQ_EN);
+       done(ep, req, status);
+ }
+ static void dma_irq(struct omap_udc *udc, u16 irq_src)
+ {
+-      u16             dman_stat = UDC_DMAN_STAT_REG;
++      u16             dman_stat = omap_readw(UDC_DMAN_STAT);
+       struct omap_ep  *ep;
+       struct omap_req *req;
+@@ -706,7 +692,7 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
+                                               struct omap_req, queue);
+                       finish_in_dma(ep, req, 0);
+               }
+-              UDC_IRQ_SRC_REG = UDC_TXN_DONE;
++              omap_writew(UDC_TXN_DONE, UDC_IRQ_SRC);
+               if (!list_empty (&ep->queue)) {
+                       req = container_of(ep->queue.next,
+@@ -725,7 +711,7 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
+                                       struct omap_req, queue);
+                       finish_out_dma(ep, req, 0, dman_stat & UDC_DMA_RX_SB);
+               }
+-              UDC_IRQ_SRC_REG = UDC_RXN_EOT;
++              omap_writew(UDC_RXN_EOT, UDC_IRQ_SRC);
+               if (!list_empty (&ep->queue)) {
+                       req = container_of(ep->queue.next,
+@@ -739,7 +725,7 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
+               ep->irqs++;
+               /* omap15xx does this unasked... */
+               VDBG("%s, RX_CNT irq?\n", ep->ep.name);
+-              UDC_IRQ_SRC_REG = UDC_RXN_CNT;
++              omap_writew(UDC_RXN_CNT, UDC_IRQ_SRC);
+       }
+ }
+@@ -762,9 +748,9 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
+       is_in = ep->bEndpointAddress & USB_DIR_IN;
+       if (is_in)
+-              reg = UDC_TXDMA_CFG_REG;
++              reg = omap_readw(UDC_TXDMA_CFG);
+       else
+-              reg = UDC_RXDMA_CFG_REG;
++              reg = omap_readw(UDC_RXDMA_CFG);
+       reg |= UDC_DMA_REQ;             /* "pulse" activated */
+       ep->dma_channel = 0;
+@@ -792,7 +778,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
+               status = omap_request_dma(dma_channel,
+                       ep->ep.name, dma_error, ep, &ep->lch);
+               if (status == 0) {
+-                      UDC_TXDMA_CFG_REG = reg;
++                      omap_writew(reg, UDC_TXDMA_CFG);
+                       /* EMIFF or SDRC */
+                       omap_set_dma_src_burst_mode(ep->lch,
+                                               OMAP_DMA_DATA_BURST_4);
+@@ -801,7 +787,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
+                       omap_set_dma_dest_params(ep->lch,
+                               OMAP_DMA_PORT_TIPB,
+                               OMAP_DMA_AMODE_CONSTANT,
+-                              (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
++                              UDC_DATA_DMA,
+                               0, 0);
+               }
+       } else {
+@@ -813,12 +799,12 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
+               status = omap_request_dma(dma_channel,
+                       ep->ep.name, dma_error, ep, &ep->lch);
+               if (status == 0) {
+-                      UDC_RXDMA_CFG_REG = reg;
++                      omap_writew(reg, UDC_RXDMA_CFG);
+                       /* TIPB */
+                       omap_set_dma_src_params(ep->lch,
+                               OMAP_DMA_PORT_TIPB,
+                               OMAP_DMA_AMODE_CONSTANT,
+-                              (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
++                              UDC_DATA_DMA,
+                               0, 0);
+                       /* EMIFF or SDRC */
+                       omap_set_dma_dest_burst_mode(ep->lch,
+@@ -834,7 +820,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
+               /* channel type P: hw synch (fifo) */
+               if (cpu_class_is_omap1() && !cpu_is_omap15xx())
+-                      OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2;
++                      omap_set_dma_channel_mode(ep->lch, OMAP_DMA_LCH_P);
+       }
+ just_restart:
+@@ -860,7 +846,7 @@ just_restart:
+                       (is_in ? write_fifo : read_fifo)(ep, req);
+                       deselect_ep();
+                       if (!is_in) {
+-                              UDC_CTRL_REG = UDC_SET_FIFO_EN;
++                              omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
+                               ep->ackwait = 1 + ep->double_buf;
+                       }
+                       /* IN: 6 wait states before it'll tx */
+@@ -881,7 +867,7 @@ static void dma_channel_release(struct omap_ep *ep)
+       else
+               req = NULL;
+-      active = ((1 << 7) & OMAP_DMA_CCR_REG(ep->lch)) != 0;
++      active = omap_get_dma_active_status(ep->lch);
+       DBG("%s release %s %cxdma%d %p\n", ep->ep.name,
+                       active ? "active" : "idle",
+@@ -894,23 +880,25 @@ static void dma_channel_release(struct omap_ep *ep)
+       /* wait till current packet DMA finishes, and fifo empties */
+       if (ep->bEndpointAddress & USB_DIR_IN) {
+-              UDC_TXDMA_CFG_REG = (UDC_TXDMA_CFG_REG & ~mask) | UDC_DMA_REQ;
++              omap_writew((omap_readw(UDC_TXDMA_CFG) & ~mask) | UDC_DMA_REQ,
++                                      UDC_TXDMA_CFG);
+               if (req) {
+                       finish_in_dma(ep, req, -ECONNRESET);
+                       /* clear FIFO; hosts probably won't empty it */
+                       use_ep(ep, UDC_EP_SEL);
+-                      UDC_CTRL_REG = UDC_CLR_EP;
++                      omap_writew(UDC_CLR_EP, UDC_CTRL);
+                       deselect_ep();
+               }
+-              while (UDC_TXDMA_CFG_REG & mask)
++              while (omap_readw(UDC_TXDMA_CFG) & mask)
+                       udelay(10);
+       } else {
+-              UDC_RXDMA_CFG_REG = (UDC_RXDMA_CFG_REG & ~mask) | UDC_DMA_REQ;
++              omap_writew((omap_readw(UDC_RXDMA_CFG) & ~mask) | UDC_DMA_REQ,
++                                      UDC_RXDMA_CFG);
+               /* dma empties the fifo */
+-              while (UDC_RXDMA_CFG_REG & mask)
++              while (omap_readw(UDC_RXDMA_CFG) & mask)
+                       udelay(10);
+               if (req)
+                       finish_out_dma(ep, req, -ECONNRESET, 0);
+@@ -997,9 +985,13 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+       req->req.actual = 0;
+       /* maybe kickstart non-iso i/o queues */
+-      if (is_iso)
+-              UDC_IRQ_EN_REG |= UDC_SOF_IE;
+-      else if (list_empty(&ep->queue) && !ep->stopped && !ep->ackwait) {
++      if (is_iso) {
++              u16 w;
++
++              w = omap_readw(UDC_IRQ_EN);
++              w |= UDC_SOF_IE;
++              omap_writew(w, UDC_IRQ_EN);
++      } else if (list_empty(&ep->queue) && !ep->stopped && !ep->ackwait) {
+               int     is_in;
+               if (ep->bEndpointAddress == 0) {
+@@ -1017,23 +1009,23 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+                                * requests to non-control endpoints
+                                */
+                               if (udc->ep0_set_config) {
+-                                      u16     irq_en = UDC_IRQ_EN_REG;
++                                      u16     irq_en = omap_readw(UDC_IRQ_EN);
+                                       irq_en |= UDC_DS_CHG_IE | UDC_EP0_IE;
+                                       if (!udc->ep0_reset_config)
+                                               irq_en |= UDC_EPN_RX_IE
+                                                       | UDC_EPN_TX_IE;
+-                                      UDC_IRQ_EN_REG = irq_en;
++                                      omap_writew(irq_en, UDC_IRQ_EN);
+                               }
+                               /* STATUS for zero length DATA stages is
+                                * always an IN ... even for IN transfers,
+                                * a weird case which seem to stall OMAP.
+                                */
+-                              UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR);
+-                              UDC_CTRL_REG = UDC_CLR_EP;
+-                              UDC_CTRL_REG = UDC_SET_FIFO_EN;
+-                              UDC_EP_NUM_REG = UDC_EP_DIR;
++                              omap_writew(UDC_EP_SEL | UDC_EP_DIR, UDC_EP_NUM);
++                              omap_writew(UDC_CLR_EP, UDC_CTRL);
++                              omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
++                              omap_writew(UDC_EP_DIR, UDC_EP_NUM);
+                               /* cleanup */
+                               udc->ep0_pending = 0;
+@@ -1042,11 +1034,11 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+                       /* non-empty DATA stage */
+                       } else if (is_in) {
+-                              UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;
++                              omap_writew(UDC_EP_SEL | UDC_EP_DIR, UDC_EP_NUM);
+                       } else {
+                               if (udc->ep0_setup)
+                                       goto irq_wait;
+-                              UDC_EP_NUM_REG = UDC_EP_SEL;
++                              omap_writew(UDC_EP_SEL, UDC_EP_NUM);
+                       }
+               } else {
+                       is_in = ep->bEndpointAddress & USB_DIR_IN;
+@@ -1062,7 +1054,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+                               req = NULL;
+                       deselect_ep();
+                       if (!is_in) {
+-                              UDC_CTRL_REG = UDC_SET_FIFO_EN;
++                              omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
+                               ep->ackwait = 1 + ep->double_buf;
+                       }
+                       /* IN: 6 wait states before it'll tx */
+@@ -1129,10 +1121,10 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
+                       status = -EINVAL;
+               else if (value) {
+                       if (ep->udc->ep0_set_config) {
+-                              WARN("error changing config?\n");
+-                              UDC_SYSCON2_REG = UDC_CLR_CFG;
++                              WARNING("error changing config?\n");
++                              omap_writew(UDC_CLR_CFG, UDC_SYSCON2);
+                       }
+-                      UDC_SYSCON2_REG = UDC_STALL_CMD;
++                      omap_writew(UDC_STALL_CMD, UDC_SYSCON2);
+                       ep->udc->ep0_pending = 0;
+                       status = 0;
+               } else /* NOP */
+@@ -1159,8 +1151,8 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
+                               channel = 0;
+                       use_ep(ep, UDC_EP_SEL);
+-                      if (UDC_STAT_FLG_REG & UDC_NON_ISO_FIFO_EMPTY) {
+-                              UDC_CTRL_REG = UDC_SET_HALT;
++                      if (omap_readw(UDC_STAT_FLG) & UDC_NON_ISO_FIFO_EMPTY) {
++                              omap_writew(UDC_SET_HALT, UDC_CTRL);
+                               status = 0;
+                       } else
+                               status = -EAGAIN;
+@@ -1170,10 +1162,10 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
+                               dma_channel_claim(ep, channel);
+               } else {
+                       use_ep(ep, 0);
+-                      UDC_CTRL_REG = ep->udc->clr_halt;
++                      omap_writew(ep->udc->clr_halt, UDC_CTRL);
+                       ep->ackwait = 0;
+                       if (!(ep->bEndpointAddress & USB_DIR_IN)) {
+-                              UDC_CTRL_REG = UDC_SET_FIFO_EN;
++                              omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
+                               ep->ackwait = 1 + ep->double_buf;
+                       }
+               }
+@@ -1205,7 +1197,7 @@ static struct usb_ep_ops omap_ep_ops = {
+ static int omap_get_frame(struct usb_gadget *gadget)
+ {
+-      u16     sof = UDC_SOF_REG;
++      u16     sof = omap_readw(UDC_SOF);
+       return (sof & UDC_TS_OK) ? (sof & UDC_TS) : -EL2NSYNC;
+ }
+@@ -1224,7 +1216,7 @@ static int omap_wakeup(struct usb_gadget *gadget)
+                */
+               if (udc->devstat & (UDC_B_HNP_ENABLE|UDC_R_WK_OK)) {
+                       DBG("remote wakeup...\n");
+-                      UDC_SYSCON2_REG = UDC_RMT_WKP;
++                      omap_writew(UDC_RMT_WKP, UDC_SYSCON2);
+                       retval = 0;
+               }
+@@ -1247,12 +1239,12 @@ omap_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+       udc = container_of(gadget, struct omap_udc, gadget);
+       spin_lock_irqsave(&udc->lock, flags);
+-      syscon1 = UDC_SYSCON1_REG;
++      syscon1 = omap_readw(UDC_SYSCON1);
+       if (is_selfpowered)
+               syscon1 |= UDC_SELF_PWR;
+       else
+               syscon1 &= ~UDC_SELF_PWR;
+-      UDC_SYSCON1_REG = syscon1;
++      omap_writew(syscon1, UDC_SYSCON1);
+       spin_unlock_irqrestore(&udc->lock, flags);
+       return 0;
+@@ -1265,18 +1257,36 @@ static int can_pullup(struct omap_udc *udc)
+ static void pullup_enable(struct omap_udc *udc)
+ {
+-      UDC_SYSCON1_REG |= UDC_PULLUP_EN;
+-      if (!gadget_is_otg(&udc->gadget) && !cpu_is_omap15xx())
+-              OTG_CTRL_REG |= OTG_BSESSVLD;
+-      UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
++      u16 w;
++
++      w = omap_readw(UDC_SYSCON1);
++      w |= UDC_PULLUP_EN;
++      omap_writew(w, UDC_SYSCON1);
++      if (!gadget_is_otg(&udc->gadget) && !cpu_is_omap15xx()) {
++              u32 l;
++
++              l = omap_readl(OTG_CTRL);
++              l |= OTG_BSESSVLD;
++              omap_writel(l, OTG_CTRL);
++      }
++      omap_writew(UDC_DS_CHG_IE, UDC_IRQ_EN);
+ }
+ static void pullup_disable(struct omap_udc *udc)
+ {
+-      if (!gadget_is_otg(&udc->gadget) && !cpu_is_omap15xx())
+-              OTG_CTRL_REG &= ~OTG_BSESSVLD;
+-      UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
+-      UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
++      u16 w;
++
++      if (!gadget_is_otg(&udc->gadget) && !cpu_is_omap15xx()) {
++              u32 l;
++
++              l = omap_readl(OTG_CTRL);
++              l &= ~OTG_BSESSVLD;
++              omap_writel(l, OTG_CTRL);
++      }
++      omap_writew(UDC_DS_CHG_IE, UDC_IRQ_EN);
++      w = omap_readw(UDC_SYSCON1);
++      w &= ~UDC_PULLUP_EN;
++      omap_writew(w, UDC_SYSCON1);
+ }
+ static struct omap_udc *udc;
+@@ -1304,6 +1314,7 @@ static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
+ {
+       struct omap_udc *udc;
+       unsigned long   flags;
++      u32 l;
+       udc = container_of(gadget, struct omap_udc, gadget);
+       spin_lock_irqsave(&udc->lock, flags);
+@@ -1311,10 +1322,12 @@ static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
+       udc->vbus_active = (is_active != 0);
+       if (cpu_is_omap15xx()) {
+               /* "software" detect, ignored if !VBUS_MODE_1510 */
++              l = omap_readl(FUNC_MUX_CTRL_0);
+               if (is_active)
+-                      FUNC_MUX_CTRL_0_REG |= VBUS_CTRL_1510;
++                      l |= VBUS_CTRL_1510;
+               else
+-                      FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
++                      l &= ~VBUS_CTRL_1510;
++              omap_writel(l, FUNC_MUX_CTRL_0);
+       }
+       if (udc->dc_clk != NULL && is_active) {
+               if (!udc->clk_requested) {
+@@ -1384,9 +1397,9 @@ static void nuke(struct omap_ep *ep, int status)
+               dma_channel_release(ep);
+       use_ep(ep, 0);
+-      UDC_CTRL_REG = UDC_CLR_EP;
++      omap_writew(UDC_CLR_EP, UDC_CTRL);
+       if (ep->bEndpointAddress && ep->bmAttributes != USB_ENDPOINT_XFER_ISOC)
+-              UDC_CTRL_REG = UDC_SET_HALT;
++              omap_writew(UDC_SET_HALT, UDC_CTRL);
+       while (!list_empty(&ep->queue)) {
+               req = list_entry(ep->queue.next, struct omap_req, queue);
+@@ -1414,8 +1427,8 @@ static void update_otg(struct omap_udc *udc)
+       if (!gadget_is_otg(&udc->gadget))
+               return;
+-      if (OTG_CTRL_REG & OTG_ID)
+-              devstat = UDC_DEVSTAT_REG;
++      if (omap_readl(OTG_CTRL) & OTG_ID)
++              devstat = omap_readw(UDC_DEVSTAT);
+       else
+               devstat = 0;
+@@ -1426,9 +1439,14 @@ static void update_otg(struct omap_udc *udc)
+       /* Enable HNP early, avoiding races on suspend irq path.
+        * ASSUMES OTG state machine B_BUS_REQ input is true.
+        */
+-      if (udc->gadget.b_hnp_enable)
+-              OTG_CTRL_REG = (OTG_CTRL_REG | OTG_B_HNPEN | OTG_B_BUSREQ)
+-                              & ~OTG_PULLUP;
++      if (udc->gadget.b_hnp_enable) {
++              u32 l;
++
++              l = omap_readl(OTG_CTRL);
++              l |= OTG_B_HNPEN | OTG_B_BUSREQ;
++              l &= ~OTG_PULLUP;
++              omap_writel(l, OTG_CTRL);
++      }
+ }
+ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
+@@ -1446,7 +1464,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
+               nuke(ep0, 0);
+               if (ack) {
+-                      UDC_IRQ_SRC_REG = ack;
++                      omap_writew(ack, UDC_IRQ_SRC);
+                       irq_src = UDC_SETUP;
+               }
+       }
+@@ -1466,9 +1484,9 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
+       if (irq_src & UDC_EP0_TX) {
+               int     stat;
+-              UDC_IRQ_SRC_REG = UDC_EP0_TX;
+-              UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;
+-              stat = UDC_STAT_FLG_REG;
++              omap_writew(UDC_EP0_TX, UDC_IRQ_SRC);
++              omap_writew(UDC_EP_SEL|UDC_EP_DIR, UDC_EP_NUM);
++              stat = omap_readw(UDC_STAT_FLG);
+               if (stat & UDC_ACK) {
+                       if (udc->ep0_in) {
+                               /* write next IN packet from response,
+@@ -1476,26 +1494,26 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
+                                */
+                               if (req)
+                                       stat = write_fifo(ep0, req);
+-                              UDC_EP_NUM_REG = UDC_EP_DIR;
++                              omap_writew(UDC_EP_DIR, UDC_EP_NUM);
+                               if (!req && udc->ep0_pending) {
+-                                      UDC_EP_NUM_REG = UDC_EP_SEL;
+-                                      UDC_CTRL_REG = UDC_CLR_EP;
+-                                      UDC_CTRL_REG = UDC_SET_FIFO_EN;
+-                                      UDC_EP_NUM_REG = 0;
++                                      omap_writew(UDC_EP_SEL, UDC_EP_NUM);
++                                      omap_writew(UDC_CLR_EP, UDC_CTRL);
++                                      omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
++                                      omap_writew(0, UDC_EP_NUM);
+                                       udc->ep0_pending = 0;
+                               } /* else:  6 wait states before it'll tx */
+                       } else {
+                               /* ack status stage of OUT transfer */
+-                              UDC_EP_NUM_REG = UDC_EP_DIR;
++                              omap_writew(UDC_EP_DIR, UDC_EP_NUM);
+                               if (req)
+                                       done(ep0, req, 0);
+                       }
+                       req = NULL;
+               } else if (stat & UDC_STALL) {
+-                      UDC_CTRL_REG = UDC_CLR_HALT;
+-                      UDC_EP_NUM_REG = UDC_EP_DIR;
++                      omap_writew(UDC_CLR_HALT, UDC_CTRL);
++                      omap_writew(UDC_EP_DIR, UDC_EP_NUM);
+               } else {
+-                      UDC_EP_NUM_REG = UDC_EP_DIR;
++                      omap_writew(UDC_EP_DIR, UDC_EP_NUM);
+               }
+       }
+@@ -1503,9 +1521,9 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
+       if (irq_src & UDC_EP0_RX) {
+               int     stat;
+-              UDC_IRQ_SRC_REG = UDC_EP0_RX;
+-              UDC_EP_NUM_REG = UDC_EP_SEL;
+-              stat = UDC_STAT_FLG_REG;
++              omap_writew(UDC_EP0_RX, UDC_IRQ_SRC);
++              omap_writew(UDC_EP_SEL, UDC_EP_NUM);
++              stat = omap_readw(UDC_STAT_FLG);
+               if (stat & UDC_ACK) {
+                       if (!udc->ep0_in) {
+                               stat = 0;
+@@ -1513,34 +1531,35 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
+                                * reactiviting the fifo; stall on errors.
+                                */
+                               if (!req || (stat = read_fifo(ep0, req)) < 0) {
+-                                      UDC_SYSCON2_REG = UDC_STALL_CMD;
++                                      omap_writew(UDC_STALL_CMD, UDC_SYSCON2);
+                                       udc->ep0_pending = 0;
+                                       stat = 0;
+                               } else if (stat == 0)
+-                                      UDC_CTRL_REG = UDC_SET_FIFO_EN;
+-                              UDC_EP_NUM_REG = 0;
++                                      omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
++                              omap_writew(0, UDC_EP_NUM);
+                               /* activate status stage */
+                               if (stat == 1) {
+                                       done(ep0, req, 0);
+                                       /* that may have STALLed ep0... */
+-                                      UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;
+-                                      UDC_CTRL_REG = UDC_CLR_EP;
+-                                      UDC_CTRL_REG = UDC_SET_FIFO_EN;
+-                                      UDC_EP_NUM_REG = UDC_EP_DIR;
++                                      omap_writew(UDC_EP_SEL | UDC_EP_DIR,
++                                                      UDC_EP_NUM);
++                                      omap_writew(UDC_CLR_EP, UDC_CTRL);
++                                      omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
++                                      omap_writew(UDC_EP_DIR, UDC_EP_NUM);
+                                       udc->ep0_pending = 0;
+                               }
+                       } else {
+                               /* ack status stage of IN transfer */
+-                              UDC_EP_NUM_REG = 0;
++                              omap_writew(0, UDC_EP_NUM);
+                               if (req)
+                                       done(ep0, req, 0);
+                       }
+               } else if (stat & UDC_STALL) {
+-                      UDC_CTRL_REG = UDC_CLR_HALT;
+-                      UDC_EP_NUM_REG = 0;
++                      omap_writew(UDC_CLR_HALT, UDC_CTRL);
++                      omap_writew(0, UDC_EP_NUM);
+               } else {
+-                      UDC_EP_NUM_REG = 0;
++                      omap_writew(0, UDC_EP_NUM);
+               }
+       }
+@@ -1555,14 +1574,14 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
+               /* read the (latest) SETUP message */
+               do {
+-                      UDC_EP_NUM_REG = UDC_SETUP_SEL;
++                      omap_writew(UDC_SETUP_SEL, UDC_EP_NUM);
+                       /* two bytes at a time */
+-                      u.word[0] = UDC_DATA_REG;
+-                      u.word[1] = UDC_DATA_REG;
+-                      u.word[2] = UDC_DATA_REG;
+-                      u.word[3] = UDC_DATA_REG;
+-                      UDC_EP_NUM_REG = 0;
+-              } while (UDC_IRQ_SRC_REG & UDC_SETUP);
++                      u.word[0] = omap_readw(UDC_DATA);
++                      u.word[1] = omap_readw(UDC_DATA);
++                      u.word[2] = omap_readw(UDC_DATA);
++                      u.word[3] = omap_readw(UDC_DATA);
++                      omap_writew(0, UDC_EP_NUM);
++              } while (omap_readw(UDC_IRQ_SRC) & UDC_SETUP);
+ #define       w_value         le16_to_cpu(u.r.wValue)
+ #define       w_index         le16_to_cpu(u.r.wIndex)
+@@ -1593,9 +1612,9 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
+                        * later if it fails the request.
+                        */
+                       if (udc->ep0_reset_config)
+-                              UDC_SYSCON2_REG = UDC_CLR_CFG;
++                              omap_writew(UDC_CLR_CFG, UDC_SYSCON2);
+                       else
+-                              UDC_SYSCON2_REG = UDC_DEV_CFG;
++                              omap_writew(UDC_DEV_CFG, UDC_SYSCON2);
+                       update_otg(udc);
+                       goto delegate;
+               case USB_REQ_CLEAR_FEATURE:
+@@ -1613,10 +1632,10 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
+                                               || !ep->desc)
+                                       goto do_stall;
+                               use_ep(ep, 0);
+-                              UDC_CTRL_REG = udc->clr_halt;
++                              omap_writew(udc->clr_halt, UDC_CTRL);
+                               ep->ackwait = 0;
+                               if (!(ep->bEndpointAddress & USB_DIR_IN)) {
+-                                      UDC_CTRL_REG = UDC_SET_FIFO_EN;
++                                      omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
+                                       ep->ackwait = 1 + ep->double_buf;
+                               }
+                               /* NOTE:  assumes the host behaves sanely,
+@@ -1649,15 +1668,15 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
+                       }
+                       use_ep(ep, 0);
+                       /* can't halt if fifo isn't empty... */
+-                      UDC_CTRL_REG = UDC_CLR_EP;
+-                      UDC_CTRL_REG = UDC_SET_HALT;
++                      omap_writew(UDC_CLR_EP, UDC_CTRL);
++                      omap_writew(UDC_SET_HALT, UDC_CTRL);
+                       VDBG("%s halted by host\n", ep->name);
+ ep0out_status_stage:
+                       status = 0;
+-                      UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;
+-                      UDC_CTRL_REG = UDC_CLR_EP;
+-                      UDC_CTRL_REG = UDC_SET_FIFO_EN;
+-                      UDC_EP_NUM_REG = UDC_EP_DIR;
++                      omap_writew(UDC_EP_SEL|UDC_EP_DIR, UDC_EP_NUM);
++                      omap_writew(UDC_CLR_EP, UDC_CTRL);
++                      omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
++                      omap_writew(UDC_EP_DIR, UDC_EP_NUM);
+                       udc->ep0_pending = 0;
+                       break;
+               case USB_REQ_GET_STATUS:
+@@ -1694,10 +1713,10 @@ intf_status:
+ zero_status:
+                       /* return two zero bytes */
+-                      UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;
+-                      UDC_DATA_REG = 0;
+-                      UDC_CTRL_REG = UDC_SET_FIFO_EN;
+-                      UDC_EP_NUM_REG = UDC_EP_DIR;
++                      omap_writew(UDC_EP_SEL|UDC_EP_DIR, UDC_EP_NUM);
++                      omap_writew(0, UDC_DATA);
++                      omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
++                      omap_writew(UDC_EP_DIR, UDC_EP_NUM);
+                       status = 0;
+                       VDBG("GET_STATUS, interface %d\n", w_index);
+                       /* next, status stage */
+@@ -1706,8 +1725,8 @@ zero_status:
+ delegate:
+                       /* activate the ep0out fifo right away */
+                       if (!udc->ep0_in && w_length) {
+-                              UDC_EP_NUM_REG = 0;
+-                              UDC_CTRL_REG = UDC_SET_FIFO_EN;
++                              omap_writew(0, UDC_EP_NUM);
++                              omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
+                       }
+                       /* gadget drivers see class/vendor specific requests,
+@@ -1746,11 +1765,11 @@ do_stall:
+                                       u.r.bRequestType, u.r.bRequest, status);
+                       if (udc->ep0_set_config) {
+                               if (udc->ep0_reset_config)
+-                                      WARN("error resetting config?\n");
++                                      WARNING("error resetting config?\n");
+                               else
+-                                      UDC_SYSCON2_REG = UDC_CLR_CFG;
++                                      omap_writew(UDC_CLR_CFG, UDC_SYSCON2);
+                       }
+-                      UDC_SYSCON2_REG = UDC_STALL_CMD;
++                      omap_writew(UDC_STALL_CMD, UDC_SYSCON2);
+                       udc->ep0_pending = 0;
+               }
+       }
+@@ -1764,7 +1783,7 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
+ {
+       u16     devstat, change;
+-      devstat = UDC_DEVSTAT_REG;
++      devstat = omap_readw(UDC_DEVSTAT);
+       change = devstat ^ udc->devstat;
+       udc->devstat = devstat;
+@@ -1804,7 +1823,8 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
+                               INFO("USB reset done, gadget %s\n",
+                                       udc->driver->driver.name);
+                               /* ep0 traffic is legal from now on */
+-                              UDC_IRQ_EN_REG = UDC_DS_CHG_IE | UDC_EP0_IE;
++                              omap_writew(UDC_DS_CHG_IE | UDC_EP0_IE,
++                                              UDC_IRQ_EN);
+                       }
+                       change &= ~UDC_USB_RESET;
+               }
+@@ -1848,7 +1868,7 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
+               VDBG("devstat %03x, ignore change %03x\n",
+                       devstat,  change);
+-      UDC_IRQ_SRC_REG = UDC_DS_CHG;
++      omap_writew(UDC_DS_CHG, UDC_IRQ_SRC);
+ }
+ static irqreturn_t omap_udc_irq(int irq, void *_udc)
+@@ -1859,7 +1879,7 @@ static irqreturn_t omap_udc_irq(int irq, void *_udc)
+       unsigned long   flags;
+       spin_lock_irqsave(&udc->lock, flags);
+-      irq_src = UDC_IRQ_SRC_REG;
++      irq_src = omap_readw(UDC_IRQ_SRC);
+       /* Device state change (usb ch9 stuff) */
+       if (irq_src & UDC_DS_CHG) {
+@@ -1882,7 +1902,7 @@ static irqreturn_t omap_udc_irq(int irq, void *_udc)
+               irq_src &= ~(UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT);
+       }
+-      irq_src &= ~(UDC_SOF|UDC_EPN_TX|UDC_EPN_RX);
++      irq_src &= ~(UDC_IRQ_SOF | UDC_EPN_TX|UDC_EPN_RX);
+       if (irq_src)
+               DBG("udc_irq, unhandled %03x\n", irq_src);
+       spin_unlock_irqrestore(&udc->lock, flags);
+@@ -1903,7 +1923,7 @@ static void pio_out_timer(unsigned long _ep)
+       spin_lock_irqsave(&ep->udc->lock, flags);
+       if (!list_empty(&ep->queue) && ep->ackwait) {
+               use_ep(ep, UDC_EP_SEL);
+-              stat_flg = UDC_STAT_FLG_REG;
++              stat_flg = omap_readw(UDC_STAT_FLG);
+               if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN)
+                               || (ep->double_buf && HALF_FULL(stat_flg)))) {
+@@ -1913,8 +1933,8 @@ static void pio_out_timer(unsigned long _ep)
+                       req = container_of(ep->queue.next,
+                                       struct omap_req, queue);
+                       (void) read_fifo(ep, req);
+-                      UDC_EP_NUM_REG = ep->bEndpointAddress;
+-                      UDC_CTRL_REG = UDC_SET_FIFO_EN;
++                      omap_writew(ep->bEndpointAddress, UDC_EP_NUM);
++                      omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
+                       ep->ackwait = 1 + ep->double_buf;
+               } else
+                       deselect_ep();
+@@ -1934,20 +1954,20 @@ static irqreturn_t omap_udc_pio_irq(int irq, void *_dev)
+       unsigned long   flags;
+       spin_lock_irqsave(&udc->lock, flags);
+-      epn_stat = UDC_EPN_STAT_REG;
+-      irq_src = UDC_IRQ_SRC_REG;
++      epn_stat = omap_readw(UDC_EPN_STAT);
++      irq_src = omap_readw(UDC_IRQ_SRC);
+       /* handle OUT first, to avoid some wasteful NAKs */
+       if (irq_src & UDC_EPN_RX) {
+               epnum = (epn_stat >> 8) & 0x0f;
+-              UDC_IRQ_SRC_REG = UDC_EPN_RX;
++              omap_writew(UDC_EPN_RX, UDC_IRQ_SRC);
+               status = IRQ_HANDLED;
+               ep = &udc->ep[epnum];
+               ep->irqs++;
+-              UDC_EP_NUM_REG = epnum | UDC_EP_SEL;
++              omap_writew(epnum | UDC_EP_SEL, UDC_EP_NUM);
+               ep->fnf = 0;
+-              if ((UDC_STAT_FLG_REG & UDC_ACK)) {
++              if (omap_readw(UDC_STAT_FLG) & UDC_ACK) {
+                       ep->ackwait--;
+                       if (!list_empty(&ep->queue)) {
+                               int stat;
+@@ -1959,15 +1979,15 @@ static irqreturn_t omap_udc_pio_irq(int irq, void *_dev)
+                       }
+               }
+               /* min 6 clock delay before clearing EP_SEL ... */
+-              epn_stat = UDC_EPN_STAT_REG;
+-              epn_stat = UDC_EPN_STAT_REG;
+-              UDC_EP_NUM_REG = epnum;
++              epn_stat = omap_readw(UDC_EPN_STAT);
++              epn_stat = omap_readw(UDC_EPN_STAT);
++              omap_writew(epnum, UDC_EP_NUM);
+               /* enabling fifo _after_ clearing ACK, contrary to docs,
+                * reduces lossage; timer still needed though (sigh).
+                */
+               if (ep->fnf) {
+-                      UDC_CTRL_REG = UDC_SET_FIFO_EN;
++                      omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
+                       ep->ackwait = 1 + ep->double_buf;
+               }
+               mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
+@@ -1976,13 +1996,13 @@ static irqreturn_t omap_udc_pio_irq(int irq, void *_dev)
+       /* then IN transfers */
+       else if (irq_src & UDC_EPN_TX) {
+               epnum = epn_stat & 0x0f;
+-              UDC_IRQ_SRC_REG = UDC_EPN_TX;
++              omap_writew(UDC_EPN_TX, UDC_IRQ_SRC);
+               status = IRQ_HANDLED;
+               ep = &udc->ep[16 + epnum];
+               ep->irqs++;
+-              UDC_EP_NUM_REG = epnum | UDC_EP_DIR | UDC_EP_SEL;
+-              if ((UDC_STAT_FLG_REG & UDC_ACK)) {
++              omap_writew(epnum | UDC_EP_DIR | UDC_EP_SEL, UDC_EP_NUM);
++              if (omap_readw(UDC_STAT_FLG) & UDC_ACK) {
+                       ep->ackwait = 0;
+                       if (!list_empty(&ep->queue)) {
+                               req = container_of(ep->queue.next,
+@@ -1991,9 +2011,9 @@ static irqreturn_t omap_udc_pio_irq(int irq, void *_dev)
+                       }
+               }
+               /* min 6 clock delay before clearing EP_SEL ... */
+-              epn_stat = UDC_EPN_STAT_REG;
+-              epn_stat = UDC_EPN_STAT_REG;
+-              UDC_EP_NUM_REG = epnum | UDC_EP_DIR;
++              epn_stat = omap_readw(UDC_EPN_STAT);
++              epn_stat = omap_readw(UDC_EPN_STAT);
++              omap_writew(epnum | UDC_EP_DIR, UDC_EP_NUM);
+               /* then 6 clocks before it'd tx */
+       }
+@@ -2021,7 +2041,7 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
+               req = list_entry(ep->queue.next, struct omap_req, queue);
+               use_ep(ep, UDC_EP_SEL);
+-              stat = UDC_STAT_FLG_REG;
++              stat = omap_readw(UDC_STAT_FLG);
+               /* NOTE: like the other controller drivers, this isn't
+                * currently reporting lost or damaged frames.
+@@ -2053,9 +2073,14 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
+               if (!list_empty(&ep->queue))
+                       pending = 1;
+       }
+-      if (!pending)
+-              UDC_IRQ_EN_REG &= ~UDC_SOF_IE;
+-      UDC_IRQ_SRC_REG = UDC_SOF;
++      if (!pending) {
++              u16 w;
++
++              w = omap_readw(UDC_IRQ_EN);
++              w &= ~UDC_SOF_IE;
++              omap_writew(w, UDC_IRQ_EN);
++      }
++      omap_writew(UDC_IRQ_SOF, UDC_IRQ_SRC);
+       spin_unlock_irqrestore(&udc->lock, flags);
+       return IRQ_HANDLED;
+@@ -2104,7 +2129,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+               if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
+                       continue;
+               use_ep(ep, 0);
+-              UDC_CTRL_REG = UDC_SET_HALT;
++              omap_writew(UDC_SET_HALT, UDC_CTRL);
+       }
+       udc->ep0_pending = 0;
+       udc->ep[0].irqs = 0;
+@@ -2128,7 +2153,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+       }
+       DBG("bound to driver %s\n", driver->driver.name);
+-      UDC_IRQ_SRC_REG = UDC_IRQ_SRC_MASK;
++      omap_writew(UDC_IRQ_SRC_MASK, UDC_IRQ_SRC);
+       /* connect to bus through transceiver */
+       if (udc->transceiver) {
+@@ -2225,7 +2250,7 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
+       else
+               buf[0] = 0;
+-      stat_flg = UDC_STAT_FLG_REG;
++      stat_flg = omap_readw(UDC_STAT_FLG);
+       seq_printf(s,
+               "\n%s %s%s%sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n",
+               ep->name, buf,
+@@ -2286,17 +2311,17 @@ static int proc_otg_show(struct seq_file *s)
+       u32             trans;
+       char            *ctrl_name;
+-      tmp = OTG_REV_REG;
++      tmp = omap_readl(OTG_REV);
+       if (cpu_is_omap24xx()) {
+               ctrl_name = "control_devconf";
+-              trans = CONTROL_DEVCONF_REG;
++              trans = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+       } else {
+               ctrl_name = "tranceiver_ctrl";
+-              trans = USB_TRANSCEIVER_CTRL_REG;
++              trans = omap_readw(USB_TRANSCEIVER_CTRL);
+       }
+       seq_printf(s, "\nOTG rev %d.%d, %s %05x\n",
+               tmp >> 4, tmp & 0xf, ctrl_name, trans);
+-      tmp = OTG_SYSCON_1_REG;
++      tmp = omap_readw(OTG_SYSCON_1);
+       seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s,"
+                       FOURBITS "\n", tmp,
+               trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R),
+@@ -2308,7 +2333,7 @@ static int proc_otg_show(struct seq_file *s)
+               (tmp & HST_IDLE_EN) ? " !host" : "",
+               (tmp & DEV_IDLE_EN) ? " !dev" : "",
+               (tmp & OTG_RESET_DONE) ? " reset_done" : " reset_active");
+-      tmp = OTG_SYSCON_2_REG;
++      tmp = omap_readl(OTG_SYSCON_2);
+       seq_printf(s, "otg_syscon2 %08x%s" EIGHTBITS
+                       " b_ase_brst=%d hmc=%d\n", tmp,
+               (tmp & OTG_EN) ? " otg_en" : "",
+@@ -2323,7 +2348,7 @@ static int proc_otg_show(struct seq_file *s)
+               (tmp & HMC_TLLATTACH) ? " tllattach" : "",
+               B_ASE_BRST(tmp),
+               OTG_HMC(tmp));
+-      tmp = OTG_CTRL_REG;
++      tmp = omap_readl(OTG_CTRL);
+       seq_printf(s, "otg_ctrl    %06x" EIGHTBITS EIGHTBITS "%s\n", tmp,
+               (tmp & OTG_ASESSVLD) ? " asess" : "",
+               (tmp & OTG_BSESSEND) ? " bsess_end" : "",
+@@ -2343,13 +2368,13 @@ static int proc_otg_show(struct seq_file *s)
+               (tmp & OTG_PU_VBUS) ? " pu_vb" : "",
+               (tmp & OTG_PU_ID) ? " pu_id" : ""
+               );
+-      tmp = OTG_IRQ_EN_REG;
++      tmp = omap_readw(OTG_IRQ_EN);
+       seq_printf(s, "otg_irq_en  %04x" "\n", tmp);
+-      tmp = OTG_IRQ_SRC_REG;
++      tmp = omap_readw(OTG_IRQ_SRC);
+       seq_printf(s, "otg_irq_src %04x" "\n", tmp);
+-      tmp = OTG_OUTCTRL_REG;
++      tmp = omap_readw(OTG_OUTCTRL);
+       seq_printf(s, "otg_outctrl %04x" "\n", tmp);
+-      tmp = OTG_TEST_REG;
++      tmp = omap_readw(OTG_TEST);
+       seq_printf(s, "otg_test    %04x" "\n", tmp);
+       return 0;
+ }
+@@ -2370,7 +2395,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
+               driver_desc,
+               use_dma ?  " (dma)" : "");
+-      tmp = UDC_REV_REG & 0xff;
++      tmp = omap_readw(UDC_REV) & 0xff;
+       seq_printf(s,
+               "UDC rev %d.%d, fifo mode %d, gadget %s\n"
+               "hmc %d, transceiver %s\n",
+@@ -2384,16 +2409,16 @@ static int proc_udc_show(struct seq_file *s, void *_)
+                               ? "external" : "(none)"));
+       if (cpu_class_is_omap1()) {
+               seq_printf(s, "ULPD control %04x req %04x status %04x\n",
+-                      __REG16(ULPD_CLOCK_CTRL),
+-                      __REG16(ULPD_SOFT_REQ),
+-                      __REG16(ULPD_STATUS_REQ));
++                      omap_readw(ULPD_CLOCK_CTRL),
++                      omap_readw(ULPD_SOFT_REQ),
++                      omap_readw(ULPD_STATUS_REQ));
+       }
+       /* OTG controller registers */
+       if (!cpu_is_omap15xx())
+               proc_otg_show(s);
+-      tmp = UDC_SYSCON1_REG;
++      tmp = omap_readw(UDC_SYSCON1);
+       seq_printf(s, "\nsyscon1     %04x" EIGHTBITS "\n", tmp,
+               (tmp & UDC_CFG_LOCK) ? " cfg_lock" : "",
+               (tmp & UDC_DATA_ENDIAN) ? " data_endian" : "",
+@@ -2412,7 +2437,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
+               return 0;
+       }
+-      tmp = UDC_DEVSTAT_REG;
++      tmp = omap_readw(UDC_DEVSTAT);
+       seq_printf(s, "devstat     %04x" EIGHTBITS "%s%s\n", tmp,
+               (tmp & UDC_B_HNP_ENABLE) ? " b_hnp" : "",
+               (tmp & UDC_A_HNP_SUPPORT) ? " a_hnp" : "",
+@@ -2424,20 +2449,20 @@ static int proc_udc_show(struct seq_file *s, void *_)
+               (tmp & UDC_ADD) ? " ADD" : "",
+               (tmp & UDC_DEF) ? " DEF" : "",
+               (tmp & UDC_ATT) ? " ATT" : "");
+-      seq_printf(s, "sof         %04x\n", UDC_SOF_REG);
+-      tmp = UDC_IRQ_EN_REG;
++      seq_printf(s, "sof         %04x\n", omap_readw(UDC_SOF));
++      tmp = omap_readw(UDC_IRQ_EN);
+       seq_printf(s, "irq_en      %04x" FOURBITS "%s\n", tmp,
+               (tmp & UDC_SOF_IE) ? " sof" : "",
+               (tmp & UDC_EPN_RX_IE) ? " epn_rx" : "",
+               (tmp & UDC_EPN_TX_IE) ? " epn_tx" : "",
+               (tmp & UDC_DS_CHG_IE) ? " ds_chg" : "",
+               (tmp & UDC_EP0_IE) ? " ep0" : "");
+-      tmp = UDC_IRQ_SRC_REG;
++      tmp = omap_readw(UDC_IRQ_SRC);
+       seq_printf(s, "irq_src     %04x" EIGHTBITS "%s%s\n", tmp,
+               (tmp & UDC_TXN_DONE) ? " txn_done" : "",
+               (tmp & UDC_RXN_CNT) ? " rxn_cnt" : "",
+               (tmp & UDC_RXN_EOT) ? " rxn_eot" : "",
+-              (tmp & UDC_SOF) ? " sof" : "",
++              (tmp & UDC_IRQ_SOF) ? " sof" : "",
+               (tmp & UDC_EPN_RX) ? " epn_rx" : "",
+               (tmp & UDC_EPN_TX) ? " epn_tx" : "",
+               (tmp & UDC_DS_CHG) ? " ds_chg" : "",
+@@ -2447,7 +2472,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
+       if (use_dma) {
+               unsigned i;
+-              tmp = UDC_DMA_IRQ_EN_REG;
++              tmp = omap_readw(UDC_DMA_IRQ_EN);
+               seq_printf(s, "dma_irq_en  %04x%s" EIGHTBITS "\n", tmp,
+                       (tmp & UDC_TX_DONE_IE(3)) ? " tx2_done" : "",
+                       (tmp & UDC_RX_CNT_IE(3)) ? " rx2_cnt" : "",
+@@ -2461,29 +2486,29 @@ static int proc_udc_show(struct seq_file *s, void *_)
+                       (tmp & UDC_RX_CNT_IE(1)) ? " rx0_cnt" : "",
+                       (tmp & UDC_RX_EOT_IE(1)) ? " rx0_eot" : "");
+-              tmp = UDC_RXDMA_CFG_REG;
++              tmp = omap_readw(UDC_RXDMA_CFG);
+               seq_printf(s, "rxdma_cfg   %04x\n", tmp);
+               if (tmp) {
+                       for (i = 0; i < 3; i++) {
+                               if ((tmp & (0x0f << (i * 4))) == 0)
+                                       continue;
+                               seq_printf(s, "rxdma[%d]    %04x\n", i,
+-                                              UDC_RXDMA_REG(i + 1));
++                                              omap_readw(UDC_RXDMA(i + 1)));
+                       }
+               }
+-              tmp = UDC_TXDMA_CFG_REG;
++              tmp = omap_readw(UDC_TXDMA_CFG);
+               seq_printf(s, "txdma_cfg   %04x\n", tmp);
+               if (tmp) {
+                       for (i = 0; i < 3; i++) {
+                               if (!(tmp & (0x0f << (i * 4))))
+                                       continue;
+                               seq_printf(s, "txdma[%d]    %04x\n", i,
+-                                              UDC_TXDMA_REG(i + 1));
++                                              omap_readw(UDC_TXDMA(i + 1)));
+                       }
+               }
+       }
+-      tmp = UDC_DEVSTAT_REG;
++      tmp = omap_readw(UDC_DEVSTAT);
+       if (tmp & UDC_ATT) {
+               proc_ep_show(s, &udc->ep[0]);
+               if (tmp & UDC_ADD) {
+@@ -2535,7 +2560,7 @@ static inline void remove_proc_file(void) {}
+  * buffer space among the endpoints we'll be operating.
+  *
+  * NOTE: as of OMAP 1710 ES2.0, writing a new endpoint config when
+- * UDC_SYSCON_1_REG.CFG_LOCK is set can now work.  We won't use that
++ * UDC_SYSCON_1.CFG_LOCK is set can now work.  We won't use that
+  * capability yet though.
+  */
+ static unsigned __init
+@@ -2597,9 +2622,9 @@ omap_ep_setup(char *name, u8 addr, u8 type,
+               name, addr, epn_rxtx, maxp, dbuf ? "x2" : "", buf);
+       if (addr & USB_DIR_IN)
+-              UDC_EP_TX_REG(addr & 0xf) = epn_rxtx;
++              omap_writew(epn_rxtx, UDC_EP_TX(addr & 0xf));
+       else
+-              UDC_EP_RX_REG(addr) = epn_rxtx;
++              omap_writew(epn_rxtx, UDC_EP_RX(addr));
+       /* next endpoint's buffer starts after this one's */
+       buf += maxp;
+@@ -2638,15 +2663,15 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
+       unsigned        tmp, buf;
+       /* abolish any previous hardware state */
+-      UDC_SYSCON1_REG = 0;
+-      UDC_IRQ_EN_REG = 0;
+-      UDC_IRQ_SRC_REG = UDC_IRQ_SRC_MASK;
+-      UDC_DMA_IRQ_EN_REG = 0;
+-      UDC_RXDMA_CFG_REG = 0;
+-      UDC_TXDMA_CFG_REG = 0;
++      omap_writew(0, UDC_SYSCON1);
++      omap_writew(0, UDC_IRQ_EN);
++      omap_writew(UDC_IRQ_SRC_MASK, UDC_IRQ_SRC);
++      omap_writew(0, UDC_DMA_IRQ_EN);
++      omap_writew(0, UDC_RXDMA_CFG);
++      omap_writew(0, UDC_TXDMA_CFG);
+       /* UDC_PULLUP_EN gates the chip clock */
+-      // OTG_SYSCON_1_REG |= DEV_IDLE_EN;
++      // OTG_SYSCON_1 |= DEV_IDLE_EN;
+       udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+       if (!udc)
+@@ -2662,7 +2687,7 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
+       udc->gadget.name = driver_name;
+       device_initialize(&udc->gadget.dev);
+-      strcpy (udc->gadget.dev.bus_id, "gadget");
++      dev_set_name(&udc->gadget.dev, "gadget");
+       udc->gadget.dev.release = omap_udc_release;
+       udc->gadget.dev.parent = &odev->dev;
+       if (use_dma)
+@@ -2677,8 +2702,8 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
+       /* initially disable all non-ep0 endpoints */
+       for (tmp = 1; tmp < 15; tmp++) {
+-              UDC_EP_RX_REG(tmp) = 0;
+-              UDC_EP_TX_REG(tmp) = 0;
++              omap_writew(0, UDC_EP_RX(tmp));
++              omap_writew(0, UDC_EP_TX(tmp));
+       }
+ #define OMAP_BULK_EP(name,addr) \
+@@ -2763,7 +2788,7 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
+               ERR("unsupported fifo_mode #%d\n", fifo_mode);
+               return -ENODEV;
+       }
+-      UDC_SYSCON1_REG = UDC_CFG_LOCK|UDC_SELF_PWR;
++      omap_writew(UDC_CFG_LOCK|UDC_SELF_PWR, UDC_SYSCON1);
+       INFO("fifo mode %d, %d bytes not used\n", fifo_mode, 2048 - buf);
+       return 0;
+ }
+@@ -2807,7 +2832,7 @@ static int __init omap_udc_probe(struct platform_device *pdev)
+       }
+       INFO("OMAP UDC rev %d.%d%s\n",
+-              UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
++              omap_readw(UDC_REV) >> 4, omap_readw(UDC_REV) & 0xf,
+               config->otg ? ", Mini-AB" : "");
+       /* use the mode given to us by board init code */
+@@ -2822,12 +2847,12 @@ static int __init omap_udc_probe(struct platform_device *pdev)
+                        * know when to turn PULLUP_EN on/off; and that
+                        * means we always "need" the 48MHz clock.
+                        */
+-                      u32 tmp = FUNC_MUX_CTRL_0_REG;
+-
+-                      FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
++                      u32 tmp = omap_readl(FUNC_MUX_CTRL_0);
++                      tmp &= ~VBUS_CTRL_1510;
++                      omap_writel(tmp, FUNC_MUX_CTRL_0);
+                       tmp |= VBUS_MODE_1510;
+                       tmp &= ~VBUS_CTRL_1510;
+-                      FUNC_MUX_CTRL_0_REG = tmp;
++                      omap_writel(tmp, FUNC_MUX_CTRL_0);
+               }
+       } else {
+               /* The transceiver may package some GPIO logic or handle
+@@ -2907,7 +2932,7 @@ known:
+ #endif
+       /* starting with omap1710 es2.0, clear toggle is a separate bit */
+-      if (UDC_REV_REG >= 0x61)
++      if (omap_readw(UDC_REV) >= 0x61)
+               udc->clr_halt = UDC_RESET_EP | UDC_CLRDATA_TOGGLE;
+       else
+               udc->clr_halt = UDC_RESET_EP;
+@@ -3005,7 +3030,7 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
+               put_device(udc->transceiver->dev);
+               udc->transceiver = NULL;
+       }
+-      UDC_SYSCON1_REG = 0;
++      omap_writew(0, UDC_SYSCON1);
+       remove_proc_file();
+@@ -3036,7 +3061,7 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
+  *
+  * REVISIT we should probably reject suspend requests when there's a host
+  * session active, rather than disconnecting, at least on boards that can
+- * report VBUS irqs (UDC_DEVSTAT_REG.UDC_ATT).  And in any case, we need to
++ * report VBUS irqs (UDC_DEVSTAT.UDC_ATT).  And in any case, we need to
+  * make host resumes and VBUS detection trigger OMAP wakeup events; that
+  * may involve talking to an external transceiver (e.g. isp1301).
+  */
+@@ -3045,14 +3070,14 @@ static int omap_udc_suspend(struct platform_device *dev, pm_message_t message)
+ {
+       u32     devstat;
+-      devstat = UDC_DEVSTAT_REG;
++      devstat = omap_readw(UDC_DEVSTAT);
+       /* we're requesting 48 MHz clock if the pullup is enabled
+        * (== we're attached to the host) and we're not suspended,
+        * which would prevent entry to deep sleep...
+        */
+       if ((devstat & UDC_ATT) != 0 && (devstat & UDC_SUS) == 0) {
+-              WARN("session active; suspend requires disconnect\n");
++              WARNING("session active; suspend requires disconnect\n");
+               omap_pullup(&udc->gadget, 0);
+       }
+diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
+index c6b9cbc..29edc51 100644
+--- a/drivers/usb/gadget/omap_udc.h
++++ b/drivers/usb/gadget/omap_udc.h
+@@ -8,23 +8,22 @@
+ /*
+  * USB device/endpoint management registers
+  */
+-#define UDC_REG(offset)              __REG16(UDC_BASE + (offset))
+-#define       UDC_REV_REG                     UDC_REG(0x0)    /* Revision */
+-#define       UDC_EP_NUM_REG                  UDC_REG(0x4)    /* Which endpoint */
++#define       UDC_REV                         (UDC_BASE + 0x0)        /* Revision */
++#define       UDC_EP_NUM                      (UDC_BASE + 0x4)        /* Which endpoint */
+ #     define  UDC_SETUP_SEL           (1 << 6)
+ #     define  UDC_EP_SEL              (1 << 5)
+ #     define  UDC_EP_DIR              (1 << 4)
+       /* low 4 bits for endpoint number */
+-#define       UDC_DATA_REG                    UDC_REG(0x08)   /* Endpoint FIFO */
+-#define       UDC_CTRL_REG                    UDC_REG(0x0C)   /* Endpoint control */
++#define       UDC_DATA                        (UDC_BASE + 0x08)       /* Endpoint FIFO */
++#define       UDC_CTRL                        (UDC_BASE + 0x0C)       /* Endpoint control */
+ #     define  UDC_CLR_HALT            (1 << 7)
+ #     define  UDC_SET_HALT            (1 << 6)
+ #     define  UDC_CLRDATA_TOGGLE      (1 << 3)
+ #     define  UDC_SET_FIFO_EN         (1 << 2)
+ #     define  UDC_CLR_EP              (1 << 1)
+ #     define  UDC_RESET_EP            (1 << 0)
+-#define       UDC_STAT_FLG_REG                UDC_REG(0x10)   /* Endpoint status */
++#define       UDC_STAT_FLG                    (UDC_BASE + 0x10)       /* Endpoint status */
+ #     define  UDC_NO_RXPACKET         (1 << 15)
+ #     define  UDC_MISS_IN             (1 << 14)
+ #     define  UDC_DATA_FLUSH          (1 << 13)
+@@ -38,8 +37,8 @@
+ #     define  UDC_FIFO_EN             (1 << 2)
+ #     define  UDC_NON_ISO_FIFO_EMPTY  (1 << 1)
+ #     define  UDC_NON_ISO_FIFO_FULL   (1 << 0)
+-#define       UDC_RXFSTAT_REG                 UDC_REG(0x14)   /* OUT bytecount */
+-#define       UDC_SYSCON1_REG                 UDC_REG(0x18)   /* System config 1 */
++#define       UDC_RXFSTAT                     (UDC_BASE + 0x14)       /* OUT bytecount */
++#define       UDC_SYSCON1                     (UDC_BASE + 0x18)       /* System config 1 */
+ #     define  UDC_CFG_LOCK            (1 << 8)
+ #     define  UDC_DATA_ENDIAN         (1 << 7)
+ #     define  UDC_DMA_ENDIAN          (1 << 6)
+@@ -48,12 +47,12 @@
+ #     define  UDC_SELF_PWR            (1 << 2)
+ #     define  UDC_SOFF_DIS            (1 << 1)
+ #     define  UDC_PULLUP_EN           (1 << 0)
+-#define       UDC_SYSCON2_REG                 UDC_REG(0x1C)   /* System config 2 */
++#define       UDC_SYSCON2                     (UDC_BASE + 0x1C)       /* System config 2 */
+ #     define  UDC_RMT_WKP             (1 << 6)
+ #     define  UDC_STALL_CMD           (1 << 5)
+ #     define  UDC_DEV_CFG             (1 << 3)
+ #     define  UDC_CLR_CFG             (1 << 2)
+-#define       UDC_DEVSTAT_REG                 UDC_REG(0x20)   /* Device status */
++#define       UDC_DEVSTAT                     (UDC_BASE + 0x20)       /* Device status */
+ #     define  UDC_B_HNP_ENABLE        (1 << 9)
+ #     define  UDC_A_HNP_SUPPORT       (1 << 8)
+ #     define  UDC_A_ALT_HNP_SUPPORT   (1 << 7)
+@@ -64,26 +63,26 @@
+ #     define  UDC_ADD                 (1 << 2)
+ #     define  UDC_DEF                 (1 << 1)
+ #     define  UDC_ATT                 (1 << 0)
+-#define       UDC_SOF_REG                     UDC_REG(0x24)   /* Start of frame */
++#define       UDC_SOF                         (UDC_BASE + 0x24)       /* Start of frame */
+ #     define  UDC_FT_LOCK             (1 << 12)
+ #     define  UDC_TS_OK               (1 << 11)
+ #     define  UDC_TS                  0x03ff
+-#define       UDC_IRQ_EN_REG                  UDC_REG(0x28)   /* Interrupt enable */
++#define       UDC_IRQ_EN                      (UDC_BASE + 0x28)       /* Interrupt enable */
+ #     define  UDC_SOF_IE              (1 << 7)
+ #     define  UDC_EPN_RX_IE           (1 << 5)
+ #     define  UDC_EPN_TX_IE           (1 << 4)
+ #     define  UDC_DS_CHG_IE           (1 << 3)
+ #     define  UDC_EP0_IE              (1 << 0)
+-#define       UDC_DMA_IRQ_EN_REG              UDC_REG(0x2C)   /* DMA irq enable */
++#define       UDC_DMA_IRQ_EN                  (UDC_BASE + 0x2C)       /* DMA irq enable */
+       /* rx/tx dma channels numbered 1-3 not 0-2 */
+ #     define  UDC_TX_DONE_IE(n)       (1 << (4 * (n) - 2))
+ #     define  UDC_RX_CNT_IE(n)        (1 << (4 * (n) - 3))
+ #     define  UDC_RX_EOT_IE(n)        (1 << (4 * (n) - 4))
+-#define       UDC_IRQ_SRC_REG                 UDC_REG(0x30)   /* Interrupt source */
++#define       UDC_IRQ_SRC                     (UDC_BASE + 0x30)       /* Interrupt source */
+ #     define  UDC_TXN_DONE            (1 << 10)
+ #     define  UDC_RXN_CNT             (1 << 9)
+ #     define  UDC_RXN_EOT             (1 << 8)
+-#     define  UDC_SOF                 (1 << 7)
++#     define  UDC_IRQ_SOF             (1 << 7)
+ #     define  UDC_EPN_RX              (1 << 5)
+ #     define  UDC_EPN_TX              (1 << 4)
+ #     define  UDC_DS_CHG              (1 << 3)
+@@ -91,41 +90,41 @@
+ #     define  UDC_EP0_RX              (1 << 1)
+ #     define  UDC_EP0_TX              (1 << 0)
+ #     define  UDC_IRQ_SRC_MASK        0x7bf
+-#define       UDC_EPN_STAT_REG                UDC_REG(0x34)   /* EP irq status */
+-#define       UDC_DMAN_STAT_REG               UDC_REG(0x38)   /* DMA irq status */
++#define       UDC_EPN_STAT                    (UDC_BASE + 0x34)       /* EP irq status */
++#define       UDC_DMAN_STAT                   (UDC_BASE + 0x38)       /* DMA irq status */
+ #     define  UDC_DMA_RX_SB           (1 << 12)
+ #     define  UDC_DMA_RX_SRC(x)       (((x)>>8) & 0xf)
+ #     define  UDC_DMA_TX_SRC(x)       (((x)>>0) & 0xf)
+ /* DMA configuration registers:  up to three channels in each direction.  */
+-#define       UDC_RXDMA_CFG_REG               UDC_REG(0x40)   /* 3 eps for RX DMA */
++#define       UDC_RXDMA_CFG                   (UDC_BASE + 0x40)       /* 3 eps for RX DMA */
+ #     define  UDC_DMA_REQ             (1 << 12)
+-#define       UDC_TXDMA_CFG_REG               UDC_REG(0x44)   /* 3 eps for TX DMA */
+-#define       UDC_DATA_DMA_REG                UDC_REG(0x48)   /* rx/tx fifo addr */
++#define       UDC_TXDMA_CFG                   (UDC_BASE + 0x44)       /* 3 eps for TX DMA */
++#define       UDC_DATA_DMA                    (UDC_BASE + 0x48)       /* rx/tx fifo addr */
+ /* rx/tx dma control, numbering channels 1-3 not 0-2 */
+-#define       UDC_TXDMA_REG(chan)             UDC_REG(0x50 - 4 + 4 * (chan))
++#define       UDC_TXDMA(chan)                 (UDC_BASE + 0x50 - 4 + 4 * (chan))
+ #     define UDC_TXN_EOT              (1 << 15)       /* bytes vs packets */
+ #     define UDC_TXN_START            (1 << 14)       /* start transfer */
+ #     define UDC_TXN_TSC              0x03ff          /* units in xfer */
+-#define       UDC_RXDMA_REG(chan)             UDC_REG(0x60 - 4 + 4 * (chan))
++#define       UDC_RXDMA(chan)                 (UDC_BASE + 0x60 - 4 + 4 * (chan))
+ #     define UDC_RXN_STOP             (1 << 15)       /* enable EOT irq */
+ #     define UDC_RXN_TC               0x00ff          /* packets in xfer */
+ /*
+  * Endpoint configuration registers (used before CFG_LOCK is set)
+- * UDC_EP_TX_REG(0) is unused
++ * UDC_EP_TX(0) is unused
+  */
+-#define       UDC_EP_RX_REG(endpoint)         UDC_REG(0x80 + (endpoint)*4)
++#define       UDC_EP_RX(endpoint)             (UDC_BASE + 0x80 + (endpoint)*4)
+ #     define  UDC_EPN_RX_VALID        (1 << 15)
+ #     define  UDC_EPN_RX_DB           (1 << 14)
+       /* buffer size in bits 13, 12 */
+ #     define  UDC_EPN_RX_ISO          (1 << 11)
+       /* buffer pointer in low 11 bits */
+-#define       UDC_EP_TX_REG(endpoint)         UDC_REG(0xc0 + (endpoint)*4)
+-      /* same bitfields as in RX_REG */
++#define       UDC_EP_TX(endpoint)             (UDC_BASE + 0xc0 + (endpoint)*4)
++      /* same bitfields as in RX */
+ /*-------------------------------------------------------------------------*/
+@@ -189,20 +188,20 @@ struct omap_udc {
+ #endif
+ #define ERR(stuff...)         pr_err("udc: " stuff)
+-#define WARN(stuff...)                pr_warning("udc: " stuff)
++#define WARNING(stuff...)     pr_warning("udc: " stuff)
+ #define INFO(stuff...)                pr_info("udc: " stuff)
+ #define DBG(stuff...)         pr_debug("udc: " stuff)
+ /*-------------------------------------------------------------------------*/
+-#define       MOD_CONF_CTRL_0_REG     __REG32(MOD_CONF_CTRL_0)
+-#define       VBUS_W2FC_1510          (1 << 17)       /* 0 gpio0, 1 dvdd2 pin */
++/* MOD_CONF_CTRL_0 */
++#define VBUS_W2FC_1510                (1 << 17)       /* 0 gpio0, 1 dvdd2 pin */
+-#define       FUNC_MUX_CTRL_0_REG     __REG32(FUNC_MUX_CTRL_0)
++/* FUNC_MUX_CTRL_0 */
+ #define       VBUS_CTRL_1510          (1 << 19)       /* 1 connected (software) */
+ #define       VBUS_MODE_1510          (1 << 18)       /* 0 hardware, 1 software */
+-#define       HMC_1510        ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f)
+-#define       HMC_1610        (OTG_SYSCON_2_REG & 0x3f)
++#define       HMC_1510        ((omap_readl(MOD_CONF_CTRL_0) >> 1) & 0x3f)
++#define       HMC_1610        (omap_readl(OTG_SYSCON_2) & 0x3f)
+ #define       HMC             (cpu_is_omap15xx() ? HMC_1510 : HMC_1610)
+diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
+index 76be75e..e009008 100644
+--- a/drivers/usb/gadget/printer.c
++++ b/drivers/usb/gadget/printer.c
+@@ -179,7 +179,7 @@ module_param(qlen, uint, S_IRUGO|S_IWUSR);
+ #define ERROR(dev, fmt, args...) \
+       xprintk(dev, KERN_ERR, fmt, ## args)
+-#define WARN(dev, fmt, args...) \
++#define WARNING(dev, fmt, args...) \
+       xprintk(dev, KERN_WARNING, fmt, ## args)
+ #define INFO(dev, fmt, args...) \
+       xprintk(dev, KERN_INFO, fmt, ## args)
+@@ -462,6 +462,7 @@ printer_open(struct inode *inode, struct file *fd)
+       unsigned long           flags;
+       int                     ret = -EBUSY;
++      lock_kernel();
+       dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev);
+       spin_lock_irqsave(&dev->lock, flags);
+@@ -477,7 +478,7 @@ printer_open(struct inode *inode, struct file *fd)
+       spin_unlock_irqrestore(&dev->lock, flags);
+       DBG(dev, "printer_open returned %x\n", ret);
+-
++      unlock_kernel();
+       return ret;
+ }
+@@ -827,9 +828,8 @@ printer_poll(struct file *fd, poll_table *wait)
+       return status;
+ }
+-static int
+-printer_ioctl(struct inode *inode, struct file *fd, unsigned int code,
+-              unsigned long arg)
++static long
++printer_ioctl(struct file *fd, unsigned int code, unsigned long arg)
+ {
+       struct printer_dev      *dev = fd->private_data;
+       unsigned long           flags;
+@@ -868,7 +868,7 @@ static struct file_operations printer_io_operations = {
+       .write =        printer_write,
+       .fsync =        printer_fsync,
+       .poll =         printer_poll,
+-      .ioctl =        printer_ioctl,
++      .unlocked_ioctl = printer_ioctl,
+       .release =      printer_close
+ };
+@@ -1360,8 +1360,8 @@ printer_bind(struct usb_gadget *gadget)
+       /* Setup the sysfs files for the printer gadget. */
+-      dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
+-                      "g_printer");
++      dev->pdev = device_create_drvdata(usb_gadget_class, NULL,
++                                        g_printer_devno, NULL, "g_printer");
+       if (IS_ERR(dev->pdev)) {
+               ERROR(dev, "Failed to create device: g_printer\n");
+               goto fail;
+diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
+new file mode 100644
+index 0000000..da6e93c
+--- /dev/null
++++ b/drivers/usb/gadget/pxa25x_udc.c
+@@ -0,0 +1,2390 @@
++/*
++ * Intel PXA25x and IXP4xx on-chip full speed USB device controllers
++ *
++ * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
++ * Copyright (C) 2003 Robert Schwebel, Pengutronix
++ * Copyright (C) 2003 Benedikt Spranger, Pengutronix
++ * Copyright (C) 2003 David Brownell
++ * Copyright (C) 2003 Joshua Wise
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/ioport.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/timer.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/mm.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/irq.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/seq_file.h>
++#include <linux/debugfs.h>
++#include <linux/io.h>
++
++#include <asm/byteorder.h>
++#include <asm/dma.h>
++#include <asm/gpio.h>
++#include <asm/system.h>
++#include <asm/mach-types.h>
++#include <asm/unaligned.h>
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++/*
++ * This driver is PXA25x only.  Grab the right register definitions.
++ */
++#ifdef CONFIG_ARCH_PXA
++#include <mach/pxa25x-udc.h>
++#endif
++
++#include <asm/mach/udc_pxa2xx.h>
++
++
++/*
++ * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x
++ * series processors.  The UDC for the IXP 4xx series is very similar.
++ * There are fifteen endpoints, in addition to ep0.
++ *
++ * Such controller drivers work with a gadget driver.  The gadget driver
++ * returns descriptors, implements configuration and data protocols used
++ * by the host to interact with this device, and allocates endpoints to
++ * the different protocol interfaces.  The controller driver virtualizes
++ * usb hardware so that the gadget drivers will be more portable.
++ *
++ * This UDC hardware wants to implement a bit too much USB protocol, so
++ * it constrains the sorts of USB configuration change events that work.
++ * The errata for these chips are misleading; some "fixed" bugs from
++ * pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
++ *
++ * Note that the UDC hardware supports DMA (except on IXP) but that's
++ * not used here.  IN-DMA (to host) is simple enough, when the data is
++ * suitably aligned (16 bytes) ... the network stack doesn't do that,
++ * other software can.  OUT-DMA is buggy in most chip versions, as well
++ * as poorly designed (data toggle not automatic).  So this driver won't
++ * bother using DMA.  (Mostly-working IN-DMA support was available in
++ * kernels before 2.6.23, but was never enabled or well tested.)
++ */
++
++#define       DRIVER_VERSION  "30-June-2007"
++#define       DRIVER_DESC     "PXA 25x USB Device Controller driver"
++
++
++static const char driver_name [] = "pxa25x_udc";
++
++static const char ep0name [] = "ep0";
++
++
++#ifdef CONFIG_ARCH_IXP4XX
++
++/* cpu-specific register addresses are compiled in to this code */
++#ifdef CONFIG_ARCH_PXA
++#error "Can't configure both IXP and PXA"
++#endif
++
++/* IXP doesn't yet support <linux/clk.h> */
++#define clk_get(dev,name)     NULL
++#define clk_enable(clk)               do { } while (0)
++#define clk_disable(clk)      do { } while (0)
++#define clk_put(clk)          do { } while (0)
++
++#endif
++
++#include "pxa25x_udc.h"
++
++
++#ifdef        CONFIG_USB_PXA25X_SMALL
++#define SIZE_STR      " (small)"
++#else
++#define SIZE_STR      ""
++#endif
++
++/* ---------------------------------------------------------------------------
++ *    endpoint related parts of the api to the usb controller hardware,
++ *    used by gadget driver; and the inner talker-to-hardware core.
++ * ---------------------------------------------------------------------------
++ */
++
++static void pxa25x_ep_fifo_flush (struct usb_ep *ep);
++static void nuke (struct pxa25x_ep *, int status);
++
++/* one GPIO should be used to detect VBUS from the host */
++static int is_vbus_present(void)
++{
++      struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
++
++      if (mach->gpio_vbus) {
++              int value = gpio_get_value(mach->gpio_vbus);
++              return mach->gpio_vbus_inverted ? !value : value;
++      }
++      if (mach->udc_is_connected)
++              return mach->udc_is_connected();
++      return 1;
++}
++
++/* one GPIO should control a D+ pullup, so host sees this device (or not) */
++static void pullup_off(void)
++{
++      struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
++      int off_level = mach->gpio_pullup_inverted;
++
++      if (mach->gpio_pullup)
++              gpio_set_value(mach->gpio_pullup, off_level);
++      else if (mach->udc_command)
++              mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
++}
++
++static void pullup_on(void)
++{
++      struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
++      int on_level = !mach->gpio_pullup_inverted;
++
++      if (mach->gpio_pullup)
++              gpio_set_value(mach->gpio_pullup, on_level);
++      else if (mach->udc_command)
++              mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
++}
++
++static void pio_irq_enable(int bEndpointAddress)
++{
++        bEndpointAddress &= 0xf;
++        if (bEndpointAddress < 8)
++                UICR0 &= ~(1 << bEndpointAddress);
++        else {
++                bEndpointAddress -= 8;
++                UICR1 &= ~(1 << bEndpointAddress);
++      }
++}
++
++static void pio_irq_disable(int bEndpointAddress)
++{
++        bEndpointAddress &= 0xf;
++        if (bEndpointAddress < 8)
++                UICR0 |= 1 << bEndpointAddress;
++        else {
++                bEndpointAddress -= 8;
++                UICR1 |= 1 << bEndpointAddress;
++        }
++}
++
++/* The UDCCR reg contains mask and interrupt status bits,
++ * so using '|=' isn't safe as it may ack an interrupt.
++ */
++#define UDCCR_MASK_BITS         (UDCCR_REM | UDCCR_SRM | UDCCR_UDE)
++
++static inline void udc_set_mask_UDCCR(int mask)
++{
++      UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS);
++}
++
++static inline void udc_clear_mask_UDCCR(int mask)
++{
++      UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS);
++}
++
++static inline void udc_ack_int_UDCCR(int mask)
++{
++      /* udccr contains the bits we dont want to change */
++      __u32 udccr = UDCCR & UDCCR_MASK_BITS;
++
++      UDCCR = udccr | (mask & ~UDCCR_MASK_BITS);
++}
++
++/*
++ * endpoint enable/disable
++ *
++ * we need to verify the descriptors used to enable endpoints.  since pxa25x
++ * endpoint configurations are fixed, and are pretty much always enabled,
++ * there's not a lot to manage here.
++ *
++ * because pxa25x can't selectively initialize bulk (or interrupt) endpoints,
++ * (resetting endpoint halt and toggle), SET_INTERFACE is unusable except
++ * for a single interface (with only the default altsetting) and for gadget
++ * drivers that don't halt endpoints (not reset by set_interface).  that also
++ * means that if you use ISO, you must violate the USB spec rule that all
++ * iso endpoints must be in non-default altsettings.
++ */
++static int pxa25x_ep_enable (struct usb_ep *_ep,
++              const struct usb_endpoint_descriptor *desc)
++{
++      struct pxa25x_ep        *ep;
++      struct pxa25x_udc       *dev;
++
++      ep = container_of (_ep, struct pxa25x_ep, ep);
++      if (!_ep || !desc || ep->desc || _ep->name == ep0name
++                      || desc->bDescriptorType != USB_DT_ENDPOINT
++                      || ep->bEndpointAddress != desc->bEndpointAddress
++                      || ep->fifo_size < le16_to_cpu
++                                              (desc->wMaxPacketSize)) {
++              DMSG("%s, bad ep or descriptor\n", __func__);
++              return -EINVAL;
++      }
++
++      /* xfer types must match, except that interrupt ~= bulk */
++      if (ep->bmAttributes != desc->bmAttributes
++                      && ep->bmAttributes != USB_ENDPOINT_XFER_BULK
++                      && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
++              DMSG("%s, %s type mismatch\n", __func__, _ep->name);
++              return -EINVAL;
++      }
++
++      /* hardware _could_ do smaller, but driver doesn't */
++      if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
++                              && le16_to_cpu (desc->wMaxPacketSize)
++                                              != BULK_FIFO_SIZE)
++                      || !desc->wMaxPacketSize) {
++              DMSG("%s, bad %s maxpacket\n", __func__, _ep->name);
++              return -ERANGE;
++      }
++
++      dev = ep->dev;
++      if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
++              DMSG("%s, bogus device state\n", __func__);
++              return -ESHUTDOWN;
++      }
++
++      ep->desc = desc;
++      ep->stopped = 0;
++      ep->pio_irqs = 0;
++      ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
++
++      /* flush fifo (mostly for OUT buffers) */
++      pxa25x_ep_fifo_flush (_ep);
++
++      /* ... reset halt state too, if we could ... */
++
++      DBG(DBG_VERBOSE, "enabled %s\n", _ep->name);
++      return 0;
++}
++
++static int pxa25x_ep_disable (struct usb_ep *_ep)
++{
++      struct pxa25x_ep        *ep;
++      unsigned long           flags;
++
++      ep = container_of (_ep, struct pxa25x_ep, ep);
++      if (!_ep || !ep->desc) {
++              DMSG("%s, %s not enabled\n", __func__,
++                      _ep ? ep->ep.name : NULL);
++              return -EINVAL;
++      }
++      local_irq_save(flags);
++
++      nuke (ep, -ESHUTDOWN);
++
++      /* flush fifo (mostly for IN buffers) */
++      pxa25x_ep_fifo_flush (_ep);
++
++      ep->desc = NULL;
++      ep->stopped = 1;
++
++      local_irq_restore(flags);
++      DBG(DBG_VERBOSE, "%s disabled\n", _ep->name);
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* for the pxa25x, these can just wrap kmalloc/kfree.  gadget drivers
++ * must still pass correctly initialized endpoints, since other controller
++ * drivers may care about how it's currently set up (dma issues etc).
++ */
++
++/*
++ *    pxa25x_ep_alloc_request - allocate a request data structure
++ */
++static struct usb_request *
++pxa25x_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
++{
++      struct pxa25x_request *req;
++
++      req = kzalloc(sizeof(*req), gfp_flags);
++      if (!req)
++              return NULL;
++
++      INIT_LIST_HEAD (&req->queue);
++      return &req->req;
++}
++
++
++/*
++ *    pxa25x_ep_free_request - deallocate a request data structure
++ */
++static void
++pxa25x_ep_free_request (struct usb_ep *_ep, struct usb_request *_req)
++{
++      struct pxa25x_request   *req;
++
++      req = container_of (_req, struct pxa25x_request, req);
++      WARN_ON(!list_empty (&req->queue));
++      kfree(req);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ *    done - retire a request; caller blocked irqs
++ */
++static void done(struct pxa25x_ep *ep, struct pxa25x_request *req, int status)
++{
++      unsigned                stopped = ep->stopped;
++
++      list_del_init(&req->queue);
++
++      if (likely (req->req.status == -EINPROGRESS))
++              req->req.status = status;
++      else
++              status = req->req.status;
++
++      if (status && status != -ESHUTDOWN)
++              DBG(DBG_VERBOSE, "complete %s req %p stat %d len %u/%u\n",
++                      ep->ep.name, &req->req, status,
++                      req->req.actual, req->req.length);
++
++      /* don't modify queue heads during completion callback */
++      ep->stopped = 1;
++      req->req.complete(&ep->ep, &req->req);
++      ep->stopped = stopped;
++}
++
++
++static inline void ep0_idle (struct pxa25x_udc *dev)
++{
++      dev->ep0state = EP0_IDLE;
++}
++
++static int
++write_packet(volatile u32 *uddr, struct pxa25x_request *req, unsigned max)
++{
++      u8              *buf;
++      unsigned        length, count;
++
++      buf = req->req.buf + req->req.actual;
++      prefetch(buf);
++
++      /* how big will this packet be? */
++      length = min(req->req.length - req->req.actual, max);
++      req->req.actual += length;
++
++      count = length;
++      while (likely(count--))
++              *uddr = *buf++;
++
++      return length;
++}
++
++/*
++ * write to an IN endpoint fifo, as many packets as possible.
++ * irqs will use this to write the rest later.
++ * caller guarantees at least one packet buffer is ready (or a zlp).
++ */
++static int
++write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
++{
++      unsigned                max;
++
++      max = le16_to_cpu(ep->desc->wMaxPacketSize);
++      do {
++              unsigned        count;
++              int             is_last, is_short;
++
++              count = write_packet(ep->reg_uddr, req, max);
++
++              /* last packet is usually short (or a zlp) */
++              if (unlikely (count != max))
++                      is_last = is_short = 1;
++              else {
++                      if (likely(req->req.length != req->req.actual)
++                                      || req->req.zero)
++                              is_last = 0;
++                      else
++                              is_last = 1;
++                      /* interrupt/iso maxpacket may not fill the fifo */
++                      is_short = unlikely (max < ep->fifo_size);
++              }
++
++              DBG(DBG_VERY_NOISY, "wrote %s %d bytes%s%s %d left %p\n",
++                      ep->ep.name, count,
++                      is_last ? "/L" : "", is_short ? "/S" : "",
++                      req->req.length - req->req.actual, req);
++
++              /* let loose that packet. maybe try writing another one,
++               * double buffering might work.  TSP, TPC, and TFS
++               * bit values are the same for all normal IN endpoints.
++               */
++              *ep->reg_udccs = UDCCS_BI_TPC;
++              if (is_short)
++                      *ep->reg_udccs = UDCCS_BI_TSP;
++
++              /* requests complete when all IN data is in the FIFO */
++              if (is_last) {
++                      done (ep, req, 0);
++                      if (list_empty(&ep->queue))
++                              pio_irq_disable (ep->bEndpointAddress);
++                      return 1;
++              }
++
++              // TODO experiment: how robust can fifo mode tweaking be?
++              // double buffering is off in the default fifo mode, which
++              // prevents TFS from being set here.
++
++      } while (*ep->reg_udccs & UDCCS_BI_TFS);
++      return 0;
++}
++
++/* caller asserts req->pending (ep0 irq status nyet cleared); starts
++ * ep0 data stage.  these chips want very simple state transitions.
++ */
++static inline
++void ep0start(struct pxa25x_udc *dev, u32 flags, const char *tag)
++{
++      UDCCS0 = flags|UDCCS0_SA|UDCCS0_OPR;
++      USIR0 = USIR0_IR0;
++      dev->req_pending = 0;
++      DBG(DBG_VERY_NOISY, "%s %s, %02x/%02x\n",
++              __func__, tag, UDCCS0, flags);
++}
++
++static int
++write_ep0_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
++{
++      unsigned        count;
++      int             is_short;
++
++      count = write_packet(&UDDR0, req, EP0_FIFO_SIZE);
++      ep->dev->stats.write.bytes += count;
++
++      /* last packet "must be" short (or a zlp) */
++      is_short = (count != EP0_FIFO_SIZE);
++
++      DBG(DBG_VERY_NOISY, "ep0in %d bytes %d left %p\n", count,
++              req->req.length - req->req.actual, req);
++
++      if (unlikely (is_short)) {
++              if (ep->dev->req_pending)
++                      ep0start(ep->dev, UDCCS0_IPR, "short IN");
++              else
++                      UDCCS0 = UDCCS0_IPR;
++
++              count = req->req.length;
++              done (ep, req, 0);
++              ep0_idle(ep->dev);
++#ifndef CONFIG_ARCH_IXP4XX
++#if 1
++              /* This seems to get rid of lost status irqs in some cases:
++               * host responds quickly, or next request involves config
++               * change automagic, or should have been hidden, or ...
++               *
++               * FIXME get rid of all udelays possible...
++               */
++              if (count >= EP0_FIFO_SIZE) {
++                      count = 100;
++                      do {
++                              if ((UDCCS0 & UDCCS0_OPR) != 0) {
++                                      /* clear OPR, generate ack */
++                                      UDCCS0 = UDCCS0_OPR;
++                                      break;
++                              }
++                              count--;
++                              udelay(1);
++                      } while (count);
++              }
++#endif
++#endif
++      } else if (ep->dev->req_pending)
++              ep0start(ep->dev, 0, "IN");
++      return is_short;
++}
++
++
++/*
++ * read_fifo -  unload packet(s) from the fifo we use for usb OUT
++ * transfers and put them into the request.  caller should have made
++ * sure there's at least one packet ready.
++ *
++ * returns true if the request completed because of short packet or the
++ * request buffer having filled (and maybe overran till end-of-packet).
++ */
++static int
++read_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
++{
++      for (;;) {
++              u32             udccs;
++              u8              *buf;
++              unsigned        bufferspace, count, is_short;
++
++              /* make sure there's a packet in the FIFO.
++               * UDCCS_{BO,IO}_RPC are all the same bit value.
++               * UDCCS_{BO,IO}_RNE are all the same bit value.
++               */
++              udccs = *ep->reg_udccs;
++              if (unlikely ((udccs & UDCCS_BO_RPC) == 0))
++                      break;
++              buf = req->req.buf + req->req.actual;
++              prefetchw(buf);
++              bufferspace = req->req.length - req->req.actual;
++
++              /* read all bytes from this packet */
++              if (likely (udccs & UDCCS_BO_RNE)) {
++                      count = 1 + (0x0ff & *ep->reg_ubcr);
++                      req->req.actual += min (count, bufferspace);
++              } else /* zlp */
++                      count = 0;
++              is_short = (count < ep->ep.maxpacket);
++              DBG(DBG_VERY_NOISY, "read %s %02x, %d bytes%s req %p %d/%d\n",
++                      ep->ep.name, udccs, count,
++                      is_short ? "/S" : "",
++                      req, req->req.actual, req->req.length);
++              while (likely (count-- != 0)) {
++                      u8      byte = (u8) *ep->reg_uddr;
++
++                      if (unlikely (bufferspace == 0)) {
++                              /* this happens when the driver's buffer
++                               * is smaller than what the host sent.
++                               * discard the extra data.
++                               */
++                              if (req->req.status != -EOVERFLOW)
++                                      DMSG("%s overflow %d\n",
++                                              ep->ep.name, count);
++                              req->req.status = -EOVERFLOW;
++                      } else {
++                              *buf++ = byte;
++                              bufferspace--;
++                      }
++              }
++              *ep->reg_udccs =  UDCCS_BO_RPC;
++              /* RPC/RSP/RNE could now reflect the other packet buffer */
++
++              /* iso is one request per packet */
++              if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
++                      if (udccs & UDCCS_IO_ROF)
++                              req->req.status = -EHOSTUNREACH;
++                      /* more like "is_done" */
++                      is_short = 1;
++              }
++
++              /* completion */
++              if (is_short || req->req.actual == req->req.length) {
++                      done (ep, req, 0);
++                      if (list_empty(&ep->queue))
++                              pio_irq_disable (ep->bEndpointAddress);
++                      return 1;
++              }
++
++              /* finished that packet.  the next one may be waiting... */
++      }
++      return 0;
++}
++
++/*
++ * special ep0 version of the above.  no UBCR0 or double buffering; status
++ * handshaking is magic.  most device protocols don't need control-OUT.
++ * CDC vendor commands (and RNDIS), mass storage CB/CBI, and some other
++ * protocols do use them.
++ */
++static int
++read_ep0_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
++{
++      u8              *buf, byte;
++      unsigned        bufferspace;
++
++      buf = req->req.buf + req->req.actual;
++      bufferspace = req->req.length - req->req.actual;
++
++      while (UDCCS0 & UDCCS0_RNE) {
++              byte = (u8) UDDR0;
++
++              if (unlikely (bufferspace == 0)) {
++                      /* this happens when the driver's buffer
++                       * is smaller than what the host sent.
++                       * discard the extra data.
++                       */
++                      if (req->req.status != -EOVERFLOW)
++                              DMSG("%s overflow\n", ep->ep.name);
++                      req->req.status = -EOVERFLOW;
++              } else {
++                      *buf++ = byte;
++                      req->req.actual++;
++                      bufferspace--;
++              }
++      }
++
++      UDCCS0 = UDCCS0_OPR | UDCCS0_IPR;
++
++      /* completion */
++      if (req->req.actual >= req->req.length)
++              return 1;
++
++      /* finished that packet.  the next one may be waiting... */
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int
++pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
++{
++      struct pxa25x_request   *req;
++      struct pxa25x_ep        *ep;
++      struct pxa25x_udc       *dev;
++      unsigned long           flags;
++
++      req = container_of(_req, struct pxa25x_request, req);
++      if (unlikely (!_req || !_req->complete || !_req->buf
++                      || !list_empty(&req->queue))) {
++              DMSG("%s, bad params\n", __func__);
++              return -EINVAL;
++      }
++
++      ep = container_of(_ep, struct pxa25x_ep, ep);
++      if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
++              DMSG("%s, bad ep\n", __func__);
++              return -EINVAL;
++      }
++
++      dev = ep->dev;
++      if (unlikely (!dev->driver
++                      || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
++              DMSG("%s, bogus device state\n", __func__);
++              return -ESHUTDOWN;
++      }
++
++      /* iso is always one packet per request, that's the only way
++       * we can report per-packet status.  that also helps with dma.
++       */
++      if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
++                      && req->req.length > le16_to_cpu
++                                              (ep->desc->wMaxPacketSize)))
++              return -EMSGSIZE;
++
++      DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
++              _ep->name, _req, _req->length, _req->buf);
++
++      local_irq_save(flags);
++
++      _req->status = -EINPROGRESS;
++      _req->actual = 0;
++
++      /* kickstart this i/o queue? */
++      if (list_empty(&ep->queue) && !ep->stopped) {
++              if (ep->desc == NULL/* ep0 */) {
++                      unsigned        length = _req->length;
++
++                      switch (dev->ep0state) {
++                      case EP0_IN_DATA_PHASE:
++                              dev->stats.write.ops++;
++                              if (write_ep0_fifo(ep, req))
++                                      req = NULL;
++                              break;
++
++                      case EP0_OUT_DATA_PHASE:
++                              dev->stats.read.ops++;
++                              /* messy ... */
++                              if (dev->req_config) {
++                                      DBG(DBG_VERBOSE, "ep0 config ack%s\n",
++                                              dev->has_cfr ?  "" : " raced");
++                                      if (dev->has_cfr)
++                                              UDCCFR = UDCCFR_AREN|UDCCFR_ACM
++                                                      |UDCCFR_MB1;
++                                      done(ep, req, 0);
++                                      dev->ep0state = EP0_END_XFER;
++                                      local_irq_restore (flags);
++                                      return 0;
++                              }
++                              if (dev->req_pending)
++                                      ep0start(dev, UDCCS0_IPR, "OUT");
++                              if (length == 0 || ((UDCCS0 & UDCCS0_RNE) != 0
++                                              && read_ep0_fifo(ep, req))) {
++                                      ep0_idle(dev);
++                                      done(ep, req, 0);
++                                      req = NULL;
++                              }
++                              break;
++
++                      default:
++                              DMSG("ep0 i/o, odd state %d\n", dev->ep0state);
++                              local_irq_restore (flags);
++                              return -EL2HLT;
++                      }
++              /* can the FIFO can satisfy the request immediately? */
++              } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
++                      if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
++                                      && write_fifo(ep, req))
++                              req = NULL;
++              } else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0
++                              && read_fifo(ep, req)) {
++                      req = NULL;
++              }
++
++              if (likely (req && ep->desc))
++                      pio_irq_enable(ep->bEndpointAddress);
++      }
++
++      /* pio or dma irq handler advances the queue. */
++      if (likely(req != NULL))
++              list_add_tail(&req->queue, &ep->queue);
++      local_irq_restore(flags);
++
++      return 0;
++}
++
++
++/*
++ *    nuke - dequeue ALL requests
++ */
++static void nuke(struct pxa25x_ep *ep, int status)
++{
++      struct pxa25x_request *req;
++
++      /* called with irqs blocked */
++      while (!list_empty(&ep->queue)) {
++              req = list_entry(ep->queue.next,
++                              struct pxa25x_request,
++                              queue);
++              done(ep, req, status);
++      }
++      if (ep->desc)
++              pio_irq_disable (ep->bEndpointAddress);
++}
++
++
++/* dequeue JUST ONE request */
++static int pxa25x_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
++{
++      struct pxa25x_ep        *ep;
++      struct pxa25x_request   *req;
++      unsigned long           flags;
++
++      ep = container_of(_ep, struct pxa25x_ep, ep);
++      if (!_ep || ep->ep.name == ep0name)
++              return -EINVAL;
++
++      local_irq_save(flags);
++
++      /* make sure it's actually queued on this endpoint */
++      list_for_each_entry (req, &ep->queue, queue) {
++              if (&req->req == _req)
++                      break;
++      }
++      if (&req->req != _req) {
++              local_irq_restore(flags);
++              return -EINVAL;
++      }
++
++      done(ep, req, -ECONNRESET);
++
++      local_irq_restore(flags);
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value)
++{
++      struct pxa25x_ep        *ep;
++      unsigned long           flags;
++
++      ep = container_of(_ep, struct pxa25x_ep, ep);
++      if (unlikely (!_ep
++                      || (!ep->desc && ep->ep.name != ep0name))
++                      || ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
++              DMSG("%s, bad ep\n", __func__);
++              return -EINVAL;
++      }
++      if (value == 0) {
++              /* this path (reset toggle+halt) is needed to implement
++               * SET_INTERFACE on normal hardware.  but it can't be
++               * done from software on the PXA UDC, and the hardware
++               * forgets to do it as part of SET_INTERFACE automagic.
++               */
++              DMSG("only host can clear %s halt\n", _ep->name);
++              return -EROFS;
++      }
++
++      local_irq_save(flags);
++
++      if ((ep->bEndpointAddress & USB_DIR_IN) != 0
++                      && ((*ep->reg_udccs & UDCCS_BI_TFS) == 0
++                         || !list_empty(&ep->queue))) {
++              local_irq_restore(flags);
++              return -EAGAIN;
++      }
++
++      /* FST bit is the same for control, bulk in, bulk out, interrupt in */
++      *ep->reg_udccs = UDCCS_BI_FST|UDCCS_BI_FTF;
++
++      /* ep0 needs special care */
++      if (!ep->desc) {
++              start_watchdog(ep->dev);
++              ep->dev->req_pending = 0;
++              ep->dev->ep0state = EP0_STALL;
++
++      /* and bulk/intr endpoints like dropping stalls too */
++      } else {
++              unsigned i;
++              for (i = 0; i < 1000; i += 20) {
++                      if (*ep->reg_udccs & UDCCS_BI_SST)
++                              break;
++                      udelay(20);
++              }
++      }
++      local_irq_restore(flags);
++
++      DBG(DBG_VERBOSE, "%s halt\n", _ep->name);
++      return 0;
++}
++
++static int pxa25x_ep_fifo_status(struct usb_ep *_ep)
++{
++      struct pxa25x_ep        *ep;
++
++      ep = container_of(_ep, struct pxa25x_ep, ep);
++      if (!_ep) {
++              DMSG("%s, bad ep\n", __func__);
++              return -ENODEV;
++      }
++      /* pxa can't report unclaimed bytes from IN fifos */
++      if ((ep->bEndpointAddress & USB_DIR_IN) != 0)
++              return -EOPNOTSUPP;
++      if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN
++                      || (*ep->reg_udccs & UDCCS_BO_RFS) == 0)
++              return 0;
++      else
++              return (*ep->reg_ubcr & 0xfff) + 1;
++}
++
++static void pxa25x_ep_fifo_flush(struct usb_ep *_ep)
++{
++      struct pxa25x_ep        *ep;
++
++      ep = container_of(_ep, struct pxa25x_ep, ep);
++      if (!_ep || ep->ep.name == ep0name || !list_empty(&ep->queue)) {
++              DMSG("%s, bad ep\n", __func__);
++              return;
++      }
++
++      /* toggle and halt bits stay unchanged */
++
++      /* for OUT, just read and discard the FIFO contents. */
++      if ((ep->bEndpointAddress & USB_DIR_IN) == 0) {
++              while (((*ep->reg_udccs) & UDCCS_BO_RNE) != 0)
++                      (void) *ep->reg_uddr;
++              return;
++      }
++
++      /* most IN status is the same, but ISO can't stall */
++      *ep->reg_udccs = UDCCS_BI_TPC|UDCCS_BI_FTF|UDCCS_BI_TUR
++              | (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
++                      ? 0 : UDCCS_BI_SST;
++}
++
++
++static struct usb_ep_ops pxa25x_ep_ops = {
++      .enable         = pxa25x_ep_enable,
++      .disable        = pxa25x_ep_disable,
++
++      .alloc_request  = pxa25x_ep_alloc_request,
++      .free_request   = pxa25x_ep_free_request,
++
++      .queue          = pxa25x_ep_queue,
++      .dequeue        = pxa25x_ep_dequeue,
++
++      .set_halt       = pxa25x_ep_set_halt,
++      .fifo_status    = pxa25x_ep_fifo_status,
++      .fifo_flush     = pxa25x_ep_fifo_flush,
++};
++
++
++/* ---------------------------------------------------------------------------
++ *    device-scoped parts of the api to the usb controller hardware
++ * ---------------------------------------------------------------------------
++ */
++
++static int pxa25x_udc_get_frame(struct usb_gadget *_gadget)
++{
++      return ((UFNRH & 0x07) << 8) | (UFNRL & 0xff);
++}
++
++static int pxa25x_udc_wakeup(struct usb_gadget *_gadget)
++{
++      /* host may not have enabled remote wakeup */
++      if ((UDCCS0 & UDCCS0_DRWF) == 0)
++              return -EHOSTUNREACH;
++      udc_set_mask_UDCCR(UDCCR_RSM);
++      return 0;
++}
++
++static void stop_activity(struct pxa25x_udc *, struct usb_gadget_driver *);
++static void udc_enable (struct pxa25x_udc *);
++static void udc_disable(struct pxa25x_udc *);
++
++/* We disable the UDC -- and its 48 MHz clock -- whenever it's not
++ * in active use.
++ */
++static int pullup(struct pxa25x_udc *udc)
++{
++      int is_active = udc->vbus && udc->pullup && !udc->suspended;
++      DMSG("%s\n", is_active ? "active" : "inactive");
++      if (is_active) {
++              if (!udc->active) {
++                      udc->active = 1;
++                      /* Enable clock for USB device */
++                      clk_enable(udc->clk);
++                      udc_enable(udc);
++              }
++      } else {
++              if (udc->active) {
++                      if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
++                              DMSG("disconnect %s\n", udc->driver
++                                      ? udc->driver->driver.name
++                                      : "(no driver)");
++                              stop_activity(udc, udc->driver);
++                      }
++                      udc_disable(udc);
++                      /* Disable clock for USB device */
++                      clk_disable(udc->clk);
++                      udc->active = 0;
++              }
++
++      }
++      return 0;
++}
++
++/* VBUS reporting logically comes from a transceiver */
++static int pxa25x_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
++{
++      struct pxa25x_udc       *udc;
++
++      udc = container_of(_gadget, struct pxa25x_udc, gadget);
++      udc->vbus = (is_active != 0);
++      DMSG("vbus %s\n", is_active ? "supplied" : "inactive");
++      pullup(udc);
++      return 0;
++}
++
++/* drivers may have software control over D+ pullup */
++static int pxa25x_udc_pullup(struct usb_gadget *_gadget, int is_active)
++{
++      struct pxa25x_udc       *udc;
++
++      udc = container_of(_gadget, struct pxa25x_udc, gadget);
++
++      /* not all boards support pullup control */
++      if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
++              return -EOPNOTSUPP;
++
++      udc->pullup = (is_active != 0);
++      pullup(udc);
++      return 0;
++}
++
++static const struct usb_gadget_ops pxa25x_udc_ops = {
++      .get_frame      = pxa25x_udc_get_frame,
++      .wakeup         = pxa25x_udc_wakeup,
++      .vbus_session   = pxa25x_udc_vbus_session,
++      .pullup         = pxa25x_udc_pullup,
++
++      // .vbus_draw ... boards may consume current from VBUS, up to
++      // 100-500mA based on config.  the 500uA suspend ceiling means
++      // that exclusively vbus-powered PXA designs violate USB specs.
++};
++
++/*-------------------------------------------------------------------------*/
++
++#ifdef CONFIG_USB_GADGET_DEBUG_FS
++
++static int
++udc_seq_show(struct seq_file *m, void *_d)
++{
++      struct pxa25x_udc       *dev = m->private;
++      unsigned long           flags;
++      int                     i;
++      u32                     tmp;
++
++      local_irq_save(flags);
++
++      /* basic device status */
++      seq_printf(m, DRIVER_DESC "\n"
++              "%s version: %s\nGadget driver: %s\nHost %s\n\n",
++              driver_name, DRIVER_VERSION SIZE_STR "(pio)",
++              dev->driver ? dev->driver->driver.name : "(none)",
++              is_vbus_present() ? "full speed" : "disconnected");
++
++      /* registers for device and ep0 */
++      seq_printf(m,
++              "uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
++              UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
++
++      tmp = UDCCR;
++      seq_printf(m,
++              "udccr %02X =%s%s%s%s%s%s%s%s\n", tmp,
++              (tmp & UDCCR_REM) ? " rem" : "",
++              (tmp & UDCCR_RSTIR) ? " rstir" : "",
++              (tmp & UDCCR_SRM) ? " srm" : "",
++              (tmp & UDCCR_SUSIR) ? " susir" : "",
++              (tmp & UDCCR_RESIR) ? " resir" : "",
++              (tmp & UDCCR_RSM) ? " rsm" : "",
++              (tmp & UDCCR_UDA) ? " uda" : "",
++              (tmp & UDCCR_UDE) ? " ude" : "");
++
++      tmp = UDCCS0;
++      seq_printf(m,
++              "udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp,
++              (tmp & UDCCS0_SA) ? " sa" : "",
++              (tmp & UDCCS0_RNE) ? " rne" : "",
++              (tmp & UDCCS0_FST) ? " fst" : "",
++              (tmp & UDCCS0_SST) ? " sst" : "",
++              (tmp & UDCCS0_DRWF) ? " dwrf" : "",
++              (tmp & UDCCS0_FTF) ? " ftf" : "",
++              (tmp & UDCCS0_IPR) ? " ipr" : "",
++              (tmp & UDCCS0_OPR) ? " opr" : "");
++
++      if (dev->has_cfr) {
++              tmp = UDCCFR;
++              seq_printf(m,
++                      "udccfr %02X =%s%s\n", tmp,
++                      (tmp & UDCCFR_AREN) ? " aren" : "",
++                      (tmp & UDCCFR_ACM) ? " acm" : "");
++      }
++
++      if (!is_vbus_present() || !dev->driver)
++              goto done;
++
++      seq_printf(m, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
++              dev->stats.write.bytes, dev->stats.write.ops,
++              dev->stats.read.bytes, dev->stats.read.ops,
++              dev->stats.irqs);
++
++      /* dump endpoint queues */
++      for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
++              struct pxa25x_ep        *ep = &dev->ep [i];
++              struct pxa25x_request   *req;
++
++              if (i != 0) {
++                      const struct usb_endpoint_descriptor    *desc;
++
++                      desc = ep->desc;
++                      if (!desc)
++                              continue;
++                      tmp = *dev->ep [i].reg_udccs;
++                      seq_printf(m,
++                              "%s max %d %s udccs %02x irqs %lu\n",
++                              ep->ep.name, le16_to_cpu(desc->wMaxPacketSize),
++                              "pio", tmp, ep->pio_irqs);
++                      /* TODO translate all five groups of udccs bits! */
++
++              } else /* ep0 should only have one transfer queued */
++                      seq_printf(m, "ep0 max 16 pio irqs %lu\n",
++                              ep->pio_irqs);
++
++              if (list_empty(&ep->queue)) {
++                      seq_printf(m, "\t(nothing queued)\n");
++                      continue;
++              }
++              list_for_each_entry(req, &ep->queue, queue) {
++                      seq_printf(m,
++                                      "\treq %p len %d/%d buf %p\n",
++                                      &req->req, req->req.actual,
++                                      req->req.length, req->req.buf);
++              }
++      }
++
++done:
++      local_irq_restore(flags);
++      return 0;
++}
++
++static int
++udc_debugfs_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, udc_seq_show, inode->i_private);
++}
++
++static const struct file_operations debug_fops = {
++      .open           = udc_debugfs_open,
++      .read           = seq_read,
++      .llseek         = seq_lseek,
++      .release        = single_release,
++      .owner          = THIS_MODULE,
++};
++
++#define create_debug_files(dev) \
++      do { \
++              dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \
++                      S_IRUGO, NULL, dev, &debug_fops); \
++      } while (0)
++#define remove_debug_files(dev) \
++      do { \
++              if (dev->debugfs_udc) \
++                      debugfs_remove(dev->debugfs_udc); \
++      } while (0)
++
++#else /* !CONFIG_USB_GADGET_DEBUG_FILES */
++
++#define create_debug_files(dev) do {} while (0)
++#define remove_debug_files(dev) do {} while (0)
++
++#endif        /* CONFIG_USB_GADGET_DEBUG_FILES */
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ *    udc_disable - disable USB device controller
++ */
++static void udc_disable(struct pxa25x_udc *dev)
++{
++      /* block all irqs */
++      udc_set_mask_UDCCR(UDCCR_SRM|UDCCR_REM);
++      UICR0 = UICR1 = 0xff;
++      UFNRH = UFNRH_SIM;
++
++      /* if hardware supports it, disconnect from usb */
++      pullup_off();
++
++      udc_clear_mask_UDCCR(UDCCR_UDE);
++
++      ep0_idle (dev);
++      dev->gadget.speed = USB_SPEED_UNKNOWN;
++}
++
++
++/*
++ *    udc_reinit - initialize software state
++ */
++static void udc_reinit(struct pxa25x_udc *dev)
++{
++      u32     i;
++
++      /* device/ep0 records init */
++      INIT_LIST_HEAD (&dev->gadget.ep_list);
++      INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
++      dev->ep0state = EP0_IDLE;
++
++      /* basic endpoint records init */
++      for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
++              struct pxa25x_ep *ep = &dev->ep[i];
++
++              if (i != 0)
++                      list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
++
++              ep->desc = NULL;
++              ep->stopped = 0;
++              INIT_LIST_HEAD (&ep->queue);
++              ep->pio_irqs = 0;
++      }
++
++      /* the rest was statically initialized, and is read-only */
++}
++
++/* until it's enabled, this UDC should be completely invisible
++ * to any USB host.
++ */
++static void udc_enable (struct pxa25x_udc *dev)
++{
++      udc_clear_mask_UDCCR(UDCCR_UDE);
++
++      /* try to clear these bits before we enable the udc */
++      udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR);
++
++      ep0_idle(dev);
++      dev->gadget.speed = USB_SPEED_UNKNOWN;
++      dev->stats.irqs = 0;
++
++      /*
++       * sequence taken from chapter 12.5.10, PXA250 AppProcDevManual:
++       * - enable UDC
++       * - if RESET is already in progress, ack interrupt
++       * - unmask reset interrupt
++       */
++      udc_set_mask_UDCCR(UDCCR_UDE);
++      if (!(UDCCR & UDCCR_UDA))
++              udc_ack_int_UDCCR(UDCCR_RSTIR);
++
++      if (dev->has_cfr /* UDC_RES2 is defined */) {
++              /* pxa255 (a0+) can avoid a set_config race that could
++               * prevent gadget drivers from configuring correctly
++               */
++              UDCCFR = UDCCFR_ACM | UDCCFR_MB1;
++      } else {
++              /* "USB test mode" for pxa250 errata 40-42 (stepping a0, a1)
++               * which could result in missing packets and interrupts.
++               * supposedly one bit per endpoint, controlling whether it
++               * double buffers or not; ACM/AREN bits fit into the holes.
++               * zero bits (like USIR0_IRx) disable double buffering.
++               */
++              UDC_RES1 = 0x00;
++              UDC_RES2 = 0x00;
++      }
++
++      /* enable suspend/resume and reset irqs */
++      udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM);
++
++      /* enable ep0 irqs */
++      UICR0 &= ~UICR0_IM0;
++
++      /* if hardware supports it, pullup D+ and wait for reset */
++      pullup_on();
++}
++
++
++/* when a driver is successfully registered, it will receive
++ * control requests including set_configuration(), which enables
++ * non-control requests.  then usb traffic follows until a
++ * disconnect is reported.  then a host may connect again, or
++ * the driver might get unbound.
++ */
++int usb_gadget_register_driver(struct usb_gadget_driver *driver)
++{
++      struct pxa25x_udc       *dev = the_controller;
++      int                     retval;
++
++      if (!driver
++                      || driver->speed < USB_SPEED_FULL
++                      || !driver->bind
++                      || !driver->disconnect
++                      || !driver->setup)
++              return -EINVAL;
++      if (!dev)
++              return -ENODEV;
++      if (dev->driver)
++              return -EBUSY;
++
++      /* first hook up the driver ... */
++      dev->driver = driver;
++      dev->gadget.dev.driver = &driver->driver;
++      dev->pullup = 1;
++
++      retval = device_add (&dev->gadget.dev);
++      if (retval) {
++fail:
++              dev->driver = NULL;
++              dev->gadget.dev.driver = NULL;
++              return retval;
++      }
++      retval = driver->bind(&dev->gadget);
++      if (retval) {
++              DMSG("bind to driver %s --> error %d\n",
++                              driver->driver.name, retval);
++              device_del (&dev->gadget.dev);
++              goto fail;
++      }
++
++      /* ... then enable host detection and ep0; and we're ready
++       * for set_configuration as well as eventual disconnect.
++       */
++      DMSG("registered gadget driver '%s'\n", driver->driver.name);
++      pullup(dev);
++      dump_state(dev);
++      return 0;
++}
++EXPORT_SYMBOL(usb_gadget_register_driver);
++
++static void
++stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
++{
++      int i;
++
++      /* don't disconnect drivers more than once */
++      if (dev->gadget.speed == USB_SPEED_UNKNOWN)
++              driver = NULL;
++      dev->gadget.speed = USB_SPEED_UNKNOWN;
++
++      /* prevent new request submissions, kill any outstanding requests  */
++      for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
++              struct pxa25x_ep *ep = &dev->ep[i];
++
++              ep->stopped = 1;
++              nuke(ep, -ESHUTDOWN);
++      }
++      del_timer_sync(&dev->timer);
++
++      /* report disconnect; the driver is already quiesced */
++      if (driver)
++              driver->disconnect(&dev->gadget);
++
++      /* re-init driver-visible data structures */
++      udc_reinit(dev);
++}
++
++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
++{
++      struct pxa25x_udc       *dev = the_controller;
++
++      if (!dev)
++              return -ENODEV;
++      if (!driver || driver != dev->driver || !driver->unbind)
++              return -EINVAL;
++
++      local_irq_disable();
++      dev->pullup = 0;
++      pullup(dev);
++      stop_activity(dev, driver);
++      local_irq_enable();
++
++      driver->unbind(&dev->gadget);
++      dev->gadget.dev.driver = NULL;
++      dev->driver = NULL;
++
++      device_del (&dev->gadget.dev);
++
++      DMSG("unregistered gadget driver '%s'\n", driver->driver.name);
++      dump_state(dev);
++      return 0;
++}
++EXPORT_SYMBOL(usb_gadget_unregister_driver);
++
++
++/*-------------------------------------------------------------------------*/
++
++#ifdef CONFIG_ARCH_LUBBOCK
++
++/* Lubbock has separate connect and disconnect irqs.  More typical designs
++ * use one GPIO as the VBUS IRQ, and another to control the D+ pullup.
++ */
++
++static irqreturn_t
++lubbock_vbus_irq(int irq, void *_dev)
++{
++      struct pxa25x_udc       *dev = _dev;
++      int                     vbus;
++
++      dev->stats.irqs++;
++      switch (irq) {
++      case LUBBOCK_USB_IRQ:
++              vbus = 1;
++              disable_irq(LUBBOCK_USB_IRQ);
++              enable_irq(LUBBOCK_USB_DISC_IRQ);
++              break;
++      case LUBBOCK_USB_DISC_IRQ:
++              vbus = 0;
++              disable_irq(LUBBOCK_USB_DISC_IRQ);
++              enable_irq(LUBBOCK_USB_IRQ);
++              break;
++      default:
++              return IRQ_NONE;
++      }
++
++      pxa25x_udc_vbus_session(&dev->gadget, vbus);
++      return IRQ_HANDLED;
++}
++
++#endif
++
++static irqreturn_t udc_vbus_irq(int irq, void *_dev)
++{
++      struct pxa25x_udc       *dev = _dev;
++      int                     vbus = gpio_get_value(dev->mach->gpio_vbus);
++
++      if (dev->mach->gpio_vbus_inverted)
++              vbus = !vbus;
++
++      pxa25x_udc_vbus_session(&dev->gadget, vbus);
++      return IRQ_HANDLED;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static inline void clear_ep_state (struct pxa25x_udc *dev)
++{
++      unsigned i;
++
++      /* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
++       * fifos, and pending transactions mustn't be continued in any case.
++       */
++      for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++)
++              nuke(&dev->ep[i], -ECONNABORTED);
++}
++
++static void udc_watchdog(unsigned long _dev)
++{
++      struct pxa25x_udc       *dev = (void *)_dev;
++
++      local_irq_disable();
++      if (dev->ep0state == EP0_STALL
++                      && (UDCCS0 & UDCCS0_FST) == 0
++                      && (UDCCS0 & UDCCS0_SST) == 0) {
++              UDCCS0 = UDCCS0_FST|UDCCS0_FTF;
++              DBG(DBG_VERBOSE, "ep0 re-stall\n");
++              start_watchdog(dev);
++      }
++      local_irq_enable();
++}
++
++static void handle_ep0 (struct pxa25x_udc *dev)
++{
++      u32                     udccs0 = UDCCS0;
++      struct pxa25x_ep        *ep = &dev->ep [0];
++      struct pxa25x_request   *req;
++      union {
++              struct usb_ctrlrequest  r;
++              u8                      raw [8];
++              u32                     word [2];
++      } u;
++
++      if (list_empty(&ep->queue))
++              req = NULL;
++      else
++              req = list_entry(ep->queue.next, struct pxa25x_request, queue);
++
++      /* clear stall status */
++      if (udccs0 & UDCCS0_SST) {
++              nuke(ep, -EPIPE);
++              UDCCS0 = UDCCS0_SST;
++              del_timer(&dev->timer);
++              ep0_idle(dev);
++      }
++
++      /* previous request unfinished?  non-error iff back-to-back ... */
++      if ((udccs0 & UDCCS0_SA) != 0 && dev->ep0state != EP0_IDLE) {
++              nuke(ep, 0);
++              del_timer(&dev->timer);
++              ep0_idle(dev);
++      }
++
++      switch (dev->ep0state) {
++      case EP0_IDLE:
++              /* late-breaking status? */
++              udccs0 = UDCCS0;
++
++              /* start control request? */
++              if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE))
++                              == (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE))) {
++                      int i;
++
++                      nuke (ep, -EPROTO);
++
++                      /* read SETUP packet */
++                      for (i = 0; i < 8; i++) {
++                              if (unlikely(!(UDCCS0 & UDCCS0_RNE))) {
++bad_setup:
++                                      DMSG("SETUP %d!\n", i);
++                                      goto stall;
++                              }
++                              u.raw [i] = (u8) UDDR0;
++                      }
++                      if (unlikely((UDCCS0 & UDCCS0_RNE) != 0))
++                              goto bad_setup;
++
++got_setup:
++                      DBG(DBG_VERBOSE, "SETUP %02x.%02x v%04x i%04x l%04x\n",
++                              u.r.bRequestType, u.r.bRequest,
++                              le16_to_cpu(u.r.wValue),
++                              le16_to_cpu(u.r.wIndex),
++                              le16_to_cpu(u.r.wLength));
++
++                      /* cope with automagic for some standard requests. */
++                      dev->req_std = (u.r.bRequestType & USB_TYPE_MASK)
++                                              == USB_TYPE_STANDARD;
++                      dev->req_config = 0;
++                      dev->req_pending = 1;
++                      switch (u.r.bRequest) {
++                      /* hardware restricts gadget drivers here! */
++                      case USB_REQ_SET_CONFIGURATION:
++                              if (u.r.bRequestType == USB_RECIP_DEVICE) {
++                                      /* reflect hardware's automagic
++                                       * up to the gadget driver.
++                                       */
++config_change:
++                                      dev->req_config = 1;
++                                      clear_ep_state(dev);
++                                      /* if !has_cfr, there's no synch
++                                       * else use AREN (later) not SA|OPR
++                                       * USIR0_IR0 acts edge sensitive
++                                       */
++                              }
++                              break;
++                      /* ... and here, even more ... */
++                      case USB_REQ_SET_INTERFACE:
++                              if (u.r.bRequestType == USB_RECIP_INTERFACE) {
++                                      /* udc hardware is broken by design:
++                                       *  - altsetting may only be zero;
++                                       *  - hw resets all interfaces' eps;
++                                       *  - ep reset doesn't include halt(?).
++                                       */
++                                      DMSG("broken set_interface (%d/%d)\n",
++                                              le16_to_cpu(u.r.wIndex),
++                                              le16_to_cpu(u.r.wValue));
++                                      goto config_change;
++                              }
++                              break;
++                      /* hardware was supposed to hide this */
++                      case USB_REQ_SET_ADDRESS:
++                              if (u.r.bRequestType == USB_RECIP_DEVICE) {
++                                      ep0start(dev, 0, "address");
++                                      return;
++                              }
++                              break;
++                      }
++
++                      if (u.r.bRequestType & USB_DIR_IN)
++                              dev->ep0state = EP0_IN_DATA_PHASE;
++                      else
++                              dev->ep0state = EP0_OUT_DATA_PHASE;
++
++                      i = dev->driver->setup(&dev->gadget, &u.r);
++                      if (i < 0) {
++                              /* hardware automagic preventing STALL... */
++                              if (dev->req_config) {
++                                      /* hardware sometimes neglects to tell
++                                       * tell us about config change events,
++                                       * so later ones may fail...
++                                       */
++                                      WARNING("config change %02x fail %d?\n",
++                                              u.r.bRequest, i);
++                                      return;
++                                      /* TODO experiment:  if has_cfr,
++                                       * hardware didn't ACK; maybe we
++                                       * could actually STALL!
++                                       */
++                              }
++                              DBG(DBG_VERBOSE, "protocol STALL, "
++                                      "%02x err %d\n", UDCCS0, i);
++stall:
++                              /* the watchdog timer helps deal with cases
++                               * where udc seems to clear FST wrongly, and
++                               * then NAKs instead of STALLing.
++                               */
++                              ep0start(dev, UDCCS0_FST|UDCCS0_FTF, "stall");
++                              start_watchdog(dev);
++                              dev->ep0state = EP0_STALL;
++
++                      /* deferred i/o == no response yet */
++                      } else if (dev->req_pending) {
++                              if (likely(dev->ep0state == EP0_IN_DATA_PHASE
++                                              || dev->req_std || u.r.wLength))
++                                      ep0start(dev, 0, "defer");
++                              else
++                                      ep0start(dev, UDCCS0_IPR, "defer/IPR");
++                      }
++
++                      /* expect at least one data or status stage irq */
++                      return;
++
++              } else if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA))
++                              == (UDCCS0_OPR|UDCCS0_SA))) {
++                      unsigned i;
++
++                      /* pxa210/250 erratum 131 for B0/B1 says RNE lies.
++                       * still observed on a pxa255 a0.
++                       */
++                      DBG(DBG_VERBOSE, "e131\n");
++                      nuke(ep, -EPROTO);
++
++                      /* read SETUP data, but don't trust it too much */
++                      for (i = 0; i < 8; i++)
++                              u.raw [i] = (u8) UDDR0;
++                      if ((u.r.bRequestType & USB_RECIP_MASK)
++                                      > USB_RECIP_OTHER)
++                              goto stall;
++                      if (u.word [0] == 0 && u.word [1] == 0)
++                              goto stall;
++                      goto got_setup;
++              } else {
++                      /* some random early IRQ:
++                       * - we acked FST
++                       * - IPR cleared
++                       * - OPR got set, without SA (likely status stage)
++                       */
++                      UDCCS0 = udccs0 & (UDCCS0_SA|UDCCS0_OPR);
++              }
++              break;
++      case EP0_IN_DATA_PHASE:                 /* GET_DESCRIPTOR etc */
++              if (udccs0 & UDCCS0_OPR) {
++                      UDCCS0 = UDCCS0_OPR|UDCCS0_FTF;
++                      DBG(DBG_VERBOSE, "ep0in premature status\n");
++                      if (req)
++                              done(ep, req, 0);
++                      ep0_idle(dev);
++              } else /* irq was IPR clearing */ {
++                      if (req) {
++                              /* this IN packet might finish the request */
++                              (void) write_ep0_fifo(ep, req);
++                      } /* else IN token before response was written */
++              }
++              break;
++      case EP0_OUT_DATA_PHASE:                /* SET_DESCRIPTOR etc */
++              if (udccs0 & UDCCS0_OPR) {
++                      if (req) {
++                              /* this OUT packet might finish the request */
++                              if (read_ep0_fifo(ep, req))
++                                      done(ep, req, 0);
++                              /* else more OUT packets expected */
++                      } /* else OUT token before read was issued */
++              } else /* irq was IPR clearing */ {
++                      DBG(DBG_VERBOSE, "ep0out premature status\n");
++                      if (req)
++                              done(ep, req, 0);
++                      ep0_idle(dev);
++              }
++              break;
++      case EP0_END_XFER:
++              if (req)
++                      done(ep, req, 0);
++              /* ack control-IN status (maybe in-zlp was skipped)
++               * also appears after some config change events.
++               */
++              if (udccs0 & UDCCS0_OPR)
++                      UDCCS0 = UDCCS0_OPR;
++              ep0_idle(dev);
++              break;
++      case EP0_STALL:
++              UDCCS0 = UDCCS0_FST;
++              break;
++      }
++      USIR0 = USIR0_IR0;
++}
++
++static void handle_ep(struct pxa25x_ep *ep)
++{
++      struct pxa25x_request   *req;
++      int                     is_in = ep->bEndpointAddress & USB_DIR_IN;
++      int                     completed;
++      u32                     udccs, tmp;
++
++      do {
++              completed = 0;
++              if (likely (!list_empty(&ep->queue)))
++                      req = list_entry(ep->queue.next,
++                                      struct pxa25x_request, queue);
++              else
++                      req = NULL;
++
++              // TODO check FST handling
++
++              udccs = *ep->reg_udccs;
++              if (unlikely(is_in)) {  /* irq from TPC, SST, or (ISO) TUR */
++                      tmp = UDCCS_BI_TUR;
++                      if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK))
++                              tmp |= UDCCS_BI_SST;
++                      tmp &= udccs;
++                      if (likely (tmp))
++                              *ep->reg_udccs = tmp;
++                      if (req && likely ((udccs & UDCCS_BI_TFS) != 0))
++                              completed = write_fifo(ep, req);
++
++              } else {        /* irq from RPC (or for ISO, ROF) */
++                      if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK))
++                              tmp = UDCCS_BO_SST | UDCCS_BO_DME;
++                      else
++                              tmp = UDCCS_IO_ROF | UDCCS_IO_DME;
++                      tmp &= udccs;
++                      if (likely(tmp))
++                              *ep->reg_udccs = tmp;
++
++                      /* fifos can hold packets, ready for reading... */
++                      if (likely(req)) {
++                              completed = read_fifo(ep, req);
++                      } else
++                              pio_irq_disable (ep->bEndpointAddress);
++              }
++              ep->pio_irqs++;
++      } while (completed);
++}
++
++/*
++ *    pxa25x_udc_irq - interrupt handler
++ *
++ * avoid delays in ep0 processing. the control handshaking isn't always
++ * under software control (pxa250c0 and the pxa255 are better), and delays
++ * could cause usb protocol errors.
++ */
++static irqreturn_t
++pxa25x_udc_irq(int irq, void *_dev)
++{
++      struct pxa25x_udc       *dev = _dev;
++      int                     handled;
++
++      dev->stats.irqs++;
++      do {
++              u32             udccr = UDCCR;
++
++              handled = 0;
++
++              /* SUSpend Interrupt Request */
++              if (unlikely(udccr & UDCCR_SUSIR)) {
++                      udc_ack_int_UDCCR(UDCCR_SUSIR);
++                      handled = 1;
++                      DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present()
++                              ? "" : "+disconnect");
++
++                      if (!is_vbus_present())
++                              stop_activity(dev, dev->driver);
++                      else if (dev->gadget.speed != USB_SPEED_UNKNOWN
++                                      && dev->driver
++                                      && dev->driver->suspend)
++                              dev->driver->suspend(&dev->gadget);
++                      ep0_idle (dev);
++              }
++
++              /* RESume Interrupt Request */
++              if (unlikely(udccr & UDCCR_RESIR)) {
++                      udc_ack_int_UDCCR(UDCCR_RESIR);
++                      handled = 1;
++                      DBG(DBG_VERBOSE, "USB resume\n");
++
++                      if (dev->gadget.speed != USB_SPEED_UNKNOWN
++                                      && dev->driver
++                                      && dev->driver->resume
++                                      && is_vbus_present())
++                              dev->driver->resume(&dev->gadget);
++              }
++
++              /* ReSeT Interrupt Request - USB reset */
++              if (unlikely(udccr & UDCCR_RSTIR)) {
++                      udc_ack_int_UDCCR(UDCCR_RSTIR);
++                      handled = 1;
++
++                      if ((UDCCR & UDCCR_UDA) == 0) {
++                              DBG(DBG_VERBOSE, "USB reset start\n");
++
++                              /* reset driver and endpoints,
++                               * in case that's not yet done
++                               */
++                              stop_activity (dev, dev->driver);
++
++                      } else {
++                              DBG(DBG_VERBOSE, "USB reset end\n");
++                              dev->gadget.speed = USB_SPEED_FULL;
++                              memset(&dev->stats, 0, sizeof dev->stats);
++                              /* driver and endpoints are still reset */
++                      }
++
++              } else {
++                      u32     usir0 = USIR0 & ~UICR0;
++                      u32     usir1 = USIR1 & ~UICR1;
++                      int     i;
++
++                      if (unlikely (!usir0 && !usir1))
++                              continue;
++
++                      DBG(DBG_VERY_NOISY, "irq %02x.%02x\n", usir1, usir0);
++
++                      /* control traffic */
++                      if (usir0 & USIR0_IR0) {
++                              dev->ep[0].pio_irqs++;
++                              handle_ep0(dev);
++                              handled = 1;
++                      }
++
++                      /* endpoint data transfers */
++                      for (i = 0; i < 8; i++) {
++                              u32     tmp = 1 << i;
++
++                              if (i && (usir0 & tmp)) {
++                                      handle_ep(&dev->ep[i]);
++                                      USIR0 |= tmp;
++                                      handled = 1;
++                              }
++                              if (usir1 & tmp) {
++                                      handle_ep(&dev->ep[i+8]);
++                                      USIR1 |= tmp;
++                                      handled = 1;
++                              }
++                      }
++              }
++
++              /* we could also ask for 1 msec SOF (SIR) interrupts */
++
++      } while (handled);
++      return IRQ_HANDLED;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void nop_release (struct device *dev)
++{
++      DMSG("%s %s\n", __func__, dev_name(dev));
++}
++
++/* this uses load-time allocation and initialization (instead of
++ * doing it at run-time) to save code, eliminate fault paths, and
++ * be more obviously correct.
++ */
++static struct pxa25x_udc memory = {
++      .gadget = {
++              .ops            = &pxa25x_udc_ops,
++              .ep0            = &memory.ep[0].ep,
++              .name           = driver_name,
++              .dev = {
++                      .bus_id         = "gadget",
++                      .release        = nop_release,
++              },
++      },
++
++      /* control endpoint */
++      .ep[0] = {
++              .ep = {
++                      .name           = ep0name,
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = EP0_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .reg_udccs      = &UDCCS0,
++              .reg_uddr       = &UDDR0,
++      },
++
++      /* first group of endpoints */
++      .ep[1] = {
++              .ep = {
++                      .name           = "ep1in-bulk",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = BULK_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = BULK_FIFO_SIZE,
++              .bEndpointAddress = USB_DIR_IN | 1,
++              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
++              .reg_udccs      = &UDCCS1,
++              .reg_uddr       = &UDDR1,
++      },
++      .ep[2] = {
++              .ep = {
++                      .name           = "ep2out-bulk",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = BULK_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = BULK_FIFO_SIZE,
++              .bEndpointAddress = 2,
++              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
++              .reg_udccs      = &UDCCS2,
++              .reg_ubcr       = &UBCR2,
++              .reg_uddr       = &UDDR2,
++      },
++#ifndef CONFIG_USB_PXA25X_SMALL
++      .ep[3] = {
++              .ep = {
++                      .name           = "ep3in-iso",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = ISO_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = ISO_FIFO_SIZE,
++              .bEndpointAddress = USB_DIR_IN | 3,
++              .bmAttributes   = USB_ENDPOINT_XFER_ISOC,
++              .reg_udccs      = &UDCCS3,
++              .reg_uddr       = &UDDR3,
++      },
++      .ep[4] = {
++              .ep = {
++                      .name           = "ep4out-iso",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = ISO_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = ISO_FIFO_SIZE,
++              .bEndpointAddress = 4,
++              .bmAttributes   = USB_ENDPOINT_XFER_ISOC,
++              .reg_udccs      = &UDCCS4,
++              .reg_ubcr       = &UBCR4,
++              .reg_uddr       = &UDDR4,
++      },
++      .ep[5] = {
++              .ep = {
++                      .name           = "ep5in-int",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = INT_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = INT_FIFO_SIZE,
++              .bEndpointAddress = USB_DIR_IN | 5,
++              .bmAttributes   = USB_ENDPOINT_XFER_INT,
++              .reg_udccs      = &UDCCS5,
++              .reg_uddr       = &UDDR5,
++      },
++
++      /* second group of endpoints */
++      .ep[6] = {
++              .ep = {
++                      .name           = "ep6in-bulk",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = BULK_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = BULK_FIFO_SIZE,
++              .bEndpointAddress = USB_DIR_IN | 6,
++              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
++              .reg_udccs      = &UDCCS6,
++              .reg_uddr       = &UDDR6,
++      },
++      .ep[7] = {
++              .ep = {
++                      .name           = "ep7out-bulk",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = BULK_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = BULK_FIFO_SIZE,
++              .bEndpointAddress = 7,
++              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
++              .reg_udccs      = &UDCCS7,
++              .reg_ubcr       = &UBCR7,
++              .reg_uddr       = &UDDR7,
++      },
++      .ep[8] = {
++              .ep = {
++                      .name           = "ep8in-iso",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = ISO_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = ISO_FIFO_SIZE,
++              .bEndpointAddress = USB_DIR_IN | 8,
++              .bmAttributes   = USB_ENDPOINT_XFER_ISOC,
++              .reg_udccs      = &UDCCS8,
++              .reg_uddr       = &UDDR8,
++      },
++      .ep[9] = {
++              .ep = {
++                      .name           = "ep9out-iso",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = ISO_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = ISO_FIFO_SIZE,
++              .bEndpointAddress = 9,
++              .bmAttributes   = USB_ENDPOINT_XFER_ISOC,
++              .reg_udccs      = &UDCCS9,
++              .reg_ubcr       = &UBCR9,
++              .reg_uddr       = &UDDR9,
++      },
++      .ep[10] = {
++              .ep = {
++                      .name           = "ep10in-int",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = INT_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = INT_FIFO_SIZE,
++              .bEndpointAddress = USB_DIR_IN | 10,
++              .bmAttributes   = USB_ENDPOINT_XFER_INT,
++              .reg_udccs      = &UDCCS10,
++              .reg_uddr       = &UDDR10,
++      },
++
++      /* third group of endpoints */
++      .ep[11] = {
++              .ep = {
++                      .name           = "ep11in-bulk",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = BULK_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = BULK_FIFO_SIZE,
++              .bEndpointAddress = USB_DIR_IN | 11,
++              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
++              .reg_udccs      = &UDCCS11,
++              .reg_uddr       = &UDDR11,
++      },
++      .ep[12] = {
++              .ep = {
++                      .name           = "ep12out-bulk",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = BULK_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = BULK_FIFO_SIZE,
++              .bEndpointAddress = 12,
++              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
++              .reg_udccs      = &UDCCS12,
++              .reg_ubcr       = &UBCR12,
++              .reg_uddr       = &UDDR12,
++      },
++      .ep[13] = {
++              .ep = {
++                      .name           = "ep13in-iso",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = ISO_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = ISO_FIFO_SIZE,
++              .bEndpointAddress = USB_DIR_IN | 13,
++              .bmAttributes   = USB_ENDPOINT_XFER_ISOC,
++              .reg_udccs      = &UDCCS13,
++              .reg_uddr       = &UDDR13,
++      },
++      .ep[14] = {
++              .ep = {
++                      .name           = "ep14out-iso",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = ISO_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = ISO_FIFO_SIZE,
++              .bEndpointAddress = 14,
++              .bmAttributes   = USB_ENDPOINT_XFER_ISOC,
++              .reg_udccs      = &UDCCS14,
++              .reg_ubcr       = &UBCR14,
++              .reg_uddr       = &UDDR14,
++      },
++      .ep[15] = {
++              .ep = {
++                      .name           = "ep15in-int",
++                      .ops            = &pxa25x_ep_ops,
++                      .maxpacket      = INT_FIFO_SIZE,
++              },
++              .dev            = &memory,
++              .fifo_size      = INT_FIFO_SIZE,
++              .bEndpointAddress = USB_DIR_IN | 15,
++              .bmAttributes   = USB_ENDPOINT_XFER_INT,
++              .reg_udccs      = &UDCCS15,
++              .reg_uddr       = &UDDR15,
++      },
++#endif /* !CONFIG_USB_PXA25X_SMALL */
++};
++
++#define CP15R0_VENDOR_MASK    0xffffe000
++
++#if   defined(CONFIG_ARCH_PXA)
++#define CP15R0_XSCALE_VALUE   0x69052000      /* intel/arm/xscale */
++
++#elif defined(CONFIG_ARCH_IXP4XX)
++#define CP15R0_XSCALE_VALUE   0x69054000      /* intel/arm/ixp4xx */
++
++#endif
++
++#define CP15R0_PROD_MASK      0x000003f0
++#define PXA25x                        0x00000100      /* and PXA26x */
++#define PXA210                        0x00000120
++
++#define CP15R0_REV_MASK               0x0000000f
++
++#define CP15R0_PRODREV_MASK   (CP15R0_PROD_MASK | CP15R0_REV_MASK)
++
++#define PXA255_A0             0x00000106      /* or PXA260_B1 */
++#define PXA250_C0             0x00000105      /* or PXA26x_B0 */
++#define PXA250_B2             0x00000104
++#define PXA250_B1             0x00000103      /* or PXA260_A0 */
++#define PXA250_B0             0x00000102
++#define PXA250_A1             0x00000101
++#define PXA250_A0             0x00000100
++
++#define PXA210_C0             0x00000125
++#define PXA210_B2             0x00000124
++#define PXA210_B1             0x00000123
++#define PXA210_B0             0x00000122
++#define IXP425_A0             0x000001c1
++#define IXP425_B0             0x000001f1
++#define IXP465_AD             0x00000200
++
++/*
++ *    probe - binds to the platform device
++ */
++static int __init pxa25x_udc_probe(struct platform_device *pdev)
++{
++      struct pxa25x_udc *dev = &memory;
++      int retval, vbus_irq, irq;
++      u32 chiprev;
++
++      /* insist on Intel/ARM/XScale */
++      asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev));
++      if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) {
++              pr_err("%s: not XScale!\n", driver_name);
++              return -ENODEV;
++      }
++
++      /* trigger chiprev-specific logic */
++      switch (chiprev & CP15R0_PRODREV_MASK) {
++#if   defined(CONFIG_ARCH_PXA)
++      case PXA255_A0:
++              dev->has_cfr = 1;
++              break;
++      case PXA250_A0:
++      case PXA250_A1:
++              /* A0/A1 "not released"; ep 13, 15 unusable */
++              /* fall through */
++      case PXA250_B2: case PXA210_B2:
++      case PXA250_B1: case PXA210_B1:
++      case PXA250_B0: case PXA210_B0:
++              /* OUT-DMA is broken ... */
++              /* fall through */
++      case PXA250_C0: case PXA210_C0:
++              break;
++#elif defined(CONFIG_ARCH_IXP4XX)
++      case IXP425_A0:
++      case IXP425_B0:
++      case IXP465_AD:
++              dev->has_cfr = 1;
++              break;
++#endif
++      default:
++              pr_err("%s: unrecognized processor: %08x\n",
++                      driver_name, chiprev);
++              /* iop3xx, ixp4xx, ... */
++              return -ENODEV;
++      }
++
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0)
++              return -ENODEV;
++
++      dev->clk = clk_get(&pdev->dev, "UDCCLK");
++      if (IS_ERR(dev->clk)) {
++              retval = PTR_ERR(dev->clk);
++              goto err_clk;
++      }
++
++      pr_debug("%s: IRQ %d%s%s\n", driver_name, irq,
++              dev->has_cfr ? "" : " (!cfr)",
++              SIZE_STR "(pio)"
++              );
++
++      /* other non-static parts of init */
++      dev->dev = &pdev->dev;
++      dev->mach = pdev->dev.platform_data;
++
++      if (dev->mach->gpio_vbus) {
++              if ((retval = gpio_request(dev->mach->gpio_vbus,
++                              "pxa25x_udc GPIO VBUS"))) {
++                      dev_dbg(&pdev->dev,
++                              "can't get vbus gpio %d, err: %d\n",
++                              dev->mach->gpio_vbus, retval);
++                      goto err_gpio_vbus;
++              }
++              gpio_direction_input(dev->mach->gpio_vbus);
++              vbus_irq = gpio_to_irq(dev->mach->gpio_vbus);
++      } else
++              vbus_irq = 0;
++
++      if (dev->mach->gpio_pullup) {
++              if ((retval = gpio_request(dev->mach->gpio_pullup,
++                              "pca25x_udc GPIO PULLUP"))) {
++                      dev_dbg(&pdev->dev,
++                              "can't get pullup gpio %d, err: %d\n",
++                              dev->mach->gpio_pullup, retval);
++                      goto err_gpio_pullup;
++              }
++              gpio_direction_output(dev->mach->gpio_pullup, 0);
++      }
++
++      init_timer(&dev->timer);
++      dev->timer.function = udc_watchdog;
++      dev->timer.data = (unsigned long) dev;
++
++      device_initialize(&dev->gadget.dev);
++      dev->gadget.dev.parent = &pdev->dev;
++      dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
++
++      the_controller = dev;
++      platform_set_drvdata(pdev, dev);
++
++      udc_disable(dev);
++      udc_reinit(dev);
++
++      dev->vbus = is_vbus_present();
++
++      /* irq setup after old hardware state is cleaned up */
++      retval = request_irq(irq, pxa25x_udc_irq,
++                      IRQF_DISABLED, driver_name, dev);
++      if (retval != 0) {
++              pr_err("%s: can't get irq %d, err %d\n",
++                      driver_name, irq, retval);
++              goto err_irq1;
++      }
++      dev->got_irq = 1;
++
++#ifdef CONFIG_ARCH_LUBBOCK
++      if (machine_is_lubbock()) {
++              retval = request_irq(LUBBOCK_USB_DISC_IRQ,
++                              lubbock_vbus_irq,
++                              IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
++                              driver_name, dev);
++              if (retval != 0) {
++                      pr_err("%s: can't get irq %i, err %d\n",
++                              driver_name, LUBBOCK_USB_DISC_IRQ, retval);
++lubbock_fail0:
++                      goto err_irq_lub;
++              }
++              retval = request_irq(LUBBOCK_USB_IRQ,
++                              lubbock_vbus_irq,
++                              IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
++                              driver_name, dev);
++              if (retval != 0) {
++                      pr_err("%s: can't get irq %i, err %d\n",
++                              driver_name, LUBBOCK_USB_IRQ, retval);
++                      free_irq(LUBBOCK_USB_DISC_IRQ, dev);
++                      goto lubbock_fail0;
++              }
++      } else
++#endif
++      if (vbus_irq) {
++              retval = request_irq(vbus_irq, udc_vbus_irq,
++                              IRQF_DISABLED | IRQF_SAMPLE_RANDOM |
++                              IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
++                              driver_name, dev);
++              if (retval != 0) {
++                      pr_err("%s: can't get irq %i, err %d\n",
++                              driver_name, vbus_irq, retval);
++                      goto err_vbus_irq;
++              }
++      }
++      create_debug_files(dev);
++
++      return 0;
++
++ err_vbus_irq:
++#ifdef        CONFIG_ARCH_LUBBOCK
++      free_irq(LUBBOCK_USB_DISC_IRQ, dev);
++ err_irq_lub:
++#endif
++      free_irq(irq, dev);
++ err_irq1:
++      if (dev->mach->gpio_pullup)
++              gpio_free(dev->mach->gpio_pullup);
++ err_gpio_pullup:
++      if (dev->mach->gpio_vbus)
++              gpio_free(dev->mach->gpio_vbus);
++ err_gpio_vbus:
++      clk_put(dev->clk);
++ err_clk:
++      return retval;
++}
++
++static void pxa25x_udc_shutdown(struct platform_device *_dev)
++{
++      pullup_off();
++}
++
++static int __exit pxa25x_udc_remove(struct platform_device *pdev)
++{
++      struct pxa25x_udc *dev = platform_get_drvdata(pdev);
++
++      if (dev->driver)
++              return -EBUSY;
++
++      dev->pullup = 0;
++      pullup(dev);
++
++      remove_debug_files(dev);
++
++      if (dev->got_irq) {
++              free_irq(platform_get_irq(pdev, 0), dev);
++              dev->got_irq = 0;
++      }
++#ifdef CONFIG_ARCH_LUBBOCK
++      if (machine_is_lubbock()) {
++              free_irq(LUBBOCK_USB_DISC_IRQ, dev);
++              free_irq(LUBBOCK_USB_IRQ, dev);
++      }
++#endif
++      if (dev->mach->gpio_vbus) {
++              free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev);
++              gpio_free(dev->mach->gpio_vbus);
++      }
++      if (dev->mach->gpio_pullup)
++              gpio_free(dev->mach->gpio_pullup);
++
++      clk_put(dev->clk);
++
++      platform_set_drvdata(pdev, NULL);
++      the_controller = NULL;
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++#ifdef        CONFIG_PM
++
++/* USB suspend (controlled by the host) and system suspend (controlled
++ * by the PXA) don't necessarily work well together.  If USB is active,
++ * the 48 MHz clock is required; so the system can't enter 33 MHz idle
++ * mode, or any deeper PM saving state.
++ *
++ * For now, we punt and forcibly disconnect from the USB host when PXA
++ * enters any suspend state.  While we're disconnected, we always disable
++ * the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states.
++ * Boards without software pullup control shouldn't use those states.
++ * VBUS IRQs should probably be ignored so that the PXA device just acts
++ * "dead" to USB hosts until system resume.
++ */
++static int pxa25x_udc_suspend(struct platform_device *dev, pm_message_t state)
++{
++      struct pxa25x_udc       *udc = platform_get_drvdata(dev);
++      unsigned long flags;
++
++      if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
++              WARNING("USB host won't detect disconnect!\n");
++      udc->suspended = 1;
++
++      local_irq_save(flags);
++      pullup(udc);
++      local_irq_restore(flags);
++
++      return 0;
++}
++
++static int pxa25x_udc_resume(struct platform_device *dev)
++{
++      struct pxa25x_udc       *udc = platform_get_drvdata(dev);
++      unsigned long flags;
++
++      udc->suspended = 0;
++      local_irq_save(flags);
++      pullup(udc);
++      local_irq_restore(flags);
++
++      return 0;
++}
++
++#else
++#define       pxa25x_udc_suspend      NULL
++#define       pxa25x_udc_resume       NULL
++#endif
++
++/*-------------------------------------------------------------------------*/
++
++static struct platform_driver udc_driver = {
++      .shutdown       = pxa25x_udc_shutdown,
++      .remove         = __exit_p(pxa25x_udc_remove),
++      .suspend        = pxa25x_udc_suspend,
++      .resume         = pxa25x_udc_resume,
++      .driver         = {
++              .owner  = THIS_MODULE,
++              .name   = "pxa25x-udc",
++      },
++};
++
++static int __init udc_init(void)
++{
++      pr_info("%s: version %s\n", driver_name, DRIVER_VERSION);
++      return platform_driver_probe(&udc_driver, pxa25x_udc_probe);
++}
++module_init(udc_init);
++
++static void __exit udc_exit(void)
++{
++      platform_driver_unregister(&udc_driver);
++}
++module_exit(udc_exit);
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:pxa25x-udc");
+diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h
+new file mode 100644
+index 0000000..1d51aa2
+--- /dev/null
++++ b/drivers/usb/gadget/pxa25x_udc.h
+@@ -0,0 +1,266 @@
++/*
++ * Intel PXA25x on-chip full speed USB device controller
++ *
++ * Copyright (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix
++ * Copyright (C) 2003 David Brownell
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef __LINUX_USB_GADGET_PXA25X_H
++#define __LINUX_USB_GADGET_PXA25X_H
++
++#include <linux/types.h>
++
++/*-------------------------------------------------------------------------*/
++
++/* pxa25x has this (move to include/asm-arm/arch-pxa/pxa-regs.h) */
++#define UFNRH_SIR     (1 << 7)        /* SOF interrupt request */
++#define UFNRH_SIM     (1 << 6)        /* SOF interrupt mask */
++#define UFNRH_IPE14   (1 << 5)        /* ISO packet error, ep14 */
++#define UFNRH_IPE9    (1 << 4)        /* ISO packet error, ep9 */
++#define UFNRH_IPE4    (1 << 3)        /* ISO packet error, ep4 */
++
++/* pxa255 has this (move to include/asm-arm/arch-pxa/pxa-regs.h) */
++#define       UDCCFR          UDC_RES2        /* UDC Control Function Register */
++#define UDCCFR_AREN   (1 << 7)        /* ACK response enable (now) */
++#define UDCCFR_ACM    (1 << 2)        /* ACK control mode (wait for AREN) */
++
++/* latest pxa255 errata define new "must be one" bits in UDCCFR */
++#define       UDCCFR_MB1      (0xff & ~(UDCCFR_AREN|UDCCFR_ACM))
++
++/*-------------------------------------------------------------------------*/
++
++struct pxa25x_udc;
++
++struct pxa25x_ep {
++      struct usb_ep                           ep;
++      struct pxa25x_udc                       *dev;
++
++      const struct usb_endpoint_descriptor    *desc;
++      struct list_head                        queue;
++      unsigned long                           pio_irqs;
++
++      unsigned short                          fifo_size;
++      u8                                      bEndpointAddress;
++      u8                                      bmAttributes;
++
++      unsigned                                stopped : 1;
++      unsigned                                dma_fixup : 1;
++
++      /* UDCCS = UDC Control/Status for this EP
++       * UBCR = UDC Byte Count Remaining (contents of OUT fifo)
++       * UDDR = UDC Endpoint Data Register (the fifo)
++       * DRCM = DMA Request Channel Map
++       */
++      volatile u32                            *reg_udccs;
++      volatile u32                            *reg_ubcr;
++      volatile u32                            *reg_uddr;
++};
++
++struct pxa25x_request {
++      struct usb_request                      req;
++      struct list_head                        queue;
++};
++
++enum ep0_state {
++      EP0_IDLE,
++      EP0_IN_DATA_PHASE,
++      EP0_OUT_DATA_PHASE,
++      EP0_END_XFER,
++      EP0_STALL,
++};
++
++#define EP0_FIFO_SIZE ((unsigned)16)
++#define BULK_FIFO_SIZE        ((unsigned)64)
++#define ISO_FIFO_SIZE ((unsigned)256)
++#define INT_FIFO_SIZE ((unsigned)8)
++
++struct udc_stats {
++      struct ep0stats {
++              unsigned long           ops;
++              unsigned long           bytes;
++      } read, write;
++      unsigned long                   irqs;
++};
++
++#ifdef CONFIG_USB_PXA25X_SMALL
++/* when memory's tight, SMALL config saves code+data.  */
++#define       PXA_UDC_NUM_ENDPOINTS   3
++#endif
++
++#ifndef       PXA_UDC_NUM_ENDPOINTS
++#define       PXA_UDC_NUM_ENDPOINTS   16
++#endif
++
++struct pxa25x_udc {
++      struct usb_gadget                       gadget;
++      struct usb_gadget_driver                *driver;
++
++      enum ep0_state                          ep0state;
++      struct udc_stats                        stats;
++      unsigned                                got_irq : 1,
++                                              vbus : 1,
++                                              pullup : 1,
++                                              has_cfr : 1,
++                                              req_pending : 1,
++                                              req_std : 1,
++                                              req_config : 1,
++                                              suspended : 1,
++                                              active : 1;
++
++#define start_watchdog(dev) mod_timer(&dev->timer, jiffies + (HZ/200))
++      struct timer_list                       timer;
++
++      struct device                           *dev;
++      struct clk                              *clk;
++      struct pxa2xx_udc_mach_info             *mach;
++      u64                                     dma_mask;
++      struct pxa25x_ep                        ep [PXA_UDC_NUM_ENDPOINTS];
++
++#ifdef CONFIG_USB_GADGET_DEBUG_FS
++      struct dentry                           *debugfs_udc;
++#endif
++};
++
++/*-------------------------------------------------------------------------*/
++
++#ifdef CONFIG_ARCH_LUBBOCK
++#include <mach/lubbock.h>
++/* lubbock can also report usb connect/disconnect irqs */
++#endif
++
++static struct pxa25x_udc *the_controller;
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * Debugging support vanishes in non-debug builds.  DBG_NORMAL should be
++ * mostly silent during normal use/testing, with no timing side-effects.
++ */
++#define DBG_NORMAL    1       /* error paths, device state transitions */
++#define DBG_VERBOSE   2       /* add some success path trace info */
++#define DBG_NOISY     3       /* ... even more: request level */
++#define DBG_VERY_NOISY        4       /* ... even more: packet level */
++
++#define DMSG(stuff...)        pr_debug("udc: " stuff)
++
++#ifdef DEBUG
++
++static int is_vbus_present(void);
++
++static const char *state_name[] = {
++      "EP0_IDLE",
++      "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE",
++      "EP0_END_XFER", "EP0_STALL"
++};
++
++#ifdef VERBOSE_DEBUG
++#    define UDC_DEBUG DBG_VERBOSE
++#else
++#    define UDC_DEBUG DBG_NORMAL
++#endif
++
++static void __maybe_unused
++dump_udccr(const char *label)
++{
++      u32     udccr = UDCCR;
++      DMSG("%s %02X =%s%s%s%s%s%s%s%s\n",
++              label, udccr,
++              (udccr & UDCCR_REM) ? " rem" : "",
++              (udccr & UDCCR_RSTIR) ? " rstir" : "",
++              (udccr & UDCCR_SRM) ? " srm" : "",
++              (udccr & UDCCR_SUSIR) ? " susir" : "",
++              (udccr & UDCCR_RESIR) ? " resir" : "",
++              (udccr & UDCCR_RSM) ? " rsm" : "",
++              (udccr & UDCCR_UDA) ? " uda" : "",
++              (udccr & UDCCR_UDE) ? " ude" : "");
++}
++
++static void __maybe_unused
++dump_udccs0(const char *label)
++{
++      u32             udccs0 = UDCCS0;
++
++      DMSG("%s %s %02X =%s%s%s%s%s%s%s%s\n",
++              label, state_name[the_controller->ep0state], udccs0,
++              (udccs0 & UDCCS0_SA) ? " sa" : "",
++              (udccs0 & UDCCS0_RNE) ? " rne" : "",
++              (udccs0 & UDCCS0_FST) ? " fst" : "",
++              (udccs0 & UDCCS0_SST) ? " sst" : "",
++              (udccs0 & UDCCS0_DRWF) ? " dwrf" : "",
++              (udccs0 & UDCCS0_FTF) ? " ftf" : "",
++              (udccs0 & UDCCS0_IPR) ? " ipr" : "",
++              (udccs0 & UDCCS0_OPR) ? " opr" : "");
++}
++
++static void __maybe_unused
++dump_state(struct pxa25x_udc *dev)
++{
++      u32             tmp;
++      unsigned        i;
++
++      DMSG("%s %s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
++              is_vbus_present() ? "host " : "disconnected",
++              state_name[dev->ep0state],
++              UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
++      dump_udccr("udccr");
++      if (dev->has_cfr) {
++              tmp = UDCCFR;
++              DMSG("udccfr %02X =%s%s\n", tmp,
++                      (tmp & UDCCFR_AREN) ? " aren" : "",
++                      (tmp & UDCCFR_ACM) ? " acm" : "");
++      }
++
++      if (!dev->driver) {
++              DMSG("no gadget driver bound\n");
++              return;
++      } else
++              DMSG("ep0 driver '%s'\n", dev->driver->driver.name);
++
++      if (!is_vbus_present())
++              return;
++
++      dump_udccs0 ("udccs0");
++      DMSG("ep0 IN %lu/%lu, OUT %lu/%lu\n",
++              dev->stats.write.bytes, dev->stats.write.ops,
++              dev->stats.read.bytes, dev->stats.read.ops);
++
++      for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) {
++              if (dev->ep [i].desc == NULL)
++                      continue;
++              DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs);
++      }
++}
++
++#else
++
++#define       dump_udccr(x)   do{}while(0)
++#define       dump_udccs0(x)  do{}while(0)
++#define       dump_state(x)   do{}while(0)
++
++#define UDC_DEBUG ((unsigned)0)
++
++#endif
++
++#define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0)
++
++#define ERR(stuff...)         pr_err("udc: " stuff)
++#define WARNING(stuff...)     pr_warning("udc: " stuff)
++#define INFO(stuff...)                pr_info("udc: " stuff)
++
++
++#endif /* __LINUX_USB_GADGET_PXA25X_H */
+diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
+index e02bfd4..7cbc78a 100644
+--- a/drivers/usb/gadget/pxa27x_udc.c
++++ b/drivers/usb/gadget/pxa27x_udc.c
+@@ -33,13 +33,13 @@
+ #include <linux/irq.h>
+ #include <asm/byteorder.h>
+-#include <asm/hardware.h>
++#include <mach/hardware.h>
+ #include <linux/usb.h>
+ #include <linux/usb/ch9.h>
+ #include <linux/usb/gadget.h>
+-
+-#include <asm/arch/udc.h>
++#include <mach/pxa2xx-regs.h> /* FIXME: for PSSR */
++#include <mach/udc.h>
+ #include "pxa27x_udc.h"
+@@ -1575,7 +1575,6 @@ static void udc_enable(struct pxa_udc *udc)
+ {
+       udc_writel(udc, UDCICR0, 0);
+       udc_writel(udc, UDCICR1, 0);
+-      udc_writel(udc, UP2OCR, UP2OCR_HXOE);
+       udc_clear_mask_UDCCR(udc, UDCCR_UDE);
+       clk_enable(udc->clk);
+@@ -1623,7 +1622,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+       struct pxa_udc *udc = the_controller;
+       int retval;
+-      if (!driver || driver->speed != USB_SPEED_FULL || !driver->bind
++      if (!driver || driver->speed < USB_SPEED_FULL || !driver->bind
+                       || !driver->disconnect || !driver->setup)
+               return -EINVAL;
+       if (!udc)
+@@ -2360,18 +2359,19 @@ static int pxa_udc_resume(struct platform_device *_dev)
+        * Software must configure the USB OTG pad, UDC, and UHC
+        * to the state they were in before entering sleep mode.
+        */
+-      PSSR |= PSSR_OTGPH;
++      if (cpu_is_pxa27x())
++              PSSR |= PSSR_OTGPH;
+       return 0;
+ }
+ #endif
+ /* work with hotplug and coldplug */
+-MODULE_ALIAS("platform:pxa2xx-udc");
++MODULE_ALIAS("platform:pxa27x-udc");
+ static struct platform_driver udc_driver = {
+       .driver         = {
+-              .name   = "pxa2xx-udc",
++              .name   = "pxa27x-udc",
+               .owner  = THIS_MODULE,
+       },
+       .remove         = __exit_p(pxa_udc_remove),
+diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h
+index 97453db..1d1b793 100644
+--- a/drivers/usb/gadget/pxa27x_udc.h
++++ b/drivers/usb/gadget/pxa27x_udc.h
+@@ -484,12 +484,4 @@ static inline struct pxa_udc *to_gadget_udc(struct usb_gadget *gadget)
+ #define ep_warn(ep, fmt, arg...) \
+       dev_warn(ep->dev->dev, "%s:%s:" fmt, EPNAME(ep), __func__, ## arg)
+-/*
+- * Cannot include pxa-regs.h, as register names are similar.
+- * So PSSR is redefined here. This should be removed once UDC registers will
+- * be gone from pxa-regs.h.
+- */
+-#define PSSR          __REG(0x40F00004)       /* Power Manager Sleep Status */
+-#define PSSR_OTGPH    (1 << 6)                /* OTG Peripheral Hold */
+-
+ #endif /* __LINUX_USB_GADGET_PXA27X_H */
+diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
+deleted file mode 100644
+index 08f699b..0000000
+--- a/drivers/usb/gadget/pxa2xx_udc.c
++++ /dev/null
+@@ -1,2383 +0,0 @@
+-/*
+- * linux/drivers/usb/gadget/pxa2xx_udc.c
+- * Intel PXA25x and IXP4xx on-chip full speed USB device controllers
+- *
+- * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
+- * Copyright (C) 2003 Robert Schwebel, Pengutronix
+- * Copyright (C) 2003 Benedikt Spranger, Pengutronix
+- * Copyright (C) 2003 David Brownell
+- * Copyright (C) 2003 Joshua Wise
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+- *
+- */
+-
+-/* #define VERBOSE_DEBUG */
+-
+-#include <linux/device.h>
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/ioport.h>
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/delay.h>
+-#include <linux/slab.h>
+-#include <linux/init.h>
+-#include <linux/timer.h>
+-#include <linux/list.h>
+-#include <linux/interrupt.h>
+-#include <linux/mm.h>
+-#include <linux/platform_device.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/irq.h>
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-#include <linux/seq_file.h>
+-#include <linux/debugfs.h>
+-
+-#include <asm/byteorder.h>
+-#include <asm/dma.h>
+-#include <asm/gpio.h>
+-#include <asm/io.h>
+-#include <asm/system.h>
+-#include <asm/mach-types.h>
+-#include <asm/unaligned.h>
+-#include <asm/hardware.h>
+-
+-#include <linux/usb/ch9.h>
+-#include <linux/usb/gadget.h>
+-
+-#include <asm/mach/udc_pxa2xx.h>
+-
+-
+-/*
+- * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x
+- * series processors.  The UDC for the IXP 4xx series is very similar.
+- * There are fifteen endpoints, in addition to ep0.
+- *
+- * Such controller drivers work with a gadget driver.  The gadget driver
+- * returns descriptors, implements configuration and data protocols used
+- * by the host to interact with this device, and allocates endpoints to
+- * the different protocol interfaces.  The controller driver virtualizes
+- * usb hardware so that the gadget drivers will be more portable.
+- *
+- * This UDC hardware wants to implement a bit too much USB protocol, so
+- * it constrains the sorts of USB configuration change events that work.
+- * The errata for these chips are misleading; some "fixed" bugs from
+- * pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
+- *
+- * Note that the UDC hardware supports DMA (except on IXP) but that's
+- * not used here.  IN-DMA (to host) is simple enough, when the data is
+- * suitably aligned (16 bytes) ... the network stack doesn't do that,
+- * other software can.  OUT-DMA is buggy in most chip versions, as well
+- * as poorly designed (data toggle not automatic).  So this driver won't
+- * bother using DMA.  (Mostly-working IN-DMA support was available in
+- * kernels before 2.6.23, but was never enabled or well tested.)
+- */
+-
+-#define       DRIVER_VERSION  "30-June-2007"
+-#define       DRIVER_DESC     "PXA 25x USB Device Controller driver"
+-
+-
+-static const char driver_name [] = "pxa2xx_udc";
+-
+-static const char ep0name [] = "ep0";
+-
+-
+-#ifdef CONFIG_ARCH_IXP4XX
+-
+-/* cpu-specific register addresses are compiled in to this code */
+-#ifdef CONFIG_ARCH_PXA
+-#error "Can't configure both IXP and PXA"
+-#endif
+-
+-/* IXP doesn't yet support <linux/clk.h> */
+-#define clk_get(dev,name)     NULL
+-#define clk_enable(clk)               do { } while (0)
+-#define clk_disable(clk)      do { } while (0)
+-#define clk_put(clk)          do { } while (0)
+-
+-#endif
+-
+-#include "pxa2xx_udc.h"
+-
+-
+-#ifdef        CONFIG_USB_PXA2XX_SMALL
+-#define SIZE_STR      " (small)"
+-#else
+-#define SIZE_STR      ""
+-#endif
+-
+-/* ---------------------------------------------------------------------------
+- *    endpoint related parts of the api to the usb controller hardware,
+- *    used by gadget driver; and the inner talker-to-hardware core.
+- * ---------------------------------------------------------------------------
+- */
+-
+-static void pxa2xx_ep_fifo_flush (struct usb_ep *ep);
+-static void nuke (struct pxa2xx_ep *, int status);
+-
+-/* one GPIO should be used to detect VBUS from the host */
+-static int is_vbus_present(void)
+-{
+-      struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
+-
+-      if (mach->gpio_vbus) {
+-              int value = gpio_get_value(mach->gpio_vbus);
+-              return mach->gpio_vbus_inverted ? !value : value;
+-      }
+-      if (mach->udc_is_connected)
+-              return mach->udc_is_connected();
+-      return 1;
+-}
+-
+-/* one GPIO should control a D+ pullup, so host sees this device (or not) */
+-static void pullup_off(void)
+-{
+-      struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
+-
+-      if (mach->gpio_pullup)
+-              gpio_set_value(mach->gpio_pullup, 0);
+-      else if (mach->udc_command)
+-              mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+-}
+-
+-static void pullup_on(void)
+-{
+-      struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
+-
+-      if (mach->gpio_pullup)
+-              gpio_set_value(mach->gpio_pullup, 1);
+-      else if (mach->udc_command)
+-              mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+-}
+-
+-static void pio_irq_enable(int bEndpointAddress)
+-{
+-        bEndpointAddress &= 0xf;
+-        if (bEndpointAddress < 8)
+-                UICR0 &= ~(1 << bEndpointAddress);
+-        else {
+-                bEndpointAddress -= 8;
+-                UICR1 &= ~(1 << bEndpointAddress);
+-      }
+-}
+-
+-static void pio_irq_disable(int bEndpointAddress)
+-{
+-        bEndpointAddress &= 0xf;
+-        if (bEndpointAddress < 8)
+-                UICR0 |= 1 << bEndpointAddress;
+-        else {
+-                bEndpointAddress -= 8;
+-                UICR1 |= 1 << bEndpointAddress;
+-        }
+-}
+-
+-/* The UDCCR reg contains mask and interrupt status bits,
+- * so using '|=' isn't safe as it may ack an interrupt.
+- */
+-#define UDCCR_MASK_BITS         (UDCCR_REM | UDCCR_SRM | UDCCR_UDE)
+-
+-static inline void udc_set_mask_UDCCR(int mask)
+-{
+-      UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS);
+-}
+-
+-static inline void udc_clear_mask_UDCCR(int mask)
+-{
+-      UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS);
+-}
+-
+-static inline void udc_ack_int_UDCCR(int mask)
+-{
+-      /* udccr contains the bits we dont want to change */
+-      __u32 udccr = UDCCR & UDCCR_MASK_BITS;
+-
+-      UDCCR = udccr | (mask & ~UDCCR_MASK_BITS);
+-}
+-
+-/*
+- * endpoint enable/disable
+- *
+- * we need to verify the descriptors used to enable endpoints.  since pxa2xx
+- * endpoint configurations are fixed, and are pretty much always enabled,
+- * there's not a lot to manage here.
+- *
+- * because pxa2xx can't selectively initialize bulk (or interrupt) endpoints,
+- * (resetting endpoint halt and toggle), SET_INTERFACE is unusable except
+- * for a single interface (with only the default altsetting) and for gadget
+- * drivers that don't halt endpoints (not reset by set_interface).  that also
+- * means that if you use ISO, you must violate the USB spec rule that all
+- * iso endpoints must be in non-default altsettings.
+- */
+-static int pxa2xx_ep_enable (struct usb_ep *_ep,
+-              const struct usb_endpoint_descriptor *desc)
+-{
+-      struct pxa2xx_ep        *ep;
+-      struct pxa2xx_udc       *dev;
+-
+-      ep = container_of (_ep, struct pxa2xx_ep, ep);
+-      if (!_ep || !desc || ep->desc || _ep->name == ep0name
+-                      || desc->bDescriptorType != USB_DT_ENDPOINT
+-                      || ep->bEndpointAddress != desc->bEndpointAddress
+-                      || ep->fifo_size < le16_to_cpu
+-                                              (desc->wMaxPacketSize)) {
+-              DMSG("%s, bad ep or descriptor\n", __func__);
+-              return -EINVAL;
+-      }
+-
+-      /* xfer types must match, except that interrupt ~= bulk */
+-      if (ep->bmAttributes != desc->bmAttributes
+-                      && ep->bmAttributes != USB_ENDPOINT_XFER_BULK
+-                      && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
+-              DMSG("%s, %s type mismatch\n", __func__, _ep->name);
+-              return -EINVAL;
+-      }
+-
+-      /* hardware _could_ do smaller, but driver doesn't */
+-      if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
+-                              && le16_to_cpu (desc->wMaxPacketSize)
+-                                              != BULK_FIFO_SIZE)
+-                      || !desc->wMaxPacketSize) {
+-              DMSG("%s, bad %s maxpacket\n", __func__, _ep->name);
+-              return -ERANGE;
+-      }
+-
+-      dev = ep->dev;
+-      if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+-              DMSG("%s, bogus device state\n", __func__);
+-              return -ESHUTDOWN;
+-      }
+-
+-      ep->desc = desc;
+-      ep->stopped = 0;
+-      ep->pio_irqs = 0;
+-      ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
+-
+-      /* flush fifo (mostly for OUT buffers) */
+-      pxa2xx_ep_fifo_flush (_ep);
+-
+-      /* ... reset halt state too, if we could ... */
+-
+-      DBG(DBG_VERBOSE, "enabled %s\n", _ep->name);
+-      return 0;
+-}
+-
+-static int pxa2xx_ep_disable (struct usb_ep *_ep)
+-{
+-      struct pxa2xx_ep        *ep;
+-      unsigned long           flags;
+-
+-      ep = container_of (_ep, struct pxa2xx_ep, ep);
+-      if (!_ep || !ep->desc) {
+-              DMSG("%s, %s not enabled\n", __func__,
+-                      _ep ? ep->ep.name : NULL);
+-              return -EINVAL;
+-      }
+-      local_irq_save(flags);
+-
+-      nuke (ep, -ESHUTDOWN);
+-
+-      /* flush fifo (mostly for IN buffers) */
+-      pxa2xx_ep_fifo_flush (_ep);
+-
+-      ep->desc = NULL;
+-      ep->stopped = 1;
+-
+-      local_irq_restore(flags);
+-      DBG(DBG_VERBOSE, "%s disabled\n", _ep->name);
+-      return 0;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/* for the pxa2xx, these can just wrap kmalloc/kfree.  gadget drivers
+- * must still pass correctly initialized endpoints, since other controller
+- * drivers may care about how it's currently set up (dma issues etc).
+- */
+-
+-/*
+- *    pxa2xx_ep_alloc_request - allocate a request data structure
+- */
+-static struct usb_request *
+-pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
+-{
+-      struct pxa2xx_request *req;
+-
+-      req = kzalloc(sizeof(*req), gfp_flags);
+-      if (!req)
+-              return NULL;
+-
+-      INIT_LIST_HEAD (&req->queue);
+-      return &req->req;
+-}
+-
+-
+-/*
+- *    pxa2xx_ep_free_request - deallocate a request data structure
+- */
+-static void
+-pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req)
+-{
+-      struct pxa2xx_request   *req;
+-
+-      req = container_of (_req, struct pxa2xx_request, req);
+-      WARN_ON (!list_empty (&req->queue));
+-      kfree(req);
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/*
+- *    done - retire a request; caller blocked irqs
+- */
+-static void done(struct pxa2xx_ep *ep, struct pxa2xx_request *req, int status)
+-{
+-      unsigned                stopped = ep->stopped;
+-
+-      list_del_init(&req->queue);
+-
+-      if (likely (req->req.status == -EINPROGRESS))
+-              req->req.status = status;
+-      else
+-              status = req->req.status;
+-
+-      if (status && status != -ESHUTDOWN)
+-              DBG(DBG_VERBOSE, "complete %s req %p stat %d len %u/%u\n",
+-                      ep->ep.name, &req->req, status,
+-                      req->req.actual, req->req.length);
+-
+-      /* don't modify queue heads during completion callback */
+-      ep->stopped = 1;
+-      req->req.complete(&ep->ep, &req->req);
+-      ep->stopped = stopped;
+-}
+-
+-
+-static inline void ep0_idle (struct pxa2xx_udc *dev)
+-{
+-      dev->ep0state = EP0_IDLE;
+-}
+-
+-static int
+-write_packet(volatile u32 *uddr, struct pxa2xx_request *req, unsigned max)
+-{
+-      u8              *buf;
+-      unsigned        length, count;
+-
+-      buf = req->req.buf + req->req.actual;
+-      prefetch(buf);
+-
+-      /* how big will this packet be? */
+-      length = min(req->req.length - req->req.actual, max);
+-      req->req.actual += length;
+-
+-      count = length;
+-      while (likely(count--))
+-              *uddr = *buf++;
+-
+-      return length;
+-}
+-
+-/*
+- * write to an IN endpoint fifo, as many packets as possible.
+- * irqs will use this to write the rest later.
+- * caller guarantees at least one packet buffer is ready (or a zlp).
+- */
+-static int
+-write_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
+-{
+-      unsigned                max;
+-
+-      max = le16_to_cpu(ep->desc->wMaxPacketSize);
+-      do {
+-              unsigned        count;
+-              int             is_last, is_short;
+-
+-              count = write_packet(ep->reg_uddr, req, max);
+-
+-              /* last packet is usually short (or a zlp) */
+-              if (unlikely (count != max))
+-                      is_last = is_short = 1;
+-              else {
+-                      if (likely(req->req.length != req->req.actual)
+-                                      || req->req.zero)
+-                              is_last = 0;
+-                      else
+-                              is_last = 1;
+-                      /* interrupt/iso maxpacket may not fill the fifo */
+-                      is_short = unlikely (max < ep->fifo_size);
+-              }
+-
+-              DBG(DBG_VERY_NOISY, "wrote %s %d bytes%s%s %d left %p\n",
+-                      ep->ep.name, count,
+-                      is_last ? "/L" : "", is_short ? "/S" : "",
+-                      req->req.length - req->req.actual, req);
+-
+-              /* let loose that packet. maybe try writing another one,
+-               * double buffering might work.  TSP, TPC, and TFS
+-               * bit values are the same for all normal IN endpoints.
+-               */
+-              *ep->reg_udccs = UDCCS_BI_TPC;
+-              if (is_short)
+-                      *ep->reg_udccs = UDCCS_BI_TSP;
+-
+-              /* requests complete when all IN data is in the FIFO */
+-              if (is_last) {
+-                      done (ep, req, 0);
+-                      if (list_empty(&ep->queue))
+-                              pio_irq_disable (ep->bEndpointAddress);
+-                      return 1;
+-              }
+-
+-              // TODO experiment: how robust can fifo mode tweaking be?
+-              // double buffering is off in the default fifo mode, which
+-              // prevents TFS from being set here.
+-
+-      } while (*ep->reg_udccs & UDCCS_BI_TFS);
+-      return 0;
+-}
+-
+-/* caller asserts req->pending (ep0 irq status nyet cleared); starts
+- * ep0 data stage.  these chips want very simple state transitions.
+- */
+-static inline
+-void ep0start(struct pxa2xx_udc *dev, u32 flags, const char *tag)
+-{
+-      UDCCS0 = flags|UDCCS0_SA|UDCCS0_OPR;
+-      USIR0 = USIR0_IR0;
+-      dev->req_pending = 0;
+-      DBG(DBG_VERY_NOISY, "%s %s, %02x/%02x\n",
+-              __func__, tag, UDCCS0, flags);
+-}
+-
+-static int
+-write_ep0_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
+-{
+-      unsigned        count;
+-      int             is_short;
+-
+-      count = write_packet(&UDDR0, req, EP0_FIFO_SIZE);
+-      ep->dev->stats.write.bytes += count;
+-
+-      /* last packet "must be" short (or a zlp) */
+-      is_short = (count != EP0_FIFO_SIZE);
+-
+-      DBG(DBG_VERY_NOISY, "ep0in %d bytes %d left %p\n", count,
+-              req->req.length - req->req.actual, req);
+-
+-      if (unlikely (is_short)) {
+-              if (ep->dev->req_pending)
+-                      ep0start(ep->dev, UDCCS0_IPR, "short IN");
+-              else
+-                      UDCCS0 = UDCCS0_IPR;
+-
+-              count = req->req.length;
+-              done (ep, req, 0);
+-              ep0_idle(ep->dev);
+-#ifndef CONFIG_ARCH_IXP4XX
+-#if 1
+-              /* This seems to get rid of lost status irqs in some cases:
+-               * host responds quickly, or next request involves config
+-               * change automagic, or should have been hidden, or ...
+-               *
+-               * FIXME get rid of all udelays possible...
+-               */
+-              if (count >= EP0_FIFO_SIZE) {
+-                      count = 100;
+-                      do {
+-                              if ((UDCCS0 & UDCCS0_OPR) != 0) {
+-                                      /* clear OPR, generate ack */
+-                                      UDCCS0 = UDCCS0_OPR;
+-                                      break;
+-                              }
+-                              count--;
+-                              udelay(1);
+-                      } while (count);
+-              }
+-#endif
+-#endif
+-      } else if (ep->dev->req_pending)
+-              ep0start(ep->dev, 0, "IN");
+-      return is_short;
+-}
+-
+-
+-/*
+- * read_fifo -  unload packet(s) from the fifo we use for usb OUT
+- * transfers and put them into the request.  caller should have made
+- * sure there's at least one packet ready.
+- *
+- * returns true if the request completed because of short packet or the
+- * request buffer having filled (and maybe overran till end-of-packet).
+- */
+-static int
+-read_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
+-{
+-      for (;;) {
+-              u32             udccs;
+-              u8              *buf;
+-              unsigned        bufferspace, count, is_short;
+-
+-              /* make sure there's a packet in the FIFO.
+-               * UDCCS_{BO,IO}_RPC are all the same bit value.
+-               * UDCCS_{BO,IO}_RNE are all the same bit value.
+-               */
+-              udccs = *ep->reg_udccs;
+-              if (unlikely ((udccs & UDCCS_BO_RPC) == 0))
+-                      break;
+-              buf = req->req.buf + req->req.actual;
+-              prefetchw(buf);
+-              bufferspace = req->req.length - req->req.actual;
+-
+-              /* read all bytes from this packet */
+-              if (likely (udccs & UDCCS_BO_RNE)) {
+-                      count = 1 + (0x0ff & *ep->reg_ubcr);
+-                      req->req.actual += min (count, bufferspace);
+-              } else /* zlp */
+-                      count = 0;
+-              is_short = (count < ep->ep.maxpacket);
+-              DBG(DBG_VERY_NOISY, "read %s %02x, %d bytes%s req %p %d/%d\n",
+-                      ep->ep.name, udccs, count,
+-                      is_short ? "/S" : "",
+-                      req, req->req.actual, req->req.length);
+-              while (likely (count-- != 0)) {
+-                      u8      byte = (u8) *ep->reg_uddr;
+-
+-                      if (unlikely (bufferspace == 0)) {
+-                              /* this happens when the driver's buffer
+-                               * is smaller than what the host sent.
+-                               * discard the extra data.
+-                               */
+-                              if (req->req.status != -EOVERFLOW)
+-                                      DMSG("%s overflow %d\n",
+-                                              ep->ep.name, count);
+-                              req->req.status = -EOVERFLOW;
+-                      } else {
+-                              *buf++ = byte;
+-                              bufferspace--;
+-                      }
+-              }
+-              *ep->reg_udccs =  UDCCS_BO_RPC;
+-              /* RPC/RSP/RNE could now reflect the other packet buffer */
+-
+-              /* iso is one request per packet */
+-              if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+-                      if (udccs & UDCCS_IO_ROF)
+-                              req->req.status = -EHOSTUNREACH;
+-                      /* more like "is_done" */
+-                      is_short = 1;
+-              }
+-
+-              /* completion */
+-              if (is_short || req->req.actual == req->req.length) {
+-                      done (ep, req, 0);
+-                      if (list_empty(&ep->queue))
+-                              pio_irq_disable (ep->bEndpointAddress);
+-                      return 1;
+-              }
+-
+-              /* finished that packet.  the next one may be waiting... */
+-      }
+-      return 0;
+-}
+-
+-/*
+- * special ep0 version of the above.  no UBCR0 or double buffering; status
+- * handshaking is magic.  most device protocols don't need control-OUT.
+- * CDC vendor commands (and RNDIS), mass storage CB/CBI, and some other
+- * protocols do use them.
+- */
+-static int
+-read_ep0_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
+-{
+-      u8              *buf, byte;
+-      unsigned        bufferspace;
+-
+-      buf = req->req.buf + req->req.actual;
+-      bufferspace = req->req.length - req->req.actual;
+-
+-      while (UDCCS0 & UDCCS0_RNE) {
+-              byte = (u8) UDDR0;
+-
+-              if (unlikely (bufferspace == 0)) {
+-                      /* this happens when the driver's buffer
+-                       * is smaller than what the host sent.
+-                       * discard the extra data.
+-                       */
+-                      if (req->req.status != -EOVERFLOW)
+-                              DMSG("%s overflow\n", ep->ep.name);
+-                      req->req.status = -EOVERFLOW;
+-              } else {
+-                      *buf++ = byte;
+-                      req->req.actual++;
+-                      bufferspace--;
+-              }
+-      }
+-
+-      UDCCS0 = UDCCS0_OPR | UDCCS0_IPR;
+-
+-      /* completion */
+-      if (req->req.actual >= req->req.length)
+-              return 1;
+-
+-      /* finished that packet.  the next one may be waiting... */
+-      return 0;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static int
+-pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+-{
+-      struct pxa2xx_request   *req;
+-      struct pxa2xx_ep        *ep;
+-      struct pxa2xx_udc       *dev;
+-      unsigned long           flags;
+-
+-      req = container_of(_req, struct pxa2xx_request, req);
+-      if (unlikely (!_req || !_req->complete || !_req->buf
+-                      || !list_empty(&req->queue))) {
+-              DMSG("%s, bad params\n", __func__);
+-              return -EINVAL;
+-      }
+-
+-      ep = container_of(_ep, struct pxa2xx_ep, ep);
+-      if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+-              DMSG("%s, bad ep\n", __func__);
+-              return -EINVAL;
+-      }
+-
+-      dev = ep->dev;
+-      if (unlikely (!dev->driver
+-                      || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+-              DMSG("%s, bogus device state\n", __func__);
+-              return -ESHUTDOWN;
+-      }
+-
+-      /* iso is always one packet per request, that's the only way
+-       * we can report per-packet status.  that also helps with dma.
+-       */
+-      if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
+-                      && req->req.length > le16_to_cpu
+-                                              (ep->desc->wMaxPacketSize)))
+-              return -EMSGSIZE;
+-
+-      DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
+-              _ep->name, _req, _req->length, _req->buf);
+-
+-      local_irq_save(flags);
+-
+-      _req->status = -EINPROGRESS;
+-      _req->actual = 0;
+-
+-      /* kickstart this i/o queue? */
+-      if (list_empty(&ep->queue) && !ep->stopped) {
+-              if (ep->desc == NULL/* ep0 */) {
+-                      unsigned        length = _req->length;
+-
+-                      switch (dev->ep0state) {
+-                      case EP0_IN_DATA_PHASE:
+-                              dev->stats.write.ops++;
+-                              if (write_ep0_fifo(ep, req))
+-                                      req = NULL;
+-                              break;
+-
+-                      case EP0_OUT_DATA_PHASE:
+-                              dev->stats.read.ops++;
+-                              /* messy ... */
+-                              if (dev->req_config) {
+-                                      DBG(DBG_VERBOSE, "ep0 config ack%s\n",
+-                                              dev->has_cfr ?  "" : " raced");
+-                                      if (dev->has_cfr)
+-                                              UDCCFR = UDCCFR_AREN|UDCCFR_ACM
+-                                                      |UDCCFR_MB1;
+-                                      done(ep, req, 0);
+-                                      dev->ep0state = EP0_END_XFER;
+-                                      local_irq_restore (flags);
+-                                      return 0;
+-                              }
+-                              if (dev->req_pending)
+-                                      ep0start(dev, UDCCS0_IPR, "OUT");
+-                              if (length == 0 || ((UDCCS0 & UDCCS0_RNE) != 0
+-                                              && read_ep0_fifo(ep, req))) {
+-                                      ep0_idle(dev);
+-                                      done(ep, req, 0);
+-                                      req = NULL;
+-                              }
+-                              break;
+-
+-                      default:
+-                              DMSG("ep0 i/o, odd state %d\n", dev->ep0state);
+-                              local_irq_restore (flags);
+-                              return -EL2HLT;
+-                      }
+-              /* can the FIFO can satisfy the request immediately? */
+-              } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
+-                      if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
+-                                      && write_fifo(ep, req))
+-                              req = NULL;
+-              } else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0
+-                              && read_fifo(ep, req)) {
+-                      req = NULL;
+-              }
+-
+-              if (likely (req && ep->desc))
+-                      pio_irq_enable(ep->bEndpointAddress);
+-      }
+-
+-      /* pio or dma irq handler advances the queue. */
+-      if (likely(req != NULL))
+-              list_add_tail(&req->queue, &ep->queue);
+-      local_irq_restore(flags);
+-
+-      return 0;
+-}
+-
+-
+-/*
+- *    nuke - dequeue ALL requests
+- */
+-static void nuke(struct pxa2xx_ep *ep, int status)
+-{
+-      struct pxa2xx_request *req;
+-
+-      /* called with irqs blocked */
+-      while (!list_empty(&ep->queue)) {
+-              req = list_entry(ep->queue.next,
+-                              struct pxa2xx_request,
+-                              queue);
+-              done(ep, req, status);
+-      }
+-      if (ep->desc)
+-              pio_irq_disable (ep->bEndpointAddress);
+-}
+-
+-
+-/* dequeue JUST ONE request */
+-static int pxa2xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+-{
+-      struct pxa2xx_ep        *ep;
+-      struct pxa2xx_request   *req;
+-      unsigned long           flags;
+-
+-      ep = container_of(_ep, struct pxa2xx_ep, ep);
+-      if (!_ep || ep->ep.name == ep0name)
+-              return -EINVAL;
+-
+-      local_irq_save(flags);
+-
+-      /* make sure it's actually queued on this endpoint */
+-      list_for_each_entry (req, &ep->queue, queue) {
+-              if (&req->req == _req)
+-                      break;
+-      }
+-      if (&req->req != _req) {
+-              local_irq_restore(flags);
+-              return -EINVAL;
+-      }
+-
+-      done(ep, req, -ECONNRESET);
+-
+-      local_irq_restore(flags);
+-      return 0;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static int pxa2xx_ep_set_halt(struct usb_ep *_ep, int value)
+-{
+-      struct pxa2xx_ep        *ep;
+-      unsigned long           flags;
+-
+-      ep = container_of(_ep, struct pxa2xx_ep, ep);
+-      if (unlikely (!_ep
+-                      || (!ep->desc && ep->ep.name != ep0name))
+-                      || ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+-              DMSG("%s, bad ep\n", __func__);
+-              return -EINVAL;
+-      }
+-      if (value == 0) {
+-              /* this path (reset toggle+halt) is needed to implement
+-               * SET_INTERFACE on normal hardware.  but it can't be
+-               * done from software on the PXA UDC, and the hardware
+-               * forgets to do it as part of SET_INTERFACE automagic.
+-               */
+-              DMSG("only host can clear %s halt\n", _ep->name);
+-              return -EROFS;
+-      }
+-
+-      local_irq_save(flags);
+-
+-      if ((ep->bEndpointAddress & USB_DIR_IN) != 0
+-                      && ((*ep->reg_udccs & UDCCS_BI_TFS) == 0
+-                         || !list_empty(&ep->queue))) {
+-              local_irq_restore(flags);
+-              return -EAGAIN;
+-      }
+-
+-      /* FST bit is the same for control, bulk in, bulk out, interrupt in */
+-      *ep->reg_udccs = UDCCS_BI_FST|UDCCS_BI_FTF;
+-
+-      /* ep0 needs special care */
+-      if (!ep->desc) {
+-              start_watchdog(ep->dev);
+-              ep->dev->req_pending = 0;
+-              ep->dev->ep0state = EP0_STALL;
+-
+-      /* and bulk/intr endpoints like dropping stalls too */
+-      } else {
+-              unsigned i;
+-              for (i = 0; i < 1000; i += 20) {
+-                      if (*ep->reg_udccs & UDCCS_BI_SST)
+-                              break;
+-                      udelay(20);
+-              }
+-      }
+-      local_irq_restore(flags);
+-
+-      DBG(DBG_VERBOSE, "%s halt\n", _ep->name);
+-      return 0;
+-}
+-
+-static int pxa2xx_ep_fifo_status(struct usb_ep *_ep)
+-{
+-      struct pxa2xx_ep        *ep;
+-
+-      ep = container_of(_ep, struct pxa2xx_ep, ep);
+-      if (!_ep) {
+-              DMSG("%s, bad ep\n", __func__);
+-              return -ENODEV;
+-      }
+-      /* pxa can't report unclaimed bytes from IN fifos */
+-      if ((ep->bEndpointAddress & USB_DIR_IN) != 0)
+-              return -EOPNOTSUPP;
+-      if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN
+-                      || (*ep->reg_udccs & UDCCS_BO_RFS) == 0)
+-              return 0;
+-      else
+-              return (*ep->reg_ubcr & 0xfff) + 1;
+-}
+-
+-static void pxa2xx_ep_fifo_flush(struct usb_ep *_ep)
+-{
+-      struct pxa2xx_ep        *ep;
+-
+-      ep = container_of(_ep, struct pxa2xx_ep, ep);
+-      if (!_ep || ep->ep.name == ep0name || !list_empty(&ep->queue)) {
+-              DMSG("%s, bad ep\n", __func__);
+-              return;
+-      }
+-
+-      /* toggle and halt bits stay unchanged */
+-
+-      /* for OUT, just read and discard the FIFO contents. */
+-      if ((ep->bEndpointAddress & USB_DIR_IN) == 0) {
+-              while (((*ep->reg_udccs) & UDCCS_BO_RNE) != 0)
+-                      (void) *ep->reg_uddr;
+-              return;
+-      }
+-
+-      /* most IN status is the same, but ISO can't stall */
+-      *ep->reg_udccs = UDCCS_BI_TPC|UDCCS_BI_FTF|UDCCS_BI_TUR
+-              | (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
+-                      ? 0 : UDCCS_BI_SST;
+-}
+-
+-
+-static struct usb_ep_ops pxa2xx_ep_ops = {
+-      .enable         = pxa2xx_ep_enable,
+-      .disable        = pxa2xx_ep_disable,
+-
+-      .alloc_request  = pxa2xx_ep_alloc_request,
+-      .free_request   = pxa2xx_ep_free_request,
+-
+-      .queue          = pxa2xx_ep_queue,
+-      .dequeue        = pxa2xx_ep_dequeue,
+-
+-      .set_halt       = pxa2xx_ep_set_halt,
+-      .fifo_status    = pxa2xx_ep_fifo_status,
+-      .fifo_flush     = pxa2xx_ep_fifo_flush,
+-};
+-
+-
+-/* ---------------------------------------------------------------------------
+- *    device-scoped parts of the api to the usb controller hardware
+- * ---------------------------------------------------------------------------
+- */
+-
+-static int pxa2xx_udc_get_frame(struct usb_gadget *_gadget)
+-{
+-      return ((UFNRH & 0x07) << 8) | (UFNRL & 0xff);
+-}
+-
+-static int pxa2xx_udc_wakeup(struct usb_gadget *_gadget)
+-{
+-      /* host may not have enabled remote wakeup */
+-      if ((UDCCS0 & UDCCS0_DRWF) == 0)
+-              return -EHOSTUNREACH;
+-      udc_set_mask_UDCCR(UDCCR_RSM);
+-      return 0;
+-}
+-
+-static void stop_activity(struct pxa2xx_udc *, struct usb_gadget_driver *);
+-static void udc_enable (struct pxa2xx_udc *);
+-static void udc_disable(struct pxa2xx_udc *);
+-
+-/* We disable the UDC -- and its 48 MHz clock -- whenever it's not
+- * in active use.
+- */
+-static int pullup(struct pxa2xx_udc *udc)
+-{
+-      int is_active = udc->vbus && udc->pullup && !udc->suspended;
+-      DMSG("%s\n", is_active ? "active" : "inactive");
+-      if (is_active) {
+-              if (!udc->active) {
+-                      udc->active = 1;
+-                      /* Enable clock for USB device */
+-                      clk_enable(udc->clk);
+-                      udc_enable(udc);
+-              }
+-      } else {
+-              if (udc->active) {
+-                      if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
+-                              DMSG("disconnect %s\n", udc->driver
+-                                      ? udc->driver->driver.name
+-                                      : "(no driver)");
+-                              stop_activity(udc, udc->driver);
+-                      }
+-                      udc_disable(udc);
+-                      /* Disable clock for USB device */
+-                      clk_disable(udc->clk);
+-                      udc->active = 0;
+-              }
+-
+-      }
+-      return 0;
+-}
+-
+-/* VBUS reporting logically comes from a transceiver */
+-static int pxa2xx_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
+-{
+-      struct pxa2xx_udc       *udc;
+-
+-      udc = container_of(_gadget, struct pxa2xx_udc, gadget);
+-      udc->vbus = (is_active != 0);
+-      DMSG("vbus %s\n", is_active ? "supplied" : "inactive");
+-      pullup(udc);
+-      return 0;
+-}
+-
+-/* drivers may have software control over D+ pullup */
+-static int pxa2xx_udc_pullup(struct usb_gadget *_gadget, int is_active)
+-{
+-      struct pxa2xx_udc       *udc;
+-
+-      udc = container_of(_gadget, struct pxa2xx_udc, gadget);
+-
+-      /* not all boards support pullup control */
+-      if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
+-              return -EOPNOTSUPP;
+-
+-      udc->pullup = (is_active != 0);
+-      pullup(udc);
+-      return 0;
+-}
+-
+-static const struct usb_gadget_ops pxa2xx_udc_ops = {
+-      .get_frame      = pxa2xx_udc_get_frame,
+-      .wakeup         = pxa2xx_udc_wakeup,
+-      .vbus_session   = pxa2xx_udc_vbus_session,
+-      .pullup         = pxa2xx_udc_pullup,
+-
+-      // .vbus_draw ... boards may consume current from VBUS, up to
+-      // 100-500mA based on config.  the 500uA suspend ceiling means
+-      // that exclusively vbus-powered PXA designs violate USB specs.
+-};
+-
+-/*-------------------------------------------------------------------------*/
+-
+-#ifdef CONFIG_USB_GADGET_DEBUG_FS
+-
+-static int
+-udc_seq_show(struct seq_file *m, void *_d)
+-{
+-      struct pxa2xx_udc       *dev = m->private;
+-      unsigned long           flags;
+-      int                     i;
+-      u32                     tmp;
+-
+-      local_irq_save(flags);
+-
+-      /* basic device status */
+-      seq_printf(m, DRIVER_DESC "\n"
+-              "%s version: %s\nGadget driver: %s\nHost %s\n\n",
+-              driver_name, DRIVER_VERSION SIZE_STR "(pio)",
+-              dev->driver ? dev->driver->driver.name : "(none)",
+-              is_vbus_present() ? "full speed" : "disconnected");
+-
+-      /* registers for device and ep0 */
+-      seq_printf(m,
+-              "uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
+-              UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
+-
+-      tmp = UDCCR;
+-      seq_printf(m,
+-              "udccr %02X =%s%s%s%s%s%s%s%s\n", tmp,
+-              (tmp & UDCCR_REM) ? " rem" : "",
+-              (tmp & UDCCR_RSTIR) ? " rstir" : "",
+-              (tmp & UDCCR_SRM) ? " srm" : "",
+-              (tmp & UDCCR_SUSIR) ? " susir" : "",
+-              (tmp & UDCCR_RESIR) ? " resir" : "",
+-              (tmp & UDCCR_RSM) ? " rsm" : "",
+-              (tmp & UDCCR_UDA) ? " uda" : "",
+-              (tmp & UDCCR_UDE) ? " ude" : "");
+-
+-      tmp = UDCCS0;
+-      seq_printf(m,
+-              "udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp,
+-              (tmp & UDCCS0_SA) ? " sa" : "",
+-              (tmp & UDCCS0_RNE) ? " rne" : "",
+-              (tmp & UDCCS0_FST) ? " fst" : "",
+-              (tmp & UDCCS0_SST) ? " sst" : "",
+-              (tmp & UDCCS0_DRWF) ? " dwrf" : "",
+-              (tmp & UDCCS0_FTF) ? " ftf" : "",
+-              (tmp & UDCCS0_IPR) ? " ipr" : "",
+-              (tmp & UDCCS0_OPR) ? " opr" : "");
+-
+-      if (dev->has_cfr) {
+-              tmp = UDCCFR;
+-              seq_printf(m,
+-                      "udccfr %02X =%s%s\n", tmp,
+-                      (tmp & UDCCFR_AREN) ? " aren" : "",
+-                      (tmp & UDCCFR_ACM) ? " acm" : "");
+-      }
+-
+-      if (!is_vbus_present() || !dev->driver)
+-              goto done;
+-
+-      seq_printf(m, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
+-              dev->stats.write.bytes, dev->stats.write.ops,
+-              dev->stats.read.bytes, dev->stats.read.ops,
+-              dev->stats.irqs);
+-
+-      /* dump endpoint queues */
+-      for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
+-              struct pxa2xx_ep        *ep = &dev->ep [i];
+-              struct pxa2xx_request   *req;
+-
+-              if (i != 0) {
+-                      const struct usb_endpoint_descriptor    *desc;
+-
+-                      desc = ep->desc;
+-                      if (!desc)
+-                              continue;
+-                      tmp = *dev->ep [i].reg_udccs;
+-                      seq_printf(m,
+-                              "%s max %d %s udccs %02x irqs %lu\n",
+-                              ep->ep.name, le16_to_cpu(desc->wMaxPacketSize),
+-                              "pio", tmp, ep->pio_irqs);
+-                      /* TODO translate all five groups of udccs bits! */
+-
+-              } else /* ep0 should only have one transfer queued */
+-                      seq_printf(m, "ep0 max 16 pio irqs %lu\n",
+-                              ep->pio_irqs);
+-
+-              if (list_empty(&ep->queue)) {
+-                      seq_printf(m, "\t(nothing queued)\n");
+-                      continue;
+-              }
+-              list_for_each_entry(req, &ep->queue, queue) {
+-                      seq_printf(m,
+-                                      "\treq %p len %d/%d buf %p\n",
+-                                      &req->req, req->req.actual,
+-                                      req->req.length, req->req.buf);
+-              }
+-      }
+-
+-done:
+-      local_irq_restore(flags);
+-      return 0;
+-}
+-
+-static int
+-udc_debugfs_open(struct inode *inode, struct file *file)
+-{
+-      return single_open(file, udc_seq_show, inode->i_private);
+-}
+-
+-static const struct file_operations debug_fops = {
+-      .open           = udc_debugfs_open,
+-      .read           = seq_read,
+-      .llseek         = seq_lseek,
+-      .release        = single_release,
+-      .owner          = THIS_MODULE,
+-};
+-
+-#define create_debug_files(dev) \
+-      do { \
+-              dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \
+-                      S_IRUGO, NULL, dev, &debug_fops); \
+-      } while (0)
+-#define remove_debug_files(dev) \
+-      do { \
+-              if (dev->debugfs_udc) \
+-                      debugfs_remove(dev->debugfs_udc); \
+-      } while (0)
+-
+-#else /* !CONFIG_USB_GADGET_DEBUG_FILES */
+-
+-#define create_debug_files(dev) do {} while (0)
+-#define remove_debug_files(dev) do {} while (0)
+-
+-#endif        /* CONFIG_USB_GADGET_DEBUG_FILES */
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/*
+- *    udc_disable - disable USB device controller
+- */
+-static void udc_disable(struct pxa2xx_udc *dev)
+-{
+-      /* block all irqs */
+-      udc_set_mask_UDCCR(UDCCR_SRM|UDCCR_REM);
+-      UICR0 = UICR1 = 0xff;
+-      UFNRH = UFNRH_SIM;
+-
+-      /* if hardware supports it, disconnect from usb */
+-      pullup_off();
+-
+-      udc_clear_mask_UDCCR(UDCCR_UDE);
+-
+-      ep0_idle (dev);
+-      dev->gadget.speed = USB_SPEED_UNKNOWN;
+-}
+-
+-
+-/*
+- *    udc_reinit - initialize software state
+- */
+-static void udc_reinit(struct pxa2xx_udc *dev)
+-{
+-      u32     i;
+-
+-      /* device/ep0 records init */
+-      INIT_LIST_HEAD (&dev->gadget.ep_list);
+-      INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
+-      dev->ep0state = EP0_IDLE;
+-
+-      /* basic endpoint records init */
+-      for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
+-              struct pxa2xx_ep *ep = &dev->ep[i];
+-
+-              if (i != 0)
+-                      list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
+-
+-              ep->desc = NULL;
+-              ep->stopped = 0;
+-              INIT_LIST_HEAD (&ep->queue);
+-              ep->pio_irqs = 0;
+-      }
+-
+-      /* the rest was statically initialized, and is read-only */
+-}
+-
+-/* until it's enabled, this UDC should be completely invisible
+- * to any USB host.
+- */
+-static void udc_enable (struct pxa2xx_udc *dev)
+-{
+-      udc_clear_mask_UDCCR(UDCCR_UDE);
+-
+-      /* try to clear these bits before we enable the udc */
+-      udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR);
+-
+-      ep0_idle(dev);
+-      dev->gadget.speed = USB_SPEED_UNKNOWN;
+-      dev->stats.irqs = 0;
+-
+-      /*
+-       * sequence taken from chapter 12.5.10, PXA250 AppProcDevManual:
+-       * - enable UDC
+-       * - if RESET is already in progress, ack interrupt
+-       * - unmask reset interrupt
+-       */
+-      udc_set_mask_UDCCR(UDCCR_UDE);
+-      if (!(UDCCR & UDCCR_UDA))
+-              udc_ack_int_UDCCR(UDCCR_RSTIR);
+-
+-      if (dev->has_cfr /* UDC_RES2 is defined */) {
+-              /* pxa255 (a0+) can avoid a set_config race that could
+-               * prevent gadget drivers from configuring correctly
+-               */
+-              UDCCFR = UDCCFR_ACM | UDCCFR_MB1;
+-      } else {
+-              /* "USB test mode" for pxa250 errata 40-42 (stepping a0, a1)
+-               * which could result in missing packets and interrupts.
+-               * supposedly one bit per endpoint, controlling whether it
+-               * double buffers or not; ACM/AREN bits fit into the holes.
+-               * zero bits (like USIR0_IRx) disable double buffering.
+-               */
+-              UDC_RES1 = 0x00;
+-              UDC_RES2 = 0x00;
+-      }
+-
+-      /* enable suspend/resume and reset irqs */
+-      udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM);
+-
+-      /* enable ep0 irqs */
+-      UICR0 &= ~UICR0_IM0;
+-
+-      /* if hardware supports it, pullup D+ and wait for reset */
+-      pullup_on();
+-}
+-
+-
+-/* when a driver is successfully registered, it will receive
+- * control requests including set_configuration(), which enables
+- * non-control requests.  then usb traffic follows until a
+- * disconnect is reported.  then a host may connect again, or
+- * the driver might get unbound.
+- */
+-int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+-{
+-      struct pxa2xx_udc       *dev = the_controller;
+-      int                     retval;
+-
+-      if (!driver
+-                      || driver->speed < USB_SPEED_FULL
+-                      || !driver->bind
+-                      || !driver->disconnect
+-                      || !driver->setup)
+-              return -EINVAL;
+-      if (!dev)
+-              return -ENODEV;
+-      if (dev->driver)
+-              return -EBUSY;
+-
+-      /* first hook up the driver ... */
+-      dev->driver = driver;
+-      dev->gadget.dev.driver = &driver->driver;
+-      dev->pullup = 1;
+-
+-      retval = device_add (&dev->gadget.dev);
+-      if (retval) {
+-fail:
+-              dev->driver = NULL;
+-              dev->gadget.dev.driver = NULL;
+-              return retval;
+-      }
+-      retval = driver->bind(&dev->gadget);
+-      if (retval) {
+-              DMSG("bind to driver %s --> error %d\n",
+-                              driver->driver.name, retval);
+-              device_del (&dev->gadget.dev);
+-              goto fail;
+-      }
+-
+-      /* ... then enable host detection and ep0; and we're ready
+-       * for set_configuration as well as eventual disconnect.
+-       */
+-      DMSG("registered gadget driver '%s'\n", driver->driver.name);
+-      pullup(dev);
+-      dump_state(dev);
+-      return 0;
+-}
+-EXPORT_SYMBOL(usb_gadget_register_driver);
+-
+-static void
+-stop_activity(struct pxa2xx_udc *dev, struct usb_gadget_driver *driver)
+-{
+-      int i;
+-
+-      /* don't disconnect drivers more than once */
+-      if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+-              driver = NULL;
+-      dev->gadget.speed = USB_SPEED_UNKNOWN;
+-
+-      /* prevent new request submissions, kill any outstanding requests  */
+-      for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
+-              struct pxa2xx_ep *ep = &dev->ep[i];
+-
+-              ep->stopped = 1;
+-              nuke(ep, -ESHUTDOWN);
+-      }
+-      del_timer_sync(&dev->timer);
+-
+-      /* report disconnect; the driver is already quiesced */
+-      if (driver)
+-              driver->disconnect(&dev->gadget);
+-
+-      /* re-init driver-visible data structures */
+-      udc_reinit(dev);
+-}
+-
+-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+-{
+-      struct pxa2xx_udc       *dev = the_controller;
+-
+-      if (!dev)
+-              return -ENODEV;
+-      if (!driver || driver != dev->driver || !driver->unbind)
+-              return -EINVAL;
+-
+-      local_irq_disable();
+-      dev->pullup = 0;
+-      pullup(dev);
+-      stop_activity(dev, driver);
+-      local_irq_enable();
+-
+-      driver->unbind(&dev->gadget);
+-      dev->gadget.dev.driver = NULL;
+-      dev->driver = NULL;
+-
+-      device_del (&dev->gadget.dev);
+-
+-      DMSG("unregistered gadget driver '%s'\n", driver->driver.name);
+-      dump_state(dev);
+-      return 0;
+-}
+-EXPORT_SYMBOL(usb_gadget_unregister_driver);
+-
+-
+-/*-------------------------------------------------------------------------*/
+-
+-#ifdef CONFIG_ARCH_LUBBOCK
+-
+-/* Lubbock has separate connect and disconnect irqs.  More typical designs
+- * use one GPIO as the VBUS IRQ, and another to control the D+ pullup.
+- */
+-
+-static irqreturn_t
+-lubbock_vbus_irq(int irq, void *_dev)
+-{
+-      struct pxa2xx_udc       *dev = _dev;
+-      int                     vbus;
+-
+-      dev->stats.irqs++;
+-      switch (irq) {
+-      case LUBBOCK_USB_IRQ:
+-              vbus = 1;
+-              disable_irq(LUBBOCK_USB_IRQ);
+-              enable_irq(LUBBOCK_USB_DISC_IRQ);
+-              break;
+-      case LUBBOCK_USB_DISC_IRQ:
+-              vbus = 0;
+-              disable_irq(LUBBOCK_USB_DISC_IRQ);
+-              enable_irq(LUBBOCK_USB_IRQ);
+-              break;
+-      default:
+-              return IRQ_NONE;
+-      }
+-
+-      pxa2xx_udc_vbus_session(&dev->gadget, vbus);
+-      return IRQ_HANDLED;
+-}
+-
+-#endif
+-
+-static irqreturn_t udc_vbus_irq(int irq, void *_dev)
+-{
+-      struct pxa2xx_udc       *dev = _dev;
+-      int                     vbus = gpio_get_value(dev->mach->gpio_vbus);
+-
+-      if (dev->mach->gpio_vbus_inverted)
+-              vbus = !vbus;
+-
+-      pxa2xx_udc_vbus_session(&dev->gadget, vbus);
+-      return IRQ_HANDLED;
+-}
+-
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static inline void clear_ep_state (struct pxa2xx_udc *dev)
+-{
+-      unsigned i;
+-
+-      /* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
+-       * fifos, and pending transactions mustn't be continued in any case.
+-       */
+-      for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++)
+-              nuke(&dev->ep[i], -ECONNABORTED);
+-}
+-
+-static void udc_watchdog(unsigned long _dev)
+-{
+-      struct pxa2xx_udc       *dev = (void *)_dev;
+-
+-      local_irq_disable();
+-      if (dev->ep0state == EP0_STALL
+-                      && (UDCCS0 & UDCCS0_FST) == 0
+-                      && (UDCCS0 & UDCCS0_SST) == 0) {
+-              UDCCS0 = UDCCS0_FST|UDCCS0_FTF;
+-              DBG(DBG_VERBOSE, "ep0 re-stall\n");
+-              start_watchdog(dev);
+-      }
+-      local_irq_enable();
+-}
+-
+-static void handle_ep0 (struct pxa2xx_udc *dev)
+-{
+-      u32                     udccs0 = UDCCS0;
+-      struct pxa2xx_ep        *ep = &dev->ep [0];
+-      struct pxa2xx_request   *req;
+-      union {
+-              struct usb_ctrlrequest  r;
+-              u8                      raw [8];
+-              u32                     word [2];
+-      } u;
+-
+-      if (list_empty(&ep->queue))
+-              req = NULL;
+-      else
+-              req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
+-
+-      /* clear stall status */
+-      if (udccs0 & UDCCS0_SST) {
+-              nuke(ep, -EPIPE);
+-              UDCCS0 = UDCCS0_SST;
+-              del_timer(&dev->timer);
+-              ep0_idle(dev);
+-      }
+-
+-      /* previous request unfinished?  non-error iff back-to-back ... */
+-      if ((udccs0 & UDCCS0_SA) != 0 && dev->ep0state != EP0_IDLE) {
+-              nuke(ep, 0);
+-              del_timer(&dev->timer);
+-              ep0_idle(dev);
+-      }
+-
+-      switch (dev->ep0state) {
+-      case EP0_IDLE:
+-              /* late-breaking status? */
+-              udccs0 = UDCCS0;
+-
+-              /* start control request? */
+-              if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE))
+-                              == (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE))) {
+-                      int i;
+-
+-                      nuke (ep, -EPROTO);
+-
+-                      /* read SETUP packet */
+-                      for (i = 0; i < 8; i++) {
+-                              if (unlikely(!(UDCCS0 & UDCCS0_RNE))) {
+-bad_setup:
+-                                      DMSG("SETUP %d!\n", i);
+-                                      goto stall;
+-                              }
+-                              u.raw [i] = (u8) UDDR0;
+-                      }
+-                      if (unlikely((UDCCS0 & UDCCS0_RNE) != 0))
+-                              goto bad_setup;
+-
+-got_setup:
+-                      DBG(DBG_VERBOSE, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+-                              u.r.bRequestType, u.r.bRequest,
+-                              le16_to_cpu(u.r.wValue),
+-                              le16_to_cpu(u.r.wIndex),
+-                              le16_to_cpu(u.r.wLength));
+-
+-                      /* cope with automagic for some standard requests. */
+-                      dev->req_std = (u.r.bRequestType & USB_TYPE_MASK)
+-                                              == USB_TYPE_STANDARD;
+-                      dev->req_config = 0;
+-                      dev->req_pending = 1;
+-                      switch (u.r.bRequest) {
+-                      /* hardware restricts gadget drivers here! */
+-                      case USB_REQ_SET_CONFIGURATION:
+-                              if (u.r.bRequestType == USB_RECIP_DEVICE) {
+-                                      /* reflect hardware's automagic
+-                                       * up to the gadget driver.
+-                                       */
+-config_change:
+-                                      dev->req_config = 1;
+-                                      clear_ep_state(dev);
+-                                      /* if !has_cfr, there's no synch
+-                                       * else use AREN (later) not SA|OPR
+-                                       * USIR0_IR0 acts edge sensitive
+-                                       */
+-                              }
+-                              break;
+-                      /* ... and here, even more ... */
+-                      case USB_REQ_SET_INTERFACE:
+-                              if (u.r.bRequestType == USB_RECIP_INTERFACE) {
+-                                      /* udc hardware is broken by design:
+-                                       *  - altsetting may only be zero;
+-                                       *  - hw resets all interfaces' eps;
+-                                       *  - ep reset doesn't include halt(?).
+-                                       */
+-                                      DMSG("broken set_interface (%d/%d)\n",
+-                                              le16_to_cpu(u.r.wIndex),
+-                                              le16_to_cpu(u.r.wValue));
+-                                      goto config_change;
+-                              }
+-                              break;
+-                      /* hardware was supposed to hide this */
+-                      case USB_REQ_SET_ADDRESS:
+-                              if (u.r.bRequestType == USB_RECIP_DEVICE) {
+-                                      ep0start(dev, 0, "address");
+-                                      return;
+-                              }
+-                              break;
+-                      }
+-
+-                      if (u.r.bRequestType & USB_DIR_IN)
+-                              dev->ep0state = EP0_IN_DATA_PHASE;
+-                      else
+-                              dev->ep0state = EP0_OUT_DATA_PHASE;
+-
+-                      i = dev->driver->setup(&dev->gadget, &u.r);
+-                      if (i < 0) {
+-                              /* hardware automagic preventing STALL... */
+-                              if (dev->req_config) {
+-                                      /* hardware sometimes neglects to tell
+-                                       * tell us about config change events,
+-                                       * so later ones may fail...
+-                                       */
+-                                      WARN("config change %02x fail %d?\n",
+-                                              u.r.bRequest, i);
+-                                      return;
+-                                      /* TODO experiment:  if has_cfr,
+-                                       * hardware didn't ACK; maybe we
+-                                       * could actually STALL!
+-                                       */
+-                              }
+-                              DBG(DBG_VERBOSE, "protocol STALL, "
+-                                      "%02x err %d\n", UDCCS0, i);
+-stall:
+-                              /* the watchdog timer helps deal with cases
+-                               * where udc seems to clear FST wrongly, and
+-                               * then NAKs instead of STALLing.
+-                               */
+-                              ep0start(dev, UDCCS0_FST|UDCCS0_FTF, "stall");
+-                              start_watchdog(dev);
+-                              dev->ep0state = EP0_STALL;
+-
+-                      /* deferred i/o == no response yet */
+-                      } else if (dev->req_pending) {
+-                              if (likely(dev->ep0state == EP0_IN_DATA_PHASE
+-                                              || dev->req_std || u.r.wLength))
+-                                      ep0start(dev, 0, "defer");
+-                              else
+-                                      ep0start(dev, UDCCS0_IPR, "defer/IPR");
+-                      }
+-
+-                      /* expect at least one data or status stage irq */
+-                      return;
+-
+-              } else if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA))
+-                              == (UDCCS0_OPR|UDCCS0_SA))) {
+-                      unsigned i;
+-
+-                      /* pxa210/250 erratum 131 for B0/B1 says RNE lies.
+-                       * still observed on a pxa255 a0.
+-                       */
+-                      DBG(DBG_VERBOSE, "e131\n");
+-                      nuke(ep, -EPROTO);
+-
+-                      /* read SETUP data, but don't trust it too much */
+-                      for (i = 0; i < 8; i++)
+-                              u.raw [i] = (u8) UDDR0;
+-                      if ((u.r.bRequestType & USB_RECIP_MASK)
+-                                      > USB_RECIP_OTHER)
+-                              goto stall;
+-                      if (u.word [0] == 0 && u.word [1] == 0)
+-                              goto stall;
+-                      goto got_setup;
+-              } else {
+-                      /* some random early IRQ:
+-                       * - we acked FST
+-                       * - IPR cleared
+-                       * - OPR got set, without SA (likely status stage)
+-                       */
+-                      UDCCS0 = udccs0 & (UDCCS0_SA|UDCCS0_OPR);
+-              }
+-              break;
+-      case EP0_IN_DATA_PHASE:                 /* GET_DESCRIPTOR etc */
+-              if (udccs0 & UDCCS0_OPR) {
+-                      UDCCS0 = UDCCS0_OPR|UDCCS0_FTF;
+-                      DBG(DBG_VERBOSE, "ep0in premature status\n");
+-                      if (req)
+-                              done(ep, req, 0);
+-                      ep0_idle(dev);
+-              } else /* irq was IPR clearing */ {
+-                      if (req) {
+-                              /* this IN packet might finish the request */
+-                              (void) write_ep0_fifo(ep, req);
+-                      } /* else IN token before response was written */
+-              }
+-              break;
+-      case EP0_OUT_DATA_PHASE:                /* SET_DESCRIPTOR etc */
+-              if (udccs0 & UDCCS0_OPR) {
+-                      if (req) {
+-                              /* this OUT packet might finish the request */
+-                              if (read_ep0_fifo(ep, req))
+-                                      done(ep, req, 0);
+-                              /* else more OUT packets expected */
+-                      } /* else OUT token before read was issued */
+-              } else /* irq was IPR clearing */ {
+-                      DBG(DBG_VERBOSE, "ep0out premature status\n");
+-                      if (req)
+-                              done(ep, req, 0);
+-                      ep0_idle(dev);
+-              }
+-              break;
+-      case EP0_END_XFER:
+-              if (req)
+-                      done(ep, req, 0);
+-              /* ack control-IN status (maybe in-zlp was skipped)
+-               * also appears after some config change events.
+-               */
+-              if (udccs0 & UDCCS0_OPR)
+-                      UDCCS0 = UDCCS0_OPR;
+-              ep0_idle(dev);
+-              break;
+-      case EP0_STALL:
+-              UDCCS0 = UDCCS0_FST;
+-              break;
+-      }
+-      USIR0 = USIR0_IR0;
+-}
+-
+-static void handle_ep(struct pxa2xx_ep *ep)
+-{
+-      struct pxa2xx_request   *req;
+-      int                     is_in = ep->bEndpointAddress & USB_DIR_IN;
+-      int                     completed;
+-      u32                     udccs, tmp;
+-
+-      do {
+-              completed = 0;
+-              if (likely (!list_empty(&ep->queue)))
+-                      req = list_entry(ep->queue.next,
+-                                      struct pxa2xx_request, queue);
+-              else
+-                      req = NULL;
+-
+-              // TODO check FST handling
+-
+-              udccs = *ep->reg_udccs;
+-              if (unlikely(is_in)) {  /* irq from TPC, SST, or (ISO) TUR */
+-                      tmp = UDCCS_BI_TUR;
+-                      if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK))
+-                              tmp |= UDCCS_BI_SST;
+-                      tmp &= udccs;
+-                      if (likely (tmp))
+-                              *ep->reg_udccs = tmp;
+-                      if (req && likely ((udccs & UDCCS_BI_TFS) != 0))
+-                              completed = write_fifo(ep, req);
+-
+-              } else {        /* irq from RPC (or for ISO, ROF) */
+-                      if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK))
+-                              tmp = UDCCS_BO_SST | UDCCS_BO_DME;
+-                      else
+-                              tmp = UDCCS_IO_ROF | UDCCS_IO_DME;
+-                      tmp &= udccs;
+-                      if (likely(tmp))
+-                              *ep->reg_udccs = tmp;
+-
+-                      /* fifos can hold packets, ready for reading... */
+-                      if (likely(req)) {
+-                              completed = read_fifo(ep, req);
+-                      } else
+-                              pio_irq_disable (ep->bEndpointAddress);
+-              }
+-              ep->pio_irqs++;
+-      } while (completed);
+-}
+-
+-/*
+- *    pxa2xx_udc_irq - interrupt handler
+- *
+- * avoid delays in ep0 processing. the control handshaking isn't always
+- * under software control (pxa250c0 and the pxa255 are better), and delays
+- * could cause usb protocol errors.
+- */
+-static irqreturn_t
+-pxa2xx_udc_irq(int irq, void *_dev)
+-{
+-      struct pxa2xx_udc       *dev = _dev;
+-      int                     handled;
+-
+-      dev->stats.irqs++;
+-      do {
+-              u32             udccr = UDCCR;
+-
+-              handled = 0;
+-
+-              /* SUSpend Interrupt Request */
+-              if (unlikely(udccr & UDCCR_SUSIR)) {
+-                      udc_ack_int_UDCCR(UDCCR_SUSIR);
+-                      handled = 1;
+-                      DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present()
+-                              ? "" : "+disconnect");
+-
+-                      if (!is_vbus_present())
+-                              stop_activity(dev, dev->driver);
+-                      else if (dev->gadget.speed != USB_SPEED_UNKNOWN
+-                                      && dev->driver
+-                                      && dev->driver->suspend)
+-                              dev->driver->suspend(&dev->gadget);
+-                      ep0_idle (dev);
+-              }
+-
+-              /* RESume Interrupt Request */
+-              if (unlikely(udccr & UDCCR_RESIR)) {
+-                      udc_ack_int_UDCCR(UDCCR_RESIR);
+-                      handled = 1;
+-                      DBG(DBG_VERBOSE, "USB resume\n");
+-
+-                      if (dev->gadget.speed != USB_SPEED_UNKNOWN
+-                                      && dev->driver
+-                                      && dev->driver->resume
+-                                      && is_vbus_present())
+-                              dev->driver->resume(&dev->gadget);
+-              }
+-
+-              /* ReSeT Interrupt Request - USB reset */
+-              if (unlikely(udccr & UDCCR_RSTIR)) {
+-                      udc_ack_int_UDCCR(UDCCR_RSTIR);
+-                      handled = 1;
+-
+-                      if ((UDCCR & UDCCR_UDA) == 0) {
+-                              DBG(DBG_VERBOSE, "USB reset start\n");
+-
+-                              /* reset driver and endpoints,
+-                               * in case that's not yet done
+-                               */
+-                              stop_activity (dev, dev->driver);
+-
+-                      } else {
+-                              DBG(DBG_VERBOSE, "USB reset end\n");
+-                              dev->gadget.speed = USB_SPEED_FULL;
+-                              memset(&dev->stats, 0, sizeof dev->stats);
+-                              /* driver and endpoints are still reset */
+-                      }
+-
+-              } else {
+-                      u32     usir0 = USIR0 & ~UICR0;
+-                      u32     usir1 = USIR1 & ~UICR1;
+-                      int     i;
+-
+-                      if (unlikely (!usir0 && !usir1))
+-                              continue;
+-
+-                      DBG(DBG_VERY_NOISY, "irq %02x.%02x\n", usir1, usir0);
+-
+-                      /* control traffic */
+-                      if (usir0 & USIR0_IR0) {
+-                              dev->ep[0].pio_irqs++;
+-                              handle_ep0(dev);
+-                              handled = 1;
+-                      }
+-
+-                      /* endpoint data transfers */
+-                      for (i = 0; i < 8; i++) {
+-                              u32     tmp = 1 << i;
+-
+-                              if (i && (usir0 & tmp)) {
+-                                      handle_ep(&dev->ep[i]);
+-                                      USIR0 |= tmp;
+-                                      handled = 1;
+-                              }
+-                              if (usir1 & tmp) {
+-                                      handle_ep(&dev->ep[i+8]);
+-                                      USIR1 |= tmp;
+-                                      handled = 1;
+-                              }
+-                      }
+-              }
+-
+-              /* we could also ask for 1 msec SOF (SIR) interrupts */
+-
+-      } while (handled);
+-      return IRQ_HANDLED;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static void nop_release (struct device *dev)
+-{
+-      DMSG("%s %s\n", __func__, dev->bus_id);
+-}
+-
+-/* this uses load-time allocation and initialization (instead of
+- * doing it at run-time) to save code, eliminate fault paths, and
+- * be more obviously correct.
+- */
+-static struct pxa2xx_udc memory = {
+-      .gadget = {
+-              .ops            = &pxa2xx_udc_ops,
+-              .ep0            = &memory.ep[0].ep,
+-              .name           = driver_name,
+-              .dev = {
+-                      .bus_id         = "gadget",
+-                      .release        = nop_release,
+-              },
+-      },
+-
+-      /* control endpoint */
+-      .ep[0] = {
+-              .ep = {
+-                      .name           = ep0name,
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = EP0_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .reg_udccs      = &UDCCS0,
+-              .reg_uddr       = &UDDR0,
+-      },
+-
+-      /* first group of endpoints */
+-      .ep[1] = {
+-              .ep = {
+-                      .name           = "ep1in-bulk",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = BULK_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = BULK_FIFO_SIZE,
+-              .bEndpointAddress = USB_DIR_IN | 1,
+-              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
+-              .reg_udccs      = &UDCCS1,
+-              .reg_uddr       = &UDDR1,
+-      },
+-      .ep[2] = {
+-              .ep = {
+-                      .name           = "ep2out-bulk",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = BULK_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = BULK_FIFO_SIZE,
+-              .bEndpointAddress = 2,
+-              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
+-              .reg_udccs      = &UDCCS2,
+-              .reg_ubcr       = &UBCR2,
+-              .reg_uddr       = &UDDR2,
+-      },
+-#ifndef CONFIG_USB_PXA2XX_SMALL
+-      .ep[3] = {
+-              .ep = {
+-                      .name           = "ep3in-iso",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = ISO_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = ISO_FIFO_SIZE,
+-              .bEndpointAddress = USB_DIR_IN | 3,
+-              .bmAttributes   = USB_ENDPOINT_XFER_ISOC,
+-              .reg_udccs      = &UDCCS3,
+-              .reg_uddr       = &UDDR3,
+-      },
+-      .ep[4] = {
+-              .ep = {
+-                      .name           = "ep4out-iso",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = ISO_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = ISO_FIFO_SIZE,
+-              .bEndpointAddress = 4,
+-              .bmAttributes   = USB_ENDPOINT_XFER_ISOC,
+-              .reg_udccs      = &UDCCS4,
+-              .reg_ubcr       = &UBCR4,
+-              .reg_uddr       = &UDDR4,
+-      },
+-      .ep[5] = {
+-              .ep = {
+-                      .name           = "ep5in-int",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = INT_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = INT_FIFO_SIZE,
+-              .bEndpointAddress = USB_DIR_IN | 5,
+-              .bmAttributes   = USB_ENDPOINT_XFER_INT,
+-              .reg_udccs      = &UDCCS5,
+-              .reg_uddr       = &UDDR5,
+-      },
+-
+-      /* second group of endpoints */
+-      .ep[6] = {
+-              .ep = {
+-                      .name           = "ep6in-bulk",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = BULK_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = BULK_FIFO_SIZE,
+-              .bEndpointAddress = USB_DIR_IN | 6,
+-              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
+-              .reg_udccs      = &UDCCS6,
+-              .reg_uddr       = &UDDR6,
+-      },
+-      .ep[7] = {
+-              .ep = {
+-                      .name           = "ep7out-bulk",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = BULK_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = BULK_FIFO_SIZE,
+-              .bEndpointAddress = 7,
+-              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
+-              .reg_udccs      = &UDCCS7,
+-              .reg_ubcr       = &UBCR7,
+-              .reg_uddr       = &UDDR7,
+-      },
+-      .ep[8] = {
+-              .ep = {
+-                      .name           = "ep8in-iso",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = ISO_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = ISO_FIFO_SIZE,
+-              .bEndpointAddress = USB_DIR_IN | 8,
+-              .bmAttributes   = USB_ENDPOINT_XFER_ISOC,
+-              .reg_udccs      = &UDCCS8,
+-              .reg_uddr       = &UDDR8,
+-      },
+-      .ep[9] = {
+-              .ep = {
+-                      .name           = "ep9out-iso",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = ISO_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = ISO_FIFO_SIZE,
+-              .bEndpointAddress = 9,
+-              .bmAttributes   = USB_ENDPOINT_XFER_ISOC,
+-              .reg_udccs      = &UDCCS9,
+-              .reg_ubcr       = &UBCR9,
+-              .reg_uddr       = &UDDR9,
+-      },
+-      .ep[10] = {
+-              .ep = {
+-                      .name           = "ep10in-int",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = INT_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = INT_FIFO_SIZE,
+-              .bEndpointAddress = USB_DIR_IN | 10,
+-              .bmAttributes   = USB_ENDPOINT_XFER_INT,
+-              .reg_udccs      = &UDCCS10,
+-              .reg_uddr       = &UDDR10,
+-      },
+-
+-      /* third group of endpoints */
+-      .ep[11] = {
+-              .ep = {
+-                      .name           = "ep11in-bulk",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = BULK_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = BULK_FIFO_SIZE,
+-              .bEndpointAddress = USB_DIR_IN | 11,
+-              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
+-              .reg_udccs      = &UDCCS11,
+-              .reg_uddr       = &UDDR11,
+-      },
+-      .ep[12] = {
+-              .ep = {
+-                      .name           = "ep12out-bulk",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = BULK_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = BULK_FIFO_SIZE,
+-              .bEndpointAddress = 12,
+-              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
+-              .reg_udccs      = &UDCCS12,
+-              .reg_ubcr       = &UBCR12,
+-              .reg_uddr       = &UDDR12,
+-      },
+-      .ep[13] = {
+-              .ep = {
+-                      .name           = "ep13in-iso",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = ISO_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = ISO_FIFO_SIZE,
+-              .bEndpointAddress = USB_DIR_IN | 13,
+-              .bmAttributes   = USB_ENDPOINT_XFER_ISOC,
+-              .reg_udccs      = &UDCCS13,
+-              .reg_uddr       = &UDDR13,
+-      },
+-      .ep[14] = {
+-              .ep = {
+-                      .name           = "ep14out-iso",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = ISO_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = ISO_FIFO_SIZE,
+-              .bEndpointAddress = 14,
+-              .bmAttributes   = USB_ENDPOINT_XFER_ISOC,
+-              .reg_udccs      = &UDCCS14,
+-              .reg_ubcr       = &UBCR14,
+-              .reg_uddr       = &UDDR14,
+-      },
+-      .ep[15] = {
+-              .ep = {
+-                      .name           = "ep15in-int",
+-                      .ops            = &pxa2xx_ep_ops,
+-                      .maxpacket      = INT_FIFO_SIZE,
+-              },
+-              .dev            = &memory,
+-              .fifo_size      = INT_FIFO_SIZE,
+-              .bEndpointAddress = USB_DIR_IN | 15,
+-              .bmAttributes   = USB_ENDPOINT_XFER_INT,
+-              .reg_udccs      = &UDCCS15,
+-              .reg_uddr       = &UDDR15,
+-      },
+-#endif /* !CONFIG_USB_PXA2XX_SMALL */
+-};
+-
+-#define CP15R0_VENDOR_MASK    0xffffe000
+-
+-#if   defined(CONFIG_ARCH_PXA)
+-#define CP15R0_XSCALE_VALUE   0x69052000      /* intel/arm/xscale */
+-
+-#elif defined(CONFIG_ARCH_IXP4XX)
+-#define CP15R0_XSCALE_VALUE   0x69054000      /* intel/arm/ixp4xx */
+-
+-#endif
+-
+-#define CP15R0_PROD_MASK      0x000003f0
+-#define PXA25x                        0x00000100      /* and PXA26x */
+-#define PXA210                        0x00000120
+-
+-#define CP15R0_REV_MASK               0x0000000f
+-
+-#define CP15R0_PRODREV_MASK   (CP15R0_PROD_MASK | CP15R0_REV_MASK)
+-
+-#define PXA255_A0             0x00000106      /* or PXA260_B1 */
+-#define PXA250_C0             0x00000105      /* or PXA26x_B0 */
+-#define PXA250_B2             0x00000104
+-#define PXA250_B1             0x00000103      /* or PXA260_A0 */
+-#define PXA250_B0             0x00000102
+-#define PXA250_A1             0x00000101
+-#define PXA250_A0             0x00000100
+-
+-#define PXA210_C0             0x00000125
+-#define PXA210_B2             0x00000124
+-#define PXA210_B1             0x00000123
+-#define PXA210_B0             0x00000122
+-#define IXP425_A0             0x000001c1
+-#define IXP425_B0             0x000001f1
+-#define IXP465_AD             0x00000200
+-
+-/*
+- *    probe - binds to the platform device
+- */
+-static int __init pxa2xx_udc_probe(struct platform_device *pdev)
+-{
+-      struct pxa2xx_udc *dev = &memory;
+-      int retval, vbus_irq, irq;
+-      u32 chiprev;
+-
+-      /* insist on Intel/ARM/XScale */
+-      asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev));
+-      if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) {
+-              pr_err("%s: not XScale!\n", driver_name);
+-              return -ENODEV;
+-      }
+-
+-      /* trigger chiprev-specific logic */
+-      switch (chiprev & CP15R0_PRODREV_MASK) {
+-#if   defined(CONFIG_ARCH_PXA)
+-      case PXA255_A0:
+-              dev->has_cfr = 1;
+-              break;
+-      case PXA250_A0:
+-      case PXA250_A1:
+-              /* A0/A1 "not released"; ep 13, 15 unusable */
+-              /* fall through */
+-      case PXA250_B2: case PXA210_B2:
+-      case PXA250_B1: case PXA210_B1:
+-      case PXA250_B0: case PXA210_B0:
+-              /* OUT-DMA is broken ... */
+-              /* fall through */
+-      case PXA250_C0: case PXA210_C0:
+-              break;
+-#elif defined(CONFIG_ARCH_IXP4XX)
+-      case IXP425_A0:
+-      case IXP425_B0:
+-      case IXP465_AD:
+-              dev->has_cfr = 1;
+-              break;
+-#endif
+-      default:
+-              pr_err("%s: unrecognized processor: %08x\n",
+-                      driver_name, chiprev);
+-              /* iop3xx, ixp4xx, ... */
+-              return -ENODEV;
+-      }
+-
+-      irq = platform_get_irq(pdev, 0);
+-      if (irq < 0)
+-              return -ENODEV;
+-
+-      dev->clk = clk_get(&pdev->dev, "UDCCLK");
+-      if (IS_ERR(dev->clk)) {
+-              retval = PTR_ERR(dev->clk);
+-              goto err_clk;
+-      }
+-
+-      pr_debug("%s: IRQ %d%s%s\n", driver_name, irq,
+-              dev->has_cfr ? "" : " (!cfr)",
+-              SIZE_STR "(pio)"
+-              );
+-
+-      /* other non-static parts of init */
+-      dev->dev = &pdev->dev;
+-      dev->mach = pdev->dev.platform_data;
+-
+-      if (dev->mach->gpio_vbus) {
+-              if ((retval = gpio_request(dev->mach->gpio_vbus,
+-                              "pxa2xx_udc GPIO VBUS"))) {
+-                      dev_dbg(&pdev->dev,
+-                              "can't get vbus gpio %d, err: %d\n",
+-                              dev->mach->gpio_vbus, retval);
+-                      goto err_gpio_vbus;
+-              }
+-              gpio_direction_input(dev->mach->gpio_vbus);
+-              vbus_irq = gpio_to_irq(dev->mach->gpio_vbus);
+-      } else
+-              vbus_irq = 0;
+-
+-      if (dev->mach->gpio_pullup) {
+-              if ((retval = gpio_request(dev->mach->gpio_pullup,
+-                              "pca2xx_udc GPIO PULLUP"))) {
+-                      dev_dbg(&pdev->dev,
+-                              "can't get pullup gpio %d, err: %d\n",
+-                              dev->mach->gpio_pullup, retval);
+-                      goto err_gpio_pullup;
+-              }
+-              gpio_direction_output(dev->mach->gpio_pullup, 0);
+-      }
+-
+-      init_timer(&dev->timer);
+-      dev->timer.function = udc_watchdog;
+-      dev->timer.data = (unsigned long) dev;
+-
+-      device_initialize(&dev->gadget.dev);
+-      dev->gadget.dev.parent = &pdev->dev;
+-      dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+-
+-      the_controller = dev;
+-      platform_set_drvdata(pdev, dev);
+-
+-      udc_disable(dev);
+-      udc_reinit(dev);
+-
+-      dev->vbus = is_vbus_present();
+-
+-      /* irq setup after old hardware state is cleaned up */
+-      retval = request_irq(irq, pxa2xx_udc_irq,
+-                      IRQF_DISABLED, driver_name, dev);
+-      if (retval != 0) {
+-              pr_err("%s: can't get irq %d, err %d\n",
+-                      driver_name, irq, retval);
+-              goto err_irq1;
+-      }
+-      dev->got_irq = 1;
+-
+-#ifdef CONFIG_ARCH_LUBBOCK
+-      if (machine_is_lubbock()) {
+-              retval = request_irq(LUBBOCK_USB_DISC_IRQ,
+-                              lubbock_vbus_irq,
+-                              IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+-                              driver_name, dev);
+-              if (retval != 0) {
+-                      pr_err("%s: can't get irq %i, err %d\n",
+-                              driver_name, LUBBOCK_USB_DISC_IRQ, retval);
+-lubbock_fail0:
+-                      goto err_irq_lub;
+-              }
+-              retval = request_irq(LUBBOCK_USB_IRQ,
+-                              lubbock_vbus_irq,
+-                              IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+-                              driver_name, dev);
+-              if (retval != 0) {
+-                      pr_err("%s: can't get irq %i, err %d\n",
+-                              driver_name, LUBBOCK_USB_IRQ, retval);
+-                      free_irq(LUBBOCK_USB_DISC_IRQ, dev);
+-                      goto lubbock_fail0;
+-              }
+-      } else
+-#endif
+-      if (vbus_irq) {
+-              retval = request_irq(vbus_irq, udc_vbus_irq,
+-                              IRQF_DISABLED | IRQF_SAMPLE_RANDOM |
+-                              IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+-                              driver_name, dev);
+-              if (retval != 0) {
+-                      pr_err("%s: can't get irq %i, err %d\n",
+-                              driver_name, vbus_irq, retval);
+-                      goto err_vbus_irq;
+-              }
+-      }
+-      create_debug_files(dev);
+-
+-      return 0;
+-
+- err_vbus_irq:
+-#ifdef        CONFIG_ARCH_LUBBOCK
+-      free_irq(LUBBOCK_USB_DISC_IRQ, dev);
+- err_irq_lub:
+-#endif
+-      free_irq(irq, dev);
+- err_irq1:
+-      if (dev->mach->gpio_pullup)
+-              gpio_free(dev->mach->gpio_pullup);
+- err_gpio_pullup:
+-      if (dev->mach->gpio_vbus)
+-              gpio_free(dev->mach->gpio_vbus);
+- err_gpio_vbus:
+-      clk_put(dev->clk);
+- err_clk:
+-      return retval;
+-}
+-
+-static void pxa2xx_udc_shutdown(struct platform_device *_dev)
+-{
+-      pullup_off();
+-}
+-
+-static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
+-{
+-      struct pxa2xx_udc *dev = platform_get_drvdata(pdev);
+-
+-      if (dev->driver)
+-              return -EBUSY;
+-
+-      dev->pullup = 0;
+-      pullup(dev);
+-
+-      remove_debug_files(dev);
+-
+-      if (dev->got_irq) {
+-              free_irq(platform_get_irq(pdev, 0), dev);
+-              dev->got_irq = 0;
+-      }
+-#ifdef CONFIG_ARCH_LUBBOCK
+-      if (machine_is_lubbock()) {
+-              free_irq(LUBBOCK_USB_DISC_IRQ, dev);
+-              free_irq(LUBBOCK_USB_IRQ, dev);
+-      }
+-#endif
+-      if (dev->mach->gpio_vbus) {
+-              free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev);
+-              gpio_free(dev->mach->gpio_vbus);
+-      }
+-      if (dev->mach->gpio_pullup)
+-              gpio_free(dev->mach->gpio_pullup);
+-
+-      clk_put(dev->clk);
+-
+-      platform_set_drvdata(pdev, NULL);
+-      the_controller = NULL;
+-      return 0;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-#ifdef        CONFIG_PM
+-
+-/* USB suspend (controlled by the host) and system suspend (controlled
+- * by the PXA) don't necessarily work well together.  If USB is active,
+- * the 48 MHz clock is required; so the system can't enter 33 MHz idle
+- * mode, or any deeper PM saving state.
+- *
+- * For now, we punt and forcibly disconnect from the USB host when PXA
+- * enters any suspend state.  While we're disconnected, we always disable
+- * the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states.
+- * Boards without software pullup control shouldn't use those states.
+- * VBUS IRQs should probably be ignored so that the PXA device just acts
+- * "dead" to USB hosts until system resume.
+- */
+-static int pxa2xx_udc_suspend(struct platform_device *dev, pm_message_t state)
+-{
+-      struct pxa2xx_udc       *udc = platform_get_drvdata(dev);
+-      unsigned long flags;
+-
+-      if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
+-              WARN("USB host won't detect disconnect!\n");
+-      udc->suspended = 1;
+-
+-      local_irq_save(flags);
+-      pullup(udc);
+-      local_irq_restore(flags);
+-
+-      return 0;
+-}
+-
+-static int pxa2xx_udc_resume(struct platform_device *dev)
+-{
+-      struct pxa2xx_udc       *udc = platform_get_drvdata(dev);
+-      unsigned long flags;
+-
+-      udc->suspended = 0;
+-      local_irq_save(flags);
+-      pullup(udc);
+-      local_irq_restore(flags);
+-
+-      return 0;
+-}
+-
+-#else
+-#define       pxa2xx_udc_suspend      NULL
+-#define       pxa2xx_udc_resume       NULL
+-#endif
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static struct platform_driver udc_driver = {
+-      .shutdown       = pxa2xx_udc_shutdown,
+-      .remove         = __exit_p(pxa2xx_udc_remove),
+-      .suspend        = pxa2xx_udc_suspend,
+-      .resume         = pxa2xx_udc_resume,
+-      .driver         = {
+-              .owner  = THIS_MODULE,
+-              .name   = "pxa2xx-udc",
+-      },
+-};
+-
+-static int __init udc_init(void)
+-{
+-      pr_info("%s: version %s\n", driver_name, DRIVER_VERSION);
+-      return platform_driver_probe(&udc_driver, pxa2xx_udc_probe);
+-}
+-module_init(udc_init);
+-
+-static void __exit udc_exit(void)
+-{
+-      platform_driver_unregister(&udc_driver);
+-}
+-module_exit(udc_exit);
+-
+-MODULE_DESCRIPTION(DRIVER_DESC);
+-MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell");
+-MODULE_LICENSE("GPL");
+-MODULE_ALIAS("platform:pxa2xx-udc");
+diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
+deleted file mode 100644
+index e2c19e8..0000000
+--- a/drivers/usb/gadget/pxa2xx_udc.h
++++ /dev/null
+@@ -1,267 +0,0 @@
+-/*
+- * linux/drivers/usb/gadget/pxa2xx_udc.h
+- * Intel PXA2xx on-chip full speed USB device controller
+- *
+- * Copyright (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix
+- * Copyright (C) 2003 David Brownell
+- *
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+- */
+-
+-#ifndef __LINUX_USB_GADGET_PXA2XX_H
+-#define __LINUX_USB_GADGET_PXA2XX_H
+-
+-#include <linux/types.h>
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/* pxa2xx has this (move to include/asm-arm/arch-pxa/pxa-regs.h) */
+-#define UFNRH_SIR     (1 << 7)        /* SOF interrupt request */
+-#define UFNRH_SIM     (1 << 6)        /* SOF interrupt mask */
+-#define UFNRH_IPE14   (1 << 5)        /* ISO packet error, ep14 */
+-#define UFNRH_IPE9    (1 << 4)        /* ISO packet error, ep9 */
+-#define UFNRH_IPE4    (1 << 3)        /* ISO packet error, ep4 */
+-
+-/* pxa255 has this (move to include/asm-arm/arch-pxa/pxa-regs.h) */
+-#define       UDCCFR          UDC_RES2        /* UDC Control Function Register */
+-#define UDCCFR_AREN   (1 << 7)        /* ACK response enable (now) */
+-#define UDCCFR_ACM    (1 << 2)        /* ACK control mode (wait for AREN) */
+-
+-/* latest pxa255 errata define new "must be one" bits in UDCCFR */
+-#define       UDCCFR_MB1      (0xff & ~(UDCCFR_AREN|UDCCFR_ACM))
+-
+-/*-------------------------------------------------------------------------*/
+-
+-struct pxa2xx_udc;
+-
+-struct pxa2xx_ep {
+-      struct usb_ep                           ep;
+-      struct pxa2xx_udc                       *dev;
+-
+-      const struct usb_endpoint_descriptor    *desc;
+-      struct list_head                        queue;
+-      unsigned long                           pio_irqs;
+-
+-      unsigned short                          fifo_size;
+-      u8                                      bEndpointAddress;
+-      u8                                      bmAttributes;
+-
+-      unsigned                                stopped : 1;
+-      unsigned                                dma_fixup : 1;
+-
+-      /* UDCCS = UDC Control/Status for this EP
+-       * UBCR = UDC Byte Count Remaining (contents of OUT fifo)
+-       * UDDR = UDC Endpoint Data Register (the fifo)
+-       * DRCM = DMA Request Channel Map
+-       */
+-      volatile u32                            *reg_udccs;
+-      volatile u32                            *reg_ubcr;
+-      volatile u32                            *reg_uddr;
+-};
+-
+-struct pxa2xx_request {
+-      struct usb_request                      req;
+-      struct list_head                        queue;
+-};
+-
+-enum ep0_state {
+-      EP0_IDLE,
+-      EP0_IN_DATA_PHASE,
+-      EP0_OUT_DATA_PHASE,
+-      EP0_END_XFER,
+-      EP0_STALL,
+-};
+-
+-#define EP0_FIFO_SIZE ((unsigned)16)
+-#define BULK_FIFO_SIZE        ((unsigned)64)
+-#define ISO_FIFO_SIZE ((unsigned)256)
+-#define INT_FIFO_SIZE ((unsigned)8)
+-
+-struct udc_stats {
+-      struct ep0stats {
+-              unsigned long           ops;
+-              unsigned long           bytes;
+-      } read, write;
+-      unsigned long                   irqs;
+-};
+-
+-#ifdef CONFIG_USB_PXA2XX_SMALL
+-/* when memory's tight, SMALL config saves code+data.  */
+-#define       PXA_UDC_NUM_ENDPOINTS   3
+-#endif
+-
+-#ifndef       PXA_UDC_NUM_ENDPOINTS
+-#define       PXA_UDC_NUM_ENDPOINTS   16
+-#endif
+-
+-struct pxa2xx_udc {
+-      struct usb_gadget                       gadget;
+-      struct usb_gadget_driver                *driver;
+-
+-      enum ep0_state                          ep0state;
+-      struct udc_stats                        stats;
+-      unsigned                                got_irq : 1,
+-                                              vbus : 1,
+-                                              pullup : 1,
+-                                              has_cfr : 1,
+-                                              req_pending : 1,
+-                                              req_std : 1,
+-                                              req_config : 1,
+-                                              suspended : 1,
+-                                              active : 1;
+-
+-#define start_watchdog(dev) mod_timer(&dev->timer, jiffies + (HZ/200))
+-      struct timer_list                       timer;
+-
+-      struct device                           *dev;
+-      struct clk                              *clk;
+-      struct pxa2xx_udc_mach_info             *mach;
+-      u64                                     dma_mask;
+-      struct pxa2xx_ep                        ep [PXA_UDC_NUM_ENDPOINTS];
+-
+-#ifdef CONFIG_USB_GADGET_DEBUG_FS
+-      struct dentry                           *debugfs_udc;
+-#endif
+-};
+-
+-/*-------------------------------------------------------------------------*/
+-
+-#ifdef CONFIG_ARCH_LUBBOCK
+-#include <asm/arch/lubbock.h>
+-/* lubbock can also report usb connect/disconnect irqs */
+-#endif
+-
+-static struct pxa2xx_udc *the_controller;
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/*
+- * Debugging support vanishes in non-debug builds.  DBG_NORMAL should be
+- * mostly silent during normal use/testing, with no timing side-effects.
+- */
+-#define DBG_NORMAL    1       /* error paths, device state transitions */
+-#define DBG_VERBOSE   2       /* add some success path trace info */
+-#define DBG_NOISY     3       /* ... even more: request level */
+-#define DBG_VERY_NOISY        4       /* ... even more: packet level */
+-
+-#define DMSG(stuff...)        pr_debug("udc: " stuff)
+-
+-#ifdef DEBUG
+-
+-static int is_vbus_present(void);
+-
+-static const char *state_name[] = {
+-      "EP0_IDLE",
+-      "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE",
+-      "EP0_END_XFER", "EP0_STALL"
+-};
+-
+-#ifdef VERBOSE_DEBUG
+-#    define UDC_DEBUG DBG_VERBOSE
+-#else
+-#    define UDC_DEBUG DBG_NORMAL
+-#endif
+-
+-static void __maybe_unused
+-dump_udccr(const char *label)
+-{
+-      u32     udccr = UDCCR;
+-      DMSG("%s %02X =%s%s%s%s%s%s%s%s\n",
+-              label, udccr,
+-              (udccr & UDCCR_REM) ? " rem" : "",
+-              (udccr & UDCCR_RSTIR) ? " rstir" : "",
+-              (udccr & UDCCR_SRM) ? " srm" : "",
+-              (udccr & UDCCR_SUSIR) ? " susir" : "",
+-              (udccr & UDCCR_RESIR) ? " resir" : "",
+-              (udccr & UDCCR_RSM) ? " rsm" : "",
+-              (udccr & UDCCR_UDA) ? " uda" : "",
+-              (udccr & UDCCR_UDE) ? " ude" : "");
+-}
+-
+-static void __maybe_unused
+-dump_udccs0(const char *label)
+-{
+-      u32             udccs0 = UDCCS0;
+-
+-      DMSG("%s %s %02X =%s%s%s%s%s%s%s%s\n",
+-              label, state_name[the_controller->ep0state], udccs0,
+-              (udccs0 & UDCCS0_SA) ? " sa" : "",
+-              (udccs0 & UDCCS0_RNE) ? " rne" : "",
+-              (udccs0 & UDCCS0_FST) ? " fst" : "",
+-              (udccs0 & UDCCS0_SST) ? " sst" : "",
+-              (udccs0 & UDCCS0_DRWF) ? " dwrf" : "",
+-              (udccs0 & UDCCS0_FTF) ? " ftf" : "",
+-              (udccs0 & UDCCS0_IPR) ? " ipr" : "",
+-              (udccs0 & UDCCS0_OPR) ? " opr" : "");
+-}
+-
+-static void __maybe_unused
+-dump_state(struct pxa2xx_udc *dev)
+-{
+-      u32             tmp;
+-      unsigned        i;
+-
+-      DMSG("%s %s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
+-              is_vbus_present() ? "host " : "disconnected",
+-              state_name[dev->ep0state],
+-              UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
+-      dump_udccr("udccr");
+-      if (dev->has_cfr) {
+-              tmp = UDCCFR;
+-              DMSG("udccfr %02X =%s%s\n", tmp,
+-                      (tmp & UDCCFR_AREN) ? " aren" : "",
+-                      (tmp & UDCCFR_ACM) ? " acm" : "");
+-      }
+-
+-      if (!dev->driver) {
+-              DMSG("no gadget driver bound\n");
+-              return;
+-      } else
+-              DMSG("ep0 driver '%s'\n", dev->driver->driver.name);
+-
+-      if (!is_vbus_present())
+-              return;
+-
+-      dump_udccs0 ("udccs0");
+-      DMSG("ep0 IN %lu/%lu, OUT %lu/%lu\n",
+-              dev->stats.write.bytes, dev->stats.write.ops,
+-              dev->stats.read.bytes, dev->stats.read.ops);
+-
+-      for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) {
+-              if (dev->ep [i].desc == NULL)
+-                      continue;
+-              DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs);
+-      }
+-}
+-
+-#else
+-
+-#define       dump_udccr(x)   do{}while(0)
+-#define       dump_udccs0(x)  do{}while(0)
+-#define       dump_state(x)   do{}while(0)
+-
+-#define UDC_DEBUG ((unsigned)0)
+-
+-#endif
+-
+-#define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0)
+-
+-#define ERR(stuff...)         pr_err("udc: " stuff)
+-#define WARN(stuff...)                pr_warning("udc: " stuff)
+-#define INFO(stuff...)                pr_info("udc: " stuff)
+-
+-
+-#endif /* __LINUX_USB_GADGET_PXA2XX_H */
+diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
+index d0677f5..7228e85 100644
+--- a/drivers/usb/gadget/rndis.c
++++ b/drivers/usb/gadget/rndis.c
+@@ -1,8 +1,6 @@
+ /*
+  * RNDIS MSG parser
+  *
+- * Version:     $Id: rndis.c,v 1.19 2004/03/25 21:33:46 robert Exp $
+- *
+  * Authors:   Benedikt Spranger, Pengutronix
+  *            Robert Schwebel, Pengutronix
+  *
+@@ -30,6 +28,7 @@
+ #include <linux/init.h>
+ #include <linux/list.h>
+ #include <linux/proc_fs.h>
++#include <linux/seq_file.h>
+ #include <linux/netdevice.h>
+ #include <asm/io.h>
+@@ -38,9 +37,7 @@
+ #include <asm/unaligned.h>
+-#undef        RNDIS_PM
+-#undef        RNDIS_WAKEUP
+-#undef        VERBOSE
++#undef        VERBOSE_DEBUG
+ #include "rndis.h"
+@@ -96,9 +93,6 @@ static const u32 oid_supported_list [] =
+       OID_GEN_MAXIMUM_TOTAL_SIZE,
+       OID_GEN_MEDIA_CONNECT_STATUS,
+       OID_GEN_PHYSICAL_MEDIUM,
+-#if 0
+-      OID_GEN_RNDIS_CONFIG_PARAMETER,
+-#endif
+       /* the statistical stuff */
+       OID_GEN_XMIT_OK,
+@@ -146,7 +140,14 @@ static const u32 oid_supported_list [] =
+ #endif        /* RNDIS_OPTIONAL_STATS */
+ #ifdef        RNDIS_PM
+-      /* PM and wakeup are mandatory for USB: */
++      /* PM and wakeup are "mandatory" for USB, but the RNDIS specs
++       * don't say what they mean ... and the NDIS specs are often
++       * confusing and/or ambiguous in this context.  (That is, more
++       * so than their specs for the other OIDs.)
++       *
++       * FIXME someone who knows what these should do, please
++       * implement them!
++       */
+       /* power management */
+       OID_PNP_CAPABILITIES,
+@@ -173,6 +174,8 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+       __le32                  *outbuf;
+       int                     i, count;
+       rndis_query_cmplt_type  *resp;
++      struct net_device       *net;
++      struct net_device_stats *stats;
+       if (!r) return -ENOMEM;
+       resp = (rndis_query_cmplt_type *) r->buf;
+@@ -194,6 +197,12 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+       outbuf = (__le32 *) &resp[1];
+       resp->InformationBufferOffset = __constant_cpu_to_le32 (16);
++      net = rndis_per_dev_params[configNr].dev;
++      if (net->get_stats)
++              stats = net->get_stats(net);
++      else
++              stats = NULL;
++
+       switch (OID) {
+       /* general oids (table 4-1) */
+@@ -350,11 +359,9 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+       case OID_GEN_XMIT_OK:
+               if (rndis_debug > 1)
+                       DBG("%s: OID_GEN_XMIT_OK\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (
+-                          rndis_per_dev_params [configNr].stats->tx_packets -
+-                          rndis_per_dev_params [configNr].stats->tx_errors -
+-                          rndis_per_dev_params [configNr].stats->tx_dropped);
++              if (stats) {
++                      *outbuf = cpu_to_le32(stats->tx_packets
++                              - stats->tx_errors - stats->tx_dropped);
+                       retval = 0;
+               }
+               break;
+@@ -363,11 +370,9 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+       case OID_GEN_RCV_OK:
+               if (rndis_debug > 1)
+                       DBG("%s: OID_GEN_RCV_OK\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (
+-                          rndis_per_dev_params [configNr].stats->rx_packets -
+-                          rndis_per_dev_params [configNr].stats->rx_errors -
+-                          rndis_per_dev_params [configNr].stats->rx_dropped);
++              if (stats) {
++                      *outbuf = cpu_to_le32(stats->rx_packets
++                              - stats->rx_errors - stats->rx_dropped);
+                       retval = 0;
+               }
+               break;
+@@ -376,9 +381,8 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+       case OID_GEN_XMIT_ERROR:
+               if (rndis_debug > 1)
+                       DBG("%s: OID_GEN_XMIT_ERROR\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->tx_errors);
++              if (stats) {
++                      *outbuf = cpu_to_le32(stats->tx_errors);
+                       retval = 0;
+               }
+               break;
+@@ -387,9 +391,8 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+       case OID_GEN_RCV_ERROR:
+               if (rndis_debug > 1)
+                       DBG("%s: OID_GEN_RCV_ERROR\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->rx_errors);
++              if (stats) {
++                      *outbuf = cpu_to_le32(stats->rx_errors);
+                       retval = 0;
+               }
+               break;
+@@ -397,150 +400,12 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+       /* mandatory */
+       case OID_GEN_RCV_NO_BUFFER:
+               DBG("%s: OID_GEN_RCV_NO_BUFFER\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->rx_dropped);
+-                      retval = 0;
+-              }
+-              break;
+-
+-#ifdef        RNDIS_OPTIONAL_STATS
+-      case OID_GEN_DIRECTED_BYTES_XMIT:
+-              DBG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __func__);
+-              /*
+-               * Aunt Tilly's size of shoes
+-               * minus antarctica count of penguins
+-               * divided by weight of Alpha Centauri
+-               */
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (
+-                              (rndis_per_dev_params [configNr]
+-                                      .stats->tx_packets -
+-                               rndis_per_dev_params [configNr]
+-                                       .stats->tx_errors -
+-                               rndis_per_dev_params [configNr]
+-                                       .stats->tx_dropped)
+-                              * 123);
+-                      retval = 0;
+-              }
+-              break;
+-
+-      case OID_GEN_DIRECTED_FRAMES_XMIT:
+-              DBG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __func__);
+-              /* dito */
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (
+-                              (rndis_per_dev_params [configNr]
+-                                      .stats->tx_packets -
+-                               rndis_per_dev_params [configNr]
+-                                       .stats->tx_errors -
+-                               rndis_per_dev_params [configNr]
+-                                       .stats->tx_dropped)
+-                              / 123);
+-                      retval = 0;
+-              }
+-              break;
+-
+-      case OID_GEN_MULTICAST_BYTES_XMIT:
+-              DBG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->multicast*1234);
+-                      retval = 0;
+-              }
+-              break;
+-
+-      case OID_GEN_MULTICAST_FRAMES_XMIT:
+-              DBG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->multicast);
+-                      retval = 0;
+-              }
+-              break;
+-
+-      case OID_GEN_BROADCAST_BYTES_XMIT:
+-              DBG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->tx_packets/42*255);
+-                      retval = 0;
+-              }
+-              break;
+-
+-      case OID_GEN_BROADCAST_FRAMES_XMIT:
+-              DBG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->tx_packets/42);
+-                      retval = 0;
+-              }
+-              break;
+-
+-      case OID_GEN_DIRECTED_BYTES_RCV:
+-              DBG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __func__);
+-              *outbuf = __constant_cpu_to_le32 (0);
+-              retval = 0;
+-              break;
+-
+-      case OID_GEN_DIRECTED_FRAMES_RCV:
+-              DBG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __func__);
+-              *outbuf = __constant_cpu_to_le32 (0);
+-              retval = 0;
+-              break;
+-
+-      case OID_GEN_MULTICAST_BYTES_RCV:
+-              DBG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->multicast * 1111);
+-                      retval = 0;
+-              }
+-              break;
+-
+-      case OID_GEN_MULTICAST_FRAMES_RCV:
+-              DBG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->multicast);
+-                      retval = 0;
+-              }
+-              break;
+-
+-      case OID_GEN_BROADCAST_BYTES_RCV:
+-              DBG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->rx_packets/42*255);
+-                      retval = 0;
+-              }
+-              break;
+-
+-      case OID_GEN_BROADCAST_FRAMES_RCV:
+-              DBG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->rx_packets/42);
++              if (stats) {
++                      *outbuf = cpu_to_le32(stats->rx_dropped);
+                       retval = 0;
+               }
+               break;
+-      case OID_GEN_RCV_CRC_ERROR:
+-              DBG("%s: OID_GEN_RCV_CRC_ERROR\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->rx_crc_errors);
+-                      retval = 0;
+-              }
+-              break;
+-
+-      case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+-              DBG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __func__);
+-              *outbuf = __constant_cpu_to_le32 (0);
+-              retval = 0;
+-              break;
+-#endif        /* RNDIS_OPTIONAL_STATS */
+-
+       /* ieee802.3 OIDs (table 4-3) */
+       /* mandatory */
+@@ -592,9 +457,8 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+       /* mandatory */
+       case OID_802_3_RCV_ERROR_ALIGNMENT:
+               DBG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__);
+-              if (rndis_per_dev_params [configNr].stats) {
+-                      *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
+-                                      .stats->rx_frame_errors);
++              if (stats) {
++                      *outbuf = cpu_to_le32(stats->rx_frame_errors);
+                       retval = 0;
+               }
+               break;
+@@ -613,64 +477,6 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+               retval = 0;
+               break;
+-#ifdef        RNDIS_OPTIONAL_STATS
+-      case OID_802_3_XMIT_DEFERRED:
+-              DBG("%s: OID_802_3_XMIT_DEFERRED\n", __func__);
+-              /* TODO */
+-              break;
+-
+-      case OID_802_3_XMIT_MAX_COLLISIONS:
+-              DBG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __func__);
+-              /* TODO */
+-              break;
+-
+-      case OID_802_3_RCV_OVERRUN:
+-              DBG("%s: OID_802_3_RCV_OVERRUN\n", __func__);
+-              /* TODO */
+-              break;
+-
+-      case OID_802_3_XMIT_UNDERRUN:
+-              DBG("%s: OID_802_3_XMIT_UNDERRUN\n", __func__);
+-              /* TODO */
+-              break;
+-
+-      case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+-              DBG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __func__);
+-              /* TODO */
+-              break;
+-
+-      case OID_802_3_XMIT_TIMES_CRS_LOST:
+-              DBG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __func__);
+-              /* TODO */
+-              break;
+-
+-      case OID_802_3_XMIT_LATE_COLLISIONS:
+-              DBG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __func__);
+-              /* TODO */
+-              break;
+-#endif        /* RNDIS_OPTIONAL_STATS */
+-
+-#ifdef        RNDIS_PM
+-      /* power management OIDs (table 4-5) */
+-      case OID_PNP_CAPABILITIES:
+-              DBG("%s: OID_PNP_CAPABILITIES\n", __func__);
+-
+-              /* for now, no wakeup capabilities */
+-              length = sizeof (struct NDIS_PNP_CAPABILITIES);
+-              memset(outbuf, 0, length);
+-              retval = 0;
+-              break;
+-      case OID_PNP_QUERY_POWER:
+-              DBG("%s: OID_PNP_QUERY_POWER D%d\n", __func__,
+-                              get_unaligned_le32(buf) - 1);
+-              /* only suspend is a real power state, and
+-               * it can't be entered by OID_PNP_SET_POWER...
+-               */
+-              length = 0;
+-              retval = 0;
+-              break;
+-#endif
+-
+       default:
+               pr_warning("%s: query unknown OID 0x%08X\n",
+                        __func__, OID);
+@@ -726,9 +532,6 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
+                * what makes the packet flow start and stop, like
+                * activating the CDC Ethernet altsetting.
+                */
+-#ifdef        RNDIS_PM
+-update_linkstate:
+-#endif
+               retval = 0;
+               if (*params->filter) {
+                       params->state = RNDIS_DATA_INITIALIZED;
+@@ -747,49 +550,6 @@ update_linkstate:
+               DBG("%s: OID_802_3_MULTICAST_LIST\n", __func__);
+               retval = 0;
+               break;
+-#if 0
+-      case OID_GEN_RNDIS_CONFIG_PARAMETER:
+-              {
+-              struct rndis_config_parameter   *param;
+-              param = (struct rndis_config_parameter *) buf;
+-              DBG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
+-                      __func__,
+-                      min(cpu_to_le32(param->ParameterNameLength),80),
+-                      buf + param->ParameterNameOffset);
+-              retval = 0;
+-              }
+-              break;
+-#endif
+-
+-#ifdef        RNDIS_PM
+-      case OID_PNP_SET_POWER:
+-              /* The only real power state is USB suspend, and RNDIS requests
+-               * can't enter it; this one isn't really about power.  After
+-               * resuming, Windows forces a reset, and then SET_POWER D0.
+-               * FIXME ... then things go batty; Windows wedges itself.
+-               */
+-              i = get_unaligned_le32(buf);
+-              DBG("%s: OID_PNP_SET_POWER D%d\n", __func__, i - 1);
+-              switch (i) {
+-              case NdisDeviceStateD0:
+-                      *params->filter = params->saved_filter;
+-                      goto update_linkstate;
+-              case NdisDeviceStateD3:
+-              case NdisDeviceStateD2:
+-              case NdisDeviceStateD1:
+-                      params->saved_filter = *params->filter;
+-                      retval = 0;
+-                      break;
+-              }
+-              break;
+-
+-#ifdef        RNDIS_WAKEUP
+-      // no wakeup support advertised, so wakeup OIDs always fail:
+-      //  - OID_PNP_ENABLE_WAKE_UP
+-      //  - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN
+-#endif
+-
+-#endif        /* RNDIS_PM */
+       default:
+               pr_warning("%s: set unknown OID 0x%08X, size %d\n",
+@@ -807,8 +567,10 @@ static int rndis_init_response (int configNr, rndis_init_msg_type *buf)
+ {
+       rndis_init_cmplt_type   *resp;
+       rndis_resp_t            *r;
++      struct rndis_params     *params = rndis_per_dev_params + configNr;
+-      if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
++      if (!params->dev)
++              return -ENOTSUPP;
+       r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type));
+       if (!r)
+@@ -826,7 +588,7 @@ static int rndis_init_response (int configNr, rndis_init_msg_type *buf)
+       resp->Medium = __constant_cpu_to_le32 (RNDIS_MEDIUM_802_3);
+       resp->MaxPacketsPerTransfer = __constant_cpu_to_le32 (1);
+       resp->MaxTransferSize = cpu_to_le32 (
+-                rndis_per_dev_params [configNr].dev->mtu
++                params->dev->mtu
+               + sizeof (struct ethhdr)
+               + sizeof (struct rndis_packet_msg_type)
+               + 22);
+@@ -834,10 +596,7 @@ static int rndis_init_response (int configNr, rndis_init_msg_type *buf)
+       resp->AFListOffset = __constant_cpu_to_le32 (0);
+       resp->AFListSize = __constant_cpu_to_le32 (0);
+-      if (rndis_per_dev_params [configNr].ack)
+-              rndis_per_dev_params [configNr].ack (
+-                      rndis_per_dev_params [configNr].dev);
+-
++      params->resp_avail(params->v);
+       return 0;
+ }
+@@ -845,9 +604,11 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
+ {
+       rndis_query_cmplt_type *resp;
+       rndis_resp_t            *r;
++      struct rndis_params     *params = rndis_per_dev_params + configNr;
+       // DBG("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID));
+-      if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
++      if (!params->dev)
++              return -ENOTSUPP;
+       /*
+        * we need more memory:
+@@ -878,9 +639,7 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
+       } else
+               resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
+-      if (rndis_per_dev_params [configNr].ack)
+-              rndis_per_dev_params [configNr].ack (
+-                      rndis_per_dev_params [configNr].dev);
++      params->resp_avail(params->v);
+       return 0;
+ }
+@@ -889,6 +648,7 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
+       u32                     BufLength, BufOffset;
+       rndis_set_cmplt_type    *resp;
+       rndis_resp_t            *r;
++      struct rndis_params     *params = rndis_per_dev_params + configNr;
+       r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type));
+       if (!r)
+@@ -898,7 +658,7 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
+       BufLength = le32_to_cpu (buf->InformationBufferLength);
+       BufOffset = le32_to_cpu (buf->InformationBufferOffset);
+-#ifdef        VERBOSE
++#ifdef        VERBOSE_DEBUG
+       DBG("%s: Length: %d\n", __func__, BufLength);
+       DBG("%s: Offset: %d\n", __func__, BufOffset);
+       DBG("%s: InfoBuffer: ", __func__);
+@@ -919,10 +679,7 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
+       else
+               resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
+-      if (rndis_per_dev_params [configNr].ack)
+-              rndis_per_dev_params [configNr].ack (
+-                      rndis_per_dev_params [configNr].dev);
+-
++      params->resp_avail(params->v);
+       return 0;
+ }
+@@ -930,6 +687,7 @@ static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf)
+ {
+       rndis_reset_cmplt_type  *resp;
+       rndis_resp_t            *r;
++      struct rndis_params     *params = rndis_per_dev_params + configNr;
+       r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type));
+       if (!r)
+@@ -942,10 +700,7 @@ static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf)
+       /* resent information */
+       resp->AddressingReset = __constant_cpu_to_le32 (1);
+-      if (rndis_per_dev_params [configNr].ack)
+-              rndis_per_dev_params [configNr].ack (
+-                      rndis_per_dev_params [configNr].dev);
+-
++      params->resp_avail(params->v);
+       return 0;
+ }
+@@ -954,6 +709,7 @@ static int rndis_keepalive_response (int configNr,
+ {
+       rndis_keepalive_cmplt_type      *resp;
+       rndis_resp_t                    *r;
++      struct rndis_params     *params = rndis_per_dev_params + configNr;
+       /* host "should" check only in RNDIS_DATA_INITIALIZED state */
+@@ -968,10 +724,7 @@ static int rndis_keepalive_response (int configNr,
+       resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+       resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
+-      if (rndis_per_dev_params [configNr].ack)
+-              rndis_per_dev_params [configNr].ack (
+-                      rndis_per_dev_params [configNr].dev);
+-
++      params->resp_avail(params->v);
+       return 0;
+ }
+@@ -983,8 +736,9 @@ static int rndis_indicate_status_msg (int configNr, u32 status)
+ {
+       rndis_indicate_status_msg_type  *resp;
+       rndis_resp_t                    *r;
++      struct rndis_params     *params = rndis_per_dev_params + configNr;
+-      if (rndis_per_dev_params [configNr].state == RNDIS_UNINITIALIZED)
++      if (params->state == RNDIS_UNINITIALIZED)
+               return -ENOTSUPP;
+       r = rndis_add_response (configNr,
+@@ -1000,9 +754,7 @@ static int rndis_indicate_status_msg (int configNr, u32 status)
+       resp->StatusBufferLength = __constant_cpu_to_le32 (0);
+       resp->StatusBufferOffset = __constant_cpu_to_le32 (0);
+-      if (rndis_per_dev_params [configNr].ack)
+-              rndis_per_dev_params [configNr].ack (
+-                      rndis_per_dev_params [configNr].dev);
++      params->resp_avail(params->v);
+       return 0;
+ }
+@@ -1029,7 +781,6 @@ void rndis_uninit (int configNr)
+       if (configNr >= RNDIS_MAX_CONFIGS)
+               return;
+-      rndis_per_dev_params [configNr].used = 0;
+       rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED;
+       /* drain the response queue */
+@@ -1142,21 +893,25 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
+       return -ENOTSUPP;
+ }
+-int rndis_register (int (* rndis_control_ack) (struct net_device *))
++int rndis_register(void (*resp_avail)(void *v), void *v)
+ {
+       u8 i;
++      if (!resp_avail)
++              return -EINVAL;
++
+       for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
+               if (!rndis_per_dev_params [i].used) {
+                       rndis_per_dev_params [i].used = 1;
+-                      rndis_per_dev_params [i].ack = rndis_control_ack;
++                      rndis_per_dev_params [i].resp_avail = resp_avail;
++                      rndis_per_dev_params [i].v = v;
+                       DBG("%s: configNr = %d\n", __func__, i);
+                       return i;
+               }
+       }
+       DBG("failed\n");
+-      return -1;
++      return -ENODEV;
+ }
+ void rndis_deregister (int configNr)
+@@ -1169,16 +924,14 @@ void rndis_deregister (int configNr)
+       return;
+ }
+-int rndis_set_param_dev (u8 configNr, struct net_device *dev,
+-                       struct net_device_stats *stats,
+-                       u16 *cdc_filter)
++int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)
+ {
+       DBG("%s:\n", __func__ );
+-      if (!dev || !stats) return -1;
++      if (!dev)
++              return -EINVAL;
+       if (configNr >= RNDIS_MAX_CONFIGS) return -1;
+       rndis_per_dev_params [configNr].dev = dev;
+-      rndis_per_dev_params [configNr].stats = stats;
+       rndis_per_dev_params [configNr].filter = cdc_filter;
+       return 0;
+@@ -1296,14 +1049,11 @@ int rndis_rm_hdr(struct sk_buff *skb)
+ #ifdef        CONFIG_USB_GADGET_DEBUG_FILES
+-static int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof,
+-              void *data)
++static int rndis_proc_show(struct seq_file *m, void *v)
+ {
+-      char *out = page;
+-      int len;
+-      rndis_params *param = (rndis_params *) data;
++      rndis_params *param = m->private;
+-      out += snprintf (out, count,
++      seq_printf(m,
+                        "Config Nr. %d\n"
+                        "used      : %s\n"
+                        "state     : %s\n"
+@@ -1326,25 +1076,13 @@ static int rndis_proc_read (char *page, char **start, off_t off, int count, int
+                        (param->media_state) ? 0 : param->speed*100,
+                        (param->media_state) ? "disconnected" : "connected",
+                        param->vendorID, param->vendorDescr);
+-
+-      len = out - page;
+-      len -= off;
+-
+-      if (len < count) {
+-              *eof = 1;
+-              if (len <= 0)
+-                      return 0;
+-      } else
+-              len = count;
+-
+-      *start = page + off;
+-      return len;
++      return 0;
+ }
+-static int rndis_proc_write (struct file *file, const char __user *buffer,
+-              unsigned long count, void *data)
++static ssize_t rndis_proc_write(struct file *file, const char __user *buffer,
++              size_t count, loff_t *ppos)
+ {
+-      rndis_params *p = data;
++      rndis_params *p = PDE(file->f_path.dentry->d_inode)->data;
+       u32 speed = 0;
+       int i, fl_speed = 0;
+@@ -1386,6 +1124,20 @@ static int rndis_proc_write (struct file *file, const char __user *buffer,
+       return count;
+ }
++static int rndis_proc_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, rndis_proc_show, PDE(inode)->data);
++}
++
++static const struct file_operations rndis_proc_fops = {
++      .owner          = THIS_MODULE,
++      .open           = rndis_proc_open,
++      .read           = seq_read,
++      .llseek         = seq_lseek,
++      .release        = single_release,
++      .write          = rndis_proc_write,
++};
++
+ #define       NAME_TEMPLATE   "driver/rndis-%03d"
+ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
+@@ -1403,7 +1155,9 @@ int __init rndis_init (void)
+               sprintf (name, NAME_TEMPLATE, i);
+               if (!(rndis_connect_state [i]
+-                              = create_proc_entry (name, 0660, NULL)))
++                              = proc_create_data(name, 0660, NULL,
++                                      &rndis_proc_fops,
++                                      (void *)(rndis_per_dev_params + i))))
+               {
+                       DBG("%s :remove entries", __func__);
+                       while (i) {
+@@ -1413,11 +1167,6 @@ int __init rndis_init (void)
+                       DBG("\n");
+                       return -EIO;
+               }
+-
+-              rndis_connect_state [i]->write_proc = rndis_proc_write;
+-              rndis_connect_state [i]->read_proc = rndis_proc_read;
+-              rndis_connect_state [i]->data = (void *)
+-                              (rndis_per_dev_params + i);
+ #endif
+               rndis_per_dev_params [i].confignr = i;
+               rndis_per_dev_params [i].used = 0;
+diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
+index 397b149..aac61df 100644
+--- a/drivers/usb/gadget/rndis.h
++++ b/drivers/usb/gadget/rndis.h
+@@ -1,8 +1,6 @@
+ /*
+  * RNDIS      Definitions for Remote NDIS
+  *
+- * Version:   $Id: rndis.h,v 1.15 2004/03/25 21:33:46 robert Exp $
+- *
+  * Authors:   Benedikt Spranger, Pengutronix
+  *            Robert Schwebel, Pengutronix
+  *
+@@ -235,20 +233,19 @@ typedef struct rndis_params
+       const u8                *host_mac;
+       u16                     *filter;
+       struct net_device       *dev;
+-      struct net_device_stats *stats;
+       u32                     vendorID;
+       const char              *vendorDescr;
+-      int                     (*ack) (struct net_device *);
++      void                    (*resp_avail)(void *v);
++      void                    *v;
+       struct list_head        resp_queue;
+ } rndis_params;
+ /* RNDIS Message parser and other useless functions */
+ int  rndis_msg_parser (u8 configNr, u8 *buf);
+-int  rndis_register (int (*rndis_control_ack) (struct net_device *));
++int  rndis_register(void (*resp_avail)(void *v), void *v);
+ void rndis_deregister (int configNr);
+ int  rndis_set_param_dev (u8 configNr, struct net_device *dev,
+-                       struct net_device_stats *stats,
+                        u16 *cdc_filter);
+ int  rndis_set_param_vendor (u8 configNr, u32 vendorID,
+                           const char *vendorDescr);
+diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
+index 6b1ef48..29d13eb 100644
+--- a/drivers/usb/gadget/s3c2410_udc.c
++++ b/drivers/usb/gadget/s3c2410_udc.c
+@@ -35,7 +35,6 @@
+ #include <linux/list.h>
+ #include <linux/interrupt.h>
+ #include <linux/platform_device.h>
+-#include <linux/version.h>
+ #include <linux/clk.h>
+ #include <linux/debugfs.h>
+@@ -49,15 +48,14 @@
+ #include <asm/irq.h>
+ #include <asm/system.h>
+ #include <asm/unaligned.h>
+-#include <asm/arch/irqs.h>
++#include <mach/irqs.h>
+-#include <asm/arch/hardware.h>
+-#include <asm/arch/regs-gpio.h>
++#include <mach/hardware.h>
++#include <mach/regs-gpio.h>
+ #include <asm/plat-s3c24xx/regs-udc.h>
+ #include <asm/plat-s3c24xx/udc.h>
+-#include <asm/mach-types.h>
+ #include "s3c2410_udc.h"
+@@ -888,7 +886,7 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
+       }
+ }
+-#include <asm/arch/regs-irq.h>
++#include <mach/regs-irq.h>
+ /*
+  *    s3c2410_udc_irq - interrupt handler
+diff --git a/drivers/usb/gadget/sa1100_udc.c b/drivers/usb/gadget/sa1100_udc.c
+new file mode 100644
+index 0000000..3a9f24f
+--- /dev/null
++++ b/drivers/usb/gadget/sa1100_udc.c
+@@ -0,0 +1,2421 @@
++/*
++ * SA1100 USB Device Controller (UDC) driver.
++ *
++ * Copyright (C) Compaq Computer Corporation, 1998, 1999
++ * Copyright (C) Extenex Corporation, 2001
++ * Copyright (C) David Brownell, 2003
++ * Copyright (C) Nick Bane, 2005, 2006, 2007
++ *   Many fragments from pxa2xx_udc.c and mach-sa1100 driver with various
++ *   GPL Copyright authors incl Russel king and Nicolas Pitre
++ *   Working port to 2.6.32-1 by N C Bane
++ *
++ * This file provides interrupt routing and overall coordination for the
++ * sa1100 USB endpoints: ep0, ep1out-bulk, ep2in-bulk, as well as device
++ * initialization and some parts of USB "Chapter 9" device behavior.
++ *
++ * It implements the "USB gadget controller" API, abstracting most hardware
++ * details so that drivers running on top of this API are mostly independent
++ * of hardware.  A key exception is that ep0 logic needs to understand which
++ * endpoints a given controller has, and their capabilities.  Also, hardware
++ * that doesn't fully support USB (like sa1100) may need workarounds in the
++ * protocols implemented by device functions.
++ *
++ * See linux/Documentation/arm/SA1100/SA1100_USB for more info, or the
++ * kerneldoc for the API exposed to gadget drivers.
++ *
++ */
++//#define DEBUG       1
++//#define     VERBOSE 1
++
++//#define SA1100_USB_DEBUG
++#ifdef SA1100_USB_DEBUG
++static int sa1100_usb_debug=0;
++#endif
++
++#define NCB_DMA_FIX
++#ifdef NCB_DMA_FIX
++// This is a clunky fix for dma alignemnt issues
++// It should probably be done better by someone more 
++// steeped in DMA lore
++#include <linux/slab.h>
++#define SEND_BUFFER_SIZE 4096 /* this is probably a bit big */
++#define RECEIVE_BUFFER_SIZE 256       /* 64 may be all that is necessary */
++static char *send_buffer=NULL;
++static char *receive_buffer=NULL;
++#endif
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/smp_lock.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/timer.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/version.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++
++#include <asm/byteorder.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/dma.h>
++#include <asm/system.h>
++#include <asm/mach-types.h>
++#include <asm/unaligned.h>
++
++#include <linux/usb.h>
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++#if CONFIG_PROC_FS
++#include <linux/proc_fs.h>
++#endif
++
++#if defined(CONFIG_SA1100_BALLOON)
++#include <asm/arch/balloon2.h>
++#endif
++
++#if defined(CONFIG_SA1100_COLLIE)
++#include <asm/hardware/scoop.h>
++#include <asm/arch/collie.h>
++#endif
++
++#define       DRIVER_VERSION          __DATE__
++
++#define       DMA_ADDR_INVALID (~(dma_addr_t)0)
++
++
++static const char driver_name [] = "sa1100_udc";
++static const char driver_desc [] = "SA-1110 USB Device Controller";
++
++static const char ep0name [] = "ep0";
++
++#ifdef        DEBUG
++static char *type_string (u8 bmAttributes)
++{
++      switch ( (bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) {
++      case USB_ENDPOINT_XFER_BULK:    return "bulk";
++      //case USB_ENDPOINT_XFER_ISOC:  return "iso";
++      case USB_ENDPOINT_XFER_INT:     return "intr";
++      };
++      return "control";
++}
++#endif
++
++#include <linux/dma-mapping.h>
++struct usb_stats_t {
++       unsigned long ep0_fifo_write_failures;
++       unsigned long ep0_bytes_written;
++       unsigned long ep0_fifo_read_failures;
++       unsigned long ep0_bytes_read;
++};
++
++struct usb_info_t {
++      dma_regs_t *dmaregs_tx, *dmaregs_rx;
++      int state;
++      unsigned char address;
++      struct usb_stats_t stats;
++};
++
++enum { kError=-1, kEvSuspend=0, kEvReset=1,
++         kEvResume=2, kEvAddress=3, kEvConfig=4, kEvDeConfig=5 };
++int usbctl_next_state_on_event( int event ) {
++    return 0;
++}
++static struct usb_info_t usbd_info;
++
++/* receiver */
++void ep1_reset(void);
++void ep1_stall(void);
++int sa1100_usb_recv (struct usb_request *req, void (*callback) (int,int));
++
++/* xmitter */
++void ep2_reset(void);
++void ep2_stall(void);
++int sa1100_usb_send (struct usb_request *req, void (*callback) (int,int));
++
++/* UDC register utility functions */
++#define UDC_write(reg, val) { \
++      int i = 10000; \
++      do { \
++              (reg) = (val); \
++              if (i-- <= 0) { \
++                      printk( "%s [%d]: write %#x to %p (%#lx) failed\n", \
++                              __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++                      break; \
++              } \
++      } while((reg) != (val)); \
++}
++
++#define UDC_set(reg, val) { \
++      int i = 10000; \
++      do { \
++              (reg) |= (val); \
++              if (i-- <= 0) { \
++                      printk( "%s [%d]: set %#x of %p (%#lx) failed\n", \
++                              __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++                      break; \
++              } \
++      } while(!((reg) & (val))); \
++}
++
++#define UDC_clear(reg, val) { \
++      int i = 10000; \
++      do { \
++              (reg) &= ~(val); \
++              if (i-- <= 0) { \
++                      printk( "%s [%d]: clear %#x of %p (%#lx) failed\n", \
++                              __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++                      break; \
++              } \
++      } while((reg) & (val)); \
++}
++
++#define UDC_flip(reg, val) { \
++      int i = 10000; \
++      (reg) = (val); \
++      do { \
++              (reg) = (val); \
++              if (i-- <= 0) { \
++                      printk( "%s [%d]: flip %#x of %p (%#lx) failed\n", \
++                              __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++                      break; \
++              } \
++      } while(((reg) & (val))); \
++}
++
++#include "sa1100_udc.h"
++
++static struct sa1100_udc      *the_controller;
++static void nuke (struct sa1100_ep *, int status);
++static void done (struct sa1100_ep *ep, struct sa1100_request *req, int status);
++static inline void ep0_idle (struct sa1100_udc *dev)
++{
++      dev->ep0state = EP0_IDLE;
++}
++
++// ep0 handlers
++
++// 1 == lots of trace noise,  0 = only "important' stuff
++#define VERBOSITY 0
++
++#if 1 && !defined( ASSERT )
++#  define ASSERT(expr) \
++          if(!(expr)) { \
++          printk( "Assertion failed! %s,%s,%s,line=%d\n",\
++          #expr,__FILE__,__FUNCTION__,__LINE__); \
++          }
++#else
++#  define ASSERT(expr)
++#endif
++
++#if VERBOSITY
++#define PRINTKD(fmt, args...) printk( fmt , ## args)
++#else
++#define PRINTKD(fmt, args...)
++#endif
++
++/* other subroutines */
++unsigned int (*wrint)(void);
++void ep0_int_hndlr( void );
++static void ep0_queue(void *buf, unsigned int req, unsigned int act);
++static void write_fifo( void );
++static int read_fifo( struct usb_ctrlrequest * p );
++
++/* some voodo helpers  01Mar01ww */
++static void set_cs_bits( __u32 set_bits );
++static void set_de( void );
++static void set_ipr( void );
++static void set_ipr_and_de( void );
++static bool clear_opr( void );
++
++/***************************************************************************
++Inline Helpers
++***************************************************************************/
++
++/* Data extraction from usb_request_t fields */
++enum { kTargetDevice=0, kTargetInterface=1, kTargetEndpoint=2 };
++static inline int request_target( __u8 b ) { return (int) ( b & 0x0F); }
++
++static inline int windex_to_ep_num( __u16 w ) { return (int) ( w & 0x000F); }
++inline int type_code_from_request( __u8 by ) { return (( by >> 4 ) & 3); }
++
++/* following is hook for self-powered flag in GET_STATUS. Some devices
++   .. might like to override and return real info */
++static inline bool self_powered_hook( void ) { return true; }
++
++#if VERBOSITY
++/* "pcs" == "print control status" */
++static inline void pcs( void )
++{
++       __u32 foo = Ser0UDCCS0;
++       printk( "%8.8X: %s %s %s %s\n",
++                       foo,
++                       foo & UDCCS0_SE ? "SE" : "",
++                       foo & UDCCS0_OPR ? "OPR" : "",
++                       foo & UDCCS0_IPR ? "IPR" : "",
++                       foo & UDCCS0_SST ? "SST" : ""
++       );
++}
++static inline void preq( struct usb_ctrlrequest * pReq )
++{
++       static char * tnames[] = { "dev", "intf", "ep", "oth" };
++       static char * rnames[] = { "std", "class", "vendor", "???" };
++       char * psz;
++       switch( pReq->bRequest ) {
++       case USB_REQ_GET_STATUS: psz = "get stat"; break;
++       case USB_REQ_CLEAR_FEATURE: psz = "clr feat"; break;
++       case USB_REQ_SET_FEATURE: psz = "set feat"; break;
++       case USB_REQ_SET_ADDRESS: psz = "set addr"; break;
++       case USB_REQ_GET_DESCRIPTOR: psz = "get desc"; break;
++       case USB_REQ_SET_DESCRIPTOR: psz = "set desc"; break;
++       case USB_REQ_GET_CONFIGURATION: psz = "get cfg"; break;
++       case USB_REQ_SET_CONFIGURATION: psz = "set cfg"; break;
++       case USB_REQ_GET_INTERFACE: psz = "get intf"; break;
++       case USB_REQ_SET_INTERFACE: psz = "set intf"; break;
++       default: psz = "unknown"; break;
++       }
++       printk( "- [%s: %s req to %s. dir=%s]\n", psz,
++                       rnames[ (pReq->bRequestType >> 5) & 3 ],
++                       tnames[ pReq->bRequestType & 3 ],
++                       ( pReq->bRequestType & 0x80 ) ? "in" : "out" );
++}
++
++static inline void usbctl_dump_request(const char *prefix, const struct usb_ctrlrequest *req)
++{
++      printk("%s: bRequestType=0x%02x bRequest=0x%02x "
++              "wValue=0x%04x wIndex=0x%04x wLength=0x%04x\n",
++              prefix, req->bRequestType, req->bRequest,
++              le16_to_cpu(req->wValue), le16_to_cpu(req->wIndex),
++              le16_to_cpu(req->wLength));
++}
++#else
++static inline void pcs( void ){}
++//static inline void preq( void ){}
++static inline void preq( void *x ){}
++static inline void usbctl_dump_request(const char *prefix, const struct usb_ctrlrequest *req) {}
++#endif
++
++/***************************************************************************
++Globals
++***************************************************************************/
++static const char pszMe[] = "usbep0: ";
++
++
++/* global write struct to keep write
++   ..state around across interrupts */
++static struct {
++              unsigned char *p;
++              int bytes_left;
++} wr;
++
++/***************************************************************************
++Public Interface
++***************************************************************************/
++
++/* reset received from HUB (or controller just went nuts and reset by itself!)
++  so udc core has been reset, track this state here  */
++void ep0_reset(void)
++{
++      /* reset state machine */
++      wr.p = NULL;
++      wr.bytes_left = 0;
++      usbd_info.address=0;
++// needed?
++      Ser0UDCAR = 0;
++}
++
++
++/* handle interrupt for endpoint zero */
++
++inline void ep0_clear_write(void) {
++      wr.p = NULL;
++      wr.bytes_left = 0;
++}
++
++/* this is a config packet parser based on that from the updated HH 2.6 udc */
++static void ep0_read_packet(void)
++{
++       unsigned char status_buf[2];  /* returned in GET_STATUS */
++       struct usb_ctrlrequest req;
++       int request_type;
++       int n;
++       __u32 address;
++       __u32 in, out;
++
++       /* reset previous count */
++       the_controller->ep0_req_len=-1;
++
++       /* read the setup request */
++       n = read_fifo( &req );
++       usbctl_dump_request("ep0_read_packet",&req);
++
++       if ( n != sizeof( req ) ) {
++                printk( "%ssetup begin: fifo READ ERROR wanted %d bytes got %d. "
++                                " Stalling out...\n",
++                                pszMe, sizeof( req ), n );
++                /* force stall, serviced out */
++                set_cs_bits( UDCCS0_FST | UDCCS0_SO  );
++                goto sh_sb_end;
++       }
++
++       /* Is it a standard request? (not vendor or class request) */
++       request_type = type_code_from_request( req.bRequestType );
++       if ( request_type != 0 ) {
++                printk( "%ssetup begin: unsupported bRequestType: %d ignored\n",
++                                pszMe, request_type );
++                set_cs_bits( UDCCS0_DE | UDCCS0_SO );
++                goto sh_sb_end;
++       }
++
++      /* save requested reply size */
++      the_controller->ep0_req_len=le16_to_cpu(req.wLength);
++      PRINTKD("%s: request length is %d\n",__FUNCTION__,the_controller->ep0_req_len);
++
++#if VERBOSITY
++       {
++       unsigned char * pdb = (unsigned char *) &req;
++       PRINTKD( "%2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X ",
++                       pdb[0], pdb[1], pdb[2], pdb[3], pdb[4], pdb[5], pdb[6], pdb[7]
++                );
++       preq( &req );
++       }
++#endif
++
++       /* Handle it */
++       switch( req.bRequest ) {
++
++                /* This first bunch have no data phase */
++
++       case USB_REQ_SET_ADDRESS:
++                address = (__u32) (req.wValue & 0x7F);
++                /* when SO and DE sent, UDC will enter status phase and ack,
++                       ..propagating new address to udc core. Next control transfer
++                       ..will be on the new address. You can't see the change in a
++                       ..read back of CAR until then. (about 250us later, on my box).
++                       ..The original Intel driver sets S0 and DE and code to check
++                       ..that address has propagated here. I tried this, but it
++                       ..would only work sometimes! The rest of the time it would
++                       ..never propagate and we'd spin forever. So now I just set
++                       ..it and pray...
++                */
++                Ser0UDCAR = address;
++                usbd_info.address = address;
++                usbctl_next_state_on_event( kEvAddress );
++                set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++                printk( "%sI have been assigned address: %d\n", pszMe, address );
++                break;
++
++
++       case USB_REQ_SET_CONFIGURATION:
++                if ( req.wValue == 1 ) {
++                         /* configured */
++                         if (usbctl_next_state_on_event( kEvConfig ) != kError) {
++                              /* (re)set the out and in max packet sizes */
++                              PRINTKD( "%s: calling the_controller.driver->setup with SET_CONFIGURATION\n", __FUNCTION__ );
++                              the_controller->driver->setup(&the_controller->gadget, &req);
++                                      in  = __le16_to_cpu( the_controller->ep[1].ep.maxpacket );
++                                      out = __le16_to_cpu( the_controller->ep[2].ep.maxpacket );
++                                      Ser0UDCOMP = ( out - 1 );
++                                      Ser0UDCIMP = ( in - 1 );
++                              // we are configured
++                              usbd_info.state = USB_STATE_CONFIGURED;
++                              // enable rx and tx interrupts
++                              Ser0UDCCR &= ~(UDCCR_RIM | UDCCR_TIM);
++
++                              printk( "%sConfigured (OMP=%8.8X IMP=%8.8X)\n", pszMe, out, in );
++                              break;
++                         }
++                } else if ( req.wValue == 0 ) {
++                         /* de-configured */
++                         if (usbctl_next_state_on_event( kEvDeConfig ) != kError )
++                                      printk( "%sDe-Configured\n", pszMe );
++                      usbd_info.state = 0;
++                      Ser0UDCCR |= UDCCR_RIM | UDCCR_TIM;
++                      ep1_reset ();
++                      ep2_reset ();
++                      printk("%s: de-configured. Tx and Rx interrupts disabled. ep1 and ep2 reset\n",__FUNCTION__);
++                } else {
++                         printk( "%ssetup phase: Unknown "
++                                         "\"set configuration\" data %d\n",
++                                         pszMe, req.wValue );
++                }
++                set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++                break;
++
++       case USB_REQ_CLEAR_FEATURE:
++                /* could check data length, direction...26Jan01ww */
++                if ( req.wValue == 0 ) { /* clearing ENDPOINT_HALT/STALL */
++                         int ep = windex_to_ep_num( req.wIndex );
++                         if ( ep == 1 ) {
++                                      printk( "%sclear feature \"endpoint halt\" "
++                                                      " on receiver\n", pszMe );
++                                      ep1_reset();
++                         }
++                         else if ( ep == 2 ) {
++                                      printk( "%sclear feature \"endpoint halt\" "
++                                                      "on xmitter\n", pszMe );
++                                      ep2_reset();
++                         } else {
++                                      printk( "%sclear feature \"endpoint halt\" "
++                                                      "on unsupported ep # %d\n",
++                                                      pszMe, ep );
++                         }
++                } else {
++                         printk( "%sUnsupported feature selector (%d) "
++                                         "in clear feature. Ignored.\n" ,
++                                         pszMe, req.wValue );
++                }
++                set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++                break;
++
++       case USB_REQ_SET_FEATURE:
++                if ( req.wValue == 0 ) { /* setting ENDPOINT_HALT/STALL */
++                         int ep = windex_to_ep_num( req.wValue );
++                         if ( ep == 1 ) {
++                                      printk( "%set feature \"endpoint halt\" "
++                                                      "on receiver\n", pszMe );
++                                      ep1_stall();
++                         }
++                         else if ( ep == 2 ) {
++                                      printk( "%sset feature \"endpoint halt\" "
++                                                      " on xmitter\n", pszMe );
++                                      ep2_stall();
++                         } else {
++                                      printk( "%sset feature \"endpoint halt\" "
++                                                      "on unsupported ep # %d\n",
++                                                      pszMe, ep );
++                         }
++                }
++                else {
++                         printk( "%sUnsupported feature selector "
++                                         "(%d) in set feature\n",
++                                         pszMe, req.wValue );
++                }
++                set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++                break;
++
++                /* The rest have a data phase that writes back to the host */
++       case USB_REQ_GET_STATUS:
++                /* return status bit flags */
++                status_buf[0] = status_buf[1] = 0;
++                n = request_target(req.bRequestType);
++                switch( n ) {
++                case kTargetDevice:
++                         if ( self_powered_hook() )
++                                      status_buf[0] |= 1;
++                         break;
++                case kTargetInterface:
++                         break;
++                case kTargetEndpoint:
++                         /* return stalled bit */
++                         n = windex_to_ep_num( req.wIndex );
++                         if ( n == 1 )
++                                      status_buf[0] |= (Ser0UDCCS1 & UDCCS1_FST) >> 4;
++                         else if ( n == 2 )
++                                      status_buf[0] |= (Ser0UDCCS2 & UDCCS2_FST) >> 5;
++                         else {
++                                      printk( "%sUnknown endpoint (%d) "
++                                                      "in GET_STATUS\n", pszMe, n );
++                         }
++                         break;
++                default:
++                         printk( "%sUnknown target (%d) in GET_STATUS\n",
++                                         pszMe, n );
++                         /* fall thru */
++                         break;
++                }
++                PRINTKD("%s: GET_STATUS writing %d\n",__FUNCTION__,req.wLength);
++                ep0_queue( status_buf, req.wLength, sizeof( status_buf ));
++                break;
++       case USB_REQ_GET_DESCRIPTOR:
++                PRINTKD( "%s: calling the_controller.driver->setup with GET_DESCRIPTOR\n", __FUNCTION__ );
++                the_controller->driver->setup(&the_controller->gadget, &req);
++                break;
++       case USB_REQ_GET_CONFIGURATION:
++                PRINTKD( "%s: calling the_controller.driver->setup with GET_CONFIGURATION\n", __FUNCTION__ );
++                the_controller->driver->setup(&the_controller->gadget, &req);
++                break;
++       case USB_REQ_GET_INTERFACE:
++                PRINTKD( "%s: calling the_controller->driver->setup with GET_INTERFACE\n", __FUNCTION__ );
++                the_controller->driver->setup(&the_controller->gadget, &req);
++                break;
++       case USB_REQ_SET_INTERFACE:
++                PRINTKD( "%s: calling the_controller->driver->setup with SET_INTERFACE\n", __FUNCTION__ );
++                the_controller->driver->setup(&the_controller->gadget, &req);
++                break;
++       default :
++                printk("%sunknown request 0x%x\n", pszMe, req.bRequest);
++                break;
++       } /* switch( bRequest ) */
++
++sh_sb_end:
++       return;
++
++}
++
++void ep0_int_hndlr(void)
++{
++      u32 cs_reg_in;
++
++      pcs();
++
++      cs_reg_in = Ser0UDCCS0;
++
++      /*
++       * If "setup end" has been set, the usb controller has terminated
++       * a setup transaction before we set DE. This happens during
++       * enumeration with some hosts. For example, the host will ask for
++       * our device descriptor and specify a return of 64 bytes. When we
++       * hand back the first 8, the host will know our max packet size
++       * and turn around and issue a new setup immediately. This causes
++       * the UDC to auto-ack the new setup and set SE. We must then
++       * "unload" (process) the new setup, which is what will happen
++       * after this preamble is finished executing.
++       */
++      if (cs_reg_in & UDCCS0_SE) {
++              PRINTKD("UDC: early termination of setup\n");
++
++              /*
++               * Clear setup end
++               */
++              set_cs_bits(UDCCS0_SSE);
++
++              /*
++               * Clear any pending write.
++               */
++              ep0_clear_write();
++      }
++
++      /*
++       * UDC sent a stall due to a protocol violation.
++       */
++      if (cs_reg_in & UDCCS0_SST) {
++              PRINTKD("UDC: write_preamble: UDC sent stall\n");
++
++              /*
++               * Clear sent stall
++               */
++              set_cs_bits(UDCCS0_SST);
++
++              /*
++               * Clear any pending write.
++               */
++              ep0_clear_write();
++      }
++
++      switch (cs_reg_in & (UDCCS0_OPR | UDCCS0_IPR)) {
++      case UDCCS0_OPR | UDCCS0_IPR:
++              PRINTKD("UDC: write_preamble: see OPR. Stopping write to "
++                      "handle new SETUP\n");
++
++              /*
++               * very rarely, you can get OPR and
++               * leftover IPR. Try to clear
++               */
++              UDC_clear(Ser0UDCCS0, UDCCS0_IPR);
++
++              /*
++               * Clear any pending write.
++               */
++              ep0_clear_write();
++
++              /*FALLTHROUGH*/
++      case UDCCS0_OPR:
++              /*
++               * A new setup request is pending.  Handle
++               * it. Note that we don't try to read a
++               * packet if SE was set and OPR is clear.
++               */
++              ep0_read_packet();
++              break;
++
++      case 0:
++              // if data pending ...
++              if (wr.p) {
++                      unsigned int cs_bits = 0;
++                      if (wr.bytes_left != 0) {
++                              /*
++                               * More data to go
++                               */
++                              write_fifo();
++                              // packet ready
++                              cs_bits |= UDCCS0_IPR;
++                      }
++
++                      if (wr.bytes_left == 0) {
++                              /*
++                               * All data sent.
++                               */
++                              cs_bits |= wrint();
++                              // a null packet may be following
++                              if (!wrint)
++                                  ep0_clear_write();
++                      }
++                      set_cs_bits(cs_bits);
++              }
++              else
++                  PRINTKD("%s: No data - probably an ACK\n",__FUNCTION__);
++              break;
++
++      case UDCCS0_IPR:
++              PRINTKD("UDC: IPR set, not writing\n");
++              break;
++      }
++
++      pcs();
++      PRINTKD( "-end-\n" );
++}
++
++static unsigned int ep0_sh_write_data(void)
++{
++      /*
++       * If bytes left is zero, we are coming in on the
++       * interrupt after the last packet went out. And
++       * we know we don't have to empty packet this
++       * transfer so just set DE and we are done
++       */
++      PRINTKD("UDC: normal packet ended\n");
++      wrint=NULL;
++      return UDCCS0_DE;
++}
++
++static unsigned int ep0_sh_write_with_empty_packet(void)
++{
++      /*
++       * If bytes left is zero, we are coming in on the
++       * interrupt after the last packet went out.
++       * We must do short packet suff, so set DE and IPR
++       */
++      PRINTKD("UDC: short packet sent\n");
++      wrint=NULL;
++      return UDCCS0_IPR | UDCCS0_DE;
++}
++
++static unsigned int ep0_sh_write_data_then_empty_packet(void)
++{
++      PRINTKD("UDC: last packet full. Send empty packet next\n");
++      wrint=ep0_sh_write_with_empty_packet;
++      return 0;
++}
++
++static void ep0_queue(void *buf, unsigned int len, unsigned int req_len)
++{
++      __u32 cs_reg_bits = UDCCS0_IPR;
++
++      PRINTKD("a=%d r=%d\n", len, req_len);
++
++      if (len == 0) {
++          // no output packet to wait for
++          PRINTKD("%s: zero byte packet being queued. Setting DE and OPR end exiting\n",__FUNCTION__);
++          set_cs_bits(UDCCS0_DE | UDCCS0_SO);
++          return;
++      }
++
++      /*
++       * thou shalt not enter data phase until
++       * Out Packet Ready is clear
++       */
++      if (!clear_opr()) {
++              printk("UDC: SO did not clear OPR\n");
++              set_cs_bits(UDCCS0_DE | UDCCS0_SO);
++              return;
++      }
++
++      // note data to xmit stored
++      wr.p=buf;
++      wr.bytes_left=min(len, req_len);
++
++      // write the first block
++      write_fifo();
++
++      // done already?
++      if (wr.bytes_left == 0) {
++              /*
++               * out in one, so data end
++               */
++              cs_reg_bits |= UDCCS0_DE;
++              ep0_clear_write();
++      // rest is a shorter than expected reply?
++      } else if (len < req_len) {
++              /*
++               * we are going to short-change host
++               * so need nul to not stall
++               */
++               if (len % 8) {
++                  PRINTKD("%s: %d more to go ending in a short packet.\n",__FUNCTION__,wr.bytes_left);
++                  wrint=ep0_sh_write_with_empty_packet;
++              }
++              // unless we are on a packet boundary. Then send full packet plus null packet.
++              else {
++                  PRINTKD("%s: %d more to go then add empty packet.\n",__FUNCTION__,wr.bytes_left);
++                  wrint=ep0_sh_write_data_then_empty_packet;
++              }
++      } else {
++              /*
++               * we have as much or more than requested
++               */
++              PRINTKD("%s: %d more to go.\n",__FUNCTION__,wr.bytes_left);
++              wrint=ep0_sh_write_data;
++      }
++
++      /*
++       * note: IPR was set uncondtionally at start of routine
++       */
++      set_cs_bits(cs_reg_bits);
++}
++
++/*
++ * write_fifo()
++ * Stick bytes in the 8 bytes endpoint zero FIFO.
++ * This version uses a variety of tricks to make sure the bytes
++ * are written correctly. 1. The count register is checked to
++ * see if the byte went in, and the write is attempted again
++ * if not. 2. An overall counter is used to break out so we
++ * don't hang in those (rare) cases where the UDC reverses
++ * direction of the FIFO underneath us without notification
++ * (in response to host aborting a setup transaction early).
++ *
++ */
++static void write_fifo( void )
++{
++      int bytes_this_time = min(wr.bytes_left, 8);
++      int bytes_written = 0;
++
++      PRINTKD( "WF=%d: ", bytes_this_time );
++
++      while( bytes_this_time-- ) {
++              unsigned int cwc;
++              int i;
++               PRINTKD( "%2.2X ", *wr.p );
++              cwc = Ser0UDCWC & 15;
++               i = 10;
++               do {
++                        Ser0UDCD0 = *wr.p;
++                        udelay( 20 );  /* voodo 28Feb01ww */
++               } while( (Ser0UDCWC &15) == cwc && --i );
++
++               if ( i == 0 ) {
++                        printk( "%swrite_fifo: write failure\n", pszMe );
++                        usbd_info.stats.ep0_fifo_write_failures++;
++               }
++
++               wr.p++;
++               bytes_written++;
++      }
++      wr.bytes_left -= bytes_written;
++
++      /* following propagation voodo so maybe caller writing IPR in
++         ..a moment might actually get it to stick 28Feb01ww */
++      udelay( 300 );
++
++      usbd_info.stats.ep0_bytes_written += bytes_written;
++      PRINTKD( "L=%d WCR=%8.8lX\n", wr.bytes_left, Ser0UDCWC );
++}
++/*
++ * read_fifo()
++ * Read 1-8 bytes out of FIFO and put in request.
++ * Called to do the initial read of setup requests
++ * from the host. Return number of bytes read.
++ *
++ * Like write fifo above, this driver uses multiple
++ * reads checked agains the count register with an
++ * overall timeout.
++ *
++ */
++static int
++read_fifo( struct usb_ctrlrequest * request )
++{
++      int bytes_read = 0;
++      int fifo_count;
++
++      unsigned char * pOut = (unsigned char*) request;
++
++      fifo_count = ( Ser0UDCWC & 0xFF );
++
++      ASSERT( fifo_count <= 8 );
++      PRINTKD( "RF=%d ", fifo_count );
++
++      while( fifo_count-- ) {
++              unsigned int cwc;
++              int i;
++
++              cwc = Ser0UDCWC & 15;
++
++               i = 10;
++               do {
++                        *pOut = (unsigned char) Ser0UDCD0;
++                        udelay( 20 );
++               } while( ( Ser0UDCWC & 15 ) == cwc && --i );
++
++               if ( i == 0 ) {
++                        printk( "%sread_fifo(): read failure\n", pszMe );
++                        usbd_info.stats.ep0_fifo_read_failures++;
++               }
++               pOut++;
++               bytes_read++;
++      }
++
++      PRINTKD( "fc=%d\n", bytes_read );
++      usbd_info.stats.ep0_bytes_read++;
++      return bytes_read;
++}
++
++/* some voodo I am adding, since the vanilla macros just aren't doing it  1Mar01ww */
++
++#define ABORT_BITS ( UDCCS0_SST | UDCCS0_SE )
++#define OK_TO_WRITE (!( Ser0UDCCS0 & ABORT_BITS ))
++#define BOTH_BITS (UDCCS0_IPR | UDCCS0_DE)
++
++static void set_cs_bits( __u32 bits )
++{
++       if ( bits & ( UDCCS0_SO | UDCCS0_SSE | UDCCS0_FST | UDCCS0_SST) )
++                Ser0UDCCS0 = bits;
++       else if ( (bits & BOTH_BITS) == BOTH_BITS )
++                set_ipr_and_de();
++       else if ( bits & UDCCS0_IPR )
++                set_ipr();
++       else if ( bits & UDCCS0_DE )
++                set_de();
++}
++
++static void set_de( void )
++{
++       int i = 1;
++       while( 1 ) {
++                if ( OK_TO_WRITE ) {
++                              Ser0UDCCS0 |= UDCCS0_DE;
++                } else {
++                         PRINTKD( "%sQuitting set DE because SST or SE set\n", pszMe );
++                         break;
++                }
++                if ( Ser0UDCCS0 & UDCCS0_DE )
++                         break;
++                udelay( i );
++                if ( ++i == 50  ) {
++                         printk( "%sDangnabbbit! Cannot set DE! (DE=%8.8X CCS0=%8.8lX)\n",
++                                         pszMe, UDCCS0_DE, Ser0UDCCS0 );
++                         break;
++                }
++       }
++}
++
++static void set_ipr( void )
++{
++       int i = 1;
++       while( 1 ) {
++                if ( OK_TO_WRITE ) {
++                              Ser0UDCCS0 |= UDCCS0_IPR;
++                } else {
++                         PRINTKD( "%sQuitting set IPR because SST or SE set\n", pszMe );
++                         break;
++                }
++                if ( Ser0UDCCS0 & UDCCS0_IPR )
++                         break;
++                udelay( i );
++                if ( ++i == 50  ) {
++                         printk( "%sDangnabbbit! Cannot set IPR! (IPR=%8.8X CCS0=%8.8lX)\n",
++                                         pszMe, UDCCS0_IPR, Ser0UDCCS0 );
++                         break;
++                }
++       }
++}
++
++static void set_ipr_and_de( void )
++{
++       int i = 1;
++       while( 1 ) {
++                if ( OK_TO_WRITE ) {
++                         Ser0UDCCS0 |= BOTH_BITS;
++                } else {
++                         PRINTKD( "%sQuitting set IPR/DE because SST or SE set\n", pszMe );
++                         break;
++                }
++                if ( (Ser0UDCCS0 & BOTH_BITS) == BOTH_BITS)
++                         break;
++                udelay( i );
++                if ( ++i == 50  ) {
++                         printk( "%sDangnabbbit! Cannot set DE/IPR! (DE=%8.8X IPR=%8.8X CCS0=%8.8lX)\n",
++                                         pszMe, UDCCS0_DE, UDCCS0_IPR, Ser0UDCCS0 );
++                         break;
++                }
++       }
++}
++
++static bool clear_opr( void )
++{
++       int i = 10000;
++       bool is_clear;
++       do {
++                Ser0UDCCS0 = UDCCS0_SO;
++                is_clear  = ! ( Ser0UDCCS0 & UDCCS0_OPR );
++                if ( i-- <= 0 ) {
++                         printk( "%sclear_opr(): failed\n", pszMe );
++                         break;
++                }
++       } while( ! is_clear );
++       return is_clear;
++}
++
++
++
++// ep1 handlers
++
++static char *ep1_buf;
++static int ep1_len;
++static void (*ep1_callback)(int flag, int size);
++static char *ep1_curdmabuf;
++static dma_addr_t ep1_curdmapos;
++static int ep1_curdmalen;
++static int ep1_remain;
++static int ep1_used;
++
++static dma_regs_t *dmaregs_rx = NULL;
++static int rx_pktsize;
++
++static int naking;
++
++static void
++ep1_start(void)
++{
++      sa1100_reset_dma(dmaregs_rx);
++      if (!ep1_curdmalen) {
++              ep1_curdmalen = rx_pktsize;
++              if (ep1_curdmalen > ep1_remain)
++                      ep1_curdmalen = ep1_remain;
++              ep1_curdmapos = dma_map_single(NULL, ep1_curdmabuf, ep1_curdmalen,
++                                             DMA_FROM_DEVICE);
++      }
++
++      UDC_write( Ser0UDCOMP, ep1_curdmalen-1 );
++
++      sa1100_start_dma(dmaregs_rx, ep1_curdmapos, ep1_curdmalen);
++
++      if ( naking ) {
++              /* turn off NAK of OUT packets, if set */
++              UDC_flip( Ser0UDCCS1, UDCCS1_RPC );
++              naking = 0;
++      }
++}
++
++static void
++ep1_done(int flag)
++{
++      int size = ep1_len - ep1_remain;
++
++      if (!ep1_len)
++              return;
++      if (ep1_curdmalen)
++              dma_unmap_single(NULL, ep1_curdmapos, ep1_curdmalen,
++                               DMA_FROM_DEVICE);
++      ep1_len = ep1_curdmalen = 0;
++      if (ep1_callback)
++              ep1_callback(flag, size);
++}
++
++void
++ep1_state_change_notify( int new_state )
++{
++
++}
++
++void
++ep1_stall( void )
++{
++      /* SET_FEATURE force stall at UDC */
++      UDC_set( Ser0UDCCS1, UDCCS1_FST );
++}
++
++int
++ep1_init(dma_regs_t *dmaregs)
++{
++      dmaregs_rx = dmaregs;
++      sa1100_reset_dma(dmaregs_rx);
++      ep1_done(-EAGAIN);
++      return 0;
++}
++
++void
++ep1_reset(void)
++{
++      if (dmaregs_rx)
++          sa1100_reset_dma(dmaregs_rx);
++      UDC_clear(Ser0UDCCS1, UDCCS1_FST);
++      ep1_done(-EINTR);
++}
++
++void ep1_int_hndlr(int udcsr)
++{
++      dma_addr_t dma_addr;
++      unsigned int len;
++      int status = Ser0UDCCS1;
++
++      if ( naking ) printk( "%sEh? in ISR but naking = %d\n", "usbrx: ", naking );
++
++      if (status & UDCCS1_RPC) {
++
++              if (!ep1_curdmalen) {
++                      printk("usb_recv: RPC for non-existent buffer\n");
++                      naking=1;
++                      return;
++              }
++
++              sa1100_stop_dma(dmaregs_rx);
++
++              if (status & UDCCS1_SST) {
++                      printk("usb_recv: stall sent OMP=%ld\n", Ser0UDCOMP);
++                      UDC_flip(Ser0UDCCS1, UDCCS1_SST);
++                      ep1_done(-EIO); // UDC aborted current transfer, so we do
++                      return;
++              }
++
++              if (status & UDCCS1_RPE) {
++                      printk("usb_recv: RPError %x\n", status);
++                      UDC_flip(Ser0UDCCS1, UDCCS1_RPC);
++                      ep1_done(-EIO);
++                      return;
++              }
++
++              dma_addr=sa1100_get_dma_pos(dmaregs_rx);
++              dma_unmap_single(NULL, ep1_curdmapos, ep1_curdmalen,
++                               DMA_FROM_DEVICE);
++              len = dma_addr - ep1_curdmapos;
++#ifdef SA1100_USB_DEBUG
++              if (sa1100_usb_debug) {
++                  int i;
++                  printk("usb rx %d :\n  ",len);
++                  if (sa1100_usb_debug>1) {
++                              for (i=0; i<len; i++) {
++                              if ((i % 32)==31)
++                                      printk("\n  ");
++                              printk("%2.2x ",((char *)ep1_curdmapos)[i]);
++                              }
++                  }
++                  printk("\n");
++              }
++#endif
++              if (len < ep1_curdmalen) {
++                      char *buf = ep1_curdmabuf + len;
++                      while (Ser0UDCCS1 & UDCCS1_RNE) {
++                              if (len >= ep1_curdmalen) {
++                                      printk("usb_recv: too much data in fifo\n");
++                                      break;
++                              }
++                              *buf++ = Ser0UDCDR;
++                              len++;
++                      }
++              } else if (Ser0UDCCS1 & UDCCS1_RNE) {
++                      printk("usb_recv: fifo screwed, shouldn't contain data\n");
++                      len = 0;
++              }
++
++#if defined(NCB_DMA_FIX)
++//            if (len && (ep1_buf != ep1_curdmabuf))
++//                memcpy(ep1_buf,ep1_curdmabuf,len);
++              if (len)
++                  memcpy(&(((unsigned char *)ep1_buf)[ep1_used]),ep1_curdmabuf,len);
++#endif
++
++              ep1_curdmalen = 0;  /* dma unmap already done */
++              ep1_remain -= len;
++              ep1_used += len;
++//            ep1_curdmabuf += len;   // use same buffer again
++              naking = 1;
++//printk("%s: received %d, %d remaining\n",__FUNCTION__,len,ep1_remain);
++              if (len && (len == rx_pktsize))
++                  ep1_start();
++              else
++              ep1_done((len) ? 0 : -EPIPE);
++      }
++      /* else, you can get here if we are holding NAK */
++}
++
++int
++sa1100_usb_recv(struct usb_request *req, void (*callback)(int flag, int size))
++{
++      unsigned long flags;
++      char *buf=req->buf;
++      int len=req->length;
++
++      if (ep1_len)
++              return -EBUSY;
++
++      local_irq_save(flags);
++      ep1_buf = buf;
++      ep1_len = len;
++      ep1_callback = callback;
++      ep1_remain = len;
++      ep1_used = 0;
++#ifdef NCB_DMA_FIX
++//    if (((size_t)buf)&3)
++      if (1)
++          ep1_curdmabuf = receive_buffer;
++      else
++#else
++      ep1_curdmabuf = buf;
++#endif
++      ep1_curdmalen = 0;
++      ep1_start();
++      local_irq_restore(flags);
++
++      return 0;
++}
++
++// ep2 handlers
++
++static char *ep2_buf;
++static int ep2_len;
++static void (*ep2_callback)(int status, int size);
++static dma_addr_t ep2_dma;
++static dma_addr_t ep2_curdmapos;
++static int ep2_curdmalen;
++static int ep2_remain;
++static dma_regs_t *dmaregs_tx = NULL;
++static int tx_pktsize;
++
++/* device state is changing, async */
++void
++ep2_state_change_notify( int new_state )
++{
++}
++
++/* set feature stall executing, async */
++void
++ep2_stall( void )
++{
++      UDC_set( Ser0UDCCS2, UDCCS2_FST );  /* force stall at UDC */
++}
++
++static void
++ep2_start(void)
++{
++      if (!ep2_len)
++              return;
++
++      ep2_curdmalen = tx_pktsize;
++      if (ep2_curdmalen > ep2_remain)
++              ep2_curdmalen = ep2_remain;
++
++      /* must do this _before_ queue buffer.. */
++      UDC_flip( Ser0UDCCS2,UDCCS2_TPC );  /* stop NAKing IN tokens */
++      UDC_write( Ser0UDCIMP, ep2_curdmalen-1 );
++
++      Ser0UDCAR = usbd_info.address; // fighting stupid silicon bug
++      sa1100_start_dma(dmaregs_tx, ep2_curdmapos, ep2_curdmalen);
++}
++
++static void
++ep2_done(int flag)
++{
++      int size = ep2_len - ep2_remain;
++      if (ep2_len) {
++              dma_unmap_single(NULL, ep2_dma, ep2_len, DMA_TO_DEVICE);
++              ep2_len = 0;
++              if (ep2_callback)
++                      ep2_callback(flag, size);
++      }
++}
++
++int ep2_init(dma_regs_t *dmaregs)
++{
++      dmaregs_tx = dmaregs;
++      sa1100_reset_dma(dmaregs_tx);
++      ep2_done(-EAGAIN);
++      return 0;
++}
++
++void ep2_reset(void)
++{
++      UDC_clear(Ser0UDCCS2, UDCCS2_FST);
++      if (dmaregs_tx)
++          sa1100_reset_dma(dmaregs_tx);
++      ep2_done(-EINTR);
++}
++
++void ep2_int_hndlr(int udcsr)
++{
++      int status = Ser0UDCCS2;
++
++      if (Ser0UDCAR != usbd_info.address) // check for stupid silicon bug.
++              Ser0UDCAR = usbd_info.address;
++
++      if (status & UDCCS2_TPC) {
++
++              UDC_flip(Ser0UDCCS2, UDCCS2_SST);
++
++              sa1100_reset_dma(dmaregs_tx);
++
++              if (status & (UDCCS2_TPE | UDCCS2_TUR)) {
++                      printk("usb_send: transmit error %x\n", status);
++                      ep2_done(-EIO);
++              } else {
++                      ep2_curdmapos += ep2_curdmalen;
++                      ep2_remain -= ep2_curdmalen;
++
++                      if (ep2_remain != 0)
++                              ep2_start();
++                      else
++                              ep2_done(0);
++              }
++      } else {
++              printk("usb_send: Not TPC: UDCCS2 = %x\n", status);
++      }
++}
++
++int
++sa1100_usb_send(struct usb_request *req, void (*callback)(int status, int size))
++{
++      char *buf=req->buf;
++      int len=req->length;
++      unsigned long flags;
++
++      if (usbd_info.state != USB_STATE_CONFIGURED) {
++              PRINTKD("%s: return -ENODEV\n",__FUNCTION__);
++              return -ENODEV;
++      }
++
++      if (ep2_len) {
++              PRINTKD("%s: return -EBUSY\n",__FUNCTION__);
++              return -EBUSY;
++      }
++
++      local_irq_save(flags);
++#ifdef NCB_DMA_FIX
++      // if misaligned, copy to aligned buffer
++//    if (((size_t)buf)&3) {
++      if (1) {
++          PRINTKD("%s: copying %d bytes to send_buffer\n",__FUNCTION__,len);
++          memcpy(send_buffer,buf,len);
++          ep2_buf = send_buffer;
++      }
++      else
++#endif
++      ep2_buf = buf;
++
++      ep2_len = len;
++      ep2_dma = dma_map_single(NULL, ep2_buf, len,DMA_TO_DEVICE);
++      PRINTKD("%s: mapped dma to buffer(%p0\n",__FUNCTION__,buf);
++
++      ep2_callback = callback;
++      ep2_remain = len;
++      ep2_curdmapos = ep2_dma;
++
++      PRINTKD("%s: calling ep2_start\n",__FUNCTION__);
++      ep2_start();
++      local_irq_restore(flags);
++
++      return 0;
++}
++/*-------------------------------------------------------------------------*/
++
++static int
++sa1100_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
++{
++      struct sa1100_udc       *dev;
++      struct sa1100_ep        *ep;
++      u32                     max;
++      int                     type;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (!_ep || !desc || ep->desc || _ep->name == ep0name
++                      || desc->bDescriptorType != USB_DT_ENDPOINT) {
++              PRINTKD("%s: _ep = %p, desc = %p\n",__FUNCTION__,_ep,desc);
++              if (_ep && desc)
++                  PRINTKD("%s: ep->desc = %p, _ep->name = %s desc->bDescriptorType = %s\n",__FUNCTION__,ep->desc,_ep->name,
++                      (desc->bDescriptorType == USB_DT_ENDPOINT) ? "USB_DT_ENDPOINT":"bad!!");
++              return -EINVAL;
++      }
++
++      dev = ep->dev;
++      if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
++              return -ESHUTDOWN;
++
++      type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
++      max = le16_to_cpu (desc->wMaxPacketSize);
++      switch (max) {
++      case 64: case 32:
++      /* note:  maxpacket > 16 means DMA might overrun/underrun */
++      case 16: case 8:
++              break;
++      default:
++              if (type == USB_ENDPOINT_XFER_INT && max < 64)
++                      break;
++              return -EDOM;
++      }
++
++      switch (type) {
++      case USB_ENDPOINT_XFER_BULK:
++      case USB_ENDPOINT_XFER_INT:
++              if (ep == &dev->ep[2]) {
++                      if (desc->bEndpointAddress != (USB_DIR_IN|2)) {
++                              PRINTKD("%s: ep[2] has invalid endpoint\n",__FUNCTION__);
++                              return -EINVAL;
++                      }
++                      tx_pktsize = max;
++                      Ser0UDCOMP = max - 1;
++                      PRINTKD("%s: ep2 max packet size is %d\n",__FUNCTION__,max);
++                      break;
++              } else if (ep == &dev->ep[1]) {
++                      if (desc->bEndpointAddress != (USB_DIR_OUT|1)) {
++                              PRINTKD("%s: ep[1] has invalid endpoint\n",__FUNCTION__);
++                              return -EINVAL;
++                      }
++                      rx_pktsize = max;
++                      Ser0UDCIMP = max - 1;
++                      PRINTKD("%s: ep1 max packet size is %d\n",__FUNCTION__,max);
++                      break;
++              }
++              // FALLTHROUGH
++      default:
++              PRINTKD("%s: Invalid endpoint\n",__FUNCTION__);
++              return -EINVAL;
++      }
++
++      _ep->maxpacket = max;
++      ep->desc = desc;
++      ep->stopped = 0;
++
++      DEBUG (dev, "enabled %s %s max %04x\n", _ep->name,
++              type_string (desc->bmAttributes), max);
++
++      return 0;
++}
++
++static int sa1100_disable (struct usb_ep *_ep)
++{
++      struct sa1100_ep        *ep;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (!_ep || !ep->desc || _ep->name == ep0name)
++              return -EINVAL;
++
++      nuke (ep, -ESHUTDOWN);
++
++      DEBUG (ep->dev, "disabled %s\n", _ep->name);
++
++      ep->desc = NULL;
++      ep->stopped = 1;
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_request *
++sa1100_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
++{
++      struct sa1100_request *req;
++
++      if (!_ep)
++              return 0;
++
++      req = kzalloc(sizeof *req, gfp_flags);
++      if (!req)
++              return 0;
++
++      memset (req, 0, sizeof *req);
++      req->req.dma = DMA_ADDR_INVALID;
++      INIT_LIST_HEAD (&req->queue);
++      return &req->req;
++}
++
++static void sa1100_free_request(struct usb_ep *_ep, struct usb_request *_req)
++{
++      struct sa1100_request   *req;
++
++      req = container_of (_req, struct sa1100_request, req);
++      WARN_ON (!list_empty (&req->queue));
++      kfree(req);     //NCB - see pxa2xx_udc
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void done(struct sa1100_ep *ep, struct sa1100_request *req, int status)
++{
++      unsigned                stopped = ep->stopped;
++
++      list_del_init (&req->queue);
++
++      if (likely(req->req.status == -EINPROGRESS))
++              req->req.status = status;
++      else
++              status = req->req.status;
++
++      if (status && status != -ESHUTDOWN)
++              VDEBUG (ep->dev, "complete %s req %p stat %d len %u/%u\n",
++                      ep->ep.name, &req->req, status,
++                      req->req.actual, req->req.length);
++
++      /* don't modify queue heads during completion callback */
++      ep->stopped = 1;
++      req->req.complete (&ep->ep, &req->req);
++      ep->stopped = stopped;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* FIXME move away from the old non-queued api.
++ * - forces extra work on us
++ * - stores request state twice
++ * - doesn't let gadget driver handle dma mapping
++ * - status codes need mapping
++ */
++
++static int map_status(int status)
++{
++      switch (status) {
++      case 0:
++      case -EIO:      /* ep[12]_int_handler */
++              return status;
++      case -EPIPE:    /* ep1_int_handler */
++              return 0;
++      //  case -EAGAIN:       /* ep[12]_init */
++      //  case -EINTR:        /* ep[12]_reset */
++      default:
++              return -ESHUTDOWN;
++      }
++}
++
++static void tx_callback(int status, int size)
++{
++      struct sa1100_ep        *ep = &the_controller->ep[2];
++      struct sa1100_request   *req;
++
++      if (list_empty (&ep->queue)) {
++              if (status != -EAGAIN)
++                      DEBUG (ep->dev, "%s, bogus tx callback %d/%d\n",
++                              ep->ep.name, status, size);
++              return;
++      }
++      req = list_entry (ep->queue.next, struct sa1100_request, queue);
++      req->req.actual = size;
++      done (ep, req, map_status (status));
++
++      if (ep->stopped || list_empty (&ep->queue))
++              return;
++      req = list_entry (ep->queue.next, struct sa1100_request, queue);
++      sa1100_usb_send (&req->req, tx_callback);
++}
++
++static void rx_callback (int status, int size)
++{
++      struct sa1100_ep        *ep = &the_controller->ep[1];
++      struct sa1100_request   *req;
++
++      if (list_empty (&ep->queue)) {
++              if (status != -EAGAIN)
++                      DEBUG (ep->dev, "%s, bogus tx callback %d/%d\n",
++                              ep->ep.name, status, size);
++              return;
++      }
++      req = list_entry (ep->queue.next, struct sa1100_request, queue);
++      req->req.actual = size;
++      done (ep, req, map_status (status));
++
++      if (ep->stopped || list_empty (&ep->queue))
++              return;
++      req = list_entry (ep->queue.next, struct sa1100_request, queue);
++      sa1100_usb_recv (&req->req, rx_callback);
++}
++
++
++static int
++sa1100_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
++{
++      struct sa1100_request   *req;
++      struct sa1100_ep        *ep;
++      struct sa1100_udc       *dev;
++      unsigned long           flags;
++
++      req = container_of (_req, struct sa1100_request, req);
++      if (!_req || !_req->complete || !_req->buf
++                      || !list_empty (&req->queue))
++              return -EINVAL;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (unlikely(!_ep || (!ep->desc && _ep->name != ep0name)))
++              return -EINVAL;
++
++      dev = ep->dev;
++      if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
++              return -ESHUTDOWN;
++
++      // handle ep0
++      if (_ep->name == ep0name) {
++          ep0_queue( _req->buf, _req->length, dev->ep0_req_len >=0 ? dev->ep0_req_len: _req->length );
++          return 0;
++      }
++
++      /* sa1100 udc can't write zlps */
++      if (ep == &dev->ep[2] && _req->length == 0)
++              return -ERANGE;
++
++      /* the old sa1100 api doesn't use 'unsigned' for lengths */
++      if (_req->length > INT_MAX)
++              return -ERANGE;
++
++      VDEBUG (dev, "%s queue req %p, len %d buf %p\n",
++                      _ep->name, _req, _req->length, _req->buf);
++
++      local_irq_save (flags);
++
++      _req->status = -EINPROGRESS;
++      _req->actual = 0;
++
++      if (list_empty (&ep->queue) && !ep->stopped) {
++              /* FIXME this does DMA mapping wrong.  caller is allowed
++               * to provide buffers that don't need mapping, but this
++               * doesn't use them.
++               */
++              if (ep == &ep->dev->ep[2]) {
++                      PRINTKD("%s: sa1100_usb_send buf %p length %d\n",__FUNCTION__,_req->buf,_req->length);
++                      sa1100_usb_send (_req, tx_callback);
++              }
++              else if (ep == &ep->dev->ep[1]) {
++                      PRINTKD("%s: sa1100_usb_recv buf %p length %d\n",__FUNCTION__,_req->buf,_req->length);
++                      sa1100_usb_recv (_req, rx_callback);
++              }
++              /* ep0 rx/tx is handled separately */
++      }
++      list_add_tail (&req->queue, &ep->queue);
++
++      local_irq_restore (flags);
++
++      return 0;
++}
++
++/* dequeue ALL requests */
++static void nuke (struct sa1100_ep *ep, int status)
++{
++      struct sa1100_request   *req;
++
++      /* called with irqs blocked */
++      while (!list_empty (&ep->queue)) {
++              req = list_entry (ep->queue.next,
++                              struct sa1100_request,
++                              queue);
++              done (ep, req, status);
++      }
++      if (ep == &ep->dev->ep[1])
++              ep1_reset ();
++      else if (ep == &ep->dev->ep[2])
++              ep2_reset ();
++}
++
++/* dequeue JUST ONE request */
++static int sa1100_dequeue (struct usb_ep *_ep, struct usb_request *_req)
++{
++      struct sa1100_ep        *ep;
++      struct sa1100_request   *req;
++      unsigned long           flags;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (!_ep || (!ep->desc && _ep->name != ep0name) || !_req)
++              return -EINVAL;
++
++      local_irq_save (flags);
++
++      /* make sure it's actually queued on this endpoint */
++      list_for_each_entry (req, &ep->queue, queue) {
++              if (&req->req == _req)
++                      break;
++      }
++      if (&req->req != _req) {
++              local_irq_restore(flags);
++              return -EINVAL;
++      }
++
++      done(ep, req, -ECONNRESET);
++
++      local_irq_restore(flags);
++
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int
++sa1100_set_halt (struct usb_ep *_ep, int value)
++{
++      struct sa1100_ep        *ep;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (unlikely(!_ep 
++              || (!ep->desc && _ep->name != ep0name))
++              || (ep->desc->bmAttributes & 0x03) == USB_ENDPOINT_XFER_ISOC)
++              return -EINVAL;
++      if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
++              return -ESHUTDOWN;
++
++      VDEBUG (ep->dev, "%s %s halt\n", _ep->name, value ? "set" : "clear");
++
++      /* set/clear, then synch memory views with the device */
++      if (value) {
++              if (ep == &ep->dev->ep[1])
++                      ep1_stall ();
++              else
++                      ep2_stall ();
++      } else {
++              if (ep == &ep->dev->ep[1])
++                      ep1_reset ();
++              else
++                      ep2_reset ();
++      }
++
++      return 0;
++}
++
++static struct usb_ep_ops sa1100_ep_ops = {
++      .enable         = sa1100_enable,
++      .disable        = sa1100_disable,
++
++      .alloc_request  = sa1100_alloc_request,
++      .free_request   = sa1100_free_request,
++
++      .queue          = sa1100_queue,
++      .dequeue        = sa1100_dequeue,
++
++      .set_halt       = sa1100_set_halt,
++      // .fifo_status = sa1100_fifo_status,
++      // .fifo_flush  = sa1100_fifo_flush,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int sa1100_get_frame (struct usb_gadget *_gadget)
++{
++      return -EOPNOTSUPP;
++}
++
++static int sa1100_wakeup (struct usb_gadget *_gadget)
++{
++      struct sa1100_udc       *dev;
++
++      if (!_gadget)
++              return 0;
++      dev = container_of (_gadget, struct sa1100_udc, gadget);
++
++      // FIXME
++
++      return 0;
++}
++
++static const struct usb_gadget_ops sa1100_ops = {
++      .get_frame      = sa1100_get_frame,
++      .wakeup         = sa1100_wakeup,
++
++      // .set_selfpowered = sa1100_set_selfpowered,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static inline void enable_resume_mask_suspend (void)
++{
++       int i = 0;
++
++       while (1) {
++                Ser0UDCCR |= UDCCR_SUSIM; // mask future suspend events
++                udelay (i);
++                if ( (Ser0UDCCR & UDCCR_SUSIM) || (Ser0UDCSR & UDCSR_RSTIR))
++                         break;
++                if (++i == 50) {
++                         WARN (&the_controller, "%s Could not set SUSIM %8.8lX\n",
++                                      __FUNCTION__, Ser0UDCCR);
++                         break;
++                }
++       }
++
++       i = 0;
++       while (1) {
++                Ser0UDCCR &= ~UDCCR_RESIM;
++                udelay (i);
++                if ( (Ser0UDCCR & UDCCR_RESIM) == 0
++                              || (Ser0UDCSR & UDCSR_RSTIR))
++                         break;
++                if (++i == 50) {
++                         WARN (&the_controller, "%s Could not clear RESIM %8.8lX\n",
++                                      __FUNCTION__, Ser0UDCCR);
++                         break;
++                }
++       }
++}
++
++static inline void enable_suspend_mask_resume (void)
++{
++       int i = 0;
++       while (1) {
++                Ser0UDCCR |= UDCCR_RESIM; // mask future resume events
++                udelay (i);
++                if (Ser0UDCCR & UDCCR_RESIM || (Ser0UDCSR & UDCSR_RSTIR))
++                         break;
++                if (++i == 50) {
++                         WARN (&the_controller, "%s could not set RESIM %8.8lX\n",
++                                      __FUNCTION__, Ser0UDCCR);
++                         break;
++                }
++       }
++       i = 0;
++       while (1) {
++                Ser0UDCCR &= ~UDCCR_SUSIM;
++                udelay (i);
++                if ( (Ser0UDCCR & UDCCR_SUSIM) == 0
++                              || (Ser0UDCSR & UDCSR_RSTIR))
++                         break;
++                if (++i == 50) {
++                         WARN (&the_controller, "%s Could not clear SUSIM %8.8lX\n",
++                                      __FUNCTION__, Ser0UDCCR);
++                         break;
++                }
++       }
++}
++
++// HACK DEBUG  3Mar01ww
++// Well, maybe not, it really seems to help!  08Mar01ww
++static void core_kicker (void)
++{
++      u32 car = Ser0UDCAR;
++      u32 imp = Ser0UDCIMP;
++      u32 omp = Ser0UDCOMP;
++
++      UDC_set (Ser0UDCCR, UDCCR_UDD);
++      udelay (300);
++      UDC_clear (Ser0UDCCR, UDCCR_UDD);
++
++      Ser0UDCAR = car;
++      Ser0UDCIMP = imp;
++      Ser0UDCOMP = omp;
++}
++
++static irqreturn_t udc_int_hndlr(int irq, void *_dev)
++{
++      struct sa1100_udc       *dev = _dev;
++      u32                     status = Ser0UDCSR;
++
++      PRINTKD("%s: status = 0x%x and control = 0x%lx\n", __FUNCTION__,
++                      status, Ser0UDCCR);
++      /* ReSeT Interrupt Request - UDC has been reset */
++      if (status & UDCSR_RSTIR) {
++              PRINTKD("%s: processing UDCSR_RSTIR\n", __FUNCTION__);
++              if (usbctl_next_state_on_event(kEvReset) != kError) {
++                      /* starting 20ms or so reset sequence now... */
++                      INFO (dev, "Resetting\n");
++                      ep0_reset();  // just set state to idle
++                      ep1_reset();  // flush dma, clear false stall
++                      ep2_reset();  // flush dma, clear false stall
++              }
++              // mask reset ints, they flood during sequence, enable
++              // suspend and resume
++              UDC_set(Ser0UDCCR, UDCCR_REM);    // mask reset
++              UDC_clear(Ser0UDCCR, (UDCCR_SUSIM | UDCCR_RESIM)); // enable suspend and resume
++              UDC_flip(Ser0UDCSR, status);    // clear all pending sources
++              PRINTKD("%s: setting USB_FULL_SPEED\n",__FUNCTION__);
++              dev->gadget.speed = USB_SPEED_FULL;
++              return IRQ_HANDLED;     // NCB
++      }
++
++      /* else we have done something other than reset,
++       * so be sure reset enabled
++       */
++      UDC_clear(Ser0UDCCR, UDCCR_REM);
++
++      /* RESume Interrupt Request */
++      if (status & UDCSR_RESIR) {
++              struct usb_gadget_driver        *driver = dev->driver;
++
++              PRINTKD("%s: processing UDCSR_RESIR\n",__FUNCTION__);
++              if (driver->resume)
++                      driver->resume (&dev->gadget);
++              core_kicker ();
++              enable_suspend_mask_resume ();
++      }
++
++      /* SUSpend Interrupt Request */
++      if (status & UDCSR_SUSIR) {
++              struct usb_gadget_driver        *driver = dev->driver;
++
++              PRINTKD("%s: processing UDCSR_SUSIR\n",__FUNCTION__);
++              if (driver->suspend)
++                      driver->suspend (&dev->gadget);
++              enable_resume_mask_suspend ();
++      }
++
++      UDC_flip(Ser0UDCSR, status); // clear all pending sources
++
++      if (status & UDCSR_EIR)
++              PRINTKD("%s: processing ep0_int_hndlr\n",__FUNCTION__);
++               ep0_int_hndlr();
++
++      if (status & UDCSR_RIR) {
++              PRINTKD("%s: processing ep1_int_hndlr\n",__FUNCTION__);
++              ep1_int_hndlr(status);
++      }
++      if (status & UDCSR_TIR) {
++              PRINTKD("%s: processing ep2_int_hndlr\n",__FUNCTION__);
++              ep2_int_hndlr(status);
++      }
++
++      return IRQ_HANDLED;     // NCB
++}
++
++/* soft_connect_hook ()
++ * Some devices have platform-specific circuitry to make USB
++ * not seem to be plugged in, even when it is. This allows
++ * software to control when a device 'appears' on the USB bus
++ * (after Linux has booted and this driver has loaded, for
++ * example). If you have such a circuit, control it here.
++ */
++#ifdef CONFIG_SA1100_EXTENEX1
++static void soft_connect_hook(int enable)
++{
++      if (machine_is_extenex1 ()) {
++              if (enable) {
++                      PPDR |= PPC_USB_SOFT_CON;
++                      PPSR |= PPC_USB_SOFT_CON;
++              } else {
++                      PPSR &= ~PPC_USB_SOFT_CON;
++                      PPDR &= ~PPC_USB_SOFT_CON;
++              }
++      }
++}
++#elif defined(CONFIG_SA1100_BALLOON)
++static void soft_connect_hook(int enable)
++{
++      if (machine_is_balloon()) {
++          if (enable)
++                      balloon_cpld_control(BALLOON_UDC_DISCONNECT, 0);
++          else
++                      balloon_cpld_control(BALLOON_UDC_DISCONNECT, 1);
++      }
++}
++#elif defined(CONFIG_SA1100_COLLIE)
++extern struct platform_device colliescoop_device;
++
++static void soft_connect_hook(int enable)
++{
++      if(enable)
++              set_scoop_gpio(&colliescoop_device.dev, COLLIE_SCP_LB_VOL_CHG);
++      else
++              reset_scoop_gpio(&colliescoop_device.dev, COLLIE_SCP_LB_VOL_CHG);
++}
++#else
++#define soft_connect_hook(x) do { } while (0);
++#endif
++
++/* "function" sysfs attribute */
++static ssize_t
++show_function(struct device *_dev, struct device_attribute *attr, char *buf)
++{
++      struct sa1100_udc       *dev = dev_get_drvdata (_dev);
++
++      if (!dev->driver
++                      || !dev->driver->function
++                      || strlen(dev->driver->function) > PAGE_SIZE)
++              return 0;
++      return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
++}
++static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
++
++/* disable the UDC at the source */
++static void udc_disable(struct sa1100_udc *dev)
++{
++      soft_connect_hook(0);
++      UDC_set(Ser0UDCCR, UDCCR_UDD);
++      dev->gadget.speed = USB_SPEED_UNKNOWN;
++      ep0_idle(dev);
++}
++
++static void udc_reinit(struct sa1100_udc *dev)
++{
++      u32     i;
++
++      /* Initialize the gadget controller data structure */
++      INIT_LIST_HEAD(&dev->gadget.ep_list);
++      INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
++      ep0_idle(dev);
++      for ( i = 0 ; i < 3 ; i++) {
++              struct sa1100_ep *ep = &dev->ep[i];
++              if (i != 0)
++                      list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
++              ep->desc     = NULL;
++              ep->stopped  = 0;
++              INIT_LIST_HEAD(&ep->queue);
++      }
++}
++
++/*  enable the udc at the source */
++static void udc_enable(struct sa1100_udc *dev)
++{
++      UDC_clear (Ser0UDCCR, UDCCR_UDD);
++      ep0_idle(dev);
++}
++
++static void ep0_start(struct sa1100_udc *dev)
++{
++      udc_enable(dev);
++      udelay(100);
++
++      /* clear stall - receiver seems to start stalled? 19Jan01ww */
++      /* also clear other stuff just to be thurough 22Feb01ww */
++      UDC_clear(Ser0UDCCS1, UDCCS1_FST | UDCCS1_RPE | UDCCS1_RPC );
++      UDC_clear(Ser0UDCCS2, UDCCS2_FST | UDCCS2_TPE | UDCCS2_TPC );
++
++      /* mask everything */
++      Ser0UDCCR = 0xFC;
++
++      /* flush DMA and fire through some -EAGAINs */
++      ep1_init(dev->ep[1].dmaregs);
++      ep2_init(dev->ep[2].dmaregs);
++
++      /* enable any platform specific hardware */
++      soft_connect_hook(1);
++
++      /* clear all top-level sources */
++      Ser0UDCSR = UDCSR_RSTIR | UDCSR_RESIR | UDCSR_EIR |
++                       UDCSR_RIR | UDCSR_TIR | UDCSR_SUSIR ;
++
++      /* EXERIMENT - a short line in the spec says toggling this
++       * bit diddles the internal state machine in the udc to
++       * expect a suspend
++       */
++      Ser0UDCCR  |= UDCCR_RESIM;
++      /* END EXPERIMENT 10Feb01ww */
++
++      /* enable any platform specific hardware */
++      soft_connect_hook(1);
++
++      /* Enable interrupts. If you are unplugged you will immediately
++       * get a suspend interrupt. If you are plugged and have a soft
++       * connect-circuit, you will get a reset.  If you are plugged
++       * without a soft-connect, I think you also get suspend. In short,
++       * start with suspend masked and everything else enabled
++       */
++      UDC_write(Ser0UDCCR, UDCCR_SUSIM);
++}
++
++
++/* when a driver is successfully registered, it will receive
++ * control requests including set_configuration(), which enables
++ * non-control requests.  then usb traffic follows until a
++ * disconnect is reported.  then a host may connect again, or
++ * the driver might get unbound.
++ */
++int usb_gadget_register_driver(struct usb_gadget_driver *driver)
++{
++      struct sa1100_udc       *dev = the_controller;
++      int                     retval;
++
++      if (!driver || !driver->bind || !driver->setup)
++              return -EINVAL;
++      if (!dev)
++              return -ENODEV;
++      if (dev->driver)
++              return -EBUSY;
++
++      /* hook up the driver ... */
++      dev->driver = driver;
++      dev->gadget.dev.driver = &driver->driver;
++
++      retval = device_add(&dev->gadget.dev);
++      if (retval != 0) {
++              printk(KERN_ERR "Error in device_add() : %d\n",retval);
++              goto register_error;
++      }
++
++      retval = driver->bind (&dev->gadget);
++      if (retval != 0) {
++              DEBUG(dev, "bind to driver %s --> %d\n",
++                              driver->driver.name, retval);
++              device_del(&dev->gadget.dev);
++              goto register_error;
++      }
++
++      retval = device_create_file(dev->dev, &dev_attr_function);
++
++      /* ... then enable host detection and ep0; and we're ready
++       * for set_configuration as well as eventual disconnect.
++       */
++      ep0_start(dev);
++
++      DEBUG(dev, "%s ready\n", driver->driver.name);
++
++      return 0;
++
++register_error:
++      dev->driver = NULL;
++      dev->gadget.dev.driver = NULL;
++      return retval;
++}
++EXPORT_SYMBOL (usb_gadget_register_driver);
++
++static void
++stop_activity(struct sa1100_udc *dev, struct usb_gadget_driver *driver)
++{
++      int i;
++
++      /* don't disconnect if it's not connected */
++      if (dev->gadget.speed == USB_SPEED_UNKNOWN)
++              driver = NULL;
++      dev->gadget.speed = USB_SPEED_UNKNOWN;
++
++      /* mask everything */
++      Ser0UDCCR = 0xFC;
++
++      /* stop hardware; prevent new request submissions;
++       * and kill any outstanding requests.
++       */
++      for (i = 0; i < 3; i++) {
++              struct sa1100_ep *ep = &dev->ep[i];
++              ep->stopped = 1;
++              nuke(ep, -ESHUTDOWN);
++      }
++      udc_disable (dev);
++
++      /* report disconnect; the driver is already quiesced */
++      if (driver)
++              driver->disconnect(&dev->gadget);
++
++      /* re-init driver-visible data structures */
++      udc_reinit(dev);
++}
++
++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
++{
++      struct sa1100_udc       *dev = the_controller;
++
++      if (!dev)
++              return -ENODEV;
++      if (!driver || driver != dev->driver)
++              return -EINVAL;
++
++      local_irq_disable();
++      stop_activity (dev, driver);
++      local_irq_enable();
++      if (driver->unbind)
++              driver->unbind(&dev->gadget);
++      dev->driver = 0;
++
++      device_del(&dev->gadget.dev);
++      device_remove_file(dev->dev, &dev_attr_function);
++
++      DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
++      return 0;
++}
++EXPORT_SYMBOL (usb_gadget_unregister_driver);
++
++
++/*-------------------------------------------------------------------------*/
++
++/*-------------------------------------------------------------------------*/
++
++//////////////////////////////////////////////////////////////////////////////
++// Proc Filesystem Support
++//////////////////////////////////////////////////////////////////////////////
++
++#if CONFIG_PROC_FS
++
++#define SAY(fmt,args...)  p += sprintf (p, fmt, ## args)
++#define SAYV(num)         p += sprintf (p, num_fmt, "Value", num)
++#define SAYC(label,yn)    p += sprintf (p, yn_fmt, label, yn)
++#define SAYS(label,v)     p += sprintf (p, cnt_fmt, label, v)
++
++static int usbctl_read_proc (char *page, char **start, off_t off,
++                          int count, int *eof, void *data)
++{
++       const char * num_fmt   = "%25.25s: %8.8lX\n";
++       const char * cnt_fmt   = "%25.25s: %lu\n";
++       const char * yn_fmt    = "%25.25s: %s\n";
++       const char * yes       = "YES";
++       const char * no        = "NO";
++       unsigned long v;
++       char * p = page;
++       int len;
++
++       SAY ("SA1100 USB Controller Core\n");
++
++       SAYS ("ep0 bytes read", usbd_info.stats.ep0_bytes_read);
++       SAYS ("ep0 bytes written", usbd_info.stats.ep0_bytes_written);
++       SAYS ("ep0 FIFO read failures", usbd_info.stats.ep0_fifo_read_failures);
++       SAYS ("ep0 FIFO write failures", usbd_info.stats.ep0_fifo_write_failures);
++
++       SAY ("\n");
++
++       v = Ser0UDCAR;
++       SAY ("%25.25s: 0x%8.8lX - %ld\n", "Address Register", v, v);
++       v = Ser0UDCIMP;
++       SAY ("%25.25s: %ld (%8.8lX)\n", "IN  max packet size", v+1, v);
++       v = Ser0UDCOMP;
++       SAY ("%25.25s: %ld (%8.8lX)\n", "OUT max packet size", v+1, v);
++
++       v = Ser0UDCCR;
++       SAY ("\nUDC Mask Register\n");
++       SAYV (v);
++       SAYC ("UDC Active", (v & UDCCR_UDA) ? yes : no);
++       SAYC ("Suspend interrupts masked", (v & UDCCR_SUSIM) ? yes : no);
++       SAYC ("Resume interrupts masked", (v & UDCCR_RESIM) ? yes : no);
++       SAYC ("Reset interrupts masked", (v & UDCCR_REM) ? yes : no);
++
++       v = Ser0UDCSR;
++       SAY ("\nUDC Interrupt Request Register\n");
++       SAYV (v);
++       SAYC ("Reset pending", (v & UDCSR_RSTIR) ? yes : no);
++       SAYC ("Suspend pending", (v & UDCSR_SUSIR) ? yes : no);
++       SAYC ("Resume pending", (v & UDCSR_RESIR) ? yes : no);
++       SAYC ("ep0 pending", (v & UDCSR_EIR)   ? yes : no);
++       SAYC ("receiver pending", (v & UDCSR_RIR)   ? yes : no);
++       SAYC ("tramsitter pending", (v & UDCSR_TIR)   ? yes : no);
++
++#ifdef CONFIG_SA1100_EXTENEX1
++       SAYC ("\nSoft connect", (PPSR & PPC_USB_SOFT_CON) ? "Visible" : "Hidden");
++#endif
++
++#if 1
++       SAY ("\nDMA Tx registers\n");
++       {
++       dma_regs_t *r=the_controller->ep[2].dmaregs;
++       SAY (" DDAR");
++       SAYV(r->DDAR);
++       SAY (" DCSR");
++       SAYV(r->RdDCSR);
++       SAY (" DBSA (address buf A) ");
++       SAYV(r->DBSA);
++       SAY (" DBTA (transfer count A) ");
++       SAYV(r->DBTA);
++       SAY (" DBSB (address buf B) ");
++       SAYV(r->DBSB);
++       SAY (" DBTB (transfer count B) ");
++       SAYV(r->DBTB);
++
++       }
++       SAY ("\nDMA Rx registers\n");
++       {
++       dma_regs_t *r=the_controller->ep[1].dmaregs;
++       SAY (" DDAR");
++       SAYV(r->DDAR);
++       SAY (" DCSR");
++       SAYV(r->RdDCSR);
++       SAY (" DBSA (address buf A) ");
++       SAYV(r->DBSA);
++       SAY (" DBTA (transfer count A) ");
++       SAYV(r->DBTA);
++       SAY (" DBSB (address buf B) ");
++       SAYV(r->DBSB);
++       SAY (" DBTB (transfer count B) ");
++       SAYV(r->DBTB);
++
++       }
++#endif
++#if 1
++       v = Ser0UDCCS0;
++       SAY ("\nUDC Endpoint Zero Status Register\n");
++       SAYV (v);
++       SAYC ("Out Packet Ready", (v & UDCCS0_OPR) ? yes : no);
++       SAYC ("In Packet Ready", (v & UDCCS0_IPR) ? yes : no);
++       SAYC ("Sent Stall", (v & UDCCS0_SST) ? yes : no);
++       SAYC ("Force Stall", (v & UDCCS0_FST) ? yes : no);
++       SAYC ("Data End", (v & UDCCS0_DE)  ? yes : no);
++       SAYC ("Data Setup End", (v & UDCCS0_SE)  ? yes : no);
++       SAYC ("Serviced (SO)", (v & UDCCS0_SO)  ? yes : no);
++
++       v = Ser0UDCCS1;
++       SAY ("\nUDC Receiver Status Register\n");
++       SAYV (v);
++       SAYC ("Receive Packet Complete", (v & UDCCS1_RPC) ? yes : no);
++       SAYC ("Sent Stall", (v & UDCCS1_SST) ? yes : no);
++       SAYC ("Force Stall", (v & UDCCS1_FST) ? yes : no);
++       SAYC ("Receive Packet Error", (v & UDCCS1_RPE) ? yes : no);
++       SAYC ("Receive FIFO not empty", (v & UDCCS1_RNE) ? yes : no);
++
++       v = Ser0UDCCS2;
++       SAY ("\nUDC Transmitter Status Register\n");
++       SAYV (v);
++       SAYC ("FIFO has < 8 of 16 chars", (v & UDCCS2_TFS) ? yes : no);
++       SAYC ("Transmit Packet Complete", (v & UDCCS2_TPC) ? yes : no);
++       SAYC ("Transmit FIFO underrun", (v & UDCCS2_TUR) ? yes : no);
++       SAYC ("Transmit Packet Error", (v & UDCCS2_TPE) ? yes : no);
++       SAYC ("Sent Stall", (v & UDCCS2_SST) ? yes : no);
++       SAYC ("Force Stall", (v & UDCCS2_FST) ? yes : no);
++#endif
++
++       len = (p - page) - off;
++       if (len < 0)
++                len = 0;
++       *eof = (len <=count) ? 1 : 0;
++       *start = page + off;
++       return len;
++}
++
++static inline void register_proc_entry (void)
++{
++      create_proc_read_entry (driver_name, 0, NULL,
++              usbctl_read_proc, NULL);
++}
++
++static inline void unregister_proc_entry (void)
++{
++      remove_proc_entry (driver_name, NULL);
++}
++
++#else
++
++#define register_proc_entry() do {} while (0)
++#define unregister_proc_entry() do {} while (0)
++
++#endif  /* CONFIG_PROC_FS */
++
++/*-------------------------------------------------------------------------*/
++
++MODULE_DESCRIPTION ("sa1100_udc");
++MODULE_AUTHOR ("Various");
++MODULE_LICENSE ("GPL");
++
++static struct sa1100_udc memory = {
++      .gadget = {
++              .ops            = &sa1100_ops,
++              .ep0            = &memory.ep[0].ep,
++              .name           = driver_name,
++              .dev = {
++                      .bus_id         = "gadget",
++              },
++      },
++
++      /* control endpoint */
++      .ep[0] = {
++              .ep = {
++                      .name           = ep0name,
++                      .ops            = &sa1100_ep_ops,
++                      .maxpacket      = EP0_FIFO_SIZE,
++              },
++              .dev            = &memory,
++      },
++
++      /* first group of endpoints */
++      .ep[1] = {
++              .ep = {
++                      .name           = "ep1out-bulk",
++                      .ops            = &sa1100_ep_ops,
++                      .maxpacket      = BULK_FIFO_SIZE,
++              },
++              .dev            = &memory,
++      },
++      .ep[2] = {
++              .ep = {
++                      .name           = "ep2in-bulk",
++                      .ops            = &sa1100_ep_ops,
++                      .maxpacket      = BULK_FIFO_SIZE,
++              },
++              .dev            = &memory,
++      }
++};
++
++static int __init sa1100_udc_probe(struct device *_dev)
++{
++      struct sa1100_udc *dev = &memory;
++      int retval = 0;
++
++      /* setup dev */
++      dev->dev = _dev;
++//    dev->mach = _dev->platform_data;
++
++      device_initialize(&dev->gadget.dev);
++      dev->gadget.dev.parent = _dev;
++      dev->gadget.dev.dma_mask = _dev->dma_mask;
++
++      the_controller = dev;
++      dev_set_drvdata(_dev, dev);
++
++      /* controller stays disabled until gadget driver is bound */
++      udc_disable(dev);
++      udc_reinit(dev);
++
++//    spin_lock_init(&the_udc.lock);
++      register_proc_entry();
++
++      /* setup dma channels and IRQ */
++      retval = sa1100_request_dma(DMA_Ser0UDCRd, "USB receive",
++                                  NULL, NULL, &dev->ep[1].dmaregs);
++      if (retval) {
++              ERROR(dev, "couldn't get rx dma, err %d\n", retval);
++              goto err_rx_dma;
++      }
++      retval = sa1100_request_dma(DMA_Ser0UDCWr, "USB transmit",
++                                  NULL, NULL, &dev->ep[2].dmaregs);
++      if (retval) {
++              ERROR(dev, "couldn't get tx dma, err %d\n", retval);
++              goto err_tx_dma;
++      }
++      retval = request_irq(IRQ_Ser0UDC, udc_int_hndlr, IRQF_DISABLED,
++                      driver_name, dev);
++      if (retval) {
++              ERROR(dev, "couldn't get irq, err %d\n", retval);
++              goto err_irq;
++      }
++
++      INFO(dev, "initialized, rx %p tx %p irq %d\n",
++              dev->ep[1].dmaregs, dev->ep[2].dmaregs, IRQ_Ser0UDC);
++      return 0;
++
++err_irq:
++      sa1100_free_dma(dev->ep[2].dmaregs);
++      usbd_info.dmaregs_rx = 0;
++err_tx_dma:
++      sa1100_free_dma(dev->ep[1].dmaregs);
++      usbd_info.dmaregs_tx = 0;
++err_rx_dma:
++      return retval;
++}
++
++static int __exit sa1100_udc_remove(struct device *_dev)
++{
++      struct sa1100_udc *dev = dev_get_drvdata(_dev);
++
++      udc_disable(dev);
++      unregister_proc_entry();
++      usb_gadget_unregister_driver(dev->driver);
++      sa1100_free_dma(dev->ep[1].dmaregs);
++      sa1100_free_dma(dev->ep[2].dmaregs);
++      free_irq(IRQ_Ser0UDC, dev);
++      dev_set_drvdata(_dev,NULL);
++      the_controller = NULL;
++      return 0;
++}
++
++static struct device_driver udc_driver = {
++      .name           = "sa11x0-udc",
++      .bus            = &platform_bus_type,
++      .probe          = sa1100_udc_probe,
++      .remove         = __exit_p(sa1100_udc_remove),
++//    .suspend        = sa1100_udc_suspend,
++//    .resume         = sa1100_udc_resume,
++      .owner          = THIS_MODULE,
++};
++
++static int __init udc_init(void)
++{
++      printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
++#ifdef NCB_DMA_FIX
++      send_buffer = (char*) kzalloc(SEND_BUFFER_SIZE, GFP_KERNEL | GFP_DMA );
++      receive_buffer = (char*) kzalloc(RECEIVE_BUFFER_SIZE, GFP_KERNEL | GFP_DMA );
++#endif
++      return driver_register(&udc_driver);
++}
++module_init(udc_init);
++
++static void __exit udc_exit(void)
++{
++#ifdef NCB_DMA_FIX
++      if (send_buffer) {
++          kfree(send_buffer);
++          send_buffer = NULL;
++      }
++      if (receive_buffer) {
++          kfree(receive_buffer);
++          receive_buffer = NULL;
++      }
++#endif
++      driver_unregister(&udc_driver);
++}
++module_exit(udc_exit);
+diff --git a/drivers/usb/gadget/sa1100_udc.h b/drivers/usb/gadget/sa1100_udc.h
+new file mode 100644
+index 0000000..acb665a
+--- /dev/null
++++ b/drivers/usb/gadget/sa1100_udc.h
+@@ -0,0 +1,94 @@
++/*
++ * internals of "new style" UDC controller
++ * <linux/usb_gadget.h> replaces ARM-specific "sa1100_usb.h".
++ */
++
++struct sa1100_ep {
++      struct usb_ep                           ep;
++      struct sa1100_udc                       *dev;
++      //unsigned long                         irqs;
++
++      const struct usb_endpoint_descriptor    *desc;
++      struct list_head                        queue;
++      dma_regs_t                              *dmaregs;
++      unsigned                                stopped : 1;
++};
++
++struct sa1100_request {
++      struct usb_request                      req;
++      struct list_head                        queue;
++// NCB        unsigned                                mapped : 1;
++};
++
++enum ep0_state {
++      EP0_IDLE,
++      EP0_IN_DATA_PHASE,
++      EP0_OUT_DATA_PHASE,
++      EP0_END_XFER,
++      EP0_STALL,
++};
++
++#define EP0_FIFO_SIZE ((unsigned)8)
++#define BULK_FIFO_SIZE        ((unsigned)64)
++//#define ISO_FIFO_SIZE       ((unsigned)256)
++//#define INT_FIFO_SIZE       ((unsigned)8)
++
++struct udc_stats {
++      struct ep0stats {
++              unsigned long           ops;
++              unsigned long           bytes;
++      } read, write;
++      unsigned long                   irqs;
++};
++
++struct sa1100_udc {
++      struct usb_gadget                       gadget;
++      struct usb_gadget_driver                *driver;
++      struct device                           *dev;
++      enum ep0_state                          ep0state;
++      struct udc_stats                        stats;
++// NCB        spinlock_t                              lock;
++// NCB        dma_regs_t                              *dmaregs_tx, *dmaregs_rx;
++      unsigned                                got_irq : 1,
++                                              vbus : 1,
++                                              pullup : 1,
++                                              has_cfr : 1,
++                                              req_pending : 1,
++                                              req_std : 1,
++                                              req_config : 1;
++      struct timer_list                       timer;
++      u64 dma_mask;
++      unsigned char                           address;
++      struct sa1100_ep                        ep[3];
++      int                                     ep0_req_len;
++};
++
++/*-------------------------------------------------------------------------*/
++
++#define xprintk(dev,level,fmt,args...) \
++      printk(level "%s: " fmt , driver_name , ## args)
++
++#ifdef DEBUG
++#undef DEBUG
++#define DEBUG(dev,fmt,args...) \
++      xprintk(dev , KERN_DEBUG , fmt , ## args)
++#else
++#define DEBUG(dev,fmt,args...) \
++      do { } while (0)
++#endif /* DEBUG */
++
++#ifdef VERBOSE
++#define VDEBUG DEBUG
++#else
++#define VDEBUG(dev,fmt,args...) \
++      do { } while (0)
++#endif        /* VERBOSE */
++
++#define ERROR(dev,fmt,args...) \
++      xprintk(dev , KERN_ERR , fmt , ## args)
++#define WARN(dev,fmt,args...) \
++      xprintk(dev , KERN_WARNING , fmt , ## args)
++#define INFO(dev,fmt,args...) \
++      xprintk(dev , KERN_INFO , fmt , ## args)\r
++
++/*-------------------------------------------------------------------------*/
+diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
+index fa019fa..b3699af 100644
+--- a/drivers/usb/gadget/serial.c
++++ b/drivers/usb/gadget/serial.c
+@@ -1,15 +1,9 @@
+ /*
+- * g_serial.c -- USB gadget serial driver
++ * serial.c -- USB gadget serial driver
+  *
+- * Copyright 2003 (C) Al Borchers (alborchers@steinerpoint.com)
+- *
+- * This code is based in part on the Gadget Zero driver, which
+- * is Copyright (C) 2003 by David Brownell, all rights reserved.
+- *
+- * This code also borrows from usbserial.c, which is
+- * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
+- * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
+- * Copyright (C) 2000 Al Borchers (alborchers@steinerpoint.com)
++ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
++ * Copyright (C) 2008 by David Brownell
++ * Copyright (C) 2008 by Nokia Corporation
+  *
+  * This software is distributed under the terms of the GNU General
+  * Public License ("GPL") as published by the Free Software Foundation,
+@@ -22,2254 +16,237 @@
+ #include <linux/tty.h>
+ #include <linux/tty_flip.h>
+-#include <linux/usb/ch9.h>
+-#include <linux/usb/cdc.h>
+-#include <linux/usb/gadget.h>
+-
++#include "u_serial.h"
+ #include "gadget_chips.h"
+ /* Defines */
+-#define GS_VERSION_STR                        "v2.2"
+-#define GS_VERSION_NUM                        0x2200
++#define GS_VERSION_STR                        "v2.4"
++#define GS_VERSION_NUM                        0x2400
+ #define GS_LONG_NAME                  "Gadget Serial"
+-#define GS_SHORT_NAME                 "g_serial"
+-
+-#define GS_MAJOR                      127
+-#define GS_MINOR_START                        0
+-
+-/* REVISIT only one port is supported for now;
+- * see gs_{send,recv}_packet() ... no multiplexing,
+- * and no support for multiple ACM devices.
+- */
+-#define GS_NUM_PORTS                  1
+-
+-#define GS_NUM_CONFIGS                        1
+-#define GS_NO_CONFIG_ID                       0
+-#define GS_BULK_CONFIG_ID             1
+-#define GS_ACM_CONFIG_ID              2
+-
+-#define GS_MAX_NUM_INTERFACES         2
+-#define GS_BULK_INTERFACE_ID          0
+-#define GS_CONTROL_INTERFACE_ID               0
+-#define GS_DATA_INTERFACE_ID          1
+-
+-#define GS_MAX_DESC_LEN                       256
+-
+-#define GS_DEFAULT_READ_Q_SIZE                32
+-#define GS_DEFAULT_WRITE_Q_SIZE               32
+-
+-#define GS_DEFAULT_WRITE_BUF_SIZE     8192
+-#define GS_TMP_BUF_SIZE                       8192
+-
+-#define GS_CLOSE_TIMEOUT              15
+-
+-#define GS_DEFAULT_USE_ACM            0
+-
+-/* 9600-8-N-1 ... matches init_termios.c_cflag and defaults
+- * expected by "usbser.sys" on MS-Windows.
+- */
+-#define GS_DEFAULT_DTE_RATE           9600
+-#define GS_DEFAULT_DATA_BITS          8
+-#define GS_DEFAULT_PARITY             USB_CDC_NO_PARITY
+-#define GS_DEFAULT_CHAR_FORMAT                USB_CDC_1_STOP_BITS
+-
+-/* maxpacket and other transfer characteristics vary by speed. */
+-static inline struct usb_endpoint_descriptor *
+-choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+-              struct usb_endpoint_descriptor *fs)
+-{
+-      if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+-              return hs;
+-      return fs;
+-}
+-
+-
+-/* debug settings */
+-#ifdef DEBUG
+-static int debug = 1;
+-#else
+-#define       debug 0
+-#endif
+-
+-#define gs_debug(format, arg...) \
+-      do { if (debug) pr_debug(format, ## arg); } while (0)
+-#define gs_debug_level(level, format, arg...) \
+-      do { if (debug >= level) pr_debug(format, ## arg); } while (0)
++#define GS_VERSION_NAME                       GS_LONG_NAME " " GS_VERSION_STR
++/*-------------------------------------------------------------------------*/
+ /* Thanks to NetChip Technologies for donating this product ID.
+- *
+- * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+- * Instead:  allocate your own, using normal USB-IF procedures.
+- */
++*
++* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
++* Instead:  allocate your own, using normal USB-IF procedures.
++*/
+ #define GS_VENDOR_ID                  0x0525  /* NetChip */
+ #define GS_PRODUCT_ID                 0xa4a6  /* Linux-USB Serial Gadget */
+ #define GS_CDC_PRODUCT_ID             0xa4a7  /* ... as CDC-ACM */
+-#define GS_LOG2_NOTIFY_INTERVAL               5       /* 1 << 5 == 32 msec */
+-#define GS_NOTIFY_MAXPACKET           8
++/* string IDs are assigned dynamically */
++#define STRING_MANUFACTURER_IDX               0
++#define STRING_PRODUCT_IDX            1
++#define STRING_DESCRIPTION_IDX                2
+-/* circular buffer */
+-struct gs_buf {
+-      unsigned int            buf_size;
+-      char                    *buf_buf;
+-      char                    *buf_get;
+-      char                    *buf_put;
+-};
++static char manufacturer[50];
+-/* the port structure holds info for each port, one for each minor number */
+-struct gs_port {
+-      struct gs_dev           *port_dev;      /* pointer to device struct */
+-      struct tty_struct       *port_tty;      /* pointer to tty struct */
+-      spinlock_t              port_lock;
+-      int                     port_num;
+-      int                     port_open_count;
+-      int                     port_in_use;    /* open/close in progress */
+-      wait_queue_head_t       port_write_wait;/* waiting to write */
+-      struct gs_buf           *port_write_buf;
+-      struct usb_cdc_line_coding port_line_coding;    /* 8-N-1 etc */
+-      u16                     port_handshake_bits;
+-#define RS232_RTS     (1 << 1)
+-#define RS232_DTE     (1 << 0)
++static struct usb_string strings_dev[] = {
++      [STRING_MANUFACTURER_IDX].s = manufacturer,
++      [STRING_PRODUCT_IDX].s = GS_VERSION_NAME,
++      [STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */,
++      {  } /* end of list */
+ };
+-/* the device structure holds info for the USB device */
+-struct gs_dev {
+-      struct usb_gadget       *dev_gadget;    /* gadget device pointer */
+-      spinlock_t              dev_lock;       /* lock for set/reset config */
+-      int                     dev_config;     /* configuration number */
+-      struct usb_ep           *dev_notify_ep; /* address of notify endpoint */
+-      struct usb_ep           *dev_in_ep;     /* address of in endpoint */
+-      struct usb_ep           *dev_out_ep;    /* address of out endpoint */
+-      struct usb_endpoint_descriptor          /* descriptor of notify ep */
+-                              *dev_notify_ep_desc;
+-      struct usb_endpoint_descriptor          /* descriptor of in endpoint */
+-                              *dev_in_ep_desc;
+-      struct usb_endpoint_descriptor          /* descriptor of out endpoint */
+-                              *dev_out_ep_desc;
+-      struct usb_request      *dev_ctrl_req;  /* control request */
+-      struct list_head        dev_req_list;   /* list of write requests */
+-      int                     dev_sched_port; /* round robin port scheduled */
+-      struct gs_port          *dev_port[GS_NUM_PORTS]; /* the ports */
++static struct usb_gadget_strings stringtab_dev = {
++      .language       = 0x0409,       /* en-us */
++      .strings        = strings_dev,
+ };
+-
+-/* Functions */
+-
+-/* tty driver internals */
+-static int gs_send(struct gs_dev *dev);
+-static int gs_send_packet(struct gs_dev *dev, char *packet,
+-      unsigned int size);
+-static int gs_recv_packet(struct gs_dev *dev, char *packet,
+-      unsigned int size);
+-static void gs_read_complete(struct usb_ep *ep, struct usb_request *req);
+-static void gs_write_complete(struct usb_ep *ep, struct usb_request *req);
+-
+-/* gadget driver internals */
+-static int gs_set_config(struct gs_dev *dev, unsigned config);
+-static void gs_reset_config(struct gs_dev *dev);
+-static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
+-              u8 type, unsigned int index, int is_otg);
+-
+-static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
+-      gfp_t kmalloc_flags);
+-static void gs_free_req(struct usb_ep *ep, struct usb_request *req);
+-
+-static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags);
+-static void gs_free_ports(struct gs_dev *dev);
+-
+-/* circular buffer */
+-static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags);
+-static void gs_buf_free(struct gs_buf *gb);
+-static void gs_buf_clear(struct gs_buf *gb);
+-static unsigned int gs_buf_data_avail(struct gs_buf *gb);
+-static unsigned int gs_buf_space_avail(struct gs_buf *gb);
+-static unsigned int gs_buf_put(struct gs_buf *gb, const char *buf,
+-      unsigned int count);
+-static unsigned int gs_buf_get(struct gs_buf *gb, char *buf,
+-      unsigned int count);
+-
+-
+-/* Globals */
+-
+-static struct gs_dev *gs_device;
+-
+-static struct mutex gs_open_close_lock[GS_NUM_PORTS];
+-
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/* USB descriptors */
+-
+-#define GS_MANUFACTURER_STR_ID        1
+-#define GS_PRODUCT_STR_ID     2
+-#define GS_SERIAL_STR_ID      3
+-#define GS_BULK_CONFIG_STR_ID 4
+-#define GS_ACM_CONFIG_STR_ID  5
+-#define GS_CONTROL_STR_ID     6
+-#define GS_DATA_STR_ID                7
+-
+-/* static strings, in UTF-8 */
+-static char manufacturer[50];
+-static struct usb_string gs_strings[] = {
+-      { GS_MANUFACTURER_STR_ID, manufacturer },
+-      { GS_PRODUCT_STR_ID, GS_LONG_NAME },
+-      { GS_BULK_CONFIG_STR_ID, "Gadget Serial Bulk" },
+-      { GS_ACM_CONFIG_STR_ID, "Gadget Serial CDC ACM" },
+-      { GS_CONTROL_STR_ID, "Gadget Serial Control" },
+-      { GS_DATA_STR_ID, "Gadget Serial Data" },
+-      {  } /* end of list */
+-};
+-
+-static struct usb_gadget_strings gs_string_table = {
+-      .language =             0x0409, /* en-us */
+-      .strings =              gs_strings,
++static struct usb_gadget_strings *dev_strings[] = {
++      &stringtab_dev,
++      NULL,
+ };
+-static struct usb_device_descriptor gs_device_desc = {
++static struct usb_device_descriptor device_desc = {
+       .bLength =              USB_DT_DEVICE_SIZE,
+       .bDescriptorType =      USB_DT_DEVICE,
+       .bcdUSB =               __constant_cpu_to_le16(0x0200),
++      /* .bDeviceClass = f(use_acm) */
+       .bDeviceSubClass =      0,
+       .bDeviceProtocol =      0,
++      /* .bMaxPacketSize0 = f(hardware) */
+       .idVendor =             __constant_cpu_to_le16(GS_VENDOR_ID),
+-      .idProduct =            __constant_cpu_to_le16(GS_PRODUCT_ID),
+-      .iManufacturer =        GS_MANUFACTURER_STR_ID,
+-      .iProduct =             GS_PRODUCT_STR_ID,
+-      .bNumConfigurations =   GS_NUM_CONFIGS,
++      /* .idProduct = f(use_acm) */
++      /* .bcdDevice = f(hardware) */
++      /* .iManufacturer = DYNAMIC */
++      /* .iProduct = DYNAMIC */
++      .bNumConfigurations =   1,
+ };
+-static struct usb_otg_descriptor gs_otg_descriptor = {
+-      .bLength =              sizeof(gs_otg_descriptor),
++static struct usb_otg_descriptor otg_descriptor = {
++      .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+-      .bmAttributes =         USB_OTG_SRP,
+-};
+-
+-static struct usb_config_descriptor gs_bulk_config_desc = {
+-      .bLength =              USB_DT_CONFIG_SIZE,
+-      .bDescriptorType =      USB_DT_CONFIG,
+-      /* .wTotalLength computed dynamically */
+-      .bNumInterfaces =       1,
+-      .bConfigurationValue =  GS_BULK_CONFIG_ID,
+-      .iConfiguration =       GS_BULK_CONFIG_STR_ID,
+-      .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+-      .bMaxPower =            1,
+-};
+-
+-static struct usb_config_descriptor gs_acm_config_desc = {
+-      .bLength =              USB_DT_CONFIG_SIZE,
+-      .bDescriptorType =      USB_DT_CONFIG,
+-      /* .wTotalLength computed dynamically */
+-      .bNumInterfaces =       2,
+-      .bConfigurationValue =  GS_ACM_CONFIG_ID,
+-      .iConfiguration =       GS_ACM_CONFIG_STR_ID,
+-      .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+-      .bMaxPower =            1,
+-};
+-
+-static const struct usb_interface_descriptor gs_bulk_interface_desc = {
+-      .bLength =              USB_DT_INTERFACE_SIZE,
+-      .bDescriptorType =      USB_DT_INTERFACE,
+-      .bInterfaceNumber =     GS_BULK_INTERFACE_ID,
+-      .bNumEndpoints =        2,
+-      .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
+-      .bInterfaceSubClass =   0,
+-      .bInterfaceProtocol =   0,
+-      .iInterface =           GS_DATA_STR_ID,
+-};
+-
+-static const struct usb_interface_descriptor gs_control_interface_desc = {
+-      .bLength =              USB_DT_INTERFACE_SIZE,
+-      .bDescriptorType =      USB_DT_INTERFACE,
+-      .bInterfaceNumber =     GS_CONTROL_INTERFACE_ID,
+-      .bNumEndpoints =        1,
+-      .bInterfaceClass =      USB_CLASS_COMM,
+-      .bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
+-      .bInterfaceProtocol =   USB_CDC_ACM_PROTO_AT_V25TER,
+-      .iInterface =           GS_CONTROL_STR_ID,
+-};
+-
+-static const struct usb_interface_descriptor gs_data_interface_desc = {
+-      .bLength =              USB_DT_INTERFACE_SIZE,
+-      .bDescriptorType =      USB_DT_INTERFACE,
+-      .bInterfaceNumber =     GS_DATA_INTERFACE_ID,
+-      .bNumEndpoints =        2,
+-      .bInterfaceClass =      USB_CLASS_CDC_DATA,
+-      .bInterfaceSubClass =   0,
+-      .bInterfaceProtocol =   0,
+-      .iInterface =           GS_DATA_STR_ID,
+-};
+-
+-static const struct usb_cdc_header_desc gs_header_desc = {
+-      .bLength =              sizeof(gs_header_desc),
+-      .bDescriptorType =      USB_DT_CS_INTERFACE,
+-      .bDescriptorSubType =   USB_CDC_HEADER_TYPE,
+-      .bcdCDC =               __constant_cpu_to_le16(0x0110),
+-};
+-
+-static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
+-      .bLength =              sizeof(gs_call_mgmt_descriptor),
+-      .bDescriptorType =      USB_DT_CS_INTERFACE,
+-      .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
+-      .bmCapabilities =       0,
+-      .bDataInterface =       1,      /* index of data interface */
+-};
+-
+-static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
+-      .bLength =              sizeof(gs_acm_descriptor),
+-      .bDescriptorType =      USB_DT_CS_INTERFACE,
+-      .bDescriptorSubType =   USB_CDC_ACM_TYPE,
+-      .bmCapabilities =       (1 << 1),
+-};
+-
+-static const struct usb_cdc_union_desc gs_union_desc = {
+-      .bLength =              sizeof(gs_union_desc),
+-      .bDescriptorType =      USB_DT_CS_INTERFACE,
+-      .bDescriptorSubType =   USB_CDC_UNION_TYPE,
+-      .bMasterInterface0 =    0,      /* index of control interface */
+-      .bSlaveInterface0 =     1,      /* index of data interface */
+-};
+-
+-static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-      .bEndpointAddress =     USB_DIR_IN,
+-      .bmAttributes =         USB_ENDPOINT_XFER_INT,
+-      .wMaxPacketSize =       __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
+-      .bInterval =            1 << GS_LOG2_NOTIFY_INTERVAL,
+-};
+-
+-static struct usb_endpoint_descriptor gs_fullspeed_in_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-      .bEndpointAddress =     USB_DIR_IN,
+-      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+-};
+-
+-static struct usb_endpoint_descriptor gs_fullspeed_out_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-      .bEndpointAddress =     USB_DIR_OUT,
+-      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+-};
+-
+-static const struct usb_descriptor_header *gs_bulk_fullspeed_function[] = {
+-      (struct usb_descriptor_header *) &gs_otg_descriptor,
+-      (struct usb_descriptor_header *) &gs_bulk_interface_desc,
+-      (struct usb_descriptor_header *) &gs_fullspeed_in_desc,
+-      (struct usb_descriptor_header *) &gs_fullspeed_out_desc,
+-      NULL,
+-};
+-
+-static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
+-      (struct usb_descriptor_header *) &gs_otg_descriptor,
+-      (struct usb_descriptor_header *) &gs_control_interface_desc,
+-      (struct usb_descriptor_header *) &gs_header_desc,
+-      (struct usb_descriptor_header *) &gs_call_mgmt_descriptor,
+-      (struct usb_descriptor_header *) &gs_acm_descriptor,
+-      (struct usb_descriptor_header *) &gs_union_desc,
+-      (struct usb_descriptor_header *) &gs_fullspeed_notify_desc,
+-      (struct usb_descriptor_header *) &gs_data_interface_desc,
+-      (struct usb_descriptor_header *) &gs_fullspeed_in_desc,
+-      (struct usb_descriptor_header *) &gs_fullspeed_out_desc,
+-      NULL,
+-};
+-static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-      .bEndpointAddress =     USB_DIR_IN,
+-      .bmAttributes =         USB_ENDPOINT_XFER_INT,
+-      .wMaxPacketSize =       __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
+-      .bInterval =            GS_LOG2_NOTIFY_INTERVAL+4,
+-};
+-
+-static struct usb_endpoint_descriptor gs_highspeed_in_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+-      .wMaxPacketSize =       __constant_cpu_to_le16(512),
+-};
+-
+-static struct usb_endpoint_descriptor gs_highspeed_out_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+-      .wMaxPacketSize =       __constant_cpu_to_le16(512),
+-};
+-
+-static struct usb_qualifier_descriptor gs_qualifier_desc = {
+-      .bLength =              sizeof(struct usb_qualifier_descriptor),
+-      .bDescriptorType =      USB_DT_DEVICE_QUALIFIER,
+-      .bcdUSB =               __constant_cpu_to_le16 (0x0200),
+-      /* assumes ep0 uses the same value for both speeds ... */
+-      .bNumConfigurations =   GS_NUM_CONFIGS,
+-};
+-
+-static const struct usb_descriptor_header *gs_bulk_highspeed_function[] = {
+-      (struct usb_descriptor_header *) &gs_otg_descriptor,
+-      (struct usb_descriptor_header *) &gs_bulk_interface_desc,
+-      (struct usb_descriptor_header *) &gs_highspeed_in_desc,
+-      (struct usb_descriptor_header *) &gs_highspeed_out_desc,
+-      NULL,
++      /* REVISIT SRP-only hardware is possible, although
++       * it would not be called "OTG" ...
++       */
++      .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+ };
+-static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
+-      (struct usb_descriptor_header *) &gs_otg_descriptor,
+-      (struct usb_descriptor_header *) &gs_control_interface_desc,
+-      (struct usb_descriptor_header *) &gs_header_desc,
+-      (struct usb_descriptor_header *) &gs_call_mgmt_descriptor,
+-      (struct usb_descriptor_header *) &gs_acm_descriptor,
+-      (struct usb_descriptor_header *) &gs_union_desc,
+-      (struct usb_descriptor_header *) &gs_highspeed_notify_desc,
+-      (struct usb_descriptor_header *) &gs_data_interface_desc,
+-      (struct usb_descriptor_header *) &gs_highspeed_in_desc,
+-      (struct usb_descriptor_header *) &gs_highspeed_out_desc,
++static const struct usb_descriptor_header *otg_desc[] = {
++      (struct usb_descriptor_header *) &otg_descriptor,
+       NULL,
+ };
+-
+ /*-------------------------------------------------------------------------*/
+ /* Module */
+-MODULE_DESCRIPTION(GS_LONG_NAME);
++MODULE_DESCRIPTION(GS_VERSION_NAME);
+ MODULE_AUTHOR("Al Borchers");
++MODULE_AUTHOR("David Brownell");
+ MODULE_LICENSE("GPL");
+-#ifdef DEBUG
+-module_param(debug, int, S_IRUGO|S_IWUSR);
+-MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
+-#endif
+-
+-static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
+-module_param(read_q_size, uint, S_IRUGO);
+-MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32");
+-
+-static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
+-module_param(write_q_size, uint, S_IRUGO);
+-MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32");
++static int use_acm = true;
++module_param(use_acm, bool, 0);
++MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes");
+-static unsigned int write_buf_size = GS_DEFAULT_WRITE_BUF_SIZE;
+-module_param(write_buf_size, uint, S_IRUGO);
+-MODULE_PARM_DESC(write_buf_size, "Write buffer size, default=8192");
+-
+-static unsigned int use_acm = GS_DEFAULT_USE_ACM;
+-module_param(use_acm, uint, S_IRUGO);
+-MODULE_PARM_DESC(use_acm, "Use CDC ACM, 0=no, 1=yes, default=no");
++static unsigned n_ports = 1;
++module_param(n_ports, uint, 0);
++MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
+ /*-------------------------------------------------------------------------*/
+-/* TTY Driver */
+-
+-/*
+- * gs_open
+- */
+-static int gs_open(struct tty_struct *tty, struct file *file)
+-{
+-      int port_num;
+-      unsigned long flags;
+-      struct gs_port *port;
+-      struct gs_dev *dev;
+-      struct gs_buf *buf;
+-      struct mutex *mtx;
+-      int ret;
+-
+-      port_num = tty->index;
+-
+-      gs_debug("gs_open: (%d,%p,%p)\n", port_num, tty, file);
+-
+-      if (port_num < 0 || port_num >= GS_NUM_PORTS) {
+-              pr_err("gs_open: (%d,%p,%p) invalid port number\n",
+-                      port_num, tty, file);
+-              return -ENODEV;
+-      }
+-
+-      dev = gs_device;
+-
+-      if (dev == NULL) {
+-              pr_err("gs_open: (%d,%p,%p) NULL device pointer\n",
+-                      port_num, tty, file);
+-              return -ENODEV;
+-      }
+-
+-      mtx = &gs_open_close_lock[port_num];
+-      if (mutex_lock_interruptible(mtx)) {
+-              pr_err("gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
+-                      port_num, tty, file);
+-              return -ERESTARTSYS;
+-      }
+-
+-      spin_lock_irqsave(&dev->dev_lock, flags);
+-
+-      if (dev->dev_config == GS_NO_CONFIG_ID) {
+-              pr_err("gs_open: (%d,%p,%p) device is not connected\n",
+-                      port_num, tty, file);
+-              ret = -ENODEV;
+-              goto exit_unlock_dev;
+-      }
+-
+-      port = dev->dev_port[port_num];
+-
+-      if (port == NULL) {
+-              pr_err("gs_open: (%d,%p,%p) NULL port pointer\n",
+-                      port_num, tty, file);
+-              ret = -ENODEV;
+-              goto exit_unlock_dev;
+-      }
+-
+-      spin_lock(&port->port_lock);
+-      spin_unlock(&dev->dev_lock);
+-
+-      if (port->port_dev == NULL) {
+-              pr_err("gs_open: (%d,%p,%p) port disconnected (1)\n",
+-                      port_num, tty, file);
+-              ret = -EIO;
+-              goto exit_unlock_port;
+-      }
+-
+-      if (port->port_open_count > 0) {
+-              ++port->port_open_count;
+-              gs_debug("gs_open: (%d,%p,%p) already open\n",
+-                      port_num, tty, file);
+-              ret = 0;
+-              goto exit_unlock_port;
+-      }
+-
+-      tty->driver_data = NULL;
+-
+-      /* mark port as in use, we can drop port lock and sleep if necessary */
+-      port->port_in_use = 1;
+-
+-      /* allocate write buffer on first open */
+-      if (port->port_write_buf == NULL) {
+-              spin_unlock_irqrestore(&port->port_lock, flags);
+-              buf = gs_buf_alloc(write_buf_size, GFP_KERNEL);
+-              spin_lock_irqsave(&port->port_lock, flags);
+-
+-              /* might have been disconnected while asleep, check */
+-              if (port->port_dev == NULL) {
+-                      pr_err("gs_open: (%d,%p,%p) port disconnected (2)\n",
+-                              port_num, tty, file);
+-                      port->port_in_use = 0;
+-                      ret = -EIO;
+-                      goto exit_unlock_port;
+-              }
+-
+-              if ((port->port_write_buf=buf) == NULL) {
+-                      pr_err("gs_open: (%d,%p,%p) cannot allocate "
+-                              "port write buffer\n",
+-                              port_num, tty, file);
+-                      port->port_in_use = 0;
+-                      ret = -ENOMEM;
+-                      goto exit_unlock_port;
+-              }
+-
+-      }
+-
+-      /* wait for carrier detect (not implemented) */
+-
+-      /* might have been disconnected while asleep, check */
+-      if (port->port_dev == NULL) {
+-              pr_err("gs_open: (%d,%p,%p) port disconnected (3)\n",
+-                      port_num, tty, file);
+-              port->port_in_use = 0;
+-              ret = -EIO;
+-              goto exit_unlock_port;
+-      }
+-
+-      tty->driver_data = port;
+-      port->port_tty = tty;
+-      port->port_open_count = 1;
+-      port->port_in_use = 0;
+-
+-      gs_debug("gs_open: (%d,%p,%p) completed\n", port_num, tty, file);
+-
+-      ret = 0;
+-
+-exit_unlock_port:
+-      spin_unlock_irqrestore(&port->port_lock, flags);
+-      mutex_unlock(mtx);
+-      return ret;
+-
+-exit_unlock_dev:
+-      spin_unlock_irqrestore(&dev->dev_lock, flags);
+-      mutex_unlock(mtx);
+-      return ret;
+-
+-}
+-
+-/*
+- * gs_close
+- */
+-
+-static int gs_write_finished_event_safely(struct gs_port *p)
+-{
+-      int cond;
+-
+-      spin_lock_irq(&(p)->port_lock);
+-      cond = !(p)->port_dev || !gs_buf_data_avail((p)->port_write_buf);
+-      spin_unlock_irq(&(p)->port_lock);
+-      return cond;
+-}
+-
+-static void gs_close(struct tty_struct *tty, struct file *file)
+-{
+-      struct gs_port *port = tty->driver_data;
+-      struct mutex *mtx;
+-
+-      if (port == NULL) {
+-              pr_err("gs_close: NULL port pointer\n");
+-              return;
+-      }
+-
+-      gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file);
+-
+-      mtx = &gs_open_close_lock[port->port_num];
+-      mutex_lock(mtx);
+-
+-      spin_lock_irq(&port->port_lock);
+-
+-      if (port->port_open_count == 0) {
+-              pr_err("gs_close: (%d,%p,%p) port is already closed\n",
+-                      port->port_num, tty, file);
+-              goto exit;
+-      }
+-
+-      if (port->port_open_count > 1) {
+-              --port->port_open_count;
+-              goto exit;
+-      }
+-
+-      /* free disconnected port on final close */
+-      if (port->port_dev == NULL) {
+-              kfree(port);
+-              goto exit;
+-      }
+-
+-      /* mark port as closed but in use, we can drop port lock */
+-      /* and sleep if necessary */
+-      port->port_in_use = 1;
+-      port->port_open_count = 0;
+-
+-      /* wait for write buffer to drain, or */
+-      /* at most GS_CLOSE_TIMEOUT seconds */
+-      if (gs_buf_data_avail(port->port_write_buf) > 0) {
+-              spin_unlock_irq(&port->port_lock);
+-              wait_event_interruptible_timeout(port->port_write_wait,
+-                                      gs_write_finished_event_safely(port),
+-                                      GS_CLOSE_TIMEOUT * HZ);
+-              spin_lock_irq(&port->port_lock);
+-      }
+-
+-      /* free disconnected port on final close */
+-      /* (might have happened during the above sleep) */
+-      if (port->port_dev == NULL) {
+-              kfree(port);
+-              goto exit;
+-      }
+-
+-      gs_buf_clear(port->port_write_buf);
+-
+-      tty->driver_data = NULL;
+-      port->port_tty = NULL;
+-      port->port_in_use = 0;
+-
+-      gs_debug("gs_close: (%d,%p,%p) completed\n",
+-              port->port_num, tty, file);
+-
+-exit:
+-      spin_unlock_irq(&port->port_lock);
+-      mutex_unlock(mtx);
+-}
+-
+-/*
+- * gs_write
+- */
+-static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
++static int __init serial_bind_config(struct usb_configuration *c)
+ {
+-      unsigned long flags;
+-      struct gs_port *port = tty->driver_data;
+-      int ret;
+-
+-      if (port == NULL) {
+-              pr_err("gs_write: NULL port pointer\n");
+-              return -EIO;
+-      }
+-
+-      gs_debug("gs_write: (%d,%p) writing %d bytes\n", port->port_num, tty,
+-              count);
+-
+-      if (count == 0)
+-              return 0;
+-
+-      spin_lock_irqsave(&port->port_lock, flags);
+-
+-      if (port->port_dev == NULL) {
+-              pr_err("gs_write: (%d,%p) port is not connected\n",
+-                      port->port_num, tty);
+-              ret = -EIO;
+-              goto exit;
+-      }
+-
+-      if (port->port_open_count == 0) {
+-              pr_err("gs_write: (%d,%p) port is closed\n",
+-                      port->port_num, tty);
+-              ret = -EBADF;
+-              goto exit;
+-      }
+-
+-      count = gs_buf_put(port->port_write_buf, buf, count);
+-
+-      spin_unlock_irqrestore(&port->port_lock, flags);
+-
+-      gs_send(gs_device);
+-
+-      gs_debug("gs_write: (%d,%p) wrote %d bytes\n", port->port_num, tty,
+-              count);
++      unsigned i;
++      int status = 0;
+-      return count;
+-
+-exit:
+-      spin_unlock_irqrestore(&port->port_lock, flags);
+-      return ret;
+-}
+-
+-/*
+- * gs_put_char
+- */
+-static int gs_put_char(struct tty_struct *tty, unsigned char ch)
+-{
+-      unsigned long flags;
+-      struct gs_port *port = tty->driver_data;
+-      int ret = 0;
+-
+-      if (port == NULL) {
+-              pr_err("gs_put_char: NULL port pointer\n");
+-              return 0;
+-      }
+-
+-      gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+-              port->port_num, tty, ch, __builtin_return_address(0));
+-
+-      spin_lock_irqsave(&port->port_lock, flags);
+-
+-      if (port->port_dev == NULL) {
+-              pr_err("gs_put_char: (%d,%p) port is not connected\n",
+-                      port->port_num, tty);
+-              goto exit;
+-      }
+-
+-      if (port->port_open_count == 0) {
+-              pr_err("gs_put_char: (%d,%p) port is closed\n",
+-                      port->port_num, tty);
+-              goto exit;
+-      }
+-
+-      ret = gs_buf_put(port->port_write_buf, &ch, 1);
+-
+-exit:
+-      spin_unlock_irqrestore(&port->port_lock, flags);
+-      return ret;
+-}
+-
+-/*
+- * gs_flush_chars
+- */
+-static void gs_flush_chars(struct tty_struct *tty)
+-{
+-      unsigned long flags;
+-      struct gs_port *port = tty->driver_data;
+-
+-      if (port == NULL) {
+-              pr_err("gs_flush_chars: NULL port pointer\n");
+-              return;
+-      }
+-
+-      gs_debug("gs_flush_chars: (%d,%p)\n", port->port_num, tty);
+-
+-      spin_lock_irqsave(&port->port_lock, flags);
+-
+-      if (port->port_dev == NULL) {
+-              pr_err("gs_flush_chars: (%d,%p) port is not connected\n",
+-                      port->port_num, tty);
+-              goto exit;
+-      }
+-
+-      if (port->port_open_count == 0) {
+-              pr_err("gs_flush_chars: (%d,%p) port is closed\n",
+-                      port->port_num, tty);
+-              goto exit;
+-      }
+-
+-      spin_unlock_irqrestore(&port->port_lock, flags);
+-
+-      gs_send(gs_device);
+-
+-      return;
+-
+-exit:
+-      spin_unlock_irqrestore(&port->port_lock, flags);
+-}
+-
+-/*
+- * gs_write_room
+- */
+-static int gs_write_room(struct tty_struct *tty)
+-{
+-
+-      int room = 0;
+-      unsigned long flags;
+-      struct gs_port *port = tty->driver_data;
+-
+-
+-      if (port == NULL)
+-              return 0;
+-
+-      spin_lock_irqsave(&port->port_lock, flags);
+-
+-      if (port->port_dev != NULL && port->port_open_count > 0
+-      && port->port_write_buf != NULL)
+-              room = gs_buf_space_avail(port->port_write_buf);
+-
+-      spin_unlock_irqrestore(&port->port_lock, flags);
+-
+-      gs_debug("gs_write_room: (%d,%p) room=%d\n",
+-              port->port_num, tty, room);
+-
+-      return room;
+-}
+-
+-/*
+- * gs_chars_in_buffer
+- */
+-static int gs_chars_in_buffer(struct tty_struct *tty)
+-{
+-      int chars = 0;
+-      unsigned long flags;
+-      struct gs_port *port = tty->driver_data;
+-
+-      if (port == NULL)
+-              return 0;
+-
+-      spin_lock_irqsave(&port->port_lock, flags);
+-
+-      if (port->port_dev != NULL && port->port_open_count > 0
+-      && port->port_write_buf != NULL)
+-              chars = gs_buf_data_avail(port->port_write_buf);
+-
+-      spin_unlock_irqrestore(&port->port_lock, flags);
+-
+-      gs_debug("gs_chars_in_buffer: (%d,%p) chars=%d\n",
+-              port->port_num, tty, chars);
+-
+-      return chars;
+-}
+-
+-/*
+- * gs_throttle
+- */
+-static void gs_throttle(struct tty_struct *tty)
+-{
+-}
+-
+-/*
+- * gs_unthrottle
+- */
+-static void gs_unthrottle(struct tty_struct *tty)
+-{
+-}
+-
+-/*
+- * gs_break
+- */
+-static void gs_break(struct tty_struct *tty, int break_state)
+-{
+-}
+-
+-/*
+- * gs_ioctl
+- */
+-static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+-{
+-      struct gs_port *port = tty->driver_data;
+-
+-      if (port == NULL) {
+-              pr_err("gs_ioctl: NULL port pointer\n");
+-              return -EIO;
++      for (i = 0; i < n_ports && status == 0; i++) {
++              if (use_acm)
++                      status = acm_bind_config(c, i);
++              else
++                      status = gser_bind_config(c, i);
+       }
+-
+-      gs_debug("gs_ioctl: (%d,%p,%p) cmd=0x%4.4x, arg=%lu\n",
+-              port->port_num, tty, file, cmd, arg);
+-
+-      /* handle ioctls */
+-
+-      /* could not handle ioctl */
+-      return -ENOIOCTLCMD;
+-}
+-
+-/*
+- * gs_set_termios
+- */
+-static void gs_set_termios(struct tty_struct *tty, struct ktermios *old)
+-{
++      return status;
+ }
+-static const struct tty_operations gs_tty_ops = {
+-      .open =                 gs_open,
+-      .close =                gs_close,
+-      .write =                gs_write,
+-      .put_char =             gs_put_char,
+-      .flush_chars =          gs_flush_chars,
+-      .write_room =           gs_write_room,
+-      .ioctl =                gs_ioctl,
+-      .set_termios =          gs_set_termios,
+-      .throttle =             gs_throttle,
+-      .unthrottle =           gs_unthrottle,
+-      .break_ctl =            gs_break,
+-      .chars_in_buffer =      gs_chars_in_buffer,
++static struct usb_configuration serial_config_driver = {
++      /* .label = f(use_acm) */
++      .bind           = serial_bind_config,
++      /* .bConfigurationValue = f(use_acm) */
++      /* .iConfiguration = DYNAMIC */
++      .bmAttributes   = USB_CONFIG_ATT_SELFPOWER,
++      .bMaxPower      = 1,    /* 2 mA, minimal */
+ };
+-/*-------------------------------------------------------------------------*/
+-
+-/*
+-* gs_send
+-*
+-* This function finds available write requests, calls
+-* gs_send_packet to fill these packets with data, and
+-* continues until either there are no more write requests
+-* available or no more data to send.  This function is
+-* run whenever data arrives or write requests are available.
+-*/
+-static int gs_send(struct gs_dev *dev)
+-{
+-      int ret,len;
+-      unsigned long flags;
+-      struct usb_ep *ep;
+-      struct usb_request *req;
+-
+-      if (dev == NULL) {
+-              pr_err("gs_send: NULL device pointer\n");
+-              return -ENODEV;
+-      }
+-
+-      spin_lock_irqsave(&dev->dev_lock, flags);
+-
+-      ep = dev->dev_in_ep;
+-
+-      while(!list_empty(&dev->dev_req_list)) {
+-
+-              req = list_entry(dev->dev_req_list.next,
+-                              struct usb_request, list);
+-
+-              len = gs_send_packet(dev, req->buf, ep->maxpacket);
+-
+-              if (len > 0) {
+-                      gs_debug_level(3, "gs_send: len=%d, 0x%2.2x "
+-                                      "0x%2.2x 0x%2.2x ...\n", len,
+-                                      *((unsigned char *)req->buf),
+-                                      *((unsigned char *)req->buf+1),
+-                                      *((unsigned char *)req->buf+2));
+-                      list_del(&req->list);
+-                      req->length = len;
+-                      spin_unlock_irqrestore(&dev->dev_lock, flags);
+-                      if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
+-                              pr_err(
+-                              "gs_send: cannot queue read request, ret=%d\n",
+-                                      ret);
+-                              spin_lock_irqsave(&dev->dev_lock, flags);
+-                              break;
+-                      }
+-                      spin_lock_irqsave(&dev->dev_lock, flags);
+-              } else {
+-                      break;
+-              }
+-
+-      }
+-
+-      spin_unlock_irqrestore(&dev->dev_lock, flags);
+-
+-      return 0;
+-}
+-
+-/*
+- * gs_send_packet
+- *
+- * If there is data to send, a packet is built in the given
+- * buffer and the size is returned.  If there is no data to
+- * send, 0 is returned.  If there is any error a negative
+- * error number is returned.
+- *
+- * Called during USB completion routine, on interrupt time.
+- *
+- * We assume that disconnect will not happen until all completion
+- * routines have completed, so we can assume that the dev_port
+- * array does not change during the lifetime of this function.
+- */
+-static int gs_send_packet(struct gs_dev *dev, char *packet, unsigned int size)
+-{
+-      unsigned int len;
+-      struct gs_port *port;
+-
+-      /* TEMPORARY -- only port 0 is supported right now */
+-      port = dev->dev_port[0];
+-
+-      if (port == NULL) {
+-              pr_err("gs_send_packet: port=%d, NULL port pointer\n", 0);
+-              return -EIO;
+-      }
+-
+-      spin_lock(&port->port_lock);
+-
+-      len = gs_buf_data_avail(port->port_write_buf);
+-      if (len < size)
+-              size = len;
+-
+-      if (size == 0)
+-              goto exit;
+-
+-      size = gs_buf_get(port->port_write_buf, packet, size);
+-
+-      if (port->port_tty)
+-              wake_up_interruptible(&port->port_tty->write_wait);
+-
+-exit:
+-      spin_unlock(&port->port_lock);
+-      return size;
+-}
+-
+-/*
+- * gs_recv_packet
+- *
+- * Called for each USB packet received.  Reads the packet
+- * header and stuffs the data in the appropriate tty buffer.
+- * Returns 0 if successful, or a negative error number.
+- *
+- * Called during USB completion routine, on interrupt time.
+- *
+- * We assume that disconnect will not happen until all completion
+- * routines have completed, so we can assume that the dev_port
+- * array does not change during the lifetime of this function.
+- */
+-static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size)
+-{
+-      unsigned int len;
+-      struct gs_port *port;
+-      int ret;
+-      struct tty_struct *tty;
+-
+-      /* TEMPORARY -- only port 0 is supported right now */
+-      port = dev->dev_port[0];
+-
+-      if (port == NULL) {
+-              pr_err("gs_recv_packet: port=%d, NULL port pointer\n",
+-                      port->port_num);
+-              return -EIO;
+-      }
+-
+-      spin_lock(&port->port_lock);
+-
+-      if (port->port_open_count == 0) {
+-              pr_err("gs_recv_packet: port=%d, port is closed\n",
+-                      port->port_num);
+-              ret = -EIO;
+-              goto exit;
+-      }
+-
+-
+-      tty = port->port_tty;
+-
+-      if (tty == NULL) {
+-              pr_err("gs_recv_packet: port=%d, NULL tty pointer\n",
+-                      port->port_num);
+-              ret = -EIO;
+-              goto exit;
+-      }
+-
+-      if (port->port_tty->magic != TTY_MAGIC) {
+-              pr_err("gs_recv_packet: port=%d, bad tty magic\n",
+-                      port->port_num);
+-              ret = -EIO;
+-              goto exit;
+-      }
+-
+-      len = tty_buffer_request_room(tty, size);
+-      if (len > 0) {
+-              tty_insert_flip_string(tty, packet, len);
+-              tty_flip_buffer_push(port->port_tty);
+-              wake_up_interruptible(&port->port_tty->read_wait);
+-      }
+-      ret = 0;
+-exit:
+-      spin_unlock(&port->port_lock);
+-      return ret;
+-}
+-
+-/*
+-* gs_read_complete
+-*/
+-static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
++static int __init gs_bind(struct usb_composite_dev *cdev)
+ {
+-      int ret;
+-      struct gs_dev *dev = ep->driver_data;
+-
+-      if (dev == NULL) {
+-              pr_err("gs_read_complete: NULL device pointer\n");
+-              return;
+-      }
++      int                     gcnum;
++      struct usb_gadget       *gadget = cdev->gadget;
++      int                     status;
+-      switch(req->status) {
+-      case 0:
+-              /* normal completion */
+-              gs_recv_packet(dev, req->buf, req->actual);
+-requeue:
+-              req->length = ep->maxpacket;
+-              if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
+-                      pr_err(
+-                      "gs_read_complete: cannot queue read request, ret=%d\n",
+-                              ret);
+-              }
+-              break;
+-
+-      case -ESHUTDOWN:
+-              /* disconnect */
+-              gs_debug("gs_read_complete: shutdown\n");
+-              gs_free_req(ep, req);
+-              break;
+-
+-      default:
+-              /* unexpected */
+-              pr_err(
+-              "gs_read_complete: unexpected status error, status=%d\n",
+-                      req->status);
+-              goto requeue;
+-              break;
+-      }
+-}
+-
+-/*
+-* gs_write_complete
+-*/
+-static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
+-{
+-      struct gs_dev *dev = ep->driver_data;
+-
+-      if (dev == NULL) {
+-              pr_err("gs_write_complete: NULL device pointer\n");
+-              return;
+-      }
++      status = gserial_setup(cdev->gadget, n_ports);
++      if (status < 0)
++              return status;
+-      switch(req->status) {
+-      case 0:
+-              /* normal completion */
+-requeue:
+-              spin_lock(&dev->dev_lock);
+-              list_add(&req->list, &dev->dev_req_list);
+-              spin_unlock(&dev->dev_lock);
+-
+-              gs_send(dev);
+-
+-              break;
+-
+-      case -ESHUTDOWN:
+-              /* disconnect */
+-              gs_debug("gs_write_complete: shutdown\n");
+-              gs_free_req(ep, req);
+-              break;
+-
+-      default:
+-              pr_err(
+-              "gs_write_complete: unexpected status error, status=%d\n",
+-                      req->status);
+-              goto requeue;
+-              break;
+-      }
+-}
++      /* Allocate string descriptor numbers ... note that string
++       * contents can be overridden by the composite_dev glue.
++       */
+-/*-------------------------------------------------------------------------*/
++      /* device description: manufacturer, product */
++      snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
++              init_utsname()->sysname, init_utsname()->release,
++              gadget->name);
++      status = usb_string_id(cdev);
++      if (status < 0)
++              goto fail;
++      strings_dev[STRING_MANUFACTURER_IDX].id = status;
+-/* Gadget Driver */
++      device_desc.iManufacturer = status;
+-/*
+- * gs_unbind
+- *
+- * Called on module unload.  Frees the control request and device
+- * structure.
+- */
+-static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
+-{
+-      struct gs_dev *dev = get_gadget_data(gadget);
++      status = usb_string_id(cdev);
++      if (status < 0)
++              goto fail;
++      strings_dev[STRING_PRODUCT_IDX].id = status;
+-      gs_device = NULL;
++      device_desc.iProduct = status;
+-      /* read/write requests already freed, only control request remains */
+-      if (dev != NULL) {
+-              if (dev->dev_ctrl_req != NULL) {
+-                      gs_free_req(gadget->ep0, dev->dev_ctrl_req);
+-                      dev->dev_ctrl_req = NULL;
+-              }
+-              gs_reset_config(dev);
+-              gs_free_ports(dev);
+-              kfree(dev);
+-              set_gadget_data(gadget, NULL);
+-      }
++      /* config description */
++      status = usb_string_id(cdev);
++      if (status < 0)
++              goto fail;
++      strings_dev[STRING_DESCRIPTION_IDX].id = status;
+-      pr_info("gs_unbind: %s %s unbound\n", GS_LONG_NAME,
+-              GS_VERSION_STR);
+-}
+-
+-/*
+- * gs_bind
+- *
+- * Called on module load.  Allocates and initializes the device
+- * structure and a control request.
+- */
+-static int __init gs_bind(struct usb_gadget *gadget)
+-{
+-      int ret;
+-      struct usb_ep *ep;
+-      struct gs_dev *dev;
+-      int gcnum;
+-
+-      /* Some controllers can't support CDC ACM:
+-       * - sh doesn't support multiple interfaces or configs;
+-       * - sa1100 doesn't have a third interrupt endpoint
+-       */
+-      if (gadget_is_sh(gadget) || gadget_is_sa1100(gadget))
+-              use_acm = 0;
++      serial_config_driver.iConfiguration = status;
++      /* set up other descriptors */
+       gcnum = usb_gadget_controller_number(gadget);
+       if (gcnum >= 0)
+-              gs_device_desc.bcdDevice =
+-                              cpu_to_le16(GS_VERSION_NUM | gcnum);
++              device_desc.bcdDevice = cpu_to_le16(GS_VERSION_NUM | gcnum);
+       else {
++              /* this is so simple (for now, no altsettings) that it
++               * SHOULD NOT have problems with bulk-capable hardware.
++               * so warn about unrcognized controllers -- don't panic.
++               *
++               * things like configuration and altsetting numbering
++               * can need hardware-specific attention though.
++               */
+               pr_warning("gs_bind: controller '%s' not recognized\n",
+                       gadget->name);
+-              /* unrecognized, but safe unless bulk is REALLY quirky */
+-              gs_device_desc.bcdDevice =
+-                      __constant_cpu_to_le16(GS_VERSION_NUM|0x0099);
+-      }
+-
+-      dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
+-      if (dev == NULL)
+-              return -ENOMEM;
+-
+-      usb_ep_autoconfig_reset(gadget);
+-
+-      ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc);
+-      if (!ep)
+-              goto autoconf_fail;
+-      dev->dev_in_ep = ep;
+-      ep->driver_data = dev;  /* claim the endpoint */
+-
+-      ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc);
+-      if (!ep)
+-              goto autoconf_fail;
+-      dev->dev_out_ep = ep;
+-      ep->driver_data = dev;  /* claim the endpoint */
+-
+-      if (use_acm) {
+-              ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc);
+-              if (!ep) {
+-                      pr_err("gs_bind: cannot run ACM on %s\n", gadget->name);
+-                      goto autoconf_fail;
+-              }
+-              gs_device_desc.idProduct = __constant_cpu_to_le16(
+-                                              GS_CDC_PRODUCT_ID),
+-              dev->dev_notify_ep = ep;
+-              ep->driver_data = dev;  /* claim the endpoint */
+-      }
+-
+-      gs_device_desc.bDeviceClass = use_acm
+-              ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+-      gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+-
+-      if (gadget_is_dualspeed(gadget)) {
+-              gs_qualifier_desc.bDeviceClass = use_acm
+-                      ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+-              /* assume ep0 uses the same packet size for both speeds */
+-              gs_qualifier_desc.bMaxPacketSize0 =
+-                      gs_device_desc.bMaxPacketSize0;
+-              /* assume endpoints are dual-speed */
+-              gs_highspeed_notify_desc.bEndpointAddress =
+-                      gs_fullspeed_notify_desc.bEndpointAddress;
+-              gs_highspeed_in_desc.bEndpointAddress =
+-                      gs_fullspeed_in_desc.bEndpointAddress;
+-              gs_highspeed_out_desc.bEndpointAddress =
+-                      gs_fullspeed_out_desc.bEndpointAddress;
+-      }
+-
+-      usb_gadget_set_selfpowered(gadget);
+-
+-      if (gadget_is_otg(gadget)) {
+-              gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
+-              gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+-              gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++              device_desc.bcdDevice =
++                      __constant_cpu_to_le16(GS_VERSION_NUM | 0x0099);
+       }
+-      gs_device = dev;
+-
+-      snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
+-              init_utsname()->sysname, init_utsname()->release,
+-              gadget->name);
+-
+-      dev->dev_gadget = gadget;
+-      spin_lock_init(&dev->dev_lock);
+-      INIT_LIST_HEAD(&dev->dev_req_list);
+-      set_gadget_data(gadget, dev);
+-
+-      if ((ret=gs_alloc_ports(dev, GFP_KERNEL)) != 0) {
+-              pr_err("gs_bind: cannot allocate ports\n");
+-              gs_unbind(gadget);
+-              return ret;
++      if (gadget_is_otg(cdev->gadget)) {
++              serial_config_driver.descriptors = otg_desc;
++              serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+-      /* preallocate control response and buffer */
+-      dev->dev_ctrl_req = gs_alloc_req(gadget->ep0, GS_MAX_DESC_LEN,
+-              GFP_KERNEL);
+-      if (dev->dev_ctrl_req == NULL) {
+-              gs_unbind(gadget);
+-              return -ENOMEM;
+-      }
+-      gadget->ep0->driver_data = dev;
++      /* register our configuration */
++      status = usb_add_config(cdev, &serial_config_driver);
++      if (status < 0)
++              goto fail;
+-      pr_info("gs_bind: %s %s bound\n",
+-              GS_LONG_NAME, GS_VERSION_STR);
++      INFO(cdev, "%s\n", GS_VERSION_NAME);
+       return 0;
+-autoconf_fail:
+-      kfree(dev);
+-      pr_err("gs_bind: cannot autoconfigure on %s\n", gadget->name);
+-      return -ENODEV;
+-}
+-
+-static int gs_setup_standard(struct usb_gadget *gadget,
+-      const struct usb_ctrlrequest *ctrl)
+-{
+-      int ret = -EOPNOTSUPP;
+-      struct gs_dev *dev = get_gadget_data(gadget);
+-      struct usb_request *req = dev->dev_ctrl_req;
+-      u16 wIndex = le16_to_cpu(ctrl->wIndex);
+-      u16 wValue = le16_to_cpu(ctrl->wValue);
+-      u16 wLength = le16_to_cpu(ctrl->wLength);
+-
+-      switch (ctrl->bRequest) {
+-      case USB_REQ_GET_DESCRIPTOR:
+-              if (ctrl->bRequestType != USB_DIR_IN)
+-                      break;
+-
+-              switch (wValue >> 8) {
+-              case USB_DT_DEVICE:
+-                      ret = min(wLength,
+-                              (u16)sizeof(struct usb_device_descriptor));
+-                      memcpy(req->buf, &gs_device_desc, ret);
+-                      break;
+-
+-              case USB_DT_DEVICE_QUALIFIER:
+-                      if (!gadget_is_dualspeed(gadget))
+-                              break;
+-                      ret = min(wLength,
+-                              (u16)sizeof(struct usb_qualifier_descriptor));
+-                      memcpy(req->buf, &gs_qualifier_desc, ret);
+-                      break;
+-
+-              case USB_DT_OTHER_SPEED_CONFIG:
+-                      if (!gadget_is_dualspeed(gadget))
+-                              break;
+-                      /* fall through */
+-              case USB_DT_CONFIG:
+-                      ret = gs_build_config_buf(req->buf, gadget,
+-                              wValue >> 8, wValue & 0xff,
+-                              gadget_is_otg(gadget));
+-                      if (ret >= 0)
+-                              ret = min(wLength, (u16)ret);
+-                      break;
+-
+-              case USB_DT_STRING:
+-                      /* wIndex == language code. */
+-                      ret = usb_gadget_get_string(&gs_string_table,
+-                              wValue & 0xff, req->buf);
+-                      if (ret >= 0)
+-                              ret = min(wLength, (u16)ret);
+-                      break;
+-              }
+-              break;
+-
+-      case USB_REQ_SET_CONFIGURATION:
+-              if (ctrl->bRequestType != 0)
+-                      break;
+-              spin_lock(&dev->dev_lock);
+-              ret = gs_set_config(dev, wValue);
+-              spin_unlock(&dev->dev_lock);
+-              break;
+-
+-      case USB_REQ_GET_CONFIGURATION:
+-              if (ctrl->bRequestType != USB_DIR_IN)
+-                      break;
+-              *(u8 *)req->buf = dev->dev_config;
+-              ret = min(wLength, (u16)1);
+-              break;
+-
+-      case USB_REQ_SET_INTERFACE:
+-              if (ctrl->bRequestType != USB_RECIP_INTERFACE
+-                              || !dev->dev_config
+-                              || wIndex >= GS_MAX_NUM_INTERFACES)
+-                      break;
+-              if (dev->dev_config == GS_BULK_CONFIG_ID
+-                              && wIndex != GS_BULK_INTERFACE_ID)
+-                      break;
+-              /* no alternate interface settings */
+-              if (wValue != 0)
+-                      break;
+-              spin_lock(&dev->dev_lock);
+-              /* PXA hardware partially handles SET_INTERFACE;
+-               * we need to kluge around that interference.  */
+-              if (gadget_is_pxa(gadget)) {
+-                      ret = gs_set_config(dev, use_acm ?
+-                              GS_ACM_CONFIG_ID : GS_BULK_CONFIG_ID);
+-                      goto set_interface_done;
+-              }
+-              if (dev->dev_config != GS_BULK_CONFIG_ID
+-                              && wIndex == GS_CONTROL_INTERFACE_ID) {
+-                      if (dev->dev_notify_ep) {
+-                              usb_ep_disable(dev->dev_notify_ep);
+-                              usb_ep_enable(dev->dev_notify_ep, dev->dev_notify_ep_desc);
+-                      }
+-              } else {
+-                      usb_ep_disable(dev->dev_in_ep);
+-                      usb_ep_disable(dev->dev_out_ep);
+-                      usb_ep_enable(dev->dev_in_ep, dev->dev_in_ep_desc);
+-                      usb_ep_enable(dev->dev_out_ep, dev->dev_out_ep_desc);
+-              }
+-              ret = 0;
+-set_interface_done:
+-              spin_unlock(&dev->dev_lock);
+-              break;
+-
+-      case USB_REQ_GET_INTERFACE:
+-              if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
+-              || dev->dev_config == GS_NO_CONFIG_ID)
+-                      break;
+-              if (wIndex >= GS_MAX_NUM_INTERFACES
+-                              || (dev->dev_config == GS_BULK_CONFIG_ID
+-                              && wIndex != GS_BULK_INTERFACE_ID)) {
+-                      ret = -EDOM;
+-                      break;
+-              }
+-              /* no alternate interface settings */
+-              *(u8 *)req->buf = 0;
+-              ret = min(wLength, (u16)1);
+-              break;
+-
+-      default:
+-              pr_err("gs_setup: unknown standard request, type=%02x, "
+-                      "request=%02x, value=%04x, index=%04x, length=%d\n",
+-                      ctrl->bRequestType, ctrl->bRequest,
+-                      wValue, wIndex, wLength);
+-              break;
+-      }
+-
+-      return ret;
++fail:
++      gserial_cleanup();
++      return status;
+ }
+-static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
+-              struct usb_request *req)
+-{
+-      struct gs_dev *dev = ep->driver_data;
+-      struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
+-
+-      switch (req->status) {
+-      case 0:
+-              /* normal completion */
+-              if (req->actual != sizeof(port->port_line_coding))
+-                      usb_ep_set_halt(ep);
+-              else if (port) {
+-                      struct usb_cdc_line_coding      *value = req->buf;
+-
+-                      /* REVISIT:  we currently just remember this data.
+-                       * If we change that, (a) validate it first, then
+-                       * (b) update whatever hardware needs updating.
+-                       */
+-                      spin_lock(&port->port_lock);
+-                      port->port_line_coding = *value;
+-                      spin_unlock(&port->port_lock);
+-              }
+-              break;
+-
+-      case -ESHUTDOWN:
+-              /* disconnect */
+-              gs_free_req(ep, req);
+-              break;
+-
+-      default:
+-              /* unexpected */
+-              break;
+-      }
+-      return;
+-}
+-
+-static int gs_setup_class(struct usb_gadget *gadget,
+-      const struct usb_ctrlrequest *ctrl)
+-{
+-      int ret = -EOPNOTSUPP;
+-      struct gs_dev *dev = get_gadget_data(gadget);
+-      struct gs_port *port = dev->dev_port[0];        /* ACM only has one port */
+-      struct usb_request *req = dev->dev_ctrl_req;
+-      u16 wIndex = le16_to_cpu(ctrl->wIndex);
+-      u16 wValue = le16_to_cpu(ctrl->wValue);
+-      u16 wLength = le16_to_cpu(ctrl->wLength);
+-
+-      switch (ctrl->bRequest) {
+-      case USB_CDC_REQ_SET_LINE_CODING:
+-              if (wLength != sizeof(struct usb_cdc_line_coding))
+-                      break;
+-              ret = wLength;
+-              req->complete = gs_setup_complete_set_line_coding;
+-              break;
+-
+-      case USB_CDC_REQ_GET_LINE_CODING:
+-              ret = min_t(int, wLength, sizeof(struct usb_cdc_line_coding));
+-              if (port) {
+-                      spin_lock(&port->port_lock);
+-                      memcpy(req->buf, &port->port_line_coding, ret);
+-                      spin_unlock(&port->port_lock);
+-              }
+-              break;
+-
+-      case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+-              if (wLength != 0)
+-                      break;
+-              ret = 0;
+-              if (port) {
+-                      /* REVISIT:  we currently just remember this data.
+-                       * If we change that, update whatever hardware needs
+-                       * updating.
+-                       */
+-                      spin_lock(&port->port_lock);
+-                      port->port_handshake_bits = wValue;
+-                      spin_unlock(&port->port_lock);
+-              }
+-              break;
+-
+-      default:
+-              /* NOTE:  strictly speaking, we should accept AT-commands
+-               * using SEND_ENCPSULATED_COMMAND/GET_ENCAPSULATED_RESPONSE.
+-               * But our call management descriptor says we don't handle
+-               * call management, so we should be able to get by without
+-               * handling those "required" commands (except by stalling).
+-               */
+-              pr_err("gs_setup: unknown class request, "
+-                              "type=%02x, request=%02x, value=%04x, "
+-                              "index=%04x, length=%d\n",
+-                      ctrl->bRequestType, ctrl->bRequest,
+-                      wValue, wIndex, wLength);
+-              break;
+-      }
+-
+-      return ret;
+-}
+-
+-/*
+- * gs_setup_complete
+- */
+-static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req)
+-{
+-      if (req->status || req->actual != req->length) {
+-              pr_err("gs_setup_complete: status error, status=%d, "
+-                      "actual=%d, length=%d\n",
+-                      req->status, req->actual, req->length);
+-      }
+-}
+-
+-/*
+- * gs_setup
+- *
+- * Implements all the control endpoint functionality that's not
+- * handled in hardware or the hardware driver.
+- *
+- * Returns the size of the data sent to the host, or a negative
+- * error number.
+- */
+-static int gs_setup(struct usb_gadget *gadget,
+-      const struct usb_ctrlrequest *ctrl)
+-{
+-      int             ret = -EOPNOTSUPP;
+-      struct gs_dev   *dev = get_gadget_data(gadget);
+-      struct usb_request *req = dev->dev_ctrl_req;
+-      u16             wIndex = le16_to_cpu(ctrl->wIndex);
+-      u16             wValue = le16_to_cpu(ctrl->wValue);
+-      u16             wLength = le16_to_cpu(ctrl->wLength);
+-
+-      req->complete = gs_setup_complete;
+-
+-      switch (ctrl->bRequestType & USB_TYPE_MASK) {
+-      case USB_TYPE_STANDARD:
+-              ret = gs_setup_standard(gadget, ctrl);
+-              break;
+-
+-      case USB_TYPE_CLASS:
+-              ret = gs_setup_class(gadget, ctrl);
+-              break;
+-
+-      default:
+-              pr_err("gs_setup: unknown request, type=%02x, request=%02x, "
+-                      "value=%04x, index=%04x, length=%d\n",
+-                      ctrl->bRequestType, ctrl->bRequest,
+-                      wValue, wIndex, wLength);
+-              break;
+-      }
+-
+-      /* respond with data transfer before status phase? */
+-      if (ret >= 0) {
+-              req->length = ret;
+-              req->zero = ret < wLength
+-                              && (ret % gadget->ep0->maxpacket) == 0;
+-              ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+-              if (ret < 0) {
+-                      pr_err("gs_setup: cannot queue response, ret=%d\n",
+-                              ret);
+-                      req->status = 0;
+-                      gs_setup_complete(gadget->ep0, req);
+-              }
+-      }
+-
+-      /* device either stalls (ret < 0) or reports success */
+-      return ret;
+-}
+-
+-/*
+- * gs_disconnect
+- *
+- * Called when the device is disconnected.  Frees the closed
+- * ports and disconnects open ports.  Open ports will be freed
+- * on close.  Then reallocates the ports for the next connection.
+- */
+-static void gs_disconnect(struct usb_gadget *gadget)
+-{
+-      unsigned long flags;
+-      struct gs_dev *dev = get_gadget_data(gadget);
+-
+-      spin_lock_irqsave(&dev->dev_lock, flags);
+-
+-      gs_reset_config(dev);
+-
+-      /* free closed ports and disconnect open ports */
+-      /* (open ports will be freed when closed) */
+-      gs_free_ports(dev);
+-
+-      /* re-allocate ports for the next connection */
+-      if (gs_alloc_ports(dev, GFP_ATOMIC) != 0)
+-              pr_err("gs_disconnect: cannot re-allocate ports\n");
+-
+-      spin_unlock_irqrestore(&dev->dev_lock, flags);
+-
+-      pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME);
+-}
+-
+-static struct usb_gadget_driver gs_gadget_driver = {
+-#ifdef CONFIG_USB_GADGET_DUALSPEED
+-      .speed =                USB_SPEED_HIGH,
+-#else
+-      .speed =                USB_SPEED_FULL,
+-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+-      .function =             GS_LONG_NAME,
+-      .bind =                 gs_bind,
+-      .unbind =               gs_unbind,
+-      .setup =                gs_setup,
+-      .disconnect =           gs_disconnect,
+-      .driver = {
+-              .name =         GS_SHORT_NAME,
+-              .owner =        THIS_MODULE,
+-      },
++static struct usb_composite_driver gserial_driver = {
++      .name           = "g_serial",
++      .dev            = &device_desc,
++      .strings        = dev_strings,
++      .bind           = gs_bind,
+ };
+-/*
+- * gs_set_config
+- *
+- * Configures the device by enabling device specific
+- * optimizations, setting up the endpoints, allocating
+- * read and write requests and queuing read requests.
+- *
+- * The device lock must be held when calling this function.
+- */
+-static int gs_set_config(struct gs_dev *dev, unsigned config)
++static int __init init(void)
+ {
+-      int i;
+-      int ret = 0;
+-      struct usb_gadget *gadget = dev->dev_gadget;
+-      struct usb_ep *ep;
+-      struct usb_endpoint_descriptor *out, *in, *notify;
+-      struct usb_request *req;
+-
+-      if (dev == NULL) {
+-              pr_err("gs_set_config: NULL device pointer\n");
+-              return 0;
+-      }
+-
+-      if (config == dev->dev_config)
+-              return 0;
+-
+-      gs_reset_config(dev);
+-
+-      switch (config) {
+-      case GS_NO_CONFIG_ID:
+-              return 0;
+-      case GS_BULK_CONFIG_ID:
+-              if (use_acm)
+-                      return -EINVAL;
+-              break;
+-      case GS_ACM_CONFIG_ID:
+-              if (!use_acm)
+-                      return -EINVAL;
+-              break;
+-      default:
+-              return -EINVAL;
+-      }
+-
+-      in = choose_ep_desc(gadget,
+-                      &gs_highspeed_in_desc,
+-                      &gs_fullspeed_in_desc);
+-      out = choose_ep_desc(gadget,
+-                      &gs_highspeed_out_desc,
+-                      &gs_fullspeed_out_desc);
+-      notify = dev->dev_notify_ep
+-              ? choose_ep_desc(gadget,
+-                              &gs_highspeed_notify_desc,
+-                              &gs_fullspeed_notify_desc)
+-              : NULL;
+-
+-      ret = usb_ep_enable(dev->dev_in_ep, in);
+-      if (ret == 0) {
+-              dev->dev_in_ep_desc = in;
+-      } else {
+-              pr_debug("%s: cannot enable %s %s, ret=%d\n",
+-                      __func__, "IN", dev->dev_in_ep->name, ret);
+-              return ret;
+-      }
+-
+-      ret = usb_ep_enable(dev->dev_out_ep, out);
+-      if (ret == 0) {
+-              dev->dev_out_ep_desc = out;
+-      } else {
+-              pr_debug("%s: cannot enable %s %s, ret=%d\n",
+-                      __func__, "OUT", dev->dev_out_ep->name, ret);
+-fail0:
+-              usb_ep_disable(dev->dev_in_ep);
+-              return ret;
+-      }
+-
+-      if (notify) {
+-              ret = usb_ep_enable(dev->dev_notify_ep, notify);
+-              if (ret == 0) {
+-                      dev->dev_notify_ep_desc = notify;
+-              } else {
+-                      pr_debug("%s: cannot enable %s %s, ret=%d\n",
+-                              __func__, "NOTIFY",
+-                              dev->dev_notify_ep->name, ret);
+-                      usb_ep_disable(dev->dev_out_ep);
+-                      goto fail0;
+-              }
+-      }
+-
+-      dev->dev_config = config;
+-
+-      /* allocate and queue read requests */
+-      ep = dev->dev_out_ep;
+-      for (i=0; i<read_q_size && ret == 0; i++) {
+-              if ((req=gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC))) {
+-                      req->complete = gs_read_complete;
+-                      if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
+-                              pr_err("gs_set_config: cannot queue read "
+-                                      "request, ret=%d\n", ret);
+-                      }
+-              } else {
+-                      pr_err("gs_set_config: cannot allocate "
+-                                      "read requests\n");
+-                      ret = -ENOMEM;
+-                      goto exit_reset_config;
+-              }
+-      }
+-
+-      /* allocate write requests, and put on free list */
+-      ep = dev->dev_in_ep;
+-      for (i=0; i<write_q_size; i++) {
+-              req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
+-              if (req) {
+-                      req->complete = gs_write_complete;
+-                      list_add(&req->list, &dev->dev_req_list);
+-              } else {
+-                      pr_err("gs_set_config: cannot allocate "
+-                                      "write requests\n");
+-                      ret = -ENOMEM;
+-                      goto exit_reset_config;
+-              }
+-      }
+-
+-      /* REVISIT the ACM mode should be able to actually *issue* some
+-       * notifications, for at least serial state change events if
+-       * not also for network connection; say so in bmCapabilities.
++      /* We *could* export two configs; that'd be much cleaner...
++       * but neither of these product IDs was defined that way.
+        */
+-
+-      pr_info("gs_set_config: %s configured, %s speed %s config\n",
+-              GS_LONG_NAME,
+-              gadget->speed == USB_SPEED_HIGH ? "high" : "full",
+-              config == GS_BULK_CONFIG_ID ? "BULK" : "CDC-ACM");
+-
+-      return 0;
+-
+-exit_reset_config:
+-      gs_reset_config(dev);
+-      return ret;
+-}
+-
+-/*
+- * gs_reset_config
+- *
+- * Mark the device as not configured, disable all endpoints,
+- * which forces completion of pending I/O and frees queued
+- * requests, and free the remaining write requests on the
+- * free list.
+- *
+- * The device lock must be held when calling this function.
+- */
+-static void gs_reset_config(struct gs_dev *dev)
+-{
+-      struct usb_request *req;
+-
+-      if (dev == NULL) {
+-              pr_err("gs_reset_config: NULL device pointer\n");
+-              return;
+-      }
+-
+-      if (dev->dev_config == GS_NO_CONFIG_ID)
+-              return;
+-
+-      dev->dev_config = GS_NO_CONFIG_ID;
+-
+-      /* free write requests on the free list */
+-      while(!list_empty(&dev->dev_req_list)) {
+-              req = list_entry(dev->dev_req_list.next,
+-                              struct usb_request, list);
+-              list_del(&req->list);
+-              gs_free_req(dev->dev_in_ep, req);
+-      }
+-
+-      /* disable endpoints, forcing completion of pending i/o; */
+-      /* completion handlers free their requests in this case */
+-      if (dev->dev_notify_ep)
+-              usb_ep_disable(dev->dev_notify_ep);
+-      usb_ep_disable(dev->dev_in_ep);
+-      usb_ep_disable(dev->dev_out_ep);
+-}
+-
+-/*
+- * gs_build_config_buf
+- *
+- * Builds the config descriptors in the given buffer and returns the
+- * length, or a negative error number.
+- */
+-static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
+-      u8 type, unsigned int index, int is_otg)
+-{
+-      int len;
+-      int high_speed = 0;
+-      const struct usb_config_descriptor *config_desc;
+-      const struct usb_descriptor_header **function;
+-
+-      if (index >= gs_device_desc.bNumConfigurations)
+-              return -EINVAL;
+-
+-      /* other speed switches high and full speed */
+-      if (gadget_is_dualspeed(g)) {
+-              high_speed = (g->speed == USB_SPEED_HIGH);
+-              if (type == USB_DT_OTHER_SPEED_CONFIG)
+-                      high_speed = !high_speed;
+-      }
+-
+       if (use_acm) {
+-              config_desc = &gs_acm_config_desc;
+-              function = high_speed
+-                      ? gs_acm_highspeed_function
+-                      : gs_acm_fullspeed_function;
++              serial_config_driver.label = "CDC ACM config";
++              serial_config_driver.bConfigurationValue = 2;
++              device_desc.bDeviceClass = USB_CLASS_COMM;
++              device_desc.idProduct =
++                              __constant_cpu_to_le16(GS_CDC_PRODUCT_ID);
+       } else {
+-              config_desc = &gs_bulk_config_desc;
+-              function = high_speed
+-                      ? gs_bulk_highspeed_function
+-                      : gs_bulk_fullspeed_function;
+-      }
+-
+-      /* for now, don't advertise srp-only devices */
+-      if (!is_otg)
+-              function++;
+-
+-      len = usb_gadget_config_buf(config_desc, buf, GS_MAX_DESC_LEN, function);
+-      if (len < 0)
+-              return len;
+-
+-      ((struct usb_config_descriptor *)buf)->bDescriptorType = type;
+-
+-      return len;
+-}
+-
+-/*
+- * gs_alloc_req
+- *
+- * Allocate a usb_request and its buffer.  Returns a pointer to the
+- * usb_request or NULL if there is an error.
+- */
+-static struct usb_request *
+-gs_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t kmalloc_flags)
+-{
+-      struct usb_request *req;
+-
+-      if (ep == NULL)
+-              return NULL;
+-
+-      req = usb_ep_alloc_request(ep, kmalloc_flags);
+-
+-      if (req != NULL) {
+-              req->length = len;
+-              req->buf = kmalloc(len, kmalloc_flags);
+-              if (req->buf == NULL) {
+-                      usb_ep_free_request(ep, req);
+-                      return NULL;
+-              }
++              serial_config_driver.label = "Generic Serial config";
++              serial_config_driver.bConfigurationValue = 1;
++              device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
++              device_desc.idProduct =
++                              __constant_cpu_to_le16(GS_PRODUCT_ID);
+       }
++      strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
+-      return req;
++      return usb_composite_register(&gserial_driver);
+ }
++module_init(init);
+-/*
+- * gs_free_req
+- *
+- * Free a usb_request and its buffer.
+- */
+-static void gs_free_req(struct usb_ep *ep, struct usb_request *req)
++static void __exit cleanup(void)
+ {
+-      if (ep != NULL && req != NULL) {
+-              kfree(req->buf);
+-              usb_ep_free_request(ep, req);
+-      }
+-}
+-
+-/*
+- * gs_alloc_ports
+- *
+- * Allocate all ports and set the gs_dev struct to point to them.
+- * Return 0 if successful, or a negative error number.
+- *
+- * The device lock is normally held when calling this function.
+- */
+-static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags)
+-{
+-      int i;
+-      struct gs_port *port;
+-
+-      if (dev == NULL)
+-              return -EIO;
+-
+-      for (i=0; i<GS_NUM_PORTS; i++) {
+-              if ((port=kzalloc(sizeof(struct gs_port), kmalloc_flags)) == NULL)
+-                      return -ENOMEM;
+-
+-              port->port_dev = dev;
+-              port->port_num = i;
+-              port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE);
+-              port->port_line_coding.bCharFormat = GS_DEFAULT_CHAR_FORMAT;
+-              port->port_line_coding.bParityType = GS_DEFAULT_PARITY;
+-              port->port_line_coding.bDataBits = GS_DEFAULT_DATA_BITS;
+-              spin_lock_init(&port->port_lock);
+-              init_waitqueue_head(&port->port_write_wait);
+-
+-              dev->dev_port[i] = port;
+-      }
+-
+-      return 0;
+-}
+-
+-/*
+- * gs_free_ports
+- *
+- * Free all closed ports.  Open ports are disconnected by
+- * freeing their write buffers, setting their device pointers
+- * and the pointers to them in the device to NULL.  These
+- * ports will be freed when closed.
+- *
+- * The device lock is normally held when calling this function.
+- */
+-static void gs_free_ports(struct gs_dev *dev)
+-{
+-      int i;
+-      unsigned long flags;
+-      struct gs_port *port;
+-
+-      if (dev == NULL)
+-              return;
+-
+-      for (i=0; i<GS_NUM_PORTS; i++) {
+-              if ((port=dev->dev_port[i]) != NULL) {
+-                      dev->dev_port[i] = NULL;
+-
+-                      spin_lock_irqsave(&port->port_lock, flags);
+-
+-                      if (port->port_write_buf != NULL) {
+-                              gs_buf_free(port->port_write_buf);
+-                              port->port_write_buf = NULL;
+-                      }
+-
+-                      if (port->port_open_count > 0 || port->port_in_use) {
+-                              port->port_dev = NULL;
+-                              wake_up_interruptible(&port->port_write_wait);
+-                              if (port->port_tty) {
+-                                      tty_hangup(port->port_tty);
+-                              }
+-                              spin_unlock_irqrestore(&port->port_lock, flags);
+-                      } else {
+-                              spin_unlock_irqrestore(&port->port_lock, flags);
+-                              kfree(port);
+-                      }
+-
+-              }
+-      }
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/* Circular Buffer */
+-
+-/*
+- * gs_buf_alloc
+- *
+- * Allocate a circular buffer and all associated memory.
+- */
+-static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags)
+-{
+-      struct gs_buf *gb;
+-
+-      if (size == 0)
+-              return NULL;
+-
+-      gb = kmalloc(sizeof(struct gs_buf), kmalloc_flags);
+-      if (gb == NULL)
+-              return NULL;
+-
+-      gb->buf_buf = kmalloc(size, kmalloc_flags);
+-      if (gb->buf_buf == NULL) {
+-              kfree(gb);
+-              return NULL;
+-      }
+-
+-      gb->buf_size = size;
+-      gb->buf_get = gb->buf_put = gb->buf_buf;
+-
+-      return gb;
+-}
+-
+-/*
+- * gs_buf_free
+- *
+- * Free the buffer and all associated memory.
+- */
+-static void gs_buf_free(struct gs_buf *gb)
+-{
+-      if (gb) {
+-              kfree(gb->buf_buf);
+-              kfree(gb);
+-      }
+-}
+-
+-/*
+- * gs_buf_clear
+- *
+- * Clear out all data in the circular buffer.
+- */
+-static void gs_buf_clear(struct gs_buf *gb)
+-{
+-      if (gb != NULL)
+-              gb->buf_get = gb->buf_put;
+-              /* equivalent to a get of all data available */
+-}
+-
+-/*
+- * gs_buf_data_avail
+- *
+- * Return the number of bytes of data available in the circular
+- * buffer.
+- */
+-static unsigned int gs_buf_data_avail(struct gs_buf *gb)
+-{
+-      if (gb != NULL)
+-              return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
+-      else
+-              return 0;
+-}
+-
+-/*
+- * gs_buf_space_avail
+- *
+- * Return the number of bytes of space available in the circular
+- * buffer.
+- */
+-static unsigned int gs_buf_space_avail(struct gs_buf *gb)
+-{
+-      if (gb != NULL)
+-              return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
+-      else
+-              return 0;
+-}
+-
+-/*
+- * gs_buf_put
+- *
+- * Copy data data from a user buffer and put it into the circular buffer.
+- * Restrict to the amount of space available.
+- *
+- * Return the number of bytes copied.
+- */
+-static unsigned int
+-gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
+-{
+-      unsigned int len;
+-
+-      if (gb == NULL)
+-              return 0;
+-
+-      len  = gs_buf_space_avail(gb);
+-      if (count > len)
+-              count = len;
+-
+-      if (count == 0)
+-              return 0;
+-
+-      len = gb->buf_buf + gb->buf_size - gb->buf_put;
+-      if (count > len) {
+-              memcpy(gb->buf_put, buf, len);
+-              memcpy(gb->buf_buf, buf+len, count - len);
+-              gb->buf_put = gb->buf_buf + count - len;
+-      } else {
+-              memcpy(gb->buf_put, buf, count);
+-              if (count < len)
+-                      gb->buf_put += count;
+-              else /* count == len */
+-                      gb->buf_put = gb->buf_buf;
+-      }
+-
+-      return count;
+-}
+-
+-/*
+- * gs_buf_get
+- *
+- * Get data from the circular buffer and copy to the given buffer.
+- * Restrict to the amount of data available.
+- *
+- * Return the number of bytes copied.
+- */
+-static unsigned int
+-gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
+-{
+-      unsigned int len;
+-
+-      if (gb == NULL)
+-              return 0;
+-
+-      len = gs_buf_data_avail(gb);
+-      if (count > len)
+-              count = len;
+-
+-      if (count == 0)
+-              return 0;
+-
+-      len = gb->buf_buf + gb->buf_size - gb->buf_get;
+-      if (count > len) {
+-              memcpy(buf, gb->buf_get, len);
+-              memcpy(buf+len, gb->buf_buf, count - len);
+-              gb->buf_get = gb->buf_buf + count - len;
+-      } else {
+-              memcpy(buf, gb->buf_get, count);
+-              if (count < len)
+-                      gb->buf_get += count;
+-              else /* count == len */
+-                      gb->buf_get = gb->buf_buf;
+-      }
+-
+-      return count;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static struct tty_driver *gs_tty_driver;
+-
+-/*
+- *  gs_module_init
+- *
+- *  Register as a USB gadget driver and a tty driver.
+- */
+-static int __init gs_module_init(void)
+-{
+-      int i;
+-      int retval;
+-
+-      retval = usb_gadget_register_driver(&gs_gadget_driver);
+-      if (retval) {
+-              pr_err("gs_module_init: cannot register gadget driver, "
+-                      "ret=%d\n", retval);
+-              return retval;
+-      }
+-
+-      gs_tty_driver = alloc_tty_driver(GS_NUM_PORTS);
+-      if (!gs_tty_driver)
+-              return -ENOMEM;
+-      gs_tty_driver->owner = THIS_MODULE;
+-      gs_tty_driver->driver_name = GS_SHORT_NAME;
+-      gs_tty_driver->name = "ttygs";
+-      gs_tty_driver->major = GS_MAJOR;
+-      gs_tty_driver->minor_start = GS_MINOR_START;
+-      gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+-      gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+-      gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+-      gs_tty_driver->init_termios = tty_std_termios;
+-      /* must match GS_DEFAULT_DTE_RATE and friends */
+-      gs_tty_driver->init_termios.c_cflag =
+-              B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+-      gs_tty_driver->init_termios.c_ispeed = GS_DEFAULT_DTE_RATE;
+-      gs_tty_driver->init_termios.c_ospeed = GS_DEFAULT_DTE_RATE;
+-      tty_set_operations(gs_tty_driver, &gs_tty_ops);
+-
+-      for (i = 0; i < GS_NUM_PORTS; i++)
+-              mutex_init(&gs_open_close_lock[i]);
+-
+-      retval = tty_register_driver(gs_tty_driver);
+-      if (retval) {
+-              usb_gadget_unregister_driver(&gs_gadget_driver);
+-              put_tty_driver(gs_tty_driver);
+-              pr_err("gs_module_init: cannot register tty driver, "
+-                              "ret=%d\n", retval);
+-              return retval;
+-      }
+-
+-      pr_info("gs_module_init: %s %s loaded\n",
+-                      GS_LONG_NAME, GS_VERSION_STR);
+-      return 0;
+-}
+-module_init(gs_module_init);
+-
+-/*
+- * gs_module_exit
+- *
+- * Unregister as a tty driver and a USB gadget driver.
+- */
+-static void __exit gs_module_exit(void)
+-{
+-      tty_unregister_driver(gs_tty_driver);
+-      put_tty_driver(gs_tty_driver);
+-      usb_gadget_unregister_driver(&gs_gadget_driver);
+-
+-      pr_info("gs_module_exit: %s %s unloaded\n",
+-                      GS_LONG_NAME, GS_VERSION_STR);
++      usb_composite_unregister(&gserial_driver);
++      gserial_cleanup();
+ }
+-module_exit(gs_module_exit);
++module_exit(cleanup);
+diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
+new file mode 100644
+index 0000000..3791e62
+--- /dev/null
++++ b/drivers/usb/gadget/u_ether.c
+@@ -0,0 +1,964 @@
++/*
++ * u_ether.c -- Ethernet-over-USB link layer utilities for Gadget stack
++ *
++ * Copyright (C) 2003-2005,2008 David Brownell
++ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
++ * Copyright (C) 2008 Nokia Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kernel.h>
++#include <linux/utsname.h>
++#include <linux/device.h>
++#include <linux/ctype.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++
++#include "u_ether.h"
++
++
++/*
++ * This component encapsulates the Ethernet link glue needed to provide
++ * one (!) network link through the USB gadget stack, normally "usb0".
++ *
++ * The control and data models are handled by the function driver which
++ * connects to this code; such as CDC Ethernet, "CDC Subset", or RNDIS.
++ * That includes all descriptor and endpoint management.
++ *
++ * Link level addressing is handled by this component using module
++ * parameters; if no such parameters are provided, random link level
++ * addresses are used.  Each end of the link uses one address.  The
++ * host end address is exported in various ways, and is often recorded
++ * in configuration databases.
++ *
++ * The driver which assembles each configuration using such a link is
++ * responsible for ensuring that each configuration includes at most one
++ * instance of is network link.  (The network layer provides ways for
++ * this single "physical" link to be used by multiple virtual links.)
++ */
++
++#define DRIVER_VERSION        "29-May-2008"
++
++struct eth_dev {
++      /* lock is held while accessing port_usb
++       * or updating its backlink port_usb->ioport
++       */
++      spinlock_t              lock;
++      struct gether           *port_usb;
++
++      struct net_device       *net;
++      struct usb_gadget       *gadget;
++
++      spinlock_t              req_lock;       /* guard {rx,tx}_reqs */
++      struct list_head        tx_reqs, rx_reqs;
++      atomic_t                tx_qlen;
++
++      unsigned                header_len;
++      struct sk_buff          *(*wrap)(struct sk_buff *skb);
++      int                     (*unwrap)(struct sk_buff *skb);
++
++      struct work_struct      work;
++
++      unsigned long           todo;
++#define       WORK_RX_MEMORY          0
++
++      bool                    zlp;
++      u8                      host_mac[ETH_ALEN];
++};
++
++/*-------------------------------------------------------------------------*/
++
++#define RX_EXTRA      20      /* bytes guarding against rx overflows */
++
++#define DEFAULT_QLEN  2       /* double buffering by default */
++
++
++#ifdef CONFIG_USB_GADGET_DUALSPEED
++
++static unsigned qmult = 5;
++module_param(qmult, uint, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(qmult, "queue length multiplier at high speed");
++
++#else /* full speed (low speed doesn't do bulk) */
++#define qmult         1
++#endif
++
++/* for dual-speed hardware, use deeper queues at highspeed */
++static inline int qlen(struct usb_gadget *gadget)
++{
++      if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH)
++              return qmult * DEFAULT_QLEN;
++      else
++              return DEFAULT_QLEN;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* REVISIT there must be a better way than having two sets
++ * of debug calls ...
++ */
++
++#undef DBG
++#undef VDBG
++#undef ERROR
++#undef INFO
++
++#define xprintk(d, level, fmt, args...) \
++      printk(level "%s: " fmt , (d)->net->name , ## args)
++
++#ifdef DEBUG
++#undef DEBUG
++#define DBG(dev, fmt, args...) \
++      xprintk(dev , KERN_DEBUG , fmt , ## args)
++#else
++#define DBG(dev, fmt, args...) \
++      do { } while (0)
++#endif /* DEBUG */
++
++#ifdef VERBOSE_DEBUG
++#define VDBG  DBG
++#else
++#define VDBG(dev, fmt, args...) \
++      do { } while (0)
++#endif /* DEBUG */
++
++#define ERROR(dev, fmt, args...) \
++      xprintk(dev , KERN_ERR , fmt , ## args)
++#define INFO(dev, fmt, args...) \
++      xprintk(dev , KERN_INFO , fmt , ## args)
++
++/*-------------------------------------------------------------------------*/
++
++/* NETWORK DRIVER HOOKUP (to the layer above this driver) */
++
++static int eth_change_mtu(struct net_device *net, int new_mtu)
++{
++      struct eth_dev  *dev = netdev_priv(net);
++      unsigned long   flags;
++      int             status = 0;
++
++      /* don't change MTU on "live" link (peer won't know) */
++      spin_lock_irqsave(&dev->lock, flags);
++      if (dev->port_usb)
++              status = -EBUSY;
++      else if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
++              status = -ERANGE;
++      else
++              net->mtu = new_mtu;
++      spin_unlock_irqrestore(&dev->lock, flags);
++
++      return status;
++}
++
++static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
++{
++      struct eth_dev  *dev = netdev_priv(net);
++
++      strlcpy(p->driver, "g_ether", sizeof p->driver);
++      strlcpy(p->version, DRIVER_VERSION, sizeof p->version);
++      strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version);
++      strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info);
++}
++
++static u32 eth_get_link(struct net_device *net)
++{
++      struct eth_dev  *dev = netdev_priv(net);
++      return dev->gadget->speed != USB_SPEED_UNKNOWN;
++}
++
++/* REVISIT can also support:
++ *   - WOL (by tracking suspends and issuing remote wakeup)
++ *   - msglevel (implies updated messaging)
++ *   - ... probably more ethtool ops
++ */
++
++static struct ethtool_ops ops = {
++      .get_drvinfo = eth_get_drvinfo,
++      .get_link = eth_get_link
++};
++
++static void defer_kevent(struct eth_dev *dev, int flag)
++{
++      if (test_and_set_bit(flag, &dev->todo))
++              return;
++      if (!schedule_work(&dev->work))
++              ERROR(dev, "kevent %d may have been dropped\n", flag);
++      else
++              DBG(dev, "kevent %d scheduled\n", flag);
++}
++
++static void rx_complete(struct usb_ep *ep, struct usb_request *req);
++
++static int
++rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
++{
++      struct sk_buff  *skb;
++      int             retval = -ENOMEM;
++      size_t          size = 0;
++      struct usb_ep   *out;
++      unsigned long   flags;
++
++      spin_lock_irqsave(&dev->lock, flags);
++      if (dev->port_usb)
++              out = dev->port_usb->out_ep;
++      else
++              out = NULL;
++      spin_unlock_irqrestore(&dev->lock, flags);
++
++      if (!out)
++              return -ENOTCONN;
++
++
++      /* Padding up to RX_EXTRA handles minor disagreements with host.
++       * Normally we use the USB "terminate on short read" convention;
++       * so allow up to (N*maxpacket), since that memory is normally
++       * already allocated.  Some hardware doesn't deal well with short
++       * reads (e.g. DMA must be N*maxpacket), so for now don't trim a
++       * byte off the end (to force hardware errors on overflow).
++       *
++       * RNDIS uses internal framing, and explicitly allows senders to
++       * pad to end-of-packet.  That's potentially nice for speed, but
++       * means receivers can't recover lost synch on their own (because
++       * new packets don't only start after a short RX).
++       */
++      size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA;
++      size += dev->port_usb->header_len;
++      size += out->maxpacket - 1;
++      size -= size % out->maxpacket;
++
++      skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
++      if (skb == NULL) {
++              DBG(dev, "no rx skb\n");
++              goto enomem;
++      }
++
++      /* Some platforms perform better when IP packets are aligned,
++       * but on at least one, checksumming fails otherwise.  Note:
++       * RNDIS headers involve variable numbers of LE32 values.
++       */
++      skb_reserve(skb, NET_IP_ALIGN);
++
++      req->buf = skb->data;
++      req->length = size;
++      req->complete = rx_complete;
++      req->context = skb;
++
++      retval = usb_ep_queue(out, req, gfp_flags);
++      if (retval == -ENOMEM)
++enomem:
++              defer_kevent(dev, WORK_RX_MEMORY);
++      if (retval) {
++              DBG(dev, "rx submit --> %d\n", retval);
++              if (skb)
++                      dev_kfree_skb_any(skb);
++              spin_lock_irqsave(&dev->req_lock, flags);
++              list_add(&req->list, &dev->rx_reqs);
++              spin_unlock_irqrestore(&dev->req_lock, flags);
++      }
++      return retval;
++}
++
++static void rx_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct sk_buff  *skb = req->context;
++      struct eth_dev  *dev = ep->driver_data;
++      int             status = req->status;
++
++      switch (status) {
++
++      /* normal completion */
++      case 0:
++              skb_put(skb, req->actual);
++              if (dev->unwrap)
++                      status = dev->unwrap(skb);
++              if (status < 0
++                              || ETH_HLEN > skb->len
++                              || skb->len > ETH_FRAME_LEN) {
++                      dev->net->stats.rx_errors++;
++                      dev->net->stats.rx_length_errors++;
++                      DBG(dev, "rx length %d\n", skb->len);
++                      break;
++              }
++
++              skb->protocol = eth_type_trans(skb, dev->net);
++              dev->net->stats.rx_packets++;
++              dev->net->stats.rx_bytes += skb->len;
++
++              /* no buffer copies needed, unless hardware can't
++               * use skb buffers.
++               */
++              status = netif_rx(skb);
++              skb = NULL;
++              break;
++
++      /* software-driven interface shutdown */
++      case -ECONNRESET:               /* unlink */
++      case -ESHUTDOWN:                /* disconnect etc */
++              VDBG(dev, "rx shutdown, code %d\n", status);
++              goto quiesce;
++
++      /* for hardware automagic (such as pxa) */
++      case -ECONNABORTED:             /* endpoint reset */
++              DBG(dev, "rx %s reset\n", ep->name);
++              defer_kevent(dev, WORK_RX_MEMORY);
++quiesce:
++              dev_kfree_skb_any(skb);
++              goto clean;
++
++      /* data overrun */
++      case -EOVERFLOW:
++              dev->net->stats.rx_over_errors++;
++              /* FALLTHROUGH */
++
++      default:
++              dev->net->stats.rx_errors++;
++              DBG(dev, "rx status %d\n", status);
++              break;
++      }
++
++      if (skb)
++              dev_kfree_skb_any(skb);
++      if (!netif_running(dev->net)) {
++clean:
++              spin_lock(&dev->req_lock);
++              list_add(&req->list, &dev->rx_reqs);
++              spin_unlock(&dev->req_lock);
++              req = NULL;
++      }
++      if (req)
++              rx_submit(dev, req, GFP_ATOMIC);
++}
++
++static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
++{
++      unsigned                i;
++      struct usb_request      *req;
++
++      if (!n)
++              return -ENOMEM;
++
++      /* queue/recycle up to N requests */
++      i = n;
++      list_for_each_entry(req, list, list) {
++              if (i-- == 0)
++                      goto extra;
++      }
++      while (i--) {
++              req = usb_ep_alloc_request(ep, GFP_ATOMIC);
++              if (!req)
++                      return list_empty(list) ? -ENOMEM : 0;
++              list_add(&req->list, list);
++      }
++      return 0;
++
++extra:
++      /* free extras */
++      for (;;) {
++              struct list_head        *next;
++
++              next = req->list.next;
++              list_del(&req->list);
++              usb_ep_free_request(ep, req);
++
++              if (next == list)
++                      break;
++
++              req = container_of(next, struct usb_request, list);
++      }
++      return 0;
++}
++
++static int alloc_requests(struct eth_dev *dev, struct gether *link, unsigned n)
++{
++      int     status;
++
++      spin_lock(&dev->req_lock);
++      status = prealloc(&dev->tx_reqs, link->in_ep, n);
++      if (status < 0)
++              goto fail;
++      status = prealloc(&dev->rx_reqs, link->out_ep, n);
++      if (status < 0)
++              goto fail;
++      goto done;
++fail:
++      DBG(dev, "can't alloc requests\n");
++done:
++      spin_unlock(&dev->req_lock);
++      return status;
++}
++
++static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
++{
++      struct usb_request      *req;
++      unsigned long           flags;
++
++      /* fill unused rxq slots with some skb */
++      spin_lock_irqsave(&dev->req_lock, flags);
++      while (!list_empty(&dev->rx_reqs)) {
++              req = container_of(dev->rx_reqs.next,
++                              struct usb_request, list);
++              list_del_init(&req->list);
++              spin_unlock_irqrestore(&dev->req_lock, flags);
++
++              if (rx_submit(dev, req, gfp_flags) < 0) {
++                      defer_kevent(dev, WORK_RX_MEMORY);
++                      return;
++              }
++
++              spin_lock_irqsave(&dev->req_lock, flags);
++      }
++      spin_unlock_irqrestore(&dev->req_lock, flags);
++}
++
++static void eth_work(struct work_struct *work)
++{
++      struct eth_dev  *dev = container_of(work, struct eth_dev, work);
++
++      if (test_and_clear_bit(WORK_RX_MEMORY, &dev->todo)) {
++              if (netif_running(dev->net))
++                      rx_fill(dev, GFP_KERNEL);
++      }
++
++      if (dev->todo)
++              DBG(dev, "work done, flags = 0x%lx\n", dev->todo);
++}
++
++static void tx_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct sk_buff  *skb = req->context;
++      struct eth_dev  *dev = ep->driver_data;
++
++      switch (req->status) {
++      default:
++              dev->net->stats.tx_errors++;
++              VDBG(dev, "tx err %d\n", req->status);
++              /* FALLTHROUGH */
++      case -ECONNRESET:               /* unlink */
++      case -ESHUTDOWN:                /* disconnect etc */
++              break;
++      case 0:
++              dev->net->stats.tx_bytes += skb->len;
++      }
++      dev->net->stats.tx_packets++;
++
++      spin_lock(&dev->req_lock);
++      list_add(&req->list, &dev->tx_reqs);
++      spin_unlock(&dev->req_lock);
++      dev_kfree_skb_any(skb);
++
++      atomic_dec(&dev->tx_qlen);
++      if (netif_carrier_ok(dev->net))
++              netif_wake_queue(dev->net);
++}
++
++static inline int is_promisc(u16 cdc_filter)
++{
++      return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
++}
++
++static int eth_start_xmit(struct sk_buff *skb, struct net_device *net)
++{
++      struct eth_dev          *dev = netdev_priv(net);
++      int                     length = skb->len;
++      int                     retval;
++      struct usb_request      *req = NULL;
++      unsigned long           flags;
++      struct usb_ep           *in;
++      u16                     cdc_filter;
++
++      spin_lock_irqsave(&dev->lock, flags);
++      if (dev->port_usb) {
++              in = dev->port_usb->in_ep;
++              cdc_filter = dev->port_usb->cdc_filter;
++      } else {
++              in = NULL;
++              cdc_filter = 0;
++      }
++      spin_unlock_irqrestore(&dev->lock, flags);
++
++      if (!in) {
++              dev_kfree_skb_any(skb);
++              return 0;
++      }
++
++      /* apply outgoing CDC or RNDIS filters */
++      if (!is_promisc(cdc_filter)) {
++              u8              *dest = skb->data;
++
++              if (is_multicast_ether_addr(dest)) {
++                      u16     type;
++
++                      /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host
++                       * SET_ETHERNET_MULTICAST_FILTERS requests
++                       */
++                      if (is_broadcast_ether_addr(dest))
++                              type = USB_CDC_PACKET_TYPE_BROADCAST;
++                      else
++                              type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
++                      if (!(cdc_filter & type)) {
++                              dev_kfree_skb_any(skb);
++                              return 0;
++                      }
++              }
++              /* ignores USB_CDC_PACKET_TYPE_DIRECTED */
++      }
++
++      spin_lock_irqsave(&dev->req_lock, flags);
++      /*
++       * this freelist can be empty if an interrupt triggered disconnect()
++       * and reconfigured the gadget (shutting down this queue) after the
++       * network stack decided to xmit but before we got the spinlock.
++       */
++      if (list_empty(&dev->tx_reqs)) {
++              spin_unlock_irqrestore(&dev->req_lock, flags);
++              return 1;
++      }
++
++      req = container_of(dev->tx_reqs.next, struct usb_request, list);
++      list_del(&req->list);
++
++      /* temporarily stop TX queue when the freelist empties */
++      if (list_empty(&dev->tx_reqs))
++              netif_stop_queue(net);
++      spin_unlock_irqrestore(&dev->req_lock, flags);
++
++      /* no buffer copies needed, unless the network stack did it
++       * or the hardware can't use skb buffers.
++       * or there's not enough space for extra headers we need
++       */
++      if (dev->wrap) {
++              struct sk_buff  *skb_new;
++
++              skb_new = dev->wrap(skb);
++              if (!skb_new)
++                      goto drop;
++
++              dev_kfree_skb_any(skb);
++              skb = skb_new;
++              length = skb->len;
++      }
++      req->buf = skb->data;
++      req->context = skb;
++      req->complete = tx_complete;
++
++      /* use zlp framing on tx for strict CDC-Ether conformance,
++       * though any robust network rx path ignores extra padding.
++       * and some hardware doesn't like to write zlps.
++       */
++      req->zero = 1;
++      if (!dev->zlp && (length % in->maxpacket) == 0)
++              length++;
++
++      req->length = length;
++
++      /* throttle highspeed IRQ rate back slightly */
++      if (gadget_is_dualspeed(dev->gadget))
++              req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
++                      ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
++                      : 0;
++
++      retval = usb_ep_queue(in, req, GFP_ATOMIC);
++      switch (retval) {
++      default:
++              DBG(dev, "tx queue err %d\n", retval);
++              break;
++      case 0:
++              net->trans_start = jiffies;
++              atomic_inc(&dev->tx_qlen);
++      }
++
++      if (retval) {
++drop:
++              dev->net->stats.tx_dropped++;
++              dev_kfree_skb_any(skb);
++              spin_lock_irqsave(&dev->req_lock, flags);
++              if (list_empty(&dev->tx_reqs))
++                      netif_start_queue(net);
++              list_add(&req->list, &dev->tx_reqs);
++              spin_unlock_irqrestore(&dev->req_lock, flags);
++      }
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void eth_start(struct eth_dev *dev, gfp_t gfp_flags)
++{
++      DBG(dev, "%s\n", __func__);
++
++      /* fill the rx queue */
++      rx_fill(dev, gfp_flags);
++
++      /* and open the tx floodgates */
++      atomic_set(&dev->tx_qlen, 0);
++      netif_wake_queue(dev->net);
++}
++
++static int eth_open(struct net_device *net)
++{
++      struct eth_dev  *dev = netdev_priv(net);
++      struct gether   *link;
++
++      DBG(dev, "%s\n", __func__);
++      if (netif_carrier_ok(dev->net))
++              eth_start(dev, GFP_KERNEL);
++
++      spin_lock_irq(&dev->lock);
++      link = dev->port_usb;
++      if (link && link->open)
++              link->open(link);
++      spin_unlock_irq(&dev->lock);
++
++      return 0;
++}
++
++static int eth_stop(struct net_device *net)
++{
++      struct eth_dev  *dev = netdev_priv(net);
++      unsigned long   flags;
++
++      VDBG(dev, "%s\n", __func__);
++      netif_stop_queue(net);
++
++      DBG(dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
++              dev->net->stats.rx_packets, dev->net->stats.tx_packets,
++              dev->net->stats.rx_errors, dev->net->stats.tx_errors
++              );
++
++      /* ensure there are no more active requests */
++      spin_lock_irqsave(&dev->lock, flags);
++      if (dev->port_usb) {
++              struct gether   *link = dev->port_usb;
++
++              if (link->close)
++                      link->close(link);
++
++              /* NOTE:  we have no abort-queue primitive we could use
++               * to cancel all pending I/O.  Instead, we disable then
++               * reenable the endpoints ... this idiom may leave toggle
++               * wrong, but that's a self-correcting error.
++               *
++               * REVISIT:  we *COULD* just let the transfers complete at
++               * their own pace; the network stack can handle old packets.
++               * For the moment we leave this here, since it works.
++               */
++              usb_ep_disable(link->in_ep);
++              usb_ep_disable(link->out_ep);
++              if (netif_carrier_ok(net)) {
++                      DBG(dev, "host still using in/out endpoints\n");
++                      usb_ep_enable(link->in_ep, link->in);
++                      usb_ep_enable(link->out_ep, link->out);
++              }
++      }
++      spin_unlock_irqrestore(&dev->lock, flags);
++
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
++static char *dev_addr;
++module_param(dev_addr, charp, S_IRUGO);
++MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
++
++/* this address is invisible to ifconfig */
++static char *host_addr;
++module_param(host_addr, charp, S_IRUGO);
++MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
++
++
++static u8 __init nibble(unsigned char c)
++{
++      if (isdigit(c))
++              return c - '0';
++      c = toupper(c);
++      if (isxdigit(c))
++              return 10 + c - 'A';
++      return 0;
++}
++
++static int __init get_ether_addr(const char *str, u8 *dev_addr)
++{
++      if (str) {
++              unsigned        i;
++
++              for (i = 0; i < 6; i++) {
++                      unsigned char num;
++
++                      if ((*str == '.') || (*str == ':'))
++                              str++;
++                      num = nibble(*str++) << 4;
++                      num |= (nibble(*str++));
++                      dev_addr [i] = num;
++              }
++              if (is_valid_ether_addr(dev_addr))
++                      return 0;
++      }
++      random_ether_addr(dev_addr);
++      return 1;
++}
++
++static struct eth_dev *the_dev;
++
++
++/**
++ * gether_setup - initialize one ethernet-over-usb link
++ * @g: gadget to associated with these links
++ * @ethaddr: NULL, or a buffer in which the ethernet address of the
++ *    host side of the link is recorded
++ * Context: may sleep
++ *
++ * This sets up the single network link that may be exported by a
++ * gadget driver using this framework.  The link layer addresses are
++ * set up using module parameters.
++ *
++ * Returns negative errno, or zero on success
++ */
++int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
++{
++      struct eth_dev          *dev;
++      struct net_device       *net;
++      int                     status;
++
++      if (the_dev)
++              return -EBUSY;
++
++      net = alloc_etherdev(sizeof *dev);
++      if (!net)
++              return -ENOMEM;
++
++      dev = netdev_priv(net);
++      spin_lock_init(&dev->lock);
++      spin_lock_init(&dev->req_lock);
++      INIT_WORK(&dev->work, eth_work);
++      INIT_LIST_HEAD(&dev->tx_reqs);
++      INIT_LIST_HEAD(&dev->rx_reqs);
++
++      /* network device setup */
++      dev->net = net;
++      strcpy(net->name, "usb%d");
++
++      if (get_ether_addr(dev_addr, net->dev_addr))
++              dev_warn(&g->dev,
++                      "using random %s ethernet address\n", "self");
++      if (get_ether_addr(host_addr, dev->host_mac))
++              dev_warn(&g->dev,
++                      "using random %s ethernet address\n", "host");
++
++      if (ethaddr)
++              memcpy(ethaddr, dev->host_mac, ETH_ALEN);
++
++      net->change_mtu = eth_change_mtu;
++      net->hard_start_xmit = eth_start_xmit;
++      net->open = eth_open;
++      net->stop = eth_stop;
++      /* watchdog_timeo, tx_timeout ... */
++      /* set_multicast_list */
++      SET_ETHTOOL_OPS(net, &ops);
++
++      /* two kinds of host-initiated state changes:
++       *  - iff DATA transfer is active, carrier is "on"
++       *  - tx queueing enabled if open *and* carrier is "on"
++       */
++      netif_stop_queue(net);
++      netif_carrier_off(net);
++
++      dev->gadget = g;
++      SET_NETDEV_DEV(net, &g->dev);
++
++      status = register_netdev(net);
++      if (status < 0) {
++              dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
++              free_netdev(net);
++      } else {
++              DECLARE_MAC_BUF(tmp);
++
++              INFO(dev, "MAC %s\n", print_mac(tmp, net->dev_addr));
++              INFO(dev, "HOST MAC %s\n", print_mac(tmp, dev->host_mac));
++
++              the_dev = dev;
++      }
++
++      return status;
++}
++
++/**
++ * gether_cleanup - remove Ethernet-over-USB device
++ * Context: may sleep
++ *
++ * This is called to free all resources allocated by @gether_setup().
++ */
++void gether_cleanup(void)
++{
++      if (!the_dev)
++              return;
++
++      unregister_netdev(the_dev->net);
++      free_netdev(the_dev->net);
++
++      /* assuming we used keventd, it must quiesce too */
++      flush_scheduled_work();
++
++      the_dev = NULL;
++}
++
++
++/**
++ * gether_connect - notify network layer that USB link is active
++ * @link: the USB link, set up with endpoints, descriptors matching
++ *    current device speed, and any framing wrapper(s) set up.
++ * Context: irqs blocked
++ *
++ * This is called to activate endpoints and let the network layer know
++ * the connection is active ("carrier detect").  It may cause the I/O
++ * queues to open and start letting network packets flow, but will in
++ * any case activate the endpoints so that they respond properly to the
++ * USB host.
++ *
++ * Verify net_device pointer returned using IS_ERR().  If it doesn't
++ * indicate some error code (negative errno), ep->driver_data values
++ * have been overwritten.
++ */
++struct net_device *gether_connect(struct gether *link)
++{
++      struct eth_dev          *dev = the_dev;
++      int                     result = 0;
++
++      if (!dev)
++              return ERR_PTR(-EINVAL);
++
++      link->in_ep->driver_data = dev;
++      result = usb_ep_enable(link->in_ep, link->in);
++      if (result != 0) {
++              DBG(dev, "enable %s --> %d\n",
++                      link->in_ep->name, result);
++              goto fail0;
++      }
++
++      link->out_ep->driver_data = dev;
++      result = usb_ep_enable(link->out_ep, link->out);
++      if (result != 0) {
++              DBG(dev, "enable %s --> %d\n",
++                      link->out_ep->name, result);
++              goto fail1;
++      }
++
++      if (result == 0)
++              result = alloc_requests(dev, link, qlen(dev->gadget));
++
++      if (result == 0) {
++              dev->zlp = link->is_zlp_ok;
++              DBG(dev, "qlen %d\n", qlen(dev->gadget));
++
++              dev->header_len = link->header_len;
++              dev->unwrap = link->unwrap;
++              dev->wrap = link->wrap;
++
++              spin_lock(&dev->lock);
++              dev->port_usb = link;
++              link->ioport = dev;
++              spin_unlock(&dev->lock);
++
++              netif_carrier_on(dev->net);
++              if (netif_running(dev->net))
++                      eth_start(dev, GFP_ATOMIC);
++
++      /* on error, disable any endpoints  */
++      } else {
++              (void) usb_ep_disable(link->out_ep);
++fail1:
++              (void) usb_ep_disable(link->in_ep);
++      }
++fail0:
++      /* caller is responsible for cleanup on error */
++      if (result < 0)
++              return ERR_PTR(result);
++      return dev->net;
++}
++
++/**
++ * gether_disconnect - notify network layer that USB link is inactive
++ * @link: the USB link, on which gether_connect() was called
++ * Context: irqs blocked
++ *
++ * This is called to deactivate endpoints and let the network layer know
++ * the connection went inactive ("no carrier").
++ *
++ * On return, the state is as if gether_connect() had never been called.
++ * The endpoints are inactive, and accordingly without active USB I/O.
++ * Pointers to endpoint descriptors and endpoint private data are nulled.
++ */
++void gether_disconnect(struct gether *link)
++{
++      struct eth_dev          *dev = link->ioport;
++      struct usb_request      *req;
++
++      WARN_ON(!dev);
++      if (!dev)
++              return;
++
++      DBG(dev, "%s\n", __func__);
++
++      netif_stop_queue(dev->net);
++      netif_carrier_off(dev->net);
++
++      /* disable endpoints, forcing (synchronous) completion
++       * of all pending i/o.  then free the request objects
++       * and forget about the endpoints.
++       */
++      usb_ep_disable(link->in_ep);
++      spin_lock(&dev->req_lock);
++      while (!list_empty(&dev->tx_reqs)) {
++              req = container_of(dev->tx_reqs.next,
++                                      struct usb_request, list);
++              list_del(&req->list);
++
++              spin_unlock(&dev->req_lock);
++              usb_ep_free_request(link->in_ep, req);
++              spin_lock(&dev->req_lock);
++      }
++      spin_unlock(&dev->req_lock);
++      link->in_ep->driver_data = NULL;
++      link->in = NULL;
++
++      usb_ep_disable(link->out_ep);
++      spin_lock(&dev->req_lock);
++      while (!list_empty(&dev->rx_reqs)) {
++              req = container_of(dev->rx_reqs.next,
++                                      struct usb_request, list);
++              list_del(&req->list);
++
++              spin_unlock(&dev->req_lock);
++              usb_ep_free_request(link->out_ep, req);
++              spin_lock(&dev->req_lock);
++      }
++      spin_unlock(&dev->req_lock);
++      link->out_ep->driver_data = NULL;
++      link->out = NULL;
++
++      /* finish forgetting about this USB link episode */
++      dev->header_len = 0;
++      dev->unwrap = NULL;
++      dev->wrap = NULL;
++
++      spin_lock(&dev->lock);
++      dev->port_usb = NULL;
++      link->ioport = NULL;
++      spin_unlock(&dev->lock);
++}
+diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
+new file mode 100644
+index 0000000..0d1f7ae
+--- /dev/null
++++ b/drivers/usb/gadget/u_ether.h
+@@ -0,0 +1,127 @@
++/*
++ * u_ether.h -- interface to USB gadget "ethernet link" utilities
++ *
++ * Copyright (C) 2003-2005,2008 David Brownell
++ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
++ * Copyright (C) 2008 Nokia Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef __U_ETHER_H
++#define __U_ETHER_H
++
++#include <linux/err.h>
++#include <linux/if_ether.h>
++#include <linux/usb/composite.h>
++#include <linux/usb/cdc.h>
++
++#include "gadget_chips.h"
++
++
++/*
++ * This represents the USB side of an "ethernet" link, managed by a USB
++ * function which provides control and (maybe) framing.  Two functions
++ * in different configurations could share the same ethernet link/netdev,
++ * using different host interaction models.
++ *
++ * There is a current limitation that only one instance of this link may
++ * be present in any given configuration.  When that's a problem, network
++ * layer facilities can be used to package multiple logical links on this
++ * single "physical" one.
++ */
++struct gether {
++      struct usb_function             func;
++
++      /* updated by gether_{connect,disconnect} */
++      struct eth_dev                  *ioport;
++
++      /* endpoints handle full and/or high speeds */
++      struct usb_ep                   *in_ep;
++      struct usb_ep                   *out_ep;
++
++      /* descriptors match device speed at gether_connect() time */
++      struct usb_endpoint_descriptor  *in;
++      struct usb_endpoint_descriptor  *out;
++
++      bool                            is_zlp_ok;
++
++      u16                             cdc_filter;
++
++      /* hooks for added framing, as needed for RNDIS and EEM.
++       * we currently don't support multiple frames per SKB.
++       */
++      u32                             header_len;
++      struct sk_buff                  *(*wrap)(struct sk_buff *skb);
++      int                             (*unwrap)(struct sk_buff *skb);
++
++      /* called on network open/close */
++      void                            (*open)(struct gether *);
++      void                            (*close)(struct gether *);
++};
++
++#define       DEFAULT_FILTER  (USB_CDC_PACKET_TYPE_BROADCAST \
++                      |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
++                      |USB_CDC_PACKET_TYPE_PROMISCUOUS \
++                      |USB_CDC_PACKET_TYPE_DIRECTED)
++
++
++/* netdev setup/teardown as directed by the gadget driver */
++int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]);
++void gether_cleanup(void);
++
++/* connect/disconnect is handled by individual functions */
++struct net_device *gether_connect(struct gether *);
++void gether_disconnect(struct gether *);
++
++/* Some controllers can't support CDC Ethernet (ECM) ... */
++static inline bool can_support_ecm(struct usb_gadget *gadget)
++{
++      if (!gadget_supports_altsettings(gadget))
++              return false;
++
++      /* SA1100 can do ECM, *without* status endpoint ... but we'll
++       * only use it in non-ECM mode for backwards compatibility
++       * (and since we currently require a status endpoint)
++       */
++      if (gadget_is_sa1100(gadget))
++              return false;
++
++      /* Everything else is *presumably* fine ... but this is a bit
++       * chancy, so be **CERTAIN** there are no hardware issues with
++       * your controller.  Add it above if it can't handle CDC.
++       */
++      return true;
++}
++
++/* each configuration may bind one instance of an ethernet link */
++int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
++int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
++
++#ifdef CONFIG_USB_ETH_RNDIS
++
++int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
++
++#else
++
++static inline int
++rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
++{
++      return 0;
++}
++
++#endif
++
++#endif /* __U_ETHER_H */
+diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
+new file mode 100644
+index 0000000..53d5928
+--- /dev/null
++++ b/drivers/usb/gadget/u_serial.c
+@@ -0,0 +1,1330 @@
++/*
++ * u_serial.c - utilities for USB gadget "serial port"/TTY support
++ *
++ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
++ * Copyright (C) 2008 David Brownell
++ * Copyright (C) 2008 by Nokia Corporation
++ *
++ * This code also borrows from usbserial.c, which is
++ * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
++ * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
++ * Copyright (C) 2000 Al Borchers (alborchers@steinerpoint.com)
++ *
++ * This software is distributed under the terms of the GNU General
++ * Public License ("GPL") as published by the Free Software Foundation,
++ * either version 2 of that License or (at your option) any later version.
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++
++#include "u_serial.h"
++
++
++/*
++ * This component encapsulates the TTY layer glue needed to provide basic
++ * "serial port" functionality through the USB gadget stack.  Each such
++ * port is exposed through a /dev/ttyGS* node.
++ *
++ * After initialization (gserial_setup), these TTY port devices stay
++ * available until they are removed (gserial_cleanup).  Each one may be
++ * connected to a USB function (gserial_connect), or disconnected (with
++ * gserial_disconnect) when the USB host issues a config change event.
++ * Data can only flow when the port is connected to the host.
++ *
++ * A given TTY port can be made available in multiple configurations.
++ * For example, each one might expose a ttyGS0 node which provides a
++ * login application.  In one case that might use CDC ACM interface 0,
++ * while another configuration might use interface 3 for that.  The
++ * work to handle that (including descriptor management) is not part
++ * of this component.
++ *
++ * Configurations may expose more than one TTY port.  For example, if
++ * ttyGS0 provides login service, then ttyGS1 might provide dialer access
++ * for a telephone or fax link.  And ttyGS2 might be something that just
++ * needs a simple byte stream interface for some messaging protocol that
++ * is managed in userspace ... OBEX, PTP, and MTP have been mentioned.
++ */
++
++#define PREFIX        "ttyGS"
++
++/*
++ * gserial is the lifecycle interface, used by USB functions
++ * gs_port is the I/O nexus, used by the tty driver
++ * tty_struct links to the tty/filesystem framework
++ *
++ * gserial <---> gs_port ... links will be null when the USB link is
++ * inactive; managed by gserial_{connect,disconnect}().  each gserial
++ * instance can wrap its own USB control protocol.
++ *    gserial->ioport == usb_ep->driver_data ... gs_port
++ *    gs_port->port_usb ... gserial
++ *
++ * gs_port <---> tty_struct ... links will be null when the TTY file
++ * isn't opened; managed by gs_open()/gs_close()
++ *    gserial->port_tty ... tty_struct
++ *    tty_struct->driver_data ... gserial
++ */
++
++/* RX and TX queues can buffer QUEUE_SIZE packets before they hit the
++ * next layer of buffering.  For TX that's a circular buffer; for RX
++ * consider it a NOP.  A third layer is provided by the TTY code.
++ */
++#define QUEUE_SIZE            16
++#define WRITE_BUF_SIZE                8192            /* TX only */
++
++/* circular buffer */
++struct gs_buf {
++      unsigned                buf_size;
++      char                    *buf_buf;
++      char                    *buf_get;
++      char                    *buf_put;
++};
++
++/*
++ * The port structure holds info for each port, one for each minor number
++ * (and thus for each /dev/ node).
++ */
++struct gs_port {
++      spinlock_t              port_lock;      /* guard port_* access */
++
++      struct gserial          *port_usb;
++      struct tty_struct       *port_tty;
++
++      unsigned                open_count;
++      bool                    openclose;      /* open/close in progress */
++      u8                      port_num;
++
++      wait_queue_head_t       close_wait;     /* wait for last close */
++
++      struct list_head        read_pool;
++      struct list_head        read_queue;
++      unsigned                n_read;
++      struct tasklet_struct   push;
++
++      struct list_head        write_pool;
++      struct gs_buf           port_write_buf;
++      wait_queue_head_t       drain_wait;     /* wait while writes drain */
++
++      /* REVISIT this state ... */
++      struct usb_cdc_line_coding port_line_coding;    /* 8-N-1 etc */
++};
++
++/* increase N_PORTS if you need more */
++#define N_PORTS               4
++static struct portmaster {
++      struct mutex    lock;                   /* protect open/close */
++      struct gs_port  *port;
++} ports[N_PORTS];
++static unsigned       n_ports;
++
++#define GS_CLOSE_TIMEOUT              15              /* seconds */
++
++
++
++#ifdef VERBOSE_DEBUG
++#define pr_vdebug(fmt, arg...) \
++      pr_debug(fmt, ##arg)
++#else
++#define pr_vdebug(fmt, arg...) \
++      ({ if (0) pr_debug(fmt, ##arg); })
++#endif
++
++/*-------------------------------------------------------------------------*/
++
++/* Circular Buffer */
++
++/*
++ * gs_buf_alloc
++ *
++ * Allocate a circular buffer and all associated memory.
++ */
++static int gs_buf_alloc(struct gs_buf *gb, unsigned size)
++{
++      gb->buf_buf = kmalloc(size, GFP_KERNEL);
++      if (gb->buf_buf == NULL)
++              return -ENOMEM;
++
++      gb->buf_size = size;
++      gb->buf_put = gb->buf_buf;
++      gb->buf_get = gb->buf_buf;
++
++      return 0;
++}
++
++/*
++ * gs_buf_free
++ *
++ * Free the buffer and all associated memory.
++ */
++static void gs_buf_free(struct gs_buf *gb)
++{
++      kfree(gb->buf_buf);
++      gb->buf_buf = NULL;
++}
++
++/*
++ * gs_buf_clear
++ *
++ * Clear out all data in the circular buffer.
++ */
++static void gs_buf_clear(struct gs_buf *gb)
++{
++      gb->buf_get = gb->buf_put;
++      /* equivalent to a get of all data available */
++}
++
++/*
++ * gs_buf_data_avail
++ *
++ * Return the number of bytes of data written into the circular
++ * buffer.
++ */
++static unsigned gs_buf_data_avail(struct gs_buf *gb)
++{
++      return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
++}
++
++/*
++ * gs_buf_space_avail
++ *
++ * Return the number of bytes of space available in the circular
++ * buffer.
++ */
++static unsigned gs_buf_space_avail(struct gs_buf *gb)
++{
++      return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
++}
++
++/*
++ * gs_buf_put
++ *
++ * Copy data data from a user buffer and put it into the circular buffer.
++ * Restrict to the amount of space available.
++ *
++ * Return the number of bytes copied.
++ */
++static unsigned
++gs_buf_put(struct gs_buf *gb, const char *buf, unsigned count)
++{
++      unsigned len;
++
++      len  = gs_buf_space_avail(gb);
++      if (count > len)
++              count = len;
++
++      if (count == 0)
++              return 0;
++
++      len = gb->buf_buf + gb->buf_size - gb->buf_put;
++      if (count > len) {
++              memcpy(gb->buf_put, buf, len);
++              memcpy(gb->buf_buf, buf+len, count - len);
++              gb->buf_put = gb->buf_buf + count - len;
++      } else {
++              memcpy(gb->buf_put, buf, count);
++              if (count < len)
++                      gb->buf_put += count;
++              else /* count == len */
++                      gb->buf_put = gb->buf_buf;
++      }
++
++      return count;
++}
++
++/*
++ * gs_buf_get
++ *
++ * Get data from the circular buffer and copy to the given buffer.
++ * Restrict to the amount of data available.
++ *
++ * Return the number of bytes copied.
++ */
++static unsigned
++gs_buf_get(struct gs_buf *gb, char *buf, unsigned count)
++{
++      unsigned len;
++
++      len = gs_buf_data_avail(gb);
++      if (count > len)
++              count = len;
++
++      if (count == 0)
++              return 0;
++
++      len = gb->buf_buf + gb->buf_size - gb->buf_get;
++      if (count > len) {
++              memcpy(buf, gb->buf_get, len);
++              memcpy(buf+len, gb->buf_buf, count - len);
++              gb->buf_get = gb->buf_buf + count - len;
++      } else {
++              memcpy(buf, gb->buf_get, count);
++              if (count < len)
++                      gb->buf_get += count;
++              else /* count == len */
++                      gb->buf_get = gb->buf_buf;
++      }
++
++      return count;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* I/O glue between TTY (upper) and USB function (lower) driver layers */
++
++/*
++ * gs_alloc_req
++ *
++ * Allocate a usb_request and its buffer.  Returns a pointer to the
++ * usb_request or NULL if there is an error.
++ */
++struct usb_request *
++gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
++{
++      struct usb_request *req;
++
++      req = usb_ep_alloc_request(ep, kmalloc_flags);
++
++      if (req != NULL) {
++              req->length = len;
++              req->buf = kmalloc(len, kmalloc_flags);
++              if (req->buf == NULL) {
++                      usb_ep_free_request(ep, req);
++                      return NULL;
++              }
++      }
++
++      return req;
++}
++
++/*
++ * gs_free_req
++ *
++ * Free a usb_request and its buffer.
++ */
++void gs_free_req(struct usb_ep *ep, struct usb_request *req)
++{
++      kfree(req->buf);
++      usb_ep_free_request(ep, req);
++}
++
++/*
++ * gs_send_packet
++ *
++ * If there is data to send, a packet is built in the given
++ * buffer and the size is returned.  If there is no data to
++ * send, 0 is returned.
++ *
++ * Called with port_lock held.
++ */
++static unsigned
++gs_send_packet(struct gs_port *port, char *packet, unsigned size)
++{
++      unsigned len;
++
++      len = gs_buf_data_avail(&port->port_write_buf);
++      if (len < size)
++              size = len;
++      if (size != 0)
++              size = gs_buf_get(&port->port_write_buf, packet, size);
++      return size;
++}
++
++/*
++ * gs_start_tx
++ *
++ * This function finds available write requests, calls
++ * gs_send_packet to fill these packets with data, and
++ * continues until either there are no more write requests
++ * available or no more data to send.  This function is
++ * run whenever data arrives or write requests are available.
++ *
++ * Context: caller owns port_lock; port_usb is non-null.
++ */
++static int gs_start_tx(struct gs_port *port)
++/*
++__releases(&port->port_lock)
++__acquires(&port->port_lock)
++*/
++{
++      struct list_head        *pool = &port->write_pool;
++      struct usb_ep           *in = port->port_usb->in;
++      int                     status = 0;
++      bool                    do_tty_wake = false;
++
++      while (!list_empty(pool)) {
++              struct usb_request      *req;
++              int                     len;
++
++              req = list_entry(pool->next, struct usb_request, list);
++              len = gs_send_packet(port, req->buf, in->maxpacket);
++              if (len == 0) {
++                      wake_up_interruptible(&port->drain_wait);
++                      break;
++              }
++              do_tty_wake = true;
++
++              req->length = len;
++              list_del(&req->list);
++
++              pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n",
++                              port->port_num, len, *((u8 *)req->buf),
++                              *((u8 *)req->buf+1), *((u8 *)req->buf+2));
++
++              /* Drop lock while we call out of driver; completions
++               * could be issued while we do so.  Disconnection may
++               * happen too; maybe immediately before we queue this!
++               *
++               * NOTE that we may keep sending data for a while after
++               * the TTY closed (dev->ioport->port_tty is NULL).
++               */
++              spin_unlock(&port->port_lock);
++              status = usb_ep_queue(in, req, GFP_ATOMIC);
++              spin_lock(&port->port_lock);
++
++              if (status) {
++                      pr_debug("%s: %s %s err %d\n",
++                                      __func__, "queue", in->name, status);
++                      list_add(&req->list, pool);
++                      break;
++              }
++
++              /* abort immediately after disconnect */
++              if (!port->port_usb)
++                      break;
++      }
++
++      if (do_tty_wake && port->port_tty)
++              tty_wakeup(port->port_tty);
++      return status;
++}
++
++/*
++ * Context: caller owns port_lock, and port_usb is set
++ */
++static unsigned gs_start_rx(struct gs_port *port)
++/*
++__releases(&port->port_lock)
++__acquires(&port->port_lock)
++*/
++{
++      struct list_head        *pool = &port->read_pool;
++      struct usb_ep           *out = port->port_usb->out;
++      unsigned                started = 0;
++
++      while (!list_empty(pool)) {
++              struct usb_request      *req;
++              int                     status;
++              struct tty_struct       *tty;
++
++              /* no more rx if closed */
++              tty = port->port_tty;
++              if (!tty)
++                      break;
++
++              req = list_entry(pool->next, struct usb_request, list);
++              list_del(&req->list);
++              req->length = out->maxpacket;
++
++              /* drop lock while we call out; the controller driver
++               * may need to call us back (e.g. for disconnect)
++               */
++              spin_unlock(&port->port_lock);
++              status = usb_ep_queue(out, req, GFP_ATOMIC);
++              spin_lock(&port->port_lock);
++
++              if (status) {
++                      pr_debug("%s: %s %s err %d\n",
++                                      __func__, "queue", out->name, status);
++                      list_add(&req->list, pool);
++                      break;
++              }
++              started++;
++
++              /* abort immediately after disconnect */
++              if (!port->port_usb)
++                      break;
++      }
++      return started;
++}
++
++/*
++ * RX tasklet takes data out of the RX queue and hands it up to the TTY
++ * layer until it refuses to take any more data (or is throttled back).
++ * Then it issues reads for any further data.
++ *
++ * If the RX queue becomes full enough that no usb_request is queued,
++ * the OUT endpoint may begin NAKing as soon as its FIFO fills up.
++ * So QUEUE_SIZE packets plus however many the FIFO holds (usually two)
++ * can be buffered before the TTY layer's buffers (currently 64 KB).
++ */
++static void gs_rx_push(unsigned long _port)
++{
++      struct gs_port          *port = (void *)_port;
++      struct tty_struct       *tty;
++      struct list_head        *queue = &port->read_queue;
++      bool                    disconnect = false;
++      bool                    do_push = false;
++
++      /* hand any queued data to the tty */
++      spin_lock_irq(&port->port_lock);
++      tty = port->port_tty;
++      while (!list_empty(queue)) {
++              struct usb_request      *req;
++
++              req = list_first_entry(queue, struct usb_request, list);
++
++              /* discard data if tty was closed */
++              if (!tty)
++                      goto recycle;
++
++              /* leave data queued if tty was rx throttled */
++              if (test_bit(TTY_THROTTLED, &tty->flags))
++                      break;
++
++              switch (req->status) {
++              case -ESHUTDOWN:
++                      disconnect = true;
++                      pr_vdebug(PREFIX "%d: shutdown\n", port->port_num);
++                      break;
++
++              default:
++                      /* presumably a transient fault */
++                      pr_warning(PREFIX "%d: unexpected RX status %d\n",
++                                      port->port_num, req->status);
++                      /* FALLTHROUGH */
++              case 0:
++                      /* normal completion */
++                      break;
++              }
++
++              /* push data to (open) tty */
++              if (req->actual) {
++                      char            *packet = req->buf;
++                      unsigned        size = req->actual;
++                      unsigned        n;
++                      int             count;
++
++                      /* we may have pushed part of this packet already... */
++                      n = port->n_read;
++                      if (n) {
++                              packet += n;
++                              size -= n;
++                      }
++
++                      count = tty_insert_flip_string(tty, packet, size);
++                      if (count)
++                              do_push = true;
++                      if (count != size) {
++                              /* stop pushing; TTY layer can't handle more */
++                              port->n_read += count;
++                              pr_vdebug(PREFIX "%d: rx block %d/%d\n",
++                                              port->port_num,
++                                              count, req->actual);
++                              break;
++                      }
++                      port->n_read = 0;
++              }
++recycle:
++              list_move(&req->list, &port->read_pool);
++      }
++
++      /* Push from tty to ldisc; this is immediate with low_latency, and
++       * may trigger callbacks to this driver ... so drop the spinlock.
++       */
++      if (tty && do_push) {
++              spin_unlock_irq(&port->port_lock);
++              tty_flip_buffer_push(tty);
++              wake_up_interruptible(&tty->read_wait);
++              spin_lock_irq(&port->port_lock);
++
++              /* tty may have been closed */
++              tty = port->port_tty;
++      }
++
++
++      /* We want our data queue to become empty ASAP, keeping data
++       * in the tty and ldisc (not here).  If we couldn't push any
++       * this time around, there may be trouble unless there's an
++       * implicit tty_unthrottle() call on its way...
++       *
++       * REVISIT we should probably add a timer to keep the tasklet
++       * from starving ... but it's not clear that case ever happens.
++       */
++      if (!list_empty(queue) && tty) {
++              if (!test_bit(TTY_THROTTLED, &tty->flags)) {
++                      if (do_push)
++                              tasklet_schedule(&port->push);
++                      else
++                              pr_warning(PREFIX "%d: RX not scheduled?\n",
++                                      port->port_num);
++              }
++      }
++
++      /* If we're still connected, refill the USB RX queue. */
++      if (!disconnect && port->port_usb)
++              gs_start_rx(port);
++
++      spin_unlock_irq(&port->port_lock);
++}
++
++static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct gs_port  *port = ep->driver_data;
++
++      /* Queue all received data until the tty layer is ready for it. */
++      spin_lock(&port->port_lock);
++      list_add_tail(&req->list, &port->read_queue);
++      tasklet_schedule(&port->push);
++      spin_unlock(&port->port_lock);
++}
++
++static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct gs_port  *port = ep->driver_data;
++
++      spin_lock(&port->port_lock);
++      list_add(&req->list, &port->write_pool);
++
++      switch (req->status) {
++      default:
++              /* presumably a transient fault */
++              pr_warning("%s: unexpected %s status %d\n",
++                              __func__, ep->name, req->status);
++              /* FALL THROUGH */
++      case 0:
++              /* normal completion */
++              gs_start_tx(port);
++              break;
++
++      case -ESHUTDOWN:
++              /* disconnect */
++              pr_vdebug("%s: %s shutdown\n", __func__, ep->name);
++              break;
++      }
++
++      spin_unlock(&port->port_lock);
++}
++
++static void gs_free_requests(struct usb_ep *ep, struct list_head *head)
++{
++      struct usb_request      *req;
++
++      while (!list_empty(head)) {
++              req = list_entry(head->next, struct usb_request, list);
++              list_del(&req->list);
++              gs_free_req(ep, req);
++      }
++}
++
++static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head,
++              void (*fn)(struct usb_ep *, struct usb_request *))
++{
++      int                     i;
++      struct usb_request      *req;
++
++      /* Pre-allocate up to QUEUE_SIZE transfers, but if we can't
++       * do quite that many this time, don't fail ... we just won't
++       * be as speedy as we might otherwise be.
++       */
++      for (i = 0; i < QUEUE_SIZE; i++) {
++              req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
++              if (!req)
++                      return list_empty(head) ? -ENOMEM : 0;
++              req->complete = fn;
++              list_add_tail(&req->list, head);
++      }
++      return 0;
++}
++
++/**
++ * gs_start_io - start USB I/O streams
++ * @dev: encapsulates endpoints to use
++ * Context: holding port_lock; port_tty and port_usb are non-null
++ *
++ * We only start I/O when something is connected to both sides of
++ * this port.  If nothing is listening on the host side, we may
++ * be pointlessly filling up our TX buffers and FIFO.
++ */
++static int gs_start_io(struct gs_port *port)
++{
++      struct list_head        *head = &port->read_pool;
++      struct usb_ep           *ep = port->port_usb->out;
++      int                     status;
++      unsigned                started;
++
++      /* Allocate RX and TX I/O buffers.  We can't easily do this much
++       * earlier (with GFP_KERNEL) because the requests are coupled to
++       * endpoints, as are the packet sizes we'll be using.  Different
++       * configurations may use different endpoints with a given port;
++       * and high speed vs full speed changes packet sizes too.
++       */
++      status = gs_alloc_requests(ep, head, gs_read_complete);
++      if (status)
++              return status;
++
++      status = gs_alloc_requests(port->port_usb->in, &port->write_pool,
++                      gs_write_complete);
++      if (status) {
++              gs_free_requests(ep, head);
++              return status;
++      }
++
++      /* queue read requests */
++      port->n_read = 0;
++      started = gs_start_rx(port);
++
++      /* unblock any pending writes into our circular buffer */
++      if (started) {
++              tty_wakeup(port->port_tty);
++      } else {
++              gs_free_requests(ep, head);
++              gs_free_requests(port->port_usb->in, &port->write_pool);
++              status = -EIO;
++      }
++
++      return status;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* TTY Driver */
++
++/*
++ * gs_open sets up the link between a gs_port and its associated TTY.
++ * That link is broken *only* by TTY close(), and all driver methods
++ * know that.
++ */
++static int gs_open(struct tty_struct *tty, struct file *file)
++{
++      int             port_num = tty->index;
++      struct gs_port  *port;
++      int             status;
++
++      if (port_num < 0 || port_num >= n_ports)
++              return -ENXIO;
++
++      do {
++              mutex_lock(&ports[port_num].lock);
++              port = ports[port_num].port;
++              if (!port)
++                      status = -ENODEV;
++              else {
++                      spin_lock_irq(&port->port_lock);
++
++                      /* already open?  Great. */
++                      if (port->open_count) {
++                              status = 0;
++                              port->open_count++;
++
++                      /* currently opening/closing? wait ... */
++                      } else if (port->openclose) {
++                              status = -EBUSY;
++
++                      /* ... else we do the work */
++                      } else {
++                              status = -EAGAIN;
++                              port->openclose = true;
++                      }
++                      spin_unlock_irq(&port->port_lock);
++              }
++              mutex_unlock(&ports[port_num].lock);
++
++              switch (status) {
++              default:
++                      /* fully handled */
++                      return status;
++              case -EAGAIN:
++                      /* must do the work */
++                      break;
++              case -EBUSY:
++                      /* wait for EAGAIN task to finish */
++                      msleep(1);
++                      /* REVISIT could have a waitchannel here, if
++                       * concurrent open performance is important
++                       */
++                      break;
++              }
++      } while (status != -EAGAIN);
++
++      /* Do the "real open" */
++      spin_lock_irq(&port->port_lock);
++
++      /* allocate circular buffer on first open */
++      if (port->port_write_buf.buf_buf == NULL) {
++
++              spin_unlock_irq(&port->port_lock);
++              status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE);
++              spin_lock_irq(&port->port_lock);
++
++              if (status) {
++                      pr_debug("gs_open: ttyGS%d (%p,%p) no buffer\n",
++                              port->port_num, tty, file);
++                      port->openclose = false;
++                      goto exit_unlock_port;
++              }
++      }
++
++      /* REVISIT if REMOVED (ports[].port NULL), abort the open
++       * to let rmmod work faster (but this way isn't wrong).
++       */
++
++      /* REVISIT maybe wait for "carrier detect" */
++
++      tty->driver_data = port;
++      port->port_tty = tty;
++
++      port->open_count = 1;
++      port->openclose = false;
++
++      /* low_latency means ldiscs work in tasklet context, without
++       * needing a workqueue schedule ... easier to keep up.
++       */
++      tty->low_latency = 1;
++
++      /* if connected, start the I/O stream */
++      if (port->port_usb) {
++              struct gserial  *gser = port->port_usb;
++
++              pr_debug("gs_open: start ttyGS%d\n", port->port_num);
++              gs_start_io(port);
++
++              if (gser->connect)
++                      gser->connect(gser);
++      }
++
++      pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file);
++
++      status = 0;
++
++exit_unlock_port:
++      spin_unlock_irq(&port->port_lock);
++      return status;
++}
++
++static int gs_writes_finished(struct gs_port *p)
++{
++      int cond;
++
++      /* return true on disconnect or empty buffer */
++      spin_lock_irq(&p->port_lock);
++      cond = (p->port_usb == NULL) || !gs_buf_data_avail(&p->port_write_buf);
++      spin_unlock_irq(&p->port_lock);
++
++      return cond;
++}
++
++static void gs_close(struct tty_struct *tty, struct file *file)
++{
++      struct gs_port *port = tty->driver_data;
++      struct gserial  *gser;
++
++      spin_lock_irq(&port->port_lock);
++
++      if (port->open_count != 1) {
++              if (port->open_count == 0)
++                      WARN_ON(1);
++              else
++                      --port->open_count;
++              goto exit;
++      }
++
++      pr_debug("gs_close: ttyGS%d (%p,%p) ...\n", port->port_num, tty, file);
++
++      /* mark port as closing but in use; we can drop port lock
++       * and sleep if necessary
++       */
++      port->openclose = true;
++      port->open_count = 0;
++
++      gser = port->port_usb;
++      if (gser && gser->disconnect)
++              gser->disconnect(gser);
++
++      /* wait for circular write buffer to drain, disconnect, or at
++       * most GS_CLOSE_TIMEOUT seconds; then discard the rest
++       */
++      if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) {
++              spin_unlock_irq(&port->port_lock);
++              wait_event_interruptible_timeout(port->drain_wait,
++                                      gs_writes_finished(port),
++                                      GS_CLOSE_TIMEOUT * HZ);
++              spin_lock_irq(&port->port_lock);
++              gser = port->port_usb;
++      }
++
++      /* Iff we're disconnected, there can be no I/O in flight so it's
++       * ok to free the circular buffer; else just scrub it.  And don't
++       * let the push tasklet fire again until we're re-opened.
++       */
++      if (gser == NULL)
++              gs_buf_free(&port->port_write_buf);
++      else
++              gs_buf_clear(&port->port_write_buf);
++
++      tty->driver_data = NULL;
++      port->port_tty = NULL;
++
++      port->openclose = false;
++
++      pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
++                      port->port_num, tty, file);
++
++      wake_up_interruptible(&port->close_wait);
++exit:
++      spin_unlock_irq(&port->port_lock);
++}
++
++static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
++{
++      struct gs_port  *port = tty->driver_data;
++      unsigned long   flags;
++      int             status;
++
++      pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n",
++                      port->port_num, tty, count);
++
++      spin_lock_irqsave(&port->port_lock, flags);
++      if (count)
++              count = gs_buf_put(&port->port_write_buf, buf, count);
++      /* treat count == 0 as flush_chars() */
++      if (port->port_usb)
++              status = gs_start_tx(port);
++      spin_unlock_irqrestore(&port->port_lock, flags);
++
++      return count;
++}
++
++static int gs_put_char(struct tty_struct *tty, unsigned char ch)
++{
++      struct gs_port  *port = tty->driver_data;
++      unsigned long   flags;
++      int             status;
++
++      pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
++              port->port_num, tty, ch, __builtin_return_address(0));
++
++      spin_lock_irqsave(&port->port_lock, flags);
++      status = gs_buf_put(&port->port_write_buf, &ch, 1);
++      spin_unlock_irqrestore(&port->port_lock, flags);
++
++      return status;
++}
++
++static void gs_flush_chars(struct tty_struct *tty)
++{
++      struct gs_port  *port = tty->driver_data;
++      unsigned long   flags;
++
++      pr_vdebug("gs_flush_chars: (%d,%p)\n", port->port_num, tty);
++
++      spin_lock_irqsave(&port->port_lock, flags);
++      if (port->port_usb)
++              gs_start_tx(port);
++      spin_unlock_irqrestore(&port->port_lock, flags);
++}
++
++static int gs_write_room(struct tty_struct *tty)
++{
++      struct gs_port  *port = tty->driver_data;
++      unsigned long   flags;
++      int             room = 0;
++
++      spin_lock_irqsave(&port->port_lock, flags);
++      if (port->port_usb)
++              room = gs_buf_space_avail(&port->port_write_buf);
++      spin_unlock_irqrestore(&port->port_lock, flags);
++
++      pr_vdebug("gs_write_room: (%d,%p) room=%d\n",
++              port->port_num, tty, room);
++
++      return room;
++}
++
++static int gs_chars_in_buffer(struct tty_struct *tty)
++{
++      struct gs_port  *port = tty->driver_data;
++      unsigned long   flags;
++      int             chars = 0;
++
++      spin_lock_irqsave(&port->port_lock, flags);
++      chars = gs_buf_data_avail(&port->port_write_buf);
++      spin_unlock_irqrestore(&port->port_lock, flags);
++
++      pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n",
++              port->port_num, tty, chars);
++
++      return chars;
++}
++
++/* undo side effects of setting TTY_THROTTLED */
++static void gs_unthrottle(struct tty_struct *tty)
++{
++      struct gs_port          *port = tty->driver_data;
++      unsigned long           flags;
++
++      spin_lock_irqsave(&port->port_lock, flags);
++      if (port->port_usb) {
++              /* Kickstart read queue processing.  We don't do xon/xoff,
++               * rts/cts, or other handshaking with the host, but if the
++               * read queue backs up enough we'll be NAKing OUT packets.
++               */
++              tasklet_schedule(&port->push);
++              pr_vdebug(PREFIX "%d: unthrottle\n", port->port_num);
++      }
++      spin_unlock_irqrestore(&port->port_lock, flags);
++}
++
++static int gs_break_ctl(struct tty_struct *tty, int duration)
++{
++      struct gs_port  *port = tty->driver_data;
++      int             status = 0;
++      struct gserial  *gser;
++
++      pr_vdebug("gs_break_ctl: ttyGS%d, send break (%d) \n",
++                      port->port_num, duration);
++
++      spin_lock_irq(&port->port_lock);
++      gser = port->port_usb;
++      if (gser && gser->send_break)
++              status = gser->send_break(gser, duration);
++      spin_unlock_irq(&port->port_lock);
++
++      return status;
++}
++
++static const struct tty_operations gs_tty_ops = {
++      .open =                 gs_open,
++      .close =                gs_close,
++      .write =                gs_write,
++      .put_char =             gs_put_char,
++      .flush_chars =          gs_flush_chars,
++      .write_room =           gs_write_room,
++      .chars_in_buffer =      gs_chars_in_buffer,
++      .unthrottle =           gs_unthrottle,
++      .break_ctl =            gs_break_ctl,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static struct tty_driver *gs_tty_driver;
++
++static int __init
++gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
++{
++      struct gs_port  *port;
++
++      port = kzalloc(sizeof(struct gs_port), GFP_KERNEL);
++      if (port == NULL)
++              return -ENOMEM;
++
++      spin_lock_init(&port->port_lock);
++      init_waitqueue_head(&port->close_wait);
++      init_waitqueue_head(&port->drain_wait);
++
++      tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
++
++      INIT_LIST_HEAD(&port->read_pool);
++      INIT_LIST_HEAD(&port->read_queue);
++      INIT_LIST_HEAD(&port->write_pool);
++
++      port->port_num = port_num;
++      port->port_line_coding = *coding;
++
++      ports[port_num].port = port;
++
++      return 0;
++}
++
++/**
++ * gserial_setup - initialize TTY driver for one or more ports
++ * @g: gadget to associate with these ports
++ * @count: how many ports to support
++ * Context: may sleep
++ *
++ * The TTY stack needs to know in advance how many devices it should
++ * plan to manage.  Use this call to set up the ports you will be
++ * exporting through USB.  Later, connect them to functions based
++ * on what configuration is activated by the USB host; and disconnect
++ * them as appropriate.
++ *
++ * An example would be a two-configuration device in which both
++ * configurations expose port 0, but through different functions.
++ * One configuration could even expose port 1 while the other
++ * one doesn't.
++ *
++ * Returns negative errno or zero.
++ */
++int __init gserial_setup(struct usb_gadget *g, unsigned count)
++{
++      unsigned                        i;
++      struct usb_cdc_line_coding      coding;
++      int                             status;
++
++      if (count == 0 || count > N_PORTS)
++              return -EINVAL;
++
++      gs_tty_driver = alloc_tty_driver(count);
++      if (!gs_tty_driver)
++              return -ENOMEM;
++
++      gs_tty_driver->owner = THIS_MODULE;
++      gs_tty_driver->driver_name = "g_serial";
++      gs_tty_driver->name = PREFIX;
++      /* uses dynamically assigned dev_t values */
++
++      gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
++      gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
++      gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
++      gs_tty_driver->init_termios = tty_std_termios;
++
++      /* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on
++       * MS-Windows.  Otherwise, most of these flags shouldn't affect
++       * anything unless we were to actually hook up to a serial line.
++       */
++      gs_tty_driver->init_termios.c_cflag =
++                      B9600 | CS8 | CREAD | HUPCL | CLOCAL;
++      gs_tty_driver->init_termios.c_ispeed = 9600;
++      gs_tty_driver->init_termios.c_ospeed = 9600;
++
++      coding.dwDTERate = __constant_cpu_to_le32(9600);
++      coding.bCharFormat = 8;
++      coding.bParityType = USB_CDC_NO_PARITY;
++      coding.bDataBits = USB_CDC_1_STOP_BITS;
++
++      tty_set_operations(gs_tty_driver, &gs_tty_ops);
++
++      /* make devices be openable */
++      for (i = 0; i < count; i++) {
++              mutex_init(&ports[i].lock);
++              status = gs_port_alloc(i, &coding);
++              if (status) {
++                      count = i;
++                      goto fail;
++              }
++      }
++      n_ports = count;
++
++      /* export the driver ... */
++      status = tty_register_driver(gs_tty_driver);
++      if (status) {
++              put_tty_driver(gs_tty_driver);
++              pr_err("%s: cannot register, err %d\n",
++                              __func__, status);
++              goto fail;
++      }
++
++      /* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */
++      for (i = 0; i < count; i++) {
++              struct device   *tty_dev;
++
++              tty_dev = tty_register_device(gs_tty_driver, i, &g->dev);
++              if (IS_ERR(tty_dev))
++                      pr_warning("%s: no classdev for port %d, err %ld\n",
++                              __func__, i, PTR_ERR(tty_dev));
++      }
++
++      pr_debug("%s: registered %d ttyGS* device%s\n", __func__,
++                      count, (count == 1) ? "" : "s");
++
++      return status;
++fail:
++      while (count--)
++              kfree(ports[count].port);
++      put_tty_driver(gs_tty_driver);
++      gs_tty_driver = NULL;
++      return status;
++}
++
++static int gs_closed(struct gs_port *port)
++{
++      int cond;
++
++      spin_lock_irq(&port->port_lock);
++      cond = (port->open_count == 0) && !port->openclose;
++      spin_unlock_irq(&port->port_lock);
++      return cond;
++}
++
++/**
++ * gserial_cleanup - remove TTY-over-USB driver and devices
++ * Context: may sleep
++ *
++ * This is called to free all resources allocated by @gserial_setup().
++ * Accordingly, it may need to wait until some open /dev/ files have
++ * closed.
++ *
++ * The caller must have issued @gserial_disconnect() for any ports
++ * that had previously been connected, so that there is never any
++ * I/O pending when it's called.
++ */
++void gserial_cleanup(void)
++{
++      unsigned        i;
++      struct gs_port  *port;
++
++      if (!gs_tty_driver)
++              return;
++
++      /* start sysfs and /dev/ttyGS* node removal */
++      for (i = 0; i < n_ports; i++)
++              tty_unregister_device(gs_tty_driver, i);
++
++      for (i = 0; i < n_ports; i++) {
++              /* prevent new opens */
++              mutex_lock(&ports[i].lock);
++              port = ports[i].port;
++              ports[i].port = NULL;
++              mutex_unlock(&ports[i].lock);
++
++              tasklet_kill(&port->push);
++
++              /* wait for old opens to finish */
++              wait_event(port->close_wait, gs_closed(port));
++
++              WARN_ON(port->port_usb != NULL);
++
++              kfree(port);
++      }
++      n_ports = 0;
++
++      tty_unregister_driver(gs_tty_driver);
++      gs_tty_driver = NULL;
++
++      pr_debug("%s: cleaned up ttyGS* support\n", __func__);
++}
++
++/**
++ * gserial_connect - notify TTY I/O glue that USB link is active
++ * @gser: the function, set up with endpoints and descriptors
++ * @port_num: which port is active
++ * Context: any (usually from irq)
++ *
++ * This is called activate endpoints and let the TTY layer know that
++ * the connection is active ... not unlike "carrier detect".  It won't
++ * necessarily start I/O queues; unless the TTY is held open by any
++ * task, there would be no point.  However, the endpoints will be
++ * activated so the USB host can perform I/O, subject to basic USB
++ * hardware flow control.
++ *
++ * Caller needs to have set up the endpoints and USB function in @dev
++ * before calling this, as well as the appropriate (speed-specific)
++ * endpoint descriptors, and also have set up the TTY driver by calling
++ * @gserial_setup().
++ *
++ * Returns negative errno or zero.
++ * On success, ep->driver_data will be overwritten.
++ */
++int gserial_connect(struct gserial *gser, u8 port_num)
++{
++      struct gs_port  *port;
++      unsigned long   flags;
++      int             status;
++
++      if (!gs_tty_driver || port_num >= n_ports)
++              return -ENXIO;
++
++      /* we "know" gserial_cleanup() hasn't been called */
++      port = ports[port_num].port;
++
++      /* activate the endpoints */
++      status = usb_ep_enable(gser->in, gser->in_desc);
++      if (status < 0)
++              return status;
++      gser->in->driver_data = port;
++
++      status = usb_ep_enable(gser->out, gser->out_desc);
++      if (status < 0)
++              goto fail_out;
++      gser->out->driver_data = port;
++
++      /* then tell the tty glue that I/O can work */
++      spin_lock_irqsave(&port->port_lock, flags);
++      gser->ioport = port;
++      port->port_usb = gser;
++
++      /* REVISIT unclear how best to handle this state...
++       * we don't really couple it with the Linux TTY.
++       */
++      gser->port_line_coding = port->port_line_coding;
++
++      /* REVISIT if waiting on "carrier detect", signal. */
++
++      /* if it's already open, start I/O ... and notify the serial
++       * protocol about open/close status (connect/disconnect).
++       */
++      if (port->open_count) {
++              pr_debug("gserial_connect: start ttyGS%d\n", port->port_num);
++              gs_start_io(port);
++              if (gser->connect)
++                      gser->connect(gser);
++      } else {
++              if (gser->disconnect)
++                      gser->disconnect(gser);
++      }
++
++      spin_unlock_irqrestore(&port->port_lock, flags);
++
++      return status;
++
++fail_out:
++      usb_ep_disable(gser->in);
++      gser->in->driver_data = NULL;
++      return status;
++}
++
++/**
++ * gserial_disconnect - notify TTY I/O glue that USB link is inactive
++ * @gser: the function, on which gserial_connect() was called
++ * Context: any (usually from irq)
++ *
++ * This is called to deactivate endpoints and let the TTY layer know
++ * that the connection went inactive ... not unlike "hangup".
++ *
++ * On return, the state is as if gserial_connect() had never been called;
++ * there is no active USB I/O on these endpoints.
++ */
++void gserial_disconnect(struct gserial *gser)
++{
++      struct gs_port  *port = gser->ioport;
++      unsigned long   flags;
++
++      if (!port)
++              return;
++
++      /* tell the TTY glue not to do I/O here any more */
++      spin_lock_irqsave(&port->port_lock, flags);
++
++      /* REVISIT as above: how best to track this? */
++      port->port_line_coding = gser->port_line_coding;
++
++      port->port_usb = NULL;
++      gser->ioport = NULL;
++      if (port->open_count > 0 || port->openclose) {
++              wake_up_interruptible(&port->drain_wait);
++              if (port->port_tty)
++                      tty_hangup(port->port_tty);
++      }
++      spin_unlock_irqrestore(&port->port_lock, flags);
++
++      /* disable endpoints, aborting down any active I/O */
++      usb_ep_disable(gser->out);
++      gser->out->driver_data = NULL;
++
++      usb_ep_disable(gser->in);
++      gser->in->driver_data = NULL;
++
++      /* finally, free any unused/unusable I/O buffers */
++      spin_lock_irqsave(&port->port_lock, flags);
++      if (port->open_count == 0 && !port->openclose)
++              gs_buf_free(&port->port_write_buf);
++      gs_free_requests(gser->out, &port->read_pool);
++      gs_free_requests(gser->out, &port->read_queue);
++      gs_free_requests(gser->in, &port->write_pool);
++      spin_unlock_irqrestore(&port->port_lock, flags);
++}
+diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h
+new file mode 100644
+index 0000000..af3910d
+--- /dev/null
++++ b/drivers/usb/gadget/u_serial.h
+@@ -0,0 +1,66 @@
++/*
++ * u_serial.h - interface to USB gadget "serial port"/TTY utilities
++ *
++ * Copyright (C) 2008 David Brownell
++ * Copyright (C) 2008 by Nokia Corporation
++ *
++ * This software is distributed under the terms of the GNU General
++ * Public License ("GPL") as published by the Free Software Foundation,
++ * either version 2 of that License or (at your option) any later version.
++ */
++
++#ifndef __U_SERIAL_H
++#define __U_SERIAL_H
++
++#include <linux/usb/composite.h>
++#include <linux/usb/cdc.h>
++
++/*
++ * One non-multiplexed "serial" I/O port ... there can be several of these
++ * on any given USB peripheral device, if it provides enough endpoints.
++ *
++ * The "u_serial" utility component exists to do one thing:  manage TTY
++ * style I/O using the USB peripheral endpoints listed here, including
++ * hookups to sysfs and /dev for each logical "tty" device.
++ *
++ * REVISIT at least ACM could support tiocmget() if needed.
++ *
++ * REVISIT someday, allow multiplexing several TTYs over these endpoints.
++ */
++struct gserial {
++      struct usb_function             func;
++
++      /* port is managed by gserial_{connect,disconnect} */
++      struct gs_port                  *ioport;
++
++      struct usb_ep                   *in;
++      struct usb_ep                   *out;
++      struct usb_endpoint_descriptor  *in_desc;
++      struct usb_endpoint_descriptor  *out_desc;
++
++      /* REVISIT avoid this CDC-ACM support harder ... */
++      struct usb_cdc_line_coding port_line_coding;    /* 9600-8-N-1 etc */
++
++      /* notification callbacks */
++      void (*connect)(struct gserial *p);
++      void (*disconnect)(struct gserial *p);
++      int (*send_break)(struct gserial *p, int duration);
++};
++
++/* utilities to allocate/free request and buffer */
++struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags);
++void gs_free_req(struct usb_ep *, struct usb_request *req);
++
++/* port setup/teardown is handled by gadget driver */
++int gserial_setup(struct usb_gadget *g, unsigned n_ports);
++void gserial_cleanup(void);
++
++/* connect/disconnect is handled by individual functions */
++int gserial_connect(struct gserial *, u8 port_num);
++void gserial_disconnect(struct gserial *);
++
++/* functions are bound to configurations by a config or gadget driver */
++int acm_bind_config(struct usb_configuration *c, u8 port_num);
++int gser_bind_config(struct usb_configuration *c, u8 port_num);
++
++#endif /* __U_SERIAL_H */
+diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
+index fce4924..aa0bd4f 100644
+--- a/drivers/usb/gadget/zero.c
++++ b/drivers/usb/gadget/zero.c
+@@ -1,8 +1,8 @@
+ /*
+  * zero.c -- Gadget Zero, for USB development
+  *
+- * Copyright (C) 2003-2007 David Brownell
+- * All rights reserved.
++ * Copyright (C) 2003-2008 David Brownell
++ * Copyright (C) 2008 by Nokia Corporation
+  *
+  * 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
+@@ -30,12 +30,7 @@
+  *
+  * It supports two similar configurations.  One sinks whatever the usb host
+  * writes, and in return sources zeroes.  The other loops whatever the host
+- * writes back, so the host can read it.  Module options include:
+- *
+- *   buflen=N         default N=4096, buffer size used
+- *   qlen=N           default N=32, how many buffers in the loopback queue
+- *   loopdefault      default false, list loopback config first
+- *   autoresume=N     default N=0, seconds before triggering remote wakeup
++ * writes back, so the host can read it.
+  *
+  * Many drivers will only have one configuration, letting them be much
+  * simpler if they also don't support high speed operation (like this
+@@ -47,94 +42,35 @@
+  * work with low capability USB controllers without four bulk endpoints.
+  */
++/*
++ * driver assumes self-powered hardware, and
++ * has no way for users to trigger remote wakeup.
++ */
++
+ /* #define VERBOSE_DEBUG */
+ #include <linux/kernel.h>
+ #include <linux/utsname.h>
+ #include <linux/device.h>
+-#include <linux/usb/ch9.h>
+-#include <linux/usb/gadget.h>
+-
++#include "g_zero.h"
+ #include "gadget_chips.h"
+ /*-------------------------------------------------------------------------*/
+-#define DRIVER_VERSION                "Earth Day 2008"
++#define DRIVER_VERSION                "Cinco de Mayo 2008"
+-static const char shortname[] = "zero";
+ static const char longname[] = "Gadget Zero";
+-static const char source_sink[] = "source and sink data";
+-static const char loopback[] = "loop input to output";
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/*
+- * driver assumes self-powered hardware, and
+- * has no way for users to trigger remote wakeup.
+- *
+- * this version autoconfigures as much as possible,
+- * which is reasonable for most "bulk-only" drivers.
+- */
+-static const char *EP_IN_NAME;                /* source */
+-static const char *EP_OUT_NAME;               /* sink */
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/* big enough to hold our biggest descriptor */
+-#define USB_BUFSIZ    256
+-
+-struct zero_dev {
+-      spinlock_t              lock;
+-      struct usb_gadget       *gadget;
+-      struct usb_request      *req;           /* for control responses */
+-
+-      /* when configured, we have one of two configs:
+-       * - source data (in to host) and sink it (out from host)
+-       * - or loop it back (out from host back in to host)
+-       */
+-      u8                      config;
+-      struct usb_ep           *in_ep, *out_ep;
+-
+-      /* autoresume timer */
+-      struct timer_list       resume;
+-};
+-
+-#define DBG(d, fmt, args...) \
+-      dev_dbg(&(d)->gadget->dev , fmt , ## args)
+-#define VDBG(d, fmt, args...) \
+-      dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+-#define ERROR(d, fmt, args...) \
+-      dev_err(&(d)->gadget->dev , fmt , ## args)
+-#define WARN(d, fmt, args...) \
+-      dev_warn(&(d)->gadget->dev , fmt , ## args)
+-#define INFO(d, fmt, args...) \
+-      dev_info(&(d)->gadget->dev , fmt , ## args)
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static unsigned buflen = 4096;
+-static unsigned qlen = 32;
+-static unsigned pattern = 0;
+-
+-module_param(buflen, uint, S_IRUGO);
+-module_param(qlen, uint, S_IRUGO);
+-module_param(pattern, uint, S_IRUGO|S_IWUSR);
+-
+-/*
+- * if it's nonzero, autoresume says how many seconds to wait
+- * before trying to wake up the host after suspend.
+- */
+-static unsigned autoresume = 0;
+-module_param(autoresume, uint, 0);
++unsigned buflen = 4096;
++module_param(buflen, uint, 0);
+ /*
+  * Normally the "loopback" configuration is second (index 1) so
+  * it's not the default.  Here's where to change that order, to
+- * work better with hosts where config changes are problematic.
+- * Or controllers (like superh) that only support one config.
++ * work better with hosts where config changes are problematic or
++ * controllers (like original superh) that only support one config.
+  */
+ static int loopdefault = 0;
+ module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
+@@ -156,24 +92,6 @@ module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
+ /*-------------------------------------------------------------------------*/
+-/*
+- * DESCRIPTORS ... most are static, but strings and (full)
+- * configuration descriptors are built on demand.
+- */
+-
+-#define STRING_MANUFACTURER           25
+-#define STRING_PRODUCT                        42
+-#define STRING_SERIAL                 101
+-#define STRING_SOURCE_SINK            250
+-#define STRING_LOOPBACK                       251
+-
+-/*
+- * This device advertises two configurations; these numbers work
+- * on a pxa250 as well as more flexible hardware.
+- */
+-#define       CONFIG_SOURCE_SINK      3
+-#define       CONFIG_LOOPBACK         2
+-
+ static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+@@ -183,248 +101,64 @@ static struct usb_device_descriptor device_desc = {
+       .idVendor =             __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
+       .idProduct =            __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
+-      .iManufacturer =        STRING_MANUFACTURER,
+-      .iProduct =             STRING_PRODUCT,
+-      .iSerialNumber =        STRING_SERIAL,
+       .bNumConfigurations =   2,
+ };
+-static struct usb_config_descriptor source_sink_config = {
+-      .bLength =              sizeof source_sink_config,
+-      .bDescriptorType =      USB_DT_CONFIG,
+-
+-      /* compute wTotalLength on the fly */
+-      .bNumInterfaces =       1,
+-      .bConfigurationValue =  CONFIG_SOURCE_SINK,
+-      .iConfiguration =       STRING_SOURCE_SINK,
+-      .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+-      .bMaxPower =            1,      /* self-powered */
+-};
+-
+-static struct usb_config_descriptor loopback_config = {
+-      .bLength =              sizeof loopback_config,
+-      .bDescriptorType =      USB_DT_CONFIG,
+-
+-      /* compute wTotalLength on the fly */
+-      .bNumInterfaces =       1,
+-      .bConfigurationValue =  CONFIG_LOOPBACK,
+-      .iConfiguration =       STRING_LOOPBACK,
+-      .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+-      .bMaxPower =            1,      /* self-powered */
+-};
+-
++#ifdef CONFIG_USB_OTG
+ static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+-      .bmAttributes =         USB_OTG_SRP,
+-};
+-
+-/* one interface in each configuration */
+-
+-static const struct usb_interface_descriptor source_sink_intf = {
+-      .bLength =              sizeof source_sink_intf,
+-      .bDescriptorType =      USB_DT_INTERFACE,
+-
+-      .bNumEndpoints =        2,
+-      .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
+-      .iInterface =           STRING_SOURCE_SINK,
+-};
+-
+-static const struct usb_interface_descriptor loopback_intf = {
+-      .bLength =              sizeof loopback_intf,
+-      .bDescriptorType =      USB_DT_INTERFACE,
+-
+-      .bNumEndpoints =        2,
+-      .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
+-      .iInterface =           STRING_LOOPBACK,
+-};
+-
+-/* two full speed bulk endpoints; their use is config-dependent */
+-
+-static struct usb_endpoint_descriptor fs_source_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-
+-      .bEndpointAddress =     USB_DIR_IN,
+-      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+-};
+-
+-static struct usb_endpoint_descriptor fs_sink_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-
+-      .bEndpointAddress =     USB_DIR_OUT,
+-      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+-};
+-
+-static const struct usb_descriptor_header *fs_source_sink_function[] = {
+-      (struct usb_descriptor_header *) &otg_descriptor,
+-      (struct usb_descriptor_header *) &source_sink_intf,
+-      (struct usb_descriptor_header *) &fs_sink_desc,
+-      (struct usb_descriptor_header *) &fs_source_desc,
+-      NULL,
+-};
+-
+-static const struct usb_descriptor_header *fs_loopback_function[] = {
+-      (struct usb_descriptor_header *) &otg_descriptor,
+-      (struct usb_descriptor_header *) &loopback_intf,
+-      (struct usb_descriptor_header *) &fs_sink_desc,
+-      (struct usb_descriptor_header *) &fs_source_desc,
+-      NULL,
+-};
+-
+-/*
+- * usb 2.0 devices need to expose both high speed and full speed
+- * descriptors, unless they only run at full speed.
+- *
+- * that means alternate endpoint descriptors (bigger packets)
+- * and a "device qualifier" ... plus more construction options
+- * for the config descriptor.
+- */
+-
+-static struct usb_endpoint_descriptor hs_source_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-
+-      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+-      .wMaxPacketSize =       __constant_cpu_to_le16(512),
+-};
+-
+-static struct usb_endpoint_descriptor hs_sink_desc = {
+-      .bLength =              USB_DT_ENDPOINT_SIZE,
+-      .bDescriptorType =      USB_DT_ENDPOINT,
+-
+-      .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+-      .wMaxPacketSize =       __constant_cpu_to_le16(512),
+-};
+-
+-static struct usb_qualifier_descriptor dev_qualifier = {
+-      .bLength =              sizeof dev_qualifier,
+-      .bDescriptorType =      USB_DT_DEVICE_QUALIFIER,
+-
+-      .bcdUSB =               __constant_cpu_to_le16(0x0200),
+-      .bDeviceClass =         USB_CLASS_VENDOR_SPEC,
+-
+-      .bNumConfigurations =   2,
++      /* REVISIT SRP-only hardware is possible, although
++       * it would not be called "OTG" ...
++       */
++      .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+ };
+-static const struct usb_descriptor_header *hs_source_sink_function[] = {
++const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+-      (struct usb_descriptor_header *) &source_sink_intf,
+-      (struct usb_descriptor_header *) &hs_source_desc,
+-      (struct usb_descriptor_header *) &hs_sink_desc,
+       NULL,
+ };
++#endif
+-static const struct usb_descriptor_header *hs_loopback_function[] = {
+-      (struct usb_descriptor_header *) &otg_descriptor,
+-      (struct usb_descriptor_header *) &loopback_intf,
+-      (struct usb_descriptor_header *) &hs_source_desc,
+-      (struct usb_descriptor_header *) &hs_sink_desc,
+-      NULL,
+-};
++/* string IDs are assigned dynamically */
+-/* maxpacket and other transfer characteristics vary by speed. */
+-static inline struct usb_endpoint_descriptor *
+-ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+-              struct usb_endpoint_descriptor *fs)
+-{
+-      if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+-              return hs;
+-      return fs;
+-}
++#define STRING_MANUFACTURER_IDX               0
++#define STRING_PRODUCT_IDX            1
++#define STRING_SERIAL_IDX             2
+ static char manufacturer[50];
+ /* default serial number takes at least two packets */
+ static char serial[] = "0123456789.0123456789.0123456789";
+-
+-/* static strings, in UTF-8 */
+-static struct usb_string strings[] = {
+-      { STRING_MANUFACTURER, manufacturer, },
+-      { STRING_PRODUCT, longname, },
+-      { STRING_SERIAL, serial, },
+-      { STRING_LOOPBACK, loopback, },
+-      { STRING_SOURCE_SINK, source_sink, },
++static struct usb_string strings_dev[] = {
++      [STRING_MANUFACTURER_IDX].s = manufacturer,
++      [STRING_PRODUCT_IDX].s = longname,
++      [STRING_SERIAL_IDX].s = serial,
+       {  }                    /* end of list */
+ };
+-static struct usb_gadget_strings stringtab = {
++static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+-      .strings        = strings,
++      .strings        = strings_dev,
+ };
+-/*
+- * config descriptors are also handcrafted.  these must agree with code
+- * that sets configurations, and with code managing interfaces and their
+- * altsettings.  other complexity may come from:
+- *
+- *  - high speed support, including "other speed config" rules
+- *  - multiple configurations
+- *  - interfaces with alternate settings
+- *  - embedded class or vendor-specific descriptors
+- *
+- * this handles high speed, and has a second config that could as easily
+- * have been an alternate interface setting (on most hardware).
+- *
+- * NOTE:  to demonstrate (and test) more USB capabilities, this driver
+- * should include an altsetting to test interrupt transfers, including
+- * high bandwidth modes at high speed.  (Maybe work like Intel's test
+- * device?)
+- */
+-static int config_buf(struct usb_gadget *gadget,
+-              u8 *buf, u8 type, unsigned index)
+-{
+-      int                             is_source_sink;
+-      int                             len;
+-      const struct usb_descriptor_header **function;
+-      int                             hs = 0;
+-
+-      /* two configurations will always be index 0 and index 1 */
+-      if (index > 1)
+-              return -EINVAL;
+-      is_source_sink = loopdefault ? (index == 1) : (index == 0);
+-
+-      if (gadget_is_dualspeed(gadget)) {
+-              hs = (gadget->speed == USB_SPEED_HIGH);
+-              if (type == USB_DT_OTHER_SPEED_CONFIG)
+-                      hs = !hs;
+-      }
+-      if (hs)
+-              function = is_source_sink
+-                      ? hs_source_sink_function
+-                      : hs_loopback_function;
+-      else
+-              function = is_source_sink
+-                      ? fs_source_sink_function
+-                      : fs_loopback_function;
+-
+-      /* for now, don't advertise srp-only devices */
+-      if (!gadget_is_otg(gadget))
+-              function++;
+-
+-      len = usb_gadget_config_buf(is_source_sink
+-                                      ? &source_sink_config
+-                                      : &loopback_config,
+-                      buf, USB_BUFSIZ, function);
+-      if (len < 0)
+-              return len;
+-      ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
+-      return len;
+-}
++static struct usb_gadget_strings *dev_strings[] = {
++      &stringtab_dev,
++      NULL,
++};
+ /*-------------------------------------------------------------------------*/
+-static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
++struct usb_request *alloc_ep_req(struct usb_ep *ep)
+ {
+       struct usb_request      *req;
+       req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+       if (req) {
+-              req->length = length;
+-              req->buf = kmalloc(length, GFP_ATOMIC);
++              req->length = buflen;
++              req->buf = kmalloc(buflen, GFP_ATOMIC);
+               if (!req->buf) {
+                       usb_ep_free_request(ep, req);
+                       req = NULL;
+@@ -433,681 +167,73 @@ static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
+       return req;
+ }
+-static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
++void free_ep_req(struct usb_ep *ep, struct usb_request *req)
+ {
+       kfree(req->buf);
+       usb_ep_free_request(ep, req);
+ }
+-/*-------------------------------------------------------------------------*/
+-
+-/*
+- * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals,
+- * this just sinks bulk packets OUT to the peripheral and sources them IN
+- * to the host, optionally with specific data patterns.
+- *
+- * In terms of control messaging, this supports all the standard requests
+- * plus two that support control-OUT tests.
+- *
+- * Note that because this doesn't queue more than one request at a time,
+- * some other function must be used to test queueing logic.  The network
+- * link (g_ether) is probably the best option for that.
+- */
+-
+-/* optionally require specific source/sink data patterns  */
+-
+-static int
+-check_read_data(
+-      struct zero_dev         *dev,
+-      struct usb_ep           *ep,
+-      struct usb_request      *req
+-)
++static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
+ {
+-      unsigned        i;
+-      u8              *buf = req->buf;
+-
+-      for (i = 0; i < req->actual; i++, buf++) {
+-              switch (pattern) {
+-              /* all-zeroes has no synchronization issues */
+-              case 0:
+-                      if (*buf == 0)
+-                              continue;
+-                      break;
+-              /* mod63 stays in sync with short-terminated transfers,
+-               * or otherwise when host and gadget agree on how large
+-               * each usb transfer request should be.  resync is done
+-               * with set_interface or set_config.
+-               */
+-              case 1:
+-                      if (*buf == (u8)(i % 63))
+-                              continue;
+-                      break;
+-              }
+-              ERROR(dev, "bad OUT byte, buf[%d] = %d\n", i, *buf);
+-              usb_ep_set_halt(ep);
+-              return -EINVAL;
++      int                     value;
++
++      if (ep->driver_data) {
++              value = usb_ep_disable(ep);
++              if (value < 0)
++                      DBG(cdev, "disable %s --> %d\n",
++                                      ep->name, value);
++              ep->driver_data = NULL;
+       }
+-      return 0;
+ }
+-static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
++void disable_endpoints(struct usb_composite_dev *cdev,
++              struct usb_ep *in, struct usb_ep *out)
+ {
+-      unsigned        i;
+-      u8              *buf = req->buf;
+-
+-      switch (pattern) {
+-      case 0:
+-              memset(req->buf, 0, req->length);
+-              break;
+-      case 1:
+-              for  (i = 0; i < req->length; i++)
+-                      *buf++ = (u8) (i % 63);
+-              break;
+-      }
+-}
+-
+-/* if there is only one request in the queue, there'll always be an
+- * irq delay between end of one request and start of the next.
+- * that prevents using hardware dma queues.
+- */
+-static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
+-{
+-      struct zero_dev *dev = ep->driver_data;
+-      int             status = req->status;
+-
+-      switch (status) {
+-
+-      case 0:                         /* normal completion? */
+-              if (ep == dev->out_ep) {
+-                      check_read_data(dev, ep, req);
+-                      memset(req->buf, 0x55, req->length);
+-              } else
+-                      reinit_write_data(ep, req);
+-              break;
+-
+-      /* this endpoint is normally active while we're configured */
+-      case -ECONNABORTED:             /* hardware forced ep reset */
+-      case -ECONNRESET:               /* request dequeued */
+-      case -ESHUTDOWN:                /* disconnect from host */
+-              VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
+-                              req->actual, req->length);
+-              if (ep == dev->out_ep)
+-                      check_read_data(dev, ep, req);
+-              free_ep_req(ep, req);
+-              return;
+-
+-      case -EOVERFLOW:                /* buffer overrun on read means that
+-                                       * we didn't provide a big enough
+-                                       * buffer.
+-                                       */
+-      default:
+-#if 1
+-              DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
+-                              status, req->actual, req->length);
+-#endif
+-      case -EREMOTEIO:                /* short read */
+-              break;
+-      }
+-
+-      status = usb_ep_queue(ep, req, GFP_ATOMIC);
+-      if (status) {
+-              ERROR(dev, "kill %s:  resubmit %d bytes --> %d\n",
+-                              ep->name, req->length, status);
+-              usb_ep_set_halt(ep);
+-              /* FIXME recover later ... somehow */
+-      }
+-}
+-
+-static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
+-{
+-      struct usb_request      *req;
+-      int                     status;
+-
+-      req = alloc_ep_req(ep, buflen);
+-      if (!req)
+-              return NULL;
+-
+-      memset(req->buf, 0, req->length);
+-      req->complete = source_sink_complete;
+-
+-      if (strcmp(ep->name, EP_IN_NAME) == 0)
+-              reinit_write_data(ep, req);
+-      else
+-              memset(req->buf, 0x55, req->length);
+-
+-      status = usb_ep_queue(ep, req, GFP_ATOMIC);
+-      if (status) {
+-              struct zero_dev *dev = ep->driver_data;
+-
+-              ERROR(dev, "start %s --> %d\n", ep->name, status);
+-              free_ep_req(ep, req);
+-              req = NULL;
+-      }
+-
+-      return req;
+-}
+-
+-static int set_source_sink_config(struct zero_dev *dev)
+-{
+-      int                     result = 0;
+-      struct usb_ep           *ep;
+-      struct usb_gadget       *gadget = dev->gadget;
+-
+-      gadget_for_each_ep(ep, gadget) {
+-              const struct usb_endpoint_descriptor    *d;
+-
+-              /* one endpoint writes (sources) zeroes in (to the host) */
+-              if (strcmp(ep->name, EP_IN_NAME) == 0) {
+-                      d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+-                      result = usb_ep_enable(ep, d);
+-                      if (result == 0) {
+-                              ep->driver_data = dev;
+-                              if (source_sink_start_ep(ep) != NULL) {
+-                                      dev->in_ep = ep;
+-                                      continue;
+-                              }
+-                              usb_ep_disable(ep);
+-                              result = -EIO;
+-                      }
+-
+-              /* one endpoint reads (sinks) anything out (from the host) */
+-              } else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
+-                      d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+-                      result = usb_ep_enable(ep, d);
+-                      if (result == 0) {
+-                              ep->driver_data = dev;
+-                              if (source_sink_start_ep(ep) != NULL) {
+-                                      dev->out_ep = ep;
+-                                      continue;
+-                              }
+-                              usb_ep_disable(ep);
+-                              result = -EIO;
+-                      }
+-
+-              /* ignore any other endpoints */
+-              } else
+-                      continue;
+-
+-              /* stop on error */
+-              ERROR(dev, "can't start %s, result %d\n", ep->name, result);
+-              break;
+-      }
+-      if (result == 0)
+-              DBG(dev, "buflen %d\n", buflen);
+-
+-      /* caller is responsible for cleanup on error */
+-      return result;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
+-{
+-      struct zero_dev *dev = ep->driver_data;
+-      int             status = req->status;
+-
+-      switch (status) {
+-
+-      case 0:                         /* normal completion? */
+-              if (ep == dev->out_ep) {
+-                      /* loop this OUT packet back IN to the host */
+-                      req->zero = (req->actual < req->length);
+-                      req->length = req->actual;
+-                      status = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
+-                      if (status == 0)
+-                              return;
+-
+-                      /* "should never get here" */
+-                      ERROR(dev, "can't loop %s to %s: %d\n",
+-                              ep->name, dev->in_ep->name,
+-                              status);
+-              }
+-
+-              /* queue the buffer for some later OUT packet */
+-              req->length = buflen;
+-              status = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
+-              if (status == 0)
+-                      return;
+-
+-              /* "should never get here" */
+-              /* FALLTHROUGH */
+-
+-      default:
+-              ERROR(dev, "%s loop complete --> %d, %d/%d\n", ep->name,
+-                              status, req->actual, req->length);
+-              /* FALLTHROUGH */
+-
+-      /* NOTE:  since this driver doesn't maintain an explicit record
+-       * of requests it submitted (just maintains qlen count), we
+-       * rely on the hardware driver to clean up on disconnect or
+-       * endpoint disable.
+-       */
+-      case -ECONNABORTED:             /* hardware forced ep reset */
+-      case -ECONNRESET:               /* request dequeued */
+-      case -ESHUTDOWN:                /* disconnect from host */
+-              free_ep_req(ep, req);
+-              return;
+-      }
+-}
+-
+-static int set_loopback_config(struct zero_dev *dev)
+-{
+-      int                     result = 0;
+-      struct usb_ep           *ep;
+-      struct usb_gadget       *gadget = dev->gadget;
+-
+-      gadget_for_each_ep(ep, gadget) {
+-              const struct usb_endpoint_descriptor    *d;
+-
+-              /* one endpoint writes data back IN to the host */
+-              if (strcmp(ep->name, EP_IN_NAME) == 0) {
+-                      d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+-                      result = usb_ep_enable(ep, d);
+-                      if (result == 0) {
+-                              ep->driver_data = dev;
+-                              dev->in_ep = ep;
+-                              continue;
+-                      }
+-
+-              /* one endpoint just reads OUT packets */
+-              } else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
+-                      d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+-                      result = usb_ep_enable(ep, d);
+-                      if (result == 0) {
+-                              ep->driver_data = dev;
+-                              dev->out_ep = ep;
+-                              continue;
+-                      }
+-
+-              /* ignore any other endpoints */
+-              } else
+-                      continue;
+-
+-              /* stop on error */
+-              ERROR(dev, "can't enable %s, result %d\n", ep->name, result);
+-              break;
+-      }
+-
+-      /* allocate a bunch of read buffers and queue them all at once.
+-       * we buffer at most 'qlen' transfers; fewer if any need more
+-       * than 'buflen' bytes each.
+-       */
+-      if (result == 0) {
+-              struct usb_request      *req;
+-              unsigned                i;
+-
+-              ep = dev->out_ep;
+-              for (i = 0; i < qlen && result == 0; i++) {
+-                      req = alloc_ep_req(ep, buflen);
+-                      if (req) {
+-                              req->complete = loopback_complete;
+-                              result = usb_ep_queue(ep, req, GFP_ATOMIC);
+-                              if (result)
+-                                      DBG(dev, "%s queue req --> %d\n",
+-                                                      ep->name, result);
+-                      } else
+-                              result = -ENOMEM;
+-              }
+-      }
+-      if (result == 0)
+-              DBG(dev, "qlen %d, buflen %d\n", qlen, buflen);
+-
+-      /* caller is responsible for cleanup on error */
+-      return result;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static void zero_reset_config(struct zero_dev *dev)
+-{
+-      if (dev->config == 0)
+-              return;
+-
+-      DBG(dev, "reset config\n");
+-
+-      /* just disable endpoints, forcing completion of pending i/o.
+-       * all our completion handlers free their requests in this case.
+-       */
+-      if (dev->in_ep) {
+-              usb_ep_disable(dev->in_ep);
+-              dev->in_ep = NULL;
+-      }
+-      if (dev->out_ep) {
+-              usb_ep_disable(dev->out_ep);
+-              dev->out_ep = NULL;
+-      }
+-      dev->config = 0;
+-      del_timer(&dev->resume);
+-}
+-
+-/* change our operational config.  this code must agree with the code
+- * that returns config descriptors, and altsetting code.
+- *
+- * it's also responsible for power management interactions. some
+- * configurations might not work with our current power sources.
+- *
+- * note that some device controller hardware will constrain what this
+- * code can do, perhaps by disallowing more than one configuration or
+- * by limiting configuration choices (like the pxa2xx).
+- */
+-static int zero_set_config(struct zero_dev *dev, unsigned number)
+-{
+-      int                     result = 0;
+-      struct usb_gadget       *gadget = dev->gadget;
+-
+-      if (number == dev->config)
+-              return 0;
+-
+-      if (gadget_is_sa1100(gadget) && dev->config) {
+-              /* tx fifo is full, but we can't clear it...*/
+-              ERROR(dev, "can't change configurations\n");
+-              return -ESPIPE;
+-      }
+-      zero_reset_config(dev);
+-
+-      switch (number) {
+-      case CONFIG_SOURCE_SINK:
+-              result = set_source_sink_config(dev);
+-              break;
+-      case CONFIG_LOOPBACK:
+-              result = set_loopback_config(dev);
+-              break;
+-      default:
+-              result = -EINVAL;
+-              /* FALL THROUGH */
+-      case 0:
+-              return result;
+-      }
+-
+-      if (!result && (!dev->in_ep || !dev->out_ep))
+-              result = -ENODEV;
+-      if (result)
+-              zero_reset_config(dev);
+-      else {
+-              char *speed;
+-
+-              switch (gadget->speed) {
+-              case USB_SPEED_LOW:     speed = "low"; break;
+-              case USB_SPEED_FULL:    speed = "full"; break;
+-              case USB_SPEED_HIGH:    speed = "high"; break;
+-              default:                speed = "?"; break;
+-              }
+-
+-              dev->config = number;
+-              INFO(dev, "%s speed config #%d: %s\n", speed, number,
+-                              (number == CONFIG_SOURCE_SINK)
+-                                      ? source_sink : loopback);
+-      }
+-      return result;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static void zero_setup_complete(struct usb_ep *ep, struct usb_request *req)
+-{
+-      if (req->status || req->actual != req->length)
+-              DBG((struct zero_dev *) ep->driver_data,
+-                              "setup complete --> %d, %d/%d\n",
+-                              req->status, req->actual, req->length);
+-}
+-
+-/*
+- * The setup() callback implements all the ep0 functionality that's
+- * not handled lower down, in hardware or the hardware driver (like
+- * device and endpoint feature flags, and their status).  It's all
+- * housekeeping for the gadget function we're implementing.  Most of
+- * the work is in config-specific setup.
+- */
+-static int
+-zero_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+-{
+-      struct zero_dev         *dev = get_gadget_data(gadget);
+-      struct usb_request      *req = dev->req;
+-      int                     value = -EOPNOTSUPP;
+-      u16                     w_index = le16_to_cpu(ctrl->wIndex);
+-      u16                     w_value = le16_to_cpu(ctrl->wValue);
+-      u16                     w_length = le16_to_cpu(ctrl->wLength);
+-
+-      /* usually this stores reply data in the pre-allocated ep0 buffer,
+-       * but config change events will reconfigure hardware.
+-       */
+-      req->zero = 0;
+-      switch (ctrl->bRequest) {
+-
+-      case USB_REQ_GET_DESCRIPTOR:
+-              if (ctrl->bRequestType != USB_DIR_IN)
+-                      goto unknown;
+-              switch (w_value >> 8) {
+-
+-              case USB_DT_DEVICE:
+-                      value = min(w_length, (u16) sizeof device_desc);
+-                      memcpy(req->buf, &device_desc, value);
+-                      break;
+-              case USB_DT_DEVICE_QUALIFIER:
+-                      if (!gadget_is_dualspeed(gadget))
+-                              break;
+-                      value = min(w_length, (u16) sizeof dev_qualifier);
+-                      memcpy(req->buf, &dev_qualifier, value);
+-                      break;
+-
+-              case USB_DT_OTHER_SPEED_CONFIG:
+-                      if (!gadget_is_dualspeed(gadget))
+-                              break;
+-                      // FALLTHROUGH
+-              case USB_DT_CONFIG:
+-                      value = config_buf(gadget, req->buf,
+-                                      w_value >> 8,
+-                                      w_value & 0xff);
+-                      if (value >= 0)
+-                              value = min(w_length, (u16) value);
+-                      break;
+-
+-              case USB_DT_STRING:
+-                      /* wIndex == language code.
+-                       * this driver only handles one language, you can
+-                       * add string tables for other languages, using
+-                       * any UTF-8 characters
+-                       */
+-                      value = usb_gadget_get_string(&stringtab,
+-                                      w_value & 0xff, req->buf);
+-                      if (value >= 0)
+-                              value = min(w_length, (u16) value);
+-                      break;
+-              }
+-              break;
+-
+-      /* currently two configs, two speeds */
+-      case USB_REQ_SET_CONFIGURATION:
+-              if (ctrl->bRequestType != 0)
+-                      goto unknown;
+-              if (gadget->a_hnp_support)
+-                      DBG(dev, "HNP available\n");
+-              else if (gadget->a_alt_hnp_support)
+-                      DBG(dev, "HNP needs a different root port\n");
+-              else
+-                      VDBG(dev, "HNP inactive\n");
+-              spin_lock(&dev->lock);
+-              value = zero_set_config(dev, w_value);
+-              spin_unlock(&dev->lock);
+-              break;
+-      case USB_REQ_GET_CONFIGURATION:
+-              if (ctrl->bRequestType != USB_DIR_IN)
+-                      goto unknown;
+-              *(u8 *)req->buf = dev->config;
+-              value = min(w_length, (u16) 1);
+-              break;
+-
+-      /* until we add altsetting support, or other interfaces,
+-       * only 0/0 are possible.  pxa2xx only supports 0/0 (poorly)
+-       * and already killed pending endpoint I/O.
+-       */
+-      case USB_REQ_SET_INTERFACE:
+-              if (ctrl->bRequestType != USB_RECIP_INTERFACE)
+-                      goto unknown;
+-              spin_lock(&dev->lock);
+-              if (dev->config && w_index == 0 && w_value == 0) {
+-                      u8              config = dev->config;
+-
+-                      /* resets interface configuration, forgets about
+-                       * previous transaction state (queued bufs, etc)
+-                       * and re-inits endpoint state (toggle etc)
+-                       * no response queued, just zero status == success.
+-                       * if we had more than one interface we couldn't
+-                       * use this "reset the config" shortcut.
+-                       */
+-                      zero_reset_config(dev);
+-                      zero_set_config(dev, config);
+-                      value = 0;
+-              }
+-              spin_unlock(&dev->lock);
+-              break;
+-      case USB_REQ_GET_INTERFACE:
+-              if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
+-                      goto unknown;
+-              if (!dev->config)
+-                      break;
+-              if (w_index != 0) {
+-                      value = -EDOM;
+-                      break;
+-              }
+-              *(u8 *)req->buf = 0;
+-              value = min(w_length, (u16) 1);
+-              break;
+-
+-      /*
+-       * These are the same vendor-specific requests supported by
+-       * Intel's USB 2.0 compliance test devices.  We exceed that
+-       * device spec by allowing multiple-packet requests.
+-       */
+-      case 0x5b:      /* control WRITE test -- fill the buffer */
+-              if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
+-                      goto unknown;
+-              if (w_value || w_index)
+-                      break;
+-              /* just read that many bytes into the buffer */
+-              if (w_length > USB_BUFSIZ)
+-                      break;
+-              value = w_length;
+-              break;
+-      case 0x5c:      /* control READ test -- return the buffer */
+-              if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
+-                      goto unknown;
+-              if (w_value || w_index)
+-                      break;
+-              /* expect those bytes are still in the buffer; send back */
+-              if (w_length > USB_BUFSIZ
+-                              || w_length != req->length)
+-                      break;
+-              value = w_length;
+-              break;
+-
+-      default:
+-unknown:
+-              VDBG(dev,
+-                      "unknown control req%02x.%02x v%04x i%04x l%d\n",
+-                      ctrl->bRequestType, ctrl->bRequest,
+-                      w_value, w_index, w_length);
+-      }
+-
+-      /* respond with data transfer before status phase? */
+-      if (value >= 0) {
+-              req->length = value;
+-              req->zero = value < w_length;
+-              value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+-              if (value < 0) {
+-                      DBG(dev, "ep_queue --> %d\n", value);
+-                      req->status = 0;
+-                      zero_setup_complete(gadget->ep0, req);
+-              }
+-      }
+-
+-      /* device either stalls (value < 0) or reports success */
+-      return value;
+-}
+-
+-static void zero_disconnect(struct usb_gadget *gadget)
+-{
+-      struct zero_dev         *dev = get_gadget_data(gadget);
+-      unsigned long           flags;
+-
+-      spin_lock_irqsave(&dev->lock, flags);
+-      zero_reset_config(dev);
+-
+-      /* a more significant application might have some non-usb
+-       * activities to quiesce here, saving resources like power
+-       * or pushing the notification up a network stack.
+-       */
+-      spin_unlock_irqrestore(&dev->lock, flags);
+-
+-      /* next we may get setup() calls to enumerate new connections;
+-       * or an unbind() during shutdown (including removing module).
+-       */
+-}
+-
+-static void zero_autoresume(unsigned long _dev)
+-{
+-      struct zero_dev *dev = (struct zero_dev *) _dev;
+-      int             status;
+-
+-      /* normally the host would be woken up for something
+-       * more significant than just a timer firing...
+-       */
+-      if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
+-              status = usb_gadget_wakeup(dev->gadget);
+-              DBG(dev, "wakeup --> %d\n", status);
+-      }
++      disable_ep(cdev, in);
++      disable_ep(cdev, out);
+ }
+ /*-------------------------------------------------------------------------*/
+-static void zero_unbind(struct usb_gadget *gadget)
++static int __init zero_bind(struct usb_composite_dev *cdev)
+ {
+-      struct zero_dev         *dev = get_gadget_data(gadget);
+-
+-      DBG(dev, "unbind\n");
+-
+-      /* we've already been disconnected ... no i/o is active */
+-      if (dev->req) {
+-              dev->req->length = USB_BUFSIZ;
+-              free_ep_req(gadget->ep0, dev->req);
+-      }
+-      del_timer_sync(&dev->resume);
+-      kfree(dev);
+-      set_gadget_data(gadget, NULL);
+-}
+-
+-static int __init zero_bind(struct usb_gadget *gadget)
+-{
+-      struct zero_dev         *dev;
+-      struct usb_ep           *ep;
+       int                     gcnum;
++      struct usb_gadget       *gadget = cdev->gadget;
++      int                     id;
+-      /* FIXME this can't yet work right with SH ... it has only
+-       * one configuration, numbered one.
++      /* Allocate string descriptor numbers ... note that string
++       * contents can be overridden by the composite_dev glue.
+        */
+-      if (gadget_is_sh(gadget))
+-              return -ENODEV;
+-
+-      /* Bulk-only drivers like this one SHOULD be able to
+-       * autoconfigure on any sane usb controller driver,
+-       * but there may also be important quirks to address.
++      id = usb_string_id(cdev);
++      if (id < 0)
++              return id;
++      strings_dev[STRING_MANUFACTURER_IDX].id = id;
++      device_desc.iManufacturer = id;
++
++      id = usb_string_id(cdev);
++      if (id < 0)
++              return id;
++      strings_dev[STRING_PRODUCT_IDX].id = id;
++      device_desc.iProduct = id;
++
++      id = usb_string_id(cdev);
++      if (id < 0)
++              return id;
++      strings_dev[STRING_SERIAL_IDX].id = id;
++      device_desc.iSerialNumber = id;
++
++      /* Register primary, then secondary configuration.  Note that
++       * SH3 only allows one config...
+        */
+-      usb_ep_autoconfig_reset(gadget);
+-      ep = usb_ep_autoconfig(gadget, &fs_source_desc);
+-      if (!ep) {
+-autoconf_fail:
+-              pr_err("%s: can't autoconfigure on %s\n",
+-                      shortname, gadget->name);
+-              return -ENODEV;
++      if (loopdefault) {
++              loopback_add(cdev);
++              if (!gadget_is_sh(gadget))
++                      sourcesink_add(cdev);
++      } else {
++              sourcesink_add(cdev);
++              if (!gadget_is_sh(gadget))
++                      loopback_add(cdev);
+       }
+-      EP_IN_NAME = ep->name;
+-      ep->driver_data = ep;   /* claim */
+-
+-      ep = usb_ep_autoconfig(gadget, &fs_sink_desc);
+-      if (!ep)
+-              goto autoconf_fail;
+-      EP_OUT_NAME = ep->name;
+-      ep->driver_data = ep;   /* claim */
+       gcnum = usb_gadget_controller_number(gadget);
+       if (gcnum >= 0)
+@@ -1115,144 +241,44 @@ autoconf_fail:
+       else {
+               /* gadget zero is so simple (for now, no altsettings) that
+                * it SHOULD NOT have problems with bulk-capable hardware.
+-               * so warn about unrcognized controllers, don't panic.
++               * so just warn about unrcognized controllers -- don't panic.
+                *
+                * things like configuration and altsetting numbering
+                * can need hardware-specific attention though.
+                */
+               pr_warning("%s: controller '%s' not recognized\n",
+-                      shortname, gadget->name);
++                      longname, gadget->name);
+               device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
+       }
+-      /* ok, we made sense of the hardware ... */
+-      dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+-      if (!dev)
+-              return -ENOMEM;
+-      spin_lock_init(&dev->lock);
+-      dev->gadget = gadget;
+-      set_gadget_data(gadget, dev);
+-
+-      init_timer(&dev->resume);
+-      dev->resume.function = zero_autoresume;
+-      dev->resume.data = (unsigned long) dev;
+-
+-      /* preallocate control response and buffer */
+-      dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+-      if (!dev->req)
+-              goto enomem;
+-      dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
+-      if (!dev->req->buf)
+-              goto enomem;
+-
+-      dev->req->complete = zero_setup_complete;
+-
+-      device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+-
+-      if (gadget_is_dualspeed(gadget)) {
+-              /* assume ep0 uses the same value for both speeds ... */
+-              dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+-
+-              /* and that all endpoints are dual-speed */
+-              hs_source_desc.bEndpointAddress =
+-                              fs_source_desc.bEndpointAddress;
+-              hs_sink_desc.bEndpointAddress =
+-                              fs_sink_desc.bEndpointAddress;
+-      }
+-
+-      if (gadget_is_otg(gadget)) {
+-              otg_descriptor.bmAttributes |= USB_OTG_HNP,
+-              source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+-              loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+-      }
+-
+-      usb_gadget_set_selfpowered(gadget);
+-
+-      if (autoresume) {
+-              source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+-              loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+-      }
+-
+-      gadget->ep0->driver_data = dev;
+-
+-      INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
+-      INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
+-              EP_OUT_NAME, EP_IN_NAME);
++      INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);
+       snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+               init_utsname()->sysname, init_utsname()->release,
+               gadget->name);
+       return 0;
+-
+-enomem:
+-      zero_unbind(gadget);
+-      return -ENOMEM;
+ }
+-/*-------------------------------------------------------------------------*/
+-
+-static void zero_suspend(struct usb_gadget *gadget)
+-{
+-      struct zero_dev         *dev = get_gadget_data(gadget);
+-
+-      if (gadget->speed == USB_SPEED_UNKNOWN)
+-              return;
+-
+-      if (autoresume) {
+-              mod_timer(&dev->resume, jiffies + (HZ * autoresume));
+-              DBG(dev, "suspend, wakeup in %d seconds\n", autoresume);
+-      } else
+-              DBG(dev, "suspend\n");
+-}
+-
+-static void zero_resume(struct usb_gadget *gadget)
+-{
+-      struct zero_dev         *dev = get_gadget_data(gadget);
+-
+-      DBG(dev, "resume\n");
+-      del_timer(&dev->resume);
+-}
+-
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static struct usb_gadget_driver zero_driver = {
+-#ifdef CONFIG_USB_GADGET_DUALSPEED
+-      .speed          = USB_SPEED_HIGH,
+-#else
+-      .speed          = USB_SPEED_FULL,
+-#endif
+-      .function       = (char *) longname,
++static struct usb_composite_driver zero_driver = {
++      .name           = "zero",
++      .dev            = &device_desc,
++      .strings        = dev_strings,
+       .bind           = zero_bind,
+-      .unbind         = __exit_p(zero_unbind),
+-
+-      .setup          = zero_setup,
+-      .disconnect     = zero_disconnect,
+-
+-      .suspend        = zero_suspend,
+-      .resume         = zero_resume,
+-
+-      .driver         = {
+-              .name           = (char *) shortname,
+-              .owner          = THIS_MODULE,
+-      },
+ };
+ MODULE_AUTHOR("David Brownell");
+ MODULE_LICENSE("GPL");
+-
+ static int __init init(void)
+ {
+-      return usb_gadget_register_driver(&zero_driver);
++      return usb_composite_register(&zero_driver);
+ }
+ module_init(init);
+ static void __exit cleanup(void)
+ {
+-      usb_gadget_unregister_driver(&zero_driver);
++      usb_composite_unregister(&zero_driver);
+ }
+ module_exit(cleanup);
+-
+diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
+new file mode 100644
+index 0000000..c932390
+--- /dev/null
++++ b/include/linux/usb/composite.h
+@@ -0,0 +1,338 @@
++/*
++ * composite.h -- framework for usb gadgets which are composite devices
++ *
++ * Copyright (C) 2006-2008 David Brownell
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#ifndef       __LINUX_USB_COMPOSITE_H
++#define       __LINUX_USB_COMPOSITE_H
++
++/*
++ * This framework is an optional layer on top of the USB Gadget interface,
++ * making it easier to build (a) Composite devices, supporting multiple
++ * functions within any single configuration, and (b) Multi-configuration
++ * devices, also supporting multiple functions but without necessarily
++ * having more than one function per configuration.
++ *
++ * Example:  a device with a single configuration supporting both network
++ * link and mass storage functions is a composite device.  Those functions
++ * might alternatively be packaged in individual configurations, but in
++ * the composite model the host can use both functions at the same time.
++ */
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++
++struct usb_configuration;
++
++/**
++ * struct usb_function - describes one function of a configuration
++ * @name: For diagnostics, identifies the function.
++ * @strings: tables of strings, keyed by identifiers assigned during bind()
++ *    and by language IDs provided in control requests
++ * @descriptors: Table of full (or low) speed descriptors, using interface and
++ *    string identifiers assigned during @bind().  If this pointer is null,
++ *    the function will not be available at full speed (or at low speed).
++ * @hs_descriptors: Table of high speed descriptors, using interface and
++ *    string identifiers assigned during @bind().  If this pointer is null,
++ *    the function will not be available at high speed.
++ * @config: assigned when @usb_add_function() is called; this is the
++ *    configuration with which this function is associated.
++ * @bind: Before the gadget can register, all of its functions bind() to the
++ *    available resources including string and interface identifiers used
++ *    in interface or class descriptors; endpoints; I/O buffers; and so on.
++ * @unbind: Reverses @bind; called as a side effect of unregistering the
++ *    driver which added this function.
++ * @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may
++ *    initialize usb_ep.driver data at this time (when it is used).
++ *    Note that setting an interface to its current altsetting resets
++ *    interface state, and that all interfaces have a disabled state.
++ * @get_alt: Returns the active altsetting.  If this is not provided,
++ *    then only altsetting zero is supported.
++ * @disable: (REQUIRED) Indicates the function should be disabled.  Reasons
++ *    include host resetting or reconfiguring the gadget, and disconnection.
++ * @setup: Used for interface-specific control requests.
++ * @suspend: Notifies functions when the host stops sending USB traffic.
++ * @resume: Notifies functions when the host restarts USB traffic.
++ *
++ * A single USB function uses one or more interfaces, and should in most
++ * cases support operation at both full and high speeds.  Each function is
++ * associated by @usb_add_function() with a one configuration; that function
++ * causes @bind() to be called so resources can be allocated as part of
++ * setting up a gadget driver.  Those resources include endpoints, which
++ * should be allocated using @usb_ep_autoconfig().
++ *
++ * To support dual speed operation, a function driver provides descriptors
++ * for both high and full speed operation.  Except in rare cases that don't
++ * involve bulk endpoints, each speed needs different endpoint descriptors.
++ *
++ * Function drivers choose their own strategies for managing instance data.
++ * The simplest strategy just declares it "static', which means the function
++ * can only be activated once.  If the function needs to be exposed in more
++ * than one configuration at a given speed, it needs to support multiple
++ * usb_function structures (one for each configuration).
++ *
++ * A more complex strategy might encapsulate a @usb_function structure inside
++ * a driver-specific instance structure to allows multiple activations.  An
++ * example of multiple activations might be a CDC ACM function that supports
++ * two or more distinct instances within the same configuration, providing
++ * several independent logical data links to a USB host.
++ */
++struct usb_function {
++      const char                      *name;
++      struct usb_gadget_strings       **strings;
++      struct usb_descriptor_header    **descriptors;
++      struct usb_descriptor_header    **hs_descriptors;
++
++      struct usb_configuration        *config;
++
++      /* REVISIT:  bind() functions can be marked __init, which
++       * makes trouble for section mismatch analysis.  See if
++       * we can't restructure things to avoid mismatching.
++       * Related:  unbind() may kfree() but bind() won't...
++       */
++
++      /* configuration management:  bind/unbind */
++      int                     (*bind)(struct usb_configuration *,
++                                      struct usb_function *);
++      void                    (*unbind)(struct usb_configuration *,
++                                      struct usb_function *);
++
++      /* runtime state management */
++      int                     (*set_alt)(struct usb_function *,
++                                      unsigned interface, unsigned alt);
++      int                     (*get_alt)(struct usb_function *,
++                                      unsigned interface);
++      void                    (*disable)(struct usb_function *);
++      int                     (*setup)(struct usb_function *,
++                                      const struct usb_ctrlrequest *);
++      void                    (*suspend)(struct usb_function *);
++      void                    (*resume)(struct usb_function *);
++
++      /* internals */
++      struct list_head                list;
++};
++
++int usb_add_function(struct usb_configuration *, struct usb_function *);
++
++int usb_interface_id(struct usb_configuration *, struct usb_function *);
++
++/**
++ * ep_choose - select descriptor endpoint at current device speed
++ * @g: gadget, connected and running at some speed
++ * @hs: descriptor to use for high speed operation
++ * @fs: descriptor to use for full or low speed operation
++ */
++static inline struct usb_endpoint_descriptor *
++ep_choose(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
++              struct usb_endpoint_descriptor *fs)
++{
++      if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
++              return hs;
++      return fs;
++}
++
++#define       MAX_CONFIG_INTERFACES           16      /* arbitrary; max 255 */
++
++/**
++ * struct usb_configuration - represents one gadget configuration
++ * @label: For diagnostics, describes the configuration.
++ * @strings: Tables of strings, keyed by identifiers assigned during @bind()
++ *    and by language IDs provided in control requests.
++ * @descriptors: Table of descriptors preceding all function descriptors.
++ *    Examples include OTG and vendor-specific descriptors.
++ * @bind: Called from @usb_add_config() to allocate resources unique to this
++ *    configuration and to call @usb_add_function() for each function used.
++ * @unbind: Reverses @bind; called as a side effect of unregistering the
++ *    driver which added this configuration.
++ * @setup: Used to delegate control requests that aren't handled by standard
++ *    device infrastructure or directed at a specific interface.
++ * @bConfigurationValue: Copied into configuration descriptor.
++ * @iConfiguration: Copied into configuration descriptor.
++ * @bmAttributes: Copied into configuration descriptor.
++ * @bMaxPower: Copied into configuration descriptor.
++ * @cdev: assigned by @usb_add_config() before calling @bind(); this is
++ *    the device associated with this configuration.
++ *
++ * Configurations are building blocks for gadget drivers structured around
++ * function drivers.  Simple USB gadgets require only one function and one
++ * configuration, and handle dual-speed hardware by always providing the same
++ * functionality.  Slightly more complex gadgets may have more than one
++ * single-function configuration at a given speed; or have configurations
++ * that only work at one speed.
++ *
++ * Composite devices are, by definition, ones with configurations which
++ * include more than one function.
++ *
++ * The lifecycle of a usb_configuration includes allocation, initialization
++ * of the fields described above, and calling @usb_add_config() to set up
++ * internal data and bind it to a specific device.  The configuration's
++ * @bind() method is then used to initialize all the functions and then
++ * call @usb_add_function() for them.
++ *
++ * Those functions would normally be independant of each other, but that's
++ * not mandatory.  CDC WMC devices are an example where functions often
++ * depend on other functions, with some functions subsidiary to others.
++ * Such interdependency may be managed in any way, so long as all of the
++ * descriptors complete by the time the composite driver returns from
++ * its bind() routine.
++ */
++struct usb_configuration {
++      const char                      *label;
++      struct usb_gadget_strings       **strings;
++      const struct usb_descriptor_header **descriptors;
++
++      /* REVISIT:  bind() functions can be marked __init, which
++       * makes trouble for section mismatch analysis.  See if
++       * we can't restructure things to avoid mismatching...
++       */
++
++      /* configuration management:  bind/unbind */
++      int                     (*bind)(struct usb_configuration *);
++      void                    (*unbind)(struct usb_configuration *);
++      int                     (*setup)(struct usb_configuration *,
++                                      const struct usb_ctrlrequest *);
++
++      /* fields in the config descriptor */
++      u8                      bConfigurationValue;
++      u8                      iConfiguration;
++      u8                      bmAttributes;
++      u8                      bMaxPower;
++
++      struct usb_composite_dev        *cdev;
++
++      /* internals */
++      struct list_head        list;
++      struct list_head        functions;
++      u8                      next_interface_id;
++      unsigned                highspeed:1;
++      unsigned                fullspeed:1;
++      struct usb_function     *interface[MAX_CONFIG_INTERFACES];
++};
++
++int usb_add_config(struct usb_composite_dev *,
++              struct usb_configuration *);
++
++/**
++ * struct usb_composite_driver - groups configurations into a gadget
++ * @name: For diagnostics, identifies the driver.
++ * @dev: Template descriptor for the device, including default device
++ *    identifiers.
++ * @strings: tables of strings, keyed by identifiers assigned during bind()
++ *    and language IDs provided in control requests
++ * @bind: (REQUIRED) Used to allocate resources that are shared across the
++ *    whole device, such as string IDs, and add its configurations using
++ *    @usb_add_config().  This may fail by returning a negative errno
++ *    value; it should return zero on successful initialization.
++ * @unbind: Reverses @bind(); called as a side effect of unregistering
++ *    this driver.
++ *
++ * Devices default to reporting self powered operation.  Devices which rely
++ * on bus powered operation should report this in their @bind() method.
++ *
++ * Before returning from @bind, various fields in the template descriptor
++ * may be overridden.  These include the idVendor/idProduct/bcdDevice values
++ * normally to bind the appropriate host side driver, and the three strings
++ * (iManufacturer, iProduct, iSerialNumber) normally used to provide user
++ * meaningful device identifiers.  (The strings will not be defined unless
++ * they are defined in @dev and @strings.)  The correct ep0 maxpacket size
++ * is also reported, as defined by the underlying controller driver.
++ */
++struct usb_composite_driver {
++      const char                              *name;
++      const struct usb_device_descriptor      *dev;
++      struct usb_gadget_strings               **strings;
++
++      /* REVISIT:  bind() functions can be marked __init, which
++       * makes trouble for section mismatch analysis.  See if
++       * we can't restructure things to avoid mismatching...
++       */
++
++      int                     (*bind)(struct usb_composite_dev *);
++      int                     (*unbind)(struct usb_composite_dev *);
++};
++
++extern int usb_composite_register(struct usb_composite_driver *);
++extern void usb_composite_unregister(struct usb_composite_driver *);
++
++
++/**
++ * struct usb_composite_device - represents one composite usb gadget
++ * @gadget: read-only, abstracts the gadget's usb peripheral controller
++ * @req: used for control responses; buffer is pre-allocated
++ * @bufsiz: size of buffer pre-allocated in @req
++ * @config: the currently active configuration
++ *
++ * One of these devices is allocated and initialized before the
++ * associated device driver's bind() is called.
++ *
++ * OPEN ISSUE:  it appears that some WUSB devices will need to be
++ * built by combining a normal (wired) gadget with a wireless one.
++ * This revision of the gadget framework should probably try to make
++ * sure doing that won't hurt too much.
++ *
++ * One notion for how to handle Wireless USB devices involves:
++ * (a) a second gadget here, discovery mechanism TBD, but likely
++ *     needing separate "register/unregister WUSB gadget" calls;
++ * (b) updates to usb_gadget to include flags "is it wireless",
++ *     "is it wired", plus (presumably in a wrapper structure)
++ *     bandgroup and PHY info;
++ * (c) presumably a wireless_ep wrapping a usb_ep, and reporting
++ *     wireless-specific parameters like maxburst and maxsequence;
++ * (d) configurations that are specific to wireless links;
++ * (e) function drivers that understand wireless configs and will
++ *     support wireless for (additional) function instances;
++ * (f) a function to support association setup (like CBAF), not
++ *     necessarily requiring a wireless adapter;
++ * (g) composite device setup that can create one or more wireless
++ *     configs, including appropriate association setup support;
++ * (h) more, TBD.
++ */
++struct usb_composite_dev {
++      struct usb_gadget               *gadget;
++      struct usb_request              *req;
++      unsigned                        bufsiz;
++
++      struct usb_configuration        *config;
++
++      /* internals */
++      struct usb_device_descriptor    desc;
++      struct list_head                configs;
++      struct usb_composite_driver     *driver;
++      u8                              next_string_id;
++
++      spinlock_t                      lock;
++
++      /* REVISIT use and existence of lock ... */
++};
++
++extern int usb_string_id(struct usb_composite_dev *c);
++
++/* messaging utils */
++#define DBG(d, fmt, args...) \
++      dev_dbg(&(d)->gadget->dev , fmt , ## args)
++#define VDBG(d, fmt, args...) \
++      dev_vdbg(&(d)->gadget->dev , fmt , ## args)
++#define ERROR(d, fmt, args...) \
++      dev_err(&(d)->gadget->dev , fmt , ## args)
++#define WARNING(d, fmt, args...) \
++      dev_warn(&(d)->gadget->dev , fmt , ## args)
++#define INFO(d, fmt, args...) \
++      dev_info(&(d)->gadget->dev , fmt , ## args)
++
++#endif        /* __LINUX_USB_COMPOSITE_H */
+diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h
+new file mode 100644
+index 0000000..5b88e36
+--- /dev/null
++++ b/include/linux/usb/ehci_def.h
+@@ -0,0 +1,160 @@
++/*
++ * Copyright (c) 2001-2002 by David Brownell
++ *
++ * 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 __LINUX_USB_EHCI_DEF_H
++#define __LINUX_USB_EHCI_DEF_H
++
++/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
++
++/* Section 2.2 Host Controller Capability Registers */
++struct ehci_caps {
++      /* these fields are specified as 8 and 16 bit registers,
++       * but some hosts can't perform 8 or 16 bit PCI accesses.
++       */
++      u32             hc_capbase;
++#define HC_LENGTH(p)          (((p)>>00)&0x00ff)      /* bits 7:0 */
++#define HC_VERSION(p)         (((p)>>16)&0xffff)      /* bits 31:16 */
++      u32             hcs_params;     /* HCSPARAMS - offset 0x4 */
++#define HCS_DEBUG_PORT(p)     (((p)>>20)&0xf) /* bits 23:20, debug port? */
++#define HCS_INDICATOR(p)      ((p)&(1 << 16)) /* true: has port indicators */
++#define HCS_N_CC(p)           (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
++#define HCS_N_PCC(p)          (((p)>>8)&0xf)  /* bits 11:8, ports per CC */
++#define HCS_PORTROUTED(p)     ((p)&(1 << 7))  /* true: port routing */
++#define HCS_PPC(p)            ((p)&(1 << 4))  /* true: port power control */
++#define HCS_N_PORTS(p)                (((p)>>0)&0xf)  /* bits 3:0, ports on HC */
++
++      u32             hcc_params;      /* HCCPARAMS - offset 0x8 */
++#define HCC_EXT_CAPS(p)               (((p)>>8)&0xff) /* for pci extended caps */
++#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
++#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
++#define HCC_CANPARK(p)                ((p)&(1 << 2))  /* true: can park on async qh */
++#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
++#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
++      u8              portroute [8];   /* nibbles for routing - offset 0xC */
++} __attribute__ ((packed));
++
++
++/* Section 2.3 Host Controller Operational Registers */
++struct ehci_regs {
++
++      /* USBCMD: offset 0x00 */
++      u32             command;
++/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
++#define CMD_PARK      (1<<11)         /* enable "park" on async qh */
++#define CMD_PARK_CNT(c)       (((c)>>8)&3)    /* how many transfers to park for */
++#define CMD_LRESET    (1<<7)          /* partial reset (no ports, etc) */
++#define CMD_IAAD      (1<<6)          /* "doorbell" interrupt async advance */
++#define CMD_ASE               (1<<5)          /* async schedule enable */
++#define CMD_PSE               (1<<4)          /* periodic schedule enable */
++/* 3:2 is periodic frame list size */
++#define CMD_RESET     (1<<1)          /* reset HC not bus */
++#define CMD_RUN               (1<<0)          /* start/stop HC */
++
++      /* USBSTS: offset 0x04 */
++      u32             status;
++#define STS_ASS               (1<<15)         /* Async Schedule Status */
++#define STS_PSS               (1<<14)         /* Periodic Schedule Status */
++#define STS_RECL      (1<<13)         /* Reclamation */
++#define STS_HALT      (1<<12)         /* Not running (any reason) */
++/* some bits reserved */
++      /* these STS_* flags are also intr_enable bits (USBINTR) */
++#define STS_IAA               (1<<5)          /* Interrupted on async advance */
++#define STS_FATAL     (1<<4)          /* such as some PCI access errors */
++#define STS_FLR               (1<<3)          /* frame list rolled over */
++#define STS_PCD               (1<<2)          /* port change detect */
++#define STS_ERR               (1<<1)          /* "error" completion (overflow, ...) */
++#define STS_INT               (1<<0)          /* "normal" completion (short, ...) */
++
++      /* USBINTR: offset 0x08 */
++      u32             intr_enable;
++
++      /* FRINDEX: offset 0x0C */
++      u32             frame_index;    /* current microframe number */
++      /* CTRLDSSEGMENT: offset 0x10 */
++      u32             segment;        /* address bits 63:32 if needed */
++      /* PERIODICLISTBASE: offset 0x14 */
++      u32             frame_list;     /* points to periodic list */
++      /* ASYNCLISTADDR: offset 0x18 */
++      u32             async_next;     /* address of next async queue head */
++
++      u32             reserved [9];
++
++      /* CONFIGFLAG: offset 0x40 */
++      u32             configured_flag;
++#define FLAG_CF               (1<<0)          /* true: we'll support "high speed" */
++
++      /* PORTSC: offset 0x44 */
++      u32             port_status [0];        /* up to N_PORTS */
++/* 31:23 reserved */
++#define PORT_WKOC_E   (1<<22)         /* wake on overcurrent (enable) */
++#define PORT_WKDISC_E (1<<21)         /* wake on disconnect (enable) */
++#define PORT_WKCONN_E (1<<20)         /* wake on connect (enable) */
++/* 19:16 for port testing */
++#define PORT_LED_OFF  (0<<14)
++#define PORT_LED_AMBER        (1<<14)
++#define PORT_LED_GREEN        (2<<14)
++#define PORT_LED_MASK (3<<14)
++#define PORT_OWNER    (1<<13)         /* true: companion hc owns this port */
++#define PORT_POWER    (1<<12)         /* true: has power (see PPC) */
++#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10))      /* USB 1.1 device */
++/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
++/* 9 reserved */
++#define PORT_RESET    (1<<8)          /* reset port */
++#define PORT_SUSPEND  (1<<7)          /* suspend port */
++#define PORT_RESUME   (1<<6)          /* resume it */
++#define PORT_OCC      (1<<5)          /* over current change */
++#define PORT_OC               (1<<4)          /* over current active */
++#define PORT_PEC      (1<<3)          /* port enable change */
++#define PORT_PE               (1<<2)          /* port enable */
++#define PORT_CSC      (1<<1)          /* connect status change */
++#define PORT_CONNECT  (1<<0)          /* device connected */
++#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
++} __attribute__ ((packed));
++
++#define USBMODE               0x68            /* USB Device mode */
++#define USBMODE_SDIS  (1<<3)          /* Stream disable */
++#define USBMODE_BE    (1<<2)          /* BE/LE endianness select */
++#define USBMODE_CM_HC (3<<0)          /* host controller mode */
++#define USBMODE_CM_IDLE       (0<<0)          /* idle state */
++
++/* Appendix C, Debug port ... intended for use with special "debug devices"
++ * that can help if there's no serial console.  (nonstandard enumeration.)
++ */
++struct ehci_dbg_port {
++      u32     control;
++#define DBGP_OWNER    (1<<30)
++#define DBGP_ENABLED  (1<<28)
++#define DBGP_DONE     (1<<16)
++#define DBGP_INUSE    (1<<10)
++#define DBGP_ERRCODE(x)       (((x)>>7)&0x07)
++#     define DBGP_ERR_BAD     1
++#     define DBGP_ERR_SIGNAL  2
++#define DBGP_ERROR    (1<<6)
++#define DBGP_GO               (1<<5)
++#define DBGP_OUT      (1<<4)
++#define DBGP_LEN(x)   (((x)>>0)&0x0f)
++      u32     pids;
++#define DBGP_PID_GET(x)               (((x)>>16)&0xff)
++#define DBGP_PID_SET(data, tok)       (((data)<<8)|(tok))
++      u32     data03;
++      u32     data47;
++      u32     address;
++#define DBGP_EPADDR(dev, ep)  (((dev)<<8)|(ep))
++} __attribute__ ((packed));
++
++#endif /* __LINUX_USB_EHCI_DEF_H */
+diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
+index cf468fb..0460a74 100644
+--- a/include/linux/usb/gadget.h
++++ b/include/linux/usb/gadget.h
+@@ -33,7 +33,8 @@ struct usb_ep;
+  * @short_not_ok: When reading data, makes short packets be
+  *     treated as errors (queue stops advancing till cleanup).
+  * @complete: Function called when request completes, so this request and
+- *    its buffer may be re-used.
++ *    its buffer may be re-used.  The function will always be called with
++ *    interrupts disabled, and it must not sleep.
+  *    Reads terminate with a short packet, or when the buffer fills,
+  *    whichever comes first.  When writes terminate, some data bytes
+  *    will usually still be in flight (often in a hardware fifo).
+@@ -271,7 +272,10 @@ static inline void usb_ep_free_request(struct usb_ep *ep,
+  * (Note that some USB device controllers disallow protocol stall responses
+  * in some cases.)  When control responses are deferred (the response is
+  * written after the setup callback returns), then usb_ep_set_halt() may be
+- * used on ep0 to trigger protocol stalls.
++ * used on ep0 to trigger protocol stalls.  Depending on the controller,
++ * it may not be possible to trigger a status-stage protocol stall when the
++ * data stage is over, that is, from within the response's completion
++ * routine.
+  *
+  * For periodic endpoints, like interrupt or isochronous ones, the usb host
+  * arranges to poll once per interval, and the gadget driver usually will
+@@ -858,6 +862,25 @@ int usb_descriptor_fillbuf(void *, unsigned,
+ int usb_gadget_config_buf(const struct usb_config_descriptor *config,
+       void *buf, unsigned buflen, const struct usb_descriptor_header **desc);
++/* copy a NULL-terminated vector of descriptors */
++struct usb_descriptor_header **usb_copy_descriptors(
++              struct usb_descriptor_header **);
++
++/* return copy of endpoint descriptor given original descriptor set */
++struct usb_endpoint_descriptor *usb_find_endpoint(
++      struct usb_descriptor_header **src,
++      struct usb_descriptor_header **copy,
++      struct usb_endpoint_descriptor *match);
++
++/**
++ * usb_free_descriptors - free descriptors returned by usb_copy_descriptors()
++ * @v: vector of descriptors
++ */
++static inline void usb_free_descriptors(struct usb_descriptor_header **v)
++{
++      kfree(v);
++}
++
+ /*-------------------------------------------------------------------------*/
+ /* utility wrapping a simple endpoint selection policy */
+diff --git a/include/linux/usb/irda.h b/include/linux/usb/irda.h
+new file mode 100644
+index 0000000..e345cea
+--- /dev/null
++++ b/include/linux/usb/irda.h
+@@ -0,0 +1,151 @@
++/*
++ * USB IrDA Bridge Device Definition
++ */
++
++#ifndef __LINUX_USB_IRDA_H
++#define __LINUX_USB_IRDA_H
++
++/* This device should use Application-specific class */
++
++#define USB_SUBCLASS_IRDA                     0x02
++
++/*-------------------------------------------------------------------------*/
++
++/* Class-Specific requests (bRequest field) */
++
++#define USB_REQ_CS_IRDA_RECEIVING             1
++#define USB_REQ_CS_IRDA_CHECK_MEDIA_BUSY      3
++#define USB_REQ_CS_IRDA_RATE_SNIFF            4
++#define USB_REQ_CS_IRDA_UNICAST_LIST          5
++#define USB_REQ_CS_IRDA_GET_CLASS_DESC                6
++
++/*-------------------------------------------------------------------------*/
++
++/* Class-Specific descriptor */
++
++#define USB_DT_CS_IRDA                                0x21
++
++/*-------------------------------------------------------------------------*/
++
++/* Data sizes */
++
++#define USB_IRDA_DS_2048                      (1 << 5)
++#define USB_IRDA_DS_1024                      (1 << 4)
++#define USB_IRDA_DS_512                               (1 << 3)
++#define USB_IRDA_DS_256                               (1 << 2)
++#define USB_IRDA_DS_128                               (1 << 1)
++#define USB_IRDA_DS_64                                (1 << 0)
++
++/* Window sizes */
++
++#define USB_IRDA_WS_7                         (1 << 6)
++#define USB_IRDA_WS_6                         (1 << 5)
++#define USB_IRDA_WS_5                         (1 << 4)
++#define USB_IRDA_WS_4                         (1 << 3)
++#define USB_IRDA_WS_3                         (1 << 2)
++#define USB_IRDA_WS_2                         (1 << 1)
++#define USB_IRDA_WS_1                         (1 << 0)
++
++/* Min turnaround times in usecs */
++
++#define USB_IRDA_MTT_0                                (1 << 7)
++#define USB_IRDA_MTT_10                               (1 << 6)
++#define USB_IRDA_MTT_50                               (1 << 5)
++#define USB_IRDA_MTT_100                      (1 << 4)
++#define USB_IRDA_MTT_500                      (1 << 3)
++#define USB_IRDA_MTT_1000                     (1 << 2)
++#define USB_IRDA_MTT_5000                     (1 << 1)
++#define USB_IRDA_MTT_10000                    (1 << 0)
++
++/* Baud rates */
++
++#define USB_IRDA_BR_4000000                   (1 << 8)
++#define USB_IRDA_BR_1152000                   (1 << 7)
++#define USB_IRDA_BR_576000                    (1 << 6)
++#define USB_IRDA_BR_115200                    (1 << 5)
++#define USB_IRDA_BR_57600                     (1 << 4)
++#define USB_IRDA_BR_38400                     (1 << 3)
++#define USB_IRDA_BR_19200                     (1 << 2)
++#define USB_IRDA_BR_9600                      (1 << 1)
++#define USB_IRDA_BR_2400                      (1 << 0)
++
++/* Additional BOFs */
++
++#define USB_IRDA_AB_0                         (1 << 7)
++#define USB_IRDA_AB_1                         (1 << 6)
++#define USB_IRDA_AB_2                         (1 << 5)
++#define USB_IRDA_AB_3                         (1 << 4)
++#define USB_IRDA_AB_6                         (1 << 3)
++#define USB_IRDA_AB_12                                (1 << 2)
++#define USB_IRDA_AB_24                                (1 << 1)
++#define USB_IRDA_AB_48                                (1 << 0)
++
++/* IRDA Rate Sniff */
++
++#define USB_IRDA_RATE_SNIFF                   1
++
++/*-------------------------------------------------------------------------*/
++
++struct usb_irda_cs_descriptor {
++      __u8    bLength;
++      __u8    bDescriptorType;
++
++      __le16  bcdSpecRevision;
++      __u8    bmDataSize;
++      __u8    bmWindowSize;
++      __u8    bmMinTurnaroundTime;
++      __le16  wBaudRate;
++      __u8    bmAdditionalBOFs;
++      __u8    bIrdaRateSniff;
++      __u8    bMaxUnicastList;
++} __attribute__ ((packed));
++
++/*-------------------------------------------------------------------------*/
++
++/* Data Format */
++
++#define USB_IRDA_STATUS_MEDIA_BUSY    (1 << 7)
++
++/* The following is a 4-bit value used for both
++ * inbound and outbound headers:
++ *
++ * 0 - speed ignored
++ * 1 - 2400 bps
++ * 2 - 9600 bps
++ * 3 - 19200 bps
++ * 4 - 38400 bps
++ * 5 - 57600 bps
++ * 6 - 115200 bps
++ * 7 - 576000 bps
++ * 8 - 1.152 Mbps
++ * 9 - 5 mbps
++ * 10..15 - Reserved
++ */
++#define USB_IRDA_STATUS_LINK_SPEED    0x0f
++
++/* The following is a 4-bit value used only for
++ * outbound header:
++ *
++ * 0 - No change (BOF ignored)
++ * 1 - 48 BOFs
++ * 2 - 24 BOFs
++ * 3 - 12 BOFs
++ * 4 - 6 BOFs
++ * 5 - 3 BOFs
++ * 6 - 2 BOFs
++ * 7 - 1 BOFs
++ * 8 - 0 BOFs
++ * 9..15 - Reserved
++ */
++#define USB_IRDA_EXTRA_BOFS           0xf0
++
++struct usb_irda_inbound_header {
++      __u8            bmStatus;
++};
++
++struct usb_irda_outbound_header {
++      __u8            bmChange;
++};
++
++#endif /* __LINUX_USB_IRDA_H */
++
+diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h
+new file mode 100644
+index 0000000..630962c
+--- /dev/null
++++ b/include/linux/usb/musb.h
+@@ -0,0 +1,98 @@
++/*
++ * This is used to for host and peripheral modes of the driver for
++ * Inventra (Multidrop) Highspeed Dual-Role Controllers:  (M)HDRC.
++ *
++ * Board initialization should put one of these into dev->platform_data,
++ * probably on some platform_device named "musb_hdrc".  It encapsulates
++ * key configuration differences between boards.
++ */
++
++/* The USB role is defined by the connector used on the board, so long as
++ * standards are being followed.  (Developer boards sometimes won't.)
++ */
++enum musb_mode {
++      MUSB_UNDEFINED = 0,
++      MUSB_HOST,              /* A or Mini-A connector */
++      MUSB_PERIPHERAL,        /* B or Mini-B connector */
++      MUSB_OTG                /* Mini-AB connector */
++};
++
++struct clk;
++
++struct musb_hdrc_eps_bits {
++      const char      name[16];
++      u8              bits;
++};
++
++struct musb_hdrc_config {
++      /* MUSB configuration-specific details */
++      unsigned        multipoint:1;   /* multipoint device */
++      unsigned        dyn_fifo:1;     /* supports dynamic fifo sizing */
++      unsigned        soft_con:1;     /* soft connect required */
++      unsigned        utm_16:1;       /* utm data witdh is 16 bits */
++      unsigned        big_endian:1;   /* true if CPU uses big-endian */
++      unsigned        mult_bulk_tx:1; /* Tx ep required for multbulk pkts */
++      unsigned        mult_bulk_rx:1; /* Rx ep required for multbulk pkts */
++      unsigned        high_iso_tx:1;  /* Tx ep required for HB iso */
++      unsigned        high_iso_rx:1;  /* Rx ep required for HD iso */
++      unsigned        dma:1;          /* supports DMA */
++      unsigned        vendor_req:1;   /* vendor registers required */
++
++      u8              num_eps;        /* number of endpoints _with_ ep0 */
++      u8              dma_channels;   /* number of dma channels */
++      u8              dyn_fifo_size;  /* dynamic size in bytes */
++      u8              vendor_ctrl;    /* vendor control reg width */
++      u8              vendor_stat;    /* vendor status reg witdh */
++      u8              dma_req_chan;   /* bitmask for required dma channels */
++      u8              ram_bits;       /* ram address size */
++
++      struct musb_hdrc_eps_bits *eps_bits;
++};
++
++struct musb_hdrc_platform_data {
++      /* MUSB_HOST, MUSB_PERIPHERAL, or MUSB_OTG */
++      u8              mode;
++
++      /* for clk_get() */
++      const char      *clock;
++
++      /* (HOST or OTG) switch VBUS on/off */
++      int             (*set_vbus)(struct device *dev, int is_on);
++
++      /* (HOST or OTG) mA/2 power supplied on (default = 8mA) */
++      u8              power;
++
++      /* (PERIPHERAL) mA/2 max power consumed (default = 100mA) */
++      u8              min_power;
++
++      /* (HOST or OTG) msec/2 after VBUS on till power good */
++      u8              potpgt;
++
++      /* Power the device on or off */
++      int             (*set_power)(int state);
++
++      /* Turn device clock on or off */
++      int             (*set_clock)(struct clk *clock, int is_on);
++
++      /* MUSB configuration-specific details */
++      struct musb_hdrc_config *config;
++};
++
++
++/* TUSB 6010 support */
++
++#define       TUSB6010_OSCCLK_60      16667   /* psec/clk @ 60.0 MHz */
++#define       TUSB6010_REFCLK_24      41667   /* psec/clk @ 24.0 MHz XI */
++#define       TUSB6010_REFCLK_19      52083   /* psec/clk @ 19.2 MHz CLKIN */
++
++#ifdef        CONFIG_ARCH_OMAP2
++
++extern int __init tusb6010_setup_interface(
++              struct musb_hdrc_platform_data *data,
++              unsigned ps_refclk, unsigned waitpin,
++              unsigned async_cs, unsigned sync_cs,
++              unsigned irq, unsigned dmachan);
++
++extern int tusb6010_platform_retime(unsigned is_refclk);
++
++#endif        /* OMAP2 */
+diff --git a/include/linux/usb/rndis_host.h b/include/linux/usb/rndis_host.h
+index 29d6458..0a6e6d4 100644
+--- a/include/linux/usb/rndis_host.h
++++ b/include/linux/usb/rndis_host.h
+@@ -260,7 +260,8 @@ struct rndis_keepalive_c { /* IN (optionally OUT) */
+ extern void rndis_status(struct usbnet *dev, struct urb *urb);
+-extern int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf);
++extern int
++rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen);
+ extern int
+ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags);
+ extern void rndis_unbind(struct usbnet *dev, struct usb_interface *intf);
+diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
+index 8f891cb..655341d 100644
+--- a/include/linux/usb/serial.h
++++ b/include/linux/usb/serial.h
+@@ -17,7 +17,8 @@
+ #include <linux/mutex.h>
+ #define SERIAL_TTY_MAJOR      188     /* Nice legal number now */
+-#define SERIAL_TTY_MINORS     255     /* loads of devices :) */
++#define SERIAL_TTY_MINORS     254     /* loads of devices :) */
++#define SERIAL_TTY_NO_MINOR   255     /* No minor was assigned */
+ /* The maximum number of ports one device can grab at once */
+ #define MAX_NUM_PORTS         8
+@@ -62,7 +63,7 @@
+  */
+ struct usb_serial_port {
+       struct usb_serial       *serial;
+-      struct tty_struct       *tty;
++      struct tty_port         port;
+       spinlock_t              lock;
+       struct mutex            mutex;
+       unsigned char           number;
+@@ -89,7 +90,6 @@ struct usb_serial_port {
+       wait_queue_head_t       write_wait;
+       struct work_struct      work;
+-      int                     open_count;
+       char                    throttled;
+       char                    throttle_req;
+       char                    console;
+@@ -217,22 +217,27 @@ struct usb_serial_driver {
+       int (*resume)(struct usb_serial *serial);
+       /* serial function calls */
+-      int  (*open)(struct usb_serial_port *port, struct file *filp);
+-      void (*close)(struct usb_serial_port *port, struct file *filp);
+-      int  (*write)(struct usb_serial_port *port, const unsigned char *buf,
+-                    int count);
+-      int  (*write_room)(struct usb_serial_port *port);
+-      int  (*ioctl)(struct usb_serial_port *port, struct file *file,
++      /* Called by console with tty = NULL and by tty */
++      int  (*open)(struct tty_struct *tty,
++                      struct usb_serial_port *port, struct file *filp);
++      void (*close)(struct tty_struct *tty,
++                      struct usb_serial_port *port, struct file *filp);
++      int  (*write)(struct tty_struct *tty, struct usb_serial_port *port,
++                      const unsigned char *buf, int count);
++      /* Called only by the tty layer */
++      int  (*write_room)(struct tty_struct *tty);
++      int  (*ioctl)(struct tty_struct *tty, struct file *file,
+                     unsigned int cmd, unsigned long arg);
+-      void (*set_termios)(struct usb_serial_port *port, struct ktermios *old);
+-      void (*break_ctl)(struct usb_serial_port *port, int break_state);
+-      int  (*chars_in_buffer)(struct usb_serial_port *port);
+-      void (*throttle)(struct usb_serial_port *port);
+-      void (*unthrottle)(struct usb_serial_port *port);
+-      int  (*tiocmget)(struct usb_serial_port *port, struct file *file);
+-      int  (*tiocmset)(struct usb_serial_port *port, struct file *file,
++      void (*set_termios)(struct tty_struct *tty,
++                      struct usb_serial_port *port, struct ktermios *old);
++      void (*break_ctl)(struct tty_struct *tty, int break_state);
++      int  (*chars_in_buffer)(struct tty_struct *tty);
++      void (*throttle)(struct tty_struct *tty);
++      void (*unthrottle)(struct tty_struct *tty);
++      int  (*tiocmget)(struct tty_struct *tty, struct file *file);
++      int  (*tiocmset)(struct tty_struct *tty, struct file *file,
+                        unsigned int set, unsigned int clear);
+-
++      /* USB events */
+       void (*read_int_callback)(struct urb *urb);
+       void (*write_int_callback)(struct urb *urb);
+       void (*read_bulk_callback)(struct urb *urb);
+@@ -270,19 +275,19 @@ static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
+ /* Functions needed by other parts of the usbserial core */
+ extern struct usb_serial *usb_serial_get_by_index(unsigned int minor);
+ extern void usb_serial_put(struct usb_serial *serial);
+-extern int usb_serial_generic_open(struct usb_serial_port *port,
+-                                 struct file *filp);
+-extern int usb_serial_generic_write(struct usb_serial_port *port,
+-                                  const unsigned char *buf, int count);
+-extern void usb_serial_generic_close(struct usb_serial_port *port,
+-                                   struct file *filp);
++extern int usb_serial_generic_open(struct tty_struct *tty,
++              struct usb_serial_port *port, struct file *filp);
++extern int usb_serial_generic_write(struct tty_struct *tty,
++      struct usb_serial_port *port, const unsigned char *buf, int count);
++extern void usb_serial_generic_close(struct tty_struct *tty,
++                      struct usb_serial_port *port, struct file *filp);
+ extern int usb_serial_generic_resume(struct usb_serial *serial);
+-extern int usb_serial_generic_write_room(struct usb_serial_port *port);
+-extern int usb_serial_generic_chars_in_buffer(struct usb_serial_port *port);
++extern int usb_serial_generic_write_room(struct tty_struct *tty);
++extern int usb_serial_generic_chars_in_buffer(struct tty_struct *tty);
+ extern void usb_serial_generic_read_bulk_callback(struct urb *urb);
+ extern void usb_serial_generic_write_bulk_callback(struct urb *urb);
+-extern void usb_serial_generic_throttle(struct usb_serial_port *port);
+-extern void usb_serial_generic_unthrottle(struct usb_serial_port *port);
++extern void usb_serial_generic_throttle(struct tty_struct *tty);
++extern void usb_serial_generic_unthrottle(struct tty_struct *tty);
+ extern void usb_serial_generic_shutdown(struct usb_serial *serial);
+ extern int usb_serial_generic_register(int debug);
+ extern void usb_serial_generic_deregister(void);
index 7e015fe..22e4909 100644 (file)
@@ -19,7 +19,7 @@ DEFAULT_PREFERENCE_spitz = "1"
 # Patches submitted upstream are towards top of this list 
 # Hacks should clearly named and at the bottom
 SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-2.6.25.tar.bz2 \
-           ${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/testing/patch-2.6.26-rc4.bz2;patch=1 \
+           ${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/testing/v2.6.26/patch-2.6.26-rc4.bz2;patch=1 \
            ${RPSRC}/lzo_jffs2_sysfs-r1.patch;patch=1 \
            ${RPSRC}/hx2750_base-r34.patch;patch=1 \
            ${RPSRC}/hx2750_bl-r9.patch;patch=1 \
index 0c76704..47932fd 100644 (file)
@@ -1,6 +1,6 @@
 require linux-rp.inc
 
-FILE_PR = "r4"
+FILE_PR = "r5"
 
 DEFAULT_PREFERENCE = "-1"
 DEFAULT_PREFERENCE_qemuarm = "-1"
@@ -82,6 +82,7 @@ SRC_URI_append_collie = "\
        file://collie.patch;patch=1 \
        file://collie_keymap.patch;patch=1 \
        file://collie-ucbfix.patch;patch=1 \
+       file://usb-gadget27bp.patch;patch=1 \
 "
 
 SRC_URI_append_poodle = "\
index da4c4ef..b3cf0fd 100644 (file)
@@ -1,13 +1,13 @@
 DESCRIPTION = "Mozilla Mobile browser"
 DEPENDS += "cairo alsa-lib "
 
-PV = "0.8+0.9pre"
-MOZPV = "0.9pre"
-FILE_PR = "r10"
+PV = "0.9+1.0a1"
+MOZPV = "1.0a1"
+FILE_PR = "r0"
 PE = "1"
 
-SRC_URI = "hg://hg.mozilla.org/;module=mozilla-central;rev=3a9a64e5bedc \
-           hg://hg.mozilla.org/;module=mobile-browser;rev=53d19b4b249a \
+SRC_URI = "hg://hg.mozilla.org/;module=mozilla-central;rev=6c2f8bd79cbc \
+           hg://hg.mozilla.org/;module=mobile-browser;rev=8f96b58057ad \
            file://jsautocfg.h \
            file://jsautocfg-dontoverwrite.patch;patch=1 \
 "
@@ -28,6 +28,7 @@ do_configure_prepend() {
        if [ -e ${WORKDIR}/mobile-browser ] ; then
                mv ${WORKDIR}/mobile-browser ${S}/mobile
        fi      
+       sed -i -e 's:head\ -1:head\ -n1:g' client.mk
        oe_runmake -f client.mk CONFIGURE_ARGS="${EXTRA_OECONF}" configure
 }
 
index 3297795..c36927d 100644 (file)
@@ -2,7 +2,7 @@ Index: Python-2.5.2/configure.in
 ===================================================================
 --- Python-2.5.2.orig/configure.in
 +++ Python-2.5.2/configure.in
-@@ -3410,45 +3410,6 @@ esac
+@@ -3410,45 +3410,8 @@ esac
                                           
  
  
@@ -45,6 +45,8 @@ Index: Python-2.5.2/configure.in
 - AC_DEFINE(PY_FORMAT_SIZE_T, "z", [Define to printf format modifier for Py_ssize_t])],
 - AC_MSG_RESULT(no))
 -
++AC_DEFINE(PY_FORMAT_SIZE_T, "z", [Defune to print format modifier for Py_ssize_t])
++
  AC_CHECK_TYPE(socklen_t,,
    AC_DEFINE(socklen_t,int,
              Define to `int' if <sys/socket.h> does not define.),[
diff --git a/packages/python/python-2.5.2/fix_pthread_site.patch b/packages/python/python-2.5.2/fix_pthread_site.patch
new file mode 100644 (file)
index 0000000..d392060
--- /dev/null
@@ -0,0 +1,38 @@
+--- configure.in.org   2008-05-01 12:40:58.000000000 +0200
++++ configure.in       2008-05-01 12:39:39.000000000 +0200
+@@ -998,7 +999,7 @@
+ # so we need to run a program to see whether it really made the
+ # function available.
+ AC_MSG_CHECKING(whether $CC accepts -pthread)
+-AC_CACHE_VAL(ac_cv_thread,
++AC_CACHE_VAL(ac_cv_pthread,
+ [ac_save_cc="$CC"
+ CC="$CC -pthread"
+ AC_TRY_RUN([
+@@ -1023,11 +1024,11 @@
+ # If we have set a CC compiler flag for thread support then
+ # check if it works for CXX, too.
+-ac_cv_cxx_thread=no
+ if test ! -z "$CXX"
+ then
+ AC_MSG_CHECKING(whether $CXX also accepts flags for thread support)
+-ac_save_cxx="$CXX"
++AC_CACHE_VAL(ac_cv_cxx_thread,
++[ac_save_cxx="$CXX"
+ if test "$ac_cv_kpthread" = "yes"
+ then
+@@ -1056,9 +1057,11 @@
+   fi
+   rm -fr conftest*
+ fi
++CXX="$ac_save_cxx"])
+ AC_MSG_RESULT($ac_cv_cxx_thread)
++else
++  ac_cv_cxx_thread=no
+ fi
+-CXX="$ac_save_cxx"
+ dnl # check for ANSI or K&R ("traditional") preprocessor
+ dnl AC_MSG_CHECKING(for C preprocessor type)
diff --git a/packages/python/python-2.5.2/forced_largefile_support.patch b/packages/python/python-2.5.2/forced_largefile_support.patch
new file mode 100644 (file)
index 0000000..2dd2e7f
--- /dev/null
@@ -0,0 +1,24 @@
+diff -Naur Python-2.5.1-org/configure Python-2.5.1/configure
+--- Python-2.5.1-org/configure 2007-03-12 11:50:51.000000000 +0100
++++ Python-2.5.1/configure     2007-07-14 01:30:20.000000000 +0200
+@@ -10569,7 +10569,7 @@
+   echo $ECHO_N "(cached) $ECHO_C" >&6
+ else
+   if test "$cross_compiling" = yes; then
+-  ac_cv_sizeof_off_t=4
++  ac_cv_sizeof_off_t=8
+ else
+   cat >conftest.$ac_ext <<_ACEOF
+ /* confdefs.h.  */
+diff -Naur Python-2.5.1-org/configure.in Python-2.5.1/configure.in
+--- Python-2.5.1-org/configure.in      2007-03-12 11:50:51.000000000 +0100
++++ Python-2.5.1/configure.in  2007-07-14 01:29:32.000000000 +0200
+@@ -1223,7 +1223,7 @@
+ }],
+ ac_cv_sizeof_off_t=`cat conftestval`,
+ ac_cv_sizeof_off_t=0,
+-ac_cv_sizeof_off_t=4)
++ac_cv_sizeof_off_t=8)
+ ])
+ AC_MSG_RESULT($ac_cv_sizeof_off_t)
+ AC_DEFINE_UNQUOTED(SIZEOF_OFF_T, $ac_cv_sizeof_off_t,
diff --git a/packages/python/python-2.5.2/some_configure_fixes.patch b/packages/python/python-2.5.2/some_configure_fixes.patch
new file mode 100644 (file)
index 0000000..eced413
--- /dev/null
@@ -0,0 +1,32 @@
+--- configure.in       2008-02-13 20:17:17.000000000 +0100
++++ configure.in       2008-10-21 22:45:31.000000000 +0200
+@@ -3369,27 +3369,9 @@
+   AC_MSG_RESULT(no)
+ )
+-AC_MSG_CHECKING(for /dev/ptmx)
++AC_CHECK_FILE(/dev/ptmx, AC_DEFINE(HAVE_DEV_PTMX, 1, [Define if we have /dev/ptmx.]))
+-if test -r /dev/ptmx
+-then
+-  AC_MSG_RESULT(yes)
+-  AC_DEFINE(HAVE_DEV_PTMX, 1,
+-  [Define if we have /dev/ptmx.])
+-else
+-  AC_MSG_RESULT(no)
+-fi
+-
+-AC_MSG_CHECKING(for /dev/ptc)
+-
+-if test -r /dev/ptc
+-then
+-  AC_MSG_RESULT(yes)
+-  AC_DEFINE(HAVE_DEV_PTC, 1,
+-  [Define if we have /dev/ptc.])
+-else
+-  AC_MSG_RESULT(no)
+-fi
++AC_CHECK_FILE(/dev/ptc, AC_DEFINE(HAVE_DEV_PTC, 1, [Define if we have /dev/ptc.]))
+ case $MACHDEP in
+ darwin)       
diff --git a/packages/python/python-2.5.2/strict_aliasing_site.patch b/packages/python/python-2.5.2/strict_aliasing_site.patch
new file mode 100644 (file)
index 0000000..12eee32
--- /dev/null
@@ -0,0 +1,19 @@
+--- configure.in.org   2008-05-01 12:40:58.000000000 +0200
++++ configure.in       2008-05-01 12:39:39.000000000 +0200
+@@ -796,13 +796,14 @@
+     # pointer types. GCC may generate bad code as a result of that,
+     # so use -fno-strict-aliasing if supported.
+     AC_MSG_CHECKING(whether $CC accepts -fno-strict-aliasing)
+-     ac_save_cc="$CC"
++    AC_CACHE_VAL(ac_cv_no_strict_aliasing_ok,
++    [ac_save_cc="$CC"
+      CC="$CC -fno-strict-aliasing"
+      AC_TRY_RUN([int main() { return 0; }],
+      ac_cv_no_strict_aliasing_ok=yes,
+      ac_cv_no_strict_aliasing_ok=no,
+      ac_cv_no_strict_aliasing_ok=no)
+-     CC="$ac_save_cc"
++     CC="$ac_save_cc"])
+     AC_MSG_RESULT($ac_cv_no_strict_aliasing_ok)
+     if test $ac_cv_no_strict_aliasing_ok = yes
+     then
index 02c5f8b..df0d349 100644 (file)
@@ -6,7 +6,7 @@ PRIORITY = "optional"
 DEPENDS = "python-native db gdbm openssl readline sqlite3 zlib"
 DEPENDS_sharprom = "python-native db readline zlib gdbm openssl"
 # bump this on every change in contrib/python/generate-manifest-2.5.py
-FILE_PR = "ml13"
+FILE_PR = "ml14"
 
 PYTHON_MAJMIN = "2.5"
 
@@ -27,6 +27,13 @@ SRC_URI = "\
   \
   file://sitecustomize.py \
 "
+
+SRC_URI_append_opendreambox = " \
+  file://some_configure_fixes.patch;patch=1;pnum=0 \
+  file://strict_aliasing_site.patch;patch=0;pnum=0 \
+  file://fix_pthread_site.patch;patch=0;pnum=0 \
+  file://forced_largefile_support.patch;patch=1;pnum=1"
+
 S = "${WORKDIR}/Python-${PV}"
 
 inherit autotools
diff --git a/packages/sysvinit/sysvinit_2.86.bb.orig b/packages/sysvinit/sysvinit_2.86.bb.orig
deleted file mode 100644 (file)
index aac840a..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-DESCRIPTION = "System-V like init."
-SECTION = "base"
-LICENSE = "GPL"
-HOMEPAGE = "http://freshmeat.net/projects/sysvinit/"
-PR = "r41"
-
-# USE_VT and SERIAL_CONSOLE are generally defined by the MACHINE .conf.
-# Set PACKAGE_ARCH appropriately.
-PACKAGE_ARCH_${PN}-inittab = "${MACHINE_ARCH}"
-
-RDEPENDS_${PN} = "${PN}-inittab"
-
-PACKAGES =+ "bootlogd ${PN}-inittab"
-FILES_bootlogd = "/etc/init.d/bootlogd /etc/init.d/stop-bootlogd /etc/rc?.d/S*bootlogd /sbin/bootlogd"
-FILES_${PN}-inittab = "${sysconfdir}/inittab"
-CONFFILES_${PN}-inittab = "${sysconfdir}/inittab"
-
-USE_VT ?= "1"
-SYSVINIT_ENABLED_GETTYS ?= "1"
-
-SRC_URI = "ftp://ftp.cistron.nl/pub/people/miquels/sysvinit/sysvinit-${PV}.tar.gz \
-           file://install.patch;patch=1 \
-           file://need \
-           file://provide \
-           file://inittab \
-           file://rcS-default \
-           file://rc \
-           file://rcS \
-           file://bootlogd.init"
-
-S = "${WORKDIR}/sysvinit-${PV}"
-B = "${S}/src"
-
-inherit update-alternatives
-
-ALTERNATIVE_NAME = "init"
-ALTERNATIVE_LINK = "${base_sbindir}/init"
-ALTERNATIVE_PATH = "${base_sbindir}/init.sysvinit"
-ALTERNATIVE_PRIORITY = "50"
-
-PACKAGES =+ "sysvinit-pidof sysvinit-sulogin"
-FILES_${PN} += "${base_sbindir}/* ${base_bindir}/*"
-FILES_sysvinit-pidof = "${base_bindir}/pidof.sysvinit"
-FILES_sysvinit-sulogin = "${base_sbindir}/sulogin"
-
-CFLAGS_prepend = "-D_GNU_SOURCE "
-export LCRYPT = "-lcrypt"
-EXTRA_OEMAKE += "'INSTALL=install' \
-                'bindir=${base_bindir}' \
-                'sbindir=${base_sbindir}' \
-                'usrbindir=${bindir}' \
-                'usrsbindir=${sbindir}' \
-                'includedir=${includedir}' \
-                'mandir=${mandir}' \
-                DISTRO=''"
-
-do_install () {
-       oe_runmake 'ROOT=${D}' install
-       install -d ${D}${sysconfdir}
-       install -d ${D}${sysconfdir}/default
-       install -d ${D}${sysconfdir}/init.d
-       install -m 0644 ${WORKDIR}/inittab ${D}${sysconfdir}/inittab
-       if [ ! -z "${SERIAL_CONSOLE}" ]; then
-               echo "S:2345:respawn:${base_sbindir}/getty ${SERIAL_CONSOLE}" >> ${D}${sysconfdir}/inittab
-       fi
-       if [ "${USE_VT}" = "1" ]; then
-               cat <<EOF >>${D}${sysconfdir}/inittab
-# ${base_sbindir}/getty invocations for the runlevels.
-#
-# The "id" field MUST be the same as the last
-# characters of the device (after "tty").
-#
-# Format:
-#  <id>:<runlevels>:<action>:<process>
-#
-
-EOF
-
-               for n in ${SYSVINIT_ENABLED_GETTYS}
-               do
-                       echo "$n:2345:respawn:${base_sbindir}/getty 38400 tty$n" >> ${D}${sysconfdir}/inittab
-               done
-               echo "" >> ${D}${sysconfdir}/inittab
-       fi
-       install -m 0644    ${WORKDIR}/rcS-default       ${D}${sysconfdir}/default/rcS
-       install -m 0755    ${WORKDIR}/rc                ${D}${sysconfdir}/init.d
-       install -m 0755    ${WORKDIR}/rcS               ${D}${sysconfdir}/init.d
-       install -m 0755    ${WORKDIR}/bootlogd.init     ${D}${sysconfdir}/init.d/bootlogd
-       ln -sf bootlogd ${D}${sysconfdir}/init.d/stop-bootlogd
-       install -d ${D}${sysconfdir}/rcS.d
-       ln -sf ../init.d/bootlogd ${D}${sysconfdir}/rcS.d/S07bootlogd
-       for level in 2 3 4 5; do
-               install -d ${D}${sysconfdir}/rc$level.d
-               ln -sf ../init.d/stop-bootlogd ${D}${sysconfdir}/rc$level.d/S99stop-bootlogd
-       done
-       mv                 ${D}${base_sbindir}/init               ${D}${base_sbindir}/init.${PN}
-       mv ${D}${base_bindir}/pidof ${D}${base_bindir}/pidof.${PN}
-       mv ${D}${base_sbindir}/halt ${D}${base_sbindir}/halt.${PN}
-       mv ${D}${base_sbindir}/reboot ${D}${base_sbindir}/reboot.${PN}
-       mv ${D}${base_sbindir}/shutdown ${D}${base_sbindir}/shutdown.${PN}
-       mv ${D}${bindir}/last ${D}${bindir}/last.${PN}
-       mv ${D}${bindir}/mesg ${D}${bindir}/mesg.${PN}
-       mv ${D}${bindir}/wall ${D}${bindir}/wall.${PN}
-}
-
-pkg_postinst_${PN} () {
-#!/bin/sh
-update-alternatives --install ${base_sbindir}/halt halt halt.${PN} 200
-update-alternatives --install ${base_sbindir}/reboot reboot reboot.${PN} 200
-update-alternatives --install ${base_sbindir}/shutdown shutdown shutdown.${PN} 200
-update-alternatives --install ${bindir}/last last last.${PN} 200
-update-alternatives --install ${bindir}/mesg mesg mesg.${PN} 200
-update-alternatives --install ${bindir}/wall wall wall.${PN} 200
-}
-
-pkg_prerm_${PN} () {
-#!/bin/sh
-update-alternatives --remove halt halt.${PN}
-update-alternatives --remove reboot reboot.${PN}
-update-alternatives --remove shutdown shutdown.${PN}
-update-alternatives --remove last last.${PN}
-update-alternatives --remove mesg mesg.${PN}
-update-alternatives --remove wall wall.${PN}
-}
-
-pkg_postinst_sysvinit-pidof () {
-#!/bin/sh
-update-alternatives --install ${base_bindir}/pidof pidof pidof.${PN} 200
-}
-
-pkg_prerm_sysvinit-pidof () {
-#!/bin/sh
-update-alternatives --remove pidof pidof.${PN}
-}
index c527c80..dcc0897 100644 (file)
@@ -2,7 +2,7 @@ DESCRIPTION = "A uniform interface to video capture devices."
 SECTION = "graphics"
 LICENSE = "GPL"
 DEPENDS = "intltool-native gtk+ libpng libxv"
-PR = "r0"
+PR = "r1"
 
 SRC_URI = "http://www.unicap-imaging.org/downloads/unicap-${PV}.tar.gz \
            file://pkgconfig.patch;patch=1"
@@ -13,10 +13,10 @@ do_stage () {
         autotools_stage_all
 }
 
-PACKAGES += "libucil libunicapgtk"
+PACKAGES += "libucil unicapgtk"
 
 FILES_${PN} = "${libdir}/libunicap.*so.* ${libdir}/unicap2/cpi/lib*.*so.*"
 FILES_${PN}-dev += " ${libdir}/unicap2/cpi/lib*.*so ${libdir}/unicap2/cpi/lib*.*a"
 FILES_${PN}-dbg += " ${libdir}/unicap2/cpi/.debug"
 FILES_libucil = "${libdir}/libucil*so.*"
-FILES_libunicapgtk = "${libdir}/libunicapgtk*so.*"
+FILES_unicapgtk = "${libdir}/libunicapgtk*so.*"
index f7ea5ed..34ce3de 100644 (file)
@@ -2,9 +2,9 @@ require xorg-driver-video.inc
 
 DESCRIPTION = "X.Org X server -- OMAP display driver"
 
-FILE_PR ="r8"
+FILE_PR ="r10"
 
-SRCREV = "9a4fe691d60ac29e510dfa5180bd799ead86d1d5"
+SRCREV = "7bf64be8e809d00c10c6bdae6933bdc71c642ea4"
 PV = "0.0.1+${PR}+git${SRCREV}"
 
 SRC_URI = "git://git.pingu.fi/xf86-video-omapfb.git;protocol=http"
diff --git a/packages/xorg-xserver/xserver-kdrive-1.4.0.90/xorg-1.4-kdrive-rotation.patch b/packages/xorg-xserver/xserver-kdrive-1.4.0.90/xorg-1.4-kdrive-rotation.patch
new file mode 100644 (file)
index 0000000..5e3eb8e
--- /dev/null
@@ -0,0 +1,31 @@
+diff -rup a/hw/kdrive/src/kinput.c b/hw/kdrive/src/kinput.c
+--- a/hw/kdrive/src/kinput.c   2007-08-23 21:04:53.000000000 +0200
++++ b/hw/kdrive/src/kinput.c   2007-12-22 12:53:27.679853402 +0100
+@@ -2075,19 +2075,25 @@ KdEnqueuePointerEvent(KdPointerInfo *pi,
+     /* we don't need to transform z, so we don't. */
+     if (flags & KD_MOUSE_DELTA) {
++/* does it really make sense to transform relative coordinates depending on screen rotation??
+       if (pi->transformCoordinates) {
+           x = matrix[0][0] * rx + matrix[0][1] * ry;
+           y = matrix[1][0] * rx + matrix[1][1] * ry;
+       }
+-      else {
++      else {*/
+           x = rx;
+           y = ry;
+-      }
++/*    }*/
+     }
+     else {
+       if (pi->transformCoordinates) {
+           x = matrix[0][0] * rx + matrix[0][1] * ry;
+           y = matrix[1][0] * rx + matrix[1][1] * ry;
++/* negative absolute values indicate calculation from the oposite end of the axis */
++            if (x < 0)
++                x += matrix[0][2];
++            if (y < 0)
++                y += matrix[1][2];
+       }
+       else {
+           x = rx;
index 1f047f0..963b112 100644 (file)
@@ -3,7 +3,7 @@ require xserver-kdrive-common.inc
 DEPENDS += "hal libxkbfile libxcalibrate pixman"
 
 PE = "1"
-FILE_PR = "r2"
+FILE_PR = "r3"
 
 SRC_URI = "${XORG_MIRROR}/individual/xserver/xorg-server-${PV}.tar.bz2 \
        ${KDRIVE_COMMON_PATCHES} \
@@ -24,6 +24,7 @@ SRC_URI = "${XORG_MIRROR}/individual/xserver/xorg-server-${PV}.tar.bz2 \
        file://xorg-avr32-support.diff;patch=1 \
        file://pkgconfig_fix.patch;patch=1 \
         file://no_xkb.patch;patch=1;pnum=0 \
+       file://xorg-1.4-kdrive-rotation.patch;patch=1 \
         "
 
 S = "${WORKDIR}/xorg-server-${PV}"
index 939d1d6..c821daf 100644 (file)
@@ -1,3 +1,8 @@
+#used by many configure scripts (i.e. for strace)
+ac_cv_c_littleendian=${ac_cv_c_littleendian=yes}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=no}
+ac_cv_have_little_endian_long_long=${ac_cv_have_little_endian_long_long=yes}
+ac_cv_have_decl_sys_siglist=${ac_cv_have_decl_sys_siglist=yes}
 
 ac_cv_func_getpgrp_void=${ac_cv_func_getpgrp_void=yes}
 ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed=no}