diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 143 |
1 files changed, 113 insertions, 30 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index e4eca7810bcf..5e1a253b08a0 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -170,6 +170,7 @@ static void acm_write_done(struct acm *acm, struct acm_wb *wb) | |||
170 | { | 170 | { |
171 | wb->use = 0; | 171 | wb->use = 0; |
172 | acm->transmitting--; | 172 | acm->transmitting--; |
173 | usb_autopm_put_interface_async(acm->control); | ||
173 | } | 174 | } |
174 | 175 | ||
175 | /* | 176 | /* |
@@ -211,9 +212,12 @@ static int acm_write_start(struct acm *acm, int wbn) | |||
211 | } | 212 | } |
212 | 213 | ||
213 | dbg("%s susp_count: %d", __func__, acm->susp_count); | 214 | dbg("%s susp_count: %d", __func__, acm->susp_count); |
215 | usb_autopm_get_interface_async(acm->control); | ||
214 | if (acm->susp_count) { | 216 | if (acm->susp_count) { |
215 | acm->delayed_wb = wb; | 217 | if (!acm->delayed_wb) |
216 | schedule_work(&acm->waker); | 218 | acm->delayed_wb = wb; |
219 | else | ||
220 | usb_autopm_put_interface_async(acm->control); | ||
217 | spin_unlock_irqrestore(&acm->write_lock, flags); | 221 | spin_unlock_irqrestore(&acm->write_lock, flags); |
218 | return 0; /* A white lie */ | 222 | return 0; /* A white lie */ |
219 | } | 223 | } |
@@ -424,7 +428,6 @@ next_buffer: | |||
424 | throttled = acm->throttle; | 428 | throttled = acm->throttle; |
425 | spin_unlock_irqrestore(&acm->throttle_lock, flags); | 429 | spin_unlock_irqrestore(&acm->throttle_lock, flags); |
426 | if (!throttled) { | 430 | if (!throttled) { |
427 | tty_buffer_request_room(tty, buf->size); | ||
428 | tty_insert_flip_string(tty, buf->base, buf->size); | 431 | tty_insert_flip_string(tty, buf->base, buf->size); |
429 | tty_flip_buffer_push(tty); | 432 | tty_flip_buffer_push(tty); |
430 | } else { | 433 | } else { |
@@ -534,23 +537,6 @@ static void acm_softint(struct work_struct *work) | |||
534 | tty_kref_put(tty); | 537 | tty_kref_put(tty); |
535 | } | 538 | } |
536 | 539 | ||
537 | static void acm_waker(struct work_struct *waker) | ||
538 | { | ||
539 | struct acm *acm = container_of(waker, struct acm, waker); | ||
540 | int rv; | ||
541 | |||
542 | rv = usb_autopm_get_interface(acm->control); | ||
543 | if (rv < 0) { | ||
544 | dev_err(&acm->dev->dev, "Autopm failure in %s\n", __func__); | ||
545 | return; | ||
546 | } | ||
547 | if (acm->delayed_wb) { | ||
548 | acm_start_wb(acm, acm->delayed_wb); | ||
549 | acm->delayed_wb = NULL; | ||
550 | } | ||
551 | usb_autopm_put_interface(acm->control); | ||
552 | } | ||
553 | |||
554 | /* | 540 | /* |
555 | * TTY handlers | 541 | * TTY handlers |
556 | */ | 542 | */ |
@@ -566,7 +552,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
566 | 552 | ||
567 | acm = acm_table[tty->index]; | 553 | acm = acm_table[tty->index]; |
568 | if (!acm || !acm->dev) | 554 | if (!acm || !acm->dev) |
569 | goto err_out; | 555 | goto out; |
570 | else | 556 | else |
571 | rv = 0; | 557 | rv = 0; |
572 | 558 | ||
@@ -582,8 +568,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
582 | 568 | ||
583 | mutex_lock(&acm->mutex); | 569 | mutex_lock(&acm->mutex); |
584 | if (acm->port.count++) { | 570 | if (acm->port.count++) { |
571 | mutex_unlock(&acm->mutex); | ||
585 | usb_autopm_put_interface(acm->control); | 572 | usb_autopm_put_interface(acm->control); |
586 | goto done; | 573 | goto out; |
587 | } | 574 | } |
588 | 575 | ||
589 | acm->ctrlurb->dev = acm->dev; | 576 | acm->ctrlurb->dev = acm->dev; |
@@ -612,18 +599,18 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
612 | set_bit(ASYNCB_INITIALIZED, &acm->port.flags); | 599 | set_bit(ASYNCB_INITIALIZED, &acm->port.flags); |
613 | rv = tty_port_block_til_ready(&acm->port, tty, filp); | 600 | rv = tty_port_block_til_ready(&acm->port, tty, filp); |
614 | tasklet_schedule(&acm->urb_task); | 601 | tasklet_schedule(&acm->urb_task); |
615 | done: | 602 | |
616 | mutex_unlock(&acm->mutex); | 603 | mutex_unlock(&acm->mutex); |
617 | err_out: | 604 | out: |
618 | mutex_unlock(&open_mutex); | 605 | mutex_unlock(&open_mutex); |
619 | return rv; | 606 | return rv; |
620 | 607 | ||
621 | full_bailout: | 608 | full_bailout: |
622 | usb_kill_urb(acm->ctrlurb); | 609 | usb_kill_urb(acm->ctrlurb); |
623 | bail_out: | 610 | bail_out: |
624 | usb_autopm_put_interface(acm->control); | ||
625 | acm->port.count--; | 611 | acm->port.count--; |
626 | mutex_unlock(&acm->mutex); | 612 | mutex_unlock(&acm->mutex); |
613 | usb_autopm_put_interface(acm->control); | ||
627 | early_bail: | 614 | early_bail: |
628 | mutex_unlock(&open_mutex); | 615 | mutex_unlock(&open_mutex); |
629 | tty_port_tty_set(&acm->port, NULL); | 616 | tty_port_tty_set(&acm->port, NULL); |
@@ -1023,7 +1010,7 @@ static int acm_probe(struct usb_interface *intf, | |||
1023 | case USB_CDC_CALL_MANAGEMENT_TYPE: | 1010 | case USB_CDC_CALL_MANAGEMENT_TYPE: |
1024 | call_management_function = buffer[3]; | 1011 | call_management_function = buffer[3]; |
1025 | call_interface_num = buffer[4]; | 1012 | call_interface_num = buffer[4]; |
1026 | if ((call_management_function & 3) != 3) | 1013 | if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3) |
1027 | dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); | 1014 | dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); |
1028 | break; | 1015 | break; |
1029 | default: | 1016 | default: |
@@ -1178,7 +1165,6 @@ made_compressed_probe: | |||
1178 | acm->urb_task.func = acm_rx_tasklet; | 1165 | acm->urb_task.func = acm_rx_tasklet; |
1179 | acm->urb_task.data = (unsigned long) acm; | 1166 | acm->urb_task.data = (unsigned long) acm; |
1180 | INIT_WORK(&acm->work, acm_softint); | 1167 | INIT_WORK(&acm->work, acm_softint); |
1181 | INIT_WORK(&acm->waker, acm_waker); | ||
1182 | init_waitqueue_head(&acm->drain_wait); | 1168 | init_waitqueue_head(&acm->drain_wait); |
1183 | spin_lock_init(&acm->throttle_lock); | 1169 | spin_lock_init(&acm->throttle_lock); |
1184 | spin_lock_init(&acm->write_lock); | 1170 | spin_lock_init(&acm->write_lock); |
@@ -1343,7 +1329,6 @@ static void stop_data_traffic(struct acm *acm) | |||
1343 | tasklet_enable(&acm->urb_task); | 1329 | tasklet_enable(&acm->urb_task); |
1344 | 1330 | ||
1345 | cancel_work_sync(&acm->work); | 1331 | cancel_work_sync(&acm->work); |
1346 | cancel_work_sync(&acm->waker); | ||
1347 | } | 1332 | } |
1348 | 1333 | ||
1349 | static void acm_disconnect(struct usb_interface *intf) | 1334 | static void acm_disconnect(struct usb_interface *intf) |
@@ -1435,6 +1420,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) | |||
1435 | static int acm_resume(struct usb_interface *intf) | 1420 | static int acm_resume(struct usb_interface *intf) |
1436 | { | 1421 | { |
1437 | struct acm *acm = usb_get_intfdata(intf); | 1422 | struct acm *acm = usb_get_intfdata(intf); |
1423 | struct acm_wb *wb; | ||
1438 | int rv = 0; | 1424 | int rv = 0; |
1439 | int cnt; | 1425 | int cnt; |
1440 | 1426 | ||
@@ -1449,6 +1435,21 @@ static int acm_resume(struct usb_interface *intf) | |||
1449 | mutex_lock(&acm->mutex); | 1435 | mutex_lock(&acm->mutex); |
1450 | if (acm->port.count) { | 1436 | if (acm->port.count) { |
1451 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); | 1437 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); |
1438 | |||
1439 | spin_lock_irq(&acm->write_lock); | ||
1440 | if (acm->delayed_wb) { | ||
1441 | wb = acm->delayed_wb; | ||
1442 | acm->delayed_wb = NULL; | ||
1443 | spin_unlock_irq(&acm->write_lock); | ||
1444 | acm_start_wb(acm, wb); | ||
1445 | } else { | ||
1446 | spin_unlock_irq(&acm->write_lock); | ||
1447 | } | ||
1448 | |||
1449 | /* | ||
1450 | * delayed error checking because we must | ||
1451 | * do the write path at all cost | ||
1452 | */ | ||
1452 | if (rv < 0) | 1453 | if (rv < 0) |
1453 | goto err_out; | 1454 | goto err_out; |
1454 | 1455 | ||
@@ -1460,12 +1461,35 @@ err_out: | |||
1460 | return rv; | 1461 | return rv; |
1461 | } | 1462 | } |
1462 | 1463 | ||
1464 | static int acm_reset_resume(struct usb_interface *intf) | ||
1465 | { | ||
1466 | struct acm *acm = usb_get_intfdata(intf); | ||
1467 | struct tty_struct *tty; | ||
1468 | |||
1469 | mutex_lock(&acm->mutex); | ||
1470 | if (acm->port.count) { | ||
1471 | tty = tty_port_tty_get(&acm->port); | ||
1472 | if (tty) { | ||
1473 | tty_hangup(tty); | ||
1474 | tty_kref_put(tty); | ||
1475 | } | ||
1476 | } | ||
1477 | mutex_unlock(&acm->mutex); | ||
1478 | return acm_resume(intf); | ||
1479 | } | ||
1480 | |||
1463 | #endif /* CONFIG_PM */ | 1481 | #endif /* CONFIG_PM */ |
1482 | |||
1483 | #define NOKIA_PCSUITE_ACM_INFO(x) \ | ||
1484 | USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \ | ||
1485 | USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ | ||
1486 | USB_CDC_ACM_PROTO_VENDOR) | ||
1487 | |||
1464 | /* | 1488 | /* |
1465 | * USB driver structure. | 1489 | * USB driver structure. |
1466 | */ | 1490 | */ |
1467 | 1491 | ||
1468 | static struct usb_device_id acm_ids[] = { | 1492 | static const struct usb_device_id acm_ids[] = { |
1469 | /* quirky and broken devices */ | 1493 | /* quirky and broken devices */ |
1470 | { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ | 1494 | { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ |
1471 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ | 1495 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ |
@@ -1518,6 +1542,65 @@ static struct usb_device_id acm_ids[] = { | |||
1518 | { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ | 1542 | { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ |
1519 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ | 1543 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ |
1520 | }, | 1544 | }, |
1545 | { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */ | ||
1546 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ | ||
1547 | }, | ||
1548 | |||
1549 | /* Nokia S60 phones expose two ACM channels. The first is | ||
1550 | * a modem and is picked up by the standard AT-command | ||
1551 | * information below. The second is 'vendor-specific' but | ||
1552 | * is treated as a serial device at the S60 end, so we want | ||
1553 | * to expose it on Linux too. */ | ||
1554 | { NOKIA_PCSUITE_ACM_INFO(0x042D), }, /* Nokia 3250 */ | ||
1555 | { NOKIA_PCSUITE_ACM_INFO(0x04D8), }, /* Nokia 5500 Sport */ | ||
1556 | { NOKIA_PCSUITE_ACM_INFO(0x04C9), }, /* Nokia E50 */ | ||
1557 | { NOKIA_PCSUITE_ACM_INFO(0x0419), }, /* Nokia E60 */ | ||
1558 | { NOKIA_PCSUITE_ACM_INFO(0x044D), }, /* Nokia E61 */ | ||
1559 | { NOKIA_PCSUITE_ACM_INFO(0x0001), }, /* Nokia E61i */ | ||
1560 | { NOKIA_PCSUITE_ACM_INFO(0x0475), }, /* Nokia E62 */ | ||
1561 | { NOKIA_PCSUITE_ACM_INFO(0x0508), }, /* Nokia E65 */ | ||
1562 | { NOKIA_PCSUITE_ACM_INFO(0x0418), }, /* Nokia E70 */ | ||
1563 | { NOKIA_PCSUITE_ACM_INFO(0x0425), }, /* Nokia N71 */ | ||
1564 | { NOKIA_PCSUITE_ACM_INFO(0x0486), }, /* Nokia N73 */ | ||
1565 | { NOKIA_PCSUITE_ACM_INFO(0x04DF), }, /* Nokia N75 */ | ||
1566 | { NOKIA_PCSUITE_ACM_INFO(0x000e), }, /* Nokia N77 */ | ||
1567 | { NOKIA_PCSUITE_ACM_INFO(0x0445), }, /* Nokia N80 */ | ||
1568 | { NOKIA_PCSUITE_ACM_INFO(0x042F), }, /* Nokia N91 & N91 8GB */ | ||
1569 | { NOKIA_PCSUITE_ACM_INFO(0x048E), }, /* Nokia N92 */ | ||
1570 | { NOKIA_PCSUITE_ACM_INFO(0x0420), }, /* Nokia N93 */ | ||
1571 | { NOKIA_PCSUITE_ACM_INFO(0x04E6), }, /* Nokia N93i */ | ||
1572 | { NOKIA_PCSUITE_ACM_INFO(0x04B2), }, /* Nokia 5700 XpressMusic */ | ||
1573 | { NOKIA_PCSUITE_ACM_INFO(0x0134), }, /* Nokia 6110 Navigator (China) */ | ||
1574 | { NOKIA_PCSUITE_ACM_INFO(0x046E), }, /* Nokia 6110 Navigator */ | ||
1575 | { NOKIA_PCSUITE_ACM_INFO(0x002f), }, /* Nokia 6120 classic & */ | ||
1576 | { NOKIA_PCSUITE_ACM_INFO(0x0088), }, /* Nokia 6121 classic */ | ||
1577 | { NOKIA_PCSUITE_ACM_INFO(0x00fc), }, /* Nokia 6124 classic */ | ||
1578 | { NOKIA_PCSUITE_ACM_INFO(0x0042), }, /* Nokia E51 */ | ||
1579 | { NOKIA_PCSUITE_ACM_INFO(0x00b0), }, /* Nokia E66 */ | ||
1580 | { NOKIA_PCSUITE_ACM_INFO(0x00ab), }, /* Nokia E71 */ | ||
1581 | { NOKIA_PCSUITE_ACM_INFO(0x0481), }, /* Nokia N76 */ | ||
1582 | { NOKIA_PCSUITE_ACM_INFO(0x0007), }, /* Nokia N81 & N81 8GB */ | ||
1583 | { NOKIA_PCSUITE_ACM_INFO(0x0071), }, /* Nokia N82 */ | ||
1584 | { NOKIA_PCSUITE_ACM_INFO(0x04F0), }, /* Nokia N95 & N95-3 NAM */ | ||
1585 | { NOKIA_PCSUITE_ACM_INFO(0x0070), }, /* Nokia N95 8GB */ | ||
1586 | { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */ | ||
1587 | { NOKIA_PCSUITE_ACM_INFO(0x0099), }, /* Nokia 6210 Navigator, RM-367 */ | ||
1588 | { NOKIA_PCSUITE_ACM_INFO(0x0128), }, /* Nokia 6210 Navigator, RM-419 */ | ||
1589 | { NOKIA_PCSUITE_ACM_INFO(0x008f), }, /* Nokia 6220 Classic */ | ||
1590 | { NOKIA_PCSUITE_ACM_INFO(0x00a0), }, /* Nokia 6650 */ | ||
1591 | { NOKIA_PCSUITE_ACM_INFO(0x007b), }, /* Nokia N78 */ | ||
1592 | { NOKIA_PCSUITE_ACM_INFO(0x0094), }, /* Nokia N85 */ | ||
1593 | { NOKIA_PCSUITE_ACM_INFO(0x003a), }, /* Nokia N96 & N96-3 */ | ||
1594 | { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */ | ||
1595 | { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */ | ||
1596 | { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */ | ||
1597 | |||
1598 | /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ | ||
1599 | |||
1600 | /* Support Lego NXT using pbLua firmware */ | ||
1601 | { USB_DEVICE(0x0694, 0xff00), | ||
1602 | .driver_info = NOT_A_MODEM, | ||
1603 | }, | ||
1521 | 1604 | ||
1522 | /* control interfaces with various AT-command sets */ | 1605 | /* control interfaces with various AT-command sets */ |
1523 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1606 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
@@ -1533,7 +1616,6 @@ static struct usb_device_id acm_ids[] = { | |||
1533 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1616 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1534 | USB_CDC_ACM_PROTO_AT_CDMA) }, | 1617 | USB_CDC_ACM_PROTO_AT_CDMA) }, |
1535 | 1618 | ||
1536 | /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */ | ||
1537 | { } | 1619 | { } |
1538 | }; | 1620 | }; |
1539 | 1621 | ||
@@ -1546,6 +1628,7 @@ static struct usb_driver acm_driver = { | |||
1546 | #ifdef CONFIG_PM | 1628 | #ifdef CONFIG_PM |
1547 | .suspend = acm_suspend, | 1629 | .suspend = acm_suspend, |
1548 | .resume = acm_resume, | 1630 | .resume = acm_resume, |
1631 | .reset_resume = acm_reset_resume, | ||
1549 | #endif | 1632 | #endif |
1550 | .id_table = acm_ids, | 1633 | .id_table = acm_ids, |
1551 | #ifdef CONFIG_PM | 1634 | #ifdef CONFIG_PM |