aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/class/cdc-acm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r--drivers/usb/class/cdc-acm.c170
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