aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/serial/Kconfig16
-rw-r--r--drivers/usb/serial/option.c136
2 files changed, 118 insertions, 34 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 12ad6f0897e0..8bd44fda5eaf 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -491,16 +491,22 @@ config USB_SERIAL_XIRCOM
491 module will be called keyspan_pda. 491 module will be called keyspan_pda.
492 492
493config USB_SERIAL_OPTION 493config USB_SERIAL_OPTION
494 tristate "USB Option PCMCIA serial driver" 494 tristate "USB driver for GSM modems"
495 depends on USB_SERIAL && USB_OHCI_HCD && PCCARD 495 depends on USB_SERIAL
496 help 496 help
497 Say Y here if you want to use an Option card. This is a 497 Say Y here if you have an "Option" GSM PCMCIA card
498 GSM card, controlled by three serial ports which are connected 498 (or an OEM version: branded Huawei, Audiovox, or Novatel).
499 via an OHCI adapter located on a PC card. 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.
500 503
501 To compile this driver as a module, choose M here: the 504 To compile this driver as a module, choose M here: the
502 module will be called option. 505 module will be called option.
503 506
507 If this driver doesn't recognize your device,
508 it might be accessible via the FTDI_SIO driver.
509
504config USB_SERIAL_OMNINET 510config USB_SERIAL_OMNINET
505 tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)" 511 tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)"
506 depends on USB_SERIAL && EXPERIMENTAL 512 depends on USB_SERIAL && EXPERIMENTAL
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 759d36087184..b0861b61bba7 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1,5 +1,5 @@
1/* 1/*
2 Option Card (PCMCIA to) USB to Serial Driver 2 USB Driver for GSM modems
3 3
4 Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de> 4 Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de>
5 5
@@ -28,15 +28,34 @@
28 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard 28 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard
29 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes 29 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes
30 wants to send >2000 bytes. 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 Work sponsored by: Sigos GmbH, Germany <info@sigos.de> 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#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" 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#include <linux/config.h> 60#include <linux/config.h>
42#include <linux/kernel.h> 61#include <linux/kernel.h>
@@ -74,22 +93,45 @@ static int option_tiocmset(struct usb_serial_port *port, struct file *file,
74static int option_send_setup(struct usb_serial_port *port); 93static int option_send_setup(struct usb_serial_port *port);
75 94
76/* Vendor and product IDs */ 95/* Vendor and product IDs */
77#define OPTION_VENDOR_ID 0x0AF0 96#define OPTION_VENDOR_ID 0x0AF0
78#define HUAWEI_VENDOR_ID 0x12D1 97#define HUAWEI_VENDOR_ID 0x12D1
79#define AUDIOVOX_VENDOR_ID 0x0F3D 98#define AUDIOVOX_VENDOR_ID 0x0F3D
80 99#define SIERRAWIRELESS_VENDOR_ID 0x1199
81#define OPTION_PRODUCT_OLD 0x5000 100#define NOVATELWIRELESS_VENDOR_ID 0x1410
82#define OPTION_PRODUCT_FUSION 0x6000 101
83#define OPTION_PRODUCT_FUSION2 0x6300 102#define OPTION_PRODUCT_OLD 0x5000
84#define HUAWEI_PRODUCT_E600 0x1001 103#define OPTION_PRODUCT_FUSION 0x6000
85#define AUDIOVOX_PRODUCT_AIRCARD 0x0112 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
87static struct usb_device_id option_ids[] = { 111static struct usb_device_id option_ids[] = {
88 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, 112 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
89 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, 113 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
90 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, 114 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
115 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
91 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, 116 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
92 { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, 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) },
120 { } /* Terminating entry */
121};
122
123static 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};
133static struct usb_device_id option_ids3[] = {
134 { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
93 { } /* Terminating entry */ 135 { } /* Terminating entry */
94}; 136};
95 137
@@ -111,12 +153,39 @@ static struct usb_serial_driver option_3port_device = {
111 .owner = THIS_MODULE, 153 .owner = THIS_MODULE,
112 .name = "option", 154 .name = "option",
113 }, 155 },
114 .description = "Option 3G data card", 156 .description = "GSM modem (3-port)",
115 .id_table = option_ids, 157 .id_table = option_ids3,
116 .num_interrupt_in = NUM_DONT_CARE, 158 .num_interrupt_in = NUM_DONT_CARE,
117 .num_bulk_in = NUM_DONT_CARE, 159 .num_bulk_in = NUM_DONT_CARE,
118 .num_bulk_out = NUM_DONT_CARE, 160 .num_bulk_out = NUM_DONT_CARE,
119 .num_ports = 1, /* 3, but the card reports its ports separately */ 161 .num_ports = 3,
162 .open = option_open,
163 .close = option_close,
164 .write = option_write,
165 .write_room = option_write_room,
166 .chars_in_buffer = option_chars_in_buffer,
167 .throttle = option_rx_throttle,
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
178static 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,
120 .open = option_open, 189 .open = option_open,
121 .close = option_close, 190 .close = option_close,
122 .write = option_write, 191 .write = option_write,
@@ -170,6 +239,9 @@ struct option_port_private {
170static int __init option_init(void) 239static int __init option_init(void)
171{ 240{
172 int retval; 241 int retval;
242 retval = usb_serial_register(&option_1port_device);
243 if (retval)
244 goto failed_1port_device_register;
173 retval = usb_serial_register(&option_3port_device); 245 retval = usb_serial_register(&option_3port_device);
174 if (retval) 246 if (retval)
175 goto failed_3port_device_register; 247 goto failed_3port_device_register;
@@ -184,6 +256,8 @@ static int __init option_init(void)
184failed_driver_register: 256failed_driver_register:
185 usb_serial_deregister (&option_3port_device); 257 usb_serial_deregister (&option_3port_device);
186failed_3port_device_register: 258failed_3port_device_register:
259 usb_serial_deregister (&option_1port_device);
260failed_1port_device_register:
187 return retval; 261 return retval;
188} 262}
189 263
@@ -191,6 +265,7 @@ static void __exit option_exit(void)
191{ 265{
192 usb_deregister (&option_driver); 266 usb_deregister (&option_driver);
193 usb_serial_deregister (&option_3port_device); 267 usb_serial_deregister (&option_3port_device);
268 usb_serial_deregister (&option_1port_device);
194} 269}
195 270
196module_init(option_init); 271module_init(option_init);
@@ -572,27 +647,30 @@ static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
572/* Setup urbs */ 647/* Setup urbs */
573static void option_setup_urbs(struct usb_serial *serial) 648static void option_setup_urbs(struct usb_serial *serial)
574{ 649{
575 int j; 650 int i,j;
576 struct usb_serial_port *port; 651 struct usb_serial_port *port;
577 struct option_port_private *portdata; 652 struct option_port_private *portdata;
578 653
579 dbg("%s", __FUNCTION__); 654 dbg("%s", __FUNCTION__);
580 655
581 port = serial->port[0]; 656
582 portdata = usb_get_serial_port_data(port); 657 for (i = 0; i < serial->num_ports; i++) {
658 port = serial->port[i];
659 portdata = usb_get_serial_port_data(port);
583 660
584 /* Do indat endpoints first */ 661 /* Do indat endpoints first */
585 for (j = 0; j < N_IN_URB; ++j) { 662 for (j = 0; j < N_IN_URB; ++j) {
586 portdata->in_urbs[j] = option_setup_urb (serial, 663 portdata->in_urbs[j] = option_setup_urb (serial,
587 port->bulk_in_endpointAddress, USB_DIR_IN, port, 664 port->bulk_in_endpointAddress, USB_DIR_IN, port,
588 portdata->in_buffer[j], IN_BUFLEN, option_indat_callback); 665 portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
589 } 666 }
590 667
591 /* outdat endpoints */ 668 /* outdat endpoints */
592 for (j = 0; j < N_OUT_URB; ++j) { 669 for (j = 0; j < N_OUT_URB; ++j) {
593 portdata->out_urbs[j] = option_setup_urb (serial, 670 portdata->out_urbs[j] = option_setup_urb (serial,
594 port->bulk_out_endpointAddress, USB_DIR_OUT, port, 671 port->bulk_out_endpointAddress, USB_DIR_OUT, port,
595 portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback); 672 portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
673 }
596 } 674 }
597} 675}
598 676