blob: ced9f32b29d9eb0a5f30b715e98e1318153aed65 [file] [log] [blame]
Matthias Urlichs58cfe912005-05-23 17:00:48 -07001/*
Matthias Urlichs14f76cc2006-06-02 11:48:56 +02002 USB Driver for GSM modems
Matthias Urlichs58cfe912005-05-23 17:00:48 -07003
4 Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de>
5
6 This driver is free software; you can redistribute it and/or modify
7 it under the terms of Version 2 of the GNU General Public License as
8 published by the Free Software Foundation.
9
10 Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
11
Matthias Urlichsb3fdab52006-08-02 16:41:41 -070012 History: see the git log.
Matthias Urlichsba460e42005-07-14 00:33:47 -070013
14 Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
15
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020016 This driver exists because the "normal" serial driver doesn't work too well
17 with GSM modems. Issues:
18 - data loss -- one single Receive URB is not nearly enough
Matthias Urlichs7c1c2f72006-07-20 04:56:00 +020019 - nonstandard flow (Option devices) control
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020020 - controlling the baud rate doesn't make sense
21
22 This driver is named "option" because the most common device it's
23 used for is a PC-Card (with an internal OHCI-USB interface, behind
24 which the GSM interface sits), made by Option Inc.
25
26 Some of the "one port" devices actually exhibit multiple USB instances
27 on the USB bus. This is not a bug, these ports are used for different
28 device features.
Matthias Urlichs58cfe912005-05-23 17:00:48 -070029*/
Matthias Urlichsba460e42005-07-14 00:33:47 -070030
Matthias Urlichse37de9e2006-07-06 13:12:53 +020031#define DRIVER_VERSION "v0.7.1"
Matthias Urlichs58cfe912005-05-23 17:00:48 -070032#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020033#define DRIVER_DESC "USB Driver for GSM modems"
Matthias Urlichs58cfe912005-05-23 17:00:48 -070034
Matthias Urlichs58cfe912005-05-23 17:00:48 -070035#include <linux/kernel.h>
36#include <linux/jiffies.h>
37#include <linux/errno.h>
38#include <linux/tty.h>
39#include <linux/tty_flip.h>
40#include <linux/module.h>
41#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070042#include <linux/usb/serial.h>
Matthias Urlichs58cfe912005-05-23 17:00:48 -070043
44/* Function prototypes */
Andrew Morton7bb75ae2005-07-27 01:08:30 -070045static int option_open(struct usb_serial_port *port, struct file *filp);
46static void option_close(struct usb_serial_port *port, struct file *filp);
47static int option_startup(struct usb_serial *serial);
48static void option_shutdown(struct usb_serial *serial);
49static void option_rx_throttle(struct usb_serial_port *port);
50static void option_rx_unthrottle(struct usb_serial_port *port);
51static int option_write_room(struct usb_serial_port *port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070052
David Howells7d12e782006-10-05 14:55:46 +010053static void option_instat_callback(struct urb *urb);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070054
Andrew Morton7bb75ae2005-07-27 01:08:30 -070055static int option_write(struct usb_serial_port *port,
56 const unsigned char *buf, int count);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070057
Andrew Morton7bb75ae2005-07-27 01:08:30 -070058static int option_chars_in_buffer(struct usb_serial_port *port);
59static int option_ioctl(struct usb_serial_port *port, struct file *file,
60 unsigned int cmd, unsigned long arg);
61static void option_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -080062 struct ktermios *old);
Andrew Morton7bb75ae2005-07-27 01:08:30 -070063static void option_break_ctl(struct usb_serial_port *port, int break_state);
64static int option_tiocmget(struct usb_serial_port *port, struct file *file);
65static int option_tiocmset(struct usb_serial_port *port, struct file *file,
66 unsigned int set, unsigned int clear);
67static int option_send_setup(struct usb_serial_port *port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070068
69/* Vendor and product IDs */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020070#define OPTION_VENDOR_ID 0x0AF0
71#define HUAWEI_VENDOR_ID 0x12D1
72#define AUDIOVOX_VENDOR_ID 0x0F3D
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020073#define NOVATELWIRELESS_VENDOR_ID 0x1410
Matthias Urlichs31fcbb72006-07-12 08:35:29 +020074#define ANYDATA_VENDOR_ID 0x16d5
Matthias Urlichs58cfe912005-05-23 17:00:48 -070075
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020076#define OPTION_PRODUCT_OLD 0x5000
77#define OPTION_PRODUCT_FUSION 0x6000
78#define OPTION_PRODUCT_FUSION2 0x6300
79#define OPTION_PRODUCT_COBRA 0x6500
Matthias Urlichse37de9e2006-07-06 13:12:53 +020080#define OPTION_PRODUCT_COBRA2 0x6600
garrett_damore@tadpole.com53e8f842007-01-12 17:10:28 -080081#define OPTION_PRODUCT_GTMAX36 0x6701
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020082#define HUAWEI_PRODUCT_E600 0x1001
Johann Wilhelmab195892006-12-02 07:25:31 +010083#define HUAWEI_PRODUCT_E220 0x1003
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020084#define AUDIOVOX_PRODUCT_AIRCARD 0x0112
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020085#define NOVATELWIRELESS_PRODUCT_U740 0x1400
Matthias Urlichs31fcbb72006-07-12 08:35:29 +020086#define ANYDATA_PRODUCT_ID 0x6501
Matthias Urlichsba460e42005-07-14 00:33:47 -070087
Matthias Urlichs58cfe912005-05-23 17:00:48 -070088static struct usb_device_id option_ids[] = {
89 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
Matthias Urlichsba460e42005-07-14 00:33:47 -070090 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
91 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020092 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
Matthias Urlichse37de9e2006-07-06 13:12:53 +020093 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
garrett_damore@tadpole.com53e8f842007-01-12 17:10:28 -080094 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
Matthias Urlichsb6137382005-09-22 00:48:40 -070095 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
Johann Wilhelmab195892006-12-02 07:25:31 +010096 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
Matthias Urlichsb6137382005-09-22 00:48:40 -070097 { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020098 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
Matthias Urlichs31fcbb72006-07-12 08:35:29 +020099 { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200100 { } /* Terminating entry */
101};
102
103static struct usb_device_id option_ids1[] = {
104 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
105 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
106 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
107 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
Matthias Urlichse37de9e2006-07-06 13:12:53 +0200108 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
garrett_damore@tadpole.com53e8f842007-01-12 17:10:28 -0800109 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200110 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
Johann Wilhelmab195892006-12-02 07:25:31 +0100111 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200112 { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
113 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
Matthias Urlichs31fcbb72006-07-12 08:35:29 +0200114 { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200115 { } /* Terminating entry */
116};
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700117
118MODULE_DEVICE_TABLE(usb, option_ids);
119
120static struct usb_driver option_driver = {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700121 .name = "option",
122 .probe = usb_serial_probe,
123 .disconnect = usb_serial_disconnect,
124 .id_table = option_ids,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800125 .no_dynamic_id = 1,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700126};
127
Uwe Zeisbergerc30fe7f2006-03-24 18:23:14 +0100128/* The card has three separate interfaces, which the serial driver
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700129 * recognizes separately, thus num_port=1.
130 */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200131
132static struct usb_serial_driver option_1port_device = {
133 .driver = {
134 .owner = THIS_MODULE,
Matthias Urlichs02b2ac52006-08-02 16:41:41 -0700135 .name = "option1",
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200136 },
137 .description = "GSM modem (1-port)",
Johannes Hölzld9b1b782006-12-17 21:50:24 +0100138 .usb_driver = &option_driver,
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200139 .id_table = option_ids1,
140 .num_interrupt_in = NUM_DONT_CARE,
141 .num_bulk_in = NUM_DONT_CARE,
142 .num_bulk_out = NUM_DONT_CARE,
143 .num_ports = 1,
Matthias Urlichsba460e42005-07-14 00:33:47 -0700144 .open = option_open,
145 .close = option_close,
146 .write = option_write,
147 .write_room = option_write_room,
148 .chars_in_buffer = option_chars_in_buffer,
149 .throttle = option_rx_throttle,
150 .unthrottle = option_rx_unthrottle,
151 .ioctl = option_ioctl,
152 .set_termios = option_set_termios,
153 .break_ctl = option_break_ctl,
154 .tiocmget = option_tiocmget,
155 .tiocmset = option_tiocmset,
156 .attach = option_startup,
157 .shutdown = option_shutdown,
158 .read_int_callback = option_instat_callback,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700159};
160
Matthias Urlichsba460e42005-07-14 00:33:47 -0700161#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700162static int debug;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700163#else
164#define debug 0
165#endif
166
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700167/* per port private data */
168
Matthias Urlichsba460e42005-07-14 00:33:47 -0700169#define N_IN_URB 4
170#define N_OUT_URB 1
Matthias Urlichsb27c73d2005-09-22 00:49:33 -0700171#define IN_BUFLEN 4096
Matthias Urlichsba460e42005-07-14 00:33:47 -0700172#define OUT_BUFLEN 128
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700173
174struct option_port_private {
175 /* Input endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700176 struct urb *in_urbs[N_IN_URB];
177 char in_buffer[N_IN_URB][IN_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700178 /* Output endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700179 struct urb *out_urbs[N_OUT_URB];
180 char out_buffer[N_OUT_URB][OUT_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700181
182 /* Settings for the port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700183 int rts_state; /* Handshaking pins (outputs) */
184 int dtr_state;
185 int cts_state; /* Handshaking pins (inputs) */
186 int dsr_state;
187 int dcd_state;
188 int ri_state;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700189
Matthias Urlichsba460e42005-07-14 00:33:47 -0700190 unsigned long tx_start_time[N_OUT_URB];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700191};
192
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700193/* Functions used by new usb-serial code. */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700194static int __init option_init(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700195{
196 int retval;
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200197 retval = usb_serial_register(&option_1port_device);
198 if (retval)
199 goto failed_1port_device_register;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700200 retval = usb_register(&option_driver);
201 if (retval)
202 goto failed_driver_register;
203
204 info(DRIVER_DESC ": " DRIVER_VERSION);
205
206 return 0;
207
208failed_driver_register:
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200209 usb_serial_deregister (&option_1port_device);
210failed_1port_device_register:
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700211 return retval;
212}
213
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700214static void __exit option_exit(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700215{
216 usb_deregister (&option_driver);
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200217 usb_serial_deregister (&option_1port_device);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700218}
219
220module_init(option_init);
221module_exit(option_exit);
222
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700223static void option_rx_throttle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700224{
225 dbg("%s", __FUNCTION__);
226}
227
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700228static void option_rx_unthrottle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700229{
230 dbg("%s", __FUNCTION__);
231}
232
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700233static void option_break_ctl(struct usb_serial_port *port, int break_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700234{
235 /* Unfortunately, I don't know how to send a break */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700236 dbg("%s", __FUNCTION__);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700237}
238
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700239static void option_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -0800240 struct ktermios *old_termios)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700241{
242 dbg("%s", __FUNCTION__);
243
244 option_send_setup(port);
245}
246
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700247static int option_tiocmget(struct usb_serial_port *port, struct file *file)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700248{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700249 unsigned int value;
250 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700251
252 portdata = usb_get_serial_port_data(port);
253
254 value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
255 ((portdata->dtr_state) ? TIOCM_DTR : 0) |
256 ((portdata->cts_state) ? TIOCM_CTS : 0) |
257 ((portdata->dsr_state) ? TIOCM_DSR : 0) |
258 ((portdata->dcd_state) ? TIOCM_CAR : 0) |
259 ((portdata->ri_state) ? TIOCM_RNG : 0);
260
261 return value;
262}
263
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700264static int option_tiocmset(struct usb_serial_port *port, struct file *file,
265 unsigned int set, unsigned int clear)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700266{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700267 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700268
269 portdata = usb_get_serial_port_data(port);
270
271 if (set & TIOCM_RTS)
272 portdata->rts_state = 1;
273 if (set & TIOCM_DTR)
274 portdata->dtr_state = 1;
275
276 if (clear & TIOCM_RTS)
277 portdata->rts_state = 0;
278 if (clear & TIOCM_DTR)
279 portdata->dtr_state = 0;
280 return option_send_setup(port);
281}
282
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700283static int option_ioctl(struct usb_serial_port *port, struct file *file,
284 unsigned int cmd, unsigned long arg)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700285{
286 return -ENOIOCTLCMD;
287}
288
289/* Write */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700290static int option_write(struct usb_serial_port *port,
291 const unsigned char *buf, int count)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700292{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700293 struct option_port_private *portdata;
294 int i;
295 int left, todo;
296 struct urb *this_urb = NULL; /* spurious */
297 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700298
299 portdata = usb_get_serial_port_data(port);
300
301 dbg("%s: write (%d chars)", __FUNCTION__, count);
302
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700303 i = 0;
304 left = count;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700305 for (i=0; left > 0 && i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700306 todo = left;
307 if (todo > OUT_BUFLEN)
308 todo = OUT_BUFLEN;
309
Matthias Urlichsba460e42005-07-14 00:33:47 -0700310 this_urb = portdata->out_urbs[i];
311 if (this_urb->status == -EINPROGRESS) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700312 if (time_before(jiffies,
313 portdata->tx_start_time[i] + 10 * HZ))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700314 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700315 usb_unlink_urb(this_urb);
Matthias Urlichsba460e42005-07-14 00:33:47 -0700316 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700317 }
Matthias Urlichsba460e42005-07-14 00:33:47 -0700318 if (this_urb->status != 0)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700319 dbg("usb_write %p failed (err=%d)",
320 this_urb, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700321
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700322 dbg("%s: endpoint %d buf %d", __FUNCTION__,
323 usb_pipeendpoint(this_urb->pipe), i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700324
Matthias Urlichsba460e42005-07-14 00:33:47 -0700325 /* send the data */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700326 memcpy (this_urb->transfer_buffer, buf, todo);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700327 this_urb->transfer_buffer_length = todo;
328
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700329 this_urb->dev = port->serial->dev;
330 err = usb_submit_urb(this_urb, GFP_ATOMIC);
331 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700332 dbg("usb_submit_urb %p (write bulk) failed "
333 "(%d, has %d)", this_urb,
334 err, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700335 continue;
336 }
337 portdata->tx_start_time[i] = jiffies;
338 buf += todo;
339 left -= todo;
340 }
341
342 count -= left;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700343 dbg("%s: wrote (did %d)", __FUNCTION__, count);
344 return count;
345}
346
David Howells7d12e782006-10-05 14:55:46 +0100347static void option_indat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700348{
Alan Cox33f0f882006-01-09 20:54:13 -0800349 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700350 int endpoint;
351 struct usb_serial_port *port;
352 struct tty_struct *tty;
353 unsigned char *data = urb->transfer_buffer;
354
355 dbg("%s: %p", __FUNCTION__, urb);
356
357 endpoint = usb_pipeendpoint(urb->pipe);
358 port = (struct usb_serial_port *) urb->context;
359
360 if (urb->status) {
361 dbg("%s: nonzero status: %d on endpoint %02x.",
362 __FUNCTION__, urb->status, endpoint);
363 } else {
364 tty = port->tty;
365 if (urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -0800366 tty_buffer_request_room(tty, urb->actual_length);
367 tty_insert_flip_string(tty, data, urb->actual_length);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700368 tty_flip_buffer_push(tty);
369 } else {
370 dbg("%s: empty read urb received", __FUNCTION__);
371 }
372
373 /* Resubmit urb so we continue receiving */
374 if (port->open_count && urb->status != -ESHUTDOWN) {
375 err = usb_submit_urb(urb, GFP_ATOMIC);
376 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700377 printk(KERN_ERR "%s: resubmit read urb failed. "
378 "(%d)", __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700379 }
380 }
381 return;
382}
383
David Howells7d12e782006-10-05 14:55:46 +0100384static void option_outdat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700385{
386 struct usb_serial_port *port;
387
388 dbg("%s", __FUNCTION__);
389
390 port = (struct usb_serial_port *) urb->context;
391
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700392 usb_serial_port_softint(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700393}
394
David Howells7d12e782006-10-05 14:55:46 +0100395static void option_instat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700396{
397 int err;
398 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
399 struct option_port_private *portdata = usb_get_serial_port_data(port);
400 struct usb_serial *serial = port->serial;
401
402 dbg("%s", __FUNCTION__);
403 dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
404
405 if (urb->status == 0) {
406 struct usb_ctrlrequest *req_pkt =
407 (struct usb_ctrlrequest *)urb->transfer_buffer;
408
409 if (!req_pkt) {
410 dbg("%s: NULL req_pkt\n", __FUNCTION__);
411 return;
412 }
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700413 if ((req_pkt->bRequestType == 0xA1) &&
414 (req_pkt->bRequest == 0x20)) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700415 int old_dcd_state;
416 unsigned char signals = *((unsigned char *)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700417 urb->transfer_buffer +
418 sizeof(struct usb_ctrlrequest));
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700419
420 dbg("%s: signal x%x", __FUNCTION__, signals);
421
422 old_dcd_state = portdata->dcd_state;
423 portdata->cts_state = 1;
424 portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
425 portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
426 portdata->ri_state = ((signals & 0x08) ? 1 : 0);
427
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700428 if (port->tty && !C_CLOCAL(port->tty) &&
429 old_dcd_state && !portdata->dcd_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700430 tty_hangup(port->tty);
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700431 } else {
432 dbg("%s: type %x req %x", __FUNCTION__,
433 req_pkt->bRequestType,req_pkt->bRequest);
434 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700435 } else
436 dbg("%s: error %d", __FUNCTION__, urb->status);
437
438 /* Resubmit urb so we continue receiving IRQ data */
439 if (urb->status != -ESHUTDOWN) {
440 urb->dev = serial->dev;
441 err = usb_submit_urb(urb, GFP_ATOMIC);
442 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700443 dbg("%s: resubmit intr urb failed. (%d)",
444 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700445 }
446}
447
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700448static int option_write_room(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700449{
450 struct option_port_private *portdata;
451 int i;
452 int data_len = 0;
453 struct urb *this_urb;
454
455 portdata = usb_get_serial_port_data(port);
456
Matthias Urlichsba460e42005-07-14 00:33:47 -0700457 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700458 this_urb = portdata->out_urbs[i];
459 if (this_urb && this_urb->status != -EINPROGRESS)
460 data_len += OUT_BUFLEN;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700461 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700462
463 dbg("%s: %d", __FUNCTION__, data_len);
464 return data_len;
465}
466
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700467static int option_chars_in_buffer(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700468{
469 struct option_port_private *portdata;
470 int i;
471 int data_len = 0;
472 struct urb *this_urb;
473
474 portdata = usb_get_serial_port_data(port);
475
Matthias Urlichsba460e42005-07-14 00:33:47 -0700476 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700477 this_urb = portdata->out_urbs[i];
478 if (this_urb && this_urb->status == -EINPROGRESS)
479 data_len += this_urb->transfer_buffer_length;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700480 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700481 dbg("%s: %d", __FUNCTION__, data_len);
482 return data_len;
483}
484
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700485static int option_open(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700486{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700487 struct option_port_private *portdata;
488 struct usb_serial *serial = port->serial;
489 int i, err;
490 struct urb *urb;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700491
492 portdata = usb_get_serial_port_data(port);
493
494 dbg("%s", __FUNCTION__);
495
496 /* Set some sane defaults */
497 portdata->rts_state = 1;
498 portdata->dtr_state = 1;
499
500 /* Reset low level data toggle and start reading from endpoints */
501 for (i = 0; i < N_IN_URB; i++) {
502 urb = portdata->in_urbs[i];
503 if (! urb)
504 continue;
505 if (urb->dev != serial->dev) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700506 dbg("%s: dev %p != %p", __FUNCTION__,
507 urb->dev, serial->dev);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700508 continue;
509 }
510
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700511 /*
512 * make sure endpoint data toggle is synchronized with the
513 * device
514 */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700515 usb_clear_halt(urb->dev, urb->pipe);
516
517 err = usb_submit_urb(urb, GFP_KERNEL);
518 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700519 dbg("%s: submit urb %d failed (%d) %d",
520 __FUNCTION__, i, err,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700521 urb->transfer_buffer_length);
522 }
523 }
524
525 /* Reset low level data toggle on out endpoints */
526 for (i = 0; i < N_OUT_URB; i++) {
527 urb = portdata->out_urbs[i];
528 if (! urb)
529 continue;
530 urb->dev = serial->dev;
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700531 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
532 usb_pipeout(urb->pipe), 0); */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700533 }
534
535 port->tty->low_latency = 1;
536
537 option_send_setup(port);
538
539 return (0);
540}
541
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700542static inline void stop_urb(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700543{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -0400544 if (urb && urb->status == -EINPROGRESS)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700545 usb_kill_urb(urb);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700546}
547
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700548static void option_close(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700549{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700550 int i;
551 struct usb_serial *serial = port->serial;
552 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700553
554 dbg("%s", __FUNCTION__);
555 portdata = usb_get_serial_port_data(port);
556
557 portdata->rts_state = 0;
558 portdata->dtr_state = 0;
559
560 if (serial->dev) {
561 option_send_setup(port);
562
563 /* Stop reading/writing urbs */
564 for (i = 0; i < N_IN_URB; i++)
565 stop_urb(portdata->in_urbs[i]);
566 for (i = 0; i < N_OUT_URB; i++)
567 stop_urb(portdata->out_urbs[i]);
568 }
569 port->tty = NULL;
570}
571
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700572/* Helper functions used by option_setup_urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700573static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
574 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +0100575 void (*callback)(struct urb *))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700576{
577 struct urb *urb;
578
579 if (endpoint == -1)
580 return NULL; /* endpoint not needed */
581
582 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
583 if (urb == NULL) {
584 dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
585 return NULL;
586 }
587
588 /* Fill URB using supplied data. */
589 usb_fill_bulk_urb(urb, serial->dev,
590 usb_sndbulkpipe(serial->dev, endpoint) | dir,
591 buf, len, callback, ctx);
592
593 return urb;
594}
595
596/* Setup urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700597static void option_setup_urbs(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700598{
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200599 int i,j;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700600 struct usb_serial_port *port;
601 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700602
603 dbg("%s", __FUNCTION__);
604
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200605 for (i = 0; i < serial->num_ports; i++) {
606 port = serial->port[i];
607 portdata = usb_get_serial_port_data(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700608
609 /* Do indat endpoints first */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200610 for (j = 0; j < N_IN_URB; ++j) {
611 portdata->in_urbs[j] = option_setup_urb (serial,
612 port->bulk_in_endpointAddress, USB_DIR_IN, port,
613 portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
614 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700615
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200616 /* outdat endpoints */
617 for (j = 0; j < N_OUT_URB; ++j) {
618 portdata->out_urbs[j] = option_setup_urb (serial,
619 port->bulk_out_endpointAddress, USB_DIR_OUT, port,
620 portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
621 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700622 }
623}
624
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700625static int option_send_setup(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700626{
627 struct usb_serial *serial = port->serial;
628 struct option_port_private *portdata;
629
630 dbg("%s", __FUNCTION__);
631
Miguel Angel Alvarez8c152712006-12-14 19:49:35 +0100632 if (port->number != 0)
633 return 0;
634
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700635 portdata = usb_get_serial_port_data(port);
636
637 if (port->tty) {
638 int val = 0;
639 if (portdata->dtr_state)
640 val |= 0x01;
641 if (portdata->rts_state)
642 val |= 0x02;
643
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700644 return usb_control_msg(serial->dev,
645 usb_rcvctrlpipe(serial->dev, 0),
646 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700647 }
648
649 return 0;
650}
651
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700652static int option_startup(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700653{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700654 int i, err;
655 struct usb_serial_port *port;
656 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700657
658 dbg("%s", __FUNCTION__);
659
660 /* Now setup per port private data */
661 for (i = 0; i < serial->num_ports; i++) {
662 port = serial->port[i];
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100663 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700664 if (!portdata) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700665 dbg("%s: kmalloc for option_port_private (%d) failed!.",
666 __FUNCTION__, i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700667 return (1);
668 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700669
670 usb_set_serial_port_data(port, portdata);
671
672 if (! port->interrupt_in_urb)
673 continue;
674 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
675 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700676 dbg("%s: submit irq_in urb failed %d",
677 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700678 }
679
680 option_setup_urbs(serial);
681
682 return (0);
683}
684
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700685static void option_shutdown(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700686{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700687 int i, j;
688 struct usb_serial_port *port;
689 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700690
691 dbg("%s", __FUNCTION__);
692
693 /* Stop reading/writing urbs */
694 for (i = 0; i < serial->num_ports; ++i) {
695 port = serial->port[i];
696 portdata = usb_get_serial_port_data(port);
697 for (j = 0; j < N_IN_URB; j++)
698 stop_urb(portdata->in_urbs[j]);
699 for (j = 0; j < N_OUT_URB; j++)
700 stop_urb(portdata->out_urbs[j]);
701 }
702
703 /* Now free them */
704 for (i = 0; i < serial->num_ports; ++i) {
705 port = serial->port[i];
706 portdata = usb_get_serial_port_data(port);
707
708 for (j = 0; j < N_IN_URB; j++) {
709 if (portdata->in_urbs[j]) {
710 usb_free_urb(portdata->in_urbs[j]);
711 portdata->in_urbs[j] = NULL;
712 }
713 }
714 for (j = 0; j < N_OUT_URB; j++) {
715 if (portdata->out_urbs[j]) {
716 usb_free_urb(portdata->out_urbs[j]);
717 portdata->out_urbs[j] = NULL;
718 }
719 }
720 }
721
722 /* Now free per port private data */
723 for (i = 0; i < serial->num_ports; i++) {
724 port = serial->port[i];
725 kfree(usb_get_serial_port_data(port));
726 }
727}
728
729MODULE_AUTHOR(DRIVER_AUTHOR);
730MODULE_DESCRIPTION(DRIVER_DESC);
731MODULE_VERSION(DRIVER_VERSION);
732MODULE_LICENSE("GPL");
733
Matthias Urlichsba460e42005-07-14 00:33:47 -0700734#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700735module_param(debug, bool, S_IRUGO | S_IWUSR);
736MODULE_PARM_DESC(debug, "Debug messages");
Matthias Urlichsba460e42005-07-14 00:33:47 -0700737#endif
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700738