diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 170 |
1 files changed, 84 insertions, 86 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index a446f61ba44..b842635dde5 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -122,23 +122,13 @@ static void acm_release_minor(struct acm *acm) static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len) { - int retval; - - retval = usb_autopm_get_interface(acm->control); - if (retval) - return retval; - - retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), + int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), request, USB_RT_ACM, value, acm->control->altsetting[0].desc.bInterfaceNumber, buf, len, 5000); - dev_dbg(&acm->control->dev, "%s - rq 0x%02x, val %#x, len %#x, result %d\n", __func__, request, value, len, retval); - - usb_autopm_put_interface(acm->control); - return retval < 0 ? retval : 0; } @@ -242,9 +232,21 @@ static int acm_write_start(struct acm *acm, int wbn) acm->susp_count); usb_autopm_get_interface_async(acm->control); if (acm->susp_count) { - usb_anchor_urb(wb->urb, &acm->delayed); +#ifdef CONFIG_PM + acm->transmitting++; + wb->urb->transfer_buffer = wb->buf; + wb->urb->transfer_dma = wb->dmah; + wb->urb->transfer_buffer_length = wb->len; + wb->urb->dev = acm->dev; + usb_anchor_urb(wb->urb, &acm->deferred); +#else + if (!acm->delayed_wb) + acm->delayed_wb = wb; + else + usb_autopm_put_interface_async(acm->control); +#endif spin_unlock_irqrestore(&acm->write_lock, flags); - return 0; + return 0; /* A white lie */ } usb_mark_last_busy(acm->dev); rc = acm_start_wb(acm, wb); @@ -544,7 +546,6 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) { struct acm *acm = container_of(port, struct acm, port); int retval = -ENODEV; - int i; dev_dbg(&acm->control->dev, "%s\n", __func__); @@ -603,8 +604,6 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) return 0; error_submit_read_urbs: - for (i = 0; i < acm->rx_buflimit; i++) - usb_kill_urb(acm->read_urbs[i]); acm->ctrlout = 0; acm_set_control(acm, acm->ctrlout); error_set_control: @@ -632,8 +631,6 @@ static void acm_port_destruct(struct tty_port *port) static void acm_port_shutdown(struct tty_port *port) { struct acm *acm = container_of(port, struct acm, port); - struct urb *urb; - struct acm_wb *wb; int i; int pm_err; @@ -643,16 +640,6 @@ static void acm_port_shutdown(struct tty_port *port) if (!acm->disconnected) { pm_err = usb_autopm_get_interface(acm->control); acm_set_control(acm, acm->ctrlout = 0); - - for (;;) { - urb = usb_get_from_anchor(&acm->delayed); - if (!urb) - break; - wb = urb->context; - wb->use = 0; - usb_autopm_put_interface_async(acm->control); - } - usb_kill_urb(acm->ctrlurb); for (i = 0; i < ACM_NW; i++) usb_kill_urb(acm->wb[i].urb); @@ -937,12 +924,11 @@ static void acm_tty_set_termios(struct tty_struct *tty, /* FIXME: Needs to clear unsupported bits in the termios */ acm->clocal = ((termios->c_cflag & CLOCAL) != 0); - if (C_BAUD(tty) == B0) { + if (!newline.dwDTERate) { newline.dwDTERate = acm->line.dwDTERate; newctrl &= ~ACM_CTRL_DTR; - } else if (termios_old && (termios_old->c_cflag & CBAUD) == B0) { + } else newctrl |= ACM_CTRL_DTR; - } if (newctrl != acm->ctrlout) acm_set_control(acm, acm->ctrlout = newctrl); @@ -1272,7 +1258,6 @@ made_compressed_probe: acm->no_hangup_in_reset_resume = 1; tty_port_init(&acm->port); acm->port.ops = &acm_port_ops; - init_usb_anchor(&acm->delayed); buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); if (!buf) { @@ -1527,15 +1512,18 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) return -ENODEV; } - spin_lock_irq(&acm->read_lock); - spin_lock(&acm->write_lock); if (PMSG_IS_AUTO(message)) { - if (acm->transmitting) { - spin_unlock(&acm->write_lock); - spin_unlock_irq(&acm->read_lock); + int b; + + spin_lock_irq(&acm->write_lock); + b = acm->transmitting; + spin_unlock_irq(&acm->write_lock); + if (b) return -EBUSY; - } } + + spin_lock_irq(&acm->read_lock); + spin_lock(&acm->write_lock); cnt = acm->susp_count++; spin_unlock(&acm->write_lock); spin_unlock_irq(&acm->read_lock); @@ -1543,7 +1531,8 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) if (cnt) return 0; - stop_data_traffic(acm); + if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) + stop_data_traffic(acm); return 0; } @@ -1551,31 +1540,57 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) static int acm_resume(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); - struct urb *urb; - int rv = 0; + int rv = 0; + int cnt; +#ifdef CONFIG_PM + struct urb *res; +#else + struct acm_wb *wb; +#endif - if (!acm) { - pr_err("%s: !acm\n", __func__); - return -ENODEV; - } + if (!acm) { + pr_err("%s: !acm\n", __func__); + return -ENODEV; + } - spin_lock_irq(&acm->read_lock); - spin_lock(&acm->write_lock); - if (acm->susp_count <= 0) - goto out; + spin_lock_irq(&acm->read_lock); + if (acm->susp_count > 0) { + acm->susp_count -= 1; + cnt = acm->susp_count; + } else { + spin_unlock_irq(&acm->read_lock); + return 0; + } + spin_unlock_irq(&acm->read_lock); - if (--acm->susp_count) - goto out; + if (cnt) + return 0; if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { - rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC); - - for (;;) { - urb = usb_get_from_anchor(&acm->delayed); - if (!urb) - break; - - acm_start_wb(acm, urb->context); + rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); + spin_lock_irq(&acm->write_lock); +#ifdef CONFIG_PM + while ((res = usb_get_from_anchor(&acm->deferred))) { + /* decrement ref count*/ + usb_put_urb(res); + rv = usb_submit_urb(res, GFP_ATOMIC); + if (rv < 0) { + dev_dbg(&acm->data->dev, + "usb_submit_urb(pending request) failed: %d", + rv); + usb_unanchor_urb(res); + acm_write_done(acm, res->context); + } + } + spin_unlock_irq(&acm->write_lock); +#else + if (acm->delayed_wb) { + wb = acm->delayed_wb; + acm->delayed_wb = NULL; + spin_unlock_irq(&acm->write_lock); + acm_start_wb(acm, wb); + } else { + spin_unlock_irq(&acm->write_lock); } /* @@ -1583,14 +1598,12 @@ static int acm_resume(struct usb_interface *intf) * do the write path at all cost */ if (rv < 0) - goto out; + goto err_out; - rv = acm_submit_read_urbs(acm, GFP_ATOMIC); + rv = acm_submit_read_urbs(acm, GFP_NOIO); } -out: - spin_unlock(&acm->write_lock); - spin_unlock_irq(&acm->read_lock); +err_out: return rv; } @@ -1675,32 +1688,17 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, - { USB_DEVICE(0x2184, 0x001c) }, /* GW Instek AFG-2225 */ { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ }, /* Motorola H24 HSPA module: */ { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */ - { USB_DEVICE(0x22b8, 0x2d92), /* modem + diagnostics */ - .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ - }, - { USB_DEVICE(0x22b8, 0x2d93), /* modem + AT port */ - .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ - }, - { USB_DEVICE(0x22b8, 0x2d95), /* modem + AT port + diagnostics */ - .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ - }, - { USB_DEVICE(0x22b8, 0x2d96), /* modem + NMEA */ - .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ - }, - { USB_DEVICE(0x22b8, 0x2d97), /* modem + diagnostics + NMEA */ - .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ - }, - { USB_DEVICE(0x22b8, 0x2d99), /* modem + AT port + NMEA */ - .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ - }, - { USB_DEVICE(0x22b8, 0x2d9a), /* modem + AT port + diagnostics + NMEA */ - .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ - }, + { USB_DEVICE(0x22b8, 0x2d92) }, /* modem + diagnostics */ + { USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port */ + { USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics */ + { USB_DEVICE(0x22b8, 0x2d96) }, /* modem + NMEA */ + { USB_DEVICE(0x22b8, 0x2d97) }, /* modem + diagnostics + NMEA */ + { USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port + NMEA */ + { USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */ { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */ .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on |
