diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 15:09:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 15:09:47 -0500 |
commit | 55b81e6f2795484ea8edf5805c95c007cacfa736 (patch) | |
tree | c3724975107857fcc03b5dd649c462e4f72397be /drivers/usb/class | |
parent | 5983faf942f260023e547f3c5f38c1033c35cc9b (diff) | |
parent | 08e87d0d773dc9ca5faf4c3306e238ed0ea129b0 (diff) |
Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (232 commits)
USB: Add USB-ID for Multiplex RC serial adapter to cp210x.c
xhci: Clean up 32-bit build warnings.
USB: update documentation for usbmon
usb: usb-storage doesn't support dynamic id currently, the patch disables the feature to fix an oops
drivers/usb/class/cdc-acm.c: clear dangling pointer
drivers/usb/dwc3/dwc3-pci.c: introduce missing kfree
drivers/usb/host/isp1760-if.c: introduce missing kfree
usb: option: add ZD Incorporated HSPA modem
usb: ch9: fix up MaxStreams helper
USB: usb-skeleton.c: cleanup open_count
USB: usb-skeleton.c: fix open/disconnect race
xhci: Properly handle COMP_2ND_BW_ERR
USB: remove dead code from suspend/resume path
USB: add quirk for another camera
drivers: usb: wusbcore: Fix dependency for USB_WUSB
xhci: Better debugging for critical host errors.
xhci: Be less verbose during URB cancellation.
xhci: Remove debugging about ring structure allocation.
xhci: Remove debugging about toggling cycle bits.
xhci: Remove debugging for individual transfers.
...
Diffstat (limited to 'drivers/usb/class')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 338 | ||||
-rw-r--r-- | drivers/usb/class/cdc-acm.h | 1 |
2 files changed, 193 insertions, 146 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index a8078d0638fa..9543b19d410c 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -58,12 +58,62 @@ static struct usb_driver acm_driver; | |||
58 | static struct tty_driver *acm_tty_driver; | 58 | static struct tty_driver *acm_tty_driver; |
59 | static struct acm *acm_table[ACM_TTY_MINORS]; | 59 | static struct acm *acm_table[ACM_TTY_MINORS]; |
60 | 60 | ||
61 | static DEFINE_MUTEX(open_mutex); | 61 | static DEFINE_MUTEX(acm_table_lock); |
62 | 62 | ||
63 | #define ACM_READY(acm) (acm && acm->dev && acm->port.count) | 63 | /* |
64 | * acm_table accessors | ||
65 | */ | ||
64 | 66 | ||
65 | static const struct tty_port_operations acm_port_ops = { | 67 | /* |
66 | }; | 68 | * Look up an ACM structure by index. If found and not disconnected, increment |
69 | * its refcount and return it with its mutex held. | ||
70 | */ | ||
71 | static struct acm *acm_get_by_index(unsigned index) | ||
72 | { | ||
73 | struct acm *acm; | ||
74 | |||
75 | mutex_lock(&acm_table_lock); | ||
76 | acm = acm_table[index]; | ||
77 | if (acm) { | ||
78 | mutex_lock(&acm->mutex); | ||
79 | if (acm->disconnected) { | ||
80 | mutex_unlock(&acm->mutex); | ||
81 | acm = NULL; | ||
82 | } else { | ||
83 | tty_port_get(&acm->port); | ||
84 | mutex_unlock(&acm->mutex); | ||
85 | } | ||
86 | } | ||
87 | mutex_unlock(&acm_table_lock); | ||
88 | return acm; | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Try to find an available minor number and if found, associate it with 'acm'. | ||
93 | */ | ||
94 | static int acm_alloc_minor(struct acm *acm) | ||
95 | { | ||
96 | int minor; | ||
97 | |||
98 | mutex_lock(&acm_table_lock); | ||
99 | for (minor = 0; minor < ACM_TTY_MINORS; minor++) { | ||
100 | if (!acm_table[minor]) { | ||
101 | acm_table[minor] = acm; | ||
102 | break; | ||
103 | } | ||
104 | } | ||
105 | mutex_unlock(&acm_table_lock); | ||
106 | |||
107 | return minor; | ||
108 | } | ||
109 | |||
110 | /* Release the minor number associated with 'acm'. */ | ||
111 | static void acm_release_minor(struct acm *acm) | ||
112 | { | ||
113 | mutex_lock(&acm_table_lock); | ||
114 | acm_table[acm->minor] = NULL; | ||
115 | mutex_unlock(&acm_table_lock); | ||
116 | } | ||
67 | 117 | ||
68 | /* | 118 | /* |
69 | * Functions for ACM control messages. | 119 | * Functions for ACM control messages. |
@@ -267,9 +317,6 @@ static void acm_ctrl_irq(struct urb *urb) | |||
267 | goto exit; | 317 | goto exit; |
268 | } | 318 | } |
269 | 319 | ||
270 | if (!ACM_READY(acm)) | ||
271 | goto exit; | ||
272 | |||
273 | usb_mark_last_busy(acm->dev); | 320 | usb_mark_last_busy(acm->dev); |
274 | 321 | ||
275 | data = (unsigned char *)(dr + 1); | 322 | data = (unsigned char *)(dr + 1); |
@@ -429,8 +476,7 @@ static void acm_write_bulk(struct urb *urb) | |||
429 | spin_lock_irqsave(&acm->write_lock, flags); | 476 | spin_lock_irqsave(&acm->write_lock, flags); |
430 | acm_write_done(acm, wb); | 477 | acm_write_done(acm, wb); |
431 | spin_unlock_irqrestore(&acm->write_lock, flags); | 478 | spin_unlock_irqrestore(&acm->write_lock, flags); |
432 | if (ACM_READY(acm)) | 479 | schedule_work(&acm->work); |
433 | schedule_work(&acm->work); | ||
434 | } | 480 | } |
435 | 481 | ||
436 | static void acm_softint(struct work_struct *work) | 482 | static void acm_softint(struct work_struct *work) |
@@ -440,8 +486,6 @@ static void acm_softint(struct work_struct *work) | |||
440 | 486 | ||
441 | dev_vdbg(&acm->data->dev, "%s\n", __func__); | 487 | dev_vdbg(&acm->data->dev, "%s\n", __func__); |
442 | 488 | ||
443 | if (!ACM_READY(acm)) | ||
444 | return; | ||
445 | tty = tty_port_tty_get(&acm->port); | 489 | tty = tty_port_tty_get(&acm->port); |
446 | if (!tty) | 490 | if (!tty) |
447 | return; | 491 | return; |
@@ -453,93 +497,122 @@ static void acm_softint(struct work_struct *work) | |||
453 | * TTY handlers | 497 | * TTY handlers |
454 | */ | 498 | */ |
455 | 499 | ||
456 | static int acm_tty_open(struct tty_struct *tty, struct file *filp) | 500 | static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty) |
457 | { | 501 | { |
458 | struct acm *acm; | 502 | struct acm *acm; |
459 | int rv = -ENODEV; | 503 | int retval; |
460 | |||
461 | mutex_lock(&open_mutex); | ||
462 | 504 | ||
463 | acm = acm_table[tty->index]; | 505 | dev_dbg(tty->dev, "%s\n", __func__); |
464 | if (!acm || !acm->dev) | ||
465 | goto out; | ||
466 | else | ||
467 | rv = 0; | ||
468 | 506 | ||
469 | dev_dbg(&acm->control->dev, "%s\n", __func__); | 507 | acm = acm_get_by_index(tty->index); |
508 | if (!acm) | ||
509 | return -ENODEV; | ||
470 | 510 | ||
471 | set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); | 511 | retval = tty_init_termios(tty); |
512 | if (retval) | ||
513 | goto error_init_termios; | ||
472 | 514 | ||
473 | tty->driver_data = acm; | 515 | tty->driver_data = acm; |
474 | tty_port_tty_set(&acm->port, tty); | ||
475 | 516 | ||
476 | if (usb_autopm_get_interface(acm->control) < 0) | 517 | /* Final install (we use the default method) */ |
477 | goto early_bail; | 518 | tty_driver_kref_get(driver); |
478 | else | 519 | tty->count++; |
479 | acm->control->needs_remote_wakeup = 1; | 520 | driver->ttys[tty->index] = tty; |
521 | |||
522 | return 0; | ||
523 | |||
524 | error_init_termios: | ||
525 | tty_port_put(&acm->port); | ||
526 | return retval; | ||
527 | } | ||
528 | |||
529 | static int acm_tty_open(struct tty_struct *tty, struct file *filp) | ||
530 | { | ||
531 | struct acm *acm = tty->driver_data; | ||
532 | |||
533 | dev_dbg(tty->dev, "%s\n", __func__); | ||
534 | |||
535 | return tty_port_open(&acm->port, tty, filp); | ||
536 | } | ||
537 | |||
538 | static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) | ||
539 | { | ||
540 | struct acm *acm = container_of(port, struct acm, port); | ||
541 | int retval = -ENODEV; | ||
542 | |||
543 | dev_dbg(&acm->control->dev, "%s\n", __func__); | ||
480 | 544 | ||
481 | mutex_lock(&acm->mutex); | 545 | mutex_lock(&acm->mutex); |
482 | if (acm->port.count++) { | 546 | if (acm->disconnected) |
483 | mutex_unlock(&acm->mutex); | 547 | goto disconnected; |
484 | usb_autopm_put_interface(acm->control); | 548 | |
485 | goto out; | 549 | retval = usb_autopm_get_interface(acm->control); |
486 | } | 550 | if (retval) |
551 | goto error_get_interface; | ||
552 | |||
553 | /* | ||
554 | * FIXME: Why do we need this? Allocating 64K of physically contiguous | ||
555 | * memory is really nasty... | ||
556 | */ | ||
557 | set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); | ||
558 | acm->control->needs_remote_wakeup = 1; | ||
487 | 559 | ||
488 | acm->ctrlurb->dev = acm->dev; | 560 | acm->ctrlurb->dev = acm->dev; |
489 | if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { | 561 | if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { |
490 | dev_err(&acm->control->dev, | 562 | dev_err(&acm->control->dev, |
491 | "%s - usb_submit_urb(ctrl irq) failed\n", __func__); | 563 | "%s - usb_submit_urb(ctrl irq) failed\n", __func__); |
492 | goto bail_out; | 564 | goto error_submit_urb; |
493 | } | 565 | } |
494 | 566 | ||
495 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && | 567 | acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS; |
568 | if (acm_set_control(acm, acm->ctrlout) < 0 && | ||
496 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) | 569 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) |
497 | goto bail_out; | 570 | goto error_set_control; |
498 | 571 | ||
499 | usb_autopm_put_interface(acm->control); | 572 | usb_autopm_put_interface(acm->control); |
500 | 573 | ||
501 | if (acm_submit_read_urbs(acm, GFP_KERNEL)) | 574 | if (acm_submit_read_urbs(acm, GFP_KERNEL)) |
502 | goto bail_out; | 575 | goto error_submit_read_urbs; |
503 | |||
504 | set_bit(ASYNCB_INITIALIZED, &acm->port.flags); | ||
505 | rv = tty_port_block_til_ready(&acm->port, tty, filp); | ||
506 | 576 | ||
507 | mutex_unlock(&acm->mutex); | 577 | mutex_unlock(&acm->mutex); |
508 | out: | ||
509 | mutex_unlock(&open_mutex); | ||
510 | return rv; | ||
511 | 578 | ||
512 | bail_out: | 579 | return 0; |
513 | acm->port.count--; | 580 | |
514 | mutex_unlock(&acm->mutex); | 581 | error_submit_read_urbs: |
582 | acm->ctrlout = 0; | ||
583 | acm_set_control(acm, acm->ctrlout); | ||
584 | error_set_control: | ||
585 | usb_kill_urb(acm->ctrlurb); | ||
586 | error_submit_urb: | ||
515 | usb_autopm_put_interface(acm->control); | 587 | usb_autopm_put_interface(acm->control); |
516 | early_bail: | 588 | error_get_interface: |
517 | mutex_unlock(&open_mutex); | 589 | disconnected: |
518 | tty_port_tty_set(&acm->port, NULL); | 590 | mutex_unlock(&acm->mutex); |
519 | return -EIO; | 591 | return retval; |
520 | } | 592 | } |
521 | 593 | ||
522 | static void acm_tty_unregister(struct acm *acm) | 594 | static void acm_port_destruct(struct tty_port *port) |
523 | { | 595 | { |
524 | int i; | 596 | struct acm *acm = container_of(port, struct acm, port); |
597 | |||
598 | dev_dbg(&acm->control->dev, "%s\n", __func__); | ||
525 | 599 | ||
526 | tty_unregister_device(acm_tty_driver, acm->minor); | 600 | tty_unregister_device(acm_tty_driver, acm->minor); |
601 | acm_release_minor(acm); | ||
527 | usb_put_intf(acm->control); | 602 | usb_put_intf(acm->control); |
528 | acm_table[acm->minor] = NULL; | ||
529 | usb_free_urb(acm->ctrlurb); | ||
530 | for (i = 0; i < ACM_NW; i++) | ||
531 | usb_free_urb(acm->wb[i].urb); | ||
532 | for (i = 0; i < acm->rx_buflimit; i++) | ||
533 | usb_free_urb(acm->read_urbs[i]); | ||
534 | kfree(acm->country_codes); | 603 | kfree(acm->country_codes); |
535 | kfree(acm); | 604 | kfree(acm); |
536 | } | 605 | } |
537 | 606 | ||
538 | static void acm_port_down(struct acm *acm) | 607 | static void acm_port_shutdown(struct tty_port *port) |
539 | { | 608 | { |
609 | struct acm *acm = container_of(port, struct acm, port); | ||
540 | int i; | 610 | int i; |
541 | 611 | ||
542 | if (acm->dev) { | 612 | dev_dbg(&acm->control->dev, "%s\n", __func__); |
613 | |||
614 | mutex_lock(&acm->mutex); | ||
615 | if (!acm->disconnected) { | ||
543 | usb_autopm_get_interface(acm->control); | 616 | usb_autopm_get_interface(acm->control); |
544 | acm_set_control(acm, acm->ctrlout = 0); | 617 | acm_set_control(acm, acm->ctrlout = 0); |
545 | usb_kill_urb(acm->ctrlurb); | 618 | usb_kill_urb(acm->ctrlurb); |
@@ -550,40 +623,28 @@ static void acm_port_down(struct acm *acm) | |||
550 | acm->control->needs_remote_wakeup = 0; | 623 | acm->control->needs_remote_wakeup = 0; |
551 | usb_autopm_put_interface(acm->control); | 624 | usb_autopm_put_interface(acm->control); |
552 | } | 625 | } |
626 | mutex_unlock(&acm->mutex); | ||
627 | } | ||
628 | |||
629 | static void acm_tty_cleanup(struct tty_struct *tty) | ||
630 | { | ||
631 | struct acm *acm = tty->driver_data; | ||
632 | dev_dbg(&acm->control->dev, "%s\n", __func__); | ||
633 | tty_port_put(&acm->port); | ||
553 | } | 634 | } |
554 | 635 | ||
555 | static void acm_tty_hangup(struct tty_struct *tty) | 636 | static void acm_tty_hangup(struct tty_struct *tty) |
556 | { | 637 | { |
557 | struct acm *acm = tty->driver_data; | 638 | struct acm *acm = tty->driver_data; |
639 | dev_dbg(&acm->control->dev, "%s\n", __func__); | ||
558 | tty_port_hangup(&acm->port); | 640 | tty_port_hangup(&acm->port); |
559 | mutex_lock(&open_mutex); | ||
560 | acm_port_down(acm); | ||
561 | mutex_unlock(&open_mutex); | ||
562 | } | 641 | } |
563 | 642 | ||
564 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) | 643 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) |
565 | { | 644 | { |
566 | struct acm *acm = tty->driver_data; | 645 | struct acm *acm = tty->driver_data; |
567 | 646 | dev_dbg(&acm->control->dev, "%s\n", __func__); | |
568 | /* Perform the closing process and see if we need to do the hardware | 647 | tty_port_close(&acm->port, tty, filp); |
569 | shutdown */ | ||
570 | if (!acm) | ||
571 | return; | ||
572 | |||
573 | mutex_lock(&open_mutex); | ||
574 | if (tty_port_close_start(&acm->port, tty, filp) == 0) { | ||
575 | if (!acm->dev) { | ||
576 | tty_port_tty_set(&acm->port, NULL); | ||
577 | acm_tty_unregister(acm); | ||
578 | tty->driver_data = NULL; | ||
579 | } | ||
580 | mutex_unlock(&open_mutex); | ||
581 | return; | ||
582 | } | ||
583 | acm_port_down(acm); | ||
584 | tty_port_close_end(&acm->port, tty); | ||
585 | tty_port_tty_set(&acm->port, NULL); | ||
586 | mutex_unlock(&open_mutex); | ||
587 | } | 648 | } |
588 | 649 | ||
589 | static int acm_tty_write(struct tty_struct *tty, | 650 | static int acm_tty_write(struct tty_struct *tty, |
@@ -595,8 +656,6 @@ static int acm_tty_write(struct tty_struct *tty, | |||
595 | int wbn; | 656 | int wbn; |
596 | struct acm_wb *wb; | 657 | struct acm_wb *wb; |
597 | 658 | ||
598 | if (!ACM_READY(acm)) | ||
599 | return -EINVAL; | ||
600 | if (!count) | 659 | if (!count) |
601 | return 0; | 660 | return 0; |
602 | 661 | ||
@@ -625,8 +684,6 @@ static int acm_tty_write(struct tty_struct *tty, | |||
625 | static int acm_tty_write_room(struct tty_struct *tty) | 684 | static int acm_tty_write_room(struct tty_struct *tty) |
626 | { | 685 | { |
627 | struct acm *acm = tty->driver_data; | 686 | struct acm *acm = tty->driver_data; |
628 | if (!ACM_READY(acm)) | ||
629 | return -EINVAL; | ||
630 | /* | 687 | /* |
631 | * Do not let the line discipline to know that we have a reserve, | 688 | * Do not let the line discipline to know that we have a reserve, |
632 | * or it might get too enthusiastic. | 689 | * or it might get too enthusiastic. |
@@ -637,7 +694,11 @@ static int acm_tty_write_room(struct tty_struct *tty) | |||
637 | static int acm_tty_chars_in_buffer(struct tty_struct *tty) | 694 | static int acm_tty_chars_in_buffer(struct tty_struct *tty) |
638 | { | 695 | { |
639 | struct acm *acm = tty->driver_data; | 696 | struct acm *acm = tty->driver_data; |
640 | if (!ACM_READY(acm)) | 697 | /* |
698 | * if the device was unplugged then any remaining characters fell out | ||
699 | * of the connector ;) | ||
700 | */ | ||
701 | if (acm->disconnected) | ||
641 | return 0; | 702 | return 0; |
642 | /* | 703 | /* |
643 | * This is inaccurate (overcounts), but it works. | 704 | * This is inaccurate (overcounts), but it works. |
@@ -649,9 +710,6 @@ static void acm_tty_throttle(struct tty_struct *tty) | |||
649 | { | 710 | { |
650 | struct acm *acm = tty->driver_data; | 711 | struct acm *acm = tty->driver_data; |
651 | 712 | ||
652 | if (!ACM_READY(acm)) | ||
653 | return; | ||
654 | |||
655 | spin_lock_irq(&acm->read_lock); | 713 | spin_lock_irq(&acm->read_lock); |
656 | acm->throttle_req = 1; | 714 | acm->throttle_req = 1; |
657 | spin_unlock_irq(&acm->read_lock); | 715 | spin_unlock_irq(&acm->read_lock); |
@@ -662,9 +720,6 @@ static void acm_tty_unthrottle(struct tty_struct *tty) | |||
662 | struct acm *acm = tty->driver_data; | 720 | struct acm *acm = tty->driver_data; |
663 | unsigned int was_throttled; | 721 | unsigned int was_throttled; |
664 | 722 | ||
665 | if (!ACM_READY(acm)) | ||
666 | return; | ||
667 | |||
668 | spin_lock_irq(&acm->read_lock); | 723 | spin_lock_irq(&acm->read_lock); |
669 | was_throttled = acm->throttled; | 724 | was_throttled = acm->throttled; |
670 | acm->throttled = 0; | 725 | acm->throttled = 0; |
@@ -679,8 +734,7 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state) | |||
679 | { | 734 | { |
680 | struct acm *acm = tty->driver_data; | 735 | struct acm *acm = tty->driver_data; |
681 | int retval; | 736 | int retval; |
682 | if (!ACM_READY(acm)) | 737 | |
683 | return -EINVAL; | ||
684 | retval = acm_send_break(acm, state ? 0xffff : 0); | 738 | retval = acm_send_break(acm, state ? 0xffff : 0); |
685 | if (retval < 0) | 739 | if (retval < 0) |
686 | dev_dbg(&acm->control->dev, "%s - send break failed\n", | 740 | dev_dbg(&acm->control->dev, "%s - send break failed\n", |
@@ -692,9 +746,6 @@ static int acm_tty_tiocmget(struct tty_struct *tty) | |||
692 | { | 746 | { |
693 | struct acm *acm = tty->driver_data; | 747 | struct acm *acm = tty->driver_data; |
694 | 748 | ||
695 | if (!ACM_READY(acm)) | ||
696 | return -EINVAL; | ||
697 | |||
698 | return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) | | 749 | return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) | |
699 | (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) | | 750 | (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) | |
700 | (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) | | 751 | (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) | |
@@ -709,9 +760,6 @@ static int acm_tty_tiocmset(struct tty_struct *tty, | |||
709 | struct acm *acm = tty->driver_data; | 760 | struct acm *acm = tty->driver_data; |
710 | unsigned int newctrl; | 761 | unsigned int newctrl; |
711 | 762 | ||
712 | if (!ACM_READY(acm)) | ||
713 | return -EINVAL; | ||
714 | |||
715 | newctrl = acm->ctrlout; | 763 | newctrl = acm->ctrlout; |
716 | set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | | 764 | set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | |
717 | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); | 765 | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); |
@@ -728,11 +776,6 @@ static int acm_tty_tiocmset(struct tty_struct *tty, | |||
728 | static int acm_tty_ioctl(struct tty_struct *tty, | 776 | static int acm_tty_ioctl(struct tty_struct *tty, |
729 | unsigned int cmd, unsigned long arg) | 777 | unsigned int cmd, unsigned long arg) |
730 | { | 778 | { |
731 | struct acm *acm = tty->driver_data; | ||
732 | |||
733 | if (!ACM_READY(acm)) | ||
734 | return -EINVAL; | ||
735 | |||
736 | return -ENOIOCTLCMD; | 779 | return -ENOIOCTLCMD; |
737 | } | 780 | } |
738 | 781 | ||
@@ -756,9 +799,6 @@ static void acm_tty_set_termios(struct tty_struct *tty, | |||
756 | struct usb_cdc_line_coding newline; | 799 | struct usb_cdc_line_coding newline; |
757 | int newctrl = acm->ctrlout; | 800 | int newctrl = acm->ctrlout; |
758 | 801 | ||
759 | if (!ACM_READY(acm)) | ||
760 | return; | ||
761 | |||
762 | newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty)); | 802 | newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty)); |
763 | newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; | 803 | newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; |
764 | newline.bParityType = termios->c_cflag & PARENB ? | 804 | newline.bParityType = termios->c_cflag & PARENB ? |
@@ -788,6 +828,12 @@ static void acm_tty_set_termios(struct tty_struct *tty, | |||
788 | } | 828 | } |
789 | } | 829 | } |
790 | 830 | ||
831 | static const struct tty_port_operations acm_port_ops = { | ||
832 | .shutdown = acm_port_shutdown, | ||
833 | .activate = acm_port_activate, | ||
834 | .destruct = acm_port_destruct, | ||
835 | }; | ||
836 | |||
791 | /* | 837 | /* |
792 | * USB probe and disconnect routines. | 838 | * USB probe and disconnect routines. |
793 | */ | 839 | */ |
@@ -1047,12 +1093,6 @@ skip_normal_probe: | |||
1047 | } | 1093 | } |
1048 | made_compressed_probe: | 1094 | made_compressed_probe: |
1049 | dev_dbg(&intf->dev, "interfaces are valid\n"); | 1095 | dev_dbg(&intf->dev, "interfaces are valid\n"); |
1050 | for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); | ||
1051 | |||
1052 | if (minor == ACM_TTY_MINORS) { | ||
1053 | dev_err(&intf->dev, "no more free acm devices\n"); | ||
1054 | return -ENODEV; | ||
1055 | } | ||
1056 | 1096 | ||
1057 | acm = kzalloc(sizeof(struct acm), GFP_KERNEL); | 1097 | acm = kzalloc(sizeof(struct acm), GFP_KERNEL); |
1058 | if (acm == NULL) { | 1098 | if (acm == NULL) { |
@@ -1060,6 +1100,13 @@ made_compressed_probe: | |||
1060 | goto alloc_fail; | 1100 | goto alloc_fail; |
1061 | } | 1101 | } |
1062 | 1102 | ||
1103 | minor = acm_alloc_minor(acm); | ||
1104 | if (minor == ACM_TTY_MINORS) { | ||
1105 | dev_err(&intf->dev, "no more free acm devices\n"); | ||
1106 | kfree(acm); | ||
1107 | return -ENODEV; | ||
1108 | } | ||
1109 | |||
1063 | ctrlsize = usb_endpoint_maxp(epctrl); | 1110 | ctrlsize = usb_endpoint_maxp(epctrl); |
1064 | readsize = usb_endpoint_maxp(epread) * | 1111 | readsize = usb_endpoint_maxp(epread) * |
1065 | (quirks == SINGLE_RX_URB ? 1 : 2); | 1112 | (quirks == SINGLE_RX_URB ? 1 : 2); |
@@ -1183,6 +1230,8 @@ made_compressed_probe: | |||
1183 | i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); | 1230 | i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); |
1184 | if (i < 0) { | 1231 | if (i < 0) { |
1185 | kfree(acm->country_codes); | 1232 | kfree(acm->country_codes); |
1233 | acm->country_codes = NULL; | ||
1234 | acm->country_code_size = 0; | ||
1186 | goto skip_countries; | 1235 | goto skip_countries; |
1187 | } | 1236 | } |
1188 | 1237 | ||
@@ -1191,6 +1240,8 @@ made_compressed_probe: | |||
1191 | if (i < 0) { | 1240 | if (i < 0) { |
1192 | device_remove_file(&intf->dev, &dev_attr_wCountryCodes); | 1241 | device_remove_file(&intf->dev, &dev_attr_wCountryCodes); |
1193 | kfree(acm->country_codes); | 1242 | kfree(acm->country_codes); |
1243 | acm->country_codes = NULL; | ||
1244 | acm->country_code_size = 0; | ||
1194 | goto skip_countries; | 1245 | goto skip_countries; |
1195 | } | 1246 | } |
1196 | } | 1247 | } |
@@ -1218,8 +1269,6 @@ skip_countries: | |||
1218 | usb_get_intf(control_interface); | 1269 | usb_get_intf(control_interface); |
1219 | tty_register_device(acm_tty_driver, minor, &control_interface->dev); | 1270 | tty_register_device(acm_tty_driver, minor, &control_interface->dev); |
1220 | 1271 | ||
1221 | acm_table[minor] = acm; | ||
1222 | |||
1223 | return 0; | 1272 | return 0; |
1224 | alloc_fail7: | 1273 | alloc_fail7: |
1225 | for (i = 0; i < ACM_NW; i++) | 1274 | for (i = 0; i < ACM_NW; i++) |
@@ -1234,6 +1283,7 @@ alloc_fail5: | |||
1234 | alloc_fail4: | 1283 | alloc_fail4: |
1235 | usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); | 1284 | usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
1236 | alloc_fail2: | 1285 | alloc_fail2: |
1286 | acm_release_minor(acm); | ||
1237 | kfree(acm); | 1287 | kfree(acm); |
1238 | alloc_fail: | 1288 | alloc_fail: |
1239 | return -ENOMEM; | 1289 | return -ENOMEM; |
@@ -1259,12 +1309,16 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1259 | struct acm *acm = usb_get_intfdata(intf); | 1309 | struct acm *acm = usb_get_intfdata(intf); |
1260 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 1310 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
1261 | struct tty_struct *tty; | 1311 | struct tty_struct *tty; |
1312 | int i; | ||
1313 | |||
1314 | dev_dbg(&intf->dev, "%s\n", __func__); | ||
1262 | 1315 | ||
1263 | /* sibling interface is already cleaning up */ | 1316 | /* sibling interface is already cleaning up */ |
1264 | if (!acm) | 1317 | if (!acm) |
1265 | return; | 1318 | return; |
1266 | 1319 | ||
1267 | mutex_lock(&open_mutex); | 1320 | mutex_lock(&acm->mutex); |
1321 | acm->disconnected = true; | ||
1268 | if (acm->country_codes) { | 1322 | if (acm->country_codes) { |
1269 | device_remove_file(&acm->control->dev, | 1323 | device_remove_file(&acm->control->dev, |
1270 | &dev_attr_wCountryCodes); | 1324 | &dev_attr_wCountryCodes); |
@@ -1272,33 +1326,32 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1272 | &dev_attr_iCountryCodeRelDate); | 1326 | &dev_attr_iCountryCodeRelDate); |
1273 | } | 1327 | } |
1274 | device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); | 1328 | device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); |
1275 | acm->dev = NULL; | ||
1276 | usb_set_intfdata(acm->control, NULL); | 1329 | usb_set_intfdata(acm->control, NULL); |
1277 | usb_set_intfdata(acm->data, NULL); | 1330 | usb_set_intfdata(acm->data, NULL); |
1331 | mutex_unlock(&acm->mutex); | ||
1332 | |||
1333 | tty = tty_port_tty_get(&acm->port); | ||
1334 | if (tty) { | ||
1335 | tty_vhangup(tty); | ||
1336 | tty_kref_put(tty); | ||
1337 | } | ||
1278 | 1338 | ||
1279 | stop_data_traffic(acm); | 1339 | stop_data_traffic(acm); |
1280 | 1340 | ||
1341 | usb_free_urb(acm->ctrlurb); | ||
1342 | for (i = 0; i < ACM_NW; i++) | ||
1343 | usb_free_urb(acm->wb[i].urb); | ||
1344 | for (i = 0; i < acm->rx_buflimit; i++) | ||
1345 | usb_free_urb(acm->read_urbs[i]); | ||
1281 | acm_write_buffers_free(acm); | 1346 | acm_write_buffers_free(acm); |
1282 | usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, | 1347 | usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
1283 | acm->ctrl_dma); | ||
1284 | acm_read_buffers_free(acm); | 1348 | acm_read_buffers_free(acm); |
1285 | 1349 | ||
1286 | if (!acm->combined_interfaces) | 1350 | if (!acm->combined_interfaces) |
1287 | usb_driver_release_interface(&acm_driver, intf == acm->control ? | 1351 | usb_driver_release_interface(&acm_driver, intf == acm->control ? |
1288 | acm->data : acm->control); | 1352 | acm->data : acm->control); |
1289 | 1353 | ||
1290 | if (acm->port.count == 0) { | 1354 | tty_port_put(&acm->port); |
1291 | acm_tty_unregister(acm); | ||
1292 | mutex_unlock(&open_mutex); | ||
1293 | return; | ||
1294 | } | ||
1295 | |||
1296 | mutex_unlock(&open_mutex); | ||
1297 | tty = tty_port_tty_get(&acm->port); | ||
1298 | if (tty) { | ||
1299 | tty_hangup(tty); | ||
1300 | tty_kref_put(tty); | ||
1301 | } | ||
1302 | } | 1355 | } |
1303 | 1356 | ||
1304 | #ifdef CONFIG_PM | 1357 | #ifdef CONFIG_PM |
@@ -1325,16 +1378,10 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) | |||
1325 | 1378 | ||
1326 | if (cnt) | 1379 | if (cnt) |
1327 | return 0; | 1380 | return 0; |
1328 | /* | ||
1329 | we treat opened interfaces differently, | ||
1330 | we must guard against open | ||
1331 | */ | ||
1332 | mutex_lock(&acm->mutex); | ||
1333 | 1381 | ||
1334 | if (acm->port.count) | 1382 | if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) |
1335 | stop_data_traffic(acm); | 1383 | stop_data_traffic(acm); |
1336 | 1384 | ||
1337 | mutex_unlock(&acm->mutex); | ||
1338 | return 0; | 1385 | return 0; |
1339 | } | 1386 | } |
1340 | 1387 | ||
@@ -1353,8 +1400,7 @@ static int acm_resume(struct usb_interface *intf) | |||
1353 | if (cnt) | 1400 | if (cnt) |
1354 | return 0; | 1401 | return 0; |
1355 | 1402 | ||
1356 | mutex_lock(&acm->mutex); | 1403 | if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { |
1357 | if (acm->port.count) { | ||
1358 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); | 1404 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); |
1359 | 1405 | ||
1360 | spin_lock_irq(&acm->write_lock); | 1406 | spin_lock_irq(&acm->write_lock); |
@@ -1378,7 +1424,6 @@ static int acm_resume(struct usb_interface *intf) | |||
1378 | } | 1424 | } |
1379 | 1425 | ||
1380 | err_out: | 1426 | err_out: |
1381 | mutex_unlock(&acm->mutex); | ||
1382 | return rv; | 1427 | return rv; |
1383 | } | 1428 | } |
1384 | 1429 | ||
@@ -1387,15 +1432,14 @@ static int acm_reset_resume(struct usb_interface *intf) | |||
1387 | struct acm *acm = usb_get_intfdata(intf); | 1432 | struct acm *acm = usb_get_intfdata(intf); |
1388 | struct tty_struct *tty; | 1433 | struct tty_struct *tty; |
1389 | 1434 | ||
1390 | mutex_lock(&acm->mutex); | 1435 | if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { |
1391 | if (acm->port.count) { | ||
1392 | tty = tty_port_tty_get(&acm->port); | 1436 | tty = tty_port_tty_get(&acm->port); |
1393 | if (tty) { | 1437 | if (tty) { |
1394 | tty_hangup(tty); | 1438 | tty_hangup(tty); |
1395 | tty_kref_put(tty); | 1439 | tty_kref_put(tty); |
1396 | } | 1440 | } |
1397 | } | 1441 | } |
1398 | mutex_unlock(&acm->mutex); | 1442 | |
1399 | return acm_resume(intf); | 1443 | return acm_resume(intf); |
1400 | } | 1444 | } |
1401 | 1445 | ||
@@ -1604,8 +1648,10 @@ static struct usb_driver acm_driver = { | |||
1604 | */ | 1648 | */ |
1605 | 1649 | ||
1606 | static const struct tty_operations acm_ops = { | 1650 | static const struct tty_operations acm_ops = { |
1651 | .install = acm_tty_install, | ||
1607 | .open = acm_tty_open, | 1652 | .open = acm_tty_open, |
1608 | .close = acm_tty_close, | 1653 | .close = acm_tty_close, |
1654 | .cleanup = acm_tty_cleanup, | ||
1609 | .hangup = acm_tty_hangup, | 1655 | .hangup = acm_tty_hangup, |
1610 | .write = acm_tty_write, | 1656 | .write = acm_tty_write, |
1611 | .write_room = acm_tty_write_room, | 1657 | .write_room = acm_tty_write_room, |
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index ca7937f26e27..35ef887b7417 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h | |||
@@ -101,6 +101,7 @@ struct acm { | |||
101 | int transmitting; | 101 | int transmitting; |
102 | spinlock_t write_lock; | 102 | spinlock_t write_lock; |
103 | struct mutex mutex; | 103 | struct mutex mutex; |
104 | bool disconnected; | ||
104 | struct usb_cdc_line_coding line; /* bits, stop, parity */ | 105 | struct usb_cdc_line_coding line; /* bits, stop, parity */ |
105 | struct work_struct work; /* work queue entry for line discipline waking up */ | 106 | struct work_struct work; /* work queue entry for line discipline waking up */ |
106 | unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ | 107 | unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ |