Skip to content

Commit

Permalink
Merge tag 'usb-3.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/gregkh/usb

Pull USB fixes from Greg Kroah-Hartman:
 "Here are a number of USB fixes that resolve issues that have been
  reported against 3.9-rc3."

* tag 'usb-3.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (37 commits)
  USB: ti_usb_3410_5052: fix use-after-free in TIOCMIWAIT
  USB: ssu100: fix use-after-free in TIOCMIWAIT
  USB: spcp8x5: fix use-after-free in TIOCMIWAIT
  USB: quatech2: fix use-after-free in TIOCMIWAIT
  USB: pl2303: fix use-after-free in TIOCMIWAIT
  USB: oti6858: fix use-after-free in TIOCMIWAIT
  USB: mos7840: fix use-after-free in TIOCMIWAIT
  USB: mos7840: fix broken TIOCMIWAIT
  USB: mct_u232: fix use-after-free in TIOCMIWAIT
  USB: io_ti: fix use-after-free in TIOCMIWAIT
  USB: io_edgeport: fix use-after-free in TIOCMIWAIT
  USB: ftdi_sio: fix use-after-free in TIOCMIWAIT
  USB: f81232: fix use-after-free in TIOCMIWAIT
  USB: cypress_m8: fix use-after-free in TIOCMIWAIT
  USB: ch341: fix use-after-free in TIOCMIWAIT
  USB: ark3116: fix use-after-free in TIOCMIWAIT
  USB: serial: add modem-status-change wait queue
  USB: serial: fix interface refcounting
  USB: io_ti: fix get_icount for two port adapters
  USB: garmin_gps: fix memory leak on disconnect
  ...
  • Loading branch information
torvalds committed Mar 22, 2013
2 parents 70dc52f + fc98ab8 commit 8f46c50
Show file tree
Hide file tree
Showing 36 changed files with 202 additions and 115 deletions.
22 changes: 19 additions & 3 deletions drivers/usb/class/cdc-acm.c
Expand Up @@ -593,7 +593,6 @@ static void acm_port_destruct(struct tty_port *port)

dev_dbg(&acm->control->dev, "%s\n", __func__);

tty_unregister_device(acm_tty_driver, acm->minor);
acm_release_minor(acm);
usb_put_intf(acm->control);
kfree(acm->country_codes);
Expand Down Expand Up @@ -977,6 +976,8 @@ static int acm_probe(struct usb_interface *intf,
int num_rx_buf;
int i;
int combined_interfaces = 0;
struct device *tty_dev;
int rv = -ENOMEM;

/* normal quirks */
quirks = (unsigned long)id->driver_info;
Expand Down Expand Up @@ -1339,11 +1340,24 @@ static int acm_probe(struct usb_interface *intf,
usb_set_intfdata(data_interface, acm);

usb_get_intf(control_interface);
tty_port_register_device(&acm->port, acm_tty_driver, minor,
tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor,
&control_interface->dev);
if (IS_ERR(tty_dev)) {
rv = PTR_ERR(tty_dev);
goto alloc_fail8;
}

return 0;
alloc_fail8:
if (acm->country_codes) {
device_remove_file(&acm->control->dev,
&dev_attr_wCountryCodes);
device_remove_file(&acm->control->dev,
&dev_attr_iCountryCodeRelDate);
}
device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
alloc_fail7:
usb_set_intfdata(intf, NULL);
for (i = 0; i < ACM_NW; i++)
usb_free_urb(acm->wb[i].urb);
alloc_fail6:
Expand All @@ -1359,7 +1373,7 @@ static int acm_probe(struct usb_interface *intf,
acm_release_minor(acm);
kfree(acm);
alloc_fail:
return -ENOMEM;
return rv;
}

static void stop_data_traffic(struct acm *acm)
Expand Down Expand Up @@ -1411,6 +1425,8 @@ static void acm_disconnect(struct usb_interface *intf)

stop_data_traffic(acm);

tty_unregister_device(acm_tty_driver, acm->minor);

usb_free_urb(acm->ctrlurb);
for (i = 0; i < ACM_NW; i++)
usb_free_urb(acm->wb[i].urb);
Expand Down
23 changes: 14 additions & 9 deletions drivers/usb/core/hcd-pci.c
Expand Up @@ -173,6 +173,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
struct hc_driver *driver;
struct usb_hcd *hcd;
int retval;
int hcd_irq = 0;

if (usb_disabled())
return -ENODEV;
Expand All @@ -187,15 +188,19 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
return -ENODEV;
dev->current_state = PCI_D0;

/* The xHCI driver supports MSI and MSI-X,
* so don't fail if the BIOS doesn't provide a legacy IRQ.
/*
* The xHCI driver has its own irq management
* make sure irq setup is not touched for xhci in generic hcd code
*/
if (!dev->irq && (driver->flags & HCD_MASK) != HCD_USB3) {
dev_err(&dev->dev,
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
pci_name(dev));
retval = -ENODEV;
goto disable_pci;
if ((driver->flags & HCD_MASK) != HCD_USB3) {
if (!dev->irq) {
dev_err(&dev->dev,
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
pci_name(dev));
retval = -ENODEV;
goto disable_pci;
}
hcd_irq = dev->irq;
}

hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));
Expand Down Expand Up @@ -245,7 +250,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)

pci_set_master(dev);

retval = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
if (retval != 0)
goto unmap_registers;
set_hs_companion(dev, hcd);
Expand Down
3 changes: 1 addition & 2 deletions drivers/usb/gadget/f_rndis.c
Expand Up @@ -447,14 +447,13 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_rndis *rndis = req->context;
struct usb_composite_dev *cdev = rndis->port.func.config->cdev;
int status;

/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
// spin_lock(&dev->lock);
status = rndis_msg_parser(rndis->config, (u8 *) req->buf);
if (status < 0)
ERROR(cdev, "RNDIS command error %d, %d/%d\n",
pr_err("RNDIS command error %d, %d/%d\n",
status, req->actual, req->length);
// spin_unlock(&dev->lock);
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/usb/gadget/g_ffs.c
Expand Up @@ -357,7 +357,7 @@ static int gfs_bind(struct usb_composite_dev *cdev)
goto error;
gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id;

for (i = func_num; --i; ) {
for (i = func_num; i--; ) {
ret = functionfs_bind(ffs_tab[i].ffs_data, cdev);
if (unlikely(ret < 0)) {
while (++i < func_num)
Expand Down Expand Up @@ -413,7 +413,7 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
gether_cleanup();
gfs_ether_setup = false;

for (i = func_num; --i; )
for (i = func_num; i--; )
if (ffs_tab[i].ffs_data)
functionfs_unbind(ffs_tab[i].ffs_data);

Expand Down
9 changes: 8 additions & 1 deletion drivers/usb/gadget/net2272.c
Expand Up @@ -59,7 +59,7 @@ static const char * const ep_name[] = {
};

#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#ifdef CONFIG_USB_GADGET_NET2272_DMA
#ifdef CONFIG_USB_NET2272_DMA
/*
* use_dma: the NET2272 can use an external DMA controller.
* Note that since there is no generic DMA api, some functions,
Expand Down Expand Up @@ -1495,6 +1495,13 @@ stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver)
for (i = 0; i < 4; ++i)
net2272_dequeue_all(&dev->ep[i]);

/* report disconnect; the driver is already quiesced */
if (driver) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}

net2272_usb_reinit(dev);
}

Expand Down
8 changes: 7 additions & 1 deletion drivers/usb/gadget/net2280.c
Expand Up @@ -1924,7 +1924,6 @@ static int net2280_start(struct usb_gadget *_gadget,
err_func:
device_remove_file (&dev->pdev->dev, &dev_attr_function);
err_unbind:
driver->unbind (&dev->gadget);
dev->gadget.dev.driver = NULL;
dev->driver = NULL;
return retval;
Expand All @@ -1946,6 +1945,13 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
for (i = 0; i < 7; i++)
nuke (&dev->ep [i]);

/* report disconnect; the driver is already quiesced */
if (driver) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}

usb_reinit (dev);
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/gadget/u_serial.c
Expand Up @@ -136,7 +136,7 @@ static struct portmaster {
pr_debug(fmt, ##arg)
#endif /* pr_vdebug */
#else
#ifndef pr_vdebig
#ifndef pr_vdebug
#define pr_vdebug(fmt, arg...) \
({ if (0) pr_debug(fmt, ##arg); })
#endif /* pr_vdebug */
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/gadget/udc-core.c
Expand Up @@ -216,7 +216,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
usb_gadget_disconnect(udc->gadget);
udc->driver->disconnect(udc->gadget);
udc->driver->unbind(udc->gadget);
usb_gadget_udc_stop(udc->gadget, udc->driver);
usb_gadget_udc_stop(udc->gadget, NULL);

udc->driver = NULL;
udc->dev.driver = NULL;
Expand Down
1 change: 1 addition & 0 deletions drivers/usb/host/ehci-hcd.c
Expand Up @@ -302,6 +302,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)

static void end_unlink_async(struct ehci_hcd *ehci);
static void unlink_empty_async(struct ehci_hcd *ehci);
static void unlink_empty_async_suspended(struct ehci_hcd *ehci);
static void ehci_work(struct ehci_hcd *ehci);
static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-hub.c
Expand Up @@ -328,7 +328,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci->rh_state = EHCI_RH_SUSPENDED;

end_unlink_async(ehci);
unlink_empty_async(ehci);
unlink_empty_async_suspended(ehci);
ehci_handle_intr_unlinks(ehci);
end_free_itds(ehci);

Expand Down
13 changes: 13 additions & 0 deletions drivers/usb/host/ehci-q.c
Expand Up @@ -1316,6 +1316,19 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
}
}

/* The root hub is suspended; unlink all the async QHs */
static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
{
struct ehci_qh *qh;

while (ehci->async->qh_next.qh) {
qh = ehci->async->qh_next.qh;
WARN_ON(!list_empty(&qh->qtd_list));
single_unlink_async(ehci, qh);
}
start_iaa_cycle(ehci, false);
}

/* makes sure the async qh will become idle */
/* caller must own ehci->lock */

Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/host/ehci-timer.c
Expand Up @@ -304,7 +304,7 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
* (a) SMP races against real IAA firing and retriggering, and
* (b) clean HC shutdown, when IAA watchdog was pending.
*/
if (ehci->async_iaa) {
if (1) {
u32 cmd, status;

/* If we get here, IAA is *REALLY* late. It's barely
Expand Down
3 changes: 2 additions & 1 deletion drivers/usb/host/xhci.c
Expand Up @@ -350,7 +350,7 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)
* generate interrupts. Don't even try to enable MSI.
*/
if (xhci->quirks & XHCI_BROKEN_MSI)
return 0;
goto legacy_irq;

/* unregister the legacy interrupt */
if (hcd->irq)
Expand All @@ -371,6 +371,7 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)
return -EINVAL;
}

legacy_irq:
/* fall back to legacy interrupt*/
ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
hcd->irq_descr, hcd);
Expand Down
4 changes: 2 additions & 2 deletions drivers/usb/host/xhci.h
Expand Up @@ -206,8 +206,8 @@ struct xhci_op_regs {
/* bits 12:31 are reserved (and should be preserved on writes). */

/* IMAN - Interrupt Management Register */
#define IMAN_IP (1 << 1)
#define IMAN_IE (1 << 0)
#define IMAN_IE (1 << 1)
#define IMAN_IP (1 << 0)

/* USBSTS - USB status - status bitmasks */
/* HC not running - set to 1 when run/stop bit is cleared. */
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/musb/da8xx.c
Expand Up @@ -327,7 +327,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
int err;

err = musb->int_usb & USB_INTR_VBUSERROR;
err = musb->int_usb & MUSB_INTR_VBUSERROR;
if (err) {
/*
* The Mentor core doesn't debounce VBUS as needed
Expand Down
9 changes: 7 additions & 2 deletions drivers/usb/musb/musb_gadget.c
Expand Up @@ -141,7 +141,9 @@ static inline void map_dma_buffer(struct musb_request *request,
static inline void unmap_dma_buffer(struct musb_request *request,
struct musb *musb)
{
if (!is_buffer_mapped(request))
struct musb_ep *musb_ep = request->ep;

if (!is_buffer_mapped(request) || !musb_ep->dma)
return;

if (request->request.dma == DMA_ADDR_INVALID) {
Expand Down Expand Up @@ -195,7 +197,10 @@ __acquires(ep->musb->lock)

ep->busy = 1;
spin_unlock(&musb->lock);
unmap_dma_buffer(req, musb);

if (!dma_mapping_error(&musb->g.dev, request->dma))
unmap_dma_buffer(req, musb);

if (request->status == 0)
dev_dbg(musb->controller, "%s done request %p, %d/%d\n",
ep->end_point.name, request,
Expand Down
10 changes: 6 additions & 4 deletions drivers/usb/serial/ark3116.c
Expand Up @@ -62,7 +62,6 @@ static int is_irda(struct usb_serial *serial)
}

struct ark3116_private {
wait_queue_head_t delta_msr_wait;
struct async_icount icount;
int irda; /* 1 for irda device */

Expand Down Expand Up @@ -146,7 +145,6 @@ static int ark3116_port_probe(struct usb_serial_port *port)
if (!priv)
return -ENOMEM;

init_waitqueue_head(&priv->delta_msr_wait);
mutex_init(&priv->hw_lock);
spin_lock_init(&priv->status_lock);

Expand Down Expand Up @@ -456,10 +454,14 @@ static int ark3116_ioctl(struct tty_struct *tty,
case TIOCMIWAIT:
for (;;) {
struct async_icount prev = priv->icount;
interruptible_sleep_on(&priv->delta_msr_wait);
interruptible_sleep_on(&port->delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;

if (port->serial->disconnected)
return -EIO;

if ((prev.rng == priv->icount.rng) &&
(prev.dsr == priv->icount.dsr) &&
(prev.dcd == priv->icount.dcd) &&
Expand Down Expand Up @@ -580,7 +582,7 @@ static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr)
priv->icount.dcd++;
if (msr & UART_MSR_TERI)
priv->icount.rng++;
wake_up_interruptible(&priv->delta_msr_wait);
wake_up_interruptible(&port->delta_msr_wait);
}
}

Expand Down
11 changes: 6 additions & 5 deletions drivers/usb/serial/ch341.c
Expand Up @@ -80,7 +80,6 @@ MODULE_DEVICE_TABLE(usb, id_table);

struct ch341_private {
spinlock_t lock; /* access lock */
wait_queue_head_t delta_msr_wait; /* wait queue for modem status */
unsigned baud_rate; /* set baud rate */
u8 line_control; /* set line control value RTS/DTR */
u8 line_status; /* active status of modem control inputs */
Expand Down Expand Up @@ -252,7 +251,6 @@ static int ch341_port_probe(struct usb_serial_port *port)
return -ENOMEM;

spin_lock_init(&priv->lock);
init_waitqueue_head(&priv->delta_msr_wait);
priv->baud_rate = DEFAULT_BAUD_RATE;
priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;

Expand Down Expand Up @@ -298,7 +296,7 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)
priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
spin_unlock_irqrestore(&priv->lock, flags);
ch341_set_handshake(port->serial->dev, priv->line_control);
wake_up_interruptible(&priv->delta_msr_wait);
wake_up_interruptible(&port->delta_msr_wait);
}

static void ch341_close(struct usb_serial_port *port)
Expand Down Expand Up @@ -491,7 +489,7 @@ static void ch341_read_int_callback(struct urb *urb)
tty_kref_put(tty);
}

wake_up_interruptible(&priv->delta_msr_wait);
wake_up_interruptible(&port->delta_msr_wait);
}

exit:
Expand All @@ -517,11 +515,14 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
spin_unlock_irqrestore(&priv->lock, flags);

while (!multi_change) {
interruptible_sleep_on(&priv->delta_msr_wait);
interruptible_sleep_on(&port->delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;

if (port->serial->disconnected)
return -EIO;

spin_lock_irqsave(&priv->lock, flags);
status = priv->line_status;
multi_change = priv->multi_status_change;
Expand Down

0 comments on commit 8f46c50

Please sign in to comment.