Commit 14f76cc7ab75b1c9db036dcd6b247e0dcc8952be
Committed by
Greg Kroah-Hartman
1 parent
786dc1d3d7
Exists in
master
and in
7 other branches
[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 |