diff options
Diffstat (limited to 'drivers/usb/serial/sierra.c')
-rw-r--r-- | drivers/usb/serial/sierra.c | 198 |
1 files changed, 119 insertions, 79 deletions
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 6b192e602ce0..6f7f01eb556a 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c | |||
@@ -58,6 +58,7 @@ struct sierra_intf_private { | |||
58 | spinlock_t susp_lock; | 58 | spinlock_t susp_lock; |
59 | unsigned int suspended:1; | 59 | unsigned int suspended:1; |
60 | int in_flight; | 60 | int in_flight; |
61 | unsigned int open_ports; | ||
61 | }; | 62 | }; |
62 | 63 | ||
63 | static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) | 64 | static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) |
@@ -315,7 +316,6 @@ struct sierra_port_private { | |||
315 | int dsr_state; | 316 | int dsr_state; |
316 | int dcd_state; | 317 | int dcd_state; |
317 | int ri_state; | 318 | int ri_state; |
318 | unsigned int opened:1; | ||
319 | }; | 319 | }; |
320 | 320 | ||
321 | static int sierra_send_setup(struct usb_serial_port *port) | 321 | static int sierra_send_setup(struct usb_serial_port *port) |
@@ -364,20 +364,13 @@ static int sierra_send_setup(struct usb_serial_port *port) | |||
364 | if (retval < 0) | 364 | if (retval < 0) |
365 | return retval; | 365 | return retval; |
366 | 366 | ||
367 | retval = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), | 367 | retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), |
368 | 0x22, 0x21, val, interface, NULL, 0, USB_CTRL_SET_TIMEOUT); | 368 | 0x22, 0x21, val, interface, NULL, 0, USB_CTRL_SET_TIMEOUT); |
369 | usb_autopm_put_interface(serial->interface); | 369 | usb_autopm_put_interface(serial->interface); |
370 | 370 | ||
371 | return retval; | 371 | return retval; |
372 | } | 372 | } |
373 | 373 | ||
374 | static void sierra_set_termios(struct tty_struct *tty, | ||
375 | struct usb_serial_port *port, struct ktermios *old_termios) | ||
376 | { | ||
377 | tty_termios_copy_hw(&tty->termios, old_termios); | ||
378 | sierra_send_setup(port); | ||
379 | } | ||
380 | |||
381 | static int sierra_tiocmget(struct tty_struct *tty) | 374 | static int sierra_tiocmget(struct tty_struct *tty) |
382 | { | 375 | { |
383 | struct usb_serial_port *port = tty->driver_data; | 376 | struct usb_serial_port *port = tty->driver_data; |
@@ -418,9 +411,7 @@ static int sierra_tiocmset(struct tty_struct *tty, | |||
418 | 411 | ||
419 | static void sierra_release_urb(struct urb *urb) | 412 | static void sierra_release_urb(struct urb *urb) |
420 | { | 413 | { |
421 | struct usb_serial_port *port; | ||
422 | if (urb) { | 414 | if (urb) { |
423 | port = urb->context; | ||
424 | kfree(urb->transfer_buffer); | 415 | kfree(urb->transfer_buffer); |
425 | usb_free_urb(urb); | 416 | usb_free_urb(urb); |
426 | } | 417 | } |
@@ -433,7 +424,7 @@ static void sierra_outdat_callback(struct urb *urb) | |||
433 | struct sierra_intf_private *intfdata; | 424 | struct sierra_intf_private *intfdata; |
434 | int status = urb->status; | 425 | int status = urb->status; |
435 | 426 | ||
436 | intfdata = port->serial->private; | 427 | intfdata = usb_get_serial_data(port->serial); |
437 | 428 | ||
438 | /* free up the transfer buffer, as usb_free_urb() does not do this */ | 429 | /* free up the transfer buffer, as usb_free_urb() does not do this */ |
439 | kfree(urb->transfer_buffer); | 430 | kfree(urb->transfer_buffer); |
@@ -470,7 +461,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
470 | return 0; | 461 | return 0; |
471 | 462 | ||
472 | portdata = usb_get_serial_port_data(port); | 463 | portdata = usb_get_serial_port_data(port); |
473 | intfdata = serial->private; | 464 | intfdata = usb_get_serial_data(serial); |
474 | 465 | ||
475 | dev_dbg(&port->dev, "%s: write (%zd bytes)\n", __func__, writesize); | 466 | dev_dbg(&port->dev, "%s: write (%zd bytes)\n", __func__, writesize); |
476 | spin_lock_irqsave(&portdata->lock, flags); | 467 | spin_lock_irqsave(&portdata->lock, flags); |
@@ -674,6 +665,23 @@ static int sierra_write_room(struct tty_struct *tty) | |||
674 | return 2048; | 665 | return 2048; |
675 | } | 666 | } |
676 | 667 | ||
668 | static int sierra_chars_in_buffer(struct tty_struct *tty) | ||
669 | { | ||
670 | struct usb_serial_port *port = tty->driver_data; | ||
671 | struct sierra_port_private *portdata = usb_get_serial_port_data(port); | ||
672 | unsigned long flags; | ||
673 | int chars; | ||
674 | |||
675 | /* NOTE: This overcounts somewhat. */ | ||
676 | spin_lock_irqsave(&portdata->lock, flags); | ||
677 | chars = portdata->outstanding_urbs * MAX_TRANSFER; | ||
678 | spin_unlock_irqrestore(&portdata->lock, flags); | ||
679 | |||
680 | dev_dbg(&port->dev, "%s - %d\n", __func__, chars); | ||
681 | |||
682 | return chars; | ||
683 | } | ||
684 | |||
677 | static void sierra_stop_rx_urbs(struct usb_serial_port *port) | 685 | static void sierra_stop_rx_urbs(struct usb_serial_port *port) |
678 | { | 686 | { |
679 | int i; | 687 | int i; |
@@ -729,9 +737,6 @@ static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint, | |||
729 | struct urb *urb; | 737 | struct urb *urb; |
730 | u8 *buf; | 738 | u8 *buf; |
731 | 739 | ||
732 | if (endpoint == -1) | ||
733 | return NULL; | ||
734 | |||
735 | urb = usb_alloc_urb(0, mem_flags); | 740 | urb = usb_alloc_urb(0, mem_flags); |
736 | if (!urb) | 741 | if (!urb) |
737 | return NULL; | 742 | return NULL; |
@@ -758,40 +763,48 @@ static void sierra_close(struct usb_serial_port *port) | |||
758 | int i; | 763 | int i; |
759 | struct usb_serial *serial = port->serial; | 764 | struct usb_serial *serial = port->serial; |
760 | struct sierra_port_private *portdata; | 765 | struct sierra_port_private *portdata; |
761 | struct sierra_intf_private *intfdata = port->serial->private; | 766 | struct sierra_intf_private *intfdata = usb_get_serial_data(serial); |
767 | struct urb *urb; | ||
762 | 768 | ||
763 | portdata = usb_get_serial_port_data(port); | 769 | portdata = usb_get_serial_port_data(port); |
764 | 770 | ||
765 | portdata->rts_state = 0; | 771 | /* |
766 | portdata->dtr_state = 0; | 772 | * Need to take susp_lock to make sure port is not already being |
767 | 773 | * resumed, but no need to hold it due to ASYNC_INITIALIZED. | |
768 | mutex_lock(&serial->disc_mutex); | 774 | */ |
769 | if (!serial->disconnected) { | 775 | spin_lock_irq(&intfdata->susp_lock); |
776 | if (--intfdata->open_ports == 0) | ||
770 | serial->interface->needs_remote_wakeup = 0; | 777 | serial->interface->needs_remote_wakeup = 0; |
771 | /* odd error handling due to pm counters */ | 778 | spin_unlock_irq(&intfdata->susp_lock); |
772 | if (!usb_autopm_get_interface(serial->interface)) | ||
773 | sierra_send_setup(port); | ||
774 | else | ||
775 | usb_autopm_get_interface_no_resume(serial->interface); | ||
776 | 779 | ||
780 | for (;;) { | ||
781 | urb = usb_get_from_anchor(&portdata->delayed); | ||
782 | if (!urb) | ||
783 | break; | ||
784 | kfree(urb->transfer_buffer); | ||
785 | usb_free_urb(urb); | ||
786 | usb_autopm_put_interface_async(serial->interface); | ||
787 | spin_lock(&portdata->lock); | ||
788 | portdata->outstanding_urbs--; | ||
789 | spin_unlock(&portdata->lock); | ||
777 | } | 790 | } |
778 | mutex_unlock(&serial->disc_mutex); | ||
779 | spin_lock_irq(&intfdata->susp_lock); | ||
780 | portdata->opened = 0; | ||
781 | spin_unlock_irq(&intfdata->susp_lock); | ||
782 | 791 | ||
783 | sierra_stop_rx_urbs(port); | 792 | sierra_stop_rx_urbs(port); |
793 | usb_kill_anchored_urbs(&portdata->active); | ||
794 | |||
784 | for (i = 0; i < portdata->num_in_urbs; i++) { | 795 | for (i = 0; i < portdata->num_in_urbs; i++) { |
785 | sierra_release_urb(portdata->in_urbs[i]); | 796 | sierra_release_urb(portdata->in_urbs[i]); |
786 | portdata->in_urbs[i] = NULL; | 797 | portdata->in_urbs[i] = NULL; |
787 | } | 798 | } |
799 | |||
800 | usb_autopm_get_interface_no_resume(serial->interface); | ||
788 | } | 801 | } |
789 | 802 | ||
790 | static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) | 803 | static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) |
791 | { | 804 | { |
792 | struct sierra_port_private *portdata; | 805 | struct sierra_port_private *portdata; |
793 | struct usb_serial *serial = port->serial; | 806 | struct usb_serial *serial = port->serial; |
794 | struct sierra_intf_private *intfdata = serial->private; | 807 | struct sierra_intf_private *intfdata = usb_get_serial_data(serial); |
795 | int i; | 808 | int i; |
796 | int err; | 809 | int err; |
797 | int endpoint; | 810 | int endpoint; |
@@ -799,11 +812,6 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
799 | 812 | ||
800 | portdata = usb_get_serial_port_data(port); | 813 | portdata = usb_get_serial_port_data(port); |
801 | 814 | ||
802 | /* Set some sane defaults */ | ||
803 | portdata->rts_state = 1; | ||
804 | portdata->dtr_state = 1; | ||
805 | |||
806 | |||
807 | endpoint = port->bulk_in_endpointAddress; | 815 | endpoint = port->bulk_in_endpointAddress; |
808 | for (i = 0; i < portdata->num_in_urbs; i++) { | 816 | for (i = 0; i < portdata->num_in_urbs; i++) { |
809 | urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port, | 817 | urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port, |
@@ -816,23 +824,26 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
816 | usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN); | 824 | usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN); |
817 | 825 | ||
818 | err = sierra_submit_rx_urbs(port, GFP_KERNEL); | 826 | err = sierra_submit_rx_urbs(port, GFP_KERNEL); |
819 | if (err) { | 827 | if (err) |
820 | /* get rid of everything as in close */ | 828 | goto err_submit; |
821 | sierra_close(port); | ||
822 | /* restore balance for autopm */ | ||
823 | if (!serial->disconnected) | ||
824 | usb_autopm_put_interface(serial->interface); | ||
825 | return err; | ||
826 | } | ||
827 | sierra_send_setup(port); | ||
828 | 829 | ||
829 | serial->interface->needs_remote_wakeup = 1; | ||
830 | spin_lock_irq(&intfdata->susp_lock); | 830 | spin_lock_irq(&intfdata->susp_lock); |
831 | portdata->opened = 1; | 831 | if (++intfdata->open_ports == 1) |
832 | serial->interface->needs_remote_wakeup = 1; | ||
832 | spin_unlock_irq(&intfdata->susp_lock); | 833 | spin_unlock_irq(&intfdata->susp_lock); |
833 | usb_autopm_put_interface(serial->interface); | 834 | usb_autopm_put_interface(serial->interface); |
834 | 835 | ||
835 | return 0; | 836 | return 0; |
837 | |||
838 | err_submit: | ||
839 | sierra_stop_rx_urbs(port); | ||
840 | |||
841 | for (i = 0; i < portdata->num_in_urbs; i++) { | ||
842 | sierra_release_urb(portdata->in_urbs[i]); | ||
843 | portdata->in_urbs[i] = NULL; | ||
844 | } | ||
845 | |||
846 | return err; | ||
836 | } | 847 | } |
837 | 848 | ||
838 | 849 | ||
@@ -928,6 +939,7 @@ static int sierra_port_remove(struct usb_serial_port *port) | |||
928 | struct sierra_port_private *portdata; | 939 | struct sierra_port_private *portdata; |
929 | 940 | ||
930 | portdata = usb_get_serial_port_data(port); | 941 | portdata = usb_get_serial_port_data(port); |
942 | usb_set_serial_port_data(port, NULL); | ||
931 | kfree(portdata); | 943 | kfree(portdata); |
932 | 944 | ||
933 | return 0; | 945 | return 0; |
@@ -944,6 +956,8 @@ static void stop_read_write_urbs(struct usb_serial *serial) | |||
944 | for (i = 0; i < serial->num_ports; ++i) { | 956 | for (i = 0; i < serial->num_ports; ++i) { |
945 | port = serial->port[i]; | 957 | port = serial->port[i]; |
946 | portdata = usb_get_serial_port_data(port); | 958 | portdata = usb_get_serial_port_data(port); |
959 | if (!portdata) | ||
960 | continue; | ||
947 | sierra_stop_rx_urbs(port); | 961 | sierra_stop_rx_urbs(port); |
948 | usb_kill_anchored_urbs(&portdata->active); | 962 | usb_kill_anchored_urbs(&portdata->active); |
949 | } | 963 | } |
@@ -951,58 +965,84 @@ static void stop_read_write_urbs(struct usb_serial *serial) | |||
951 | 965 | ||
952 | static int sierra_suspend(struct usb_serial *serial, pm_message_t message) | 966 | static int sierra_suspend(struct usb_serial *serial, pm_message_t message) |
953 | { | 967 | { |
954 | struct sierra_intf_private *intfdata; | 968 | struct sierra_intf_private *intfdata = usb_get_serial_data(serial); |
955 | int b; | ||
956 | 969 | ||
970 | spin_lock_irq(&intfdata->susp_lock); | ||
957 | if (PMSG_IS_AUTO(message)) { | 971 | if (PMSG_IS_AUTO(message)) { |
958 | intfdata = serial->private; | 972 | if (intfdata->in_flight) { |
959 | spin_lock_irq(&intfdata->susp_lock); | ||
960 | b = intfdata->in_flight; | ||
961 | |||
962 | if (b) { | ||
963 | spin_unlock_irq(&intfdata->susp_lock); | 973 | spin_unlock_irq(&intfdata->susp_lock); |
964 | return -EBUSY; | 974 | return -EBUSY; |
965 | } else { | ||
966 | intfdata->suspended = 1; | ||
967 | spin_unlock_irq(&intfdata->susp_lock); | ||
968 | } | 975 | } |
969 | } | 976 | } |
977 | intfdata->suspended = 1; | ||
978 | spin_unlock_irq(&intfdata->susp_lock); | ||
979 | |||
970 | stop_read_write_urbs(serial); | 980 | stop_read_write_urbs(serial); |
971 | 981 | ||
972 | return 0; | 982 | return 0; |
973 | } | 983 | } |
974 | 984 | ||
985 | /* Caller must hold susp_lock. */ | ||
986 | static int sierra_submit_delayed_urbs(struct usb_serial_port *port) | ||
987 | { | ||
988 | struct sierra_port_private *portdata = usb_get_serial_port_data(port); | ||
989 | struct sierra_intf_private *intfdata; | ||
990 | struct urb *urb; | ||
991 | int ec = 0; | ||
992 | int err; | ||
993 | |||
994 | intfdata = usb_get_serial_data(port->serial); | ||
995 | |||
996 | for (;;) { | ||
997 | urb = usb_get_from_anchor(&portdata->delayed); | ||
998 | if (!urb) | ||
999 | break; | ||
1000 | |||
1001 | usb_anchor_urb(urb, &portdata->active); | ||
1002 | intfdata->in_flight++; | ||
1003 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
1004 | if (err) { | ||
1005 | dev_err(&port->dev, "%s - submit urb failed: %d", | ||
1006 | __func__, err); | ||
1007 | ec++; | ||
1008 | intfdata->in_flight--; | ||
1009 | usb_unanchor_urb(urb); | ||
1010 | kfree(urb->transfer_buffer); | ||
1011 | usb_free_urb(urb); | ||
1012 | |||
1013 | spin_lock(&portdata->lock); | ||
1014 | portdata->outstanding_urbs--; | ||
1015 | spin_unlock(&portdata->lock); | ||
1016 | } | ||
1017 | } | ||
1018 | |||
1019 | if (ec) | ||
1020 | return -EIO; | ||
1021 | |||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
975 | static int sierra_resume(struct usb_serial *serial) | 1025 | static int sierra_resume(struct usb_serial *serial) |
976 | { | 1026 | { |
977 | struct usb_serial_port *port; | 1027 | struct usb_serial_port *port; |
978 | struct sierra_intf_private *intfdata = serial->private; | 1028 | struct sierra_intf_private *intfdata = usb_get_serial_data(serial); |
979 | struct sierra_port_private *portdata; | ||
980 | struct urb *urb; | ||
981 | int ec = 0; | 1029 | int ec = 0; |
982 | int i, err; | 1030 | int i, err; |
983 | 1031 | ||
984 | spin_lock_irq(&intfdata->susp_lock); | 1032 | spin_lock_irq(&intfdata->susp_lock); |
985 | for (i = 0; i < serial->num_ports; i++) { | 1033 | for (i = 0; i < serial->num_ports; i++) { |
986 | port = serial->port[i]; | 1034 | port = serial->port[i]; |
987 | portdata = usb_get_serial_port_data(port); | ||
988 | 1035 | ||
989 | while ((urb = usb_get_from_anchor(&portdata->delayed))) { | 1036 | if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) |
990 | usb_anchor_urb(urb, &portdata->active); | 1037 | continue; |
991 | intfdata->in_flight++; | ||
992 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
993 | if (err < 0) { | ||
994 | intfdata->in_flight--; | ||
995 | usb_unanchor_urb(urb); | ||
996 | usb_scuttle_anchored_urbs(&portdata->delayed); | ||
997 | break; | ||
998 | } | ||
999 | } | ||
1000 | 1038 | ||
1001 | if (portdata->opened) { | 1039 | err = sierra_submit_delayed_urbs(port); |
1002 | err = sierra_submit_rx_urbs(port, GFP_ATOMIC); | 1040 | if (err) |
1003 | if (err) | 1041 | ec++; |
1004 | ec++; | 1042 | |
1005 | } | 1043 | err = sierra_submit_rx_urbs(port, GFP_ATOMIC); |
1044 | if (err) | ||
1045 | ec++; | ||
1006 | } | 1046 | } |
1007 | intfdata->suspended = 0; | 1047 | intfdata->suspended = 0; |
1008 | spin_unlock_irq(&intfdata->susp_lock); | 1048 | spin_unlock_irq(&intfdata->susp_lock); |
@@ -1029,7 +1069,7 @@ static struct usb_serial_driver sierra_device = { | |||
1029 | .dtr_rts = sierra_dtr_rts, | 1069 | .dtr_rts = sierra_dtr_rts, |
1030 | .write = sierra_write, | 1070 | .write = sierra_write, |
1031 | .write_room = sierra_write_room, | 1071 | .write_room = sierra_write_room, |
1032 | .set_termios = sierra_set_termios, | 1072 | .chars_in_buffer = sierra_chars_in_buffer, |
1033 | .tiocmget = sierra_tiocmget, | 1073 | .tiocmget = sierra_tiocmget, |
1034 | .tiocmset = sierra_tiocmset, | 1074 | .tiocmset = sierra_tiocmset, |
1035 | .attach = sierra_startup, | 1075 | .attach = sierra_startup, |