Commit 14f76cc7ab75b1c9db036dcd6b247e0dcc8952be

Authored by Matthias Urlichs
Committed by Greg Kroah-Hartman
1 parent 786dc1d3d7

[PATCH] USB: new devices for the Option driver

This patch extends the "option" driver with a few more devices, some of
which are actually connected to USB the "right" way -- as opposed to
doing it via PCMCIA and OHCI.

Signed-Off-By: Matthias Urlichs <smurf@debian.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

Showing 2 changed files with 118 additions and 34 deletions Side-by-side Diff

drivers/usb/serial/Kconfig
... ... @@ -491,15 +491,21 @@
491 491 module will be called keyspan_pda.
492 492  
493 493 config USB_SERIAL_OPTION
494   - tristate "USB Option PCMCIA serial driver"
495   - depends on USB_SERIAL && USB_OHCI_HCD && PCCARD
  494 + tristate "USB driver for GSM modems"
  495 + depends on USB_SERIAL
496 496 help
497   - Say Y here if you want to use an Option card. This is a
498   - GSM card, controlled by three serial ports which are connected
499   - via an OHCI adapter located on a PC card.
  497 + Say Y here if you have an "Option" GSM PCMCIA card
  498 + (or an OEM version: branded Huawei, Audiovox, or Novatel).
500 499  
  500 + These cards feature a built-in OHCI-USB adapter and an
  501 + internally-connected GSM modem. The USB bus is not
  502 + accessible externally.
  503 +
501 504 To compile this driver as a module, choose M here: the
502 505 module will be called option.
  506 +
  507 + If this driver doesn't recognize your device,
  508 + it might be accessible via the FTDI_SIO driver.
503 509  
504 510 config USB_SERIAL_OMNINET
505 511 tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)"
drivers/usb/serial/option.c
1 1 /*
2   - Option Card (PCMCIA to) USB to Serial Driver
  2 + USB Driver for GSM modems
3 3  
4 4 Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de>
5 5  
6 6  
7 7  
8 8  
... ... @@ -28,15 +28,34 @@
28 28 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard
29 29 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes
30 30 wants to send >2000 bytes.
31   - 2006-04-10 v0.4.2 fixed two array overrun errors :-/
  31 + 2006-04-10 v0.5 fixed two array overrun errors :-/
  32 + 2006-04-21 v0.5.1 added support for Sierra Wireless MC8755
  33 + 2006-05-15 v0.6 re-enable multi-port support
  34 + 2006-06-01 v0.6.1 add COBRA
  35 + 2006-06-01 v0.6.2 add backwards-compatibility stuff
  36 + 2006-06-01 v0.6.3 add Novatel Wireless
  37 + 2006-06-01 v0.7 Option => GSM
32 38  
33 39 Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
34 40  
  41 + This driver exists because the "normal" serial driver doesn't work too well
  42 + with GSM modems. Issues:
  43 + - data loss -- one single Receive URB is not nearly enough
  44 + - nonstandard flow (Option devices) and multiplex (Sierra) control
  45 + - controlling the baud rate doesn't make sense
  46 +
  47 + This driver is named "option" because the most common device it's
  48 + used for is a PC-Card (with an internal OHCI-USB interface, behind
  49 + which the GSM interface sits), made by Option Inc.
  50 +
  51 + Some of the "one port" devices actually exhibit multiple USB instances
  52 + on the USB bus. This is not a bug, these ports are used for different
  53 + device features.
35 54 */
36 55  
37   -#define DRIVER_VERSION "v0.4"
  56 +#define DRIVER_VERSION "v0.7.0"
38 57 #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
39   -#define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver"
  58 +#define DRIVER_DESC "USB Driver for GSM modems"
40 59  
41 60 #include <linux/config.h>
42 61 #include <linux/kernel.h>
43 62  
44 63  
45 64  
46 65  
... ... @@ -74,25 +93,48 @@
74 93 static int option_send_setup(struct usb_serial_port *port);
75 94  
76 95 /* Vendor and product IDs */
77   -#define OPTION_VENDOR_ID 0x0AF0
78   -#define HUAWEI_VENDOR_ID 0x12D1
79   -#define AUDIOVOX_VENDOR_ID 0x0F3D
  96 +#define OPTION_VENDOR_ID 0x0AF0
  97 +#define HUAWEI_VENDOR_ID 0x12D1
  98 +#define AUDIOVOX_VENDOR_ID 0x0F3D
  99 +#define SIERRAWIRELESS_VENDOR_ID 0x1199
  100 +#define NOVATELWIRELESS_VENDOR_ID 0x1410
80 101  
81   -#define OPTION_PRODUCT_OLD 0x5000
82   -#define OPTION_PRODUCT_FUSION 0x6000
83   -#define OPTION_PRODUCT_FUSION2 0x6300
84   -#define HUAWEI_PRODUCT_E600 0x1001
85   -#define AUDIOVOX_PRODUCT_AIRCARD 0x0112
  102 +#define OPTION_PRODUCT_OLD 0x5000
  103 +#define OPTION_PRODUCT_FUSION 0x6000
  104 +#define OPTION_PRODUCT_FUSION2 0x6300
  105 +#define OPTION_PRODUCT_COBRA 0x6500
  106 +#define HUAWEI_PRODUCT_E600 0x1001
  107 +#define AUDIOVOX_PRODUCT_AIRCARD 0x0112
  108 +#define SIERRAWIRELESS_PRODUCT_MC8755 0x6802
  109 +#define NOVATELWIRELESS_PRODUCT_U740 0x1400
86 110  
87 111 static struct usb_device_id option_ids[] = {
88 112 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
89 113 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
90 114 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
  115 + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
91 116 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
92 117 { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
  118 + { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
  119 + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
93 120 { } /* Terminating entry */
94 121 };
95 122  
  123 +static struct usb_device_id option_ids1[] = {
  124 + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
  125 + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
  126 + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
  127 + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
  128 + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
  129 + { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
  130 + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
  131 + { } /* Terminating entry */
  132 +};
  133 +static struct usb_device_id option_ids3[] = {
  134 + { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
  135 + { } /* Terminating entry */
  136 +};
  137 +
96 138 MODULE_DEVICE_TABLE(usb, option_ids);
97 139  
98 140 static struct usb_driver option_driver = {
99 141  
... ... @@ -111,12 +153,12 @@
111 153 .owner = THIS_MODULE,
112 154 .name = "option",
113 155 },
114   - .description = "Option 3G data card",
115   - .id_table = option_ids,
  156 + .description = "GSM modem (3-port)",
  157 + .id_table = option_ids3,
116 158 .num_interrupt_in = NUM_DONT_CARE,
117 159 .num_bulk_in = NUM_DONT_CARE,
118 160 .num_bulk_out = NUM_DONT_CARE,
119   - .num_ports = 1, /* 3, but the card reports its ports separately */
  161 + .num_ports = 3,
120 162 .open = option_open,
121 163 .close = option_close,
122 164 .write = option_write,
... ... @@ -124,6 +166,33 @@
124 166 .chars_in_buffer = option_chars_in_buffer,
125 167 .throttle = option_rx_throttle,
126 168 .unthrottle = option_rx_unthrottle,
  169 + .set_termios = option_set_termios,
  170 + .break_ctl = option_break_ctl,
  171 + .tiocmget = option_tiocmget,
  172 + .tiocmset = option_tiocmset,
  173 + .attach = option_startup,
  174 + .shutdown = option_shutdown,
  175 + .read_int_callback = option_instat_callback,
  176 +};
  177 +
  178 +static struct usb_serial_driver option_1port_device = {
  179 + .driver = {
  180 + .owner = THIS_MODULE,
  181 + .name = "option",
  182 + },
  183 + .description = "GSM modem (1-port)",
  184 + .id_table = option_ids1,
  185 + .num_interrupt_in = NUM_DONT_CARE,
  186 + .num_bulk_in = NUM_DONT_CARE,
  187 + .num_bulk_out = NUM_DONT_CARE,
  188 + .num_ports = 1,
  189 + .open = option_open,
  190 + .close = option_close,
  191 + .write = option_write,
  192 + .write_room = option_write_room,
  193 + .chars_in_buffer = option_chars_in_buffer,
  194 + .throttle = option_rx_throttle,
  195 + .unthrottle = option_rx_unthrottle,
127 196 .ioctl = option_ioctl,
128 197 .set_termios = option_set_termios,
129 198 .break_ctl = option_break_ctl,
... ... @@ -170,6 +239,9 @@
170 239 static int __init option_init(void)
171 240 {
172 241 int retval;
  242 + retval = usb_serial_register(&option_1port_device);
  243 + if (retval)
  244 + goto failed_1port_device_register;
173 245 retval = usb_serial_register(&option_3port_device);
174 246 if (retval)
175 247 goto failed_3port_device_register;
... ... @@ -184,6 +256,8 @@
184 256 failed_driver_register:
185 257 usb_serial_deregister (&option_3port_device);
186 258 failed_3port_device_register:
  259 + usb_serial_deregister (&option_1port_device);
  260 +failed_1port_device_register:
187 261 return retval;
188 262 }
189 263  
... ... @@ -191,6 +265,7 @@
191 265 {
192 266 usb_deregister (&option_driver);
193 267 usb_serial_deregister (&option_3port_device);
  268 + usb_serial_deregister (&option_1port_device);
194 269 }
195 270  
196 271 module_init(option_init);
197 272  
198 273  
199 274  
200 275  
... ... @@ -572,27 +647,30 @@
572 647 /* Setup urbs */
573 648 static void option_setup_urbs(struct usb_serial *serial)
574 649 {
575   - int j;
  650 + int i,j;
576 651 struct usb_serial_port *port;
577 652 struct option_port_private *portdata;
578 653  
579 654 dbg("%s", __FUNCTION__);
580 655  
581   - port = serial->port[0];
582   - portdata = usb_get_serial_port_data(port);
583 656  
  657 + for (i = 0; i < serial->num_ports; i++) {
  658 + port = serial->port[i];
  659 + portdata = usb_get_serial_port_data(port);
  660 +
584 661 /* Do indat endpoints first */
585   - for (j = 0; j < N_IN_URB; ++j) {
586   - portdata->in_urbs[j] = option_setup_urb (serial,
587   - port->bulk_in_endpointAddress, USB_DIR_IN, port,
588   - portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
589   - }
  662 + for (j = 0; j < N_IN_URB; ++j) {
  663 + portdata->in_urbs[j] = option_setup_urb (serial,
  664 + port->bulk_in_endpointAddress, USB_DIR_IN, port,
  665 + portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
  666 + }
590 667  
591   - /* outdat endpoints */
592   - for (j = 0; j < N_OUT_URB; ++j) {
593   - portdata->out_urbs[j] = option_setup_urb (serial,
594   - port->bulk_out_endpointAddress, USB_DIR_OUT, port,
595   - portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
  668 + /* outdat endpoints */
  669 + for (j = 0; j < N_OUT_URB; ++j) {
  670 + portdata->out_urbs[j] = option_setup_urb (serial,
  671 + port->bulk_out_endpointAddress, USB_DIR_OUT, port,
  672 + portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
  673 + }
596 674 }
597 675 }
598 676