aboutsummaryrefslogtreecommitdiffstats
path: root/usb
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2009-07-10 14:51:46 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2009-07-10 14:51:46 -0700
commitda0168ad6c26fae5cb53775a5ad2c95af0dfa8b7 (patch)
tree38aa162f12e37ce1834126e24c94bd9475f5e20e /usb
parent24e34cceebec70f8b7d2229c537e66818b0ecad2 (diff)
downloadpatches-da0168ad6c26fae5cb53775a5ad2c95af0dfa8b7.tar.gz
more patches
Diffstat (limited to 'usb')
-rw-r--r--usb/usb-add-api-for-userspace-drivers-to-claim-ports.patch317
-rw-r--r--usb/usb-at91_udc-at91sam9g20-updates.patch88
-rw-r--r--usb/usb-make-intf.pm_usage-an-atomic_t.patch192
-rw-r--r--usb/usb-make-the-usbfs_snoop-log-more-pertinent.patch311
-rw-r--r--usb/usb-whci-hcd-make-endpoint_reset-method-async.patch156
5 files changed, 1064 insertions, 0 deletions
diff --git a/usb/usb-add-api-for-userspace-drivers-to-claim-ports.patch b/usb/usb-add-api-for-userspace-drivers-to-claim-ports.patch
new file mode 100644
index 00000000000000..120b7b8cbe2edd
--- /dev/null
+++ b/usb/usb-add-api-for-userspace-drivers-to-claim-ports.patch
@@ -0,0 +1,317 @@
+From stern@rowland.harvard.edu Fri Jul 10 14:42:02 2009
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Mon, 29 Jun 2009 10:56:54 -0400 (EDT)
+Subject: USB: add API for userspace drivers to "claim" ports
+To: Greg KH <greg@kroah.com>
+Cc: Pantelis Koukousoulas <pktoss@gmail.com>
+Message-ID: <Pine.LNX.4.44L0.0906291049560.16597-100000@iolanthe.rowland.org>
+
+
+This patch (as1258) implements a feature that users have been asking
+for: It gives programs the ability to "claim" a port on a hub, via a
+new usbfs ioctl. A device plugged into a "claimed" port will not be
+touched by the kernel beyond the immediate necessities of
+initialization and enumeration.
+
+In particular, when a device is plugged into a "claimed" port, the
+kernel will not select and install a configuration. And when a config
+is installed by usbfs or sysfs, the kernel will not probe any drivers
+for any of the interfaces. (However the kernel will fetch various
+string descriptors during enumeration. One could argue that this
+isn't really necessary, but the strings are exported in sysfs.)
+
+The patch does not guarantee exclusive access to these devices; it is
+still possible for more than one program to open the device file
+concurrently. Programs are responsible for coordinating access among
+themselves.
+
+A demonstration program showing how to use the new interface can be
+found in an attachment to
+
+ http://marc.info/?l=linux-usb&m=124345857431452&w=2
+
+The patch also makes a small simplification to the hub driver,
+replacing a bunch of more-or-less useless variants of "out of memory"
+with a single message.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/devio.c | 35 +++++++++++++++++
+ drivers/usb/core/driver.c | 3 +
+ drivers/usb/core/generic.c | 4 +
+ drivers/usb/core/hub.c | 88 ++++++++++++++++++++++++++++++++++++++++---
+ drivers/usb/core/usb.h | 7 +++
+ include/linux/usbdevice_fs.h | 2
+ 6 files changed, 133 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/core/devio.c
++++ b/drivers/usb/core/devio.c
+@@ -52,6 +52,7 @@
+
+ #include "hcd.h" /* for usbcore internals */
+ #include "usb.h"
++#include "hub.h"
+
+ #define USB_MAXBUS 64
+ #define USB_DEVICE_MAX USB_MAXBUS * 128
+@@ -655,6 +656,7 @@ static int usbdev_release(struct inode *
+ struct async *as;
+
+ usb_lock_device(dev);
++ usb_hub_release_all_ports(dev, ps);
+
+ /* Protect against simultaneous open */
+ mutex_lock(&usbfs_mutex);
+@@ -1546,6 +1548,29 @@ static int proc_ioctl_compat(struct dev_
+ }
+ #endif
+
++static int proc_claim_port(struct dev_state *ps, void __user *arg)
++{
++ unsigned portnum;
++ int rc;
++
++ if (get_user(portnum, (unsigned __user *) arg))
++ return -EFAULT;
++ rc = usb_hub_claim_port(ps->dev, portnum, ps);
++ if (rc == 0)
++ snoop(&ps->dev->dev, "port %d claimed by process %d: %s\n",
++ portnum, task_pid_nr(current), current->comm);
++ return rc;
++}
++
++static int proc_release_port(struct dev_state *ps, void __user *arg)
++{
++ unsigned portnum;
++
++ if (get_user(portnum, (unsigned __user *) arg))
++ return -EFAULT;
++ return usb_hub_release_port(ps->dev, portnum, ps);
++}
++
+ /*
+ * NOTE: All requests here that have interface numbers as parameters
+ * are assuming that somehow the configuration has been prevented from
+@@ -1687,6 +1712,16 @@ static int usbdev_ioctl(struct inode *in
+ snoop(&dev->dev, "%s: IOCTL\n", __func__);
+ ret = proc_ioctl_default(ps, p);
+ break;
++
++ case USBDEVFS_CLAIM_PORT:
++ snoop(&dev->dev, "%s: CLAIM_PORT\n", __func__);
++ ret = proc_claim_port(ps, p);
++ break;
++
++ case USBDEVFS_RELEASE_PORT:
++ snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
++ ret = proc_release_port(ps, p);
++ break;
+ }
+ usb_unlock_device(dev);
+ if (ret >= 0)
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -207,6 +207,9 @@ static int usb_probe_interface(struct de
+
+ intf->needs_binding = 0;
+
++ if (usb_device_is_owned(udev))
++ return -ENODEV;
++
+ if (udev->authorized == 0) {
+ dev_err(&intf->dev, "Device is not authorized for usage\n");
+ return -ENODEV;
+--- a/drivers/usb/core/generic.c
++++ b/drivers/usb/core/generic.c
+@@ -158,7 +158,9 @@ static int generic_probe(struct usb_devi
+ /* Choose and set the configuration. This registers the interfaces
+ * with the driver core and lets interface drivers bind to them.
+ */
+- if (udev->authorized == 0)
++ if (usb_device_is_owned(udev))
++ ; /* Don't configure if the device is owned */
++ else if (udev->authorized == 0)
+ dev_err(&udev->dev, "Device is not authorized for usage\n");
+ else {
+ c = usb_choose_configuration(udev);
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -78,6 +78,7 @@ struct usb_hub {
+ u8 indicator[USB_MAXCHILDREN];
+ struct delayed_work leds;
+ struct delayed_work init_work;
++ void **port_owners;
+ };
+
+
+@@ -860,19 +861,17 @@ static int hub_configure(struct usb_hub
+ u16 wHubCharacteristics;
+ unsigned int pipe;
+ int maxp, ret;
+- char *message;
++ char *message = "out of memory";
+
+ hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,
+ &hub->buffer_dma);
+ if (!hub->buffer) {
+- message = "can't allocate hub irq buffer";
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
+ if (!hub->status) {
+- message = "can't kmalloc hub status buffer";
+ ret = -ENOMEM;
+ goto fail;
+ }
+@@ -880,7 +879,6 @@ static int hub_configure(struct usb_hub
+
+ hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
+ if (!hub->descriptor) {
+- message = "can't kmalloc hub descriptor";
+ ret = -ENOMEM;
+ goto fail;
+ }
+@@ -904,6 +902,12 @@ static int hub_configure(struct usb_hub
+ dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
+ (hdev->maxchild == 1) ? "" : "s");
+
++ hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
++ if (!hub->port_owners) {
++ ret = -ENOMEM;
++ goto fail;
++ }
++
+ wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
+
+ if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
+@@ -1082,7 +1086,6 @@ static int hub_configure(struct usb_hub
+
+ hub->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!hub->urb) {
+- message = "couldn't allocate interrupt urb";
+ ret = -ENOMEM;
+ goto fail;
+ }
+@@ -1131,11 +1134,13 @@ static void hub_disconnect(struct usb_in
+ hub_quiesce(hub, HUB_DISCONNECT);
+
+ usb_set_intfdata (intf, NULL);
++ hub->hdev->maxchild = 0;
+
+ if (hub->hdev->speed == USB_SPEED_HIGH)
+ highspeed_hubs--;
+
+ usb_free_urb(hub->urb);
++ kfree(hub->port_owners);
+ kfree(hub->descriptor);
+ kfree(hub->status);
+ usb_buffer_free(hub->hdev, sizeof(*hub->buffer), hub->buffer,
+@@ -1250,6 +1255,79 @@ hub_ioctl(struct usb_interface *intf, un
+ }
+ }
+
++/*
++ * Allow user programs to claim ports on a hub. When a device is attached
++ * to one of these "claimed" ports, the program will "own" the device.
++ */
++static int find_port_owner(struct usb_device *hdev, unsigned port1,
++ void ***ppowner)
++{
++ if (hdev->state == USB_STATE_NOTATTACHED)
++ return -ENODEV;
++ if (port1 == 0 || port1 > hdev->maxchild)
++ return -EINVAL;
++
++ /* This assumes that devices not managed by the hub driver
++ * will always have maxchild equal to 0.
++ */
++ *ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]);
++ return 0;
++}
++
++/* In the following three functions, the caller must hold hdev's lock */
++int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, void *owner)
++{
++ int rc;
++ void **powner;
++
++ rc = find_port_owner(hdev, port1, &powner);
++ if (rc)
++ return rc;
++ if (*powner)
++ return -EBUSY;
++ *powner = owner;
++ return rc;
++}
++
++int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner)
++{
++ int rc;
++ void **powner;
++
++ rc = find_port_owner(hdev, port1, &powner);
++ if (rc)
++ return rc;
++ if (*powner != owner)
++ return -ENOENT;
++ *powner = NULL;
++ return rc;
++}
++
++void usb_hub_release_all_ports(struct usb_device *hdev, void *owner)
++{
++ int n;
++ void **powner;
++
++ n = find_port_owner(hdev, 1, &powner);
++ if (n == 0) {
++ for (; n < hdev->maxchild; (++n, ++powner)) {
++ if (*powner == owner)
++ *powner = NULL;
++ }
++ }
++}
++
++/* The caller must hold udev's lock */
++bool usb_device_is_owned(struct usb_device *udev)
++{
++ struct usb_hub *hub;
++
++ if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
++ return false;
++ hub = hdev_to_hub(udev->parent);
++ return !!hub->port_owners[udev->portnum - 1];
++}
++
+
+ static void recursively_mark_NOTATTACHED(struct usb_device *udev)
+ {
+--- a/drivers/usb/core/usb.h
++++ b/drivers/usb/core/usb.h
+@@ -37,6 +37,13 @@ extern int usb_match_device(struct usb_d
+ extern void usb_forced_unbind_intf(struct usb_interface *intf);
+ extern void usb_rebind_intf(struct usb_interface *intf);
+
++extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port,
++ void *owner);
++extern int usb_hub_release_port(struct usb_device *hdev, unsigned port,
++ void *owner);
++extern void usb_hub_release_all_ports(struct usb_device *hdev, void *owner);
++extern bool usb_device_is_owned(struct usb_device *udev);
++
+ extern int usb_hub_init(void);
+ extern void usb_hub_cleanup(void);
+ extern int usb_major_init(void);
+--- a/include/linux/usbdevice_fs.h
++++ b/include/linux/usbdevice_fs.h
+@@ -175,4 +175,6 @@ struct usbdevfs_ioctl32 {
+ #define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int)
+ #define USBDEVFS_DISCONNECT _IO('U', 22)
+ #define USBDEVFS_CONNECT _IO('U', 23)
++#define USBDEVFS_CLAIM_PORT _IOR('U', 24, unsigned int)
++#define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int)
+ #endif /* _LINUX_USBDEVICE_FS_H */
diff --git a/usb/usb-at91_udc-at91sam9g20-updates.patch b/usb/usb-at91_udc-at91sam9g20-updates.patch
new file mode 100644
index 00000000000000..b4b5e0f2dc869c
--- /dev/null
+++ b/usb/usb-at91_udc-at91sam9g20-updates.patch
@@ -0,0 +1,88 @@
+From david-b@pacbell.net Fri Jul 10 14:33:04 2009
+From: David Brownell <david-b@pacbell.net>
+Date: Fri, 19 Jun 2009 02:20:24 -0700
+Subject: USB: at91_udc: at91sam9g20 updates
+To: linux-usb@vger.kernel.org
+Cc: Manuel Sahm <Manuel.Sahm@feig.de>, Nicolas Ferre <nicolas.ferre@rfo.atmel.com>, Anti Sullin <anti.sullin@artecdesign.ee>
+Message-ID: <200906190220.24750.david-b@pacbell.net>
+Content-Disposition: inline
+
+
+From: David Brownell <dbrownell@users.sourceforge.net>
+
+Update the at91_udc driver to improve at91sam9g20 support. This
+is a sped-up at91sam9260; the CPU is twice as fast, but clocking
+for peripheralsl won't change much.
+
+ - Its endpoint FIFOs have the same larger sizes as the '9260.
+
+ - It's more open to races with data still on its way to the USB
+ peripheral, while the driver acts as if it already got there.
+
+Fix the former by adding the relevant cpu_is_*() check, and the
+latter by updating some FIFO read/write paths so they wait until
+the CPU's write buffer drains ... that's a bit cheaper than just
+issuing a controller read.
+
+Problem noted by Manuel Sahm <Manuel.Sahm@feig.de>, who also
+provided a patch for this. One race could be the same as one
+noted by Anti Sullin <anti.sullin@artecdesign.ee> after a GCC
+upgrade on a sam9261 board.
+
+Cc: Manuel Sahm <Manuel.Sahm@feig.de>
+Cc: Nicolas Ferre <nicolas.ferre@rfo.atmel.com>
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/at91_udc.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/gadget/at91_udc.c
++++ b/drivers/usb/gadget/at91_udc.c
+@@ -82,6 +82,11 @@ static const char ep0name[] = "ep0";
+ #define at91_udp_write(dev, reg, val) \
+ __raw_writel((val), (dev)->udp_baseaddr + (reg))
+
++static inline int drain_write_buffer(void)
++{
++ asm("mcr p15, 0, r0, c7, c10, 4 @ drain write buffer\n");
++}
++
+ /*-------------------------------------------------------------------------*/
+
+ #ifdef CONFIG_USB_GADGET_DEBUG_FILES
+@@ -350,6 +355,7 @@ rescan:
+ } else
+ csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+ __raw_writel(csr, creg);
++ drain_write_buffer();
+
+ req->req.actual += count;
+ is_done = (count < ep->ep.maxpacket);
+@@ -434,6 +440,8 @@ static int write_fifo(struct at91_ep *ep
+ csr &= ~SET_FX;
+ csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+ __raw_writel(csr, creg);
++ drain_write_buffer();
++
+ req->req.actual += count;
+
+ PACKET("%s %p in/%d%s\n", ep->ep.name, &req->req, count,
+@@ -669,6 +677,7 @@ ep0_in_status:
+ tmp &= ~SET_FX;
+ tmp |= CLR_FX | AT91_UDP_TXPKTRDY;
+ __raw_writel(tmp, ep->creg);
++ drain_write_buffer();
+ dev->req_pending = 0;
+ goto done;
+ }
+@@ -1687,7 +1696,7 @@ static int __init at91udc_probe(struct p
+ }
+
+ /* newer chips have more FIFO memory than rm9200 */
+- if (cpu_is_at91sam9260()) {
++ if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) {
+ udc->ep[0].maxpacket = 64;
+ udc->ep[3].maxpacket = 64;
+ udc->ep[4].maxpacket = 512;
diff --git a/usb/usb-make-intf.pm_usage-an-atomic_t.patch b/usb/usb-make-intf.pm_usage-an-atomic_t.patch
new file mode 100644
index 00000000000000..2d347c3b337d2e
--- /dev/null
+++ b/usb/usb-make-intf.pm_usage-an-atomic_t.patch
@@ -0,0 +1,192 @@
+From stern@rowland.harvard.edu Fri Jul 10 14:43:11 2009
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Mon, 29 Jun 2009 11:00:01 -0400 (EDT)
+Subject: USB: make intf.pm_usage an atomic_t
+To: Greg KH <greg@kroah.com>
+Message-ID: <Pine.LNX.4.44L0.0906291058430.16597-100000@iolanthe.rowland.org>
+
+
+This patch (as1260) changes the pm_usage_cnt field in struct
+usb_interface from an int to an atomic_t. This is so that drivers can
+invoke the usb_autopm_get_interface_async() and
+usb_autopm_put_interface_async() routines without locking and without
+fear of corrupting the pm_usage_cnt value.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/core/driver.c | 38 ++++++++++++++++++++++----------------
+ drivers/usb/core/hub.c | 5 +++--
+ include/linux/usb.h | 6 +++---
+ 3 files changed, 28 insertions(+), 21 deletions(-)
+
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -235,7 +235,7 @@ static int usb_probe_interface(struct de
+ /* The interface should always appear to be in use
+ * unless the driver suports autosuspend.
+ */
+- intf->pm_usage_cnt = !(driver->supports_autosuspend);
++ atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend);
+
+ /* Carry out a deferred switch to altsetting 0 */
+ if (intf->needs_altsetting0) {
+@@ -347,7 +347,7 @@ int usb_driver_claim_interface(struct us
+ usb_pm_lock(udev);
+ iface->condition = USB_INTERFACE_BOUND;
+ mark_active(iface);
+- iface->pm_usage_cnt = !(driver->supports_autosuspend);
++ atomic_set(&iface->pm_usage_cnt, !driver->supports_autosuspend);
+ usb_pm_unlock(udev);
+
+ /* if interface was already added, bind now; else let
+@@ -1068,7 +1068,7 @@ static int autosuspend_check(struct usb_
+ intf = udev->actconfig->interface[i];
+ if (!is_active(intf))
+ continue;
+- if (intf->pm_usage_cnt > 0)
++ if (atomic_read(&intf->pm_usage_cnt) > 0)
+ return -EBUSY;
+ if (intf->needs_remote_wakeup &&
+ !udev->do_remote_wakeup) {
+@@ -1464,17 +1464,19 @@ static int usb_autopm_do_interface(struc
+ status = -ENODEV;
+ else {
+ udev->auto_pm = 1;
+- intf->pm_usage_cnt += inc_usage_cnt;
++ atomic_add(inc_usage_cnt, &intf->pm_usage_cnt);
+ udev->last_busy = jiffies;
+- if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
++ if (inc_usage_cnt >= 0 &&
++ atomic_read(&intf->pm_usage_cnt) > 0) {
+ if (udev->state == USB_STATE_SUSPENDED)
+ status = usb_resume_both(udev,
+ PMSG_AUTO_RESUME);
+ if (status != 0)
+- intf->pm_usage_cnt -= inc_usage_cnt;
++ atomic_sub(inc_usage_cnt, &intf->pm_usage_cnt);
+ else
+ udev->last_busy = jiffies;
+- } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) {
++ } else if (inc_usage_cnt <= 0 &&
++ atomic_read(&intf->pm_usage_cnt) <= 0) {
+ status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
+ }
+ }
+@@ -1519,7 +1521,7 @@ void usb_autopm_put_interface(struct usb
+
+ status = usb_autopm_do_interface(intf, -1);
+ dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+- __func__, status, intf->pm_usage_cnt);
++ __func__, status, atomic_read(&intf->pm_usage_cnt));
+ }
+ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
+
+@@ -1547,10 +1549,10 @@ void usb_autopm_put_interface_async(stru
+ status = -ENODEV;
+ } else {
+ udev->last_busy = jiffies;
+- --intf->pm_usage_cnt;
++ atomic_dec(&intf->pm_usage_cnt);
+ if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
+ status = -EPERM;
+- else if (intf->pm_usage_cnt <= 0 &&
++ else if (atomic_read(&intf->pm_usage_cnt) <= 0 &&
+ !timer_pending(&udev->autosuspend.timer)) {
+ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+ round_jiffies_up_relative(
+@@ -1558,7 +1560,7 @@ void usb_autopm_put_interface_async(stru
+ }
+ }
+ dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+- __func__, status, intf->pm_usage_cnt);
++ __func__, status, atomic_read(&intf->pm_usage_cnt));
+ }
+ EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
+
+@@ -1602,7 +1604,7 @@ int usb_autopm_get_interface(struct usb_
+
+ status = usb_autopm_do_interface(intf, 1);
+ dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+- __func__, status, intf->pm_usage_cnt);
++ __func__, status, atomic_read(&intf->pm_usage_cnt));
+ return status;
+ }
+ EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
+@@ -1630,10 +1632,14 @@ int usb_autopm_get_interface_async(struc
+ status = -ENODEV;
+ else if (udev->autoresume_disabled)
+ status = -EPERM;
+- else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED)
+- queue_work(ksuspend_usb_wq, &udev->autoresume);
++ else {
++ atomic_inc(&intf->pm_usage_cnt);
++ if (atomic_read(&intf->pm_usage_cnt) > 0 &&
++ udev->state == USB_STATE_SUSPENDED)
++ queue_work(ksuspend_usb_wq, &udev->autoresume);
++ }
+ dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+- __func__, status, intf->pm_usage_cnt);
++ __func__, status, atomic_read(&intf->pm_usage_cnt));
+ return status;
+ }
+ EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
+@@ -1655,7 +1661,7 @@ int usb_autopm_set_interface(struct usb_
+
+ status = usb_autopm_do_interface(intf, 0);
+ dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+- __func__, status, intf->pm_usage_cnt);
++ __func__, status, atomic_read(&intf->pm_usage_cnt));
+ return status;
+ }
+ EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -373,7 +373,7 @@ static void kick_khubd(struct usb_hub *h
+ unsigned long flags;
+
+ /* Suppress autosuspend until khubd runs */
+- to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;
++ atomic_set(&to_usb_interface(hub->intfdev)->pm_usage_cnt, 1);
+
+ spin_lock_irqsave(&hub_event_lock, flags);
+ if (!hub->disconnected && list_empty(&hub->event_list)) {
+@@ -678,7 +678,8 @@ static void hub_activate(struct usb_hub
+ msecs_to_jiffies(delay));
+
+ /* Suppress autosuspend until init is done */
+- to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;
++ atomic_set(&to_usb_interface(hub->intfdev)->
++ pm_usage_cnt, 1);
+ return; /* Continues at init2: below */
+ } else {
+ hub_power_on(hub, true);
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -195,7 +195,7 @@ struct usb_interface {
+
+ struct device dev; /* interface specific device info */
+ struct device *usb_dev;
+- int pm_usage_cnt; /* usage counter for autosuspend */
++ atomic_t pm_usage_cnt; /* usage counter for autosuspend */
+ struct work_struct reset_ws; /* for resets in atomic context */
+ };
+ #define to_usb_interface(d) container_of(d, struct usb_interface, dev)
+@@ -551,13 +551,13 @@ extern void usb_autopm_put_interface_asy
+
+ static inline void usb_autopm_enable(struct usb_interface *intf)
+ {
+- intf->pm_usage_cnt = 0;
++ atomic_set(&intf->pm_usage_cnt, 0);
+ usb_autopm_set_interface(intf);
+ }
+
+ static inline void usb_autopm_disable(struct usb_interface *intf)
+ {
+- intf->pm_usage_cnt = 1;
++ atomic_set(&intf->pm_usage_cnt, 1);
+ usb_autopm_set_interface(intf);
+ }
+
diff --git a/usb/usb-make-the-usbfs_snoop-log-more-pertinent.patch b/usb/usb-make-the-usbfs_snoop-log-more-pertinent.patch
new file mode 100644
index 00000000000000..81bb88b2db20d0
--- /dev/null
+++ b/usb/usb-make-the-usbfs_snoop-log-more-pertinent.patch
@@ -0,0 +1,311 @@
+From stern@rowland.harvard.edu Fri Jul 10 14:43:26 2009
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Mon, 29 Jun 2009 11:02:04 -0400 (EDT)
+Subject: USB: make the "usbfs_snoop" log more pertinent
+To: Greg KH <greg@kroah.com>
+Message-ID: <Pine.LNX.4.44L0.0906291100070.16597-100000@iolanthe.rowland.org>
+
+
+This patch (as1261) reduces the amount of detailed URB information
+logged by usbfs when the usbfs_snoop parameter is enabled.
+
+Currently we don't display the final status value for a completed URB.
+But we do display the entire data buffer twice: both before submission
+and after completion. The after-completion display doesn't limit
+itself to the actual_length value. But since usbmon is readily
+available in virtually all distributions, there's no reason for usbfs
+to print out any buffer contents at all!
+
+So this patch restricts the information to: userspace buffer pointer,
+endpoint number, type, and direction, length or actual_length, and
+timeout value or status. Now everything fits neatly into a single
+line.
+
+Along with those changes, the patch also fixes the snoop output for
+the REAPURBNDELAY and REAPURBNDELAY32 ioctls. The current version
+omits the 'N' from the names.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/devio.c | 133 ++++++++++++++++++++++-------------------------
+ 1 file changed, 63 insertions(+), 70 deletions(-)
+
+--- a/drivers/usb/core/devio.c
++++ b/drivers/usb/core/devio.c
+@@ -100,11 +100,15 @@ MODULE_PARM_DESC(usbfs_snoop, "true to l
+ dev_info(dev , format , ## arg); \
+ } while (0)
+
+-#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)
++enum snoop_when {
++ SUBMIT, COMPLETE
++};
+
++#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)
+
+ #define MAX_USBFS_BUFFER_SIZE 16384
+
++
+ static int connected(struct dev_state *ps)
+ {
+ return (!list_empty(&ps->list) &&
+@@ -301,24 +305,42 @@ static struct async *async_getpending(st
+ return NULL;
+ }
+
+-static void snoop_urb(struct urb *urb, void __user *userurb)
+-{
+- unsigned j;
+- unsigned char *data = urb->transfer_buffer;
++static void snoop_urb(struct usb_device *udev,
++ void __user *userurb, int pipe, unsigned length,
++ int timeout_or_status, enum snoop_when when)
++{
++ static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
++ static const char *dirs[] = {"out", "in"};
++ int ep;
++ const char *t, *d;
+
+ if (!usbfs_snoop)
+ return;
+
+- dev_info(&urb->dev->dev, "direction=%s\n",
+- usb_urb_dir_in(urb) ? "IN" : "OUT");
+- dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
+- dev_info(&urb->dev->dev, "transfer_buffer_length=%u\n",
+- urb->transfer_buffer_length);
+- dev_info(&urb->dev->dev, "actual_length=%u\n", urb->actual_length);
+- dev_info(&urb->dev->dev, "data: ");
+- for (j = 0; j < urb->transfer_buffer_length; ++j)
+- printk("%02x ", data[j]);
+- printk("\n");
++ ep = usb_pipeendpoint(pipe);
++ t = types[usb_pipetype(pipe)];
++ d = dirs[!!usb_pipein(pipe)];
++
++ if (userurb) { /* Async */
++ if (when == SUBMIT)
++ dev_info(&udev->dev, "userurb %p, ep%d %s-%s, "
++ "length %u\n",
++ userurb, ep, t, d, length);
++ else
++ dev_info(&udev->dev, "userurb %p, ep%d %s-%s, "
++ "actual_length %u status %d\n",
++ userurb, ep, t, d, length,
++ timeout_or_status);
++ } else {
++ if (when == SUBMIT)
++ dev_info(&udev->dev, "ep%d %s-%s, length %u, "
++ "timeout %d\n",
++ ep, t, d, length, timeout_or_status);
++ else
++ dev_info(&udev->dev, "ep%d %s-%s, actual_length %u, "
++ "status %d\n",
++ ep, t, d, length, timeout_or_status);
++ }
+ }
+
+ static void async_completed(struct urb *urb)
+@@ -347,7 +369,8 @@ static void async_completed(struct urb *
+ secid = as->secid;
+ }
+ snoop(&urb->dev->dev, "urb complete\n");
+- snoop_urb(urb, as->userurb);
++ snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
++ as->status, COMPLETE);
+ spin_unlock(&ps->lock);
+
+ if (signr)
+@@ -690,7 +713,7 @@ static int proc_control(struct dev_state
+ unsigned int tmo;
+ unsigned char *tbuf;
+ unsigned wLength;
+- int i, j, ret;
++ int i, pipe, ret;
+
+ if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+ return -EFAULT;
+@@ -710,24 +733,17 @@ static int proc_control(struct dev_state
+ free_page((unsigned long)tbuf);
+ return -EINVAL;
+ }
+- snoop(&dev->dev, "control read: bRequest=%02x "
+- "bRrequestType=%02x wValue=%04x "
+- "wIndex=%04x wLength=%04x\n",
+- ctrl.bRequest, ctrl.bRequestType, ctrl.wValue,
+- ctrl.wIndex, ctrl.wLength);
++ pipe = usb_rcvctrlpipe(dev, 0);
++ snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
+
+ usb_unlock_device(dev);
+- i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest,
++ i = usb_control_msg(dev, pipe, ctrl.bRequest,
+ ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
+ tbuf, ctrl.wLength, tmo);
+ usb_lock_device(dev);
++ snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
++
+ if ((i > 0) && ctrl.wLength) {
+- if (usbfs_snoop) {
+- dev_info(&dev->dev, "control read: data ");
+- for (j = 0; j < i; ++j)
+- printk("%02x ", (u8)(tbuf)[j]);
+- printk("\n");
+- }
+ if (copy_to_user(ctrl.data, tbuf, i)) {
+ free_page((unsigned long)tbuf);
+ return -EFAULT;
+@@ -740,22 +756,15 @@ static int proc_control(struct dev_state
+ return -EFAULT;
+ }
+ }
+- snoop(&dev->dev, "control write: bRequest=%02x "
+- "bRrequestType=%02x wValue=%04x "
+- "wIndex=%04x wLength=%04x\n",
+- ctrl.bRequest, ctrl.bRequestType, ctrl.wValue,
+- ctrl.wIndex, ctrl.wLength);
+- if (usbfs_snoop) {
+- dev_info(&dev->dev, "control write: data: ");
+- for (j = 0; j < ctrl.wLength; ++j)
+- printk("%02x ", (unsigned char)(tbuf)[j]);
+- printk("\n");
+- }
++ pipe = usb_sndctrlpipe(dev, 0);
++ snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
++
+ usb_unlock_device(dev);
+ i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
+ ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
+ tbuf, ctrl.wLength, tmo);
+ usb_lock_device(dev);
++ snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
+ }
+ free_page((unsigned long)tbuf);
+ if (i < 0 && i != -EPIPE) {
+@@ -774,7 +783,7 @@ static int proc_bulk(struct dev_state *p
+ unsigned int tmo, len1, pipe;
+ int len2;
+ unsigned char *tbuf;
+- int i, j, ret;
++ int i, ret;
+
+ if (copy_from_user(&bulk, arg, sizeof(bulk)))
+ return -EFAULT;
+@@ -801,18 +810,14 @@ static int proc_bulk(struct dev_state *p
+ kfree(tbuf);
+ return -EINVAL;
+ }
+- snoop(&dev->dev, "bulk read: len=0x%02x timeout=%04d\n",
+- bulk.len, bulk.timeout);
++ snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
++
+ usb_unlock_device(dev);
+ i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ usb_lock_device(dev);
++ snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
++
+ if (!i && len2) {
+- if (usbfs_snoop) {
+- dev_info(&dev->dev, "bulk read: data ");
+- for (j = 0; j < len2; ++j)
+- printk("%02x ", (u8)(tbuf)[j]);
+- printk("\n");
+- }
+ if (copy_to_user(bulk.data, tbuf, len2)) {
+ kfree(tbuf);
+ return -EFAULT;
+@@ -825,17 +830,12 @@ static int proc_bulk(struct dev_state *p
+ return -EFAULT;
+ }
+ }
+- snoop(&dev->dev, "bulk write: len=0x%02x timeout=%04d\n",
+- bulk.len, bulk.timeout);
+- if (usbfs_snoop) {
+- dev_info(&dev->dev, "bulk write: data: ");
+- for (j = 0; j < len1; ++j)
+- printk("%02x ", (unsigned char)(tbuf)[j]);
+- printk("\n");
+- }
++ snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
++
+ usb_unlock_device(dev);
+ i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ usb_lock_device(dev);
++ snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
+ }
+ kfree(tbuf);
+ if (i < 0)
+@@ -1053,13 +1053,6 @@ static int proc_do_submiturb(struct dev_
+ is_in = 0;
+ uurb->endpoint &= ~USB_DIR_IN;
+ }
+- snoop(&ps->dev->dev, "control urb: bRequest=%02x "
+- "bRrequestType=%02x wValue=%04x "
+- "wIndex=%04x wLength=%04x\n",
+- dr->bRequest, dr->bRequestType,
+- __le16_to_cpup(&dr->wValue),
+- __le16_to_cpup(&dr->wIndex),
+- __le16_to_cpup(&dr->wLength));
+ break;
+
+ case USBDEVFS_URB_TYPE_BULK:
+@@ -1072,7 +1065,6 @@ static int proc_do_submiturb(struct dev_
+ uurb->number_of_packets = 0;
+ if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
+ return -EINVAL;
+- snoop(&ps->dev->dev, "bulk urb\n");
+ break;
+
+ case USBDEVFS_URB_TYPE_ISO:
+@@ -1104,7 +1096,6 @@ static int proc_do_submiturb(struct dev_
+ return -EINVAL;
+ }
+ uurb->buffer_length = totlen;
+- snoop(&ps->dev->dev, "iso urb\n");
+ break;
+
+ case USBDEVFS_URB_TYPE_INTERRUPT:
+@@ -1113,7 +1104,6 @@ static int proc_do_submiturb(struct dev_
+ return -EINVAL;
+ if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
+ return -EINVAL;
+- snoop(&ps->dev->dev, "interrupt urb\n");
+ break;
+
+ default:
+@@ -1200,11 +1190,14 @@ static int proc_do_submiturb(struct dev_
+ return -EFAULT;
+ }
+ }
+- snoop_urb(as->urb, as->userurb);
++ snoop_urb(ps->dev, as->userurb, as->urb->pipe,
++ as->urb->transfer_buffer_length, 0, SUBMIT);
+ async_newpending(as);
+ if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
+ dev_printk(KERN_DEBUG, &ps->dev->dev,
+ "usbfs: usb_submit_urb returned %d\n", ret);
++ snoop_urb(ps->dev, as->userurb, as->urb->pipe,
++ 0, ret, COMPLETE);
+ async_removepending(as);
+ free_async(as);
+ return ret;
+@@ -1668,7 +1661,7 @@ static int usbdev_ioctl(struct inode *in
+ break;
+
+ case USBDEVFS_REAPURBNDELAY32:
+- snoop(&dev->dev, "%s: REAPURBDELAY32\n", __func__);
++ snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
+ ret = proc_reapurbnonblock_compat(ps, p);
+ break;
+
+@@ -1689,7 +1682,7 @@ static int usbdev_ioctl(struct inode *in
+ break;
+
+ case USBDEVFS_REAPURBNDELAY:
+- snoop(&dev->dev, "%s: REAPURBDELAY\n", __func__);
++ snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
+ ret = proc_reapurbnonblock(ps, p);
+ break;
+
diff --git a/usb/usb-whci-hcd-make-endpoint_reset-method-async.patch b/usb/usb-whci-hcd-make-endpoint_reset-method-async.patch
new file mode 100644
index 00000000000000..fb907d09fb5623
--- /dev/null
+++ b/usb/usb-whci-hcd-make-endpoint_reset-method-async.patch
@@ -0,0 +1,156 @@
+From david.vrabel@csr.com Fri Jul 10 14:38:40 2009
+From: David Vrabel <david.vrabel@csr.com>
+Date: Wed, 24 Jun 2009 18:26:40 +0100
+Subject: USB: whci-hcd: make endpoint_reset method async
+To: Greg KH <greg@kroah.com>
+Message-ID: <4A4261D0.9080006@csr.com>
+
+
+usb_hcd_endpoint_reset() may be called in atomic context and must not
+sleep. So make whci-hcd's endpoint_reset() asynchronous. URBs
+submitted while the reset is in progress will be queued (on the std
+list) and transfers will resume once the reset is complete.
+
+Signed-off-by: David Vrabel <david.vrabel@csr.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/host/whci/asl.c | 12 +++++++++++-
+ drivers/usb/host/whci/hcd.c | 8 ++++++--
+ drivers/usb/host/whci/pzl.c | 12 +++++++++++-
+ drivers/usb/host/whci/qset.c | 4 ++--
+ drivers/usb/host/whci/whci-hc.h | 1 +
+ 5 files changed, 31 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/host/whci/asl.c
++++ b/drivers/usb/host/whci/asl.c
+@@ -227,11 +227,21 @@ void scan_async_work(struct work_struct
+ /*
+ * Now that the ASL is updated, complete the removal of any
+ * removed qsets.
++ *
++ * If the qset was to be reset, do so and reinsert it into the
++ * ASL if it has pending transfers.
+ */
+ spin_lock_irq(&whc->lock);
+
+ list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) {
+ qset_remove_complete(whc, qset);
++ if (qset->reset) {
++ qset_reset(whc, qset);
++ if (!list_empty(&qset->stds)) {
++ asl_qset_insert_begin(whc, qset);
++ queue_work(whc->workqueue, &whc->async_work);
++ }
++ }
+ }
+
+ spin_unlock_irq(&whc->lock);
+@@ -267,7 +277,7 @@ int asl_urb_enqueue(struct whc *whc, str
+ else
+ err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
+ if (!err) {
+- if (!qset->in_sw_list)
++ if (!qset->in_sw_list && !qset->remove)
+ asl_qset_insert_begin(whc, qset);
+ } else
+ usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
+--- a/drivers/usb/host/whci/hcd.c
++++ b/drivers/usb/host/whci/hcd.c
+@@ -192,19 +192,23 @@ static void whc_endpoint_reset(struct us
+ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+ struct whc *whc = wusbhc_to_whc(wusbhc);
+ struct whc_qset *qset;
++ unsigned long flags;
++
++ spin_lock_irqsave(&whc->lock, flags);
+
+ qset = ep->hcpriv;
+ if (qset) {
+ qset->remove = 1;
++ qset->reset = 1;
+
+ if (usb_endpoint_xfer_bulk(&ep->desc)
+ || usb_endpoint_xfer_control(&ep->desc))
+ queue_work(whc->workqueue, &whc->async_work);
+ else
+ queue_work(whc->workqueue, &whc->periodic_work);
+-
+- qset_reset(whc, qset);
+ }
++
++ spin_unlock_irqrestore(&whc->lock, flags);
+ }
+
+
+--- a/drivers/usb/host/whci/pzl.c
++++ b/drivers/usb/host/whci/pzl.c
+@@ -255,11 +255,21 @@ void scan_periodic_work(struct work_stru
+ /*
+ * Now that the PZL is updated, complete the removal of any
+ * removed qsets.
++ *
++ * If the qset was to be reset, do so and reinsert it into the
++ * PZL if it has pending transfers.
+ */
+ spin_lock_irq(&whc->lock);
+
+ list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
+ qset_remove_complete(whc, qset);
++ if (qset->reset) {
++ qset_reset(whc, qset);
++ if (!list_empty(&qset->stds)) {
++ qset_insert_in_sw_list(whc, qset);
++ queue_work(whc->workqueue, &whc->periodic_work);
++ }
++ }
+ }
+
+ spin_unlock_irq(&whc->lock);
+@@ -295,7 +305,7 @@ int pzl_urb_enqueue(struct whc *whc, str
+ else
+ err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
+ if (!err) {
+- if (!qset->in_sw_list)
++ if (!qset->in_sw_list && !qset->remove)
+ qset_insert_in_sw_list(whc, qset);
+ } else
+ usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
+--- a/drivers/usb/host/whci/qset.c
++++ b/drivers/usb/host/whci/qset.c
+@@ -103,7 +103,6 @@ static void qset_fill_qh(struct whc_qset
+ void qset_clear(struct whc *whc, struct whc_qset *qset)
+ {
+ qset->td_start = qset->td_end = qset->ntds = 0;
+- qset->remove = 0;
+
+ qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T);
+ qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK;
+@@ -125,7 +124,7 @@ void qset_clear(struct whc *whc, struct
+ */
+ void qset_reset(struct whc *whc, struct whc_qset *qset)
+ {
+- wait_for_completion(&qset->remove_complete);
++ qset->reset = 0;
+
+ qset->qh.status &= ~QH_STATUS_SEQ_MASK;
+ qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
+@@ -156,6 +155,7 @@ struct whc_qset *get_qset(struct whc *wh
+
+ void qset_remove_complete(struct whc *whc, struct whc_qset *qset)
+ {
++ qset->remove = 0;
+ list_del_init(&qset->list_node);
+ complete(&qset->remove_complete);
+ }
+--- a/drivers/usb/host/whci/whci-hc.h
++++ b/drivers/usb/host/whci/whci-hc.h
+@@ -264,6 +264,7 @@ struct whc_qset {
+ unsigned in_sw_list:1;
+ unsigned in_hw_list:1;
+ unsigned remove:1;
++ unsigned reset:1;
+ struct urb *pause_after_urb;
+ struct completion remove_complete;
+ int max_burst;