diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 82 |
1 files changed, 53 insertions, 29 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 34d4eb98829e..975d556b4787 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, acm->delayed_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,6 +1461,23 @@ 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 */ |
1464 | 1482 | ||
1465 | #define NOKIA_PCSUITE_ACM_INFO(x) \ | 1483 | #define NOKIA_PCSUITE_ACM_INFO(x) \ |
@@ -1471,7 +1489,7 @@ err_out: | |||
1471 | * USB driver structure. | 1489 | * USB driver structure. |
1472 | */ | 1490 | */ |
1473 | 1491 | ||
1474 | static struct usb_device_id acm_ids[] = { | 1492 | static const struct usb_device_id acm_ids[] = { |
1475 | /* quirky and broken devices */ | 1493 | /* quirky and broken devices */ |
1476 | { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ | 1494 | { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ |
1477 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ | 1495 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ |
@@ -1576,6 +1594,11 @@ static struct usb_device_id acm_ids[] = { | |||
1576 | 1594 | ||
1577 | /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ | 1595 | /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ |
1578 | 1596 | ||
1597 | /* Support Lego NXT using pbLua firmware */ | ||
1598 | { USB_DEVICE(0x0694, 0xff00), | ||
1599 | .driver_info = NOT_A_MODEM, | ||
1600 | }, | ||
1601 | |||
1579 | /* control interfaces with various AT-command sets */ | 1602 | /* control interfaces with various AT-command sets */ |
1580 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1603 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1581 | USB_CDC_ACM_PROTO_AT_V25TER) }, | 1604 | USB_CDC_ACM_PROTO_AT_V25TER) }, |
@@ -1602,6 +1625,7 @@ static struct usb_driver acm_driver = { | |||
1602 | #ifdef CONFIG_PM | 1625 | #ifdef CONFIG_PM |
1603 | .suspend = acm_suspend, | 1626 | .suspend = acm_suspend, |
1604 | .resume = acm_resume, | 1627 | .resume = acm_resume, |
1628 | .reset_resume = acm_reset_resume, | ||
1605 | #endif | 1629 | #endif |
1606 | .id_table = acm_ids, | 1630 | .id_table = acm_ids, |
1607 | #ifdef CONFIG_PM | 1631 | #ifdef CONFIG_PM |