diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 326 |
1 files changed, 188 insertions, 138 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index e8c564a53346..3027ada1b812 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -58,12 +58,64 @@ 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 | #define ACM_READY(acm) (acm && acm->dev && acm->port.count) |
64 | 64 | ||
65 | static const struct tty_port_operations acm_port_ops = { | 65 | /* |
66 | }; | 66 | * acm_table accessors |
67 | */ | ||
68 | |||
69 | /* | ||
70 | * Look up an ACM structure by index. If found and not disconnected, increment | ||
71 | * its refcount and return it with its mutex held. | ||
72 | */ | ||
73 | static struct acm *acm_get_by_index(unsigned index) | ||
74 | { | ||
75 | struct acm *acm; | ||
76 | |||
77 | mutex_lock(&acm_table_lock); | ||
78 | acm = acm_table[index]; | ||
79 | if (acm) { | ||
80 | mutex_lock(&acm->mutex); | ||
81 | if (acm->disconnected) { | ||
82 | mutex_unlock(&acm->mutex); | ||
83 | acm = NULL; | ||
84 | } else { | ||
85 | tty_port_get(&acm->port); | ||
86 | mutex_unlock(&acm->mutex); | ||
87 | } | ||
88 | } | ||
89 | mutex_unlock(&acm_table_lock); | ||
90 | return acm; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * Try to find an available minor number and if found, associate it with 'acm'. | ||
95 | */ | ||
96 | static int acm_alloc_minor(struct acm *acm) | ||
97 | { | ||
98 | int minor; | ||
99 | |||
100 | mutex_lock(&acm_table_lock); | ||
101 | for (minor = 0; minor < ACM_TTY_MINORS; minor++) { | ||
102 | if (!acm_table[minor]) { | ||
103 | acm_table[minor] = acm; | ||
104 | break; | ||
105 | } | ||
106 | } | ||
107 | mutex_unlock(&acm_table_lock); | ||
108 | |||
109 | return minor; | ||
110 | } | ||
111 | |||
112 | /* Release the minor number associated with 'acm'. */ | ||
113 | static void acm_release_minor(struct acm *acm) | ||
114 | { | ||
115 | mutex_lock(&acm_table_lock); | ||
116 | acm_table[acm->minor] = NULL; | ||
117 | mutex_unlock(&acm_table_lock); | ||
118 | } | ||
67 | 119 | ||
68 | /* | 120 | /* |
69 | * Functions for ACM control messages. | 121 | * Functions for ACM control messages. |
@@ -453,93 +505,122 @@ static void acm_softint(struct work_struct *work) | |||
453 | * TTY handlers | 505 | * TTY handlers |
454 | */ | 506 | */ |
455 | 507 | ||
456 | static int acm_tty_open(struct tty_struct *tty, struct file *filp) | 508 | static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty) |
457 | { | 509 | { |
458 | struct acm *acm; | 510 | struct acm *acm; |
459 | int rv = -ENODEV; | 511 | int retval; |
460 | |||
461 | mutex_lock(&open_mutex); | ||
462 | 512 | ||
463 | acm = acm_table[tty->index]; | 513 | dev_dbg(tty->dev, "%s\n", __func__); |
464 | if (!acm || !acm->dev) | ||
465 | goto out; | ||
466 | else | ||
467 | rv = 0; | ||
468 | 514 | ||
469 | dev_dbg(&acm->control->dev, "%s\n", __func__); | 515 | acm = acm_get_by_index(tty->index); |
516 | if (!acm) | ||
517 | return -ENODEV; | ||
470 | 518 | ||
471 | set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); | 519 | retval = tty_init_termios(tty); |
520 | if (retval) | ||
521 | goto error_init_termios; | ||
472 | 522 | ||
473 | tty->driver_data = acm; | 523 | tty->driver_data = acm; |
474 | tty_port_tty_set(&acm->port, tty); | ||
475 | 524 | ||
476 | if (usb_autopm_get_interface(acm->control) < 0) | 525 | /* Final install (we use the default method) */ |
477 | goto early_bail; | 526 | tty_driver_kref_get(driver); |
478 | else | 527 | tty->count++; |
479 | acm->control->needs_remote_wakeup = 1; | 528 | driver->ttys[tty->index] = tty; |
529 | |||
530 | return 0; | ||
531 | |||
532 | error_init_termios: | ||
533 | tty_port_put(&acm->port); | ||
534 | return retval; | ||
535 | } | ||
536 | |||
537 | static int acm_tty_open(struct tty_struct *tty, struct file *filp) | ||
538 | { | ||
539 | struct acm *acm = tty->driver_data; | ||
540 | |||
541 | dev_dbg(tty->dev, "%s\n", __func__); | ||
542 | |||
543 | return tty_port_open(&acm->port, tty, filp); | ||
544 | } | ||
545 | |||
546 | static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) | ||
547 | { | ||
548 | struct acm *acm = container_of(port, struct acm, port); | ||
549 | int retval = -ENODEV; | ||
550 | |||
551 | dev_dbg(&acm->control->dev, "%s\n", __func__); | ||
480 | 552 | ||
481 | mutex_lock(&acm->mutex); | 553 | mutex_lock(&acm->mutex); |
482 | if (acm->port.count++) { | 554 | if (acm->disconnected) |
483 | mutex_unlock(&acm->mutex); | 555 | goto disconnected; |
484 | usb_autopm_put_interface(acm->control); | 556 | |
485 | goto out; | 557 | retval = usb_autopm_get_interface(acm->control); |
486 | } | 558 | if (retval) |
559 | goto error_get_interface; | ||
560 | |||
561 | /* | ||
562 | * FIXME: Why do we need this? Allocating 64K of physically contiguous | ||
563 | * memory is really nasty... | ||
564 | */ | ||
565 | set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); | ||
566 | acm->control->needs_remote_wakeup = 1; | ||
487 | 567 | ||
488 | acm->ctrlurb->dev = acm->dev; | 568 | acm->ctrlurb->dev = acm->dev; |
489 | if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { | 569 | if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { |
490 | dev_err(&acm->control->dev, | 570 | dev_err(&acm->control->dev, |
491 | "%s - usb_submit_urb(ctrl irq) failed\n", __func__); | 571 | "%s - usb_submit_urb(ctrl irq) failed\n", __func__); |
492 | goto bail_out; | 572 | goto error_submit_urb; |
493 | } | 573 | } |
494 | 574 | ||
495 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && | 575 | acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS; |
576 | if (acm_set_control(acm, acm->ctrlout) < 0 && | ||
496 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) | 577 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) |
497 | goto bail_out; | 578 | goto error_set_control; |
498 | 579 | ||
499 | usb_autopm_put_interface(acm->control); | 580 | usb_autopm_put_interface(acm->control); |
500 | 581 | ||
501 | if (acm_submit_read_urbs(acm, GFP_KERNEL)) | 582 | if (acm_submit_read_urbs(acm, GFP_KERNEL)) |
502 | goto bail_out; | 583 | 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 | 584 | ||
507 | mutex_unlock(&acm->mutex); | 585 | mutex_unlock(&acm->mutex); |
508 | out: | ||
509 | mutex_unlock(&open_mutex); | ||
510 | return rv; | ||
511 | 586 | ||
512 | bail_out: | 587 | return 0; |
513 | acm->port.count--; | 588 | |
514 | mutex_unlock(&acm->mutex); | 589 | error_submit_read_urbs: |
590 | acm->ctrlout = 0; | ||
591 | acm_set_control(acm, acm->ctrlout); | ||
592 | error_set_control: | ||
593 | usb_kill_urb(acm->ctrlurb); | ||
594 | error_submit_urb: | ||
515 | usb_autopm_put_interface(acm->control); | 595 | usb_autopm_put_interface(acm->control); |
516 | early_bail: | 596 | error_get_interface: |
517 | mutex_unlock(&open_mutex); | 597 | disconnected: |
518 | tty_port_tty_set(&acm->port, NULL); | 598 | mutex_unlock(&acm->mutex); |
519 | return -EIO; | 599 | return retval; |
520 | } | 600 | } |
521 | 601 | ||
522 | static void acm_tty_unregister(struct acm *acm) | 602 | static void acm_port_destruct(struct tty_port *port) |
523 | { | 603 | { |
524 | int i; | 604 | struct acm *acm = container_of(port, struct acm, port); |
605 | |||
606 | dev_dbg(&acm->control->dev, "%s\n", __func__); | ||
525 | 607 | ||
526 | tty_unregister_device(acm_tty_driver, acm->minor); | 608 | tty_unregister_device(acm_tty_driver, acm->minor); |
609 | acm_release_minor(acm); | ||
527 | usb_put_intf(acm->control); | 610 | 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); | 611 | kfree(acm->country_codes); |
535 | kfree(acm); | 612 | kfree(acm); |
536 | } | 613 | } |
537 | 614 | ||
538 | static void acm_port_down(struct acm *acm) | 615 | static void acm_port_shutdown(struct tty_port *port) |
539 | { | 616 | { |
617 | struct acm *acm = container_of(port, struct acm, port); | ||
540 | int i; | 618 | int i; |
541 | 619 | ||
542 | if (acm->dev) { | 620 | dev_dbg(&acm->control->dev, "%s\n", __func__); |
621 | |||
622 | mutex_lock(&acm->mutex); | ||
623 | if (!acm->disconnected) { | ||
543 | usb_autopm_get_interface(acm->control); | 624 | usb_autopm_get_interface(acm->control); |
544 | acm_set_control(acm, acm->ctrlout = 0); | 625 | acm_set_control(acm, acm->ctrlout = 0); |
545 | usb_kill_urb(acm->ctrlurb); | 626 | usb_kill_urb(acm->ctrlurb); |
@@ -550,40 +631,28 @@ static void acm_port_down(struct acm *acm) | |||
550 | acm->control->needs_remote_wakeup = 0; | 631 | acm->control->needs_remote_wakeup = 0; |
551 | usb_autopm_put_interface(acm->control); | 632 | usb_autopm_put_interface(acm->control); |
552 | } | 633 | } |
634 | mutex_unlock(&acm->mutex); | ||
635 | } | ||
636 | |||
637 | static void acm_tty_cleanup(struct tty_struct *tty) | ||
638 | { | ||
639 | struct acm *acm = tty->driver_data; | ||
640 | dev_dbg(&acm->control->dev, "%s\n", __func__); | ||
641 | tty_port_put(&acm->port); | ||
553 | } | 642 | } |
554 | 643 | ||
555 | static void acm_tty_hangup(struct tty_struct *tty) | 644 | static void acm_tty_hangup(struct tty_struct *tty) |
556 | { | 645 | { |
557 | struct acm *acm = tty->driver_data; | 646 | struct acm *acm = tty->driver_data; |
647 | dev_dbg(&acm->control->dev, "%s\n", __func__); | ||
558 | tty_port_hangup(&acm->port); | 648 | tty_port_hangup(&acm->port); |
559 | mutex_lock(&open_mutex); | ||
560 | acm_port_down(acm); | ||
561 | mutex_unlock(&open_mutex); | ||
562 | } | 649 | } |
563 | 650 | ||
564 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) | 651 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) |
565 | { | 652 | { |
566 | struct acm *acm = tty->driver_data; | 653 | struct acm *acm = tty->driver_data; |
567 | 654 | dev_dbg(&acm->control->dev, "%s\n", __func__); | |
568 | /* Perform the closing process and see if we need to do the hardware | 655 | 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 | } | 656 | } |
588 | 657 | ||
589 | static int acm_tty_write(struct tty_struct *tty, | 658 | static int acm_tty_write(struct tty_struct *tty, |
@@ -595,8 +664,6 @@ static int acm_tty_write(struct tty_struct *tty, | |||
595 | int wbn; | 664 | int wbn; |
596 | struct acm_wb *wb; | 665 | struct acm_wb *wb; |
597 | 666 | ||
598 | if (!ACM_READY(acm)) | ||
599 | return -EINVAL; | ||
600 | if (!count) | 667 | if (!count) |
601 | return 0; | 668 | return 0; |
602 | 669 | ||
@@ -625,8 +692,6 @@ static int acm_tty_write(struct tty_struct *tty, | |||
625 | static int acm_tty_write_room(struct tty_struct *tty) | 692 | static int acm_tty_write_room(struct tty_struct *tty) |
626 | { | 693 | { |
627 | struct acm *acm = tty->driver_data; | 694 | struct acm *acm = tty->driver_data; |
628 | if (!ACM_READY(acm)) | ||
629 | return -EINVAL; | ||
630 | /* | 695 | /* |
631 | * Do not let the line discipline to know that we have a reserve, | 696 | * Do not let the line discipline to know that we have a reserve, |
632 | * or it might get too enthusiastic. | 697 | * or it might get too enthusiastic. |
@@ -637,7 +702,11 @@ static int acm_tty_write_room(struct tty_struct *tty) | |||
637 | static int acm_tty_chars_in_buffer(struct tty_struct *tty) | 702 | static int acm_tty_chars_in_buffer(struct tty_struct *tty) |
638 | { | 703 | { |
639 | struct acm *acm = tty->driver_data; | 704 | struct acm *acm = tty->driver_data; |
640 | if (!ACM_READY(acm)) | 705 | /* |
706 | * if the device was unplugged then any remaining characters fell out | ||
707 | * of the connector ;) | ||
708 | */ | ||
709 | if (acm->disconnected) | ||
641 | return 0; | 710 | return 0; |
642 | /* | 711 | /* |
643 | * This is inaccurate (overcounts), but it works. | 712 | * This is inaccurate (overcounts), but it works. |
@@ -649,9 +718,6 @@ static void acm_tty_throttle(struct tty_struct *tty) | |||
649 | { | 718 | { |
650 | struct acm *acm = tty->driver_data; | 719 | struct acm *acm = tty->driver_data; |
651 | 720 | ||
652 | if (!ACM_READY(acm)) | ||
653 | return; | ||
654 | |||
655 | spin_lock_irq(&acm->read_lock); | 721 | spin_lock_irq(&acm->read_lock); |
656 | acm->throttle_req = 1; | 722 | acm->throttle_req = 1; |
657 | spin_unlock_irq(&acm->read_lock); | 723 | spin_unlock_irq(&acm->read_lock); |
@@ -662,9 +728,6 @@ static void acm_tty_unthrottle(struct tty_struct *tty) | |||
662 | struct acm *acm = tty->driver_data; | 728 | struct acm *acm = tty->driver_data; |
663 | unsigned int was_throttled; | 729 | unsigned int was_throttled; |
664 | 730 | ||
665 | if (!ACM_READY(acm)) | ||
666 | return; | ||
667 | |||
668 | spin_lock_irq(&acm->read_lock); | 731 | spin_lock_irq(&acm->read_lock); |
669 | was_throttled = acm->throttled; | 732 | was_throttled = acm->throttled; |
670 | acm->throttled = 0; | 733 | acm->throttled = 0; |
@@ -679,8 +742,7 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state) | |||
679 | { | 742 | { |
680 | struct acm *acm = tty->driver_data; | 743 | struct acm *acm = tty->driver_data; |
681 | int retval; | 744 | int retval; |
682 | if (!ACM_READY(acm)) | 745 | |
683 | return -EINVAL; | ||
684 | retval = acm_send_break(acm, state ? 0xffff : 0); | 746 | retval = acm_send_break(acm, state ? 0xffff : 0); |
685 | if (retval < 0) | 747 | if (retval < 0) |
686 | dev_dbg(&acm->control->dev, "%s - send break failed\n", | 748 | dev_dbg(&acm->control->dev, "%s - send break failed\n", |
@@ -692,9 +754,6 @@ static int acm_tty_tiocmget(struct tty_struct *tty) | |||
692 | { | 754 | { |
693 | struct acm *acm = tty->driver_data; | 755 | struct acm *acm = tty->driver_data; |
694 | 756 | ||
695 | if (!ACM_READY(acm)) | ||
696 | return -EINVAL; | ||
697 | |||
698 | return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) | | 757 | return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) | |
699 | (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) | | 758 | (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) | |
700 | (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) | | 759 | (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) | |
@@ -709,9 +768,6 @@ static int acm_tty_tiocmset(struct tty_struct *tty, | |||
709 | struct acm *acm = tty->driver_data; | 768 | struct acm *acm = tty->driver_data; |
710 | unsigned int newctrl; | 769 | unsigned int newctrl; |
711 | 770 | ||
712 | if (!ACM_READY(acm)) | ||
713 | return -EINVAL; | ||
714 | |||
715 | newctrl = acm->ctrlout; | 771 | newctrl = acm->ctrlout; |
716 | set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | | 772 | set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | |
717 | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); | 773 | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); |
@@ -728,11 +784,6 @@ static int acm_tty_tiocmset(struct tty_struct *tty, | |||
728 | static int acm_tty_ioctl(struct tty_struct *tty, | 784 | static int acm_tty_ioctl(struct tty_struct *tty, |
729 | unsigned int cmd, unsigned long arg) | 785 | unsigned int cmd, unsigned long arg) |
730 | { | 786 | { |
731 | struct acm *acm = tty->driver_data; | ||
732 | |||
733 | if (!ACM_READY(acm)) | ||
734 | return -EINVAL; | ||
735 | |||
736 | return -ENOIOCTLCMD; | 787 | return -ENOIOCTLCMD; |
737 | } | 788 | } |
738 | 789 | ||
@@ -756,9 +807,6 @@ static void acm_tty_set_termios(struct tty_struct *tty, | |||
756 | struct usb_cdc_line_coding newline; | 807 | struct usb_cdc_line_coding newline; |
757 | int newctrl = acm->ctrlout; | 808 | int newctrl = acm->ctrlout; |
758 | 809 | ||
759 | if (!ACM_READY(acm)) | ||
760 | return; | ||
761 | |||
762 | newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty)); | 810 | newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty)); |
763 | newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; | 811 | newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; |
764 | newline.bParityType = termios->c_cflag & PARENB ? | 812 | newline.bParityType = termios->c_cflag & PARENB ? |
@@ -788,6 +836,12 @@ static void acm_tty_set_termios(struct tty_struct *tty, | |||
788 | } | 836 | } |
789 | } | 837 | } |
790 | 838 | ||
839 | static const struct tty_port_operations acm_port_ops = { | ||
840 | .shutdown = acm_port_shutdown, | ||
841 | .activate = acm_port_activate, | ||
842 | .destruct = acm_port_destruct, | ||
843 | }; | ||
844 | |||
791 | /* | 845 | /* |
792 | * USB probe and disconnect routines. | 846 | * USB probe and disconnect routines. |
793 | */ | 847 | */ |
@@ -1047,12 +1101,6 @@ skip_normal_probe: | |||
1047 | } | 1101 | } |
1048 | made_compressed_probe: | 1102 | made_compressed_probe: |
1049 | dev_dbg(&intf->dev, "interfaces are valid\n"); | 1103 | 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 | 1104 | ||
1057 | acm = kzalloc(sizeof(struct acm), GFP_KERNEL); | 1105 | acm = kzalloc(sizeof(struct acm), GFP_KERNEL); |
1058 | if (acm == NULL) { | 1106 | if (acm == NULL) { |
@@ -1060,6 +1108,13 @@ made_compressed_probe: | |||
1060 | goto alloc_fail; | 1108 | goto alloc_fail; |
1061 | } | 1109 | } |
1062 | 1110 | ||
1111 | minor = acm_alloc_minor(acm); | ||
1112 | if (minor == ACM_TTY_MINORS) { | ||
1113 | dev_err(&intf->dev, "no more free acm devices\n"); | ||
1114 | kfree(acm); | ||
1115 | return -ENODEV; | ||
1116 | } | ||
1117 | |||
1063 | ctrlsize = usb_endpoint_maxp(epctrl); | 1118 | ctrlsize = usb_endpoint_maxp(epctrl); |
1064 | readsize = usb_endpoint_maxp(epread) * | 1119 | readsize = usb_endpoint_maxp(epread) * |
1065 | (quirks == SINGLE_RX_URB ? 1 : 2); | 1120 | (quirks == SINGLE_RX_URB ? 1 : 2); |
@@ -1218,8 +1273,6 @@ skip_countries: | |||
1218 | usb_get_intf(control_interface); | 1273 | usb_get_intf(control_interface); |
1219 | tty_register_device(acm_tty_driver, minor, &control_interface->dev); | 1274 | tty_register_device(acm_tty_driver, minor, &control_interface->dev); |
1220 | 1275 | ||
1221 | acm_table[minor] = acm; | ||
1222 | |||
1223 | return 0; | 1276 | return 0; |
1224 | alloc_fail7: | 1277 | alloc_fail7: |
1225 | for (i = 0; i < ACM_NW; i++) | 1278 | for (i = 0; i < ACM_NW; i++) |
@@ -1234,6 +1287,7 @@ alloc_fail5: | |||
1234 | alloc_fail4: | 1287 | alloc_fail4: |
1235 | usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); | 1288 | usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
1236 | alloc_fail2: | 1289 | alloc_fail2: |
1290 | acm_release_minor(acm); | ||
1237 | kfree(acm); | 1291 | kfree(acm); |
1238 | alloc_fail: | 1292 | alloc_fail: |
1239 | return -ENOMEM; | 1293 | return -ENOMEM; |
@@ -1259,12 +1313,16 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1259 | struct acm *acm = usb_get_intfdata(intf); | 1313 | struct acm *acm = usb_get_intfdata(intf); |
1260 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 1314 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
1261 | struct tty_struct *tty; | 1315 | struct tty_struct *tty; |
1316 | int i; | ||
1317 | |||
1318 | dev_dbg(&intf->dev, "%s\n", __func__); | ||
1262 | 1319 | ||
1263 | /* sibling interface is already cleaning up */ | 1320 | /* sibling interface is already cleaning up */ |
1264 | if (!acm) | 1321 | if (!acm) |
1265 | return; | 1322 | return; |
1266 | 1323 | ||
1267 | mutex_lock(&open_mutex); | 1324 | mutex_lock(&acm->mutex); |
1325 | acm->disconnected = true; | ||
1268 | if (acm->country_codes) { | 1326 | if (acm->country_codes) { |
1269 | device_remove_file(&acm->control->dev, | 1327 | device_remove_file(&acm->control->dev, |
1270 | &dev_attr_wCountryCodes); | 1328 | &dev_attr_wCountryCodes); |
@@ -1272,33 +1330,32 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1272 | &dev_attr_iCountryCodeRelDate); | 1330 | &dev_attr_iCountryCodeRelDate); |
1273 | } | 1331 | } |
1274 | device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); | 1332 | device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); |
1275 | acm->dev = NULL; | ||
1276 | usb_set_intfdata(acm->control, NULL); | 1333 | usb_set_intfdata(acm->control, NULL); |
1277 | usb_set_intfdata(acm->data, NULL); | 1334 | usb_set_intfdata(acm->data, NULL); |
1335 | mutex_unlock(&acm->mutex); | ||
1336 | |||
1337 | tty = tty_port_tty_get(&acm->port); | ||
1338 | if (tty) { | ||
1339 | tty_vhangup(tty); | ||
1340 | tty_kref_put(tty); | ||
1341 | } | ||
1278 | 1342 | ||
1279 | stop_data_traffic(acm); | 1343 | stop_data_traffic(acm); |
1280 | 1344 | ||
1345 | usb_free_urb(acm->ctrlurb); | ||
1346 | for (i = 0; i < ACM_NW; i++) | ||
1347 | usb_free_urb(acm->wb[i].urb); | ||
1348 | for (i = 0; i < acm->rx_buflimit; i++) | ||
1349 | usb_free_urb(acm->read_urbs[i]); | ||
1281 | acm_write_buffers_free(acm); | 1350 | acm_write_buffers_free(acm); |
1282 | usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, | 1351 | usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
1283 | acm->ctrl_dma); | ||
1284 | acm_read_buffers_free(acm); | 1352 | acm_read_buffers_free(acm); |
1285 | 1353 | ||
1286 | if (!acm->combined_interfaces) | 1354 | if (!acm->combined_interfaces) |
1287 | usb_driver_release_interface(&acm_driver, intf == acm->control ? | 1355 | usb_driver_release_interface(&acm_driver, intf == acm->control ? |
1288 | acm->data : acm->control); | 1356 | acm->data : acm->control); |
1289 | 1357 | ||
1290 | if (acm->port.count == 0) { | 1358 | 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 | } | 1359 | } |
1303 | 1360 | ||
1304 | #ifdef CONFIG_PM | 1361 | #ifdef CONFIG_PM |
@@ -1325,16 +1382,10 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) | |||
1325 | 1382 | ||
1326 | if (cnt) | 1383 | if (cnt) |
1327 | return 0; | 1384 | return 0; |
1328 | /* | ||
1329 | we treat opened interfaces differently, | ||
1330 | we must guard against open | ||
1331 | */ | ||
1332 | mutex_lock(&acm->mutex); | ||
1333 | 1385 | ||
1334 | if (acm->port.count) | 1386 | if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) |
1335 | stop_data_traffic(acm); | 1387 | stop_data_traffic(acm); |
1336 | 1388 | ||
1337 | mutex_unlock(&acm->mutex); | ||
1338 | return 0; | 1389 | return 0; |
1339 | } | 1390 | } |
1340 | 1391 | ||
@@ -1353,8 +1404,7 @@ static int acm_resume(struct usb_interface *intf) | |||
1353 | if (cnt) | 1404 | if (cnt) |
1354 | return 0; | 1405 | return 0; |
1355 | 1406 | ||
1356 | mutex_lock(&acm->mutex); | 1407 | if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { |
1357 | if (acm->port.count) { | ||
1358 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); | 1408 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); |
1359 | 1409 | ||
1360 | spin_lock_irq(&acm->write_lock); | 1410 | spin_lock_irq(&acm->write_lock); |
@@ -1378,7 +1428,6 @@ static int acm_resume(struct usb_interface *intf) | |||
1378 | } | 1428 | } |
1379 | 1429 | ||
1380 | err_out: | 1430 | err_out: |
1381 | mutex_unlock(&acm->mutex); | ||
1382 | return rv; | 1431 | return rv; |
1383 | } | 1432 | } |
1384 | 1433 | ||
@@ -1387,15 +1436,14 @@ static int acm_reset_resume(struct usb_interface *intf) | |||
1387 | struct acm *acm = usb_get_intfdata(intf); | 1436 | struct acm *acm = usb_get_intfdata(intf); |
1388 | struct tty_struct *tty; | 1437 | struct tty_struct *tty; |
1389 | 1438 | ||
1390 | mutex_lock(&acm->mutex); | 1439 | if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { |
1391 | if (acm->port.count) { | ||
1392 | tty = tty_port_tty_get(&acm->port); | 1440 | tty = tty_port_tty_get(&acm->port); |
1393 | if (tty) { | 1441 | if (tty) { |
1394 | tty_hangup(tty); | 1442 | tty_hangup(tty); |
1395 | tty_kref_put(tty); | 1443 | tty_kref_put(tty); |
1396 | } | 1444 | } |
1397 | } | 1445 | } |
1398 | mutex_unlock(&acm->mutex); | 1446 | |
1399 | return acm_resume(intf); | 1447 | return acm_resume(intf); |
1400 | } | 1448 | } |
1401 | 1449 | ||
@@ -1594,8 +1642,10 @@ static struct usb_driver acm_driver = { | |||
1594 | */ | 1642 | */ |
1595 | 1643 | ||
1596 | static const struct tty_operations acm_ops = { | 1644 | static const struct tty_operations acm_ops = { |
1645 | .install = acm_tty_install, | ||
1597 | .open = acm_tty_open, | 1646 | .open = acm_tty_open, |
1598 | .close = acm_tty_close, | 1647 | .close = acm_tty_close, |
1648 | .cleanup = acm_tty_cleanup, | ||
1599 | .hangup = acm_tty_hangup, | 1649 | .hangup = acm_tty_hangup, |
1600 | .write = acm_tty_write, | 1650 | .write = acm_tty_write, |
1601 | .write_room = acm_tty_write_room, | 1651 | .write_room = acm_tty_write_room, |