X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fserial%2Foption.c;fp=drivers%2Fusb%2Fserial%2Foption.c;h=c856e6f40e22c5ff7716e5d01f18c50a9c2b1bc0;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=5cf2b80add7aa01ede3b1a588dc5c002d6dbccb8;hpb=4e76c8a9fa413ccc09d3f7f664183dcce3555d57;p=linux-2.6.git diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5cf2b80ad..c856e6f40 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1,5 +1,5 @@ /* - Option Card (PCMCIA to) USB to Serial Driver + USB Driver for GSM modems Copyright (C) 2005 Matthias Urlichs @@ -9,36 +9,29 @@ Portions copied from the Keyspan driver by Hugh Blemings - History: - - 2005-05-19 v0.1 Initial version, based on incomplete docs - and analysis of misbehavior with the standard driver - 2005-05-20 v0.2 Extended the input buffer to avoid losing - random 64-byte chunks of data - 2005-05-21 v0.3 implemented chars_in_buffer() - turned on low_latency - simplified the code somewhat - 2005-05-24 v0.4 option_write() sometimes deadlocked under heavy load - removed some dead code - added sponsor notice - coding style clean-up - 2005-06-20 v0.4.1 add missing braces :-/ - killed end-of-line whitespace - 2005-07-15 v0.4.2 rename WLAN product to FUSION, add FUSION2 - 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 - wants to send >2000 bytes. - 2006-04-10 v0.4.2 fixed two array overrun errors :-/ + History: see the git log. Work sponsored by: Sigos GmbH, Germany + 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) 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.1" #define DRIVER_AUTHOR "Matthias Urlichs " -#define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver" +#define DRIVER_DESC "USB Driver for GSM modems" -#include #include #include #include @@ -46,7 +39,7 @@ #include #include #include -#include "usb-serial.h" +#include /* Function prototypes */ static int option_open(struct usb_serial_port *port, struct file *filp); @@ -74,22 +67,45 @@ static int option_tiocmset(struct usb_serial_port *port, struct file *file, static int option_send_setup(struct usb_serial_port *port); /* Vendor and product IDs */ -#define OPTION_VENDOR_ID 0x0AF0 -#define HUAWEI_VENDOR_ID 0x12D1 -#define AUDIOVOX_VENDOR_ID 0x0F3D - -#define OPTION_PRODUCT_OLD 0x5000 -#define OPTION_PRODUCT_FUSION 0x6000 -#define OPTION_PRODUCT_FUSION2 0x6300 -#define HUAWEI_PRODUCT_E600 0x1001 -#define AUDIOVOX_PRODUCT_AIRCARD 0x0112 +#define OPTION_VENDOR_ID 0x0AF0 +#define HUAWEI_VENDOR_ID 0x12D1 +#define AUDIOVOX_VENDOR_ID 0x0F3D +#define NOVATELWIRELESS_VENDOR_ID 0x1410 +#define ANYDATA_VENDOR_ID 0x16d5 + +#define OPTION_PRODUCT_OLD 0x5000 +#define OPTION_PRODUCT_FUSION 0x6000 +#define OPTION_PRODUCT_FUSION2 0x6300 +#define OPTION_PRODUCT_COBRA 0x6500 +#define OPTION_PRODUCT_COBRA2 0x6600 +#define HUAWEI_PRODUCT_E600 0x1001 +#define AUDIOVOX_PRODUCT_AIRCARD 0x0112 +#define NOVATELWIRELESS_PRODUCT_U740 0x1400 +#define ANYDATA_PRODUCT_ID 0x6501 static struct usb_device_id option_ids[] = { { 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(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, + { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, + { } /* 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(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, + { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, + { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, { } /* Terminating entry */ }; @@ -106,17 +122,18 @@ static struct usb_driver option_driver = { /* The card has three separate interfaces, which the serial driver * recognizes separately, thus num_port=1. */ -static struct usb_serial_driver option_3port_device = { + +static struct usb_serial_driver option_1port_device = { .driver = { .owner = THIS_MODULE, - .name = "option", + .name = "option1", }, - .description = "Option 3G data card", - .id_table = option_ids, + .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, /* 3, but the card reports its ports separately */ + .num_ports = 1, .open = option_open, .close = option_close, .write = option_write, @@ -170,9 +187,9 @@ struct option_port_private { static int __init option_init(void) { int retval; - retval = usb_serial_register(&option_3port_device); + retval = usb_serial_register(&option_1port_device); if (retval) - goto failed_3port_device_register; + goto failed_1port_device_register; retval = usb_register(&option_driver); if (retval) goto failed_driver_register; @@ -182,15 +199,15 @@ static int __init option_init(void) return 0; failed_driver_register: - usb_serial_deregister (&option_3port_device); -failed_3port_device_register: + usb_serial_deregister (&option_1port_device); +failed_1port_device_register: return retval; } static void __exit option_exit(void) { usb_deregister (&option_driver); - usb_serial_deregister (&option_3port_device); + usb_serial_deregister (&option_1port_device); } module_init(option_init); @@ -365,8 +382,7 @@ static void option_outdat_callback(struct urb *urb, struct pt_regs *regs) port = (struct usb_serial_port *) urb->context; - if (port->open_count) - schedule_work(&port->work); + usb_serial_port_softint(port); } static void option_instat_callback(struct urb *urb, struct pt_regs *regs) @@ -573,27 +589,29 @@ static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint, /* Setup urbs */ static void option_setup_urbs(struct usb_serial *serial) { - int j; + int i,j; struct usb_serial_port *port; struct option_port_private *portdata; dbg("%s", __FUNCTION__); - port = serial->port[0]; - portdata = usb_get_serial_port_data(port); + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); /* Do indat endpoints first */ - for (j = 0; j < N_IN_URB; ++j) { - portdata->in_urbs[j] = option_setup_urb (serial, - port->bulk_in_endpointAddress, USB_DIR_IN, port, - portdata->in_buffer[j], IN_BUFLEN, option_indat_callback); - } + for (j = 0; j < N_IN_URB; ++j) { + portdata->in_urbs[j] = option_setup_urb (serial, + port->bulk_in_endpointAddress, USB_DIR_IN, port, + portdata->in_buffer[j], IN_BUFLEN, option_indat_callback); + } - /* outdat endpoints */ - for (j = 0; j < N_OUT_URB; ++j) { - portdata->out_urbs[j] = option_setup_urb (serial, - port->bulk_out_endpointAddress, USB_DIR_OUT, port, - portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback); + /* outdat endpoints */ + for (j = 0; j < N_OUT_URB; ++j) { + portdata->out_urbs[j] = option_setup_urb (serial, + port->bulk_out_endpointAddress, USB_DIR_OUT, port, + portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback); + } } }