aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/option.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/option.c')
-rw-r--r--drivers/usb/serial/option.c109
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 */
46static int option_probe(struct usb_serial *serial,
47 const struct usb_device_id *id);
46static int option_open(struct tty_struct *tty, struct usb_serial_port *port, 48static int option_open(struct tty_struct *tty, struct usb_serial_port *port,
47 struct file *filp); 49 struct file *filp);
48static void option_close(struct tty_struct *tty, struct usb_serial_port *port, 50static void option_close(struct usb_serial_port *port);
49 struct file *filp); 51static void option_dtr_rts(struct usb_serial_port *port, int on);
52
50static int option_startup(struct usb_serial *serial); 53static int option_startup(struct usb_serial *serial);
51static void option_shutdown(struct usb_serial *serial); 54static void option_disconnect(struct usb_serial *serial);
55static void option_release(struct usb_serial *serial);
52static int option_write_room(struct tty_struct *tty); 56static int option_write_room(struct tty_struct *tty);
53 57
54static void option_instat_callback(struct urb *urb); 58static void option_instat_callback(struct urb *urb);
@@ -61,7 +65,7 @@ static void option_set_termios(struct tty_struct *tty,
61static int option_tiocmget(struct tty_struct *tty, struct file *file); 65static int option_tiocmget(struct tty_struct *tty, struct file *file);
62static int option_tiocmset(struct tty_struct *tty, struct file *file, 66static int option_tiocmset(struct tty_struct *tty, struct file *file,
63 unsigned int set, unsigned int clear); 67 unsigned int set, unsigned int clear);
64static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *port); 68static int option_send_setup(struct usb_serial_port *port);
65static int option_suspend(struct usb_serial *serial, pm_message_t message); 69static int option_suspend(struct usb_serial *serial, pm_message_t message);
66static int option_resume(struct usb_serial *serial); 70static 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
307static struct usb_device_id option_ids[] = { 315static 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};
527MODULE_DEVICE_TABLE(usb, option_ids); 536MODULE_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)
624module_init(option_init); 636module_init(option_init);
625module_exit(option_exit); 637module_exit(option_exit);
626 638
639static 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
627static void option_set_termios(struct tty_struct *tty, 651static 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
636static int option_tiocmget(struct tty_struct *tty, struct file *file) 660static 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
944static void option_close(struct tty_struct *tty, 964static 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) { 980static 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*/
1035static int option_send_setup(struct tty_struct *tty, 1061static 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
1059static int option_startup(struct usb_serial *serial) 1081static 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
1132static void option_shutdown(struct usb_serial *serial) 1154static void option_disconnect(struct usb_serial *serial)
1155{
1156 dbg("%s", __func__);
1157
1158 stop_read_write_urbs(serial);
1159}
1160
1161static 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];