summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/bluez/bluez-utils3.inc11
-rw-r--r--packages/busybox/busybox-1.11.3/angstrom/defconfig (renamed from packages/busybox/busybox-1.11.1/angstrom/defconfig)0
-rw-r--r--packages/busybox/busybox-1.11.3/defconfig (renamed from packages/busybox/busybox-1.11.1/defconfig)0
-rw-r--r--packages/busybox/busybox-1.11.3/slugos/defconfig (renamed from packages/busybox/busybox-1.11.1/slugos/defconfig)0
-rw-r--r--packages/busybox/busybox-1.11.3/udhcpscript.patch (renamed from packages/busybox/busybox-1.11.1/udhcpscript.patch)0
-rw-r--r--packages/busybox/busybox.inc13
-rw-r--r--packages/busybox/busybox_1.11.3.bb (renamed from packages/busybox/busybox_1.11.1.bb)4
-rw-r--r--packages/ccid/ccid_1.3.8.bb21
-rw-r--r--packages/classpath/classpath-native.inc4
-rw-r--r--packages/dmidecode/dmidecode_2.9.bb19
-rw-r--r--packages/dsplink/codec-engine_2.10.bb5
-rw-r--r--packages/dsplink/codec-engine_2.21.bb160
-rw-r--r--packages/dsplink/dsplink.inc87
-rw-r--r--packages/dsplink/dsplink_1.51.00.08.bb3
-rw-r--r--packages/dsplink/dsplink_1.60.00.04.bb21
-rwxr-xr-xpackages/dsplink/files/Makefile.dsplink106
-rw-r--r--packages/dsplink/files/c64xx_5.xx_linux.mk2
-rw-r--r--packages/dsplink/ti-paths.inc6
-rw-r--r--packages/fswebcam/fswebcam_20070108.bb10
-rw-r--r--packages/gcc/gcc-configure-common.inc9
-rw-r--r--packages/gcc/gcc-cross-kernel.inc7
-rw-r--r--packages/gdb/gdb.inc5
-rw-r--r--packages/gdb/gdb_6.3.bb2
-rw-r--r--packages/gdb/gdb_6.4.bb2
-rw-r--r--packages/gdb/gdb_6.6.bb2
-rw-r--r--packages/gdb/gdb_6.7.1.bb2
-rw-r--r--packages/gdb/gdb_6.8.bb2
-rw-r--r--packages/giflib/giflib_4.1.6.bb18
-rw-r--r--packages/glibc/files/etc/ld.so.conf2
-rw-r--r--packages/glibc/glibc-package.bbclass6
-rw-r--r--packages/glibc/glibc_2.2.5.bb2
-rw-r--r--packages/glibc/glibc_2.3.2+cvs20040726.bb2
-rw-r--r--packages/glibc/glibc_2.3.2.bb2
-rw-r--r--packages/glibc/glibc_2.3.3+cvs20041128.bb2
-rw-r--r--packages/glibc/glibc_2.3.3+cvs20050221.bb2
-rw-r--r--packages/glibc/glibc_2.3.3+cvs20050420.bb2
-rw-r--r--packages/glibc/glibc_2.3.3.bb2
-rw-r--r--packages/glibc/glibc_2.3.5+cvs20050627.bb2
-rw-r--r--packages/glibc/glibc_2.3.6.bb2
-rw-r--r--packages/glibc/glibc_2.4.bb2
-rw-r--r--packages/glibc/glibc_2.5.bb2
-rw-r--r--packages/glibc/glibc_2.6.1.bb2
-rw-r--r--packages/glibc/glibc_2.7.bb2
-rw-r--r--packages/gtk+/gdk-pixbuf-csource-native_2.12.11.bb2
-rw-r--r--packages/kexecboot/linux-kexecboot-2.6.26/collie/defconfig12
-rw-r--r--packages/kexecboot/linux-kexecboot_2.6.26.bb2
-rw-r--r--packages/lesstif/files/000_bootstrap_script.diff30
-rw-r--r--packages/lesstif/files/000_libtool_linking.diff11
-rw-r--r--packages/lesstif/files/010_rebootstrap-small.diff456
-rw-r--r--packages/lesstif/files/020_bad_integer_cast.diff13
-rw-r--r--packages/lesstif/files/020_missing_xm_h.diff11
-rw-r--r--packages/lesstif/files/020_render_table_crash.diff11
-rw-r--r--packages/lesstif/files/020_unsigned_int.diff38
-rw-r--r--packages/lesstif/files/020_xpmpipethrough.diff381
-rw-r--r--packages/lesstif/files/021_xim_chained_list_crash.diff24
-rw-r--r--packages/lesstif/files/030_manpage.diff11
-rw-r--r--packages/lesstif/files/ac_debug.m4.diff95
-rw-r--r--packages/lesstif/files/ac_find_xft.m4.diff304
-rw-r--r--packages/lesstif/files/ac_have_libxp.m4.diff57
-rw-r--r--packages/lesstif/files/aclocal.m4.diff2746
-rw-r--r--packages/lesstif/files/disable-docs.patch29
-rw-r--r--packages/lesstif/lesstif_0.95.0.bb49
-rw-r--r--packages/libffi/libffi_2.0+gcc4.3.2.bb64
-rw-r--r--packages/libsdl/files/fixmfour.patch14
-rw-r--r--packages/libsdl/libsdl-image_1.2.6.bb4
-rw-r--r--packages/libsdl/libsdl-x11_1.2.11.bb3
-rw-r--r--packages/linux/linux-omap2-git/beagleboard/defconfig4
-rw-r--r--packages/linux/linux-rp-2.6.26/defconfig-collie58
-rw-r--r--packages/linux/linux-rp-2.6.26/usb-gadget27bp.patch26674
-rw-r--r--packages/linux/linux-rp_2.6.25+2.6.26-rc4.bb2
-rw-r--r--packages/linux/linux-rp_2.6.26.bb3
-rw-r--r--packages/meta/slugos-packages.bb2
-rw-r--r--packages/mozilla/fennec_hg.bb11
-rw-r--r--packages/nfs-utils/nfs-utils_1.1.2.bb2
-rw-r--r--packages/openchrome/configure-dri.patch11
-rw-r--r--packages/pcsc-lite/files/pcscd.init32
-rw-r--r--packages/pcsc-lite/pcsc-lite_1.4.102.bb35
-rw-r--r--packages/perl/perl-native_5.8.8.bb6
-rw-r--r--packages/python/python-2.5-manifest.inc27
-rw-r--r--packages/python/python-2.5.2/05-install.patch13
-rw-r--r--packages/python/python-2.5.2/06-fix-urllib-exception.patch13
-rw-r--r--packages/python/python-2.5.2/13-set-wakeup-fix.patch87
-rw-r--r--packages/python/python-2.5.2/14-encodings-oriental.patch64
-rw-r--r--packages/python/python-2.5.2/16-bug1179-imageop.patch219
-rw-r--r--packages/python/python_2.5.2.bb28
-rw-r--r--packages/tasks/task-xfce-base.bb29
-rw-r--r--packages/ttf-fonts/ttf-wqy-zenhei_0.6.26.bb19
-rw-r--r--packages/unicap/unicap_0.9.3.bb6
-rw-r--r--packages/xorg-driver/xf86-video-omapfb_git.bb4
-rw-r--r--packages/xorg-xserver/xserver-kdrive-1.4.0.90/xorg-1.4-kdrive-rotation.patch31
-rw-r--r--packages/xorg-xserver/xserver-kdrive_1.4.0.90.bb3
91 files changed, 32145 insertions, 160 deletions
diff --git a/packages/bluez/bluez-utils3.inc b/packages/bluez/bluez-utils3.inc
index 0bbba2cd14..c4debd01b2 100644
--- a/packages/bluez/bluez-utils3.inc
+++ b/packages/bluez/bluez-utils3.inc
@@ -76,9 +76,14 @@ OE_LT_RPATH_ALLOW[export]="1"
do_install_append() {
install -d ${D}${base_sbindir} ${D}${base_bindir}/ ${D}${sysconfdir}/apm/event.d/
- mv ${D}${sbindir}/* ${D}${base_sbindir}/
- mv ${D}${bindir}/* ${D}${base_bindir}/
- rmdir ${D}${bindir} ${D}${sbindir}
+ if [ "${sbindir}" != "${base_sbindir}" ]; then
+ mv ${D}${sbindir}/* ${D}${base_sbindir}/
+ rmdir ${D}${sbindir}
+ fi
+ if [ "${bindir}" != "${base_bindir}" ]; then
+ mv ${D}${bindir}/* ${D}${base_bindir}/
+ rmdir ${D}${bindir}
+ fi
chmod u+s ${D}${base_sbindir}/hciattach ${D}${base_sbindir}/hciconfig
install -m 0644 ${WORKDIR}/hcid.conf ${D}${sysconfdir}/bluetooth/
install -m 0644 ${S}/rfcomm/rfcomm.conf ${D}${sysconfdir}/bluetooth/
diff --git a/packages/busybox/busybox-1.11.1/angstrom/defconfig b/packages/busybox/busybox-1.11.3/angstrom/defconfig
index f3130caca8..f3130caca8 100644
--- a/packages/busybox/busybox-1.11.1/angstrom/defconfig
+++ b/packages/busybox/busybox-1.11.3/angstrom/defconfig
diff --git a/packages/busybox/busybox-1.11.1/defconfig b/packages/busybox/busybox-1.11.3/defconfig
index a7b8ed53a0..a7b8ed53a0 100644
--- a/packages/busybox/busybox-1.11.1/defconfig
+++ b/packages/busybox/busybox-1.11.3/defconfig
diff --git a/packages/busybox/busybox-1.11.1/slugos/defconfig b/packages/busybox/busybox-1.11.3/slugos/defconfig
index d922529cc2..d922529cc2 100644
--- a/packages/busybox/busybox-1.11.1/slugos/defconfig
+++ b/packages/busybox/busybox-1.11.3/slugos/defconfig
diff --git a/packages/busybox/busybox-1.11.1/udhcpscript.patch b/packages/busybox/busybox-1.11.3/udhcpscript.patch
index fc21d440cd..fc21d440cd 100644
--- a/packages/busybox/busybox-1.11.1/udhcpscript.patch
+++ b/packages/busybox/busybox-1.11.3/udhcpscript.patch
diff --git a/packages/busybox/busybox.inc b/packages/busybox/busybox.inc
index cc196ad767..63f839e246 100644
--- a/packages/busybox/busybox.inc
+++ b/packages/busybox/busybox.inc
@@ -58,6 +58,13 @@ do_compile() {
}
do_install () {
+ oe_runmake busybox.links
+ if [ "x${layout_prefix}" = "x" ]; then
+ sed 's:^/usr/:/:' < busybox.links >busybox.links.new
+ mv busybox.links.new busybox.links
+ elif [ "${layout_prefix}" != "/usr" ]; then
+ echo "warning, busybox.links will lose with this prefix"
+ fi
unset CFLAGS CPPFLAGS CXXFLAGS LDFLAGS
install -d ${D}${sysconfdir}/init.d
oe_runmake "PREFIX=${D}" install
@@ -67,7 +74,11 @@ do_install () {
install -d ${D}/busybox
ls ${D} -R
- cp -dPr ${D}${base_bindir} ${D}${base_sbindir} ${D}${prefix} ${D}/busybox/
+ for i in ${D}${base_bindir} ${D}${base_sbindir} ${D}${prefix} ; do
+ if [ -d $i ]; then
+ cp -dPr $i ${D}/busybox/
+ fi
+ done
# Move the busybox binary back to /bin
install -d ${D}${base_bindir}
mv ${D}/busybox${base_bindir}/busybox ${D}${base_bindir}/
diff --git a/packages/busybox/busybox_1.11.1.bb b/packages/busybox/busybox_1.11.3.bb
index 4d488218e2..790bf518cc 100644
--- a/packages/busybox/busybox_1.11.1.bb
+++ b/packages/busybox/busybox_1.11.3.bb
@@ -1,10 +1,8 @@
require busybox.inc
-PR = "r3"
+PR = "r0"
SRC_URI = "\
http://www.busybox.net/downloads/busybox-${PV}.tar.gz \
- http://busybox.net/downloads/fixes-1.11.1/busybox-1.11.1-basename.patch;patch=1 \
- http://busybox.net/downloads/fixes-1.11.1/busybox-1.11.1-tar.patch;patch=1 \
\
file://udhcpscript.patch;patch=1 \
file://busybox-cron \
diff --git a/packages/ccid/ccid_1.3.8.bb b/packages/ccid/ccid_1.3.8.bb
new file mode 100644
index 0000000000..c2ade3119a
--- /dev/null
+++ b/packages/ccid/ccid_1.3.8.bb
@@ -0,0 +1,21 @@
+DESCRIPTION = "Generic USB CCID smart card reader driver"
+HOMEPAGE = "http://pcsclite.alioth.debian.org/ccid.html"
+LICENSE = "GPL"
+PR = "r0"
+
+DEPENDS = "libusb pcsc-lite"
+RDEPENDS = "pcsc-lite"
+
+SRC_URI = "http://alioth.debian.org/download.php/2482/ccid-${PV}.tar.bz2"
+
+inherit autotools
+
+EXTRA_OECONF = "--enable-udev"
+
+do_install_append () {
+ install -d "${D}/etc/udev/rules.d"
+ install -m 644 "${S}/src/pcscd_ccid.rules" "${D}/etc/udev/rules.d/85-pcscd_ccid.rules"
+}
+
+FILES_${PN} += "${libdir}/pcsc/"
+FILES_${PN}-dbg += "${libdir}/pcsc/drivers/*/*/*/.debug"
diff --git a/packages/classpath/classpath-native.inc b/packages/classpath/classpath-native.inc
index d178ce6779..31015b3d71 100644
--- a/packages/classpath/classpath-native.inc
+++ b/packages/classpath/classpath-native.inc
@@ -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}
diff --git a/packages/dmidecode/dmidecode_2.9.bb b/packages/dmidecode/dmidecode_2.9.bb
new file mode 100644
index 0000000000..2186120498
--- /dev/null
+++ b/packages/dmidecode/dmidecode_2.9.bb
@@ -0,0 +1,19 @@
+DESCRIPTION = "DMI (Desktop Management Interface) table related utilities"
+HOMEPAGE = "http://www.nongnu.org/dmidecode/"
+LICENSE = "GPLv2"
+PR = "r0"
+
+SRC_URI = "http://savannah.nongnu.org/download/dmidecode/${P}.tar.bz2"
+
+COMPATIBLE_HOST = "i.86.*-linux"
+
+do_unpack_extra() {
+ sed -i \
+ -e '/^prefix/s:/usr/local:/usr:' \
+ Makefile
+}
+addtask unpack_extra after do_unpack before do_patch
+
+do_install() {
+ oe_runmake DESTDIR="${D}" install
+}
diff --git a/packages/dsplink/codec-engine_2.10.bb b/packages/dsplink/codec-engine_2.10.bb
index 098d0054cd..abfe2f24e6 100644
--- a/packages/dsplink/codec-engine_2.10.bb
+++ b/packages/dsplink/codec-engine_2.10.bb
@@ -5,8 +5,9 @@ RDEPENDS = "update-modules"
inherit module
-PR = "r7"
-PV = "2.10"
+# tconf from xdctools dislikes '.' in pwd :/
+PR = "r0"
+PV = "210"
# Get CE tarball from TI website, place in sources and calculate
# md5sum
diff --git a/packages/dsplink/codec-engine_2.21.bb b/packages/dsplink/codec-engine_2.21.bb
new file mode 100644
index 0000000000..4c75464a27
--- /dev/null
+++ b/packages/dsplink/codec-engine_2.21.bb
@@ -0,0 +1,160 @@
+DESCRIPTION = "Codec Engine for TI ARM/DSP processors"
+
+DEPENDS = "virtual/kernel perl-native"
+RDEPENDS = "update-modules"
+
+inherit module
+
+# tconf from xdctools dislikes '.' in pwd :/
+PR = "r0"
+PV = "221"
+
+# Get CE tarball from TI website, place in sources and calculate
+# md5sum
+# Look for tarball at https://www-a.ti.com/downloads/sds_support/targetcontent/CE/index.html
+
+SRC_URI = "http://install.tarball.in.source.dir/codec_engine_2_21_00_06.tar.gz \
+ "
+
+S = "${WORKDIR}/codec_engine_2_21_00_06"
+
+require ti-paths.inc
+
+PARALLEL_MAKE = ""
+do_compile() {
+ echo "MVTOOL_PREFIX=${TARGET_PREFIX}" > ${S}/Rules.make
+ echo "UCTOOL_PREFIX=${TARGET_PREFIX}" >> ${S}/Rules.make
+ echo "LINUXKERNEL_INSTALL_DIR=${STAGING_KERNEL_DIR}" >> ${S}/Rules.make
+
+ unset CFLAGS CPPFLAGS CXXFLAGS LDFLAGS
+ cd ${S}/cetools/packages/ti/sdo/linuxutils/cmem
+
+ oe_runmake clean
+ oe_runmake KERNEL_PATH=${STAGING_KERNEL_DIR} \
+ KERNEL_SRC=${STAGING_KERNEL_DIR} \
+ KERNEL_VERSION=${KERNEL_VERSION} \
+ CC="${KERNEL_CC}" LD="${KERNEL_LD}" \
+ AR="${KERNEL_AR}" \
+ release
+ oe_runmake KERNEL_PATH=${STAGING_KERNEL_DIR} \
+ KERNEL_SRC=${STAGING_KERNEL_DIR} \
+ KERNEL_VERSION=${KERNEL_VERSION} \
+ CC="${KERNEL_CC}" LD="${KERNEL_LD}" \
+ AR="${KERNEL_AR}" \
+ debug
+ oe_runmake KERNEL_PATH=${STAGING_KERNEL_DIR} \
+ KERNEL_SRC=${STAGING_KERNEL_DIR} \
+ KERNEL_VERSION=${KERNEL_VERSION} \
+ CC="${KERNEL_CC}" LD="${KERNEL_LD}" \
+ AR="${KERNEL_AR}"
+
+ cd ${S}/cetools/packages/ti/bios/power
+ if ! [ -e omap3530 ] ; then tar xf ti_bios_power,omap3530_bld.tar ; fi
+ cd omap3530/lpm
+
+ sed -i -e s:/db/toolsrc/library/tools/vendors/mvl/arm/omap3/OMAP35x_SDK_0.9.7/src/linux/kernel_org/2.6_kernel:${STAGING_KERNEL_DIR}:g \
+ -e s:/db/toolsrc/library/tools/vendors/cs/arm/arm-2007q3/bin/arm-none-linux-gnueabi-:${TARGET_PREFIX}:g \
+ -e s:/db/atree/library/trees/power/power-d02x/imports:${STAGING_DIR_TARGET}:g \
+ Makefile
+
+ oe_runmake KERNEL_PATH=${STAGING_KERNEL_DIR} \
+ KERNEL_SRC=${STAGING_KERNEL_DIR} \
+ KERNEL_VERSION=${KERNEL_VERSION} \
+ CC="${KERNEL_CC}" LD="${KERNEL_LD}" \
+ AR="${KERNEL_AR}"
+
+ cd ${S}/examples
+ export CE_INSTALL_DIR=${S}
+ export XDC_INSTALL_DIR=${TIXDCTOOLSDIR}
+ export BIOS_INSTALL_DIR=${TITOOLSDIR}/${TIBIOSDIR}
+
+ sed -i -e s:/db/toolsrc/library/tools/vendors/cs/arm/arm-2007q3:${CROSS_DIR}:g \
+ -e s:/db/toolsrc/library/tools/vendors/ti/c6x/6.0.16/Linux:${TITOOLSDIR}/${TICGTOOLSDIR}:g \
+ -e s:/db/toolsrc/library/tools/vendors/opensource/gcc/4.1.0/Linux/gcc-4.1.0-glibc-2.3.6/i686-unknown-linux-gnu:/usr:g \
+ -e s:arm-none-linux-gnueabi-:${TARGET_PREFIX}:g \
+ -e 's:true, // build for uC Linux:false,:g' \
+ ${S}/examples/user.bld
+
+ sed -i -e s:/db/toolsrc/library/tools/vendors/ti/c6x/6.0.16/Linux:${TITOOLSDIR}/${TICGTOOLSDIR}:g \
+ xdcpaths.mak
+
+ for i in codecs extensions servers apps ; do
+ make -e -C ${S}/examples/ti/sdo/ce/examples/$i clean
+ make -e -C ${S}/examples/ti/sdo/ce/examples/$i
+ done
+
+}
+
+export DSPLIBS = "${S}/packages/ti/sdo/ce/utils/trace/lib/*.a* \
+ ${S}/packages/ti/sdo/ce/bioslog/lib/*.a* \
+ ${S}/packages/ti/sdo/ce/video/lib/*.a* \
+ ${S}/packages/ti/sdo/ce/audio/lib/*.a* \
+ ${S}/packages/ti/sdo/ce/speech/lib/*.a* \
+ ${S}/packages/ti/sdo/ce/lib/*.a* \
+ ${S}/packages/ti/sdo/ce/alg/lib/*.a* \
+ ${S}/cetools/packages/ti/sdo/fc/dman3/*.a* \
+ ${S}/cetools/packages/ti/sdo/fc/acpy3/*.a* \
+ ${S}/packages/ti/sdo/ce/osal/linux/lib/osal_linux_470.a* \
+ ${S}/packages/ti/sdo/ce/utils/xdm/lib/*.a* \
+ ${S}/cetools/packages/ti/sdo/utils/trace/lib/*.a* \
+ "
+
+do_install() {
+ unset CFLAGS CPPFLAGS CXXFLAGS LDFLAGS
+ cd ${S}/cetools/packages/ti/sdo/linuxutils/cmem
+ oe_runmake install
+ install -d ${D}/lib/modules/${KERNEL_VERSION}/kernel/drivers/dsp
+ mv ${D}/cmemk.ko ${D}/lib/modules/${KERNEL_VERSION}/kernel/drivers/dsp
+ install -d ${D}/${base_sbindir}
+ cd ${D} ; mv apitest apitestd multi_process multi_processd translate translated ${D}/${base_sbindir}
+
+
+ install -d ${D}/${libdir}
+ for i in ${DSPLIBS}; do
+ install -m 0755 $i ${D}/${libdir}/ || true
+ done
+ install -m 0755 ${S}/cetools/packages/ti/sdo/linuxutils/cmem/lib/*.a ${D}/${libdir}
+}
+
+do_stage() {
+ install -d ${STAGING_LIBDIR}
+ for i in ${DSPLIBS} ; do
+ install -m 0755 $i ${STAGING_LIBDIR}/
+ ln -sf ${STAGING_LIBDIR}/$(basename $i | awk -F. '{print $1}').a470MV ${STAGING_LIBDIR}/$(basename $i | awk -F. '{print $1}').a || true
+ done
+
+ install -m 0755 ${S}/cetools/packages/ti/sdo/linuxutils/cmem/lib/*.a ${STAGING_LIBDIR}/
+
+ install -d ${STAGING_INCDIR}/codec-engine}
+
+ for header in $(find ${S}/cetools/packages/ -name "*.h") ; do
+ install -d ${STAGING_INCDIR}/codec-engine/$(dirname $header | sed s:${S}::g)
+ cp -pPr $header ${STAGING_INCDIR}/codec-engine/$(echo $header | sed s:${S}::g)
+ done
+
+ for header in $(find ${S}/packages/ -name "*.h") ; do
+ install -d ${STAGING_INCDIR}/codec-engine/$(dirname $header | sed s:${S}::g)
+ cp -pPr $header ${STAGING_INCDIR}/codec-engine/$(echo $header | sed s:${S}::g)
+ done
+
+}
+
+pkg_postinst_${PN}-module () {
+ if [ -n "$D" ]; then
+ exit 1
+ fi
+ depmod -a
+ update-modules || true
+}
+
+pkg_postrm_${PN}-module () {
+ update-modules || true
+}
+
+PACKAGES =+ "dsplink-cmemk-module"
+FILES_dsplink-cmemk-module = "${sysconfdir} /lib/modules/${KERNEL_VERSION}/kernel/drivers/dsp/*ko"
+INHIBIT_PACKAGE_STRIP = "1"
+
+FILES_${PN} = "${base_sbindir}"
+
+PACKAGE_ARCH = "${MACHINE_ARCH}"
diff --git a/packages/dsplink/dsplink.inc b/packages/dsplink/dsplink.inc
index f303b6e53f..3b18d490cd 100644
--- a/packages/dsplink/dsplink.inc
+++ b/packages/dsplink/dsplink.inc
@@ -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}
@@ -136,8 +113,8 @@ do_install () {
do_stage() {
- install -d ${STAGING_LIBDIR}
- install -m 0755 ${S}/gpp/BUILD/EXPORT/RELEASE/dsplink.lib ${STAGING_LIBDIR}/
+ install -d ${STAGING_DIR_TARGET}/dsplink
+ cp -pPr ${S}/* ${STAGING_DIR_TARGET}/dsplink/
}
pkg_postinst_${PN}-module () {
diff --git a/packages/dsplink/dsplink_1.51.00.08.bb b/packages/dsplink/dsplink_1.51.00.08.bb
index b110ab9fb6..3c6d39e6c9 100644
--- a/packages/dsplink/dsplink_1.51.00.08.bb
+++ b/packages/dsplink/dsplink_1.51.00.08.bb
@@ -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
index 0000000000..2e0de85b58
--- /dev/null
+++ b/packages/dsplink/dsplink_1.60.00.04.bb
@@ -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
index 0000000000..7156bcbda3
--- /dev/null
+++ b/packages/dsplink/files/Makefile.dsplink
@@ -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/*
diff --git a/packages/dsplink/files/c64xx_5.xx_linux.mk b/packages/dsplink/files/c64xx_5.xx_linux.mk
index ea806fff4e..0a75c147ae 100644
--- a/packages/dsplink/files/c64xx_5.xx_linux.mk
+++ b/packages/dsplink/files/c64xx_5.xx_linux.mk
@@ -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
diff --git a/packages/dsplink/ti-paths.inc b/packages/dsplink/ti-paths.inc
index 83cbe683c0..b54f4bc6f5 100644
--- a/packages/dsplink/ti-paths.inc
+++ b/packages/dsplink/ti-paths.inc
@@ -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"
-TIXDCTOOLSDIR ?= "${TIBIOSDIR}/xdctools"
+TIBIOSDIR ?= "bios_5_32_04"
+TIXDCTOOLSDIR ?= "${TITOOLSDIR}/xdctools_3_10_02"
# Path under TITOOLSDIR where the dsp toolchain is unpacked
-TICGTOOLSDIR ?= "cg6x_6_1_2"
+TICGTOOLSDIR ?= "cg6x_6_0_19"
diff --git a/packages/fswebcam/fswebcam_20070108.bb b/packages/fswebcam/fswebcam_20070108.bb
new file mode 100644
index 0000000000..e24dbf3533
--- /dev/null
+++ b/packages/fswebcam/fswebcam_20070108.bb
@@ -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/gcc/gcc-configure-common.inc b/packages/gcc/gcc-configure-common.inc
index 795911db74..e88cee5cb2 100644
--- a/packages/gcc/gcc-configure-common.inc
+++ b/packages/gcc/gcc-configure-common.inc
@@ -75,6 +75,13 @@ do_configure () {
export LDFLAGS_FOR_BUILD="${BUILD_LDFLAGS}"
export ARCH_FLAGS_FOR_TARGET="${ARCH_FLAGS_FOR_TARGET}"
(cd ${S} && gnu-configize) || die "failure running gnu-configize"
+
+ # splice our idea of where the headers live into gcc's world
+ echo "NATIVE_SYSTEM_HEADER_DIR = ${layout_includedir}" > ${T}/t-oe
+ sed 's%^tmake_file=.*$%& ${T}/t-oe%' < ${S}/gcc/Makefile.in >${S}/gcc/Makefile.in.new
+ mv ${S}/gcc/Makefile.in.new ${S}/gcc/Makefile.in
+
+ echo "#define STANDARD_INCLUDE_DIR \"${layout_includedir}\"" >> ${S}/gcc/defaults.h
+
oe_runconf
}
-
diff --git a/packages/gcc/gcc-cross-kernel.inc b/packages/gcc/gcc-cross-kernel.inc
index a567c60119..c0a8de77cc 100644
--- a/packages/gcc/gcc-cross-kernel.inc
+++ b/packages/gcc/gcc-cross-kernel.inc
@@ -9,6 +9,13 @@ do_install () {
:
}
+do_compile () {
+ # This compiler is only for the kernel. Don't bother running fixincludes.
+ mkdir -p gcc
+ touch gcc/stmp-fixinc
+ oe_runmake
+}
+
do_stage () {
cd gcc
oe_runmake installdirs install-common install-headers install-libgcc
diff --git a/packages/gdb/gdb.inc b/packages/gdb/gdb.inc
index 8e7121bd49..77a9ca6a3e 100644
--- a/packages/gdb/gdb.inc
+++ b/packages/gdb/gdb.inc
@@ -29,6 +29,11 @@ do_configure () {
# override this function to avoid the autoconf/automake/aclocal/autoheader
# calls for now
(cd ${S} && gnu-configize) || die "failure in running gnu-configize"
+
+ # Remove duplicate spaces to work around configure complaining about
+ # changed LDFLAGS.
+ LDFLAGS=$(echo "${LDFLAGS}" | sed "s/ / /")
+
CPPFLAGS="" oe_runconf
}
diff --git a/packages/gdb/gdb_6.3.bb b/packages/gdb/gdb_6.3.bb
index a558775ff4..988cfb4c44 100644
--- a/packages/gdb/gdb_6.3.bb
+++ b/packages/gdb/gdb_6.3.bb
@@ -1,3 +1,3 @@
require gdb.inc
-PR = "r3"
+PR = "r4"
diff --git a/packages/gdb/gdb_6.4.bb b/packages/gdb/gdb_6.4.bb
index de6bcf34ba..be40f3f12b 100644
--- a/packages/gdb/gdb_6.4.bb
+++ b/packages/gdb/gdb_6.4.bb
@@ -1,3 +1,3 @@
require gdb.inc
-PR = "r1" \ No newline at end of file
+PR = "r2"
diff --git a/packages/gdb/gdb_6.6.bb b/packages/gdb/gdb_6.6.bb
index c507a48aa8..e4502a648e 100644
--- a/packages/gdb/gdb_6.6.bb
+++ b/packages/gdb/gdb_6.6.bb
@@ -1,5 +1,5 @@
require gdb.inc
-PR = "r4"
+PR = "r5"
SRC_URI += "file://early_debug_in_nptl.patch;patch=1;pnum=0"
diff --git a/packages/gdb/gdb_6.7.1.bb b/packages/gdb/gdb_6.7.1.bb
index a411974b15..fedf2bf1f1 100644
--- a/packages/gdb/gdb_6.7.1.bb
+++ b/packages/gdb/gdb_6.7.1.bb
@@ -1,5 +1,7 @@
require gdb.inc
+PR = "r1"
+
DEFAULT_PREFERENCE_avr32 = "99"
SRC_URI_avr32 = " http://avr32linux.org/twiki/pub/Main/GDBPatches/gdb-6.7.1.atmel.1.0.3.tar.bz2"
S_avr32 = "${WORKDIR}/gdb-6.7.1.atmel.1.0.3"
diff --git a/packages/gdb/gdb_6.8.bb b/packages/gdb/gdb_6.8.bb
index 5b8f3769bd..be40f3f12b 100644
--- a/packages/gdb/gdb_6.8.bb
+++ b/packages/gdb/gdb_6.8.bb
@@ -1,3 +1,3 @@
require gdb.inc
-PR = "r1"
+PR = "r2"
diff --git a/packages/giflib/giflib_4.1.6.bb b/packages/giflib/giflib_4.1.6.bb
new file mode 100644
index 0000000000..0f4223c76a
--- /dev/null
+++ b/packages/giflib/giflib_4.1.6.bb
@@ -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/glibc/files/etc/ld.so.conf b/packages/glibc/files/etc/ld.so.conf
deleted file mode 100644
index dfa65edb85..0000000000
--- a/packages/glibc/files/etc/ld.so.conf
+++ /dev/null
@@ -1,2 +0,0 @@
-/usr/local/lib
-/usr/X11R6/lib
diff --git a/packages/glibc/glibc-package.bbclass b/packages/glibc/glibc-package.bbclass
index 43a64d8af1..e982a24eb2 100644
--- a/packages/glibc/glibc-package.bbclass
+++ b/packages/glibc/glibc-package.bbclass
@@ -26,12 +26,15 @@ ENABLE_BINARY_LOCALE_GENERATION ?= "0"
# BINARY_LOCALE_ARCHES is a space separated list of regular expressions
BINARY_LOCALE_ARCHES ?= "arm.*"
+# Set this to zero if you don't want ldconfig in the output package
+USE_LDCONFIG ?= "1"
+
PACKAGES = "glibc-dbg glibc catchsegv sln nscd ldd localedef glibc-utils glibc-dev glibc-doc glibc-locale libsegfault glibc-extra-nss glibc-thread-db glibc-pcprofile"
PACKAGES_DYNAMIC = "glibc-gconv-* glibc-charmap-* glibc-localedata-* locale-base-* glibc-binary-localedata-*"
libc_baselibs = "/lib/libc* /lib/libm* /lib/ld* /lib/libpthread* /lib/libresolv* /lib/librt* /lib/libutil* /lib/libnsl* /lib/libnss_files* /lib/libnss_compat* /lib/libnss_dns* /lib/libdl* /lib/libanl* /lib/libBrokenLocale*"
-FILES_${PN} = "${sysconfdir} ${libc_baselibs} /sbin/ldconfig ${libexecdir}/* ${datadir}/zoneinfo"
+FILES_${PN} = "${libc_baselibs} ${libexecdir}/* ${datadir}/zoneinfo ${@base_conditional('USE_LDCONFIG', '1', '/sbin/ldconfig', '', d)}"
FILES_ldd = "${bindir}/ldd"
FILES_libsegfault = "/lib/libSegFault*"
FILES_glibc-extra-nss = "/lib/libnss*"
@@ -70,7 +73,6 @@ do_install() {
h=`echo $r|sed -e's,\.x$,.h,'`
install -m 0644 ${S}/sunrpc/rpcsvc/$h ${D}/${includedir}/rpcsvc/
done
- install -m 0644 ${WORKDIR}/etc/ld.so.conf ${D}/${sysconfdir}/
install -d ${D}${libdir}/locale
make -f ${WORKDIR}/generate-supported.mk IN="${S}/localedata/SUPPORTED" OUT="${WORKDIR}/SUPPORTED"
# get rid of some broken files...
diff --git a/packages/glibc/glibc_2.2.5.bb b/packages/glibc/glibc_2.2.5.bb
index 3e57d857ae..c7d308b6a2 100644
--- a/packages/glibc/glibc_2.2.5.bb
+++ b/packages/glibc/glibc_2.2.5.bb
@@ -1,7 +1,7 @@
require glibc.inc
FILESDIR = "${@os.path.dirname(bb.data.getVar('FILE',d,1))}/glibc-cvs"
-PR = "r18"
+PR = "r19"
DEFAULT_PREFERENCE_sh3 = "-99"
diff --git a/packages/glibc/glibc_2.3.2+cvs20040726.bb b/packages/glibc/glibc_2.3.2+cvs20040726.bb
index c53c2dd620..f0521d41ab 100644
--- a/packages/glibc/glibc_2.3.2+cvs20040726.bb
+++ b/packages/glibc/glibc_2.3.2+cvs20040726.bb
@@ -3,7 +3,7 @@ require glibc.inc
DEFAULT_PREFERENCE_sh3 = "-99"
FILESDIR = "${@os.path.dirname(bb.data.getVar('FILE',d,1))}/glibc-cvs"
-PR = "r29"
+PR = "r30"
GLIBC_ADDONS ?= "linuxthreads"
diff --git a/packages/glibc/glibc_2.3.2.bb b/packages/glibc/glibc_2.3.2.bb
index 05b46ba2e9..891d9da388 100644
--- a/packages/glibc/glibc_2.3.2.bb
+++ b/packages/glibc/glibc_2.3.2.bb
@@ -1,6 +1,6 @@
require glibc.inc
-PR = "r18"
+PR = "r19"
DEFAULT_PREFERENCE_sh3 = "-99"
diff --git a/packages/glibc/glibc_2.3.3+cvs20041128.bb b/packages/glibc/glibc_2.3.3+cvs20041128.bb
index a2492f6801..560347d770 100644
--- a/packages/glibc/glibc_2.3.3+cvs20041128.bb
+++ b/packages/glibc/glibc_2.3.3+cvs20041128.bb
@@ -3,7 +3,7 @@ require glibc.inc
DEFAULT_PREFERENCE_sh3 = "-99"
FILESDIR = "${@os.path.dirname(bb.data.getVar('FILE',d,1))}/glibc-cvs"
-PR = "r14"
+PR = "r15"
GLIBC_ADDONS ?= "linuxthreads"
diff --git a/packages/glibc/glibc_2.3.3+cvs20050221.bb b/packages/glibc/glibc_2.3.3+cvs20050221.bb
index 16525029da..e0becb8c3f 100644
--- a/packages/glibc/glibc_2.3.3+cvs20050221.bb
+++ b/packages/glibc/glibc_2.3.3+cvs20050221.bb
@@ -3,7 +3,7 @@ require glibc.inc
DEFAULT_PREFERENCE_sh3 = "-99"
FILESDIR = "${@os.path.dirname(bb.data.getVar('FILE',d,1))}/glibc-cvs"
-PR = "r14"
+PR = "r15"
GLIBC_ADDONS ?= "linuxthreads"
diff --git a/packages/glibc/glibc_2.3.3+cvs20050420.bb b/packages/glibc/glibc_2.3.3+cvs20050420.bb
index bd394921b9..1ae351889c 100644
--- a/packages/glibc/glibc_2.3.3+cvs20050420.bb
+++ b/packages/glibc/glibc_2.3.3+cvs20050420.bb
@@ -5,7 +5,7 @@ DEFAULT_PREFERENCE_i586 = "0"
DEFAULT_PREFERENCE_sh3 = "-99"
FILESDIR = "${@os.path.dirname(bb.data.getVar('FILE',d,1))}/glibc-cvs"
-PR = "r12"
+PR = "r13"
GLIBC_ADDONS ?= "linuxthreads"
diff --git a/packages/glibc/glibc_2.3.3.bb b/packages/glibc/glibc_2.3.3.bb
index 2908baf4cb..03711f7ae3 100644
--- a/packages/glibc/glibc_2.3.3.bb
+++ b/packages/glibc/glibc_2.3.3.bb
@@ -1,6 +1,6 @@
require glibc.inc
-PR = "r15"
+PR = "r16"
DEFAULT_PREFERENCE_sh3 = "-99"
diff --git a/packages/glibc/glibc_2.3.5+cvs20050627.bb b/packages/glibc/glibc_2.3.5+cvs20050627.bb
index 54a1654404..c9d0b66daf 100644
--- a/packages/glibc/glibc_2.3.5+cvs20050627.bb
+++ b/packages/glibc/glibc_2.3.5+cvs20050627.bb
@@ -2,7 +2,7 @@ require glibc.inc
FILESDIR = "${@os.path.dirname(bb.data.getVar('FILE',d,1))}/glibc-cvs-2.3.5"
SRCDATE = "20050627"
-PR = "r21"
+PR = "r22"
#Doesnt build for sh3
DEFAULT_PREFERENCE_sh3="-1"
diff --git a/packages/glibc/glibc_2.3.6.bb b/packages/glibc/glibc_2.3.6.bb
index edf15cab61..8442a15e69 100644
--- a/packages/glibc/glibc_2.3.6.bb
+++ b/packages/glibc/glibc_2.3.6.bb
@@ -1,6 +1,6 @@
require glibc.inc
-PR = "r3"
+PR = "r4"
#FILESPATH = "${@base_set_filespath([ '${FILE_DIRNAME}/glibc-2.3.6', '${FILE_DIRNAME}/orig/glibc', '${FILE_DIRNAME}/orig/files', '${FILE_DIRNAME}/orig' ], d)}"
diff --git a/packages/glibc/glibc_2.4.bb b/packages/glibc/glibc_2.4.bb
index 17cebf8921..8ee10003df 100644
--- a/packages/glibc/glibc_2.4.bb
+++ b/packages/glibc/glibc_2.4.bb
@@ -1,6 +1,6 @@
require glibc.inc
-PR = "r19"
+PR = "r20"
#add the hosts that are confirmed to be working to COMPATIBLE_HOSTi
COMPATIBLE_HOST = '(i.86.*-linux|sh.*-linux)'
diff --git a/packages/glibc/glibc_2.5.bb b/packages/glibc/glibc_2.5.bb
index a5908762ef..6e2295904b 100644
--- a/packages/glibc/glibc_2.5.bb
+++ b/packages/glibc/glibc_2.5.bb
@@ -1,5 +1,5 @@
require glibc.inc
-PR = "r17"
+PR = "r18"
ARM_INSTRUCTION_SET = "arm"
diff --git a/packages/glibc/glibc_2.6.1.bb b/packages/glibc/glibc_2.6.1.bb
index 5cd1d5b3e7..c563a1f389 100644
--- a/packages/glibc/glibc_2.6.1.bb
+++ b/packages/glibc/glibc_2.6.1.bb
@@ -1,5 +1,5 @@
require glibc.inc
-PR = "r12"
+PR = "r13"
PACKAGES_DYNAMIC = "libc6*"
RPROVIDES_${PN}-dev = "libc6-dev virtual-libc-dev"
diff --git a/packages/glibc/glibc_2.7.bb b/packages/glibc/glibc_2.7.bb
index b6c329091c..3349ce5eef 100644
--- a/packages/glibc/glibc_2.7.bb
+++ b/packages/glibc/glibc_2.7.bb
@@ -5,7 +5,7 @@ ARM_INSTRUCTION_SET = "arm"
PACKAGES_DYNAMIC = "libc6*"
RPROVIDES_${PN}-dev = "libc6-dev virtual-libc-dev"
-PR = "r7"
+PR = "r8"
# the -isystem in bitbake.conf screws up glibc do_stage
BUILD_CPPFLAGS = "-I${STAGING_INCDIR_NATIVE}"
diff --git a/packages/gtk+/gdk-pixbuf-csource-native_2.12.11.bb b/packages/gtk+/gdk-pixbuf-csource-native_2.12.11.bb
index 2af16a344b..c7abc18855 100644
--- a/packages/gtk+/gdk-pixbuf-csource-native_2.12.11.bb
+++ b/packages/gtk+/gdk-pixbuf-csource-native_2.12.11.bb
@@ -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/kexecboot/linux-kexecboot-2.6.26/collie/defconfig b/packages/kexecboot/linux-kexecboot-2.6.26/collie/defconfig
index 4434962a64..2e7c8130f6 100644
--- a/packages/kexecboot/linux-kexecboot-2.6.26/collie/defconfig
+++ b/packages/kexecboot/linux-kexecboot-2.6.26/collie/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.26
-# Thu Jul 24 23:13:04 2008
+# Sat Oct 18 23:52:11 2008
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -34,7 +34,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
-# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
@@ -49,6 +49,8 @@ CONFIG_LOG_BUF_SHIFT=14
# CONFIG_NAMESPACES is not set
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE="initramfs.cpio.gz"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
@@ -251,7 +253,7 @@ CONFIG_ALIGNMENT_TRAP=y
#
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttySA0,115200n8 console=tty1 noinitrd root=/dev/mtdblock2 rootfstype=jffs2 rootdelay=3 mem=64M fbcon=rotate:1 dyntick=enable"
+CONFIG_CMDLINE="console=ttySA0,115200n8 console=tty1 mem=64M fbcon=rotate:1"
# CONFIG_XIP_KERNEL is not set
CONFIG_KEXEC=y
CONFIG_ATAGS_PROC=y
@@ -342,14 +344,12 @@ CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
-CONFING_MTD_SHARP=y
+CONFIG_MTD_SHARP=y
#
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_ARM_INTEGRATOR is not set
CONFIG_MTD_SA1100=y
# CONFIG_MTD_PLATRAM is not set
diff --git a/packages/kexecboot/linux-kexecboot_2.6.26.bb b/packages/kexecboot/linux-kexecboot_2.6.26.bb
index 2db6575a72..a0d00ab120 100644
--- a/packages/kexecboot/linux-kexecboot_2.6.26.bb
+++ b/packages/kexecboot/linux-kexecboot_2.6.26.bb
@@ -1,6 +1,6 @@
require linux-kexecboot.inc
-PR = "r5"
+PR = "r6"
DEFAULT_PREFERENCE = "-1"
DEFAULT_PREFERENCE_qemuarm = "-1"
DEFAULT_PREFERENCE_qemux86 = "-1"
diff --git a/packages/lesstif/files/000_bootstrap_script.diff b/packages/lesstif/files/000_bootstrap_script.diff
new file mode 100644
index 0000000000..ca1a998700
--- /dev/null
+++ b/packages/lesstif/files/000_bootstrap_script.diff
@@ -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
index 0000000000..18a5bc57a4
--- /dev/null
+++ b/packages/lesstif/files/000_libtool_linking.diff
@@ -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
index 0000000000..8bf355fdb9
--- /dev/null
+++ b/packages/lesstif/files/010_rebootstrap-small.diff
@@ -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
index 0000000000..620d702f0f
--- /dev/null
+++ b/packages/lesstif/files/020_bad_integer_cast.diff
@@ -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
index 0000000000..2d298d5f4c
--- /dev/null
+++ b/packages/lesstif/files/020_missing_xm_h.diff
@@ -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
index 0000000000..1699dbe190
--- /dev/null
+++ b/packages/lesstif/files/020_render_table_crash.diff
@@ -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
index 0000000000..a682d9704c
--- /dev/null
+++ b/packages/lesstif/files/020_unsigned_int.diff
@@ -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
index 0000000000..69f9a2464c
--- /dev/null
+++ b/packages/lesstif/files/020_xpmpipethrough.diff
@@ -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
index 0000000000..10bdf8d0b9
--- /dev/null
+++ b/packages/lesstif/files/021_xim_chained_list_crash.diff
@@ -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
index 0000000000..da6363258c
--- /dev/null
+++ b/packages/lesstif/files/030_manpage.diff
@@ -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
index 0000000000..3fe6e8357d
--- /dev/null
+++ b/packages/lesstif/files/ac_debug.m4.diff
@@ -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
index 0000000000..69529b868d
--- /dev/null
+++ b/packages/lesstif/files/ac_find_xft.m4.diff
@@ -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
index 0000000000..577bd5de0a
--- /dev/null
+++ b/packages/lesstif/files/ac_have_libxp.m4.diff
@@ -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
index 0000000000..6ce3f8a939
--- /dev/null
+++ b/packages/lesstif/files/aclocal.m4.diff
@@ -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
index 0000000000..f6038370d5
--- /dev/null
+++ b/packages/lesstif/files/disable-docs.patch
@@ -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
index 0000000000..6a01a9c72b
--- /dev/null
+++ b/packages/lesstif/lesstif_0.95.0.bb
@@ -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
index 0000000000..300df81564
--- /dev/null
+++ b/packages/libffi/libffi_2.0+gcc4.3.2.bb
@@ -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
+}
diff --git a/packages/libsdl/files/fixmfour.patch b/packages/libsdl/files/fixmfour.patch
new file mode 100644
index 0000000000..0d534bd9a1
--- /dev/null
+++ b/packages/libsdl/files/fixmfour.patch
@@ -0,0 +1,14 @@
+Index: SDL-1.2.11/sdl.m4
+===================================================================
+--- SDL-1.2.11.orig/sdl.m4 2008-10-18 21:20:13.482478928 +0200
++++ SDL-1.2.11/sdl.m4 2008-10-18 21:20:28.979441480 +0200
+@@ -32,9 +32,6 @@
+ fi
+ fi
+
+- if test "x$prefix" != xNONE; then
+- PATH="$prefix/bin:$prefix/usr/bin:$PATH"
+- fi
+ AC_PATH_PROG(SDL_CONFIG, sdl-config, no, [$PATH])
+ min_sdl_version=ifelse([$1], ,0.11.0,$1)
+ AC_MSG_CHECKING(for SDL - version >= $min_sdl_version)
diff --git a/packages/libsdl/libsdl-image_1.2.6.bb b/packages/libsdl/libsdl-image_1.2.6.bb
index 27b5aa7d1a..99fd98f508 100644
--- a/packages/libsdl/libsdl-image_1.2.6.bb
+++ b/packages/libsdl/libsdl-image_1.2.6.bb
@@ -1,8 +1,12 @@
require libsdl-image.inc
+PR = "r1"
+
+DEPENDS += "tiff"
do_unpackpost() {
# Removing this file fixes a libtool version mismatch.
rm acinclude/libtool.m4
+ rm acinclude/sdl.m4
}
addtask unpackpost after do_unpack before do_patch
diff --git a/packages/libsdl/libsdl-x11_1.2.11.bb b/packages/libsdl/libsdl-x11_1.2.11.bb
index 3f9120edb4..ab349d6306 100644
--- a/packages/libsdl/libsdl-x11_1.2.11.bb
+++ b/packages/libsdl/libsdl-x11_1.2.11.bb
@@ -3,7 +3,7 @@ require libsdl.inc
# extra-keys.patch is missing
DEFAULT_PREFERENCE = "-1"
-PR = "r6"
+PR = "r7"
SRC_URI = "\
http://www.libsdl.org/release/SDL-${PV}.tar.gz \
@@ -12,6 +12,7 @@ SRC_URI = "\
file://pagesize.patch;patch=1 \
file://kernel-asm-page.patch;patch=1 \
file://sdl-cdfix.patch;patch=1 \
+ file://fixmfour.patch;patch=1 \
"
EXTRA_OECONF = "--disable-static --disable-debug --enable-cdrom --enable-threads --enable-timers --enable-endian \
diff --git a/packages/linux/linux-omap2-git/beagleboard/defconfig b/packages/linux/linux-omap2-git/beagleboard/defconfig
index c726740485..413167de7e 100644
--- a/packages/linux/linux-omap2-git/beagleboard/defconfig
+++ b/packages/linux/linux-omap2-git/beagleboard/defconfig
@@ -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
diff --git a/packages/linux/linux-rp-2.6.26/defconfig-collie b/packages/linux/linux-rp-2.6.26/defconfig-collie
index e21cc21da2..e80885f332 100644
--- a/packages/linux/linux-rp-2.6.26/defconfig-collie
+++ b/packages/linux/linux-rp-2.6.26/defconfig-collie
@@ -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
index 0000000000..3c86f1a474
--- /dev/null
+++ b/packages/linux/linux-rp-2.6.26/usb-gadget27bp.patch
@@ -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)
++
++/*-------------------------------------------------------------------------*/
+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);
diff --git a/packages/linux/linux-rp_2.6.25+2.6.26-rc4.bb b/packages/linux/linux-rp_2.6.25+2.6.26-rc4.bb
index a027a59380..3f9eac86a5 100644
--- a/packages/linux/linux-rp_2.6.25+2.6.26-rc4.bb
+++ b/packages/linux/linux-rp_2.6.25+2.6.26-rc4.bb
@@ -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 \
diff --git a/packages/linux/linux-rp_2.6.26.bb b/packages/linux/linux-rp_2.6.26.bb
index 00e39a77a3..dd126285ea 100644
--- a/packages/linux/linux-rp_2.6.26.bb
+++ b/packages/linux/linux-rp_2.6.26.bb
@@ -1,6 +1,6 @@
require linux-rp.inc
-PR = "r4"
+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 = "\
diff --git a/packages/meta/slugos-packages.bb b/packages/meta/slugos-packages.bb
index dd19abccaf..b01c96b189 100644
--- a/packages/meta/slugos-packages.bb
+++ b/packages/meta/slugos-packages.bb
@@ -92,6 +92,7 @@ SLUGOS_PACKAGES = "\
fuse \
gawk \
gcc \
+ gdb \
gdbm \
glib-2.0 \
gnu-config \
@@ -254,7 +255,6 @@ SLUGOS_BROKEN_PACKAGES = "\
ctorrent \
dsniff \
eciadsl \
- gdb \
gspcav1 \
linphone \
lirc-modules lirc \
diff --git a/packages/mozilla/fennec_hg.bb b/packages/mozilla/fennec_hg.bb
index 0760768e09..8c6f326f73 100644
--- a/packages/mozilla/fennec_hg.bb
+++ b/packages/mozilla/fennec_hg.bb
@@ -1,13 +1,13 @@
DESCRIPTION = "Mozilla Mobile browser"
DEPENDS += "cairo alsa-lib "
-PV = "0.8+0.9pre"
-MOZPV = "0.9pre"
-PR = "r10"
+PV = "0.9+1.0a1"
+MOZPV = "1.0a1"
+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
}
diff --git a/packages/nfs-utils/nfs-utils_1.1.2.bb b/packages/nfs-utils/nfs-utils_1.1.2.bb
index bcdabd59e5..872a9bf8ff 100644
--- a/packages/nfs-utils/nfs-utils_1.1.2.bb
+++ b/packages/nfs-utils/nfs-utils_1.1.2.bb
@@ -5,7 +5,7 @@ LICENSE = "GPL"
PR = "2"
-DEPENDS = "tcp-wrappers libevent"
+DEPENDS = "e2fsprogs tcp-wrappers libevent"
SRC_URI = "${SOURCEFORGE_MIRROR}/nfs/nfs-utils-${PV}.tar.gz \
file://nfsserver \
diff --git a/packages/openchrome/configure-dri.patch b/packages/openchrome/configure-dri.patch
new file mode 100644
index 0000000000..605078ec2b
--- /dev/null
+++ b/packages/openchrome/configure-dri.patch
@@ -0,0 +1,11 @@
+--- s/configure.ac~ 2008-07-27 10:50:51.000000000 +0100
++++ s/configure.ac 2008-07-27 10:57:25.000000000 +0100
+@@ -70,7 +70,7 @@
+ XORG_DRIVER_CHECK_EXT(DPMSExtension, xextproto)
+
+ # Checks for pkg-config packages
+-PKG_CHECK_MODULES(XORG, [xorg-server xproto xvmc fontsproto libdrm $REQUIRED_MODULES])
++PKG_CHECK_MODULES(XORG, [xorg-server xproto xvmc fontsproto libdrm xf86driproto $REQUIRED_MODULES])
+ sdkdir=$(pkg-config --variable=sdkdir xorg-server)
+
+ # Checks for libraries.
diff --git a/packages/pcsc-lite/files/pcscd.init b/packages/pcsc-lite/files/pcscd.init
new file mode 100644
index 0000000000..92385ab196
--- /dev/null
+++ b/packages/pcsc-lite/files/pcscd.init
@@ -0,0 +1,32 @@
+#!/bin/sh
+DAEMON=/usr/sbin/pcscd
+NAME=pcscd
+DESC="PCSC Daemon"
+PIDFILE=/var/run/pcscd/pcscd.pid
+ARGS=""
+
+test -f $DAEMON || exit 0
+
+case "$1" in
+ start)
+ echo -n "Starting $DESC: $NAME"
+ start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- $ARGS
+ echo "."
+ ;;
+ stop)
+ echo -n "Stopping $DESC: $NAME"
+ start-stop-daemon --stop --quiet --pidfile $PIDFILE --exec $DAEMON
+ echo "."
+ ;;
+ restart)
+ $0 stop
+ sleep 1
+ $0 start
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|restart}"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/packages/pcsc-lite/pcsc-lite_1.4.102.bb b/packages/pcsc-lite/pcsc-lite_1.4.102.bb
new file mode 100644
index 0000000000..0455ae47a8
--- /dev/null
+++ b/packages/pcsc-lite/pcsc-lite_1.4.102.bb
@@ -0,0 +1,35 @@
+DESCRIPTION = "PC/SC Lite smart card framework and applications"
+HOMEPAGE = "http://pcsclite.alioth.debian.org/"
+LICENSE = "BSD"
+PR = "r0"
+
+DEPENDS = "hal"
+RDEPENDS_${PN} = "hal"
+
+SRC_URI = "http://alioth.debian.org/download.php/2479/pcsc-lite-${PV}.tar.bz2 \
+ file://pcscd.init "
+
+inherit autotools update-rc.d
+
+INITSCRIPT_NAME = "pcscd"
+INITSCRIPT_PARAMS = "defaults"
+
+EXTRA_OECONF = " \
+ --enable-libhal \
+ --disable-libusb \
+ --enable-usbdropdir=${libdir}/pcsc/drivers \
+ "
+
+do_stage() {
+ autotools_stage_all
+}
+
+do_install() {
+ oe_runmake DESTDIR="${D}" install
+ install -d "${D}/etc/init.d"
+ install -m 755 "${WORKDIR}/pcscd.init" "${D}/etc/init.d/pcscd"
+}
+
+PACKAGES =+ "libpcsclite"
+
+FILES_libpcsclite = "${libdir}/libpcsclite.so.*"
diff --git a/packages/perl/perl-native_5.8.8.bb b/packages/perl/perl-native_5.8.8.bb
index c1f2585658..c58f82822c 100644
--- a/packages/perl/perl-native_5.8.8.bb
+++ b/packages/perl/perl-native_5.8.8.bb
@@ -55,8 +55,10 @@ do_configure () {
-Ud_csh \
-Uusesfio \
-Uusenm -des
- sed 's!${STAGING_DIR}/bin!${STAGING_BINDIR}!;
- s!${STAGING_DIR}/lib!${STAGING_LIBDIR}!' < config.sh > config.sh.new
+ sed "s!${STAGING_DIR}/bin!${STAGING_BINDIR}!;
+ s!${STAGING_DIR}/lib!${STAGING_LIBDIR}!;
+ s!^installbin=.*!installbin=\'${STAGING_BINDIR}\'!;
+ s!^installsitebin=.*!installsitebin=\'${STAGING_BINDIR}\'!" < config.sh > config.sh.new
mv config.sh.new config.sh
}
do_stage_append() {
diff --git a/packages/python/python-2.5-manifest.inc b/packages/python/python-2.5-manifest.inc
index 827105ce69..4142a4b620 100644
--- a/packages/python/python-2.5-manifest.inc
+++ b/packages/python/python-2.5-manifest.inc
@@ -1,12 +1,12 @@
# WARNING: This file is AUTO GENERATED: Manual edits will be lost next time I regenerate the file.
-# Generator: 'generate-manifest-2.5.py' Version 20080722 (C) 2002-2008 Michael 'Mickey' Lauer <mlauer@vanille-media.de>
+# Generator: './generate-manifest-2.5.py' Version 20080722 (C) 2002-2008 Michael 'Mickey' Lauer <mlauer@vanille-media.de>
# Visit the Python for Embedded Systems Site => http://www.Vanille.de/projects/python.spy
-PROVIDES+="python-profile python-threading python-distutils python-doctest python-codecs python-ctypes python-pickle python-bzip2 python-datetime python-core python-io python-compiler python-compression python-re python-xmlrpc python-terminal python-email python-image python-tests python-core-dbg python-resource python-devel python-difflib python-math python-syslog python-hotshot python-unixadmin python-textutils python-tkinter python-gdbm python-elementtree python-fcntl python-netclient python-pprint python-netserver python-curses python-smtpd python-html python-readline python-subprocess python-pydoc python-logging python-mailbox python-xml python-mime python-sqlite3 python-sqlite3-tests python-unittest python-stringold python-robotparser python-lib-old-and-deprecated python-compile python-debugger python-pkgutil python-shell python-bsddb python-mmap python-zlib python-db python-crypt python-idle python-lang python-audio "
+PROVIDES+="python-profile python-threading python-distutils python-doctest python-codecs python-ctypes python-pickle python-bzip2 python-datetime python-core python-io python-compiler python-compression python-re python-xmlrpc python-terminal python-email python-image python-tests python-core-dbg python-resource python-devel python-difflib python-math python-syslog python-hotshot python-unixadmin python-textutils python-tkinter python-gdbm python-elementtree python-fcntl python-netclient python-pprint python-netserver python-curses python-smtpd python-html python-readline python-subprocess python-pydoc python-logging python-mailbox python-xml python-mime python-sqlite3 python-sqlite3-tests python-unittest python-stringold python-robotparser python-compile python-debugger python-pkgutil python-shell python-bsddb python-mmap python-zlib python-db python-crypt python-idle python-lang python-audio "
-PACKAGES="python-profile python-threading python-distutils python-doctest python-codecs python-ctypes python-pickle python-bzip2 python-datetime python-core python-io python-compiler python-compression python-re python-xmlrpc python-terminal python-email python-image python-tests python-core-dbg python-resource python-devel python-difflib python-math python-syslog python-hotshot python-unixadmin python-textutils python-tkinter python-gdbm python-elementtree python-fcntl python-netclient python-pprint python-netserver python-curses python-smtpd python-html python-readline python-subprocess python-pydoc python-logging python-mailbox python-xml python-mime python-sqlite3 python-sqlite3-tests python-unittest python-stringold python-robotparser python-lib-old-and-deprecated python-compile python-debugger python-pkgutil python-shell python-bsddb python-mmap python-zlib python-db python-crypt python-idle python-lang python-audio "
+PACKAGES="python-profile python-threading python-distutils python-doctest python-codecs python-ctypes python-pickle python-bzip2 python-datetime python-core python-io python-compiler python-compression python-re python-xmlrpc python-terminal python-email python-image python-tests python-core-dbg python-resource python-devel python-difflib python-math python-syslog python-hotshot python-unixadmin python-textutils python-tkinter python-gdbm python-elementtree python-fcntl python-netclient python-pprint python-netserver python-curses python-smtpd python-html python-readline python-subprocess python-pydoc python-logging python-mailbox python-xml python-mime python-sqlite3 python-sqlite3-tests python-unittest python-stringold python-robotparser python-compile python-debugger python-pkgutil python-shell python-bsddb python-mmap python-zlib python-db python-crypt python-idle python-lang python-audio "
DESCRIPTION_python-profile="Python Basic Profiling Support"
PR_python-profile="ml0"
@@ -69,7 +69,7 @@ RDEPENDS_python-compiler="python-core"
FILES_python-compiler="${libdir}/python2.5/compiler "
DESCRIPTION_python-compression="Python High Level Compression Support"
-PR_python-compression="ml1"
+PR_python-compression="ml0"
RDEPENDS_python-compression="python-core python-zlib"
FILES_python-compression="${libdir}/python2.5/gzip.* ${libdir}/python2.5/zipfile.* ${libdir}/python2.5/tarfile.* "
@@ -214,7 +214,7 @@ RDEPENDS_python-pydoc="python-core python-lang python-stringold python-re"
FILES_python-pydoc="${bindir}/pydoc ${libdir}/python2.5/pydoc.* "
DESCRIPTION_python-logging="Python Logging Support"
-PR_python-logging="ml1"
+PR_python-logging="ml0"
RDEPENDS_python-logging="python-core python-io python-lang python-pickle python-stringold"
FILES_python-logging="${libdir}/python2.5/logging "
@@ -224,7 +224,7 @@ RDEPENDS_python-mailbox="python-core python-mime"
FILES_python-mailbox="${libdir}/python2.5/mailbox.* "
DESCRIPTION_python-xml="Python basic XML support."
-PR_python-xml="ml1"
+PR_python-xml="ml0"
RDEPENDS_python-xml="python-core python-re"
FILES_python-xml="${libdir}/python2.5/lib-dynload/pyexpat.so ${libdir}/python2.5/xml ${libdir}/python2.5/xmllib.* "
@@ -258,18 +258,13 @@ PR_python-robotparser="ml0"
RDEPENDS_python-robotparser="python-core python-netclient"
FILES_python-robotparser="${libdir}/python2.5/robotparser.* "
-DESCRIPTION_python-lib-old-and-deprecated="Python Deprecated Libraries"
-PR_python-lib-old-and-deprecated="ml0"
-RDEPENDS_python-lib-old-and-deprecated="python-core"
-FILES_python-lib-old-and-deprecated="${libdir}/python2.5/lib-old "
-
DESCRIPTION_python-compile="Python Bytecode Compilation Support"
PR_python-compile="ml0"
RDEPENDS_python-compile="python-core"
FILES_python-compile="${libdir}/python2.5/py_compile.* ${libdir}/python2.5/compileall.* "
DESCRIPTION_python-debugger="Python Debugger"
-PR_python-debugger="ml1"
+PR_python-debugger="ml0"
RDEPENDS_python-debugger="python-core python-io python-lang python-re python-stringold python-shell python-pprint"
FILES_python-debugger="${libdir}/python2.5/bdb.* ${libdir}/python2.5/pdb.* "
@@ -279,12 +274,12 @@ RDEPENDS_python-pkgutil="python-core"
FILES_python-pkgutil="${libdir}/python2.5/pkgutil.* "
DESCRIPTION_python-shell="Python Shell-Like Functionality"
-PR_python-shell="ml1"
+PR_python-shell="ml0"
RDEPENDS_python-shell="python-core python-re"
FILES_python-shell="${libdir}/python2.5/cmd.* ${libdir}/python2.5/commands.* ${libdir}/python2.5/dircache.* ${libdir}/python2.5/fnmatch.* ${libdir}/python2.5/glob.* ${libdir}/python2.5/popen2.* ${libdir}/python2.5/shlex.* ${libdir}/python2.5/shutil.* "
DESCRIPTION_python-bsddb="Python Berkeley Database Bindings"
-PR_python-bsddb="ml1"
+PR_python-bsddb="ml0"
RDEPENDS_python-bsddb="python-core"
FILES_python-bsddb="${libdir}/python2.5/bsddb ${libdir}/python2.5/lib-dynload/_bsddb.so "
@@ -304,7 +299,7 @@ RDEPENDS_python-db="python-core"
FILES_python-db="${libdir}/python2.5/anydbm.* ${libdir}/python2.5/dumbdbm.* ${libdir}/python2.5/whichdb.* "
DESCRIPTION_python-crypt="Python Basic Cryptographic and Hashing Support"
-PR_python-crypt="ml1"
+PR_python-crypt="ml0"
RDEPENDS_python-crypt="python-core"
FILES_python-crypt="${libdir}/python2.5/hashlib.* ${libdir}/python2.5/md5.* ${libdir}/python2.5/sha.* ${libdir}/python2.5/lib-dynload/crypt.so ${libdir}/python2.5/lib-dynload/_hashlib.so ${libdir}/python2.5/lib-dynload/_sha256.so ${libdir}/python2.5/lib-dynload/_sha512.so "
@@ -314,7 +309,7 @@ RDEPENDS_python-idle="python-core python-tkinter"
FILES_python-idle="${bindir}/idle ${libdir}/python2.5/idlelib "
DESCRIPTION_python-lang="Python Low-Level Language Support"
-PR_python-lang="ml1"
+PR_python-lang="ml0"
RDEPENDS_python-lang="python-core"
FILES_python-lang="${libdir}/python2.5/lib-dynload/array.so ${libdir}/python2.5/lib-dynload/parser.so ${libdir}/python2.5/lib-dynload/operator.so ${libdir}/python2.5/lib-dynload/_weakref.so ${libdir}/python2.5/lib-dynload/itertools.so ${libdir}/python2.5/lib-dynload/collections.so ${libdir}/python2.5/lib-dynload/_bisect.so ${libdir}/python2.5/lib-dynload/_heapq.so ${libdir}/python2.5/atexit.* ${libdir}/python2.5/bisect.* ${libdir}/python2.5/code.* ${libdir}/python2.5/codeop.* ${libdir}/python2.5/dis.* ${libdir}/python2.5/heapq.* ${libdir}/python2.5/inspect.* ${libdir}/python2.5/keyword.* ${libdir}/python2.5/opcode.* ${libdir}/python2.5/symbol.* ${libdir}/python2.5/repr.* ${libdir}/python2.5/token.* ${libdir}/python2.5/tokenize.* ${libdir}/python2.5/traceback.* ${libdir}/python2.5/linecache.* ${libdir}/python2.5/weakref.* "
diff --git a/packages/python/python-2.5.2/05-install.patch b/packages/python/python-2.5.2/05-install.patch
new file mode 100644
index 0000000000..c3e249db1c
--- /dev/null
+++ b/packages/python/python-2.5.2/05-install.patch
@@ -0,0 +1,13 @@
+Index: python/Lib/distutils/command/install.py
+===================================================================
+--- python.orig/Lib/distutils/command/install.py 2007-03-06 17:15:43.000000000 -0300
++++ python/Lib/distutils/command/install.py 2007-03-06 17:16:04.000000000 -0300
+@@ -601,7 +601,7 @@
+ ('install_headers', has_headers),
+ ('install_scripts', has_scripts),
+ ('install_data', has_data),
+- ('install_egg_info', lambda self:True),
++ ('install_egg_info', lambda self:False),
+ ]
+
+ # class install
diff --git a/packages/python/python-2.5.2/06-fix-urllib-exception.patch b/packages/python/python-2.5.2/06-fix-urllib-exception.patch
new file mode 100644
index 0000000000..d096ee9402
--- /dev/null
+++ b/packages/python/python-2.5.2/06-fix-urllib-exception.patch
@@ -0,0 +1,13 @@
+Index: python/Lib/urllib.py
+===================================================================
+--- python.orig/Lib/urllib.py 2007-03-06 17:16:49.000000000 -0300
++++ python/Lib/urllib.py 2007-03-06 17:17:05.000000000 -0300
+@@ -358,7 +358,7 @@
+ """Default error handler: close the connection and raise IOError."""
+ void = fp.read()
+ fp.close()
+- raise IOError, ('http error', errcode, errmsg, headers)
++ raise IOError, ('http error', errcode, errmsg)
+
+ if hasattr(socket, "ssl"):
+ def open_https(self, url, data=None):
diff --git a/packages/python/python-2.5.2/13-set-wakeup-fix.patch b/packages/python/python-2.5.2/13-set-wakeup-fix.patch
new file mode 100644
index 0000000000..807014b7a7
--- /dev/null
+++ b/packages/python/python-2.5.2/13-set-wakeup-fix.patch
@@ -0,0 +1,87 @@
+Index: python-2.5.2/Modules/signalmodule.c
+===================================================================
+--- python-2.5.2.orig/Modules/signalmodule.c 2008-02-23 13:10:12.000000000 -0300
++++ python-2.5.2/Modules/signalmodule.c 2008-02-23 13:10:48.000000000 -0300
+@@ -12,6 +12,8 @@
+
+ #include <signal.h>
+
++#include <sys/stat.h>
++
+ #ifndef SIG_ERR
+ #define SIG_ERR ((PyOS_sighandler_t)(-1))
+ #endif
+@@ -75,6 +77,8 @@
+ PyObject *func;
+ } Handlers[NSIG];
+
++static sig_atomic_t wakeup_fd = -1;
++
+ /* Speed up sigcheck() when none tripped */
+ static volatile sig_atomic_t is_tripped = 0;
+
+@@ -113,6 +117,7 @@
+ static void
+ signal_handler(int sig_num)
+ {
++ const char dummy_byte = '\0';
+ #ifdef WITH_THREAD
+ #ifdef WITH_PTH
+ if (PyThread_get_thread_ident() != main_thread) {
+@@ -128,6 +133,8 @@
+ cleared in PyErr_CheckSignals() before .tripped. */
+ is_tripped = 1;
+ Py_AddPendingCall(checksignals_witharg, NULL);
++ if (wakeup_fd != -1)
++ write(wakeup_fd, &dummy_byte, 1);
+ #ifdef WITH_THREAD
+ }
+ #endif
+@@ -267,6 +274,39 @@
+ anything else -- the callable Python object used as a handler");
+
+
++static PyObject *
++signal_set_wakeup_fd(PyObject *self, PyObject *args)
++{
++ struct stat buf;
++ int fd, old_fd;
++ if (!PyArg_ParseTuple(args, "i:set_wakeup_fd", &fd))
++ return NULL;
++#ifdef WITH_THREAD
++ if (PyThread_get_thread_ident() != main_thread) {
++ PyErr_SetString(PyExc_ValueError,
++ "set_wakeup_fd only works in main thread");
++ return NULL;
++ }
++#endif
++ if (fd != -1 && fstat(fd, &buf) != 0) {
++ PyErr_SetString(PyExc_ValueError, "invalid fd");
++ return NULL;
++ }
++ old_fd = wakeup_fd;
++ wakeup_fd = fd;
++ return PyLong_FromLong(old_fd);
++}
++
++PyDoc_STRVAR(set_wakeup_fd_doc,
++"set_wakeup_fd(fd) -> fd\n\
++\n\
++Sets the fd to be written to (with '\\0') when a signal\n\
++comes in. A library can use this to wakeup select or poll.\n\
++The previous fd is returned.\n\
++\n\
++The fd must be non-blocking.");
++
++
+ /* List of functions defined in the module */
+ static PyMethodDef signal_methods[] = {
+ #ifdef HAVE_ALARM
+@@ -274,6 +314,7 @@
+ #endif
+ {"signal", signal_signal, METH_VARARGS, signal_doc},
+ {"getsignal", signal_getsignal, METH_VARARGS, getsignal_doc},
++ {"set_wakeup_fd", signal_set_wakeup_fd, METH_VARARGS, set_wakeup_fd_doc},
+ #ifdef HAVE_PAUSE
+ {"pause", (PyCFunction)signal_pause,
+ METH_NOARGS,pause_doc},
diff --git a/packages/python/python-2.5.2/14-encodings-oriental.patch b/packages/python/python-2.5.2/14-encodings-oriental.patch
new file mode 100644
index 0000000000..4c942f1b75
--- /dev/null
+++ b/packages/python/python-2.5.2/14-encodings-oriental.patch
@@ -0,0 +1,64 @@
+Index: python-2.5.2/debian/rules
+===================================================================
+--- python-2.5.2.orig/debian/rules 2008-02-26 14:15:36.000000000 -0300
++++ python-2.5.2/debian/rules 2008-02-26 14:17:42.000000000 -0300
+@@ -134,6 +134,8 @@
+ )
+ find $(d_dev)/$(scriptdir) -name "*.pyo" -type f | grep -v -f $(only_dev_list) | xargs rm -f
+
++ find $(d_dev)/$(scriptdir)/encodings | grep -f $(only_dev_list) | xargs -i mv '{}' $(d_dev)/$(scriptdir)/encodings_orient
++
+ # move the interpreter
+ mv $(d_dev)/usr/bin/python2.5 $(d_base)/usr/bin/python2.5
+
+Index: python-2.5.2/Lib/encodings/__init__.py
+===================================================================
+--- python-2.5.2.orig/Lib/encodings/__init__.py 2008-02-26 14:15:07.000000000 -0300
++++ python-2.5.2/Lib/encodings/__init__.py 2008-02-26 14:17:42.000000000 -0300
+@@ -99,6 +99,14 @@
+ pass
+ else:
+ break
++
++ try:
++ mod = __import__('encodings_orient.' + modname,
++ globals(), locals(), _import_tail)
++ except ImportError:
++ pass
++ else:
++ break
+ else:
+ mod = None
+
+Index: python-2.5.2/Makefile.pre.in
+===================================================================
+--- python-2.5.2.orig/Makefile.pre.in 2008-02-26 14:15:07.000000000 -0300
++++ python-2.5.2/Makefile.pre.in 2008-02-26 14:17:42.000000000 -0300
+@@ -717,7 +717,7 @@
+ PLATMACPATH=:plat-mac:plat-mac/lib-scriptpackages
+ LIBSUBDIRS= lib-tk site-packages test test/output test/data \
+ test/decimaltestdata \
+- encodings compiler hotshot \
++ encodings encodings_orient compiler hotshot \
+ email email/mime email/test email/test/data \
+ sqlite3 sqlite3/test \
+ logging bsddb bsddb/test csv wsgiref \
+Index: python-2.5.2/debian/onlysdk
+===================================================================
+--- python-2.5.2.orig/debian/onlysdk 2008-02-26 14:15:07.000000000 -0300
++++ python-2.5.2/debian/onlysdk 2008-02-26 14:17:42.000000000 -0300
+@@ -1,7 +1,6 @@
+ distutils
+ compile
+-encodings/cp
+-encodings/mac
++encodings_orient
+ doctest
+ unittest
+ hotshot
+Index: python-2.5.2/Lib/encodings_orient/__init__.py
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ python-2.5.2/Lib/encodings_orient/__init__.py 2008-02-26 14:17:42.000000000 -0300
+@@ -0,0 +1 @@
++#Dummy
diff --git a/packages/python/python-2.5.2/16-bug1179-imageop.patch b/packages/python/python-2.5.2/16-bug1179-imageop.patch
new file mode 100644
index 0000000000..895d4e0a17
--- /dev/null
+++ b/packages/python/python-2.5.2/16-bug1179-imageop.patch
@@ -0,0 +1,219 @@
+Index: python-2.5.2/Modules/imageop.c
+===================================================================
+--- python-2.5.2.orig/Modules/imageop.c 2006-01-19 03:09:39.000000000 -0300
++++ python-2.5.2/Modules/imageop.c 2008-04-07 16:29:09.000000000 -0300
+@@ -78,7 +78,7 @@
+ char *cp, *ncp;
+ short *nsp;
+ Py_Int32 *nlp;
+- int len, size, x, y, newx1, newx2, newy1, newy2;
++ int len, size, x, y, newx1, newx2, newy1, newy2, nlen;
+ int ix, iy, xstep, ystep;
+ PyObject *rv;
+
+@@ -90,13 +90,19 @@
+ PyErr_SetString(ImageopError, "Size should be 1, 2 or 4");
+ return 0;
+ }
+- if ( len != size*x*y ) {
++ if (( len != size*x*y ) ||
++ ( size != ((len / x) / y) )) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+ }
+ xstep = (newx1 < newx2)? 1 : -1;
+ ystep = (newy1 < newy2)? 1 : -1;
+
++ nlen = (abs(newx2-newx1)+1)*(abs(newy2-newy1)+1)*size;
++ if ( size != ((nlen / (abs(newx2-newx1)+1)) / (abs(newy2-newy1)+1)) ) {
++ PyErr_SetString(ImageopError, "String has incorrect length");
++ return 0;
++ }
+ rv = PyString_FromStringAndSize(NULL,
+ (abs(newx2-newx1)+1)*(abs(newy2-newy1)+1)*size);
+ if ( rv == 0 )
+@@ -132,7 +138,7 @@
+ char *cp, *ncp;
+ short *nsp;
+ Py_Int32 *nlp;
+- int len, size, x, y, newx, newy;
++ int len, size, x, y, newx, newy, nlen;
+ int ix, iy;
+ int oix, oiy;
+ PyObject *rv;
+@@ -145,12 +151,18 @@
+ PyErr_SetString(ImageopError, "Size should be 1, 2 or 4");
+ return 0;
+ }
+- if ( len != size*x*y ) {
++ if ( ( len != size*x*y ) ||
++ ( size != ((len / x) / y) ) ) {
++ PyErr_SetString(ImageopError, "String has incorrect length");
++ return 0;
++ }
++ nlen = newx*newy*size;
++ if ( size != ((nlen / newx) / newy) ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+ }
+
+- rv = PyString_FromStringAndSize(NULL, newx*newy*size);
++ rv = PyString_FromStringAndSize(NULL, nlen);
+ if ( rv == 0 )
+ return 0;
+ ncp = (char *)PyString_AsString(rv);
+@@ -190,7 +202,8 @@
+ PyErr_SetString(ImageopError, "Size should be 1 or 4");
+ return 0;
+ }
+- if ( maxx*maxy*width != len ) {
++ if ( ( maxx*maxy*width != len ) ||
++ ( maxx != ((len / maxy) / width) ) ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+ }
+@@ -240,7 +253,8 @@
+ if ( !PyArg_ParseTuple(args, "s#iii", &cp, &len, &x, &y, &tres) )
+ return 0;
+
+- if ( x*y != len ) {
++ if ( ( x*y != len ) ||
++ ( x != len / y ) ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+ }
+@@ -281,7 +295,8 @@
+ if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
+ return 0;
+
+- if ( x*y != len ) {
++ if ( ( x*y != len ) ||
++ ( x != len / y ) ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+ }
+@@ -320,7 +335,8 @@
+ if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
+ return 0;
+
+- if ( x*y != len ) {
++ if ( ( x*y != len ) ||
++ ( x != len / y ) ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+ }
+@@ -358,7 +374,8 @@
+ if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
+ return 0;
+
+- if ( x*y != len ) {
++ if ( ( x*y != len ) ||
++ ( x != len / y ) ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+ }
+@@ -404,7 +421,8 @@
+ if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) )
+ return 0;
+
+- if ( x*y != len ) {
++ if ( ( x*y != len ) ||
++ ( x != len / y ) ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+ }
+@@ -443,7 +461,11 @@
+ if ( !PyArg_ParseTuple(args, "s#iiii", &cp, &len, &x, &y, &v0, &v1) )
+ return 0;
+
+- nlen = x*y;
++ nlen = x*y;
++ if ( x != (nlen / y) ) {
++ PyErr_SetString(ImageopError, "String has incorrect length");
++ return 0;
++ }
+ if ( (nlen+7)/8 != len ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+@@ -481,6 +503,10 @@
+ return 0;
+
+ nlen = x*y;
++ if ( x != (nlen / y) ) {
++ PyErr_SetString(ImageopError, "String has incorrect length");
++ return 0;
++ }
+ if ( (nlen+3)/4 != len ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+@@ -517,6 +543,10 @@
+ return 0;
+
+ nlen = x*y;
++ if ( x != (nlen / y) ) {
++ PyErr_SetString(ImageopError, "String has incorrect length");
++ return 0;
++ }
+ if ( (nlen+1)/2 != len ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+@@ -554,6 +584,10 @@
+ return 0;
+
+ nlen = x*y;
++ if ( x != (nlen / y) ) {
++ PyErr_SetString(ImageopError, "String has incorrect length");
++ return 0;
++ }
+ if ( nlen*4 != len ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+@@ -598,6 +632,10 @@
+ return 0;
+
+ nlen = x*y;
++ if ( x != (nlen / y) ) {
++ PyErr_SetString(ImageopError, "String has incorrect length");
++ return 0;
++ }
+ if ( nlen != len ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+@@ -648,6 +686,10 @@
+ return 0;
+
+ nlen = x*y;
++ if ( x != (nlen / y) ) {
++ PyErr_SetString(ImageopError, "String has incorrect length");
++ return 0;
++ }
+ if ( nlen*4 != len ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+@@ -693,6 +735,10 @@
+ return 0;
+
+ nlen = x*y;
++ if ( x != (nlen / y) ) {
++ PyErr_SetString(ImageopError, "String has incorrect length");
++ return 0;
++ }
+ if ( nlen != len ) {
+ PyErr_SetString(ImageopError, "String has incorrect length");
+ return 0;
+Index: python-2.5.2/Modules/rgbimgmodule.c
+===================================================================
+--- python-2.5.2.orig/Modules/rgbimgmodule.c 2008-02-14 08:26:18.000000000 -0300
++++ python-2.5.2/Modules/rgbimgmodule.c 2008-04-07 16:29:10.000000000 -0300
+@@ -299,6 +299,11 @@
+ xsize = image.xsize;
+ ysize = image.ysize;
+ zsize = image.zsize;
++ tablen = xsize * ysize * zsize * sizeof(Py_Int32);
++ if (xsize != (((tablen / ysize) / zsize) / sizeof(Py_Int32))) {
++ PyErr_NoMemory();
++ goto finally;
++ }
+ if (rle) {
+ tablen = ysize * zsize * sizeof(Py_Int32);
+ rlebuflen = (int) (1.05 * xsize +10);
diff --git a/packages/python/python_2.5.2.bb b/packages/python/python_2.5.2.bb
index 3ba35544a8..35bcf858e6 100644
--- a/packages/python/python_2.5.2.bb
+++ b/packages/python/python_2.5.2.bb
@@ -6,19 +6,27 @@ PRIORITY = "optional"
DEPENDS = "python-native db gdbm openssl readline sqlite3 tcl tk zlib"
DEPENDS_sharprom = "python-native db readline zlib gdbm openssl"
# bump this on every change in contrib/python/generate-manifest-2.5.py
-PR = "ml11"
+PR = "ml13"
PYTHON_MAJMIN = "2.5"
-SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.bz2 \
- file://bindir-libdir.patch;patch=1 \
- file://crosscompile.patch;patch=1 \
- file://fix-tkinter-detection.patch;patch=1 \
- file://autohell.patch;patch=1 \
- file://sitebranding.patch;patch=1 \
- file://enable-ctypes-module.patch;patch=1 \
- file://default-is-optimized.patch;patch=1 \
- file://sitecustomize.py"
+SRC_URI = "\
+ http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.bz2 \
+ file://bindir-libdir.patch;patch=1 \
+ file://crosscompile.patch;patch=1 \
+ file://fix-tkinter-detection.patch;patch=1 \
+ file://autohell.patch;patch=1 \
+ file://sitebranding.patch;patch=1 \
+ file://enable-ctypes-module.patch;patch=1 \
+ file://default-is-optimized.patch;patch=1 \
+ \
+ file://05-install.patch;patch=1 \
+ file://06-fix-urllib-exception.patch;patch=1 \
+ file://16-bug1179-imageop.patch;patch=1 \
+ file://13-set-wakeup-fix.patch;patch=1 \
+ \
+ file://sitecustomize.py \
+"
S = "${WORKDIR}/Python-${PV}"
inherit autotools
diff --git a/packages/tasks/task-xfce-base.bb b/packages/tasks/task-xfce-base.bb
index c846b22de5..239725feaa 100644
--- a/packages/tasks/task-xfce-base.bb
+++ b/packages/tasks/task-xfce-base.bb
@@ -4,12 +4,31 @@
DESCRIPTION = "All packages required for an base XFCE installation"
LICENSE = "MIT"
-PR = "r3"
+PR = "r4"
inherit task
-RDEPENDS_${PN} = "xfce-mcs-manager xfwm4 xfwm4-theme-default xfce-utils xfdesktop \
- xfce4-panel xfce4-panel-plugins xfce-mcs-plugins xfwm4-mcs-plugins \
- xfce4-panel-mcs-plugins \
- xfdesktop-mcs-plugins"
+RDEPENDS_${PN} = " \
+ xfce-mcs-manager \
+ xfwm4 \
+ xfwm4-theme-default \
+ xfce-utils \
+ xfdesktop \
+ xfce4-panel \
+ xfce4-panel-plugin-actions \
+ xfce4-panel-plugin-clock \
+ xfce4-panel-plugin-iconbox \
+ xfce4-panel-plugin-launcher \
+ xfce4-panel-plugin-pager \
+ xfce4-panel-plugin-separator \
+ xfce4-panel-plugin-showdesktop \
+ xfce4-panel-plugin-systray \
+ xfce4-panel-plugin-tasklist \
+ xfce4-panel-plugin-windowlist \
+ xfce-mcs-plugins \
+ xfwm4-mcs-plugins \
+ xfce4-panel-mcs-plugins \
+ xfdesktop-mcs-plugins \
+"
+
RRECOMMENDS_${PN} = "xfce-utils-mcs-plugins"
diff --git a/packages/ttf-fonts/ttf-wqy-zenhei_0.6.26.bb b/packages/ttf-fonts/ttf-wqy-zenhei_0.6.26.bb
new file mode 100644
index 0000000000..873179d6a6
--- /dev/null
+++ b/packages/ttf-fonts/ttf-wqy-zenhei_0.6.26.bb
@@ -0,0 +1,19 @@
+require ttf.inc
+
+DESCRIPTION = "WenQuanYi Zen Hei - A Hei-Ti Style Chinese font"
+AUTHOR = "Qianqian Fang and The WenQuanYi Project Contributors"
+HOMEPAGE = "http://wqy.sourceforge.net/en/"
+LICENSE = "GPLv2"
+
+SRC_URI = "${SOURCEFORGE_MIRROR}/wqy/wqy-zenhei-${PV}-0.tar.gz"
+S = "${WORKDIR}/wqy-zenhei"
+
+do_install_append () {
+ install -d ${D}${sysconfdir}/fonts/conf.d/
+ install -m 0644 ${S}/44-wqy-zenhei.conf ${D}${sysconfdir}/fonts/conf.d/
+ install -m 0644 ${S}/66-wqy-zenhei-sharp.conf ${D}${sysconfdir}/fonts/conf.d/
+}
+
+PACKAGES = "${PN}"
+
+FILES_${PN} = "${datadir}/fonts ${sysconfdir}"
diff --git a/packages/unicap/unicap_0.9.3.bb b/packages/unicap/unicap_0.9.3.bb
index c527c80819..dcc0897aa8 100644
--- a/packages/unicap/unicap_0.9.3.bb
+++ b/packages/unicap/unicap_0.9.3.bb
@@ -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.*"
diff --git a/packages/xorg-driver/xf86-video-omapfb_git.bb b/packages/xorg-driver/xf86-video-omapfb_git.bb
index d14c1fd396..9be61695ae 100644
--- a/packages/xorg-driver/xf86-video-omapfb_git.bb
+++ b/packages/xorg-driver/xf86-video-omapfb_git.bb
@@ -2,9 +2,9 @@ require xorg-driver-video.inc
DESCRIPTION = "X.Org X server -- OMAP display driver"
-PR ="r8"
+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
index 0000000000..5e3eb8ee14
--- /dev/null
+++ b/packages/xorg-xserver/xserver-kdrive-1.4.0.90/xorg-1.4-kdrive-rotation.patch
@@ -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;
diff --git a/packages/xorg-xserver/xserver-kdrive_1.4.0.90.bb b/packages/xorg-xserver/xserver-kdrive_1.4.0.90.bb
index 922d8f58f3..48ff0ea6fa 100644
--- a/packages/xorg-xserver/xserver-kdrive_1.4.0.90.bb
+++ b/packages/xorg-xserver/xserver-kdrive_1.4.0.90.bb
@@ -3,7 +3,7 @@ require xserver-kdrive-common.inc
DEPENDS += "hal libxkbfile libxcalibrate pixman"
PE = "1"
-PR = "r2"
+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}"