diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2009-07-10 15:54:59 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-07-10 15:54:59 -0700 |
| commit | c37e90a77bc09d5418453bac39282b4e6c6575c6 (patch) | |
| tree | 93ce5a83676b67961ee0a56b3c1f41647c98f8c9 /usb | |
| parent | dbae88ae94dd4f1faf09236ad97dd63d4e452aa5 (diff) | |
| download | patches-c37e90a77bc09d5418453bac39282b4e6c6575c6.tar.gz | |
more patches
Diffstat (limited to 'usb')
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); + } + |
