aboutsummaryrefslogtreecommitdiffstats
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2008-06-27 15:31:36 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2008-06-27 15:31:36 -0700
commitfac3bd7fb0ab462289f9763a71730b4443d71f10 (patch)
tree44c74bfe4f09223a6b28e09c2fd2c433e67b2dce
parentd3d8f7cbd2aa88b680430dfea88dea6bb3a73250 (diff)
downloadpatches-fac3bd7fb0ab462289f9763a71730b4443d71f10.tar.gz
lots of new patches
-rw-r--r--driver-core/always-enable-fw_loader-unless-embedded-y.patch51
-rw-r--r--driver-core/howto-change-email-addresses-of-james-in-howto.patch27
-rw-r--r--driver-core/uio-howto.tmpl-use-standard-copyright-legal-markings.patch64
-rw-r--r--driver-core/uio-howto.tmpl-use-unique-output-names.patch35
-rw-r--r--series25
-rw-r--r--usb.current/sisusbvga-fix-oops-on-disconnect.patch35
-rw-r--r--usb.current/usb-new-device-id-for-ftdi_sio-driver.patch67
-rw-r--r--usb/usb-additional-power-savings-for-cdc-acm-devices-that-support-remote-wakeup.patch367
-rw-r--r--usb/usb-au1xxx-usb-clean-up-ohci-ehci-bus-glue-sources.patch742
-rw-r--r--usb/usb-au1xxx-usb-suspend-resume-support.patch242
-rw-r--r--usb/usb-autosuspend-for-cdc-wdm.patch215
-rw-r--r--usb/usb-debug-port-converter-does-not-accept-more-than-8-byte-packets.patch55
-rw-r--r--usb/usb-fix-disconnect-bug-in-cdc-acm.patch88
-rw-r--r--usb/usb-fix-uninitialized-variable-warning-in-keyspan_pda.patch29
-rw-r--r--usb/usb-fix-usb-serial-pm-counter-decrement-for-disconnected-interfaces.patch38
-rw-r--r--usb/usb-force-unbinding-of-drivers-lacking-reset_resume-or-other-methods.patch319
-rw-r--r--usb/usb-keyspan-remove-duplicate-device-entries.patch47
-rw-r--r--usb/usb-make-pxa27x_udc-less-invasive-on-up2ocr-pxa-register.patch44
-rw-r--r--usb/usb-ohci-pnx4008-i2c-cleanups-and-fixes.patch101
-rw-r--r--usb/usb-r8a66597-hcd-fix-iinterval-for-full-low-speed-device.patch65
-rw-r--r--usb/usb-r8a66597-hcd-fix-interrupt-trigger.patch41
-rw-r--r--usb/usbfs-don-t-store-bad-pointers-in-registration.patch57
-rw-r--r--usb/usbfs-fix-race-between-open-and-unregister.patch70
-rw-r--r--usb/usbfs-send-disconnect-signals-when-device-is-unregistered.patch161
-rw-r--r--usb/usbfs-simplify-the-lookup-by-minor-routines.patch60
25 files changed, 3045 insertions, 0 deletions
diff --git a/driver-core/always-enable-fw_loader-unless-embedded-y.patch b/driver-core/always-enable-fw_loader-unless-embedded-y.patch
new file mode 100644
index 00000000000000..850768771587a9
--- /dev/null
+++ b/driver-core/always-enable-fw_loader-unless-embedded-y.patch
@@ -0,0 +1,51 @@
+From bunk@kernel.org Fri Jun 27 15:13:04 2008
+From: Adrian Bunk <bunk@kernel.org>
+Date: Tue, 10 Jun 2008 19:04:08 +0300
+Subject: always enable FW_LOADER unless EMBEDDED=y
+To: linux-kernel@vger.kernel.org
+Cc: David Woodhouse <dwmw2@infradead.org>, James Bottomley <James.Bottomley@HansenPartnership.com>, Greg KH <greg@kroah.com>, Andrew Morton <akpm@linux-foundation.org>
+Message-ID: <20080610160408.GB11685@cs181133002.pp.htv.fi>
+Content-Disposition: inline
+
+
+James Bottomley recently discovered that we have
+{request,release}_firmware() dummies for the case of the actual
+functions not being available and has a fix for the bug that was
+actually causing build errors for built-in users with
+CONFIG_FW_LOADER=m.
+
+But now missing selects on FW_LOADER are no longer visible at
+compile-time at all and can become runtime problems.
+
+FW_LOADER is infrastructure with relatively small codesize we can safely
+enable for everyone, and only for people who really need small kernels
+(and can be expected to know what they are doing) it matters being able
+to disable it.
+
+This patch therefore always sets FW_LOADER=y and allows users only to
+disable it with EMBEDDED=y.
+
+As a bonus, we can then get rid of all "select FW_LOADER" plus the due
+to it required "depends on HOTPLUG" which removes some complexity from
+our Kconfig files.
+
+Signed-off-by: Adrian Bunk <bunk@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/base/Kconfig | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/base/Kconfig
++++ b/drivers/base/Kconfig
+@@ -27,8 +27,9 @@ config PREVENT_FIRMWARE_BUILD
+ If unsure say Y here.
+
+ config FW_LOADER
+- tristate "Userspace firmware loading support"
++ tristate "Userspace firmware loading support" if EMBEDDED
+ depends on HOTPLUG
++ default y
+ ---help---
+ This option is provided for the case where no in-kernel-tree modules
+ require userspace firmware loading support, but a module built outside
diff --git a/driver-core/howto-change-email-addresses-of-james-in-howto.patch b/driver-core/howto-change-email-addresses-of-james-in-howto.patch
new file mode 100644
index 00000000000000..cda9901bfbc87c
--- /dev/null
+++ b/driver-core/howto-change-email-addresses-of-james-in-howto.patch
@@ -0,0 +1,27 @@
+From tshibata@ab.jp.nec.com Fri Jun 27 14:41:46 2008
+From: Tsugikazu Shibata <tshibata@ab.jp.nec.com>
+Date: Fri, 20 Jun 2008 10:59:52 +0900 (JST)
+Subject: HOWTO: change email addresses of James in HOWTO
+To: greg@kroah.com, James.Bottomley@HansenPartnership.com
+Cc: tshibata@ab.jp.nec.com
+Message-ID: <20080620.105952.95887859.tshibata@ab.jp.nec.com>
+
+
+Signed-off-by: Tsugikazu Shibata <tshibata@ab.jp.nec.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/HOWTO | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/Documentation/HOWTO
++++ b/Documentation/HOWTO
+@@ -358,7 +358,7 @@ Here is a list of some of the different
+ - pcmcia, Dominik Brodowski <linux@dominikbrodowski.net>
+ git.kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git
+
+- - SCSI, James Bottomley <James.Bottomley@SteelEye.com>
++ - SCSI, James Bottomley <James.Bottomley@hansenpartnership.com>
+ git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
+
+ - x86, Ingo Molnar <mingo@elte.hu>
diff --git a/driver-core/uio-howto.tmpl-use-standard-copyright-legal-markings.patch b/driver-core/uio-howto.tmpl-use-standard-copyright-legal-markings.patch
new file mode 100644
index 00000000000000..bb884ef3c91973
--- /dev/null
+++ b/driver-core/uio-howto.tmpl-use-standard-copyright-legal-markings.patch
@@ -0,0 +1,64 @@
+From akpm@linux-foundation.org Fri Jun 27 14:39:54 2008
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 24 Jun 2008 14:24:57 -0700
+Subject: uio-howto.tmpl: use standard copyright/legal markings
+To: mm-commits@vger.kernel.org
+Cc: vapier@gentoo.org, greg@kroah.com, hjk@linutronix.de, randy.dunlap@oracle.com
+Message-ID: <200806242124.m5OLOw69006858@imap1.linux-foundation.org>
+
+
+From: Mike Frysinger <vapier@gentoo.org>
+
+The Userspace I/O HOWTO document uses straight <sect1> tags and plain text
+to describe copyright/legal information. It should instead use the
+<copyright> and <legalnotice> tags like all other documents in the kernel.
+
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Acked-by: Hans J. Koch <hjk@linutronix.de>
+Cc: Randy Dunlap <randy.dunlap@oracle.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/DocBook/uio-howto.tmpl | 23 ++++++++++++-----------
+ 1 file changed, 12 insertions(+), 11 deletions(-)
+
+--- a/Documentation/DocBook/uio-howto.tmpl
++++ b/Documentation/DocBook/uio-howto.tmpl
+@@ -21,6 +21,18 @@
+ </affiliation>
+ </author>
+
++<copyright>
++ <year>2006-2008</year>
++ <holder>Hans-Jürgen Koch.</holder>
++</copyright>
++
++<legalnotice>
++<para>
++This documentation is Free Software licensed under the terms of the
++GPL version 2.
++</para>
++</legalnotice>
++
+ <pubdate>2006-12-11</pubdate>
+
+ <abstract>
+@@ -66,17 +78,6 @@
+ <?dbhtml filename="about.html"?>
+ <title>About this document</title>
+
+-<sect1 id="copyright">
+-<?dbhtml filename="copyright.html"?>
+-<title>Copyright and License</title>
+-<para>
+- Copyright (c) 2006-2008 by Hans-Jürgen Koch.</para>
+-<para>
+-This documentation is Free Software licensed under the terms of the
+-GPL version 2.
+-</para>
+-</sect1>
+-
+ <sect1 id="translations">
+ <?dbhtml filename="translations.html"?>
+ <title>Translations</title>
diff --git a/driver-core/uio-howto.tmpl-use-unique-output-names.patch b/driver-core/uio-howto.tmpl-use-unique-output-names.patch
new file mode 100644
index 00000000000000..6a910dfe2bc9ac
--- /dev/null
+++ b/driver-core/uio-howto.tmpl-use-unique-output-names.patch
@@ -0,0 +1,35 @@
+From akpm@linux-foundation.org Fri Jun 27 14:40:23 2008
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 24 Jun 2008 14:25:00 -0700
+Subject: uio-howto.tmpl: use unique output names
+To: mm-commits@vger.kernel.org
+Cc: vapier@gentoo.org, greg@kroah.com, hjk@linutronix.de, randy.dunlap@oracle.com
+Message-ID: <200806242125.m5OLP26K006869@imap1.linux-foundation.org>
+
+From: Mike Frysinger <vapier@gentoo.org>
+
+The Userspace I/O HOWTO template sets two different sections with the same
+html output name (about.html). This clearly won't work, so change the
+first one to a unique "aboutthis.html" to prevent clobbering.
+
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Acked-by: Hans J. Koch <hjk@linutronix.de>
+Cc: Randy Dunlap <randy.dunlap@oracle.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/DocBook/uio-howto.tmpl | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/Documentation/DocBook/uio-howto.tmpl
++++ b/Documentation/DocBook/uio-howto.tmpl
+@@ -75,7 +75,7 @@ GPL version 2.
+ </bookinfo>
+
+ <chapter id="aboutthisdoc">
+-<?dbhtml filename="about.html"?>
++<?dbhtml filename="aboutthis.html"?>
+ <title>About this document</title>
+
+ <sect1 id="translations">
diff --git a/series b/series
index 7390102017934d..bafb3485dc9fbe 100644
--- a/series
+++ b/series
@@ -23,6 +23,8 @@ usb.current/usb-fix-cdc-acm-resume.patch
usb.current/usb-ehci-fix-timer-regression.patch
usb.current/usb-ohci-record-data-toggle-after-unlink.patch
usb.current/usb-mass-storage-new-id-for-us_sc_cyp_atacb.patch
+usb.current/sisusbvga-fix-oops-on-disconnect.patch
+usb.current/usb-new-device-id-for-ftdi_sio-driver.patch
#####################################################################
# Stuff to be merged after 2.6.26 is out
@@ -101,6 +103,10 @@ driver-core/kobject-reorder-kobject-to-save-space-on-64-bit-builds.patch
driver-core/kobject-should-use-kobject_put-in-kset-example.patch
driver-core/sysdev-fix-debugging-statements-in-registration-code.patch
driver-core/sysfs-don-t-call-notify_change.patch
+driver-core/uio-howto.tmpl-use-standard-copyright-legal-markings.patch
+driver-core/uio-howto.tmpl-use-unique-output-names.patch
+driver-core/always-enable-fw_loader-unless-embedded-y.patch
+driver-core/howto-change-email-addresses-of-james-in-howto.patch
# bus_id fun
driver-core/pci-make-pci_name-use-dev_name.patch
@@ -229,6 +235,24 @@ usb/usb-fix-comment-of-usb_set_configuration.patch
usb/usb-isp1760-support-board-specific-hardware-configurations.patch
usb/usb-usb-serial-fix-a-sparse-warning-about-different-signedness.patch
usb/usb-fix-usb_reset_device-and-usb_reset_composite_device.patch
+usb/usb-r8a66597-hcd-fix-interrupt-trigger.patch
+usb/usb-r8a66597-hcd-fix-iinterval-for-full-low-speed-device.patch
+usb/usb-fix-uninitialized-variable-warning-in-keyspan_pda.patch
+usb/usb-keyspan-remove-duplicate-device-entries.patch
+usb/usb-additional-power-savings-for-cdc-acm-devices-that-support-remote-wakeup.patch
+usb/usb-autosuspend-for-cdc-wdm.patch
+usb/usb-fix-usb-serial-pm-counter-decrement-for-disconnected-interfaces.patch
+usb/usb-fix-disconnect-bug-in-cdc-acm.patch
+usb/usb-debug-port-converter-does-not-accept-more-than-8-byte-packets.patch
+usb/usb-ohci-pnx4008-i2c-cleanups-and-fixes.patch
+usb/usb-make-pxa27x_udc-less-invasive-on-up2ocr-pxa-register.patch
+usb/usb-force-unbinding-of-drivers-lacking-reset_resume-or-other-methods.patch
+usb/usbfs-send-disconnect-signals-when-device-is-unregistered.patch
+usb/usbfs-simplify-the-lookup-by-minor-routines.patch
+usb/usbfs-fix-race-between-open-and-unregister.patch
+usb/usbfs-don-t-store-bad-pointers-in-registration.patch
+usb/usb-au1xxx-usb-clean-up-ohci-ehci-bus-glue-sources.patch
+usb/usb-au1xxx-usb-suspend-resume-support.patch
# wireless usb, still a work in progress
usb/bitmap-add-bitmap_copy_le.patch
@@ -292,3 +316,4 @@ usb/usb-gotemp.patch
#module-usb-serial.patch
#modpost
+
diff --git a/usb.current/sisusbvga-fix-oops-on-disconnect.patch b/usb.current/sisusbvga-fix-oops-on-disconnect.patch
new file mode 100644
index 00000000000000..70633160bb1875
--- /dev/null
+++ b/usb.current/sisusbvga-fix-oops-on-disconnect.patch
@@ -0,0 +1,35 @@
+From will.newton@imgtec.com Fri Jun 27 14:34:47 2008
+From: Will Newton <will.newton@imgtec.com>
+Date: Fri, 27 Jun 2008 13:08:08 +0100
+Subject: sisusbvga: Fix oops on disconnect.
+To: linux-kernel@vger.kernel.org
+Cc: linux-usb@vger.kernel.org, felipe.lima@indt.org.br, gregkh@suse.de, Will Newton <will.newton@gmail.com>
+Message-ID: <1214568488-5356-1-git-send-email-will.newton@imgtec.com>
+
+
+From: Will Newton <will.newton@gmail.com>
+
+Remove dev_info call on disconnect. The sisusb_dev pointer may have been
+set to zero by sisusb_delete at this point causing an oops.
+
+The message does not provide any extra information over the standard USB
+subsystem output so removing it does not affect functionality.
+
+Signed-off-by: Will Newton <will.newton@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/sisusbvga/sisusb.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/usb/misc/sisusbvga/sisusb.c
++++ b/drivers/usb/misc/sisusbvga/sisusb.c
+@@ -3264,8 +3264,6 @@ static void sisusb_disconnect(struct usb
+
+ /* decrement our usage count */
+ kref_put(&sisusb->kref, sisusb_delete);
+-
+- dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
+ }
+
+ static struct usb_device_id sisusb_table [] = {
diff --git a/usb.current/usb-new-device-id-for-ftdi_sio-driver.patch b/usb.current/usb-new-device-id-for-ftdi_sio-driver.patch
new file mode 100644
index 00000000000000..075546fde1e358
--- /dev/null
+++ b/usb.current/usb-new-device-id-for-ftdi_sio-driver.patch
@@ -0,0 +1,67 @@
+From hellan@acm.org Fri Jun 27 15:17:23 2008
+From: Jon K Hellan <hellan@acm.org>
+Date: Tue, 24 Jun 2008 11:43:13 +0200
+Subject: USB: New device ID for ftdi_sio driver
+To: linux-usb@vger.kernel.org
+Message-ID: <4860C1B1.4060001@acm.org>
+
+From: Jon K Hellan <hellan@acm.org>
+
+Here's a new device ID for the ftdio_sio driver.
+The diff is with linus's tree as of this morning.
+
+The device is the RigExpert Tiny USB Soundcard Transceiver Interface for ham
+radio.
+
+(I didn't actually test this. A fellow ham couldn't get the device to work, and
+I suggested binding the device ID using sysfs - see
+"http://jk.ufisa.uninett.no/usb/". However, he had had moved on to other things
+by then. I guess adding the device ID to the kernel "on spec" won't hurt.
+The relevant part of cat /proc/bus/usb/devices shows:
+
+T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
+D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
+P: Vendor=0403 ProdID=ed22 Rev= 5.00
+S: Manufacturer=FTDI
+S: Product=MixW RigExpert Tiny
+S: SerialNumber=00000000
+C:* #Ifs= 2 Cfg#= 1 Atr=80 MxPwr=100mA
+I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
+E: Ad=81(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
+E: Ad=83(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+E: Ad=04(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+)
+
+From: Jon K Hellan <hellan@acm.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/serial/ftdi_sio.c | 1 +
+ drivers/usb/serial/ftdi_sio.h | 3 +++
+ 2 files changed, 4 insertions(+)
+
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -637,6 +637,7 @@ static struct usb_device_id id_table_com
+ { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
++ { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
+ { }, /* Optional parameter entry */
+ { } /* Terminating entry */
+ };
+--- a/drivers/usb/serial/ftdi_sio.h
++++ b/drivers/usb/serial/ftdi_sio.h
+@@ -828,6 +828,9 @@
+ /* Propox devices */
+ #define FTDI_PROPOX_JTAGCABLEII_PID 0xD738
+
++/* Rig Expert Ukraine devices */
++#define FTDI_REU_TINY_PID 0xED22 /* RigExpert Tiny */
++
+ /* Commands */
+ #define FTDI_SIO_RESET 0 /* Reset the port */
+ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
diff --git a/usb/usb-additional-power-savings-for-cdc-acm-devices-that-support-remote-wakeup.patch b/usb/usb-additional-power-savings-for-cdc-acm-devices-that-support-remote-wakeup.patch
new file mode 100644
index 00000000000000..edf68b8c8413d4
--- /dev/null
+++ b/usb/usb-additional-power-savings-for-cdc-acm-devices-that-support-remote-wakeup.patch
@@ -0,0 +1,367 @@
+From oliver@neukum.org Fri Jun 27 14:38:18 2008
+From: Oliver Neukum <oliver@neukum.org>
+Date: Fri, 20 Jun 2008 11:25:57 +0200
+Subject: USB: additional power savings for cdc-acm devices that support remote wakeup
+To: Greg KH <greg@kroah.com>, USB list <linux-usb@vger.kernel.org>
+Message-ID: <200806201125.57479.oliver@neukum.org>
+Content-Disposition: inline
+
+
+this patch saves power for cdc-acm devices that support remote wakeup
+while the device is connected.
+
+- request needs_remote_wakeup when needed
+- delayed write while a device is autoresumed
+- the device is marked busy when appropriate
+
+Signed-off-by: Oliver Neukum <oneukum@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/class/cdc-acm.c | 142 +++++++++++++++++++++++++++++++++++++-------
+ drivers/usb/class/cdc-acm.h | 5 +
+ 2 files changed, 126 insertions(+), 21 deletions(-)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -159,12 +159,34 @@ static void acm_write_done(struct acm *a
+ spin_lock_irqsave(&acm->write_lock, flags);
+ acm->write_ready = 1;
+ wb->use = 0;
++ acm->transmitting--;
+ spin_unlock_irqrestore(&acm->write_lock, flags);
+ }
+
+ /*
+ * Poke write.
++ *
++ * the caller is responsible for locking
+ */
++
++static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
++{
++ int rc;
++
++ acm->transmitting++;
++
++ wb->urb->transfer_buffer = wb->buf;
++ wb->urb->transfer_dma = wb->dmah;
++ wb->urb->transfer_buffer_length = wb->len;
++ wb->urb->dev = acm->dev;
++
++ if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) {
++ dbg("usb_submit_urb(write bulk) failed: %d", rc);
++ acm_write_done(acm, wb);
++ }
++ return rc;
++}
++
+ static int acm_write_start(struct acm *acm, int wbn)
+ {
+ unsigned long flags;
+@@ -182,26 +204,31 @@ static int acm_write_start(struct acm *a
+ return 0; /* A white lie */
+ }
+
++ wb = &acm->wb[wbn];
++ if(acm_wb_is_avail(acm) <= 1)
++ acm->write_ready = 0;
++
++ dbg("%s susp_count: %d", __func__, acm->susp_count);
++ if (acm->susp_count) {
++ acm->old_ready = acm->write_ready;
++ acm->delayed_wb = wb;
++ acm->write_ready = 0;
++ schedule_work(&acm->waker);
++ spin_unlock_irqrestore(&acm->write_lock, flags);
++ return 0; /* A white lie */
++ }
++ usb_mark_last_busy(acm->dev);
++
+ if (!acm_wb_is_used(acm, wbn)) {
+ spin_unlock_irqrestore(&acm->write_lock, flags);
+ return 0;
+ }
+- wb = &acm->wb[wbn];
+
+- if(acm_wb_is_avail(acm) <= 1)
+- acm->write_ready = 0;
++ rc = acm_start_wb(acm, wb);
+ spin_unlock_irqrestore(&acm->write_lock, flags);
+
+- wb->urb->transfer_buffer = wb->buf;
+- wb->urb->transfer_dma = wb->dmah;
+- wb->urb->transfer_buffer_length = wb->len;
+- wb->urb->dev = acm->dev;
+-
+- if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) {
+- dbg("usb_submit_urb(write bulk) failed: %d", rc);
+- acm_write_done(acm, wb);
+- }
+ return rc;
++
+ }
+ /*
+ * attributes exported through sysfs
+@@ -304,6 +331,7 @@ static void acm_ctrl_irq(struct urb *urb
+ break;
+ }
+ exit:
++ usb_mark_last_busy(acm->dev);
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
+ err ("%s - usb_submit_urb failed with result %d",
+@@ -320,8 +348,11 @@ static void acm_read_bulk(struct urb *ur
+
+ dbg("Entering acm_read_bulk with status %d", status);
+
+- if (!ACM_READY(acm))
++ if (!ACM_READY(acm)) {
++ dev_dbg(&acm->data->dev, "Aborting, acm not ready");
+ return;
++ }
++ usb_mark_last_busy(acm->dev);
+
+ if (status)
+ dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
+@@ -331,6 +362,7 @@ static void acm_read_bulk(struct urb *ur
+
+ if (likely(status == 0)) {
+ spin_lock(&acm->read_lock);
++ acm->processing++;
+ list_add_tail(&rcv->list, &acm->spare_read_urbs);
+ list_add_tail(&buf->list, &acm->filled_read_bufs);
+ spin_unlock(&acm->read_lock);
+@@ -343,7 +375,8 @@ static void acm_read_bulk(struct urb *ur
+ /* nevertheless the tasklet must be kicked unconditionally
+ so the queue cannot dry up */
+ }
+- tasklet_schedule(&acm->urb_task);
++ if (likely(!acm->susp_count))
++ tasklet_schedule(&acm->urb_task);
+ }
+
+ static void acm_rx_tasklet(unsigned long _acm)
+@@ -354,16 +387,23 @@ static void acm_rx_tasklet(unsigned long
+ struct acm_ru *rcv;
+ unsigned long flags;
+ unsigned char throttled;
++
+ dbg("Entering acm_rx_tasklet");
+
+ if (!ACM_READY(acm))
++ {
++ dbg("acm_rx_tasklet: ACM not ready");
+ return;
++ }
+
+ spin_lock_irqsave(&acm->throttle_lock, flags);
+ throttled = acm->throttle;
+ spin_unlock_irqrestore(&acm->throttle_lock, flags);
+ if (throttled)
++ {
++ dbg("acm_rx_tasklet: throttled");
+ return;
++ }
+
+ next_buffer:
+ spin_lock_irqsave(&acm->read_lock, flags);
+@@ -403,6 +443,7 @@ urbs:
+ while (!list_empty(&acm->spare_read_bufs)) {
+ spin_lock_irqsave(&acm->read_lock, flags);
+ if (list_empty(&acm->spare_read_urbs)) {
++ acm->processing = 0;
+ spin_unlock_irqrestore(&acm->read_lock, flags);
+ return;
+ }
+@@ -425,18 +466,23 @@ urbs:
+ rcv->urb->transfer_dma = buf->dma;
+ rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+- dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf);
+-
+ /* This shouldn't kill the driver as unsuccessful URBs are returned to the
+ free-urbs-pool and resubmited ASAP */
+- if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
++ spin_lock_irqsave(&acm->read_lock, flags);
++ if (acm->susp_count || usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
+ list_add(&buf->list, &acm->spare_read_bufs);
+- spin_lock_irqsave(&acm->read_lock, flags);
+ list_add(&rcv->list, &acm->spare_read_urbs);
++ acm->processing = 0;
+ spin_unlock_irqrestore(&acm->read_lock, flags);
+ return;
++ } else {
++ spin_unlock_irqrestore(&acm->read_lock, flags);
++ dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf);
+ }
+ }
++ spin_lock_irqsave(&acm->read_lock, flags);
++ acm->processing = 0;
++ spin_unlock_irqrestore(&acm->read_lock, flags);
+ }
+
+ /* data interface wrote those outgoing bytes */
+@@ -463,6 +509,27 @@ static void acm_softint(struct work_stru
+ tty_wakeup(acm->tty);
+ }
+
++static void acm_waker(struct work_struct *waker)
++{
++ struct acm *acm = container_of(waker, struct acm, waker);
++ long flags;
++ int rv;
++
++ rv = usb_autopm_get_interface(acm->control);
++ if (rv < 0) {
++ err("Autopm failure in %s", __func__);
++ return;
++ }
++ if (acm->delayed_wb) {
++ acm_start_wb(acm, acm->delayed_wb);
++ acm->delayed_wb = NULL;
++ }
++ spin_lock_irqsave(&acm->write_lock, flags);
++ acm->write_ready = acm->old_ready;
++ spin_unlock_irqrestore(&acm->write_lock, flags);
++ usb_autopm_put_interface(acm->control);
++}
++
+ /*
+ * TTY handlers
+ */
+@@ -492,6 +559,8 @@ static int acm_tty_open(struct tty_struc
+
+ if (usb_autopm_get_interface(acm->control) < 0)
+ goto early_bail;
++ else
++ acm->control->needs_remote_wakeup = 1;
+
+ mutex_lock(&acm->mutex);
+ if (acm->used++) {
+@@ -509,6 +578,7 @@ static int acm_tty_open(struct tty_struc
+ if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
+ (acm->ctrl_caps & USB_CDC_CAP_LINE))
+ goto full_bailout;
++ usb_autopm_put_interface(acm->control);
+
+ INIT_LIST_HEAD(&acm->spare_read_urbs);
+ INIT_LIST_HEAD(&acm->spare_read_bufs);
+@@ -570,12 +640,14 @@ static void acm_tty_close(struct tty_str
+ mutex_lock(&open_mutex);
+ if (!--acm->used) {
+ if (acm->dev) {
++ usb_autopm_get_interface(acm->control);
+ acm_set_control(acm, acm->ctrlout = 0);
+ usb_kill_urb(acm->ctrlurb);
+ for (i = 0; i < ACM_NW; i++)
+ usb_kill_urb(acm->wb[i].urb);
+ for (i = 0; i < nr; i++)
+ usb_kill_urb(acm->ru[i].urb);
++ acm->control->needs_remote_wakeup = 0;
+ usb_autopm_put_interface(acm->control);
+ } else
+ acm_tty_unregister(acm);
+@@ -987,6 +1059,7 @@ skip_normal_probe:
+ acm->urb_task.func = acm_rx_tasklet;
+ acm->urb_task.data = (unsigned long) acm;
+ INIT_WORK(&acm->work, acm_softint);
++ INIT_WORK(&acm->waker, acm_waker);
+ spin_lock_init(&acm->throttle_lock);
+ spin_lock_init(&acm->write_lock);
+ spin_lock_init(&acm->read_lock);
+@@ -1116,6 +1189,7 @@ alloc_fail:
+ static void stop_data_traffic(struct acm *acm)
+ {
+ int i;
++ dbg("Entering stop_data_traffic");
+
+ tasklet_disable(&acm->urb_task);
+
+@@ -1128,6 +1202,7 @@ static void stop_data_traffic(struct acm
+ tasklet_enable(&acm->urb_task);
+
+ cancel_work_sync(&acm->work);
++ cancel_work_sync(&acm->waker);
+ }
+
+ static void acm_disconnect(struct usb_interface *intf)
+@@ -1181,8 +1256,27 @@ static void acm_disconnect(struct usb_in
+ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
+ {
+ struct acm *acm = usb_get_intfdata(intf);
++ int cnt;
+
+- if (acm->susp_count++)
++ if (acm->dev->auto_pm) {
++ int b;
++
++ spin_lock_irq(&acm->read_lock);
++ spin_lock(&acm->write_lock);
++ b = acm->processing + acm->transmitting;
++ spin_unlock(&acm->write_lock);
++ spin_unlock_irq(&acm->read_lock);
++ if (b)
++ return -EBUSY;
++ }
++
++ spin_lock_irq(&acm->read_lock);
++ spin_lock(&acm->write_lock);
++ cnt = acm->susp_count++;
++ spin_unlock(&acm->write_lock);
++ spin_unlock_irq(&acm->read_lock);
++
++ if (cnt)
+ return 0;
+ /*
+ we treat opened interfaces differently,
+@@ -1201,15 +1295,21 @@ static int acm_resume(struct usb_interfa
+ {
+ struct acm *acm = usb_get_intfdata(intf);
+ int rv = 0;
++ int cnt;
+
+- if (--acm->susp_count)
++ spin_lock_irq(&acm->read_lock);
++ acm->susp_count -= 1;
++ cnt = acm->susp_count;
++ spin_unlock_irq(&acm->read_lock);
++
++ if (cnt)
+ return 0;
+
+ mutex_lock(&acm->mutex);
+ if (acm->used) {
+ rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
+ if (rv < 0)
+- goto err_out;
++ goto err_out;
+
+ tasklet_schedule(&acm->urb_task);
+ }
+--- a/drivers/usb/class/cdc-acm.h
++++ b/drivers/usb/class/cdc-acm.h
+@@ -107,10 +107,14 @@ struct acm {
+ struct list_head filled_read_bufs;
+ int write_used; /* number of non-empty write buffers */
+ int write_ready; /* write urb is not running */
++ int old_ready;
++ int processing;
++ int transmitting;
+ spinlock_t write_lock;
+ struct mutex mutex;
+ struct usb_cdc_line_coding line; /* bits, stop, parity */
+ struct work_struct work; /* work queue entry for line discipline waking up */
++ struct work_struct waker;
+ struct tasklet_struct urb_task; /* rx processing */
+ spinlock_t throttle_lock; /* synchronize throtteling and read callback */
+ unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
+@@ -123,6 +127,7 @@ struct acm {
+ unsigned char clocal; /* termios CLOCAL */
+ unsigned int ctrl_caps; /* control capabilities from the class specific header */
+ unsigned int susp_count; /* number of suspended interfaces */
++ struct acm_wb *delayed_wb; /* write queued for a device about to be woken */
+ };
+
+ #define CDC_DATA_INTERFACE_TYPE 0x0a
diff --git a/usb/usb-au1xxx-usb-clean-up-ohci-ehci-bus-glue-sources.patch b/usb/usb-au1xxx-usb-clean-up-ohci-ehci-bus-glue-sources.patch
new file mode 100644
index 00000000000000..cd4041de667e8a
--- /dev/null
+++ b/usb/usb-au1xxx-usb-clean-up-ohci-ehci-bus-glue-sources.patch
@@ -0,0 +1,742 @@
+From mano@roarinelk.homelinux.net Fri Jun 27 15:16:24 2008
+From: Manuel Lauss <mano@roarinelk.homelinux.net>
+Date: Mon, 23 Jun 2008 09:08:29 +0200
+Subject: USB: Au1xxx-usb: clean up ohci/ehci bus glue sources.
+To: linux-usb@vger.kernel.org
+Message-ID: <20080623070829.GA20861@roarinelk.homelinux.net>
+Content-Disposition: inline
+
+
+From: Manuel Lauss <mano@roarinelk.homelinux.net>
+
+- Fold multiple probe/remove callbacks into one function;
+- minor style fixes, no functional changes.
+
+Tested on Au1200.
+
+Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
+Cc: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ehci-au1xxx.c | 276 ++++++++++++++++-------------------------
+ drivers/usb/host/ohci-au1xxx.c | 268 ++++++++++++++-------------------------
+ 2 files changed, 210 insertions(+), 334 deletions(-)
+
+--- a/drivers/usb/host/ehci-au1xxx.c
++++ b/drivers/usb/host/ehci-au1xxx.c
+@@ -19,236 +19,179 @@
+ #define USB_MCFG_RDCOMB (1<<30)
+ #define USB_MCFG_SSDEN (1<<23)
+ #define USB_MCFG_PHYPLLEN (1<<19)
++#define USB_MCFG_UCECLKEN (1<<18)
+ #define USB_MCFG_EHCCLKEN (1<<17)
++#ifdef CONFIG_DMA_COHERENT
+ #define USB_MCFG_UCAM (1<<7)
++#else
++#define USB_MCFG_UCAM (0)
++#endif
+ #define USB_MCFG_EBMEN (1<<3)
+ #define USB_MCFG_EMEMEN (1<<2)
+
+-#define USBH_ENABLE_CE (USB_MCFG_PHYPLLEN | USB_MCFG_EHCCLKEN)
++#define USBH_ENABLE_CE (USB_MCFG_PHYPLLEN | USB_MCFG_EHCCLKEN)
++#define USBH_ENABLE_INIT (USB_MCFG_PFEN | USB_MCFG_RDCOMB | \
++ USBH_ENABLE_CE | USB_MCFG_SSDEN | \
++ USB_MCFG_UCAM | USB_MCFG_EBMEN | \
++ USB_MCFG_EMEMEN)
+
+-#ifdef CONFIG_DMA_COHERENT
+-#define USBH_ENABLE_INIT (USBH_ENABLE_CE \
+- | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+- | USB_MCFG_SSDEN | USB_MCFG_UCAM \
+- | USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
+-#else
+-#define USBH_ENABLE_INIT (USBH_ENABLE_CE \
+- | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+- | USB_MCFG_SSDEN \
+- | USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
+-#endif
+ #define USBH_DISABLE (USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
+
+ extern int usb_disabled(void);
+
+-/*-------------------------------------------------------------------------*/
+-
+-static void au1xxx_start_ehc(struct platform_device *dev)
++static void au1xxx_start_ehc(void)
+ {
+- pr_debug(__FILE__ ": starting Au1xxx EHCI USB Controller\n");
+-
+- /* write HW defaults again in case Yamon cleared them */
+- if (au_readl(USB_HOST_CONFIG) == 0) {
+- au_writel(0x00d02000, USB_HOST_CONFIG);
+- au_readl(USB_HOST_CONFIG);
+- udelay(1000);
+- }
+- /* enable host controller */
+- au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+- au_readl(USB_HOST_CONFIG);
+- udelay(1000);
+- au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG),
+- USB_HOST_CONFIG);
+- au_readl(USB_HOST_CONFIG);
++ /* enable clock to EHCI block and HS PHY PLL*/
++ au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_CE, USB_HOST_CONFIG);
++ au_sync();
+ udelay(1000);
+
+- pr_debug(__FILE__ ": Clock to USB host has been enabled\n");
++ /* enable EHCI mmio */
++ au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_INIT, USB_HOST_CONFIG);
++ au_sync();
++ udelay(1000);
+ }
+
+-static void au1xxx_stop_ehc(struct platform_device *dev)
++static void au1xxx_stop_ehc(void)
+ {
+- pr_debug(__FILE__ ": stopping Au1xxx EHCI USB Controller\n");
++ unsigned long c;
+
+ /* Disable mem */
+- au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
++ au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_DISABLE, USB_HOST_CONFIG);
++ au_sync();
+ udelay(1000);
+- /* Disable clock */
+- au_writel(~USB_MCFG_EHCCLKEN & au_readl(USB_HOST_CONFIG),
+- USB_HOST_CONFIG);
+- au_readl(USB_HOST_CONFIG);
++
++ /* Disable EHC clock. If the HS PHY is unused disable it too. */
++ c = au_readl(USB_HOST_CONFIG) & ~USB_MCFG_EHCCLKEN;
++ if (!(c & USB_MCFG_UCECLKEN)) /* UDC disabled? */
++ c &= ~USB_MCFG_PHYPLLEN; /* yes: disable HS PHY PLL */
++ au_writel(c, USB_HOST_CONFIG);
++ au_sync();
+ }
+
+-/*-------------------------------------------------------------------------*/
++static const struct hc_driver ehci_au1xxx_hc_driver = {
++ .description = hcd_name,
++ .product_desc = "Au1xxx EHCI",
++ .hcd_priv_size = sizeof(struct ehci_hcd),
++
++ /*
++ * generic hardware linkage
++ */
++ .irq = ehci_irq,
++ .flags = HCD_MEMORY | HCD_USB2,
+
+-/* configure so an HC device and id are always provided */
+-/* always called with process context; sleeping is OK */
++ /*
++ * basic lifecycle operations
++ *
++ * FIXME -- ehci_init() doesn't do enough here.
++ * See ehci-ppc-soc for a complete implementation.
++ */
++ .reset = ehci_init,
++ .start = ehci_run,
++ .stop = ehci_stop,
++ .shutdown = ehci_shutdown,
+
+-/**
+- * usb_ehci_au1xxx_probe - initialize Au1xxx-based HCDs
+- * Context: !in_interrupt()
+- *
+- * Allocates basic resources for this USB host controller, and
+- * then invokes the start() method for the HCD associated with it
+- * through the hotplug entry's driver_data.
+- *
+- */
+-int usb_ehci_au1xxx_probe(const struct hc_driver *driver,
+- struct usb_hcd **hcd_out, struct platform_device *dev)
++ /*
++ * managing i/o requests and associated device resources
++ */
++ .urb_enqueue = ehci_urb_enqueue,
++ .urb_dequeue = ehci_urb_dequeue,
++ .endpoint_disable = ehci_endpoint_disable,
++
++ /*
++ * scheduling support
++ */
++ .get_frame_number = ehci_get_frame,
++
++ /*
++ * root hub support
++ */
++ .hub_status_data = ehci_hub_status_data,
++ .hub_control = ehci_hub_control,
++ .bus_suspend = ehci_bus_suspend,
++ .bus_resume = ehci_bus_resume,
++ .relinquish_port = ehci_relinquish_port,
++ .port_handed_over = ehci_port_handed_over,
++};
++
++static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
+ {
+- int retval;
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
++ int ret;
+
+-#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
++ if (usb_disabled())
++ return -ENODEV;
+
++#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
+ /* Au1200 AB USB does not support coherent memory */
+ if (!(read_c0_prid() & 0xff)) {
+- pr_info("%s: this is chip revision AB!\n", dev->name);
+- pr_info("%s: update your board or re-configure the kernel\n",
+- dev->name);
++ printk(KERN_INFO "%s: this is chip revision AB!\n", pdev->name);
++ printk(KERN_INFO "%s: update your board or re-configure"
++ " the kernel\n", pdev->name);
+ return -ENODEV;
+ }
+ #endif
+
+- au1xxx_start_ehc(dev);
+-
+- if (dev->resource[1].flags != IORESOURCE_IRQ) {
++ if (pdev->resource[1].flags != IORESOURCE_IRQ) {
+ pr_debug("resource[1] is not IORESOURCE_IRQ");
+- retval = -ENOMEM;
++ return -ENOMEM;
+ }
+- hcd = usb_create_hcd(driver, &dev->dev, "Au1xxx");
++ hcd = usb_create_hcd(&ehci_au1xxx_hc_driver, &pdev->dev, "Au1xxx");
+ if (!hcd)
+ return -ENOMEM;
+- hcd->rsrc_start = dev->resource[0].start;
+- hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
++
++ hcd->rsrc_start = pdev->resource[0].start;
++ hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_debug("request_mem_region failed");
+- retval = -EBUSY;
++ ret = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ pr_debug("ioremap failed");
+- retval = -ENOMEM;
++ ret = -ENOMEM;
+ goto err2;
+ }
+
++ au1xxx_start_ehc();
++
+ ehci = hcd_to_ehci(hcd);
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+- /* ehci_hcd_init(hcd_to_ehci(hcd)); */
+-
+- retval =
+- usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED | IRQF_SHARED);
+- if (retval == 0)
+- return retval;
++ ret = usb_add_hcd(hcd, pdev->resource[1].start,
++ IRQF_DISABLED | IRQF_SHARED);
++ if (ret == 0) {
++ platform_set_drvdata(pdev, hcd);
++ return ret;
++ }
+
+- au1xxx_stop_ehc(dev);
++ au1xxx_stop_ehc();
+ iounmap(hcd->regs);
+ err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+ usb_put_hcd(hcd);
+- return retval;
++ return ret;
+ }
+
+-/* may be called without controller electrically present */
+-/* may be called with controller, bus, and devices active */
+-
+-/**
+- * usb_ehci_hcd_au1xxx_remove - shutdown processing for Au1xxx-based HCDs
+- * @dev: USB Host Controller being removed
+- * Context: !in_interrupt()
+- *
+- * Reverses the effect of usb_ehci_hcd_au1xxx_probe(), first invoking
+- * the HCD's stop() method. It is always called from a thread
+- * context, normally "rmmod", "apmd", or something similar.
+- *
+- */
+-void usb_ehci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev)
++static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
+ {
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+- au1xxx_stop_ehc(dev);
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static const struct hc_driver ehci_au1xxx_hc_driver = {
+- .description = hcd_name,
+- .product_desc = "Au1xxx EHCI",
+- .hcd_priv_size = sizeof(struct ehci_hcd),
+-
+- /*
+- * generic hardware linkage
+- */
+- .irq = ehci_irq,
+- .flags = HCD_MEMORY | HCD_USB2,
+-
+- /*
+- * basic lifecycle operations
+- *
+- * FIXME -- ehci_init() doesn't do enough here.
+- * See ehci-ppc-soc for a complete implementation.
+- */
+- .reset = ehci_init,
+- .start = ehci_run,
+- .stop = ehci_stop,
+- .shutdown = ehci_shutdown,
+-
+- /*
+- * managing i/o requests and associated device resources
+- */
+- .urb_enqueue = ehci_urb_enqueue,
+- .urb_dequeue = ehci_urb_dequeue,
+- .endpoint_disable = ehci_endpoint_disable,
+-
+- /*
+- * scheduling support
+- */
+- .get_frame_number = ehci_get_frame,
++ au1xxx_stop_ehc();
++ platform_set_drvdata(pdev, NULL);
+
+- /*
+- * root hub support
+- */
+- .hub_status_data = ehci_hub_status_data,
+- .hub_control = ehci_hub_control,
+- .bus_suspend = ehci_bus_suspend,
+- .bus_resume = ehci_bus_resume,
+- .relinquish_port = ehci_relinquish_port,
+- .port_handed_over = ehci_port_handed_over,
+-};
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
+-{
+- struct usb_hcd *hcd = NULL;
+- int ret;
+-
+- pr_debug("In ehci_hcd_au1xxx_drv_probe\n");
+-
+- if (usb_disabled())
+- return -ENODEV;
+-
+- /* FIXME we only want one one probe() not two */
+- ret = usb_ehci_au1xxx_probe(&ehci_au1xxx_hc_driver, &hcd, pdev);
+- return ret;
+-}
+-
+-static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
+-{
+- struct usb_hcd *hcd = platform_get_drvdata(pdev);
+-
+- /* FIXME we only want one one remove() not two */
+- usb_ehci_au1xxx_remove(hcd, pdev);
+ return 0;
+ }
+
+@@ -268,14 +211,17 @@ static int ehci_hcd_au1xxx_drv_resume(st
+ return 0;
+ }
+ */
+-MODULE_ALIAS("platform:au1xxx-ehci");
++
+ static struct platform_driver ehci_hcd_au1xxx_driver = {
+- .probe = ehci_hcd_au1xxx_drv_probe,
+- .remove = ehci_hcd_au1xxx_drv_remove,
+- .shutdown = usb_hcd_platform_shutdown,
++ .probe = ehci_hcd_au1xxx_drv_probe,
++ .remove = ehci_hcd_au1xxx_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
+ /*.suspend = ehci_hcd_au1xxx_drv_suspend, */
+ /*.resume = ehci_hcd_au1xxx_drv_resume, */
+ .driver = {
+- .name = "au1xxx-ehci",
++ .name = "au1xxx-ehci",
++ .owner = THIS_MODULE,
+ }
+ };
++
++MODULE_ALIAS("platform:au1xxx-ehci");
+--- a/drivers/usb/host/ohci-au1xxx.c
++++ b/drivers/usb/host/ohci-au1xxx.c
+@@ -34,7 +34,8 @@
+ #ifdef __LITTLE_ENDIAN
+ #define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C)
+ #elif __BIG_ENDIAN
+-#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | USBH_ENABLE_BE)
++#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | \
++ USBH_ENABLE_BE)
+ #else
+ #error not byte order defined
+ #endif
+@@ -46,213 +47,87 @@
+ #define USB_MCFG_RDCOMB (1<<30)
+ #define USB_MCFG_SSDEN (1<<23)
+ #define USB_MCFG_OHCCLKEN (1<<16)
++#ifdef CONFIG_DMA_COHERENT
+ #define USB_MCFG_UCAM (1<<7)
++#else
++#define USB_MCFG_UCAM (0)
++#endif
+ #define USB_MCFG_OBMEN (1<<1)
+ #define USB_MCFG_OMEMEN (1<<0)
+
+ #define USBH_ENABLE_CE USB_MCFG_OHCCLKEN
+-#ifdef CONFIG_DMA_COHERENT
+-#define USBH_ENABLE_INIT (USB_MCFG_OHCCLKEN \
+- | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+- | USB_MCFG_SSDEN | USB_MCFG_UCAM \
+- | USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
+-#else
+-#define USBH_ENABLE_INIT (USB_MCFG_OHCCLKEN \
+- | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+- | USB_MCFG_SSDEN \
+- | USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
+-#endif
++
++#define USBH_ENABLE_INIT (USB_MCFG_PFEN | USB_MCFG_RDCOMB | \
++ USBH_ENABLE_CE | USB_MCFG_SSDEN | \
++ USB_MCFG_UCAM | \
++ USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
++
+ #define USBH_DISABLE (USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
+
+ #endif /* Au1200 */
+
+ extern int usb_disabled(void);
+
+-/*-------------------------------------------------------------------------*/
+-
+-static void au1xxx_start_ohc(struct platform_device *dev)
++static void au1xxx_start_ohc(void)
+ {
+- printk(KERN_DEBUG __FILE__
+- ": starting Au1xxx OHCI USB Controller\n");
+-
+ /* enable host controller */
+-
+ #ifndef CONFIG_SOC_AU1200
+-
+ au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
+- udelay(1000);
+- au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG);
++ au_sync();
+ udelay(1000);
+
+-#else /* Au1200 */
+-
+- /* write HW defaults again in case Yamon cleared them */
+- if (au_readl(USB_HOST_CONFIG) == 0) {
+- au_writel(0x00d02000, USB_HOST_CONFIG);
+- au_readl(USB_HOST_CONFIG);
+- udelay(1000);
+- }
+- au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+- au_readl(USB_HOST_CONFIG);
++ au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_INIT, USB_HOST_CONFIG);
++ au_sync();
+ udelay(1000);
+- au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+- au_readl(USB_HOST_CONFIG);
+- udelay(1000);
+-
+-#endif /* Au1200 */
+
+-#ifndef CONFIG_SOC_AU1200
+ /* wait for reset complete (read register twice; see au1500 errata) */
+ while (au_readl(USB_HOST_CONFIG),
+ !(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
+-#endif
+ udelay(1000);
+
+- printk(KERN_DEBUG __FILE__
+- ": Clock to USB host has been enabled \n");
+-}
+-
+-static void au1xxx_stop_ohc(struct platform_device *dev)
+-{
+- printk(KERN_DEBUG __FILE__
+- ": stopping Au1xxx OHCI USB Controller\n");
+-
+-#ifndef CONFIG_SOC_AU1200
+-
+- /* Disable clock */
+- au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
+-
+ #else /* Au1200 */
+-
+- /* Disable mem */
+- au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
++ au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_CE, USB_HOST_CONFIG);
++ au_sync();
+ udelay(1000);
+- /* Disable clock */
+- au_writel(~USBH_ENABLE_CE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+- au_readl(USB_HOST_CONFIG);
++
++ au_writel(au_readl(USB_HOST_CONFIG) | USBH_ENABLE_INIT, USB_HOST_CONFIG);
++ au_sync();
++ udelay(2000);
+ #endif /* Au1200 */
+ }
+
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/* configure so an HC device and id are always provided */
+-/* always called with process context; sleeping is OK */
+-
+-
+-/**
+- * usb_ohci_au1xxx_probe - initialize Au1xxx-based HCDs
+- * Context: !in_interrupt()
+- *
+- * Allocates basic resources for this USB host controller, and
+- * then invokes the start() method for the HCD associated with it
+- * through the hotplug entry's driver_data.
+- *
+- */
+-static int usb_ohci_au1xxx_probe(const struct hc_driver *driver,
+- struct platform_device *dev)
++static void au1xxx_stop_ohc(void)
+ {
+- int retval;
+- struct usb_hcd *hcd;
+-
+-#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
+- /* Au1200 AB USB does not support coherent memory */
+- if (!(read_c0_prid() & 0xff)) {
+- pr_info("%s: this is chip revision AB !!\n",
+- dev->name);
+- pr_info("%s: update your board or re-configure the kernel\n",
+- dev->name);
+- return -ENODEV;
+- }
++#ifdef CONFIG_SOC_AU1200
++ /* Disable mem */
++ au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_DISABLE, USB_HOST_CONFIG);
++ au_sync();
++ udelay(1000);
+ #endif
+-
+- if (dev->resource[1].flags != IORESOURCE_IRQ) {
+- pr_debug("resource[1] is not IORESOURCE_IRQ\n");
+- return -ENOMEM;
+- }
+-
+- hcd = usb_create_hcd(driver, &dev->dev, "au1xxx");
+- if (!hcd)
+- return -ENOMEM;
+- hcd->rsrc_start = dev->resource[0].start;
+- hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+-
+- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+- pr_debug("request_mem_region failed\n");
+- retval = -EBUSY;
+- goto err1;
+- }
+-
+- hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+- if (!hcd->regs) {
+- pr_debug("ioremap failed\n");
+- retval = -ENOMEM;
+- goto err2;
+- }
+-
+- au1xxx_start_ohc(dev);
+- ohci_hcd_init(hcd_to_ohci(hcd));
+-
+- retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED | IRQF_SHARED);
+- if (retval == 0)
+- return retval;
+-
+- au1xxx_stop_ohc(dev);
+- iounmap(hcd->regs);
+- err2:
+- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+- err1:
+- usb_put_hcd(hcd);
+- return retval;
+-}
+-
+-
+-/* may be called without controller electrically present */
+-/* may be called with controller, bus, and devices active */
+-
+-/**
+- * usb_hcd_au1xxx_remove - shutdown processing for Au1xxx-based HCDs
+- * @dev: USB Host Controller being removed
+- * Context: !in_interrupt()
+- *
+- * Reverses the effect of usb_hcd_au1xxx_probe(), first invoking
+- * the HCD's stop() method. It is always called from a thread
+- * context, normally "rmmod", "apmd", or something similar.
+- *
+- */
+-static void usb_ohci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev)
+-{
+- usb_remove_hcd(hcd);
+- au1xxx_stop_ohc(dev);
+- iounmap(hcd->regs);
+- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+- usb_put_hcd(hcd);
++ /* Disable clock */
++ au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
++ au_sync();
+ }
+
+-/*-------------------------------------------------------------------------*/
+-
+-static int __devinit
+-ohci_au1xxx_start (struct usb_hcd *hcd)
++static int __devinit ohci_au1xxx_start(struct usb_hcd *hcd)
+ {
+- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+- int ret;
++ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
++ int ret;
+
+- ohci_dbg (ohci, "ohci_au1xxx_start, ohci:%p", ohci);
++ ohci_dbg(ohci, "ohci_au1xxx_start, ohci:%p", ohci);
+
+- if ((ret = ohci_init (ohci)) < 0)
++ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+- if ((ret = ohci_run (ohci)) < 0) {
++ if ((ret = ohci_run(ohci)) < 0) {
+ err ("can't start %s", hcd->self.bus_name);
+- ohci_stop (hcd);
++ ohci_stop(hcd);
+ return ret;
+ }
+
+ return 0;
+ }
+
+-/*-------------------------------------------------------------------------*/
+-
+ static const struct hc_driver ohci_au1xxx_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Au1xxx OHCI",
+@@ -295,18 +170,66 @@ static const struct hc_driver ohci_au1xx
+ .start_port_reset = ohci_start_port_reset,
+ };
+
+-/*-------------------------------------------------------------------------*/
+-
+ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
+ {
+ int ret;
+-
+- pr_debug ("In ohci_hcd_au1xxx_drv_probe");
++ struct usb_hcd *hcd;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+- ret = usb_ohci_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
++#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
++ /* Au1200 AB USB does not support coherent memory */
++ if (!(read_c0_prid() & 0xff)) {
++ printk(KERN_INFO "%s: this is chip revision AB !!\n",
++ pdev->name);
++ printk(KERN_INFO "%s: update your board or re-configure "
++ "the kernel\n", pdev->name);
++ return -ENODEV;
++ }
++#endif
++
++ if (pdev->resource[1].flags != IORESOURCE_IRQ) {
++ pr_debug("resource[1] is not IORESOURCE_IRQ\n");
++ return -ENOMEM;
++ }
++
++ hcd = usb_create_hcd(&ohci_au1xxx_hc_driver, &pdev->dev, "au1xxx");
++ if (!hcd)
++ return -ENOMEM;
++
++ hcd->rsrc_start = pdev->resource[0].start;
++ hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
++
++ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++ pr_debug("request_mem_region failed\n");
++ ret = -EBUSY;
++ goto err1;
++ }
++
++ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++ if (!hcd->regs) {
++ pr_debug("ioremap failed\n");
++ ret = -ENOMEM;
++ goto err2;
++ }
++
++ au1xxx_start_ohc();
++ ohci_hcd_init(hcd_to_ohci(hcd));
++
++ ret = usb_add_hcd(hcd, pdev->resource[1].start,
++ IRQF_DISABLED | IRQF_SHARED);
++ if (ret == 0) {
++ platform_set_drvdata(pdev, hcd);
++ return ret;
++ }
++
++ au1xxx_stop_ohc();
++ iounmap(hcd->regs);
++err2:
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++err1:
++ usb_put_hcd(hcd);
+ return ret;
+ }
+
+@@ -314,9 +237,16 @@ static int ohci_hcd_au1xxx_drv_remove(st
+ {
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+- usb_ohci_au1xxx_remove(hcd, pdev);
++ usb_remove_hcd(hcd);
++ au1xxx_stop_ohc();
++ iounmap(hcd->regs);
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ usb_put_hcd(hcd);
++ platform_set_drvdata(pdev, NULL);
++
+ return 0;
+ }
++
+ /*TBD*/
+ /*static int ohci_hcd_au1xxx_drv_suspend(struct platform_device *dev)
+ {
diff --git a/usb/usb-au1xxx-usb-suspend-resume-support.patch b/usb/usb-au1xxx-usb-suspend-resume-support.patch
new file mode 100644
index 00000000000000..6a0807d4d0f216
--- /dev/null
+++ b/usb/usb-au1xxx-usb-suspend-resume-support.patch
@@ -0,0 +1,242 @@
+From mano@roarinelk.homelinux.net Fri Jun 27 15:16:57 2008
+From: Manuel Lauss <mano@roarinelk.homelinux.net>
+Date: Mon, 23 Jun 2008 09:09:37 +0200
+Subject: USB: Au1xxx-usb: suspend/resume support.
+To: linux-usb@vger.kernel.org
+Message-ID: <20080623070937.GB20861@roarinelk.homelinux.net>
+Content-Disposition: inline
+
+
+From: Manuel Lauss <mano@roarinelk.homelinux.net>
+
+Copy the OHCI/EHCI PM callbacks of the PCI implementation since
+they work equally well on Au1xxx hardware.
+
+Tested on Au1200.
+
+Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
+Cc: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ehci-au1xxx.c | 115 +++++++++++++++++++++++++++++++++++++----
+ drivers/usb/host/ohci-au1xxx.c | 59 +++++++++++++++++----
+ 2 files changed, 155 insertions(+), 19 deletions(-)
+
+--- a/drivers/usb/host/ehci-au1xxx.c
++++ b/drivers/usb/host/ehci-au1xxx.c
+@@ -195,29 +195,124 @@ static int ehci_hcd_au1xxx_drv_remove(st
+ return 0;
+ }
+
+- /*TBD*/
+-/*static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
++#ifdef CONFIG_PM
++static int ehci_hcd_au1xxx_drv_suspend(struct platform_device *pdev,
++ pm_message_t message)
+ {
+- struct platform_device *pdev = to_platform_device(dev);
+- struct usb_hcd *hcd = dev_get_drvdata(dev);
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ unsigned long flags;
++ int rc;
+
+ return 0;
++ rc = 0;
++
++ if (time_before(jiffies, ehci->next_statechange))
++ msleep(10);
++
++ /* Root hub was already suspended. Disable irq emission and
++ * mark HW unaccessible, bail out if RH has been resumed. Use
++ * the spinlock to properly synchronize with possible pending
++ * RH suspend or resume activity.
++ *
++ * This is still racy as hcd->state is manipulated outside of
++ * any locks =P But that will be a different fix.
++ */
++ spin_lock_irqsave(&ehci->lock, flags);
++ if (hcd->state != HC_STATE_SUSPENDED) {
++ rc = -EINVAL;
++ goto bail;
++ }
++ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
++ (void)ehci_readl(ehci, &ehci->regs->intr_enable);
++
++ /* make sure snapshot being resumed re-enumerates everything */
++ if (message.event == PM_EVENT_PRETHAW) {
++ ehci_halt(ehci);
++ ehci_reset(ehci);
++ }
++
++ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
++
++ au1xxx_stop_ehc();
++
++bail:
++ spin_unlock_irqrestore(&ehci->lock, flags);
++
++ // could save FLADJ in case of Vaux power loss
++ // ... we'd only use it to handle clock skew
++
++ return rc;
+ }
+-static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
++
++
++static int ehci_hcd_au1xxx_drv_resume(struct platform_device *pdev)
+ {
+- struct platform_device *pdev = to_platform_device(dev);
+- struct usb_hcd *hcd = dev_get_drvdata(dev);
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++
++ au1xxx_start_ehc();
++
++ // maybe restore FLADJ
++
++ if (time_before(jiffies, ehci->next_statechange))
++ msleep(100);
++
++ /* Mark hardware accessible again as we are out of D3 state by now */
++ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
++
++ /* If CF is still set, we maintained PCI Vaux power.
++ * Just undo the effect of ehci_pci_suspend().
++ */
++ if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
++ int mask = INTR_MASK;
++
++ if (!hcd->self.root_hub->do_remote_wakeup)
++ mask &= ~STS_PCD;
++ ehci_writel(ehci, mask, &ehci->regs->intr_enable);
++ ehci_readl(ehci, &ehci->regs->intr_enable);
++ return 0;
++ }
++
++ ehci_dbg(ehci, "lost power, restarting\n");
++ usb_root_hub_lost_power(hcd->self.root_hub);
++
++ /* Else reset, to cope with power loss or flush-to-storage
++ * style "resume" having let BIOS kick in during reboot.
++ */
++ (void) ehci_halt(ehci);
++ (void) ehci_reset(ehci);
++
++ /* emptying the schedule aborts any urbs */
++ spin_lock_irq(&ehci->lock);
++ if (ehci->reclaim)
++ end_unlink_async(ehci);
++ ehci_work(ehci);
++ spin_unlock_irq(&ehci->lock);
++
++ ehci_writel(ehci, ehci->command, &ehci->regs->command);
++ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
++ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
++
++ /* here we "know" root ports should always stay powered */
++ ehci_port_power(ehci, 1);
++
++ hcd->state = HC_STATE_SUSPENDED;
+
+ return 0;
+ }
+-*/
++
++#else
++#define ehci_hcd_au1xxx_drv_suspend NULL
++#define ehci_hcd_au1xxx_drv_resume NULL
++#endif
+
+ static struct platform_driver ehci_hcd_au1xxx_driver = {
+ .probe = ehci_hcd_au1xxx_drv_probe,
+ .remove = ehci_hcd_au1xxx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+- /*.suspend = ehci_hcd_au1xxx_drv_suspend, */
+- /*.resume = ehci_hcd_au1xxx_drv_resume, */
++ .suspend = ehci_hcd_au1xxx_drv_suspend,
++ .resume = ehci_hcd_au1xxx_drv_resume,
+ .driver = {
+ .name = "au1xxx-ehci",
+ .owner = THIS_MODULE,
+--- a/drivers/usb/host/ohci-au1xxx.c
++++ b/drivers/usb/host/ohci-au1xxx.c
+@@ -247,27 +247,68 @@ static int ohci_hcd_au1xxx_drv_remove(st
+ return 0;
+ }
+
+- /*TBD*/
+-/*static int ohci_hcd_au1xxx_drv_suspend(struct platform_device *dev)
++#ifdef CONFIG_PM
++static int ohci_hcd_au1xxx_drv_suspend(struct platform_device *pdev,
++ pm_message_t message)
+ {
+- struct usb_hcd *hcd = platform_get_drvdata(dev);
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
++ unsigned long flags;
++ int rc;
+
+- return 0;
++ rc = 0;
++
++ /* Root hub was already suspended. Disable irq emission and
++ * mark HW unaccessible, bail out if RH has been resumed. Use
++ * the spinlock to properly synchronize with possible pending
++ * RH suspend or resume activity.
++ *
++ * This is still racy as hcd->state is manipulated outside of
++ * any locks =P But that will be a different fix.
++ */
++ spin_lock_irqsave(&ohci->lock, flags);
++ if (hcd->state != HC_STATE_SUSPENDED) {
++ rc = -EINVAL;
++ goto bail;
++ }
++ ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
++ (void)ohci_readl(ohci, &ohci->regs->intrdisable);
++
++ /* make sure snapshot being resumed re-enumerates everything */
++ if (message.event == PM_EVENT_PRETHAW)
++ ohci_usb_reset(ohci);
++
++ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
++
++ au1xxx_stop_ohc();
++bail:
++ spin_unlock_irqrestore(&ohci->lock, flags);
++
++ return rc;
+ }
+-static int ohci_hcd_au1xxx_drv_resume(struct platform_device *dev)
++
++static int ohci_hcd_au1xxx_drv_resume(struct platform_device *pdev)
+ {
+- struct usb_hcd *hcd = platform_get_drvdata(dev);
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ au1xxx_start_ohc();
++
++ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
++ ohci_finish_controller_resume(hcd);
+
+ return 0;
+ }
+-*/
++#else
++#define ohci_hcd_au1xxx_drv_suspend NULL
++#define ohci_hcd_au1xxx_drv_resume NULL
++#endif
+
+ static struct platform_driver ohci_hcd_au1xxx_driver = {
+ .probe = ohci_hcd_au1xxx_drv_probe,
+ .remove = ohci_hcd_au1xxx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+- /*.suspend = ohci_hcd_au1xxx_drv_suspend, */
+- /*.resume = ohci_hcd_au1xxx_drv_resume, */
++ .suspend = ohci_hcd_au1xxx_drv_suspend,
++ .resume = ohci_hcd_au1xxx_drv_resume,
+ .driver = {
+ .name = "au1xxx-ohci",
+ .owner = THIS_MODULE,
diff --git a/usb/usb-autosuspend-for-cdc-wdm.patch b/usb/usb-autosuspend-for-cdc-wdm.patch
new file mode 100644
index 00000000000000..7f40dd6459b6fc
--- /dev/null
+++ b/usb/usb-autosuspend-for-cdc-wdm.patch
@@ -0,0 +1,215 @@
+From oliver@neukum.org Fri Jun 27 14:38:34 2008
+From: Oliver Neukum <oliver@neukum.org>
+Date: Tue, 24 Jun 2008 15:56:10 +0200
+Subject: USB: autosuspend for cdc-wdm
+To: Greg KH <greg@kroah.com>, linux-usb@vger.kernel.org
+Message-ID: <200806241556.11242.oliver@neukum.org>
+Content-Disposition: inline
+
+this patch implements
+
+- suspend/resume
+- aggressive autosuspend for the cdc-wdm driver
+- pre/post_reset
+
+Signed-off-by: Oliver Neukum <oneukum@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/class/cdc-wdm.c | 107 +++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 101 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/class/cdc-wdm.c
++++ b/drivers/usb/class/cdc-wdm.c
+@@ -88,6 +88,7 @@ struct wdm_device {
+ dma_addr_t ihandle;
+ struct mutex wlock;
+ struct mutex rlock;
++ struct mutex plock;
+ wait_queue_head_t wait;
+ struct work_struct rxwork;
+ int werr;
+@@ -248,6 +249,7 @@ exit:
+
+ static void kill_urbs(struct wdm_device *desc)
+ {
++ /* the order here is essential */
+ usb_kill_urb(desc->command);
+ usb_kill_urb(desc->validity);
+ usb_kill_urb(desc->response);
+@@ -300,6 +302,9 @@ static ssize_t wdm_write
+ if (r)
+ goto outnl;
+
++ r = usb_autopm_get_interface(desc->intf);
++ if (r < 0)
++ goto outnp;
+ r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
+ &desc->flags));
+ if (r < 0)
+@@ -354,6 +359,8 @@ static ssize_t wdm_write
+ req->wIndex);
+ }
+ out:
++ usb_autopm_put_interface(desc->intf);
++outnp:
+ mutex_unlock(&desc->wlock);
+ outnl:
+ return rv < 0 ? rv : count;
+@@ -378,6 +385,11 @@ retry:
+ rv = wait_event_interruptible(desc->wait,
+ test_bit(WDM_READ, &desc->flags));
+
++ if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
++ rv = -ENODEV;
++ goto err;
++ }
++ usb_mark_last_busy(interface_to_usbdev(desc->intf));
+ if (rv < 0) {
+ rv = -ERESTARTSYS;
+ goto err;
+@@ -485,18 +497,28 @@ static int wdm_open(struct inode *inode,
+ if (test_bit(WDM_DISCONNECTING, &desc->flags))
+ goto out;
+
+- desc->count++;
++ ;
+ file->private_data = desc;
+
+- rv = usb_submit_urb(desc->validity, GFP_KERNEL);
+-
++ rv = usb_autopm_get_interface(desc->intf);
+ if (rv < 0) {
+- desc->count--;
+- err("Error submitting int urb - %d", rv);
++ err("Error autopm - %d", rv);
+ goto out;
+ }
+- rv = 0;
++ intf->needs_remote_wakeup = 1;
+
++ mutex_lock(&desc->plock);
++ if (!desc->count++) {
++ rv = usb_submit_urb(desc->validity, GFP_KERNEL);
++ if (rv < 0) {
++ desc->count--;
++ err("Error submitting int urb - %d", rv);
++ }
++ } else {
++ rv = 0;
++ }
++ mutex_unlock(&desc->plock);
++ usb_autopm_put_interface(desc->intf);
+ out:
+ mutex_unlock(&wdm_mutex);
+ return rv;
+@@ -507,10 +529,15 @@ static int wdm_release(struct inode *ino
+ struct wdm_device *desc = file->private_data;
+
+ mutex_lock(&wdm_mutex);
++ mutex_lock(&desc->plock);
+ desc->count--;
++ mutex_unlock(&desc->plock);
++
+ if (!desc->count) {
+ dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
+ kill_urbs(desc);
++ if (!test_bit(WDM_DISCONNECTING, &desc->flags))
++ desc->intf->needs_remote_wakeup = 0;
+ }
+ mutex_unlock(&wdm_mutex);
+ return 0;
+@@ -602,6 +629,7 @@ next_desc:
+ goto out;
+ mutex_init(&desc->wlock);
+ mutex_init(&desc->rlock);
++ mutex_init(&desc->plock);
+ spin_lock_init(&desc->iuspin);
+ init_waitqueue_head(&desc->wait);
+ desc->wMaxCommand = maxcom;
+@@ -703,6 +731,7 @@ static void wdm_disconnect(struct usb_in
+ spin_lock_irqsave(&desc->iuspin, flags);
+ set_bit(WDM_DISCONNECTING, &desc->flags);
+ set_bit(WDM_READ, &desc->flags);
++ /* to terminate pending flushes */
+ clear_bit(WDM_IN_USE, &desc->flags);
+ spin_unlock_irqrestore(&desc->iuspin, flags);
+ cancel_work_sync(&desc->rxwork);
+@@ -713,11 +742,77 @@ static void wdm_disconnect(struct usb_in
+ mutex_unlock(&wdm_mutex);
+ }
+
++static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
++{
++ struct wdm_device *desc = usb_get_intfdata(intf);
++ int rv = 0;
++
++ dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
++
++ mutex_lock(&desc->plock);
++ if (interface_to_usbdev(desc->intf)->auto_pm && test_bit(WDM_IN_USE, &desc->flags)) {
++ rv = -EBUSY;
++ } else {
++ cancel_work_sync(&desc->rxwork);
++ kill_urbs(desc);
++ }
++ mutex_unlock(&desc->plock);
++
++ return rv;
++}
++
++static int recover_from_urb_loss(struct wdm_device *desc)
++{
++ int rv = 0;
++
++ if (desc->count) {
++ rv = usb_submit_urb(desc->validity, GFP_NOIO);
++ if (rv < 0)
++ err("Error resume submitting int urb - %d", rv);
++ }
++ return rv;
++}
++static int wdm_resume(struct usb_interface *intf)
++{
++ struct wdm_device *desc = usb_get_intfdata(intf);
++ int rv;
++
++ dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor);
++ mutex_lock(&desc->plock);
++ rv = recover_from_urb_loss(desc);
++ mutex_unlock(&desc->plock);
++ return rv;
++}
++
++static int wdm_pre_reset(struct usb_interface *intf)
++{
++ struct wdm_device *desc = usb_get_intfdata(intf);
++
++ mutex_lock(&desc->plock);
++ return 0;
++}
++
++static int wdm_post_reset(struct usb_interface *intf)
++{
++ struct wdm_device *desc = usb_get_intfdata(intf);
++ int rv;
++
++ rv = recover_from_urb_loss(desc);
++ mutex_unlock(&desc->plock);
++ return 0;
++}
++
+ static struct usb_driver wdm_driver = {
+ .name = "cdc_wdm",
+ .probe = wdm_probe,
+ .disconnect = wdm_disconnect,
++ .suspend = wdm_suspend,
++ .resume = wdm_resume,
++ .reset_resume = wdm_resume,
++ .pre_reset = wdm_pre_reset,
++ .post_reset = wdm_post_reset,
+ .id_table = wdm_ids,
++ .supports_autosuspend = 1,
+ };
+
+ /* --- low level module stuff --- */
diff --git a/usb/usb-debug-port-converter-does-not-accept-more-than-8-byte-packets.patch b/usb/usb-debug-port-converter-does-not-accept-more-than-8-byte-packets.patch
new file mode 100644
index 00000000000000..d9363e925826f6
--- /dev/null
+++ b/usb/usb-debug-port-converter-does-not-accept-more-than-8-byte-packets.patch
@@ -0,0 +1,55 @@
+From dared1st@yahoo.com Fri Jun 27 14:42:45 2008
+From: Aleksey Gorelov <dared1st@yahoo.com>
+Date: Thu, 19 Jun 2008 15:22:17 -0700 (PDT)
+Subject: USB: debug port converter does not accept more than 8 byte packets
+To: linux-usb-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org
+Cc: greg@kroah.com
+Message-ID: <911755.27146.qm@web83307.mail.sp1.yahoo.com>
+
+
+USB debug port only supports 8 byte rx/tx packets. Although spec implies that
+"if a packet larger than eight bytes is received from the remote computer, the
+device must break the larger packet into eight-byte packets before sending the
+data to the Debug Port", the real PLX NET20DC device does not handle it right -
+data is corrupted on debug port end if serial interface sends >8 byte urbs.
+Patch below fixes the issue by limiting tx urb to 8 byte.
+
+Signed off by: Aleks Gorelov <dared1st@yahoo.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/usb_debug.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/usb/serial/usb_debug.c
++++ b/drivers/usb/serial/usb_debug.c
+@@ -15,6 +15,8 @@
+ #include <linux/usb.h>
+ #include <linux/usb/serial.h>
+
++#define USB_DEBUG_MAX_PACKET_SIZE 8
++
+ static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x0525, 0x127a) },
+ { },
+@@ -29,6 +31,12 @@ static struct usb_driver debug_driver =
+ .no_dynamic_id = 1,
+ };
+
++int usb_debug_open(struct usb_serial_port *port, struct file *filp)
++{
++ port->bulk_out_size = USB_DEBUG_MAX_PACKET_SIZE;
++ return usb_serial_generic_open(port, filp);
++}
++
+ static struct usb_serial_driver debug_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+@@ -36,6 +44,7 @@ static struct usb_serial_driver debug_de
+ },
+ .id_table = id_table,
+ .num_ports = 1,
++ .open = usb_debug_open,
+ };
+
+ static int __init debug_init(void)
diff --git a/usb/usb-fix-disconnect-bug-in-cdc-acm.patch b/usb/usb-fix-disconnect-bug-in-cdc-acm.patch
new file mode 100644
index 00000000000000..20cb2aea26c74c
--- /dev/null
+++ b/usb/usb-fix-disconnect-bug-in-cdc-acm.patch
@@ -0,0 +1,88 @@
+From oliver@neukum.org Fri Jun 27 14:39:17 2008
+From: Oliver Neukum <oliver@neukum.org>
+Date: Wed, 25 Jun 2008 14:17:16 +0200
+Subject: USB: fix disconnect bug in cdc-acm
+To: Greg KH <greg@kroah.com>, linux-usb@vger.kernel.org
+Message-ID: <200806251417.17070.oliver@neukum.org>
+Content-Disposition: inline
+
+
+cdc-acm must give up secondary interfaces if the primary is disconnected
+and vice versa. This wasn't done correctly.
+
+Signed-off-by: Oliver Neukum <oneukum@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/class/cdc-acm.c | 28 +++++++++++++++-------------
+ 1 file changed, 15 insertions(+), 13 deletions(-)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -838,7 +838,7 @@ static void acm_tty_set_termios(struct t
+ * USB probe and disconnect routines.
+ */
+
+-/* Little helper: write buffers free */
++/* Little helpers: write/read buffers free */
+ static void acm_write_buffers_free(struct acm *acm)
+ {
+ int i;
+@@ -849,6 +849,15 @@ static void acm_write_buffers_free(struc
+ }
+ }
+
++static void acm_read_buffers_free(struct acm *acm)
++{
++ struct usb_device *usb_dev = interface_to_usbdev(acm->control);
++ int i, n = acm->rx_buflimit;
++
++ for (i = 0; i < n; i++)
++ usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
++}
++
+ /* Little helper: write buffers allocate */
+ static int acm_write_buffers_alloc(struct acm *acm)
+ {
+@@ -1171,8 +1180,7 @@ alloc_fail8:
+ for (i = 0; i < ACM_NW; i++)
+ usb_free_urb(acm->wb[i].urb);
+ alloc_fail7:
+- for (i = 0; i < num_rx_buf; i++)
+- usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
++ acm_read_buffers_free(acm);
+ for (i = 0; i < num_rx_buf; i++)
+ usb_free_urb(acm->ru[i].urb);
+ usb_free_urb(acm->ctrlurb);
+@@ -1209,15 +1217,9 @@ static void acm_disconnect(struct usb_in
+ {
+ struct acm *acm = usb_get_intfdata(intf);
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+- int i;
+-
+- if (!acm || !acm->dev) {
+- dbg("disconnect on nonexisting interface");
+- return;
+- }
+
+ mutex_lock(&open_mutex);
+- if (!usb_get_intfdata(intf)) {
++ if (!acm || !acm->dev) {
+ mutex_unlock(&open_mutex);
+ return;
+ }
+@@ -1236,10 +1238,10 @@ static void acm_disconnect(struct usb_in
+
+ acm_write_buffers_free(acm);
+ usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
+- for (i = 0; i < acm->rx_buflimit; i++)
+- usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
++ acm_read_buffers_free(acm);
+
+- usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf);
++ usb_driver_release_interface(&acm_driver, intf == acm->control ?
++ acm->data : acm->control);
+
+ if (!acm->used) {
+ acm_tty_unregister(acm);
diff --git a/usb/usb-fix-uninitialized-variable-warning-in-keyspan_pda.patch b/usb/usb-fix-uninitialized-variable-warning-in-keyspan_pda.patch
new file mode 100644
index 00000000000000..c738d0cb9cd9b2
--- /dev/null
+++ b/usb/usb-fix-uninitialized-variable-warning-in-keyspan_pda.patch
@@ -0,0 +1,29 @@
+From bhalevy@panasas.com Fri Jun 27 14:35:37 2008
+From: Benny Halevy <bhalevy@panasas.com>
+Date: Fri, 27 Jun 2008 12:22:32 +0300
+Subject: usb: fix uninitialized variable warning in keyspan_pda
+To: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Greg KH <greg@kroah.com>, linux-kernel@vger.kernel.org
+Message-ID: <4864B158.6080301@panasas.com>
+
+From: Benny Halevy <bhalevy@panasas.com>
+
+This fixes the compiler warning.
+
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/keyspan_pda.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/keyspan_pda.c
++++ b/drivers/usb/serial/keyspan_pda.c
+@@ -420,7 +420,7 @@ static int keyspan_pda_get_modem_info(st
+ 3, /* get pins */
+ USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
+ 0, 0, &data, 1, 2000);
+- if (rc > 0)
++ if (rc >= 0)
+ *value = data;
+ return rc;
+ }
diff --git a/usb/usb-fix-usb-serial-pm-counter-decrement-for-disconnected-interfaces.patch b/usb/usb-fix-usb-serial-pm-counter-decrement-for-disconnected-interfaces.patch
new file mode 100644
index 00000000000000..fa409c21807a4d
--- /dev/null
+++ b/usb/usb-fix-usb-serial-pm-counter-decrement-for-disconnected-interfaces.patch
@@ -0,0 +1,38 @@
+From oliver@neukum.org Fri Jun 27 14:38:53 2008
+From: Oliver Neukum <oliver@neukum.org>
+Date: Wed, 25 Jun 2008 13:32:49 +0200
+Subject: USB: fix usb serial pm counter decrement for disconnected interfaces
+To: Greg KH <greg@kroah.com>, linux-usb@vger.kernel.org
+Message-ID: <200806251332.49797.oliver@neukum.org>
+Content-Disposition: inline
+
+
+usb serial decrements the pm counter even if an interface has been
+disconnected. If it was a logical disconnect the interface may belong
+already to another driver. This patch introduces a check for disconnected
+interfaces.
+
+Signed-off-by: Oliver Neukum <oneukum@suse.de>
+Cc: Stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+
+---
+ drivers/usb/serial/usb-serial.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -283,7 +283,10 @@ static void serial_close(struct tty_stru
+ }
+
+ if (port->open_count == 0) {
+- usb_autopm_put_interface(port->serial->interface);
++ mutex_lock(&port->serial->disc_mutex);
++ if (!port->serial->disconnected)
++ usb_autopm_put_interface(port->serial->interface);
++ mutex_unlock(&port->serial->disc_mutex);
+ module_put(port->serial->type->driver.owner);
+ }
+
diff --git a/usb/usb-force-unbinding-of-drivers-lacking-reset_resume-or-other-methods.patch b/usb/usb-force-unbinding-of-drivers-lacking-reset_resume-or-other-methods.patch
new file mode 100644
index 00000000000000..da6aff2866ff38
--- /dev/null
+++ b/usb/usb-force-unbinding-of-drivers-lacking-reset_resume-or-other-methods.patch
@@ -0,0 +1,319 @@
+From stern@rowland.harvard.edu Fri Jun 27 15:14:03 2008
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Mon, 23 Jun 2008 16:00:40 -0400 (EDT)
+Subject: USB: Force unbinding of drivers lacking reset_resume or other methods
+To: Greg KH <greg@kroah.com>
+Cc: USB list <linux-usb@vger.kernel.org>
+Message-ID: <Pine.LNX.4.44L0.0806231558370.30973-100000@iolanthe.rowland.org>
+
+
+This patch (as1024) takes care of a FIXME issue: Drivers that don't
+have the necessary suspend, resume, reset_resume, pre_reset, or
+post_reset methods will be unbound and their interface reprobed when
+one of the unsupported events occurs.
+
+This is made slightly more difficult by the fact that bind operations
+won't work during a system sleep transition. So instead the code has
+to defer the operation until the transition ends.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/driver.c | 131 ++++++++++++++++++++++++++++++++++++++++------
+ drivers/usb/core/hub.c | 27 +++++++--
+ drivers/usb/core/usb.h | 2
+ include/linux/usb.h | 1
+ 4 files changed, 140 insertions(+), 21 deletions(-)
+
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -201,6 +201,7 @@ static int usb_probe_interface(struct de
+
+ intf = to_usb_interface(dev);
+ udev = interface_to_usbdev(intf);
++ intf->needs_binding = 0;
+
+ if (udev->authorized == 0) {
+ dev_err(&intf->dev, "Device is not authorized for usage\n");
+@@ -311,6 +312,7 @@ int usb_driver_claim_interface(struct us
+
+ dev->driver = &driver->drvwrap.driver;
+ usb_set_intfdata(iface, priv);
++ iface->needs_binding = 0;
+
+ usb_pm_lock(udev);
+ iface->condition = USB_INTERFACE_BOUND;
+@@ -772,6 +774,104 @@ void usb_deregister(struct usb_driver *d
+ }
+ EXPORT_SYMBOL_GPL(usb_deregister);
+
++
++/* Forced unbinding of a USB interface driver, either because
++ * it doesn't support pre_reset/post_reset/reset_resume or
++ * because it doesn't support suspend/resume.
++ *
++ * The caller must hold @intf's device's lock, but not its pm_mutex
++ * and not @intf->dev.sem.
++ */
++void usb_forced_unbind_intf(struct usb_interface *intf)
++{
++ struct usb_driver *driver = to_usb_driver(intf->dev.driver);
++
++ dev_dbg(&intf->dev, "forced unbind\n");
++ usb_driver_release_interface(driver, intf);
++
++ /* Mark the interface for later rebinding */
++ intf->needs_binding = 1;
++}
++
++/* Delayed forced unbinding of a USB interface driver and scan
++ * for rebinding.
++ *
++ * The caller must hold @intf's device's lock, but not its pm_mutex
++ * and not @intf->dev.sem.
++ *
++ * FIXME: The caller must block system sleep transitions.
++ */
++void usb_rebind_intf(struct usb_interface *intf)
++{
++ int rc;
++
++ /* Delayed unbind of an existing driver */
++ if (intf->dev.driver) {
++ struct usb_driver *driver =
++ to_usb_driver(intf->dev.driver);
++
++ dev_dbg(&intf->dev, "forced unbind\n");
++ usb_driver_release_interface(driver, intf);
++ }
++
++ /* Try to rebind the interface */
++ intf->needs_binding = 0;
++ rc = device_attach(&intf->dev);
++ if (rc < 0)
++ dev_warn(&intf->dev, "rebind failed: %d\n", rc);
++}
++
++#define DO_UNBIND 0
++#define DO_REBIND 1
++
++/* Unbind drivers for @udev's interfaces that don't support suspend/resume,
++ * or rebind interfaces that have been unbound, according to @action.
++ *
++ * The caller must hold @udev's device lock.
++ * FIXME: For rebinds, the caller must block system sleep transitions.
++ */
++static void do_unbind_rebind(struct usb_device *udev, int action)
++{
++ struct usb_host_config *config;
++ int i;
++ struct usb_interface *intf;
++ struct usb_driver *drv;
++
++ config = udev->actconfig;
++ if (config) {
++ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
++ intf = config->interface[i];
++ switch (action) {
++ case DO_UNBIND:
++ if (intf->dev.driver) {
++ drv = to_usb_driver(intf->dev.driver);
++ if (!drv->suspend || !drv->resume)
++ usb_forced_unbind_intf(intf);
++ }
++ break;
++ case DO_REBIND:
++ if (intf->needs_binding) {
++
++ /* FIXME: The next line is needed because we are going to probe
++ * the interface, but as far as the PM core is concerned the
++ * interface is still suspended. The problem wouldn't exist
++ * if we could rebind the interface during the interface's own
++ * resume() call, but at the time the usb_device isn't locked!
++ *
++ * The real solution will be to carry this out during the device's
++ * complete() callback. Until that is implemented, we have to
++ * use this hack.
++ */
++ intf->dev.power.sleeping = 0;
++
++ usb_rebind_intf(intf);
++ }
++ break;
++ }
++ }
++ }
++}
++
+ #ifdef CONFIG_PM
+
+ /* Caller has locked udev's pm_mutex */
+@@ -841,7 +941,7 @@ static int usb_suspend_interface(struct
+ goto done;
+ driver = to_usb_driver(intf->dev.driver);
+
+- if (driver->suspend && driver->resume) {
++ if (driver->suspend) {
+ status = driver->suspend(intf, msg);
+ if (status == 0)
+ mark_quiesced(intf);
+@@ -849,12 +949,10 @@ static int usb_suspend_interface(struct
+ dev_err(&intf->dev, "%s error %d\n",
+ "suspend", status);
+ } else {
+- /*
+- * FIXME else if there's no suspend method, disconnect...
+- * Not possible if auto_pm is set...
+- */
+- dev_warn(&intf->dev, "no suspend for driver %s?\n",
+- driver->name);
++ /* Later we will unbind the driver and reprobe */
++ intf->needs_binding = 1;
++ dev_warn(&intf->dev, "no %s for driver %s?\n",
++ "suspend", driver->name);
+ mark_quiesced(intf);
+ }
+
+@@ -878,10 +976,12 @@ static int usb_resume_interface(struct u
+ goto done;
+
+ /* Can't resume it if it doesn't have a driver. */
+- if (intf->condition == USB_INTERFACE_UNBOUND) {
+- status = -ENOTCONN;
++ if (intf->condition == USB_INTERFACE_UNBOUND)
++ goto done;
++
++ /* Don't resume if the interface is marked for rebinding */
++ if (intf->needs_binding)
+ goto done;
+- }
+ driver = to_usb_driver(intf->dev.driver);
+
+ if (reset_resume) {
+@@ -891,7 +991,7 @@ static int usb_resume_interface(struct u
+ dev_err(&intf->dev, "%s error %d\n",
+ "reset_resume", status);
+ } else {
+- /* status = -EOPNOTSUPP; */
++ intf->needs_binding = 1;
+ dev_warn(&intf->dev, "no %s for driver %s?\n",
+ "reset_resume", driver->name);
+ }
+@@ -902,7 +1002,7 @@ static int usb_resume_interface(struct u
+ dev_err(&intf->dev, "%s error %d\n",
+ "resume", status);
+ } else {
+- /* status = -EOPNOTSUPP; */
++ intf->needs_binding = 1;
+ dev_warn(&intf->dev, "no %s for driver %s?\n",
+ "resume", driver->name);
+ }
+@@ -910,11 +1010,10 @@ static int usb_resume_interface(struct u
+
+ done:
+ dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
+- if (status == 0)
++ if (status == 0 && intf->condition == USB_INTERFACE_BOUND)
+ mark_active(intf);
+
+- /* FIXME: Unbind the driver and reprobe if the resume failed
+- * (not possible if auto_pm is set) */
++ /* Later we will unbind the driver and/or reprobe, if necessary */
+ return status;
+ }
+
+@@ -1470,6 +1569,7 @@ int usb_external_suspend_device(struct u
+ {
+ int status;
+
++ do_unbind_rebind(udev, DO_UNBIND);
+ usb_pm_lock(udev);
+ udev->auto_pm = 0;
+ status = usb_suspend_both(udev, msg);
+@@ -1497,6 +1597,7 @@ int usb_external_resume_device(struct us
+ status = usb_resume_both(udev);
+ udev->last_busy = jiffies;
+ usb_pm_unlock(udev);
++ do_unbind_rebind(udev, DO_REBIND);
+
+ /* Now that the device is awake, we can start trying to autosuspend
+ * it again. */
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -3357,6 +3357,11 @@ re_enumerate:
+ * this from a driver probe() routine after downloading new firmware.
+ * For calls that might not occur during probe(), drivers should lock
+ * the device using usb_lock_device_for_reset().
++ *
++ * If an interface is currently being probed or disconnected, we assume
++ * its driver knows how to handle resets. For all other interfaces,
++ * if the driver doesn't have pre_reset and post_reset methods then
++ * we attempt to unbind it and rebind afterward.
+ */
+ int usb_reset_device(struct usb_device *udev)
+ {
+@@ -3378,12 +3383,17 @@ int usb_reset_device(struct usb_device *
+ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+ struct usb_interface *cintf = config->interface[i];
+ struct usb_driver *drv;
++ int unbind = 0;
+
+ if (cintf->dev.driver) {
+ drv = to_usb_driver(cintf->dev.driver);
+- if (drv->pre_reset)
+- (drv->pre_reset)(cintf);
+- /* FIXME: Unbind if pre_reset returns an error or isn't defined */
++ if (drv->pre_reset && drv->post_reset)
++ unbind = (drv->pre_reset)(cintf);
++ else if (cintf->condition ==
++ USB_INTERFACE_BOUND)
++ unbind = 1;
++ if (unbind)
++ usb_forced_unbind_intf(cintf);
+ }
+ }
+ }
+@@ -3394,13 +3404,18 @@ int usb_reset_device(struct usb_device *
+ for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) {
+ struct usb_interface *cintf = config->interface[i];
+ struct usb_driver *drv;
++ int rebind = cintf->needs_binding;
+
+- if (cintf->dev.driver) {
++ if (!rebind && cintf->dev.driver) {
+ drv = to_usb_driver(cintf->dev.driver);
+ if (drv->post_reset)
+- (drv->post_reset)(cintf);
+- /* FIXME: Unbind if post_reset returns an error or isn't defined */
++ rebind = (drv->post_reset)(cintf);
++ else if (cintf->condition ==
++ USB_INTERFACE_BOUND)
++ rebind = 1;
+ }
++ if (rebind)
++ usb_rebind_intf(cintf);
+ }
+ }
+
+--- a/drivers/usb/core/usb.h
++++ b/drivers/usb/core/usb.h
+@@ -29,6 +29,8 @@ extern int usb_choose_configuration(stru
+ extern void usb_kick_khubd(struct usb_device *dev);
+ extern int usb_match_device(struct usb_device *dev,
+ const struct usb_device_id *id);
++extern void usb_forced_unbind_intf(struct usb_interface *intf);
++extern void usb_rebind_intf(struct usb_interface *intf);
+
+ extern int usb_hub_init(void);
+ extern void usb_hub_cleanup(void);
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -160,6 +160,7 @@ struct usb_interface {
+ unsigned is_active:1; /* the interface is not suspended */
+ unsigned sysfs_files_created:1; /* the sysfs attributes exist */
+ unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
++ unsigned needs_binding:1; /* needs delayed unbind/rebind */
+
+ struct device dev; /* interface specific device info */
+ struct device *usb_dev;
diff --git a/usb/usb-keyspan-remove-duplicate-device-entries.patch b/usb/usb-keyspan-remove-duplicate-device-entries.patch
new file mode 100644
index 00000000000000..fe57697bb15ecc
--- /dev/null
+++ b/usb/usb-keyspan-remove-duplicate-device-entries.patch
@@ -0,0 +1,47 @@
+From ben.collins@canonical.com Fri Jun 27 14:37:22 2008
+From: Ben Collins <ben.collins@canonical.com>
+Date: Thu, 26 Jun 2008 20:08:16 -0400
+Subject: USB: keyspan: Remove duplicate device entries
+To: gregkh <gregkh@suse.de>
+Message-ID: <1214525296.7150.120.camel@cunning>
+
+
+The 28xb, as documented in comments, has the same ID's as the 28x.
+Remove the duplicated ID's from the device tables, and expand the
+comment to document this.
+
+Signed-off-by: Ben Collins <ben.collins@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/keyspan.h | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/serial/keyspan.h
++++ b/drivers/usb/serial/keyspan.h
+@@ -222,7 +222,8 @@ struct ezusb_hex_record {
+
+ /* Product IDs post-renumeration. Note that the 28x and 28xb
+ have the same id's post-renumeration but behave identically
+- so it's not an issue. */
++ so it's not an issue. As such, the 28xb is not listed in any
++ of the device tables. */
+ #define keyspan_usa18x_product_id 0x0112
+ #define keyspan_usa19_product_id 0x0107
+ #define keyspan_usa19qi_product_id 0x010c
+@@ -566,7 +567,6 @@ static struct usb_device_id keyspan_ids_
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
+- { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
+@@ -616,7 +616,6 @@ static struct usb_device_id keyspan_2por
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
+- { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) },
+ { } /* Terminating entry */
+ };
diff --git a/usb/usb-make-pxa27x_udc-less-invasive-on-up2ocr-pxa-register.patch b/usb/usb-make-pxa27x_udc-less-invasive-on-up2ocr-pxa-register.patch
new file mode 100644
index 00000000000000..38f1407c819ddd
--- /dev/null
+++ b/usb/usb-make-pxa27x_udc-less-invasive-on-up2ocr-pxa-register.patch
@@ -0,0 +1,44 @@
+From david-b@pacbell.net Fri Jun 27 15:12:21 2008
+From: Robert Jarzmik <rjarzmik@free.fr>
+Date: Tue, 10 Jun 2008 15:01:15 -0700
+Subject: USB: Make pxa27x_udc less invasive on UP2OCR pxa register.
+To: Robert Jarzmik <rjarzmik@free.fr>
+Cc: linux-usb@vger.kernel.org
+Message-ID: <200806101501.15282.david-b@pacbell.net>
+Content-Disposition: inline
+
+From: Robert Jarzmik <rjarzmik@free.fr>
+
+UP2OCR registers sets up usb client function, as well as
+other board specific setups (resistors pullups and
+pulldowns). Let the driver setup the "non-OTG client" part,
+and let all other bits as they were set by board code.
+
+Signed-off-by: Robert Jarzmik <rjarzmik@free.fr>
+Acked-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/pxa27x_udc.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/gadget/pxa27x_udc.c
++++ b/drivers/usb/gadget/pxa27x_udc.c
+@@ -1573,9 +1573,16 @@ static __init void udc_init_data(struct
+ */
+ static void udc_enable(struct pxa_udc *udc)
+ {
++ u32 up2ocr;
++
+ udc_writel(udc, UDCICR0, 0);
+ udc_writel(udc, UDCICR1, 0);
+- udc_writel(udc, UP2OCR, UP2OCR_HXOE);
++ /*
++ * UP2OCR : set HXOE=1, HXS=0, SEOS=0 => non-OTG client
++ */
++ up2ocr = udc_readl(udc, UP2OCR);
++ up2ocr = (up2ocr & ~(UP2OCR_HXS - 1)) | UP2OCR_HXOE;
++ udc_writel(udc, UP2OCR, up2ocr);
+ udc_clear_mask_UDCCR(udc, UDCCR_UDE);
+
+ clk_enable(udc->clk);
diff --git a/usb/usb-ohci-pnx4008-i2c-cleanups-and-fixes.patch b/usb/usb-ohci-pnx4008-i2c-cleanups-and-fixes.patch
new file mode 100644
index 00000000000000..e70eefc0a99a51
--- /dev/null
+++ b/usb/usb-ohci-pnx4008-i2c-cleanups-and-fixes.patch
@@ -0,0 +1,101 @@
+From khali@linux-fr.org Fri Jun 27 15:11:56 2008
+From: Jean Delvare <khali@linux-fr.org>
+Date: Wed, 18 Jun 2008 14:46:27 +0200
+Subject: USB: ohci-pnx4008: I2C cleanups and fixes
+To: Vitaly Wool <vitalywool@gmail.com>
+Cc: David Brownell <david-b@pacbell.net>, linux-usb@vger.kernel.org
+Message-ID: <20080618144627.7cdfd5d3@hyperion.delvare>
+
+
+Various cleanups and fixes to the i2c code in ohci-pnx4008:
+* Delete empty isp1301_command. The i2c driver command implementation
+ is optional, so there's no point in providing an empty
+ implementation.
+* Give a name to isp1301_driver. I'm surprised that i2c-core accepted
+ to register this driver at all. I've chosen "isp1301_pnx" as the
+ name, because it's not a generic ISP1301 driver (much like the
+ isp1301_omap driver.) We might want to make the name even more
+ specific (but "isp1301_ohci_pnx4008" doesn't fit.)
+* The ISP1301 is definitely not a hardware monitoring device.
+* Fix a memory leak on failure in isp1301_attach. If
+ i2c_attach_client fails, the client is not registered so
+ isp1301_detach is never called and the i2c_client memory is lost.
+* Use strlcpy instead of strcpy.
+
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Cc: Vitaly Wool <vitalywool@gmail.com>
+Cc: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ohci-pnx4008.c | 26 ++++++++++++--------------
+ 1 file changed, 12 insertions(+), 14 deletions(-)
+
+--- a/drivers/usb/host/ohci-pnx4008.c
++++ b/drivers/usb/host/ohci-pnx4008.c
+@@ -109,8 +109,6 @@ static struct clk *usb_clk;
+
+ static int isp1301_probe(struct i2c_adapter *adap);
+ static int isp1301_detach(struct i2c_client *client);
+-static int isp1301_command(struct i2c_client *client, unsigned int cmd,
+- void *arg);
+
+ static const unsigned short normal_i2c[] =
+ { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
+@@ -123,30 +121,37 @@ static struct i2c_client_address_data ad
+ };
+
+ struct i2c_driver isp1301_driver = {
+- .class = I2C_CLASS_HWMON,
++ .driver = {
++ .name = "isp1301_pnx",
++ },
+ .attach_adapter = isp1301_probe,
+ .detach_client = isp1301_detach,
+- .command = isp1301_command
+ };
+
+ static int isp1301_attach(struct i2c_adapter *adap, int addr, int kind)
+ {
+ struct i2c_client *c;
++ int err;
+
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
+-
+ if (!c)
+ return -ENOMEM;
+
+- strcpy(c->name, "isp1301");
++ strlcpy(c->name, "isp1301_pnx", I2C_NAME_SIZE);
+ c->flags = 0;
+ c->addr = addr;
+ c->adapter = adap;
+ c->driver = &isp1301_driver;
+
++ err = i2c_attach_client(c);
++ if (err) {
++ kfree(c);
++ return err;
++ }
++
+ isp1301_i2c_client = c;
+
+- return i2c_attach_client(c);
++ return 0;
+ }
+
+ static int isp1301_probe(struct i2c_adapter *adap)
+@@ -161,13 +166,6 @@ static int isp1301_detach(struct i2c_cli
+ return 0;
+ }
+
+-/* No commands defined */
+-static int isp1301_command(struct i2c_client *client, unsigned int cmd,
+- void *arg)
+-{
+- return 0;
+-}
+-
+ static void i2c_write(u8 buf, u8 subaddr)
+ {
+ char tmpbuf[2];
diff --git a/usb/usb-r8a66597-hcd-fix-iinterval-for-full-low-speed-device.patch b/usb/usb-r8a66597-hcd-fix-iinterval-for-full-low-speed-device.patch
new file mode 100644
index 00000000000000..21d87f8b42ad5f
--- /dev/null
+++ b/usb/usb-r8a66597-hcd-fix-iinterval-for-full-low-speed-device.patch
@@ -0,0 +1,65 @@
+From shimoda.yoshihiro@renesas.com Fri Jun 27 14:35:17 2008
+From: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+Date: Fri, 27 Jun 2008 19:09:58 +0900
+Subject: usb: r8a66597-hcd: fix iinterval for Full/Low speed device
+To: gregkh@suse.de
+Cc: linux-usb@vger.kernel.org
+Message-ID: <4864BC76.7040004@renesas.com>
+
+
+fix interrupt transfer interval for Full/Low speed device.
+
+Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/r8a66597-hcd.c | 31 +++++++++++++++++++++++++++----
+ 1 file changed, 27 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/host/r8a66597-hcd.c
++++ b/drivers/usb/host/r8a66597-hcd.c
+@@ -863,6 +863,32 @@ static void disable_r8a66597_pipe_all(st
+ dev->dma_map = 0;
+ }
+
++static u16 get_interval(struct urb *urb, __u8 interval)
++{
++ u16 time = 1;
++ int i;
++
++ if (urb->dev->speed == USB_SPEED_HIGH) {
++ if (interval > IITV)
++ time = IITV;
++ else
++ time = interval ? interval - 1 : 0;
++ } else {
++ if (interval > 128) {
++ time = IITV;
++ } else {
++ /* calculate the nearest value for PIPEPERI */
++ for (i = 0; i < 7; i++) {
++ if ((1 << i) < interval &&
++ (1 << (i + 1) > interval))
++ time = 1 << i;
++ }
++ }
++ }
++
++ return time;
++}
++
+ static unsigned long get_timer_interval(struct urb *urb, __u8 interval)
+ {
+ __u8 i;
+@@ -901,10 +927,7 @@ static void init_pipe_info(struct r8a665
+ info.interval = 0;
+ info.timer_interval = 0;
+ } else {
+- if (ep->bInterval > IITV)
+- info.interval = IITV;
+- else
+- info.interval = ep->bInterval ? ep->bInterval - 1 : 0;
++ info.interval = get_interval(urb, ep->bInterval);
+ info.timer_interval = get_timer_interval(urb, ep->bInterval);
+ }
+ if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
diff --git a/usb/usb-r8a66597-hcd-fix-interrupt-trigger.patch b/usb/usb-r8a66597-hcd-fix-interrupt-trigger.patch
new file mode 100644
index 00000000000000..bf4409bac2813b
--- /dev/null
+++ b/usb/usb-r8a66597-hcd-fix-interrupt-trigger.patch
@@ -0,0 +1,41 @@
+From shimoda.yoshihiro@renesas.com Fri Jun 27 14:35:05 2008
+From: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+Date: Fri, 27 Jun 2008 19:09:55 +0900
+Subject: usb: r8a66597-hcd: fix interrupt trigger
+To: gregkh@suse.de
+Cc: linux-usb@vger.kernel.org
+Message-ID: <4864BC73.4050607@renesas.com>
+
+
+fix the problem that did not set IRQF_TRIGGER_ flag.
+
+Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/r8a66597-hcd.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/r8a66597-hcd.c
++++ b/drivers/usb/host/r8a66597-hcd.c
+@@ -2244,6 +2244,7 @@ static int __init r8a66597_probe(struct
+ struct r8a66597 *r8a66597;
+ int ret = 0;
+ int i;
++ unsigned long irq_trigger;
+
+ if (pdev->dev.dma_mask) {
+ ret = -EINVAL;
+@@ -2302,7 +2303,11 @@ static int __init r8a66597_probe(struct
+ INIT_LIST_HEAD(&r8a66597->child_device);
+
+ hcd->rsrc_start = res->start;
+- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
++ if (irq_sense == INTL)
++ irq_trigger = IRQF_TRIGGER_LOW;
++ else
++ irq_trigger = IRQF_TRIGGER_FALLING;
++ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger);
+ if (ret != 0) {
+ err("Failed to add hcd");
+ goto clean_up;
diff --git a/usb/usbfs-don-t-store-bad-pointers-in-registration.patch b/usb/usbfs-don-t-store-bad-pointers-in-registration.patch
new file mode 100644
index 00000000000000..560709639fa273
--- /dev/null
+++ b/usb/usbfs-don-t-store-bad-pointers-in-registration.patch
@@ -0,0 +1,57 @@
+From stern@rowland.harvard.edu Fri Jun 27 15:15:45 2008
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 24 Jun 2008 14:47:29 -0400 (EDT)
+Subject: usbfs: don't store bad pointers in registration
+To: Greg KH <greg@kroah.com>
+Cc: USB list <linux-usb@vger.kernel.org>
+Message-ID: <Pine.LNX.4.44L0.0806241444500.2166-100000@iolanthe.rowland.org>
+
+
+This patch (as1107) fixes a small bug in the usbfs registration and
+unregistration code. It avoids leaving an error value stored in the
+device's usb_classdev field and it avoids trying to unregister a NULL
+pointer. (It also fixes a rather extreme overuse of whitespace.)
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/devio.c | 21 +++++++++------------
+ 1 file changed, 9 insertions(+), 12 deletions(-)
+
+--- a/drivers/usb/core/devio.c
++++ b/drivers/usb/core/devio.c
+@@ -1724,24 +1724,21 @@ static struct class *usb_classdev_class;
+
+ static int usb_classdev_add(struct usb_device *dev)
+ {
+- int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
+-
+- dev->usb_classdev = device_create_drvdata(usb_classdev_class,
+- &dev->dev,
+- MKDEV(USB_DEVICE_MAJOR,
+- minor), NULL,
+- "usbdev%d.%d",
+- dev->bus->busnum,
+- dev->devnum);
+- if (IS_ERR(dev->usb_classdev))
+- return PTR_ERR(dev->usb_classdev);
++ struct device *cldev;
+
++ cldev = device_create_drvdata(usb_classdev_class,
++ &dev->dev, dev->dev.devt, NULL,
++ "usbdev%d.%d", dev->bus->busnum, dev->devnum);
++ if (IS_ERR(cldev))
++ return PTR_ERR(cldev);
++ dev->usb_classdev = cldev;
+ return 0;
+ }
+
+ static void usb_classdev_remove(struct usb_device *dev)
+ {
+- device_unregister(dev->usb_classdev);
++ if (dev->usb_classdev)
++ device_unregister(dev->usb_classdev);
+ usb_fs_classdev_common_remove(dev);
+ }
+
diff --git a/usb/usbfs-fix-race-between-open-and-unregister.patch b/usb/usbfs-fix-race-between-open-and-unregister.patch
new file mode 100644
index 00000000000000..585ad3b7d4662b
--- /dev/null
+++ b/usb/usbfs-fix-race-between-open-and-unregister.patch
@@ -0,0 +1,70 @@
+From stern@rowland.harvard.edu Fri Jun 27 15:15:27 2008
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 24 Jun 2008 14:47:19 -0400 (EDT)
+Subject: usbfs: fix race between open and unregister
+To: Greg KH <greg@kroah.com>
+Cc: USB list <linux-usb@vger.kernel.org>
+Message-ID: <Pine.LNX.4.44L0.0806241443260.2166-100000@iolanthe.rowland.org>
+
+
+This patch (as1106) fixes a race between opening and unregistering
+device files in usbfs. The current code drops its reference to the
+device and then reacquires it, ignoring the possibility that the
+device structure might have been removed in the meantime. It also
+doesn't check whether the device is already in the NOTATTACHED state
+when the file is opened.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/devio.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/core/devio.c
++++ b/drivers/usb/core/devio.c
+@@ -562,7 +562,6 @@ static struct usb_device *usbdev_lookup_
+ dev = bus_find_device(&usb_bus_type, NULL, (void *) devt, match_devt);
+ if (!dev)
+ return NULL;
+- put_device(dev);
+ return container_of(dev, struct usb_device, dev);
+ }
+
+@@ -590,16 +589,21 @@ static int usbdev_open(struct inode *ino
+ dev = usbdev_lookup_by_devt(inode->i_rdev);
+ #ifdef CONFIG_USB_DEVICEFS
+ /* procfs file */
+- if (!dev)
++ if (!dev) {
+ dev = inode->i_private;
++ if (dev && dev->usbfs_dentry &&
++ dev->usbfs_dentry->d_inode == inode)
++ usb_get_dev(dev);
++ else
++ dev = NULL;
++ }
+ #endif
+- if (!dev)
++ if (!dev || dev->state == USB_STATE_NOTATTACHED)
+ goto out;
+ ret = usb_autoresume_device(dev);
+ if (ret)
+ goto out;
+
+- usb_get_dev(dev);
+ ret = 0;
+ ps->dev = dev;
+ ps->file = file;
+@@ -619,8 +623,10 @@ static int usbdev_open(struct inode *ino
+ list_add_tail(&ps->list, &dev->filelist);
+ file->private_data = ps;
+ out:
+- if (ret)
++ if (ret) {
+ kfree(ps);
++ usb_put_dev(dev);
++ }
+ mutex_unlock(&usbfs_mutex);
+ return ret;
+ }
diff --git a/usb/usbfs-send-disconnect-signals-when-device-is-unregistered.patch b/usb/usbfs-send-disconnect-signals-when-device-is-unregistered.patch
new file mode 100644
index 00000000000000..8fcfb7d15eddd8
--- /dev/null
+++ b/usb/usbfs-send-disconnect-signals-when-device-is-unregistered.patch
@@ -0,0 +1,161 @@
+From stern@rowland.harvard.edu Fri Jun 27 15:14:42 2008
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 24 Jun 2008 14:47:04 -0400 (EDT)
+Subject: usbfs: send disconnect signals when device is unregistered
+To: Greg KH <greg@kroah.com>
+Cc: USB list <linux-usb@vger.kernel.org>
+Message-ID: <Pine.LNX.4.44L0.0806241441310.2166-100000@iolanthe.rowland.org>
+
+
+USB device files are accessible in two ways: as files in usbfs and as
+character device nodes. The two paths are supposed to behave
+identically, but they don't. When the underlying USB device is
+unplugged, disconnect signals are sent to processes with open usbfs
+files (if they requested these signals) but not to processes with open
+device node files.
+
+This patch (as1104) fixes the bug by moving the disconnect-signalling
+code into a common subroutine which is called from both paths.
+Putting this subroutine in devio.c removes the only out-of-file
+reference to struct dev_state, and so the structure's declaration can
+be moved from usb.h into devio.c.
+
+Finally, the new subroutine performs one extra action: It kills all
+the outstanding async URBs. (I'd kill the outstanding synchronous
+URBs too, if there was any way to do it.) In the past this hasn't
+mattered much, because devices were unregistered from usbfs only
+when they were disconnected. But now the unregistration can also
+occur whenever devices are unbound from the usb_generic driver. At
+any rate, killing URBs when a device is unregistered from usbfs seems
+like a good thing to do.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/devio.c | 39 +++++++++++++++++++++++++++++++++++++++
+ drivers/usb/core/inode.c | 16 +---------------
+ drivers/usb/core/usb.h | 17 +----------------
+ 3 files changed, 41 insertions(+), 31 deletions(-)
+
+--- a/drivers/usb/core/devio.c
++++ b/drivers/usb/core/devio.c
+@@ -59,6 +59,22 @@
+ /* Mutual exclusion for removal, open, and release */
+ DEFINE_MUTEX(usbfs_mutex);
+
++struct dev_state {
++ struct list_head list; /* state list */
++ struct usb_device *dev;
++ struct file *file;
++ spinlock_t lock; /* protects the async urb lists */
++ struct list_head async_pending;
++ struct list_head async_completed;
++ wait_queue_head_t wait; /* wake up if a request completed */
++ unsigned int discsignr;
++ struct pid *disc_pid;
++ uid_t disc_uid, disc_euid;
++ void __user *disccontext;
++ unsigned long ifclaimed;
++ u32 secid;
++};
++
+ struct async {
+ struct list_head asynclist;
+ struct dev_state *ps;
+@@ -1678,6 +1694,28 @@ const struct file_operations usbdev_file
+ .release = usbdev_release,
+ };
+
++void usb_fs_classdev_common_remove(struct usb_device *udev)
++{
++ struct dev_state *ps;
++ struct siginfo sinfo;
++
++ while (!list_empty(&udev->filelist)) {
++ ps = list_entry(udev->filelist.next, struct dev_state, list);
++ destroy_all_async(ps);
++ wake_up_all(&ps->wait);
++ list_del_init(&ps->list);
++ if (ps->discsignr) {
++ sinfo.si_signo = ps->discsignr;
++ sinfo.si_errno = EPIPE;
++ sinfo.si_code = SI_ASYNCIO;
++ sinfo.si_addr = ps->disccontext;
++ kill_pid_info_as_uid(ps->discsignr, &sinfo,
++ ps->disc_pid, ps->disc_uid,
++ ps->disc_euid, ps->secid);
++ }
++ }
++}
++
+ #ifdef CONFIG_USB_DEVICE_CLASS
+ static struct class *usb_classdev_class;
+
+@@ -1701,6 +1739,7 @@ static int usb_classdev_add(struct usb_d
+ static void usb_classdev_remove(struct usb_device *dev)
+ {
+ device_unregister(dev->usb_classdev);
++ usb_fs_classdev_common_remove(dev);
+ }
+
+ static int usb_classdev_notify(struct notifier_block *self,
+--- a/drivers/usb/core/inode.c
++++ b/drivers/usb/core/inode.c
+@@ -712,25 +712,11 @@ static void usbfs_add_device(struct usb_
+
+ static void usbfs_remove_device(struct usb_device *dev)
+ {
+- struct dev_state *ds;
+- struct siginfo sinfo;
+-
+ if (dev->usbfs_dentry) {
+ fs_remove_file (dev->usbfs_dentry);
+ dev->usbfs_dentry = NULL;
+ }
+- while (!list_empty(&dev->filelist)) {
+- ds = list_entry(dev->filelist.next, struct dev_state, list);
+- wake_up_all(&ds->wait);
+- list_del_init(&ds->list);
+- if (ds->discsignr) {
+- sinfo.si_signo = ds->discsignr;
+- sinfo.si_errno = EPIPE;
+- sinfo.si_code = SI_ASYNCIO;
+- sinfo.si_addr = ds->disccontext;
+- kill_pid_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid);
+- }
+- }
++ usb_fs_classdev_common_remove(dev);
+ }
+
+ static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev)
+--- a/drivers/usb/core/usb.h
++++ b/drivers/usb/core/usb.h
+@@ -142,26 +142,11 @@ extern struct usb_driver usbfs_driver;
+ extern const struct file_operations usbfs_devices_fops;
+ extern const struct file_operations usbdev_file_operations;
+ extern void usbfs_conn_disc_event(void);
++extern void usb_fs_classdev_common_remove(struct usb_device *udev);
+
+ extern int usb_devio_init(void);
+ extern void usb_devio_cleanup(void);
+
+-struct dev_state {
+- struct list_head list; /* state list */
+- struct usb_device *dev;
+- struct file *file;
+- spinlock_t lock; /* protects the async urb lists */
+- struct list_head async_pending;
+- struct list_head async_completed;
+- wait_queue_head_t wait; /* wake up if a request completed */
+- unsigned int discsignr;
+- struct pid *disc_pid;
+- uid_t disc_uid, disc_euid;
+- void __user *disccontext;
+- unsigned long ifclaimed;
+- u32 secid;
+-};
+-
+ /* internal notify stuff */
+ extern void usb_notify_add_device(struct usb_device *udev);
+ extern void usb_notify_remove_device(struct usb_device *udev);
diff --git a/usb/usbfs-simplify-the-lookup-by-minor-routines.patch b/usb/usbfs-simplify-the-lookup-by-minor-routines.patch
new file mode 100644
index 00000000000000..822752eb4bcbeb
--- /dev/null
+++ b/usb/usbfs-simplify-the-lookup-by-minor-routines.patch
@@ -0,0 +1,60 @@
+From stern@rowland.harvard.edu Fri Jun 27 15:15:09 2008
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 24 Jun 2008 14:47:12 -0400 (EDT)
+Subject: usbfs: simplify the lookup-by-minor routines
+To: Greg KH <greg@kroah.com>
+Cc: USB list <linux-usb@vger.kernel.org>
+Message-ID: <Pine.LNX.4.44L0.0806241442410.2166-100000@iolanthe.rowland.org>
+
+
+This patch (as1105) simplifies the lookup-by-minor-number code in
+usbfs. Instead of passing the minor number to the callback, which
+must then reconstruct the entire dev_t value, the patch passes the
+dev_t value directly.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/devio.c | 15 ++++++---------
+ 1 file changed, 6 insertions(+), 9 deletions(-)
+
+--- a/drivers/usb/core/devio.c
++++ b/drivers/usb/core/devio.c
+@@ -550,20 +550,16 @@ static int check_ctrlrecip(struct dev_st
+ return ret;
+ }
+
+-static int __match_minor(struct device *dev, void *data)
++static int match_devt(struct device *dev, void *data)
+ {
+- int minor = *((int *)data);
+-
+- if (dev->devt == MKDEV(USB_DEVICE_MAJOR, minor))
+- return 1;
+- return 0;
++ return (dev->devt == (dev_t) data);
+ }
+
+-static struct usb_device *usbdev_lookup_by_minor(int minor)
++static struct usb_device *usbdev_lookup_by_devt(dev_t devt)
+ {
+ struct device *dev;
+
+- dev = bus_find_device(&usb_bus_type, NULL, &minor, __match_minor);
++ dev = bus_find_device(&usb_bus_type, NULL, (void *) devt, match_devt);
+ if (!dev)
+ return NULL;
+ put_device(dev);
+@@ -588,9 +584,10 @@ static int usbdev_open(struct inode *ino
+ goto out;
+
+ ret = -ENOENT;
++
+ /* usbdev device-node */
+ if (imajor(inode) == USB_DEVICE_MAJOR)
+- dev = usbdev_lookup_by_minor(iminor(inode));
++ dev = usbdev_lookup_by_devt(inode->i_rdev);
+ #ifdef CONFIG_USB_DEVICEFS
+ /* procfs file */
+ if (!dev)