diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-03 11:48:58 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-03 11:48:58 -0500 |
| commit | 7f5b09c15ab989ed5ce4adda0be42c1302df70b7 (patch) | |
| tree | 9695b00983d1bd077ff91c463abcb136330cf344 /drivers/usb/class/cdc-acm.c | |
| parent | 94468080220162f74dc6ce5c3e95e5fec8022902 (diff) | |
| parent | cedf8a78421943441b9011ce7bcdab55f07d2ea6 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (220 commits)
USB: backlight, appledisplay: fix incomplete registration failure handling
USB: pl2303: remove unnecessary reset of usb_device in urbs
USB: ftdi_sio: remove obsolete check in unthrottle
USB: ftdi_sio: remove unused tx_bytes counter
USB: qcaux: driver for auxiliary serial ports on Qualcomm devices
USB: pl2303: initial TIOCGSERIAL support
USB: option: add Longcheer/Longsung vendor ID
USB: fix I2C API usage in ohci-pnx4008.
USB: usbmon: mask seconds properly in text API
USB: sisusbvga: no unnecessary GFP_ATOMIC
USB: storage: onetouch: unnecessary GFP_ATOMIC
USB: serial: ftdi: add CONTEC vendor and product id
USB: remove references to port->port.count from the serial drivers
USB: tty: Prune uses of tty_request_room in the USB layer
USB: tty: Add a function to insert a string of characters with the same flag
USB: don't read past config->interface[] if usb_control_msg() fails in usb_reset_configuration()
USB: tty: kill request_room for USB ACM class
USB: tty: sort out the request_room handling for whiteheat
USB: storage: fix misplaced parenthesis
USB: vstusb.c: removal of driver for Vernier Software & Technology, Inc., devices and spectrometers
...
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 |
