Commit 14f76cc7 authored by Matthias Urlichs's avatar Matthias Urlichs Committed by Greg Kroah-Hartman

[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: default avatarMatthias Urlichs <smurf@debian.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 786dc1d3
...@@ -491,16 +491,22 @@ config USB_SERIAL_XIRCOM ...@@ -491,16 +491,22 @@ config USB_SERIAL_XIRCOM
module will be called keyspan_pda. module will be called keyspan_pda.
config USB_SERIAL_OPTION config USB_SERIAL_OPTION
tristate "USB Option PCMCIA serial driver" tristate "USB driver for GSM modems"
depends on USB_SERIAL && USB_OHCI_HCD && PCCARD depends on USB_SERIAL
help help
Say Y here if you want to use an Option card. This is a Say Y here if you have an "Option" GSM PCMCIA card
GSM card, controlled by three serial ports which are connected (or an OEM version: branded Huawei, Audiovox, or Novatel).
via an OHCI adapter located on a PC card.
These cards feature a built-in OHCI-USB adapter and an
internally-connected GSM modem. The USB bus is not
accessible externally.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called option. module will be called option.
If this driver doesn't recognize your device,
it might be accessible via the FTDI_SIO driver.
config USB_SERIAL_OMNINET config USB_SERIAL_OMNINET
tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)" tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)"
depends on USB_SERIAL && EXPERIMENTAL depends on USB_SERIAL && EXPERIMENTAL
......
/* /*
Option Card (PCMCIA to) USB to Serial Driver USB Driver for GSM modems
Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de> Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de>
...@@ -28,15 +28,34 @@ ...@@ -28,15 +28,34 @@
2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard
2005-09-20 v0.4.4 increased recv buffer size: the card sometimes 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes
wants to send >2000 bytes. wants to send >2000 bytes.
2006-04-10 v0.4.2 fixed two array overrun errors :-/ 2006-04-10 v0.5 fixed two array overrun errors :-/
2006-04-21 v0.5.1 added support for Sierra Wireless MC8755
2006-05-15 v0.6 re-enable multi-port support
2006-06-01 v0.6.1 add COBRA
2006-06-01 v0.6.2 add backwards-compatibility stuff
2006-06-01 v0.6.3 add Novatel Wireless
2006-06-01 v0.7 Option => GSM
Work sponsored by: Sigos GmbH, Germany <info@sigos.de> Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
This driver exists because the "normal" serial driver doesn't work too well
with GSM modems. Issues:
- data loss -- one single Receive URB is not nearly enough
- nonstandard flow (Option devices) and multiplex (Sierra) control
- controlling the baud rate doesn't make sense
This driver is named "option" because the most common device it's
used for is a PC-Card (with an internal OHCI-USB interface, behind
which the GSM interface sits), made by Option Inc.
Some of the "one port" devices actually exhibit multiple USB instances
on the USB bus. This is not a bug, these ports are used for different
device features.
*/ */
#define DRIVER_VERSION "v0.4" #define DRIVER_VERSION "v0.7.0"
#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
#define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver" #define DRIVER_DESC "USB Driver for GSM modems"
#include <linux/config.h> #include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -77,19 +96,42 @@ static int option_send_setup(struct usb_serial_port *port); ...@@ -77,19 +96,42 @@ static int option_send_setup(struct usb_serial_port *port);
#define OPTION_VENDOR_ID 0x0AF0 #define OPTION_VENDOR_ID 0x0AF0
#define HUAWEI_VENDOR_ID 0x12D1 #define HUAWEI_VENDOR_ID 0x12D1
#define AUDIOVOX_VENDOR_ID 0x0F3D #define AUDIOVOX_VENDOR_ID 0x0F3D
#define SIERRAWIRELESS_VENDOR_ID 0x1199
#define NOVATELWIRELESS_VENDOR_ID 0x1410
#define OPTION_PRODUCT_OLD 0x5000 #define OPTION_PRODUCT_OLD 0x5000
#define OPTION_PRODUCT_FUSION 0x6000 #define OPTION_PRODUCT_FUSION 0x6000
#define OPTION_PRODUCT_FUSION2 0x6300 #define OPTION_PRODUCT_FUSION2 0x6300
#define OPTION_PRODUCT_COBRA 0x6500
#define HUAWEI_PRODUCT_E600 0x1001 #define HUAWEI_PRODUCT_E600 0x1001
#define AUDIOVOX_PRODUCT_AIRCARD 0x0112 #define AUDIOVOX_PRODUCT_AIRCARD 0x0112
#define SIERRAWIRELESS_PRODUCT_MC8755 0x6802
#define NOVATELWIRELESS_PRODUCT_U740 0x1400
static struct usb_device_id option_ids[] = { static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
{ USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
{ } /* Terminating entry */
};
static struct usb_device_id option_ids1[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
{ } /* Terminating entry */
};
static struct usb_device_id option_ids3[] = {
{ USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -111,12 +153,39 @@ static struct usb_serial_driver option_3port_device = { ...@@ -111,12 +153,39 @@ static struct usb_serial_driver option_3port_device = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "option", .name = "option",
}, },
.description = "Option 3G data card", .description = "GSM modem (3-port)",
.id_table = option_ids, .id_table = option_ids3,
.num_interrupt_in = NUM_DONT_CARE, .num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1, /* 3, but the card reports its ports separately */ .num_ports = 3,
.open = option_open,
.close = option_close,
.write = option_write,
.write_room = option_write_room,
.chars_in_buffer = option_chars_in_buffer,
.throttle = option_rx_throttle,
.unthrottle = option_rx_unthrottle,
.set_termios = option_set_termios,
.break_ctl = option_break_ctl,
.tiocmget = option_tiocmget,
.tiocmset = option_tiocmset,
.attach = option_startup,
.shutdown = option_shutdown,
.read_int_callback = option_instat_callback,
};
static struct usb_serial_driver option_1port_device = {
.driver = {
.owner = THIS_MODULE,
.name = "option",
},
.description = "GSM modem (1-port)",
.id_table = option_ids1,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.open = option_open, .open = option_open,
.close = option_close, .close = option_close,
.write = option_write, .write = option_write,
...@@ -170,6 +239,9 @@ struct option_port_private { ...@@ -170,6 +239,9 @@ struct option_port_private {
static int __init option_init(void) static int __init option_init(void)
{ {
int retval; int retval;
retval = usb_serial_register(&option_1port_device);
if (retval)
goto failed_1port_device_register;
retval = usb_serial_register(&option_3port_device); retval = usb_serial_register(&option_3port_device);
if (retval) if (retval)
goto failed_3port_device_register; goto failed_3port_device_register;
...@@ -184,6 +256,8 @@ static int __init option_init(void) ...@@ -184,6 +256,8 @@ static int __init option_init(void)
failed_driver_register: failed_driver_register:
usb_serial_deregister (&option_3port_device); usb_serial_deregister (&option_3port_device);
failed_3port_device_register: failed_3port_device_register:
usb_serial_deregister (&option_1port_device);
failed_1port_device_register:
return retval; return retval;
} }
...@@ -191,6 +265,7 @@ static void __exit option_exit(void) ...@@ -191,6 +265,7 @@ static void __exit option_exit(void)
{ {
usb_deregister (&option_driver); usb_deregister (&option_driver);
usb_serial_deregister (&option_3port_device); usb_serial_deregister (&option_3port_device);
usb_serial_deregister (&option_1port_device);
} }
module_init(option_init); module_init(option_init);
...@@ -572,13 +647,15 @@ static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint, ...@@ -572,13 +647,15 @@ static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
/* Setup urbs */ /* Setup urbs */
static void option_setup_urbs(struct usb_serial *serial) static void option_setup_urbs(struct usb_serial *serial)
{ {
int j; int i,j;
struct usb_serial_port *port; struct usb_serial_port *port;
struct option_port_private *portdata; struct option_port_private *portdata;
dbg("%s", __FUNCTION__); dbg("%s", __FUNCTION__);
port = serial->port[0];
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
portdata = usb_get_serial_port_data(port); portdata = usb_get_serial_port_data(port);
/* Do indat endpoints first */ /* Do indat endpoints first */
...@@ -594,6 +671,7 @@ static void option_setup_urbs(struct usb_serial *serial) ...@@ -594,6 +671,7 @@ static void option_setup_urbs(struct usb_serial *serial)
port->bulk_out_endpointAddress, USB_DIR_OUT, port, port->bulk_out_endpointAddress, USB_DIR_OUT, port,
portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback); portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
} }
}
} }
static int option_send_setup(struct usb_serial_port *port) static int option_send_setup(struct usb_serial_port *port)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment