blob: 78ad4b3126a646a7311a8255bac4d9d821c050e5 [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
12 History:
13
14 2005-05-19 v0.1 Initial version, based on incomplete docs
Matthias Urlichsba460e42005-07-14 00:33:47 -070015 and analysis of misbehavior with the standard driver
Matthias Urlichs58cfe912005-05-23 17:00:48 -070016 2005-05-20 v0.2 Extended the input buffer to avoid losing
17 random 64-byte chunks of data
18 2005-05-21 v0.3 implemented chars_in_buffer()
19 turned on low_latency
20 simplified the code somewhat
Matthias Urlichsba460e42005-07-14 00:33:47 -070021 2005-05-24 v0.4 option_write() sometimes deadlocked under heavy load
22 removed some dead code
23 added sponsor notice
24 coding style clean-up
25 2005-06-20 v0.4.1 add missing braces :-/
26 killed end-of-line whitespace
27 2005-07-15 v0.4.2 rename WLAN product to FUSION, add FUSION2
Matthias Urlichsb6137382005-09-22 00:48:40 -070028 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard
Matthias Urlichsb27c73d2005-09-22 00:49:33 -070029 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes
30 wants to send >2000 bytes.
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020031 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
Matthias Urlichsba460e42005-07-14 00:33:47 -070038
39 Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
40
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020041 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.
Matthias Urlichs58cfe912005-05-23 17:00:48 -070054*/
Matthias Urlichsba460e42005-07-14 00:33:47 -070055
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020056#define DRIVER_VERSION "v0.7.0"
Matthias Urlichs58cfe912005-05-23 17:00:48 -070057#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020058#define DRIVER_DESC "USB Driver for GSM modems"
Matthias Urlichs58cfe912005-05-23 17:00:48 -070059
Matthias Urlichs58cfe912005-05-23 17:00:48 -070060#include <linux/kernel.h>
61#include <linux/jiffies.h>
62#include <linux/errno.h>
63#include <linux/tty.h>
64#include <linux/tty_flip.h>
65#include <linux/module.h>
66#include <linux/usb.h>
67#include "usb-serial.h"
68
69/* Function prototypes */
Andrew Morton7bb75ae2005-07-27 01:08:30 -070070static int option_open(struct usb_serial_port *port, struct file *filp);
71static void option_close(struct usb_serial_port *port, struct file *filp);
72static int option_startup(struct usb_serial *serial);
73static void option_shutdown(struct usb_serial *serial);
74static void option_rx_throttle(struct usb_serial_port *port);
75static void option_rx_unthrottle(struct usb_serial_port *port);
76static int option_write_room(struct usb_serial_port *port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070077
78static void option_instat_callback(struct urb *urb, struct pt_regs *regs);
79
Andrew Morton7bb75ae2005-07-27 01:08:30 -070080static int option_write(struct usb_serial_port *port,
81 const unsigned char *buf, int count);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070082
Andrew Morton7bb75ae2005-07-27 01:08:30 -070083static int option_chars_in_buffer(struct usb_serial_port *port);
84static int option_ioctl(struct usb_serial_port *port, struct file *file,
85 unsigned int cmd, unsigned long arg);
86static void option_set_termios(struct usb_serial_port *port,
87 struct termios *old);
88static void option_break_ctl(struct usb_serial_port *port, int break_state);
89static int option_tiocmget(struct usb_serial_port *port, struct file *file);
90static int option_tiocmset(struct usb_serial_port *port, struct file *file,
91 unsigned int set, unsigned int clear);
92static int option_send_setup(struct usb_serial_port *port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070093
94/* Vendor and product IDs */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020095#define OPTION_VENDOR_ID 0x0AF0
96#define HUAWEI_VENDOR_ID 0x12D1
97#define AUDIOVOX_VENDOR_ID 0x0F3D
98#define SIERRAWIRELESS_VENDOR_ID 0x1199
99#define NOVATELWIRELESS_VENDOR_ID 0x1410
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700100
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200101#define OPTION_PRODUCT_OLD 0x5000
102#define OPTION_PRODUCT_FUSION 0x6000
103#define OPTION_PRODUCT_FUSION2 0x6300
104#define OPTION_PRODUCT_COBRA 0x6500
105#define HUAWEI_PRODUCT_E600 0x1001
106#define AUDIOVOX_PRODUCT_AIRCARD 0x0112
107#define SIERRAWIRELESS_PRODUCT_MC8755 0x6802
108#define NOVATELWIRELESS_PRODUCT_U740 0x1400
Matthias Urlichsba460e42005-07-14 00:33:47 -0700109
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700110static struct usb_device_id option_ids[] = {
111 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
Matthias Urlichsba460e42005-07-14 00:33:47 -0700112 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
113 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200114 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
Matthias Urlichsb6137382005-09-22 00:48:40 -0700115 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
116 { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200117 { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
118 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
119 { } /* Terminating entry */
120};
121
122static struct usb_device_id option_ids1[] = {
123 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
124 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
125 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
126 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
127 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
128 { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
129 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
130 { } /* Terminating entry */
131};
132static struct usb_device_id option_ids3[] = {
133 { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700134 { } /* Terminating entry */
135};
136
137MODULE_DEVICE_TABLE(usb, option_ids);
138
139static struct usb_driver option_driver = {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700140 .name = "option",
141 .probe = usb_serial_probe,
142 .disconnect = usb_serial_disconnect,
143 .id_table = option_ids,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800144 .no_dynamic_id = 1,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700145};
146
Uwe Zeisbergerc30fe7f2006-03-24 18:23:14 +0100147/* The card has three separate interfaces, which the serial driver
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700148 * recognizes separately, thus num_port=1.
149 */
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700150static struct usb_serial_driver option_3port_device = {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700151 .driver = {
152 .owner = THIS_MODULE,
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -0700153 .name = "option",
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700154 },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200155 .description = "GSM modem (3-port)",
156 .id_table = option_ids3,
Matthias Urlichsba460e42005-07-14 00:33:47 -0700157 .num_interrupt_in = NUM_DONT_CARE,
158 .num_bulk_in = NUM_DONT_CARE,
159 .num_bulk_out = NUM_DONT_CARE,
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200160 .num_ports = 3,
161 .open = option_open,
162 .close = option_close,
163 .write = option_write,
164 .write_room = option_write_room,
165 .chars_in_buffer = option_chars_in_buffer,
166 .throttle = option_rx_throttle,
167 .unthrottle = option_rx_unthrottle,
168 .set_termios = option_set_termios,
169 .break_ctl = option_break_ctl,
170 .tiocmget = option_tiocmget,
171 .tiocmset = option_tiocmset,
172 .attach = option_startup,
173 .shutdown = option_shutdown,
174 .read_int_callback = option_instat_callback,
175};
176
177static struct usb_serial_driver option_1port_device = {
178 .driver = {
179 .owner = THIS_MODULE,
180 .name = "option",
181 },
182 .description = "GSM modem (1-port)",
183 .id_table = option_ids1,
184 .num_interrupt_in = NUM_DONT_CARE,
185 .num_bulk_in = NUM_DONT_CARE,
186 .num_bulk_out = NUM_DONT_CARE,
187 .num_ports = 1,
Matthias Urlichsba460e42005-07-14 00:33:47 -0700188 .open = option_open,
189 .close = option_close,
190 .write = option_write,
191 .write_room = option_write_room,
192 .chars_in_buffer = option_chars_in_buffer,
193 .throttle = option_rx_throttle,
194 .unthrottle = option_rx_unthrottle,
195 .ioctl = option_ioctl,
196 .set_termios = option_set_termios,
197 .break_ctl = option_break_ctl,
198 .tiocmget = option_tiocmget,
199 .tiocmset = option_tiocmset,
200 .attach = option_startup,
201 .shutdown = option_shutdown,
202 .read_int_callback = option_instat_callback,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700203};
204
Matthias Urlichsba460e42005-07-14 00:33:47 -0700205#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700206static int debug;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700207#else
208#define debug 0
209#endif
210
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700211/* per port private data */
212
Matthias Urlichsba460e42005-07-14 00:33:47 -0700213#define N_IN_URB 4
214#define N_OUT_URB 1
Matthias Urlichsb27c73d2005-09-22 00:49:33 -0700215#define IN_BUFLEN 4096
Matthias Urlichsba460e42005-07-14 00:33:47 -0700216#define OUT_BUFLEN 128
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700217
218struct option_port_private {
219 /* Input endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700220 struct urb *in_urbs[N_IN_URB];
221 char in_buffer[N_IN_URB][IN_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700222 /* Output endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700223 struct urb *out_urbs[N_OUT_URB];
224 char out_buffer[N_OUT_URB][OUT_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700225
226 /* Settings for the port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700227 int rts_state; /* Handshaking pins (outputs) */
228 int dtr_state;
229 int cts_state; /* Handshaking pins (inputs) */
230 int dsr_state;
231 int dcd_state;
232 int ri_state;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700233
Matthias Urlichsba460e42005-07-14 00:33:47 -0700234 unsigned long tx_start_time[N_OUT_URB];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700235};
236
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700237/* Functions used by new usb-serial code. */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700238static int __init option_init(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700239{
240 int retval;
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200241 retval = usb_serial_register(&option_1port_device);
242 if (retval)
243 goto failed_1port_device_register;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700244 retval = usb_serial_register(&option_3port_device);
245 if (retval)
246 goto failed_3port_device_register;
247 retval = usb_register(&option_driver);
248 if (retval)
249 goto failed_driver_register;
250
251 info(DRIVER_DESC ": " DRIVER_VERSION);
252
253 return 0;
254
255failed_driver_register:
256 usb_serial_deregister (&option_3port_device);
257failed_3port_device_register:
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200258 usb_serial_deregister (&option_1port_device);
259failed_1port_device_register:
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700260 return retval;
261}
262
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700263static void __exit option_exit(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700264{
265 usb_deregister (&option_driver);
266 usb_serial_deregister (&option_3port_device);
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200267 usb_serial_deregister (&option_1port_device);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700268}
269
270module_init(option_init);
271module_exit(option_exit);
272
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700273static void option_rx_throttle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700274{
275 dbg("%s", __FUNCTION__);
276}
277
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700278static void option_rx_unthrottle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700279{
280 dbg("%s", __FUNCTION__);
281}
282
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700283static void option_break_ctl(struct usb_serial_port *port, int break_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700284{
285 /* Unfortunately, I don't know how to send a break */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700286 dbg("%s", __FUNCTION__);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700287}
288
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700289static void option_set_termios(struct usb_serial_port *port,
290 struct termios *old_termios)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700291{
292 dbg("%s", __FUNCTION__);
293
294 option_send_setup(port);
295}
296
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700297static int option_tiocmget(struct usb_serial_port *port, struct file *file)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700298{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700299 unsigned int value;
300 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700301
302 portdata = usb_get_serial_port_data(port);
303
304 value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
305 ((portdata->dtr_state) ? TIOCM_DTR : 0) |
306 ((portdata->cts_state) ? TIOCM_CTS : 0) |
307 ((portdata->dsr_state) ? TIOCM_DSR : 0) |
308 ((portdata->dcd_state) ? TIOCM_CAR : 0) |
309 ((portdata->ri_state) ? TIOCM_RNG : 0);
310
311 return value;
312}
313
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700314static int option_tiocmset(struct usb_serial_port *port, struct file *file,
315 unsigned int set, unsigned int clear)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700316{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700317 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700318
319 portdata = usb_get_serial_port_data(port);
320
321 if (set & TIOCM_RTS)
322 portdata->rts_state = 1;
323 if (set & TIOCM_DTR)
324 portdata->dtr_state = 1;
325
326 if (clear & TIOCM_RTS)
327 portdata->rts_state = 0;
328 if (clear & TIOCM_DTR)
329 portdata->dtr_state = 0;
330 return option_send_setup(port);
331}
332
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700333static int option_ioctl(struct usb_serial_port *port, struct file *file,
334 unsigned int cmd, unsigned long arg)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700335{
336 return -ENOIOCTLCMD;
337}
338
339/* Write */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700340static int option_write(struct usb_serial_port *port,
341 const unsigned char *buf, int count)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700342{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700343 struct option_port_private *portdata;
344 int i;
345 int left, todo;
346 struct urb *this_urb = NULL; /* spurious */
347 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700348
349 portdata = usb_get_serial_port_data(port);
350
351 dbg("%s: write (%d chars)", __FUNCTION__, count);
352
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700353 i = 0;
354 left = count;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700355 for (i=0; left > 0 && i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700356 todo = left;
357 if (todo > OUT_BUFLEN)
358 todo = OUT_BUFLEN;
359
Matthias Urlichsba460e42005-07-14 00:33:47 -0700360 this_urb = portdata->out_urbs[i];
361 if (this_urb->status == -EINPROGRESS) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700362 if (time_before(jiffies,
363 portdata->tx_start_time[i] + 10 * HZ))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700364 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700365 usb_unlink_urb(this_urb);
Matthias Urlichsba460e42005-07-14 00:33:47 -0700366 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700367 }
Matthias Urlichsba460e42005-07-14 00:33:47 -0700368 if (this_urb->status != 0)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700369 dbg("usb_write %p failed (err=%d)",
370 this_urb, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700371
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700372 dbg("%s: endpoint %d buf %d", __FUNCTION__,
373 usb_pipeendpoint(this_urb->pipe), i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700374
Matthias Urlichsba460e42005-07-14 00:33:47 -0700375 /* send the data */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700376 memcpy (this_urb->transfer_buffer, buf, todo);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700377 this_urb->transfer_buffer_length = todo;
378
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700379 this_urb->dev = port->serial->dev;
380 err = usb_submit_urb(this_urb, GFP_ATOMIC);
381 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700382 dbg("usb_submit_urb %p (write bulk) failed "
383 "(%d, has %d)", this_urb,
384 err, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700385 continue;
386 }
387 portdata->tx_start_time[i] = jiffies;
388 buf += todo;
389 left -= todo;
390 }
391
392 count -= left;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700393 dbg("%s: wrote (did %d)", __FUNCTION__, count);
394 return count;
395}
396
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700397static void option_indat_callback(struct urb *urb, struct pt_regs *regs)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700398{
Alan Cox33f0f882006-01-09 20:54:13 -0800399 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700400 int endpoint;
401 struct usb_serial_port *port;
402 struct tty_struct *tty;
403 unsigned char *data = urb->transfer_buffer;
404
405 dbg("%s: %p", __FUNCTION__, urb);
406
407 endpoint = usb_pipeendpoint(urb->pipe);
408 port = (struct usb_serial_port *) urb->context;
409
410 if (urb->status) {
411 dbg("%s: nonzero status: %d on endpoint %02x.",
412 __FUNCTION__, urb->status, endpoint);
413 } else {
414 tty = port->tty;
415 if (urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -0800416 tty_buffer_request_room(tty, urb->actual_length);
417 tty_insert_flip_string(tty, data, urb->actual_length);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700418 tty_flip_buffer_push(tty);
419 } else {
420 dbg("%s: empty read urb received", __FUNCTION__);
421 }
422
423 /* Resubmit urb so we continue receiving */
424 if (port->open_count && urb->status != -ESHUTDOWN) {
425 err = usb_submit_urb(urb, GFP_ATOMIC);
426 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700427 printk(KERN_ERR "%s: resubmit read urb failed. "
428 "(%d)", __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700429 }
430 }
431 return;
432}
433
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700434static void option_outdat_callback(struct urb *urb, struct pt_regs *regs)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700435{
436 struct usb_serial_port *port;
437
438 dbg("%s", __FUNCTION__);
439
440 port = (struct usb_serial_port *) urb->context;
441
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700442 usb_serial_port_softint(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700443}
444
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700445static void option_instat_callback(struct urb *urb, struct pt_regs *regs)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700446{
447 int err;
448 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
449 struct option_port_private *portdata = usb_get_serial_port_data(port);
450 struct usb_serial *serial = port->serial;
451
452 dbg("%s", __FUNCTION__);
453 dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
454
455 if (urb->status == 0) {
456 struct usb_ctrlrequest *req_pkt =
457 (struct usb_ctrlrequest *)urb->transfer_buffer;
458
459 if (!req_pkt) {
460 dbg("%s: NULL req_pkt\n", __FUNCTION__);
461 return;
462 }
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700463 if ((req_pkt->bRequestType == 0xA1) &&
464 (req_pkt->bRequest == 0x20)) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700465 int old_dcd_state;
466 unsigned char signals = *((unsigned char *)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700467 urb->transfer_buffer +
468 sizeof(struct usb_ctrlrequest));
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700469
470 dbg("%s: signal x%x", __FUNCTION__, signals);
471
472 old_dcd_state = portdata->dcd_state;
473 portdata->cts_state = 1;
474 portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
475 portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
476 portdata->ri_state = ((signals & 0x08) ? 1 : 0);
477
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700478 if (port->tty && !C_CLOCAL(port->tty) &&
479 old_dcd_state && !portdata->dcd_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700480 tty_hangup(port->tty);
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700481 } else {
482 dbg("%s: type %x req %x", __FUNCTION__,
483 req_pkt->bRequestType,req_pkt->bRequest);
484 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700485 } else
486 dbg("%s: error %d", __FUNCTION__, urb->status);
487
488 /* Resubmit urb so we continue receiving IRQ data */
489 if (urb->status != -ESHUTDOWN) {
490 urb->dev = serial->dev;
491 err = usb_submit_urb(urb, GFP_ATOMIC);
492 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700493 dbg("%s: resubmit intr urb failed. (%d)",
494 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700495 }
496}
497
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700498static int option_write_room(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700499{
500 struct option_port_private *portdata;
501 int i;
502 int data_len = 0;
503 struct urb *this_urb;
504
505 portdata = usb_get_serial_port_data(port);
506
Matthias Urlichsba460e42005-07-14 00:33:47 -0700507 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700508 this_urb = portdata->out_urbs[i];
509 if (this_urb && this_urb->status != -EINPROGRESS)
510 data_len += OUT_BUFLEN;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700511 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700512
513 dbg("%s: %d", __FUNCTION__, data_len);
514 return data_len;
515}
516
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700517static int option_chars_in_buffer(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700518{
519 struct option_port_private *portdata;
520 int i;
521 int data_len = 0;
522 struct urb *this_urb;
523
524 portdata = usb_get_serial_port_data(port);
525
Matthias Urlichsba460e42005-07-14 00:33:47 -0700526 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700527 this_urb = portdata->out_urbs[i];
528 if (this_urb && this_urb->status == -EINPROGRESS)
529 data_len += this_urb->transfer_buffer_length;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700530 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700531 dbg("%s: %d", __FUNCTION__, data_len);
532 return data_len;
533}
534
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700535static int option_open(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700536{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700537 struct option_port_private *portdata;
538 struct usb_serial *serial = port->serial;
539 int i, err;
540 struct urb *urb;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700541
542 portdata = usb_get_serial_port_data(port);
543
544 dbg("%s", __FUNCTION__);
545
546 /* Set some sane defaults */
547 portdata->rts_state = 1;
548 portdata->dtr_state = 1;
549
550 /* Reset low level data toggle and start reading from endpoints */
551 for (i = 0; i < N_IN_URB; i++) {
552 urb = portdata->in_urbs[i];
553 if (! urb)
554 continue;
555 if (urb->dev != serial->dev) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700556 dbg("%s: dev %p != %p", __FUNCTION__,
557 urb->dev, serial->dev);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700558 continue;
559 }
560
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700561 /*
562 * make sure endpoint data toggle is synchronized with the
563 * device
564 */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700565 usb_clear_halt(urb->dev, urb->pipe);
566
567 err = usb_submit_urb(urb, GFP_KERNEL);
568 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700569 dbg("%s: submit urb %d failed (%d) %d",
570 __FUNCTION__, i, err,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700571 urb->transfer_buffer_length);
572 }
573 }
574
575 /* Reset low level data toggle on out endpoints */
576 for (i = 0; i < N_OUT_URB; i++) {
577 urb = portdata->out_urbs[i];
578 if (! urb)
579 continue;
580 urb->dev = serial->dev;
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700581 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
582 usb_pipeout(urb->pipe), 0); */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700583 }
584
585 port->tty->low_latency = 1;
586
587 option_send_setup(port);
588
589 return (0);
590}
591
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700592static inline void stop_urb(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700593{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -0400594 if (urb && urb->status == -EINPROGRESS)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700595 usb_kill_urb(urb);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700596}
597
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700598static void option_close(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700599{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700600 int i;
601 struct usb_serial *serial = port->serial;
602 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700603
604 dbg("%s", __FUNCTION__);
605 portdata = usb_get_serial_port_data(port);
606
607 portdata->rts_state = 0;
608 portdata->dtr_state = 0;
609
610 if (serial->dev) {
611 option_send_setup(port);
612
613 /* Stop reading/writing urbs */
614 for (i = 0; i < N_IN_URB; i++)
615 stop_urb(portdata->in_urbs[i]);
616 for (i = 0; i < N_OUT_URB; i++)
617 stop_urb(portdata->out_urbs[i]);
618 }
619 port->tty = NULL;
620}
621
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700622/* Helper functions used by option_setup_urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700623static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
624 int dir, void *ctx, char *buf, int len,
625 void (*callback)(struct urb *, struct pt_regs *regs))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700626{
627 struct urb *urb;
628
629 if (endpoint == -1)
630 return NULL; /* endpoint not needed */
631
632 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
633 if (urb == NULL) {
634 dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
635 return NULL;
636 }
637
638 /* Fill URB using supplied data. */
639 usb_fill_bulk_urb(urb, serial->dev,
640 usb_sndbulkpipe(serial->dev, endpoint) | dir,
641 buf, len, callback, ctx);
642
643 return urb;
644}
645
646/* Setup urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700647static void option_setup_urbs(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700648{
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200649 int i,j;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700650 struct usb_serial_port *port;
651 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700652
653 dbg("%s", __FUNCTION__);
654
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200655
656 for (i = 0; i < serial->num_ports; i++) {
657 port = serial->port[i];
658 portdata = usb_get_serial_port_data(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700659
660 /* Do indat endpoints first */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200661 for (j = 0; j < N_IN_URB; ++j) {
662 portdata->in_urbs[j] = option_setup_urb (serial,
663 port->bulk_in_endpointAddress, USB_DIR_IN, port,
664 portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
665 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700666
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200667 /* outdat endpoints */
668 for (j = 0; j < N_OUT_URB; ++j) {
669 portdata->out_urbs[j] = option_setup_urb (serial,
670 port->bulk_out_endpointAddress, USB_DIR_OUT, port,
671 portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
672 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700673 }
674}
675
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700676static int option_send_setup(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700677{
678 struct usb_serial *serial = port->serial;
679 struct option_port_private *portdata;
680
681 dbg("%s", __FUNCTION__);
682
683 portdata = usb_get_serial_port_data(port);
684
685 if (port->tty) {
686 int val = 0;
687 if (portdata->dtr_state)
688 val |= 0x01;
689 if (portdata->rts_state)
690 val |= 0x02;
691
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700692 return usb_control_msg(serial->dev,
693 usb_rcvctrlpipe(serial->dev, 0),
694 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700695 }
696
697 return 0;
698}
699
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700700static int option_startup(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700701{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700702 int i, err;
703 struct usb_serial_port *port;
704 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700705
706 dbg("%s", __FUNCTION__);
707
708 /* Now setup per port private data */
709 for (i = 0; i < serial->num_ports; i++) {
710 port = serial->port[i];
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100711 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700712 if (!portdata) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700713 dbg("%s: kmalloc for option_port_private (%d) failed!.",
714 __FUNCTION__, i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700715 return (1);
716 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700717
718 usb_set_serial_port_data(port, portdata);
719
720 if (! port->interrupt_in_urb)
721 continue;
722 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
723 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700724 dbg("%s: submit irq_in urb failed %d",
725 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700726 }
727
728 option_setup_urbs(serial);
729
730 return (0);
731}
732
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700733static void option_shutdown(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700734{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700735 int i, j;
736 struct usb_serial_port *port;
737 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700738
739 dbg("%s", __FUNCTION__);
740
741 /* Stop reading/writing urbs */
742 for (i = 0; i < serial->num_ports; ++i) {
743 port = serial->port[i];
744 portdata = usb_get_serial_port_data(port);
745 for (j = 0; j < N_IN_URB; j++)
746 stop_urb(portdata->in_urbs[j]);
747 for (j = 0; j < N_OUT_URB; j++)
748 stop_urb(portdata->out_urbs[j]);
749 }
750
751 /* Now free them */
752 for (i = 0; i < serial->num_ports; ++i) {
753 port = serial->port[i];
754 portdata = usb_get_serial_port_data(port);
755
756 for (j = 0; j < N_IN_URB; j++) {
757 if (portdata->in_urbs[j]) {
758 usb_free_urb(portdata->in_urbs[j]);
759 portdata->in_urbs[j] = NULL;
760 }
761 }
762 for (j = 0; j < N_OUT_URB; j++) {
763 if (portdata->out_urbs[j]) {
764 usb_free_urb(portdata->out_urbs[j]);
765 portdata->out_urbs[j] = NULL;
766 }
767 }
768 }
769
770 /* Now free per port private data */
771 for (i = 0; i < serial->num_ports; i++) {
772 port = serial->port[i];
773 kfree(usb_get_serial_port_data(port));
774 }
775}
776
777MODULE_AUTHOR(DRIVER_AUTHOR);
778MODULE_DESCRIPTION(DRIVER_DESC);
779MODULE_VERSION(DRIVER_VERSION);
780MODULE_LICENSE("GPL");
781
Matthias Urlichsba460e42005-07-14 00:33:47 -0700782#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700783module_param(debug, bool, S_IRUGO | S_IWUSR);
784MODULE_PARM_DESC(debug, "Debug messages");
Matthias Urlichsba460e42005-07-14 00:33:47 -0700785#endif
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700786