aboutsummaryrefslogtreecommitdiffstats
path: root/usb
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2009-07-10 15:54:59 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2009-07-10 15:54:59 -0700
commitc37e90a77bc09d5418453bac39282b4e6c6575c6 (patch)
tree93ce5a83676b67961ee0a56b3c1f41647c98f8c9 /usb
parentdbae88ae94dd4f1faf09236ad97dd63d4e452aa5 (diff)
downloadpatches-c37e90a77bc09d5418453bac39282b4e6c6575c6.tar.gz
more patches
Diffstat (limited to 'usb')
-rw-r--r--usb/usb-at91_udc-at91sam9g20-updates.patch88
-rw-r--r--usb/usb-gadget-pxa25x-basic-transceiver-support.patch147
-rw-r--r--usb/usb-ldusb-should-signal-an-error-in-poll-if-the-device-is-disconnected.patch39
-rw-r--r--usb/usb-legousbtower-make-poll-notice-disconnect.patch42
-rw-r--r--usb/usb-musb-cleanup-the-nop-registration-for-omap3evm.patch94
-rw-r--r--usb/usb-serial-full-autosuspend-support-for-the-option-driver.patch335
-rw-r--r--usb/usb-suspend-resume-support-for-usbtmc.patch46
-rw-r--r--usb/usb-usb-serial-remove-unused-variables.patch41
-rw-r--r--usb/usb-usbtmc-can-do-io-to-device-after-disconnect.patch89
9 files changed, 833 insertions, 88 deletions
diff --git a/usb/usb-at91_udc-at91sam9g20-updates.patch b/usb/usb-at91_udc-at91sam9g20-updates.patch
deleted file mode 100644
index b4b5e0f2dc869c..00000000000000
--- a/usb/usb-at91_udc-at91sam9g20-updates.patch
+++ /dev/null
@@ -1,88 +0,0 @@
-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-gadget-pxa25x-basic-transceiver-support.patch b/usb/usb-gadget-pxa25x-basic-transceiver-support.patch
new file mode 100644
index 00000000000000..0df8e3fa473cf5
--- /dev/null
+++ b/usb/usb-gadget-pxa25x-basic-transceiver-support.patch
@@ -0,0 +1,147 @@
+From david-b@pacbell.net Fri Jul 10 15:11:17 2009
+From: Philipp Zabel <philipp.zabel@gmail.com>
+Date: Wed, 1 Jul 2009 03:46:25 -0700
+Subject: USB: gadget: pxa25x: basic transceiver support
+To: Greg KH <greg@kroah.com>
+Cc: linux-usb@vger.kernel.org, Eric Miao <eric.y.miao@gmail.com>, phi\@pogo
+Message-ID: <200907010346.25776.david-b@pacbell.net>
+Content-Disposition: inline
+
+
+From: Philipp Zabel <philipp.zabel@gmail.com>
+
+This adds very basic otg_transceiver support, with vbus_session
+and vbus_draw callbacks.
+
+Now VBUS sensing can be handled by an external driver which registers
+the otg_transceiver interface. It also allows gadget drivers to configure
+the current drawn from VBUS. The UDC driver just passes their requests
+along to the transceiver driver.
+
+Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/pxa25x_udc.c | 49 ++++++++++++++++++++++++++++++++++++----
+ drivers/usb/gadget/pxa25x_udc.h | 1
+ 2 files changed, 46 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/gadget/pxa25x_udc.c
++++ b/drivers/usb/gadget/pxa25x_udc.c
+@@ -56,6 +56,7 @@
+
+ #include <linux/usb/ch9.h>
+ #include <linux/usb/gadget.h>
++#include <linux/usb/otg.h>
+
+ /*
+ * This driver is PXA25x only. Grab the right register definitions.
+@@ -1008,15 +1009,27 @@ static int pxa25x_udc_pullup(struct usb_
+ return 0;
+ }
+
++/* boards may consume current from VBUS, up to 100-500mA based on config.
++ * the 500uA suspend ceiling means that exclusively vbus-powered PXA designs
++ * violate USB specs.
++ */
++static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
++{
++ struct pxa25x_udc *udc;
++
++ udc = container_of(_gadget, struct pxa25x_udc, gadget);
++
++ if (udc->transceiver)
++ return otg_set_power(udc->transceiver, mA);
++ return -EOPNOTSUPP;
++}
++
+ static const struct usb_gadget_ops pxa25x_udc_ops = {
+ .get_frame = pxa25x_udc_get_frame,
+ .wakeup = pxa25x_udc_wakeup,
+ .vbus_session = pxa25x_udc_vbus_session,
+ .pullup = pxa25x_udc_pullup,
+-
+- // .vbus_draw ... boards may consume current from VBUS, up to
+- // 100-500mA based on config. the 500uA suspend ceiling means
+- // that exclusively vbus-powered PXA designs violate USB specs.
++ .vbus_draw = pxa25x_udc_vbus_draw,
+ };
+
+ /*-------------------------------------------------------------------------*/
+@@ -1303,9 +1316,23 @@ fail:
+ * for set_configuration as well as eventual disconnect.
+ */
+ DMSG("registered gadget driver '%s'\n", driver->driver.name);
++
++ /* connect to bus through transceiver */
++ if (dev->transceiver) {
++ retval = otg_set_peripheral(dev->transceiver, &dev->gadget);
++ if (retval) {
++ DMSG("can't bind to transceiver\n");
++ if (driver->unbind)
++ driver->unbind(&dev->gadget);
++ goto bind_fail;
++ }
++ }
++
+ pullup(dev);
+ dump_state(dev);
+ return 0;
++bind_fail:
++ return retval;
+ }
+ EXPORT_SYMBOL(usb_gadget_register_driver);
+
+@@ -1351,6 +1378,9 @@ int usb_gadget_unregister_driver(struct
+ stop_activity(dev, driver);
+ local_irq_enable();
+
++ if (dev->transceiver)
++ (void) otg_set_peripheral(dev->transceiver, NULL);
++
+ driver->unbind(&dev->gadget);
+ dev->gadget.dev.driver = NULL;
+ dev->driver = NULL;
+@@ -2162,6 +2192,8 @@ static int __init pxa25x_udc_probe(struc
+ dev->dev = &pdev->dev;
+ dev->mach = pdev->dev.platform_data;
+
++ dev->transceiver = otg_get_transceiver();
++
+ if (gpio_is_valid(dev->mach->gpio_vbus)) {
+ if ((retval = gpio_request(dev->mach->gpio_vbus,
+ "pxa25x_udc GPIO VBUS"))) {
+@@ -2264,6 +2296,10 @@ lubbock_fail0:
+ if (gpio_is_valid(dev->mach->gpio_vbus))
+ gpio_free(dev->mach->gpio_vbus);
+ err_gpio_vbus:
++ if (dev->transceiver) {
++ otg_put_transceiver(dev->transceiver);
++ dev->transceiver = NULL;
++ }
+ clk_put(dev->clk);
+ err_clk:
+ return retval;
+@@ -2305,6 +2341,11 @@ static int __exit pxa25x_udc_remove(stru
+
+ clk_put(dev->clk);
+
++ if (dev->transceiver) {
++ otg_put_transceiver(dev->transceiver);
++ dev->transceiver = NULL;
++ }
++
+ platform_set_drvdata(pdev, NULL);
+ the_controller = NULL;
+ return 0;
+--- a/drivers/usb/gadget/pxa25x_udc.h
++++ b/drivers/usb/gadget/pxa25x_udc.h
+@@ -128,6 +128,7 @@ struct pxa25x_udc {
+ struct device *dev;
+ struct clk *clk;
+ struct pxa2xx_udc_mach_info *mach;
++ struct otg_transceiver *transceiver;
+ u64 dma_mask;
+ struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS];
+
diff --git a/usb/usb-ldusb-should-signal-an-error-in-poll-if-the-device-is-disconnected.patch b/usb/usb-ldusb-should-signal-an-error-in-poll-if-the-device-is-disconnected.patch
new file mode 100644
index 00000000000000..9212fde6d03f83
--- /dev/null
+++ b/usb/usb-ldusb-should-signal-an-error-in-poll-if-the-device-is-disconnected.patch
@@ -0,0 +1,39 @@
+From oliver@neukum.org Fri Jul 10 15:18:16 2009
+From: Oliver Neukum <oliver@neukum.org>
+Date: Thu, 2 Jul 2009 17:01:06 +0200
+Subject: USB: ldusb should signal an error in poll if the device is disconnected
+To: Michael Hund <mhund@ld-didactic.de>, greg@kroah.com, USB list <linux-usb@vger.kernel.org>
+Message-ID: <200907021701.06689.oliver@neukum.org>
+
+
+poll() should test for a disconnection of the device.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/ldusb.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/usb/misc/ldusb.c
++++ b/drivers/usb/misc/ldusb.c
+@@ -412,6 +412,9 @@ static unsigned int ld_usb_poll(struct f
+
+ dev = file->private_data;
+
++ if (!dev->intf)
++ return POLLERR | POLLHUP;
++
+ poll_wait(file, &dev->read_wait, wait);
+ poll_wait(file, &dev->write_wait, wait);
+
+@@ -767,6 +770,9 @@ static void ld_usb_disconnect(struct usb
+ ld_usb_delete(dev);
+ } else {
+ dev->intf = NULL;
++ /* wake up pollers */
++ wake_up_interruptible_all(&dev->read_wait);
++ wake_up_interruptible_all(&dev->write_wait);
+ mutex_unlock(&dev->mutex);
+ }
+
diff --git a/usb/usb-legousbtower-make-poll-notice-disconnect.patch b/usb/usb-legousbtower-make-poll-notice-disconnect.patch
new file mode 100644
index 00000000000000..f388220a94f693
--- /dev/null
+++ b/usb/usb-legousbtower-make-poll-notice-disconnect.patch
@@ -0,0 +1,42 @@
+From oliver@neukum.org Fri Jul 10 15:17:50 2009
+From: Oliver Neukum <oliver@neukum.org>
+Date: Thu, 2 Jul 2009 12:07:07 +0200
+Subject: USB: legousbtower: make poll notice disconnect
+To: greg@kroah.com, USB list <linux-usb@vger.kernel.org>, starblue@users.sourceforge.net, davidgsf@sourceforge.net
+Message-ID: <200907021207.07770.oliver@neukum.org>
+Content-Disposition: inline
+
+
+poll needs to return an error if a device is disconnected
+ - make poll check for device's presence
+ - wake all waiters in disconnect
+
+Signed-off-by: Oliver Neukum <oliver@neukum.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/legousbtower.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/usb/misc/legousbtower.c
++++ b/drivers/usb/misc/legousbtower.c
+@@ -552,6 +552,9 @@ static unsigned int tower_poll (struct f
+
+ dev = file->private_data;
+
++ if (!dev->udev)
++ return POLLERR | POLLHUP;
++
+ poll_wait(file, &dev->read_wait, wait);
+ poll_wait(file, &dev->write_wait, wait);
+
+@@ -1025,6 +1028,9 @@ static void tower_disconnect (struct usb
+ tower_delete (dev);
+ } else {
+ dev->udev = NULL;
++ /* wake up pollers */
++ wake_up_interruptible_all(&dev->read_wait);
++ wake_up_interruptible_all(&dev->write_wait);
+ mutex_unlock(&dev->lock);
+ }
+
diff --git a/usb/usb-musb-cleanup-the-nop-registration-for-omap3evm.patch b/usb/usb-musb-cleanup-the-nop-registration-for-omap3evm.patch
new file mode 100644
index 00000000000000..fe6004bb0f6abe
--- /dev/null
+++ b/usb/usb-musb-cleanup-the-nop-registration-for-omap3evm.patch
@@ -0,0 +1,94 @@
+From ajay.gupta@ti.com Fri Jul 10 15:20:10 2009
+From: Ajay Kumar Gupta <ajay.gupta@ti.com>
+Date: Fri, 3 Jul 2009 14:30:26 +0530
+Subject: USB: musb: cleanup the nop registration for OMAP3EVM
+To: linux-usb@vger.kernel.org
+Cc: linux-omap@vger.kernel.org, david-b@pacbell.net, felipe.balbi@nokia.com, tony@atomide.com, Ajay Kumar Gupta <ajay.gupta@ti.com>
+Message-ID: <1246611626-28137-1-git-send-email-ajay.gupta@ti.com>
+
+
+OMAP3EVM uses ISP1504 phy which doesn't require any
+programming and thus has to use NOP otg transceiver.
+
+Cleanups being done:
+ - Remove unwanted code in usb-musb.c file
+ - Register nop in OMAP3EVM board file using
+ usb_nop_xceiv_register().
+ - Select NOP_USB_XCEIV for OMAP3EVM boards.
+
+Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
+Acked-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/arm/mach-omap2/board-omap3evm.c | 3 +++
+ arch/arm/mach-omap2/usb-musb.c | 21 ---------------------
+ drivers/usb/musb/Kconfig | 1 +
+ 3 files changed, 4 insertions(+), 21 deletions(-)
+
+--- a/arch/arm/mach-omap2/board-omap3evm.c
++++ b/arch/arm/mach-omap2/board-omap3evm.c
+@@ -25,6 +25,7 @@
+ #include <linux/spi/spi.h>
+ #include <linux/spi/ads7846.h>
+ #include <linux/i2c/twl4030.h>
++#include <linux/usb/otg.h>
+
+ #include <mach/hardware.h>
+ #include <asm/mach-types.h>
+@@ -307,6 +308,8 @@ static void __init omap3_evm_init(void)
+ ARRAY_SIZE(omap3evm_spi_board_info));
+
+ omap_serial_init();
++ /* OMAP3EVM uses ISP1504 phy and thus has to register nop transceiver */
++ usb_nop_xceiv_register();
+ usb_musb_init();
+ ads7846_dev_init();
+ }
+--- a/arch/arm/mach-omap2/usb-musb.c
++++ b/arch/arm/mach-omap2/usb-musb.c
+@@ -155,20 +155,6 @@ static struct platform_device musb_devic
+ .resource = musb_resources,
+ };
+
+-#ifdef CONFIG_NOP_USB_XCEIV
+-static u64 nop_xceiv_dmamask = DMA_BIT_MASK(32);
+-
+-static struct platform_device nop_xceiv_device = {
+- .name = "nop_usb_xceiv",
+- .id = -1,
+- .dev = {
+- .dma_mask = &nop_xceiv_dmamask,
+- .coherent_dma_mask = DMA_BIT_MASK(32),
+- .platform_data = NULL,
+- },
+-};
+-#endif
+-
+ void __init usb_musb_init(void)
+ {
+ if (cpu_is_omap243x())
+@@ -183,13 +169,6 @@ void __init usb_musb_init(void)
+ */
+ musb_plat.clock = "ick";
+
+-#ifdef CONFIG_NOP_USB_XCEIV
+- if (platform_device_register(&nop_xceiv_device) < 0) {
+- printk(KERN_ERR "Unable to register NOP-XCEIV device\n");
+- return;
+- }
+-#endif
+-
+ if (platform_device_register(&musb_device) < 0) {
+ printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
+ return;
+--- a/drivers/usb/musb/Kconfig
++++ b/drivers/usb/musb/Kconfig
+@@ -11,6 +11,7 @@ config USB_MUSB_HDRC
+ depends on (USB || USB_GADGET) && HAVE_CLK
+ depends on !SUPERH
+ select NOP_USB_XCEIV if ARCH_DAVINCI
++ select NOP_USB_XCEIV if MACH_OMAP3EVM
+ select TWL4030_USB if MACH_OMAP_3430SDP
+ select USB_OTG_UTILS
+ tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
diff --git a/usb/usb-serial-full-autosuspend-support-for-the-option-driver.patch b/usb/usb-serial-full-autosuspend-support-for-the-option-driver.patch
new file mode 100644
index 00000000000000..adc9b123f35cb6
--- /dev/null
+++ b/usb/usb-serial-full-autosuspend-support-for-the-option-driver.patch
@@ -0,0 +1,335 @@
+From oliver@neukum.org Fri Jul 10 15:11:40 2009
+From: Oliver Neukum <oliver@neukum.org>
+Date: Wed, 1 Jul 2009 16:00:32 +0200
+Subject: USB: serial: full autosuspend support for the option driver
+To: zhao.ming9@zte.com.cn, greg@kroah.com, USB list <linux-usb@vger.kernel.org>
+Message-ID: <200907011600.33423.oliver@neukum.org>
+
+
+this adds autosupport usable even in an always online mode.
+
+- enables remote wakeup on open
+- autoresume for sending
+- timeout based autosuspend if nothing is sent or recieved
+- autosuspend without remote wakeup support on open/close
+
+Signed-off-by: Oliver Neukum <oliver@neukum.org>
+Tested-off-by: Zhao Ming <zhao.ming9@zte.com.cn>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/option.c | 134 +++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 115 insertions(+), 19 deletions(-)
+
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -559,6 +559,7 @@ static struct usb_driver option_driver =
+ .resume = usb_serial_resume,
+ .id_table = option_ids,
+ .no_dynamic_id = 1,
++ .supports_autosuspend = 1,
+ };
+
+ /* The card has three separate interfaces, which the serial driver
+@@ -601,6 +602,12 @@ static int debug;
+ #define IN_BUFLEN 4096
+ #define OUT_BUFLEN 4096
+
++struct option_intf_private {
++ spinlock_t susp_lock;
++ unsigned int suspended:1;
++ int in_flight;
++};
++
+ struct option_port_private {
+ /* Input endpoints and buffer for this port */
+ struct urb *in_urbs[N_IN_URB];
+@@ -609,6 +616,8 @@ struct option_port_private {
+ struct urb *out_urbs[N_OUT_URB];
+ u8 *out_buffer[N_OUT_URB];
+ unsigned long out_busy; /* Bit vector of URBs in use */
++ int opened;
++ struct usb_anchor delayed;
+
+ /* Settings for the port */
+ int rts_state; /* Handshaking pins (outputs) */
+@@ -655,12 +664,17 @@ module_exit(option_exit);
+ static int option_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+ {
++ struct option_intf_private *data;
+ /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */
+ if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID &&
+ serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 &&
+ serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8)
+ return -ENODEV;
+
++ data = serial->private = kzalloc(sizeof(struct option_intf_private), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++ spin_lock_init(&data->susp_lock);
+ return 0;
+ }
+
+@@ -717,12 +731,15 @@ static int option_write(struct tty_struc
+ const unsigned char *buf, int count)
+ {
+ struct option_port_private *portdata;
++ struct option_intf_private *intfdata;
+ int i;
+ int left, todo;
+ struct urb *this_urb = NULL; /* spurious */
+ int err;
++ unsigned long flags;
+
+ portdata = usb_get_serial_port_data(port);
++ intfdata = port->serial->private;
+
+ dbg("%s: write (%d chars)", __func__, count);
+
+@@ -744,17 +761,33 @@ static int option_write(struct tty_struc
+ dbg("%s: endpoint %d buf %d", __func__,
+ usb_pipeendpoint(this_urb->pipe), i);
+
++ err = usb_autopm_get_interface_async(port->serial->interface);
++ if (err < 0)
++ break;
++
+ /* send the data */
+ memcpy(this_urb->transfer_buffer, buf, todo);
+ this_urb->transfer_buffer_length = todo;
+
+- err = usb_submit_urb(this_urb, GFP_ATOMIC);
+- if (err) {
+- dbg("usb_submit_urb %p (write bulk) failed "
+- "(%d)", this_urb, err);
+- clear_bit(i, &portdata->out_busy);
+- continue;
++ spin_lock_irqsave(&intfdata->susp_lock, flags);
++ if (intfdata->suspended) {
++ usb_anchor_urb(this_urb, &portdata->delayed);
++ spin_unlock_irqrestore(&intfdata->susp_lock, flags);
++ } else {
++ intfdata->in_flight++;
++ spin_unlock_irqrestore(&intfdata->susp_lock, flags);
++ err = usb_submit_urb(this_urb, GFP_ATOMIC);
++ if (err) {
++ dbg("usb_submit_urb %p (write bulk) failed "
++ "(%d)", this_urb, err);
++ clear_bit(i, &portdata->out_busy);
++ spin_lock_irqsave(&intfdata->susp_lock, flags);
++ intfdata->in_flight--;
++ spin_unlock_irqrestore(&intfdata->susp_lock, flags);
++ continue;
++ }
+ }
++
+ portdata->tx_start_time[i] = jiffies;
+ buf += todo;
+ left -= todo;
+@@ -798,7 +831,10 @@ static void option_indat_callback(struct
+ if (err)
+ printk(KERN_ERR "%s: resubmit read urb failed. "
+ "(%d)", __func__, err);
++ else
++ usb_mark_last_busy(port->serial->dev);
+ }
++
+ }
+ return;
+ }
+@@ -807,15 +843,21 @@ static void option_outdat_callback(struc
+ {
+ struct usb_serial_port *port;
+ struct option_port_private *portdata;
++ struct option_intf_private *intfdata;
+ int i;
+
+ dbg("%s", __func__);
+
+ port = urb->context;
++ intfdata = port->serial->private;
+
+ usb_serial_port_softint(port);
+-
++ usb_autopm_put_interface_async(port->serial->interface);
+ portdata = usb_get_serial_port_data(port);
++ spin_lock(&intfdata->susp_lock);
++ intfdata->in_flight--;
++ spin_unlock(&intfdata->susp_lock);
++
+ for (i = 0; i < N_OUT_URB; ++i) {
+ if (portdata->out_urbs[i] == urb) {
+ smp_mb__before_clear_bit();
+@@ -831,7 +873,6 @@ static void option_instat_callback(struc
+ int status = urb->status;
+ struct usb_serial_port *port = urb->context;
+ struct option_port_private *portdata = usb_get_serial_port_data(port);
+- struct usb_serial *serial = port->serial;
+
+ dbg("%s", __func__);
+ dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata);
+@@ -927,11 +968,13 @@ static int option_open(struct tty_struct
+ struct usb_serial_port *port, struct file *filp)
+ {
+ struct option_port_private *portdata;
++ struct option_intf_private *intfdata;
+ struct usb_serial *serial = port->serial;
+ int i, err;
+ struct urb *urb;
+
+ portdata = usb_get_serial_port_data(port);
++ intfdata = port->serial->private;
+
+ dbg("%s", __func__);
+
+@@ -950,6 +993,12 @@ static int option_open(struct tty_struct
+
+ option_send_setup(port);
+
++ serial->interface->needs_remote_wakeup = 1;
++ spin_lock_irq(&intfdata->susp_lock);
++ portdata->opened = 1;
++ spin_unlock_irq(&intfdata->susp_lock);
++ usb_autopm_put_interface(serial->interface);
++
+ return 0;
+ }
+
+@@ -974,16 +1023,23 @@ static void option_close(struct usb_seri
+ int i;
+ struct usb_serial *serial = port->serial;
+ struct option_port_private *portdata;
++ struct option_intf_private *intfdata = port->serial->private;
+
+ dbg("%s", __func__);
+ portdata = usb_get_serial_port_data(port);
+
+ if (serial->dev) {
+ /* Stop reading/writing urbs */
++ spin_lock_irq(&intfdata->susp_lock);
++ portdata->opened = 0;
++ spin_unlock_irq(&intfdata->susp_lock);
++
+ for (i = 0; i < N_IN_URB; i++)
+ usb_kill_urb(portdata->in_urbs[i]);
+ for (i = 0; i < N_OUT_URB; i++)
+ usb_kill_urb(portdata->out_urbs[i]);
++ usb_autopm_get_interface(serial->interface);
++ serial->interface->needs_remote_wakeup = 0;
+ }
+ }
+
+@@ -1088,6 +1144,7 @@ static int option_startup(struct usb_ser
+ __func__, i);
+ return 1;
+ }
++ init_usb_anchor(&portdata->delayed);
+
+ for (j = 0; j < N_IN_URB; j++) {
+ buffer = (u8 *)__get_free_page(GFP_KERNEL);
+@@ -1189,18 +1246,52 @@ static void option_release(struct usb_se
+
+ static int option_suspend(struct usb_serial *serial, pm_message_t message)
+ {
++ struct option_intf_private *intfdata = serial->private;
++ int b;
++
+ dbg("%s entered", __func__);
++
++ if (serial->dev->auto_pm) {
++ spin_lock_irq(&intfdata->susp_lock);
++ b = intfdata->in_flight;
++ spin_unlock_irq(&intfdata->susp_lock);
++
++ if (b)
++ return -EBUSY;
++ }
++
++ spin_lock_irq(&intfdata->susp_lock);
++ intfdata->suspended = 1;
++ spin_unlock_irq(&intfdata->susp_lock);
+ stop_read_write_urbs(serial);
+
+ return 0;
+ }
+
++static void play_delayed(struct usb_serial_port *port)
++{
++ struct option_intf_private *data;
++ struct option_port_private *portdata;
++ struct urb *urb;
++ int err;
++
++ portdata = usb_get_serial_port_data(port);
++ data = port->serial->private;
++ while ((urb = usb_get_from_anchor(&portdata->delayed))) {
++ err = usb_submit_urb(urb, GFP_ATOMIC);
++ if (!err)
++ data->in_flight++;
++ }
++}
++
+ static int option_resume(struct usb_serial *serial)
+ {
+- int err, i, j;
++ int i, j;
+ struct usb_serial_port *port;
+- struct urb *urb;
++ struct option_intf_private *intfdata = serial->private;
+ struct option_port_private *portdata;
++ struct urb *urb;
++ int err = 0;
+
+ dbg("%s entered", __func__);
+ /* get the interrupt URBs resubmitted unconditionally */
+@@ -1215,7 +1306,7 @@ static int option_resume(struct usb_seri
+ if (err < 0) {
+ err("%s: Error %d for interrupt URB of port%d",
+ __func__, err, i);
+- return err;
++ goto err_out;
+ }
+ }
+
+@@ -1223,27 +1314,32 @@ static int option_resume(struct usb_seri
+ /* walk all ports */
+ port = serial->port[i];
+ portdata = usb_get_serial_port_data(port);
+- mutex_lock(&port->mutex);
+
+ /* skip closed ports */
+- if (!port->port.count) {
+- mutex_unlock(&port->mutex);
++ spin_lock_irq(&intfdata->susp_lock);
++ if (!portdata->opened) {
++ spin_unlock_irq(&intfdata->susp_lock);
+ continue;
+ }
+
+ for (j = 0; j < N_IN_URB; j++) {
+ urb = portdata->in_urbs[j];
+- err = usb_submit_urb(urb, GFP_NOIO);
++ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0) {
+- mutex_unlock(&port->mutex);
+ err("%s: Error %d for bulk URB %d",
+ __func__, err, i);
+- return err;
++ spin_unlock_irq(&intfdata->susp_lock);
++ goto err_out;
+ }
+ }
+- mutex_unlock(&port->mutex);
++ play_delayed(port);
++ spin_unlock_irq(&intfdata->susp_lock);
+ }
+- return 0;
++ spin_lock_irq(&intfdata->susp_lock);
++ intfdata->suspended = 0;
++ spin_unlock_irq(&intfdata->susp_lock);
++err_out:
++ return err;
+ }
+
+ MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/usb/usb-suspend-resume-support-for-usbtmc.patch b/usb/usb-suspend-resume-support-for-usbtmc.patch
new file mode 100644
index 00000000000000..2479e93598ecad
--- /dev/null
+++ b/usb/usb-suspend-resume-support-for-usbtmc.patch
@@ -0,0 +1,46 @@
+From oliver@neukum.org Fri Jul 10 15:17:33 2009
+From: Oliver Neukum <oliver@neukum.org>
+Date: Thu, 2 Jul 2009 11:44:33 +0200
+Subject: USB: suspend/resume support for usbtmc
+To: greg@kroah.com, USB list <linux-usb@vger.kernel.org>
+Message-ID: <200907021144.33515.oliver@neukum.org>
+
+
+a class driver should have suspend/resume. This makes sure we
+don't see a virtual disconnect unnecessarily.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/class/usbtmc.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/class/usbtmc.c
++++ b/drivers/usb/class/usbtmc.c
+@@ -1087,11 +1087,24 @@ static void usbtmc_disconnect(struct usb
+ kref_put(&data->kref, usbtmc_delete);
+ }
+
++static int usbtmc_suspend (struct usb_interface *intf, pm_message_t message)
++{
++ /* this driver does not have pending URBs */
++ return 0;
++}
++
++static int usbtmc_resume (struct usb_interface *intf)
++{
++ return 0;
++}
++
+ static struct usb_driver usbtmc_driver = {
+ .name = "usbtmc",
+ .id_table = usbtmc_devices,
+ .probe = usbtmc_probe,
+- .disconnect = usbtmc_disconnect
++ .disconnect = usbtmc_disconnect,
++ .suspend = usbtmc_suspend,
++ .resume = usbtmc_resume,
+ };
+
+ static int __init usbtmc_init(void)
diff --git a/usb/usb-usb-serial-remove-unused-variables.patch b/usb/usb-usb-serial-remove-unused-variables.patch
new file mode 100644
index 00000000000000..1eb5fbf44f83f5
--- /dev/null
+++ b/usb/usb-usb-serial-remove-unused-variables.patch
@@ -0,0 +1,41 @@
+From jirislaby@gmail.com Fri Jul 10 15:15:05 2009
+From: Jiri Slaby <jirislaby@gmail.com>
+Date: Fri, 3 Jul 2009 23:09:41 +0200
+Subject: USB: usb-serial, remove unused variables
+To: gregkh@suse.de
+Message-ID: <1246655381-18007-1-git-send-email-jirislaby@gmail.com>
+
+
+There are some unused variables in serial_do_down. Remove them.
+
+Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/usb-serial.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -281,8 +281,6 @@ bailout_serial_put:
+ static void serial_do_down(struct usb_serial_port *port)
+ {
+ struct usb_serial_driver *drv = port->serial->type;
+- struct usb_serial *serial;
+- struct module *owner;
+
+ /* The console is magical, do not hang up the console hardware
+ or there will be tears */
+@@ -290,12 +288,8 @@ static void serial_do_down(struct usb_se
+ return;
+
+ mutex_lock(&port->mutex);
+- serial = port->serial;
+- owner = serial->type->driver.owner;
+-
+ if (drv->close)
+ drv->close(port);
+-
+ mutex_unlock(&port->mutex);
+ }
+
diff --git a/usb/usb-usbtmc-can-do-io-to-device-after-disconnect.patch b/usb/usb-usbtmc-can-do-io-to-device-after-disconnect.patch
new file mode 100644
index 00000000000000..30f03951812756
--- /dev/null
+++ b/usb/usb-usbtmc-can-do-io-to-device-after-disconnect.patch
@@ -0,0 +1,89 @@
+From oliver@neukum.org Fri Jul 10 15:17:05 2009
+From: Oliver Neukum <oliver@neukum.org>
+Date: Thu, 2 Jul 2009 11:36:30 +0200
+Subject: USB: usbtmc can do IO to device after disconnect
+To: greg@kroah.com, USB list <linux-usb@vger.kernel.org>
+Message-ID: <200907021136.30963.oliver@neukum.org>
+
+
+usbtmc will happily complete read/write requests even after disconnect
+has returned. The fix is to introduce a flag.
+
+
+Signed-off-by: Oliver Neukum <oliver@neukum.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/class/usbtmc.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+--- a/drivers/usb/class/usbtmc.c
++++ b/drivers/usb/class/usbtmc.c
+@@ -86,6 +86,8 @@ struct usbtmc_device_data {
+ bool TermCharEnabled;
+ bool auto_abort;
+
++ bool zombie; /* fd of disconnected device */
++
+ struct usbtmc_dev_capabilities capabilities;
+ struct kref kref;
+ struct mutex io_mutex; /* only one i/o function running at a time */
+@@ -384,6 +386,10 @@ static ssize_t usbtmc_read(struct file *
+ return -ENOMEM;
+
+ mutex_lock(&data->io_mutex);
++ if (data->zombie) {
++ retval = -ENODEV;
++ goto exit;
++ }
+
+ remaining = count;
+ done = 0;
+@@ -496,6 +502,10 @@ static ssize_t usbtmc_write(struct file
+ return -ENOMEM;
+
+ mutex_lock(&data->io_mutex);
++ if (data->zombie) {
++ retval = -ENODEV;
++ goto exit;
++ }
+
+ remaining = count;
+ done = 0;
+@@ -925,6 +935,10 @@ static long usbtmc_ioctl(struct file *fi
+
+ data = file->private_data;
+ mutex_lock(&data->io_mutex);
++ if (data->zombie) {
++ retval = -ENODEV;
++ goto skip_io_on_zombie;
++ }
+
+ switch (cmd) {
+ case USBTMC_IOCTL_CLEAR_OUT_HALT:
+@@ -952,6 +966,7 @@ static long usbtmc_ioctl(struct file *fi
+ break;
+ }
+
++skip_io_on_zombie:
+ mutex_unlock(&data->io_mutex);
+ return retval;
+ }
+@@ -995,6 +1010,7 @@ static int usbtmc_probe(struct usb_inter
+ usb_set_intfdata(intf, data);
+ kref_init(&data->kref);
+ mutex_init(&data->io_mutex);
++ data->zombie = 0;
+
+ /* Initialize USBTMC bTag and other fields */
+ data->bTag = 1;
+@@ -1065,6 +1081,9 @@ static void usbtmc_disconnect(struct usb
+ usb_deregister_dev(intf, &usbtmc_class);
+ sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
+ sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
++ mutex_lock(&data->io_mutex);
++ data->zombie = 1;
++ mutex_unlock(&data->io_mutex);
+ kref_put(&data->kref, usbtmc_delete);
+ }
+