From 44a0c0190b500ee6bcfc0976fe540f65dee2cd67 Mon Sep 17 00:00:00 2001 From: Jon Povey Date: Mon, 14 Jun 2010 19:41:04 +0900 Subject: [PATCH 01/22] USB: g_serial: don't set low_latency flag No longer set low_latency flag as it causes this warning backtrace: WARNING: at kernel/mutex.c:207 __mutex_lock_slowpath+0x6c/0x288() Fix associated locking and wakeups. Signed-off-by: Jon Povey Cc: Maulik Mankad Cc: stable Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/u_serial.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 16bdf77f582a..a0f79df4c6c2 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -536,17 +536,11 @@ static void gs_rx_push(unsigned long _port) list_move(&req->list, &port->read_pool); } - /* Push from tty to ldisc; this is immediate with low_latency, and - * may trigger callbacks to this driver ... so drop the spinlock. + /* Push from tty to ldisc; without low_latency set this is handled by + * a workqueue, so we won't get callbacks and can hold port_lock */ if (tty && do_push) { - spin_unlock_irq(&port->port_lock); tty_flip_buffer_push(tty); - wake_up_interruptible(&tty->read_wait); - spin_lock_irq(&port->port_lock); - - /* tty may have been closed */ - tty = port->port_tty; } @@ -784,11 +778,6 @@ static int gs_open(struct tty_struct *tty, struct file *file) port->open_count = 1; port->openclose = false; - /* low_latency means ldiscs work in tasklet context, without - * needing a workqueue schedule ... easier to keep up. - */ - tty->low_latency = 1; - /* if connected, start the I/O stream */ if (port->port_usb) { struct gserial *gser = port->port_usb; From b23097b793081358a6d943263c91bae4c955c4e3 Mon Sep 17 00:00:00 2001 From: Jon Povey Date: Mon, 14 Jun 2010 19:42:10 +0900 Subject: [PATCH 02/22] USB: g_serial: fix tty cleanup on unload Call put_tty_driver() in cleanup function, to fix Oops when trying to open gadget serial char device after module unload. Signed-off-by: Jon Povey Acked-by: David Brownell Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/u_serial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index a0f79df4c6c2..3e8dcb5455e3 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -1184,6 +1184,7 @@ void gserial_cleanup(void) n_ports = 0; tty_unregister_driver(gs_tty_driver); + put_tty_driver(gs_tty_driver); gs_tty_driver = NULL; pr_debug("%s: cleaned up ttyGS* support\n", __func__); From f588c0db39ca35f69f815dabe5682759daa25098 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Mon, 14 Jun 2010 10:43:34 +0200 Subject: [PATCH 03/22] USB: gadget: g_fs: possible invalid pointer reference bug fixed During __gfs_do_config() some invalid pointers may be left in usb_configuration::interfaces array from previous calls to the __gfs_do_config() for the same configuration. This will always happen if an user space function which has a fewer then the last user space function registers itself. Composite's set_config() function that a pointer after the last interface in usb_configuration::interface is NULL unless the array is full. This patch makes the __gfs_do_config() make sure that if the usb_configuration::interface is not full then a pointer after the last interface is NULL. Signed-off-by: Michal Nazarewicz Signed-off-by: Kyungmin Park Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/g_ffs.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index 4b0e4a040d6f..d1af253a9105 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -392,6 +392,17 @@ static int __gfs_do_config(struct usb_configuration *c, if (unlikely(ret < 0)) return ret; + /* After previous do_configs there may be some invalid + * pointers in c->interface array. This happens every time + * a user space function with fewer interfaces than a user + * space function that was run before the new one is run. The + * compasit's set_config() assumes that if there is no more + * then MAX_CONFIG_INTERFACES interfaces in a configuration + * then there is a NULL pointer after the last interface in + * c->interface array. We need to make sure this is true. */ + if (c->next_interface_id < ARRAY_SIZE(c->interface)) + c->interface[c->next_interface_id] = NULL; + return 0; } From 6cc30d85a5bf61248ff0e1f0e0f15fe718bae378 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 10 Jun 2010 12:25:28 -0700 Subject: [PATCH 04/22] USB: xHCI: Fix bug in link TRB activation change. Commit 6c12db90f19727c76990e7f4801c67a148b30111 introduced a bug for control transfers. The patch was supposed to change when the link TRBs at the end of each ring segment were given to the hardware. If a transfer descriptor (TD) ended just before the link TRB, the code wouldn't give back the link TRB to the hardware; instead it would be given back in prepare_ring() just before the next TD was enqueued at the top of the ring. Unfortunately, the code relied on checking the chain bit of the TRB to determine whether the TD ended just before the link TRB. It assumed that the ring enqueuing code would call prepare_ring() before enqueuing the next TD. However, control transfers are made of multiple TDs, and prepare_ring() is only called once before enqueuing two or three TDs. If the first or second TD of the control transfer ended just before the link TRB, then the code in inc_enq() would not move the enqueue pointer past the link TRB, and the link TRB would get overwritten. This would cause the xHCI driver to start writing to memory past the ring segment, and eventually the system would crash or hang. The fix is to add a flag to inc_enq() that says whether the caller will enqueue more TDs before calling prepare_ring(). If the chain bit is cleared (meaning this is the last TRB in a TD), and the caller will not enqueue more TDs, then we defer giving back the link TRB. Signed-off-by: Sarah Sharp Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 62 ++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9012098add6b..94e6934edb09 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -182,8 +182,12 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer * set, but other sections talk about dealing with the chain bit set. This was * fixed in the 0.96 specification errata, but we have to assume that all 0.95 * xHCI hardware can't handle the chain bit being cleared on a link TRB. + * + * @more_trbs_coming: Will you enqueue more TRBs before calling + * prepare_transfer()? */ -static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer) +static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, + bool consumer, bool more_trbs_coming) { u32 chain; union xhci_trb *next; @@ -199,15 +203,28 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer while (last_trb(xhci, ring, ring->enq_seg, next)) { if (!consumer) { if (ring != xhci->event_ring) { - if (chain) { - next->link.control |= TRB_CHAIN; - - /* Give this link TRB to the hardware */ - wmb(); - next->link.control ^= TRB_CYCLE; - } else { + /* + * If the caller doesn't plan on enqueueing more + * TDs before ringing the doorbell, then we + * don't want to give the link TRB to the + * hardware just yet. We'll give the link TRB + * back in prepare_ring() just before we enqueue + * the TD at the top of the ring. + */ + if (!chain && !more_trbs_coming) break; + + /* If we're not dealing with 0.95 hardware, + * carry over the chain bit of the previous TRB + * (which may mean the chain bit is cleared). + */ + if (!xhci_link_trb_quirk(xhci)) { + next->link.control &= ~TRB_CHAIN; + next->link.control |= chain; } + /* Give this link TRB to the hardware */ + wmb(); + next->link.control ^= TRB_CYCLE; } /* Toggle the cycle bit after the last ring segment. */ if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { @@ -1707,9 +1724,12 @@ void xhci_handle_event(struct xhci_hcd *xhci) /* * Generic function for queueing a TRB on a ring. * The caller must have checked to make sure there's room on the ring. + * + * @more_trbs_coming: Will you enqueue more TRBs before calling + * prepare_transfer()? */ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, - bool consumer, + bool consumer, bool more_trbs_coming, u32 field1, u32 field2, u32 field3, u32 field4) { struct xhci_generic_trb *trb; @@ -1719,7 +1739,7 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, trb->field[1] = field2; trb->field[2] = field3; trb->field[3] = field4; - inc_enq(xhci, ring, consumer); + inc_enq(xhci, ring, consumer, more_trbs_coming); } /* @@ -1988,6 +2008,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, int trb_buff_len, this_sg_len, running_total; bool first_trb; u64 addr; + bool more_trbs_coming; struct xhci_generic_trb *start_trb; int start_cycle; @@ -2073,7 +2094,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, length_field = TRB_LEN(trb_buff_len) | remainder | TRB_INTR_TARGET(0); - queue_trb(xhci, ep_ring, false, + if (num_trbs > 1) + more_trbs_coming = true; + else + more_trbs_coming = false; + queue_trb(xhci, ep_ring, false, more_trbs_coming, lower_32_bits(addr), upper_32_bits(addr), length_field, @@ -2124,6 +2149,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, int num_trbs; struct xhci_generic_trb *start_trb; bool first_trb; + bool more_trbs_coming; int start_cycle; u32 field, length_field; @@ -2212,7 +2238,11 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, length_field = TRB_LEN(trb_buff_len) | remainder | TRB_INTR_TARGET(0); - queue_trb(xhci, ep_ring, false, + if (num_trbs > 1) + more_trbs_coming = true; + else + more_trbs_coming = false; + queue_trb(xhci, ep_ring, false, more_trbs_coming, lower_32_bits(addr), upper_32_bits(addr), length_field, @@ -2291,7 +2321,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Queue setup TRB - see section 6.4.1.2.1 */ /* FIXME better way to translate setup_packet into two u32 fields? */ setup = (struct usb_ctrlrequest *) urb->setup_packet; - queue_trb(xhci, ep_ring, false, + queue_trb(xhci, ep_ring, false, true, /* FIXME endianness is probably going to bite my ass here. */ setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16, setup->wIndex | setup->wLength << 16, @@ -2307,7 +2337,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (urb->transfer_buffer_length > 0) { if (setup->bRequestType & USB_DIR_IN) field |= TRB_DIR_IN; - queue_trb(xhci, ep_ring, false, + queue_trb(xhci, ep_ring, false, true, lower_32_bits(urb->transfer_dma), upper_32_bits(urb->transfer_dma), length_field, @@ -2324,7 +2354,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field = 0; else field = TRB_DIR_IN; - queue_trb(xhci, ep_ring, false, + queue_trb(xhci, ep_ring, false, false, 0, 0, TRB_INTR_TARGET(0), @@ -2361,7 +2391,7 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, "unfailable commands failed.\n"); return -ENOMEM; } - queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3, + queue_trb(xhci, xhci->cmd_ring, false, false, field1, field2, field3, field4 | xhci->cmd_ring->cycle_state); return 0; } From a5797a686f4c7cbced782959509d735cfa1344b1 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 7 Jun 2010 16:55:56 +0900 Subject: [PATCH 05/22] USB: r8a66597: Fix failure in change of status In the change by 749da5f82fe33ff68dd4aa1a5e35cd9aa6246dab, The change in the status when the USB device is connected is wrong. Therefore, the device is not recognized. Acked-by: Alan Stern CC: Yoshihiro Shimoda CC: Paul Mundt" Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 1a2bb4ce638f..77be3c24a427 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1065,7 +1065,7 @@ static void r8a66597_usb_connect(struct r8a66597 *r8a66597, int port) else if (speed == LSMODE) rh->port |= USB_PORT_STAT_LOW_SPEED; - rh->port &= USB_PORT_STAT_RESET; + rh->port &= ~USB_PORT_STAT_RESET; rh->port |= USB_PORT_STAT_ENABLE; } From 2bb14cbf04ded4b9e394a6ba9e4f06b82fbac8b2 Mon Sep 17 00:00:00 2001 From: Maulik Mankad Date: Tue, 15 Jun 2010 14:40:27 +0530 Subject: [PATCH 06/22] usb: musb: Fix a bug by making suspend interrupt available in device mode As a part of aligning the ISR code for MUSB with the specs, the ISR code was re-written. See Commit 1c25fda4a09e8229800979986ef399401053b46e (usb: musb: handle irqs in the order dictated by programming guide) With this the suspend interrupt came accidently under CONFIG_USB_MUSB_HDRC_HCD. The fix brings suspend interrupt handling outside CONFIG_USB_MUSB_HDRC_HCD. Signed-off-by: Maulik Mankad Cc: David Brownell Acked-by: Felipe Balbi Cc: stable [.34] Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index fad70bc83555..56b6debaf2d9 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -642,7 +642,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, handled = IRQ_HANDLED; } - +#endif if (int_usb & MUSB_INTR_SUSPEND) { DBG(1, "SUSPEND (%s) devctl %02x power %02x\n", otg_state_string(musb), devctl, power); @@ -705,6 +705,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } } +#ifdef CONFIG_USB_MUSB_HDRC_HCD if (int_usb & MUSB_INTR_CONNECT) { struct usb_hcd *hcd = musb_to_hcd(musb); void __iomem *mbase = musb->mregs; From 7b4a036722cfab2b3922685ad473fac35a55c3fa Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 15 Jun 2010 12:34:22 +0200 Subject: [PATCH 07/22] USB: otg/ulpi: bail out on read errors otg_read may return errnos, so bail out correctly to prevent bogus ID-numbers. Signed-off-by: Wolfram Sang Cc: Sascha Hauer Acked-by: Daniel Mack Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/otg/ulpi.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/otg/ulpi.c index b1b346932946..d331b222ad21 100644 --- a/drivers/usb/otg/ulpi.c +++ b/drivers/usb/otg/ulpi.c @@ -59,12 +59,17 @@ static int ulpi_set_flags(struct otg_transceiver *otg) static int ulpi_init(struct otg_transceiver *otg) { - int i, vid, pid; + int i, vid, pid, ret; + u32 ulpi_id = 0; - vid = (otg_io_read(otg, ULPI_VENDOR_ID_HIGH) << 8) | - otg_io_read(otg, ULPI_VENDOR_ID_LOW); - pid = (otg_io_read(otg, ULPI_PRODUCT_ID_HIGH) << 8) | - otg_io_read(otg, ULPI_PRODUCT_ID_LOW); + for (i = 0; i < 4; i++) { + ret = otg_io_read(otg, ULPI_PRODUCT_ID_HIGH - i); + if (ret < 0) + return ret; + ulpi_id = (ulpi_id << 8) | ret; + } + vid = ulpi_id & 0xffff; + pid = ulpi_id >> 16; pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid); From 4c9715de52b9b6256bf1e9510917111a47b0c176 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 15 Jun 2010 12:34:23 +0200 Subject: [PATCH 08/22] USB: ehci-mxc: bail out on transceiver problems The old code registered the hcd even if there were no transceivers detected, leading to oopses like this if we try to probe a non-existant ULPI: [ 2.730000] mxc-ehci mxc-ehci.0: unable to init transceiver [ 2.740000] timeout polling for ULPI device [ 2.740000] timeout polling for ULPI device [ 2.750000] mxc-ehci mxc-ehci.0: unable to enable vbus on transceiver [ 2.750000] mxc-ehci mxc-ehci.0: Freescale On-Chip EHCI Host Controller [ 2.760000] mxc-ehci mxc-ehci.0: new USB bus registered, assigned bus number 2 [ 2.770000] Unhandled fault: external abort on non-linefetch (0x808) at 0xc4876184 [ 2.770000] Internal error: : 808 [#1] PREEMPT [ 2.770000] last sysfs file: [ 2.770000] Modules linked in: [ 2.770000] CPU: 0 Not tainted (2.6.33.5 #5) [ 2.770000] PC is at ehci_hub_control+0x4d4/0x8f8 [ 2.770000] LR is at ehci_mxc_setup+0xbc/0xdc [ 2.770000] pc : [] lr : [] psr: 00000093 [ 2.770000] sp : c3815e40 ip : 00000001 fp : 60000013 [ 2.770000] r10: c4876184 r9 : 00000000 r8 : c3814000 [ 2.770000] r7 : c391d2cc r6 : 00000001 r5 : 00000001 r4 : 00000000 [ 2.770000] r3 : 80000000 r2 : 00000007 r1 : 80000000 r0 : c4876184 [ 2.770000] Flags: nzcv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel [ 2.770000] Control: 0005317f Table: a0004000 DAC: 00000017 [ 2.770000] Process swapper (pid: 1, stack limit = 0xc3814270) ... Signed-off-by: Wolfram Sang Cc: Sascha Hauer Cc: stable Acked-by: Daniel Mack Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-mxc.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index 544ccfd7056e..bd4027745aa7 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -207,10 +207,17 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) /* Initialize the transceiver */ if (pdata->otg) { pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET; - if (otg_init(pdata->otg) != 0) - dev_err(dev, "unable to init transceiver\n"); - else if (otg_set_vbus(pdata->otg, 1) != 0) + ret = otg_init(pdata->otg); + if (ret) { + dev_err(dev, "unable to init transceiver, probably missing\n"); + ret = -ENODEV; + goto err_add; + } + ret = otg_set_vbus(pdata->otg, 1); + if (ret) { dev_err(dev, "unable to enable vbus on transceiver\n"); + goto err_add; + } } priv->hcd = hcd; From 3b49d2315c119b9ae8a9a33b07d4eb7d194c01a7 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Fri, 18 Jun 2010 08:25:00 +0400 Subject: [PATCH 09/22] USB: s3c2410: deactivate endpoints before gadget unbinding Gadget disconnect must be called before unbinding to avoid races. The change fixes an oops on g_ether module unregistering. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/s3c2410_udc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index d5f4c1d45c97..e724a051bfdd 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1700,9 +1700,13 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!driver || driver != udc->driver || !driver->unbind) return -EINVAL; - dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n", + dprintk(DEBUG_NORMAL, "usb_gadget_unregister_driver() '%s'\n", driver->driver.name); + /* report disconnect */ + if (driver->disconnect) + driver->disconnect(&udc->gadget); + driver->unbind(&udc->gadget); device_del(&udc->gadget.dev); From 64d65872f96e2a754caa12ef48949c314384bd9f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 18 Jun 2010 10:16:33 -0400 Subject: [PATCH 10/22] USB: fix oops in usb_sg_init() This patch (as1401) fixes a bug in usb_sg_init() that can cause an invalid pointer dereference. An inner loop reuses some local variables in an unsafe manner, so new variables are introduced. Signed-off-by: Alan Stern Tested-by: Ajay Kumar Gupta Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index a73e08fdab36..fd4c36ea5e46 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -416,8 +416,11 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, /* A length of zero means transfer the whole sg list */ len = length; if (len == 0) { - for_each_sg(sg, sg, nents, i) - len += sg->length; + struct scatterlist *sg2; + int j; + + for_each_sg(sg, sg2, nents, j) + len += sg2->length; } } else { /* From 9a49a14da4afe2c4ab7d7025a2f7f0f99a1c90e0 Mon Sep 17 00:00:00 2001 From: Daniel Sangorrin Date: Fri, 18 Jun 2010 15:30:02 +0900 Subject: [PATCH 11/22] USB: serial: ftdi: correct merge conflict with CONTEC id This patch corrects a problem with the merge of a previous patch to add the CONTEC identifier. I believe the merge problem occurred with the commit: dee5658b482e9e2ac7d6205dc876fc11d4008138 Originally I submitted a patch and then they asked me to order the IDs and resubmit, so did I. But unfortunately in the end somehow both patches were merged. Signed-off-by: Daniel Sangorrin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 - drivers/usb/serial/ftdi_sio_ids.h | 7 ------- 2 files changed, 8 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 79dd1ae195e5..da7e334b0407 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -653,7 +653,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) }, { USB_DEVICE(EVOLUTION_VID, EVO_HYBRID_PID) }, { USB_DEVICE(EVOLUTION_VID, EVO_RCM4_PID) }, - { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 94d86c3febcb..bbc159a1df45 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -500,13 +500,6 @@ #define CONTEC_VID 0x06CE /* Vendor ID */ #define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */ -/* - * Contec products (http://www.contec.com) - * Submitted by Daniel Sangorrin - */ -#define CONTEC_VID 0x06CE /* Vendor ID */ -#define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */ - /* * Definitions for B&B Electronics products. */ From 1c815577823951ff082fe1201fdd5efec5e6e8ea Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 21 Jun 2010 17:02:51 +0200 Subject: [PATCH 12/22] USB: isp1362-hcd, fix double lock Stanse found that isp1362_sw_reset tries to take a isp1362_hcd->lock, but it is already held in isp1362_hc_stop. Avoid that by introducing __isp1362_sw_reset which doesn't take the lock and call it from isp1362_hc_stop. isp1362_sw_reset is then as simple as lock -- __isp1362_sw_reset -- unlock. Signed-off-by: Jiri Slaby Cc: Lothar Wassmann Cc: Michael Hennerich Cc: Bryan Wu Cc: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1362-hcd.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 20a0dfe0fe36..0587ad4ce5c2 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2224,12 +2224,9 @@ static void remove_debug_file(struct isp1362_hcd *isp1362_hcd) /*-------------------------------------------------------------------------*/ -static void isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd) +static void __isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd) { int tmp = 20; - unsigned long flags; - - spin_lock_irqsave(&isp1362_hcd->lock, flags); isp1362_write_reg16(isp1362_hcd, HCSWRES, HCSWRES_MAGIC); isp1362_write_reg32(isp1362_hcd, HCCMDSTAT, OHCI_HCR); @@ -2240,6 +2237,14 @@ static void isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd) } if (!tmp) pr_err("Software reset timeout\n"); +} + +static void isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd) +{ + unsigned long flags; + + spin_lock_irqsave(&isp1362_hcd->lock, flags); + __isp1362_sw_reset(isp1362_hcd); spin_unlock_irqrestore(&isp1362_hcd->lock, flags); } @@ -2418,7 +2423,7 @@ static void isp1362_hc_stop(struct usb_hcd *hcd) if (isp1362_hcd->board && isp1362_hcd->board->reset) isp1362_hcd->board->reset(hcd->self.controller, 1); else - isp1362_sw_reset(isp1362_hcd); + __isp1362_sw_reset(isp1362_hcd); if (isp1362_hcd->board && isp1362_hcd->board->clock) isp1362_hcd->board->clock(hcd->self.controller, 0); From 10ca4425714a6115c5d865718d64874a1e1ea09a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 21 Jun 2010 17:02:40 +0200 Subject: [PATCH 13/22] USB: gadget/printer, fix sleep inside atomic Stanse found that sleep is called inside atomic context created by lock_printer_io spinlock in several functions. It's used in process context only and some functions sleep inside its critical section. As this is not allowed for spinlocks, switch it to mutex. Signed-off-by: Jiri Slaby Cc: Craig W. Nadler Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/printer.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 43abf55d8c60..4c3ac5c42237 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -82,7 +82,7 @@ static struct class *usb_gadget_class; struct printer_dev { spinlock_t lock; /* lock this structure */ /* lock buffer lists during read/write calls */ - spinlock_t lock_printer_io; + struct mutex lock_printer_io; struct usb_gadget *gadget; struct usb_request *req; /* for control responses */ u8 config; @@ -567,7 +567,7 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) DBG(dev, "printer_read trying to read %d bytes\n", (int)len); - spin_lock(&dev->lock_printer_io); + mutex_lock(&dev->lock_printer_io); spin_lock_irqsave(&dev->lock, flags); /* We will use this flag later to check if a printer reset happened @@ -601,7 +601,7 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) * call or not. */ if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { - spin_unlock(&dev->lock_printer_io); + mutex_unlock(&dev->lock_printer_io); return -EAGAIN; } @@ -648,7 +648,7 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) if (dev->reset_printer) { list_add(¤t_rx_req->list, &dev->rx_reqs); spin_unlock_irqrestore(&dev->lock, flags); - spin_unlock(&dev->lock_printer_io); + mutex_unlock(&dev->lock_printer_io); return -EAGAIN; } @@ -673,7 +673,7 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) dev->current_rx_buf = current_rx_buf; spin_unlock_irqrestore(&dev->lock, flags); - spin_unlock(&dev->lock_printer_io); + mutex_unlock(&dev->lock_printer_io); DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied); @@ -697,7 +697,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) if (len == 0) return -EINVAL; - spin_lock(&dev->lock_printer_io); + mutex_lock(&dev->lock_printer_io); spin_lock_irqsave(&dev->lock, flags); /* Check if a printer reset happens while we have interrupts on */ @@ -713,7 +713,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) * a NON-Blocking call or not. */ if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { - spin_unlock(&dev->lock_printer_io); + mutex_unlock(&dev->lock_printer_io); return -EAGAIN; } @@ -752,7 +752,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) if (copy_from_user(req->buf, buf, size)) { list_add(&req->list, &dev->tx_reqs); - spin_unlock(&dev->lock_printer_io); + mutex_unlock(&dev->lock_printer_io); return bytes_copied; } @@ -766,14 +766,14 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) if (dev->reset_printer) { list_add(&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->lock, flags); - spin_unlock(&dev->lock_printer_io); + mutex_unlock(&dev->lock_printer_io); return -EAGAIN; } if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) { list_add(&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->lock, flags); - spin_unlock(&dev->lock_printer_io); + mutex_unlock(&dev->lock_printer_io); return -EAGAIN; } @@ -782,7 +782,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) } spin_unlock_irqrestore(&dev->lock, flags); - spin_unlock(&dev->lock_printer_io); + mutex_unlock(&dev->lock_printer_io); DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied); @@ -820,11 +820,11 @@ printer_poll(struct file *fd, poll_table *wait) unsigned long flags; int status = 0; - spin_lock(&dev->lock_printer_io); + mutex_lock(&dev->lock_printer_io); spin_lock_irqsave(&dev->lock, flags); setup_rx_reqs(dev); spin_unlock_irqrestore(&dev->lock, flags); - spin_unlock(&dev->lock_printer_io); + mutex_unlock(&dev->lock_printer_io); poll_wait(fd, &dev->rx_wait, wait); poll_wait(fd, &dev->tx_wait, wait); @@ -1461,7 +1461,7 @@ printer_bind(struct usb_gadget *gadget) } spin_lock_init(&dev->lock); - spin_lock_init(&dev->lock_printer_io); + mutex_init(&dev->lock_printer_io); INIT_LIST_HEAD(&dev->tx_reqs); INIT_LIST_HEAD(&dev->tx_reqs_active); INIT_LIST_HEAD(&dev->rx_reqs); @@ -1594,7 +1594,7 @@ cleanup(void) { int status; - spin_lock(&usb_printer_gadget.lock_printer_io); + mutex_lock(&usb_printer_gadget.lock_printer_io); class_destroy(usb_gadget_class); unregister_chrdev_region(g_printer_devno, 2); @@ -1602,6 +1602,6 @@ cleanup(void) if (status) ERROR(dev, "usb_gadget_unregister_driver %x\n", status); - spin_unlock(&usb_printer_gadget.lock_printer_io); + mutex_unlock(&usb_printer_gadget.lock_printer_io); } module_exit(cleanup); From 0d152de56938361fa2b960db67657b20cdaa6d84 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 21 Jun 2010 08:44:17 +0800 Subject: [PATCH 14/22] USB: qcserial: fix a memory leak in qcprobe error path This patch adds missing kfree(data) before return -ENODEV. Signed-off-by: Axel Lin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcserial.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 04bb759536bb..93d72eb8cafc 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -139,6 +139,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) "Could not set interface, error %d\n", retval); retval = -ENODEV; + kfree(data); } return retval; } @@ -155,6 +156,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) "Could not set interface, error %d\n", retval); retval = -ENODEV; + kfree(data); } return retval; } @@ -163,6 +165,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) default: dev_err(&serial->dev->dev, "unknown number of interfaces: %d\n", nintf); + kfree(data); return -ENODEV; } From 03ab7461df3c74c9418c3f5485ea1127ece1ff79 Mon Sep 17 00:00:00 2001 From: Jiri Pinkava Date: Sun, 20 Jun 2010 20:05:52 +0200 Subject: [PATCH 15/22] USB: gadget eth: Fix calculate CRC32 in EEM CRC should be calculated for Ethernet frame, not for whole recievede EEM data. This bug shows rarely, because in many times len == skb->len. Signed-off-by: Jiri Pinkava Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_eem.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index 38226e9a371d..95dd4662d6a8 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -469,8 +469,7 @@ static int eem_unwrap(struct gether *port, crc = get_unaligned_le32(skb->data + len - ETH_FCS_LEN); crc2 = ~crc32_le(~0, - skb->data, - skb->len - ETH_FCS_LEN); + skb->data, len - ETH_FCS_LEN); } else { crc = get_unaligned_be32(skb->data + len - ETH_FCS_LEN); From 48826626263d4a61d06fd8c5805da31f925aefa0 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 22 Jun 2010 16:14:48 -0400 Subject: [PATCH 16/22] USB: obey the sysfs power/wakeup setting This patch (as1403) is a partial reversion of an earlier change (commit 5f677f1d45b2bf08085bbba7394392dfa586fa8e "USB: fix remote wakeup settings during system sleep"). After hearing from a user, I realized that remote wakeup should be enabled during system sleep whenever userspace allows it, and not only if a driver requests it too. Indeed, there could be a device with no driver, that does nothing but generate a wakeup request when the user presses a button. Such a device should be allowed to do its job. The problem fixed by the earlier patch -- device generating a wakeup request for no reason, causing system suspend to abort -- was also addressed by a later patch ("USB: don't enable remote wakeup by default", accepted but not yet merged into mainline). The device won't be able to generate the bogus wakeup requests because it will be disabled for remote wakeup by default. Hence this reversion will not re-introduce any old problems. Signed-off-by: Alan Stern Cc: stable [.34] Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index de98a94d1853..a6bd53ace035 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1272,8 +1272,7 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) static void choose_wakeup(struct usb_device *udev, pm_message_t msg) { - int w, i; - struct usb_interface *intf; + int w; /* Remote wakeup is needed only when we actually go to sleep. * For things like FREEZE and QUIESCE, if the device is already @@ -1285,16 +1284,10 @@ static void choose_wakeup(struct usb_device *udev, pm_message_t msg) return; } - /* If remote wakeup is permitted, see whether any interface drivers + /* Enable remote wakeup if it is allowed, even if no interface drivers * actually want it. */ - w = 0; - if (device_may_wakeup(&udev->dev) && udev->actconfig) { - for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { - intf = udev->actconfig->interface[i]; - w |= intf->needs_remote_wakeup; - } - } + w = device_may_wakeup(&udev->dev); /* If the device is autosuspended with the wrong wakeup setting, * autoresume now so the setting can be changed. From 7d9645fdca444d53907b22a4b73e3967efe09781 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 24 Jun 2010 23:07:06 +0530 Subject: [PATCH 17/22] USB: musb_core: make disconnect and suspend interrupts work again Commit 1c25fda4a09e8229800979986ef399401053b46e (usb: musb: handle irqs in the order dictated by programming guide) forgot to get rid of the old 'STAGE0_MASK' filter for calling musb_stage0_irq(), so now disconnect and suspend interrupts are effectively ignored... Signed-off-by: Sergei Shtylyov Cc: stable Signed-off-by: Ajay Kumar Gupta Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 56b6debaf2d9..737cab7fc3ce 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -451,10 +451,6 @@ void musb_hnp_stop(struct musb *musb) * @param power */ -#define STAGE0_MASK (MUSB_INTR_RESUME | MUSB_INTR_SESSREQ \ - | MUSB_INTR_VBUSERROR | MUSB_INTR_CONNECT \ - | MUSB_INTR_RESET) - static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, u8 devctl, u8 power) { @@ -1598,7 +1594,7 @@ irqreturn_t musb_interrupt(struct musb *musb) /* the core can interrupt us for multiple reasons; docs have * a generic interrupt flowchart to follow */ - if (musb->int_usb & STAGE0_MASK) + if (musb->int_usb) retval |= musb_stage0_irq(musb, musb->int_usb, devctl, power); From 9297688a9257d73956d4bba484d9dd331ca72c25 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 24 Jun 2010 23:07:07 +0530 Subject: [PATCH 18/22] USB: MUSB: make non-OMAP platforms build with CONFIG_PM=y Attempt to build MUSB driver with CONFIG_PM=y (e.g. in the OTG mode) on DaVinci results in these link errors: drivers/built-in.o: In function `musb_restore_context': led-triggers.c:(.text+0x714d8): undefined reference to `musb_platform_restore_context' drivers/built-in.o: In function `musb_save_context': led-triggers.c:(.text+0x71788): undefined reference to `musb_platform_save_context' This turned out to be caused by commit 9957dd97ec5e98dd334f87ade1d9a0b24d1f86eb (usb: musb: Fix compile error for omaps for musb_hdrc). Revert it, taking into account the rename of CONFIG_ARCH_OMAP34XX into CONFIG_ARCH_OMAP3 (which that commit fixed in a completely inappropriate way) and the recent addition of OMAP4 support. Signed-off-by: Sergei Shtylyov Signed-off-by: Ajay Kumar Gupta Acked-by: Felipe Balbi Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index b22d02dea7d3..91d67794e350 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -470,7 +470,8 @@ struct musb_csr_regs { struct musb_context_registers { -#ifdef CONFIG_PM +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \ + defined(CONFIG_ARCH_OMAP4) u32 otg_sysconfig, otg_forcestandby; #endif u8 power; @@ -484,7 +485,8 @@ struct musb_context_registers { struct musb_csr_regs index_regs[MUSB_C_NUM_EPS]; }; -#ifdef CONFIG_PM +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \ + defined(CONFIG_ARCH_OMAP4) extern void musb_platform_save_context(struct musb *musb, struct musb_context_registers *musb_context); extern void musb_platform_restore_context(struct musb *musb, From f2263db74a66f1e341efb115e9f2420678c927b9 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 24 Jun 2010 23:07:08 +0530 Subject: [PATCH 19/22] USB: musb: fix Blackfin ulpi stubs The new ulpi code defines fallback stubs for the Blackfin arch, but does so incorrectly leading to a build failure: drivers/usb/musb/musb_core.c:227: error: 'musb_ulpi_read' undeclared here (not in a function) drivers/usb/musb/musb_core.c:228: error: 'musb_ulpi_write' undeclared here (not in a function) Tweak the fallback stubs so that they do work as intended. Signed-off-by: Mike Frysinger Signed-off-by: Ajay Kumar Gupta Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 737cab7fc3ce..3b795c56221f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -219,8 +219,8 @@ static int musb_ulpi_write(struct otg_transceiver *otg, return 0; } #else -#define musb_ulpi_read(a, b) NULL -#define musb_ulpi_write(a, b, c) NULL +#define musb_ulpi_read NULL +#define musb_ulpi_write NULL #endif static struct otg_io_access_ops musb_ulpi_access = { From c0f1f8e38fda8e345cad9269c559b4f036378120 Mon Sep 17 00:00:00 2001 From: Hema HK Date: Thu, 24 Jun 2010 23:07:09 +0530 Subject: [PATCH 20/22] USB: musb: Enable the maximum supported burst mode for DMA Setting MUSB Burst Mode 3 automatically enables support for lower burst modes (BURST4, BURST8, BURST16 or bursts of unspecified length). There is no need to set these burst modes based on the packet size. Also enable the burst mode for both mode1 and mode0. This is a fix for buggy hardware - having the lower burst modes enabled can potentially cause lockups of the DMA engine used in OMAP2/3/4 chips. Signed-off-by: Hema HK Signed-off-by: Anand Gadiyar Signed-off-by: Ajay Kumar Gupta Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musbhsdma.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 1008044a3bbc..dc66e4376d49 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -132,18 +132,9 @@ static void configure_channel(struct dma_channel *channel, if (mode) { csr |= 1 << MUSB_HSDMA_MODE1_SHIFT; BUG_ON(len < packet_sz); - - if (packet_sz >= 64) { - csr |= MUSB_HSDMA_BURSTMODE_INCR16 - << MUSB_HSDMA_BURSTMODE_SHIFT; - } else if (packet_sz >= 32) { - csr |= MUSB_HSDMA_BURSTMODE_INCR8 - << MUSB_HSDMA_BURSTMODE_SHIFT; - } else if (packet_sz >= 16) { - csr |= MUSB_HSDMA_BURSTMODE_INCR4 - << MUSB_HSDMA_BURSTMODE_SHIFT; - } } + csr |= MUSB_HSDMA_BURSTMODE_INCR16 + << MUSB_HSDMA_BURSTMODE_SHIFT; csr |= (musb_channel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT) | (1 << MUSB_HSDMA_ENABLE_SHIFT) From e5fd39d9b80aaa0b8a16dd570fa55009905d6af4 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Fri, 25 Jun 2010 16:29:26 +0200 Subject: [PATCH 21/22] USB: gadget: f_mass_storage: fixed fs descriptors not being updated The full speed descriptors were copied to the usb_function structure in the fsg_bind_config function before call to the usb_ep_autoconfig. The usb_ep_autoconfig was called in fsg_bind using the original descriptors. In effect copied descriptors were not updated. This patch changes the copy full speed descriptors after the call to usb_op_autoconfig is performed. This way, copied full speed descriptors have updated values. Signed-off-by: Michal Nazarewicz Cc: Kyungmin Park Reported-by: Dries Van Puymbroeck Tested-by: Dries Van Puymbroeck Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_mass_storage.c | 34 ++++++++++------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 7d05a0be5c60..f866b7e72a28 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2970,7 +2970,6 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) { struct fsg_dev *fsg = fsg_from_func(f); struct usb_gadget *gadget = c->cdev->gadget; - int rc; int i; struct usb_ep *ep; @@ -2996,6 +2995,11 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) ep->driver_data = fsg->common; /* claim the endpoint */ fsg->bulk_out = ep; + /* Copy descriptors */ + f->descriptors = usb_copy_descriptors(fsg_fs_function); + if (unlikely(!f->descriptors)) + return -ENOMEM; + if (gadget_is_dualspeed(gadget)) { /* Assume endpoint addresses are the same for both speeds */ fsg_hs_bulk_in_desc.bEndpointAddress = @@ -3003,16 +3007,17 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) fsg_hs_bulk_out_desc.bEndpointAddress = fsg_fs_bulk_out_desc.bEndpointAddress; f->hs_descriptors = usb_copy_descriptors(fsg_hs_function); - if (unlikely(!f->hs_descriptors)) + if (unlikely(!f->hs_descriptors)) { + usb_free_descriptors(f->descriptors); return -ENOMEM; + } } return 0; autoconf_fail: ERROR(fsg, "unable to autoconfigure all endpoints\n"); - rc = -ENOTSUPP; - return rc; + return -ENOTSUPP; } @@ -3036,11 +3041,6 @@ static int fsg_add(struct usb_composite_dev *cdev, fsg->function.name = FSG_DRIVER_DESC; fsg->function.strings = fsg_strings_array; - fsg->function.descriptors = usb_copy_descriptors(fsg_fs_function); - if (unlikely(!fsg->function.descriptors)) { - rc = -ENOMEM; - goto error_free_fsg; - } fsg->function.bind = fsg_bind; fsg->function.unbind = fsg_unbind; fsg->function.setup = fsg_setup; @@ -3056,19 +3056,9 @@ static int fsg_add(struct usb_composite_dev *cdev, rc = usb_add_function(c, &fsg->function); if (unlikely(rc)) - goto error_free_all; - - fsg_common_get(fsg->common); - return 0; - -error_free_all: - usb_free_descriptors(fsg->function.descriptors); - /* fsg_bind() might have copied those; or maybe not? who cares - * -- free it just in case. */ - usb_free_descriptors(fsg->function.hs_descriptors); -error_free_fsg: - kfree(fsg); - + kfree(fsg); + else + fsg_common_get(fsg->common); return rc; } From b894f60a232d552fc18b018271c2893f0b0c1c15 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Fri, 25 Jun 2010 16:29:28 +0200 Subject: [PATCH 22/22] USB: gadget: f_mass_storage: stale common->fsg value bug fix On fsg_unbind the common->fsg pointer was not NULLed if the unbound fsg_dev instance was the current one. As an effect, the incorrect pointer was preserved in all further operations which caused do_set_interface to reference an invalid region. This commit fixes this by raising an exception in fsg_bind which will change the common->fsg pointer. This also requires an wait queue so that the thread in fsg_bind can wait till the worker thread handles the exception. This commit removes also a config and new_config fields of fsg_common as they are no longer needed since fsg can be used to determine whether function is active or not. Moreover, this commit removes possible race condition where the fsg field was modified in both the worker thread and form various other contexts. This is fixed by replacing prev_fsg with new_fsg. At this point, fsg is assigned only in worker thread. Signed-off-by: Michal Nazarewicz Cc: Kyungmin Park Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_mass_storage.c | 160 +++++++++++----------------- 1 file changed, 61 insertions(+), 99 deletions(-) diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index f866b7e72a28..4ce899c9b165 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -321,8 +321,8 @@ struct fsg_dev; /* Data shared by all the FSG instances. */ struct fsg_common { struct usb_gadget *gadget; - struct fsg_dev *fsg; - struct fsg_dev *prev_fsg; + struct fsg_dev *fsg, *new_fsg; + wait_queue_head_t fsg_wait; /* filesem protects: backing files in use */ struct rw_semaphore filesem; @@ -351,7 +351,6 @@ struct fsg_common { enum fsg_state state; /* For exception handling */ unsigned int exception_req_tag; - u8 config, new_config; enum data_direction data_dir; u32 data_size; u32 data_size_from_cmnd; @@ -595,7 +594,7 @@ static int fsg_setup(struct usb_function *f, u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); - if (!fsg->common->config) + if (!fsg_is_set(fsg->common)) return -EOPNOTSUPP; switch (ctrl->bRequest) { @@ -2303,24 +2302,20 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep, return -ENOMEM; } -/* - * Reset interface setting and re-init endpoint state (toggle etc). - * Call with altsetting < 0 to disable the interface. The only other - * available altsetting is 0, which enables the interface. - */ -static int do_set_interface(struct fsg_common *common, int altsetting) +/* Reset interface setting and re-init endpoint state (toggle etc). */ +static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg) { - int rc = 0; - int i; - const struct usb_endpoint_descriptor *d; + const struct usb_endpoint_descriptor *d; + struct fsg_dev *fsg; + int i, rc = 0; if (common->running) DBG(common, "reset interface\n"); reset: /* Deallocate the requests */ - if (common->prev_fsg) { - struct fsg_dev *fsg = common->prev_fsg; + if (common->fsg) { + fsg = common->fsg; for (i = 0; i < FSG_NUM_BUFFERS; ++i) { struct fsg_buffhd *bh = &common->buffhds[i]; @@ -2345,88 +2340,53 @@ static int do_set_interface(struct fsg_common *common, int altsetting) fsg->bulk_out_enabled = 0; } - common->prev_fsg = 0; + common->fsg = NULL; + wake_up(&common->fsg_wait); } common->running = 0; - if (altsetting < 0 || rc != 0) + if (!new_fsg || rc) return rc; - DBG(common, "set interface %d\n", altsetting); + common->fsg = new_fsg; + fsg = common->fsg; - if (fsg_is_set(common)) { - struct fsg_dev *fsg = common->fsg; - common->prev_fsg = common->fsg; + /* Enable the endpoints */ + d = fsg_ep_desc(common->gadget, + &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc); + rc = enable_endpoint(common, fsg->bulk_in, d); + if (rc) + goto reset; + fsg->bulk_in_enabled = 1; - /* Enable the endpoints */ - d = fsg_ep_desc(common->gadget, - &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc); - rc = enable_endpoint(common, fsg->bulk_in, d); + d = fsg_ep_desc(common->gadget, + &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc); + rc = enable_endpoint(common, fsg->bulk_out, d); + if (rc) + goto reset; + fsg->bulk_out_enabled = 1; + common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); + clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); + + /* Allocate the requests */ + for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &common->buffhds[i]; + + rc = alloc_request(common, fsg->bulk_in, &bh->inreq); if (rc) goto reset; - fsg->bulk_in_enabled = 1; - - d = fsg_ep_desc(common->gadget, - &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc); - rc = enable_endpoint(common, fsg->bulk_out, d); + rc = alloc_request(common, fsg->bulk_out, &bh->outreq); if (rc) goto reset; - fsg->bulk_out_enabled = 1; - common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); - clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); - - /* Allocate the requests */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { - struct fsg_buffhd *bh = &common->buffhds[i]; - - rc = alloc_request(common, fsg->bulk_in, &bh->inreq); - if (rc) - goto reset; - rc = alloc_request(common, fsg->bulk_out, &bh->outreq); - if (rc) - goto reset; - bh->inreq->buf = bh->outreq->buf = bh->buf; - bh->inreq->context = bh->outreq->context = bh; - bh->inreq->complete = bulk_in_complete; - bh->outreq->complete = bulk_out_complete; - } - - common->running = 1; - for (i = 0; i < common->nluns; ++i) - common->luns[i].unit_attention_data = SS_RESET_OCCURRED; - return rc; - } else { - return -EIO; - } -} - - -/* - * Change our operational configuration. This code must agree with the code - * that returns config descriptors, and with interface altsetting code. - * - * It's also responsible for power management interactions. Some - * configurations might not work with our current power sources. - * For now we just assume the gadget is always self-powered. - */ -static int do_set_config(struct fsg_common *common, u8 new_config) -{ - int rc = 0; - - /* Disable the single interface */ - if (common->config != 0) { - DBG(common, "reset config\n"); - common->config = 0; - rc = do_set_interface(common, -1); + bh->inreq->buf = bh->outreq->buf = bh->buf; + bh->inreq->context = bh->outreq->context = bh; + bh->inreq->complete = bulk_in_complete; + bh->outreq->complete = bulk_out_complete; } - /* Enable the interface */ - if (new_config != 0) { - common->config = new_config; - rc = do_set_interface(common, 0); - if (rc != 0) - common->config = 0; /* Reset on errors */ - } + common->running = 1; + for (i = 0; i < common->nluns; ++i) + common->luns[i].unit_attention_data = SS_RESET_OCCURRED; return rc; } @@ -2437,9 +2397,7 @@ static int do_set_config(struct fsg_common *common, u8 new_config) static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct fsg_dev *fsg = fsg_from_func(f); - fsg->common->prev_fsg = fsg->common->fsg; - fsg->common->fsg = fsg; - fsg->common->new_config = 1; + fsg->common->new_fsg = fsg; raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); return 0; } @@ -2447,9 +2405,7 @@ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) static void fsg_disable(struct usb_function *f) { struct fsg_dev *fsg = fsg_from_func(f); - fsg->common->prev_fsg = fsg->common->fsg; - fsg->common->fsg = fsg; - fsg->common->new_config = 0; + fsg->common->new_fsg = NULL; raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); } @@ -2459,19 +2415,17 @@ static void fsg_disable(struct usb_function *f) static void handle_exception(struct fsg_common *common) { siginfo_t info; - int sig; int i; struct fsg_buffhd *bh; enum fsg_state old_state; - u8 new_config; struct fsg_lun *curlun; unsigned int exception_req_tag; - int rc; /* Clear the existing signals. Anything but SIGUSR1 is converted * into a high-priority EXIT exception. */ for (;;) { - sig = dequeue_signal_lock(current, ¤t->blocked, &info); + int sig = + dequeue_signal_lock(current, ¤t->blocked, &info); if (!sig) break; if (sig != SIGUSR1) { @@ -2482,7 +2436,7 @@ static void handle_exception(struct fsg_common *common) } /* Cancel all the pending transfers */ - if (fsg_is_set(common)) { + if (likely(common->fsg)) { for (i = 0; i < FSG_NUM_BUFFERS; ++i) { bh = &common->buffhds[i]; if (bh->inreq_busy) @@ -2523,7 +2477,6 @@ static void handle_exception(struct fsg_common *common) common->next_buffhd_to_fill = &common->buffhds[0]; common->next_buffhd_to_drain = &common->buffhds[0]; exception_req_tag = common->exception_req_tag; - new_config = common->new_config; old_state = common->state; if (old_state == FSG_STATE_ABORT_BULK_OUT) @@ -2573,12 +2526,12 @@ static void handle_exception(struct fsg_common *common) break; case FSG_STATE_CONFIG_CHANGE: - rc = do_set_config(common, new_config); + do_set_interface(common, common->new_fsg); break; case FSG_STATE_EXIT: case FSG_STATE_TERMINATED: - do_set_config(common, 0); /* Free resources */ + do_set_interface(common, NULL); /* Free resources */ spin_lock_irq(&common->lock); common->state = FSG_STATE_TERMINATED; /* Stop the thread */ spin_unlock_irq(&common->lock); @@ -2863,6 +2816,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, goto error_release; } init_completion(&common->thread_notifier); + init_waitqueue_head(&common->fsg_wait); #undef OR @@ -2957,9 +2911,17 @@ static void fsg_common_release(struct kref *ref) static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) { struct fsg_dev *fsg = fsg_from_func(f); + struct fsg_common *common = fsg->common; DBG(fsg, "unbind\n"); - fsg_common_put(fsg->common); + if (fsg->common->fsg == fsg) { + fsg->common->new_fsg = NULL; + raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); + /* FIXME: make interruptible or killable somehow? */ + wait_event(common->fsg_wait, common->fsg != fsg); + } + + fsg_common_put(common); usb_free_descriptors(fsg->function.descriptors); usb_free_descriptors(fsg->function.hs_descriptors); kfree(fsg);