diff options
Diffstat (limited to 'drivers/usb/serial/option.c')
-rw-r--r-- | drivers/usb/serial/option.c | 109 |
1 files changed, 68 insertions, 41 deletions
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 7817b82889ca..575816e6ba37 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
@@ -43,12 +43,16 @@ | |||
43 | #include <linux/usb/serial.h> | 43 | #include <linux/usb/serial.h> |
44 | 44 | ||
45 | /* Function prototypes */ | 45 | /* Function prototypes */ |
46 | static int option_probe(struct usb_serial *serial, | ||
47 | const struct usb_device_id *id); | ||
46 | static int option_open(struct tty_struct *tty, struct usb_serial_port *port, | 48 | static int option_open(struct tty_struct *tty, struct usb_serial_port *port, |
47 | struct file *filp); | 49 | struct file *filp); |
48 | static void option_close(struct tty_struct *tty, struct usb_serial_port *port, | 50 | static void option_close(struct usb_serial_port *port); |
49 | struct file *filp); | 51 | static void option_dtr_rts(struct usb_serial_port *port, int on); |
52 | |||
50 | static int option_startup(struct usb_serial *serial); | 53 | static int option_startup(struct usb_serial *serial); |
51 | static void option_shutdown(struct usb_serial *serial); | 54 | static void option_disconnect(struct usb_serial *serial); |
55 | static void option_release(struct usb_serial *serial); | ||
52 | static int option_write_room(struct tty_struct *tty); | 56 | static int option_write_room(struct tty_struct *tty); |
53 | 57 | ||
54 | static void option_instat_callback(struct urb *urb); | 58 | static void option_instat_callback(struct urb *urb); |
@@ -61,7 +65,7 @@ static void option_set_termios(struct tty_struct *tty, | |||
61 | static int option_tiocmget(struct tty_struct *tty, struct file *file); | 65 | static int option_tiocmget(struct tty_struct *tty, struct file *file); |
62 | static int option_tiocmset(struct tty_struct *tty, struct file *file, | 66 | static int option_tiocmset(struct tty_struct *tty, struct file *file, |
63 | unsigned int set, unsigned int clear); | 67 | unsigned int set, unsigned int clear); |
64 | static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *port); | 68 | static int option_send_setup(struct usb_serial_port *port); |
65 | static int option_suspend(struct usb_serial *serial, pm_message_t message); | 69 | static int option_suspend(struct usb_serial *serial, pm_message_t message); |
66 | static int option_resume(struct usb_serial *serial); | 70 | static int option_resume(struct usb_serial *serial); |
67 | 71 | ||
@@ -201,9 +205,9 @@ static int option_resume(struct usb_serial *serial); | |||
201 | #define NOVATELWIRELESS_PRODUCT_MC727 0x4100 | 205 | #define NOVATELWIRELESS_PRODUCT_MC727 0x4100 |
202 | #define NOVATELWIRELESS_PRODUCT_MC950D 0x4400 | 206 | #define NOVATELWIRELESS_PRODUCT_MC950D 0x4400 |
203 | #define NOVATELWIRELESS_PRODUCT_U727 0x5010 | 207 | #define NOVATELWIRELESS_PRODUCT_U727 0x5010 |
208 | #define NOVATELWIRELESS_PRODUCT_MC760 0x6000 | ||
204 | 209 | ||
205 | /* FUTURE NOVATEL PRODUCTS */ | 210 | /* FUTURE NOVATEL PRODUCTS */ |
206 | #define NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED 0X6000 | ||
207 | #define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0X6001 | 211 | #define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0X6001 |
208 | #define NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED 0X7000 | 212 | #define NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED 0X7000 |
209 | #define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED 0X7001 | 213 | #define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED 0X7001 |
@@ -304,6 +308,10 @@ static int option_resume(struct usb_serial *serial); | |||
304 | #define DLINK_PRODUCT_DWM_652 0x3e04 | 308 | #define DLINK_PRODUCT_DWM_652 0x3e04 |
305 | 309 | ||
306 | 310 | ||
311 | /* TOSHIBA PRODUCTS */ | ||
312 | #define TOSHIBA_VENDOR_ID 0x0930 | ||
313 | #define TOSHIBA_PRODUCT_HSDPA_MINICARD 0x1302 | ||
314 | |||
307 | static struct usb_device_id option_ids[] = { | 315 | static struct usb_device_id option_ids[] = { |
308 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, | 316 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, |
309 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, | 317 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, |
@@ -421,7 +429,7 @@ static struct usb_device_id option_ids[] = { | |||
421 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, /* Novatel MC930D/MC950D */ | 429 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, /* Novatel MC930D/MC950D */ |
422 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */ | 430 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */ |
423 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel MC727/U727/USB727 */ | 431 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel MC727/U727/USB727 */ |
424 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED) }, /* Novatel EVDO product */ | 432 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC760) }, /* Novatel MC760/U760/USB760 */ |
425 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED) }, /* Novatel HSPA product */ | 433 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED) }, /* Novatel HSPA product */ |
426 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, /* Novatel EVDO Embedded product */ | 434 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, /* Novatel EVDO Embedded product */ |
427 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, /* Novatel HSPA Embedded product */ | 435 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, /* Novatel HSPA Embedded product */ |
@@ -522,6 +530,7 @@ static struct usb_device_id option_ids[] = { | |||
522 | { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, | 530 | { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, |
523 | { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, | 531 | { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, |
524 | { USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */ | 532 | { USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */ |
533 | { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */ | ||
525 | { } /* Terminating entry */ | 534 | { } /* Terminating entry */ |
526 | }; | 535 | }; |
527 | MODULE_DEVICE_TABLE(usb, option_ids); | 536 | MODULE_DEVICE_TABLE(usb, option_ids); |
@@ -549,8 +558,10 @@ static struct usb_serial_driver option_1port_device = { | |||
549 | .usb_driver = &option_driver, | 558 | .usb_driver = &option_driver, |
550 | .id_table = option_ids, | 559 | .id_table = option_ids, |
551 | .num_ports = 1, | 560 | .num_ports = 1, |
561 | .probe = option_probe, | ||
552 | .open = option_open, | 562 | .open = option_open, |
553 | .close = option_close, | 563 | .close = option_close, |
564 | .dtr_rts = option_dtr_rts, | ||
554 | .write = option_write, | 565 | .write = option_write, |
555 | .write_room = option_write_room, | 566 | .write_room = option_write_room, |
556 | .chars_in_buffer = option_chars_in_buffer, | 567 | .chars_in_buffer = option_chars_in_buffer, |
@@ -558,7 +569,8 @@ static struct usb_serial_driver option_1port_device = { | |||
558 | .tiocmget = option_tiocmget, | 569 | .tiocmget = option_tiocmget, |
559 | .tiocmset = option_tiocmset, | 570 | .tiocmset = option_tiocmset, |
560 | .attach = option_startup, | 571 | .attach = option_startup, |
561 | .shutdown = option_shutdown, | 572 | .disconnect = option_disconnect, |
573 | .release = option_release, | ||
562 | .read_int_callback = option_instat_callback, | 574 | .read_int_callback = option_instat_callback, |
563 | .suspend = option_suspend, | 575 | .suspend = option_suspend, |
564 | .resume = option_resume, | 576 | .resume = option_resume, |
@@ -624,13 +636,25 @@ static void __exit option_exit(void) | |||
624 | module_init(option_init); | 636 | module_init(option_init); |
625 | module_exit(option_exit); | 637 | module_exit(option_exit); |
626 | 638 | ||
639 | static int option_probe(struct usb_serial *serial, | ||
640 | const struct usb_device_id *id) | ||
641 | { | ||
642 | /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */ | ||
643 | if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID && | ||
644 | serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 && | ||
645 | serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8) | ||
646 | return -ENODEV; | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | |||
627 | static void option_set_termios(struct tty_struct *tty, | 651 | static void option_set_termios(struct tty_struct *tty, |
628 | struct usb_serial_port *port, struct ktermios *old_termios) | 652 | struct usb_serial_port *port, struct ktermios *old_termios) |
629 | { | 653 | { |
630 | dbg("%s", __func__); | 654 | dbg("%s", __func__); |
631 | /* Doesn't support option setting */ | 655 | /* Doesn't support option setting */ |
632 | tty_termios_copy_hw(tty->termios, old_termios); | 656 | tty_termios_copy_hw(tty->termios, old_termios); |
633 | option_send_setup(tty, port); | 657 | option_send_setup(port); |
634 | } | 658 | } |
635 | 659 | ||
636 | static int option_tiocmget(struct tty_struct *tty, struct file *file) | 660 | static int option_tiocmget(struct tty_struct *tty, struct file *file) |
@@ -669,7 +693,7 @@ static int option_tiocmset(struct tty_struct *tty, struct file *file, | |||
669 | portdata->rts_state = 0; | 693 | portdata->rts_state = 0; |
670 | if (clear & TIOCM_DTR) | 694 | if (clear & TIOCM_DTR) |
671 | portdata->dtr_state = 0; | 695 | portdata->dtr_state = 0; |
672 | return option_send_setup(tty, port); | 696 | return option_send_setup(port); |
673 | } | 697 | } |
674 | 698 | ||
675 | /* Write */ | 699 | /* Write */ |
@@ -897,10 +921,6 @@ static int option_open(struct tty_struct *tty, | |||
897 | 921 | ||
898 | dbg("%s", __func__); | 922 | dbg("%s", __func__); |
899 | 923 | ||
900 | /* Set some sane defaults */ | ||
901 | portdata->rts_state = 1; | ||
902 | portdata->dtr_state = 1; | ||
903 | |||
904 | /* Reset low level data toggle and start reading from endpoints */ | 924 | /* Reset low level data toggle and start reading from endpoints */ |
905 | for (i = 0; i < N_IN_URB; i++) { | 925 | for (i = 0; i < N_IN_URB; i++) { |
906 | urb = portdata->in_urbs[i]; | 926 | urb = portdata->in_urbs[i]; |
@@ -936,37 +956,43 @@ static int option_open(struct tty_struct *tty, | |||
936 | usb_pipeout(urb->pipe), 0); */ | 956 | usb_pipeout(urb->pipe), 0); */ |
937 | } | 957 | } |
938 | 958 | ||
939 | option_send_setup(tty, port); | 959 | option_send_setup(port); |
940 | 960 | ||
941 | return 0; | 961 | return 0; |
942 | } | 962 | } |
943 | 963 | ||
944 | static void option_close(struct tty_struct *tty, | 964 | static void option_dtr_rts(struct usb_serial_port *port, int on) |
945 | struct usb_serial_port *port, struct file *filp) | ||
946 | { | 965 | { |
947 | int i; | ||
948 | struct usb_serial *serial = port->serial; | 966 | struct usb_serial *serial = port->serial; |
949 | struct option_port_private *portdata; | 967 | struct option_port_private *portdata; |
950 | 968 | ||
951 | dbg("%s", __func__); | 969 | dbg("%s", __func__); |
952 | portdata = usb_get_serial_port_data(port); | 970 | portdata = usb_get_serial_port_data(port); |
971 | mutex_lock(&serial->disc_mutex); | ||
972 | portdata->rts_state = on; | ||
973 | portdata->dtr_state = on; | ||
974 | if (serial->dev) | ||
975 | option_send_setup(port); | ||
976 | mutex_unlock(&serial->disc_mutex); | ||
977 | } | ||
953 | 978 | ||
954 | portdata->rts_state = 0; | ||
955 | portdata->dtr_state = 0; | ||
956 | 979 | ||
957 | if (serial->dev) { | 980 | static void option_close(struct usb_serial_port *port) |
958 | mutex_lock(&serial->disc_mutex); | 981 | { |
959 | if (!serial->disconnected) | 982 | int i; |
960 | option_send_setup(tty, port); | 983 | struct usb_serial *serial = port->serial; |
961 | mutex_unlock(&serial->disc_mutex); | 984 | struct option_port_private *portdata; |
985 | |||
986 | dbg("%s", __func__); | ||
987 | portdata = usb_get_serial_port_data(port); | ||
962 | 988 | ||
989 | if (serial->dev) { | ||
963 | /* Stop reading/writing urbs */ | 990 | /* Stop reading/writing urbs */ |
964 | for (i = 0; i < N_IN_URB; i++) | 991 | for (i = 0; i < N_IN_URB; i++) |
965 | usb_kill_urb(portdata->in_urbs[i]); | 992 | usb_kill_urb(portdata->in_urbs[i]); |
966 | for (i = 0; i < N_OUT_URB; i++) | 993 | for (i = 0; i < N_OUT_URB; i++) |
967 | usb_kill_urb(portdata->out_urbs[i]); | 994 | usb_kill_urb(portdata->out_urbs[i]); |
968 | } | 995 | } |
969 | tty_port_tty_set(&port->port, NULL); | ||
970 | } | 996 | } |
971 | 997 | ||
972 | /* Helper functions used by option_setup_urbs */ | 998 | /* Helper functions used by option_setup_urbs */ |
@@ -1032,28 +1058,24 @@ static void option_setup_urbs(struct usb_serial *serial) | |||
1032 | * This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN | 1058 | * This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN |
1033 | * CDC. | 1059 | * CDC. |
1034 | */ | 1060 | */ |
1035 | static int option_send_setup(struct tty_struct *tty, | 1061 | static int option_send_setup(struct usb_serial_port *port) |
1036 | struct usb_serial_port *port) | ||
1037 | { | 1062 | { |
1038 | struct usb_serial *serial = port->serial; | 1063 | struct usb_serial *serial = port->serial; |
1039 | struct option_port_private *portdata; | 1064 | struct option_port_private *portdata; |
1040 | int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; | 1065 | int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; |
1066 | int val = 0; | ||
1041 | dbg("%s", __func__); | 1067 | dbg("%s", __func__); |
1042 | 1068 | ||
1043 | portdata = usb_get_serial_port_data(port); | 1069 | portdata = usb_get_serial_port_data(port); |
1044 | 1070 | ||
1045 | if (tty) { | 1071 | if (portdata->dtr_state) |
1046 | int val = 0; | 1072 | val |= 0x01; |
1047 | if (portdata->dtr_state) | 1073 | if (portdata->rts_state) |
1048 | val |= 0x01; | 1074 | val |= 0x02; |
1049 | if (portdata->rts_state) | ||
1050 | val |= 0x02; | ||
1051 | 1075 | ||
1052 | return usb_control_msg(serial->dev, | 1076 | return usb_control_msg(serial->dev, |
1053 | usb_rcvctrlpipe(serial->dev, 0), | 1077 | usb_rcvctrlpipe(serial->dev, 0), |
1054 | 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT); | 1078 | 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT); |
1055 | } | ||
1056 | return 0; | ||
1057 | } | 1079 | } |
1058 | 1080 | ||
1059 | static int option_startup(struct usb_serial *serial) | 1081 | static int option_startup(struct usb_serial *serial) |
@@ -1129,7 +1151,14 @@ static void stop_read_write_urbs(struct usb_serial *serial) | |||
1129 | } | 1151 | } |
1130 | } | 1152 | } |
1131 | 1153 | ||
1132 | static void option_shutdown(struct usb_serial *serial) | 1154 | static void option_disconnect(struct usb_serial *serial) |
1155 | { | ||
1156 | dbg("%s", __func__); | ||
1157 | |||
1158 | stop_read_write_urbs(serial); | ||
1159 | } | ||
1160 | |||
1161 | static void option_release(struct usb_serial *serial) | ||
1133 | { | 1162 | { |
1134 | int i, j; | 1163 | int i, j; |
1135 | struct usb_serial_port *port; | 1164 | struct usb_serial_port *port; |
@@ -1137,8 +1166,6 @@ static void option_shutdown(struct usb_serial *serial) | |||
1137 | 1166 | ||
1138 | dbg("%s", __func__); | 1167 | dbg("%s", __func__); |
1139 | 1168 | ||
1140 | stop_read_write_urbs(serial); | ||
1141 | |||
1142 | /* Now free them */ | 1169 | /* Now free them */ |
1143 | for (i = 0; i < serial->num_ports; ++i) { | 1170 | for (i = 0; i < serial->num_ports; ++i) { |
1144 | port = serial->port[i]; | 1171 | port = serial->port[i]; |