blob: b0861b61bba78e36920e8913e15fcd3b4733658d [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
60#include <linux/config.h>
61#include <linux/kernel.h>
62#include <linux/jiffies.h>
63#include <linux/errno.h>
64#include <linux/tty.h>
65#include <linux/tty_flip.h>
66#include <linux/module.h>
67#include <linux/usb.h>
68#include "usb-serial.h"
69
70/* Function prototypes */
Andrew Morton7bb75ae2005-07-27 01:08:30 -070071static int option_open(struct usb_serial_port *port, struct file *filp);
72static void option_close(struct usb_serial_port *port, struct file *filp);
73static int option_startup(struct usb_serial *serial);
74static void option_shutdown(struct usb_serial *serial);
75static void option_rx_throttle(struct usb_serial_port *port);
76static void option_rx_unthrottle(struct usb_serial_port *port);
77static int option_write_room(struct usb_serial_port *port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070078
79static void option_instat_callback(struct urb *urb, struct pt_regs *regs);
80
Andrew Morton7bb75ae2005-07-27 01:08:30 -070081static int option_write(struct usb_serial_port *port,
82 const unsigned char *buf, int count);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070083
Andrew Morton7bb75ae2005-07-27 01:08:30 -070084static int option_chars_in_buffer(struct usb_serial_port *port);
85static int option_ioctl(struct usb_serial_port *port, struct file *file,
86 unsigned int cmd, unsigned long arg);
87static void option_set_termios(struct usb_serial_port *port,
88 struct termios *old);
89static void option_break_ctl(struct usb_serial_port *port, int break_state);
90static int option_tiocmget(struct usb_serial_port *port, struct file *file);
91static int option_tiocmset(struct usb_serial_port *port, struct file *file,
92 unsigned int set, unsigned int clear);
93static int option_send_setup(struct usb_serial_port *port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070094
95/* Vendor and product IDs */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020096#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
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700101
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200102#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
Matthias Urlichsba460e42005-07-14 00:33:47 -0700110
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700111static struct usb_device_id option_ids[] = {
112 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
Matthias Urlichsba460e42005-07-14 00:33:47 -0700113 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
114 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200115 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
Matthias Urlichsb6137382005-09-22 00:48:40 -0700116 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
117 { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200118 { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
119 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
120 { } /* Terminating entry */
121};
122
123static 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};
133static struct usb_device_id option_ids3[] = {
134 { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700135 { } /* Terminating entry */
136};
137
138MODULE_DEVICE_TABLE(usb, option_ids);
139
140static struct usb_driver option_driver = {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700141 .name = "option",
142 .probe = usb_serial_probe,
143 .disconnect = usb_serial_disconnect,
144 .id_table = option_ids,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800145 .no_dynamic_id = 1,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700146};
147
Uwe Zeisbergerc30fe7f2006-03-24 18:23:14 +0100148/* The card has three separate interfaces, which the serial driver
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700149 * recognizes separately, thus num_port=1.
150 */
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700151static struct usb_serial_driver option_3port_device = {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700152 .driver = {
153 .owner = THIS_MODULE,
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -0700154 .name = "option",
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700155 },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200156 .description = "GSM modem (3-port)",
157 .id_table = option_ids3,
Matthias Urlichsba460e42005-07-14 00:33:47 -0700158 .num_interrupt_in = NUM_DONT_CARE,
159 .num_bulk_in = NUM_DONT_CARE,
160 .num_bulk_out = NUM_DONT_CARE,
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200161 .num_ports = 3,
162 .open = option_open,
163 .close = option_close,
164 .write = option_write,
165 .write_room = option_write_room,
166 .chars_in_buffer = option_chars_in_buffer,
167 .throttle = option_rx_throttle,
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
178static 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,
Matthias Urlichsba460e42005-07-14 00:33:47 -0700189 .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,
196 .ioctl = option_ioctl,
197 .set_termios = option_set_termios,
198 .break_ctl = option_break_ctl,
199 .tiocmget = option_tiocmget,
200 .tiocmset = option_tiocmset,
201 .attach = option_startup,
202 .shutdown = option_shutdown,
203 .read_int_callback = option_instat_callback,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700204};
205
Matthias Urlichsba460e42005-07-14 00:33:47 -0700206#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700207static int debug;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700208#else
209#define debug 0
210#endif
211
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700212/* per port private data */
213
Matthias Urlichsba460e42005-07-14 00:33:47 -0700214#define N_IN_URB 4
215#define N_OUT_URB 1
Matthias Urlichsb27c73d2005-09-22 00:49:33 -0700216#define IN_BUFLEN 4096
Matthias Urlichsba460e42005-07-14 00:33:47 -0700217#define OUT_BUFLEN 128
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700218
219struct option_port_private {
220 /* Input endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700221 struct urb *in_urbs[N_IN_URB];
222 char in_buffer[N_IN_URB][IN_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700223 /* Output endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700224 struct urb *out_urbs[N_OUT_URB];
225 char out_buffer[N_OUT_URB][OUT_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700226
227 /* Settings for the port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700228 int rts_state; /* Handshaking pins (outputs) */
229 int dtr_state;
230 int cts_state; /* Handshaking pins (inputs) */
231 int dsr_state;
232 int dcd_state;
233 int ri_state;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700234
Matthias Urlichsba460e42005-07-14 00:33:47 -0700235 unsigned long tx_start_time[N_OUT_URB];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700236};
237
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700238/* Functions used by new usb-serial code. */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700239static int __init option_init(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700240{
241 int retval;
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200242 retval = usb_serial_register(&option_1port_device);
243 if (retval)
244 goto failed_1port_device_register;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700245 retval = usb_serial_register(&option_3port_device);
246 if (retval)
247 goto failed_3port_device_register;
248 retval = usb_register(&option_driver);
249 if (retval)
250 goto failed_driver_register;
251
252 info(DRIVER_DESC ": " DRIVER_VERSION);
253
254 return 0;
255
256failed_driver_register:
257 usb_serial_deregister (&option_3port_device);
258failed_3port_device_register:
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200259 usb_serial_deregister (&option_1port_device);
260failed_1port_device_register:
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700261 return retval;
262}
263
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700264static void __exit option_exit(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700265{
266 usb_deregister (&option_driver);
267 usb_serial_deregister (&option_3port_device);
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200268 usb_serial_deregister (&option_1port_device);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700269}
270
271module_init(option_init);
272module_exit(option_exit);
273
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700274static void option_rx_throttle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700275{
276 dbg("%s", __FUNCTION__);
277}
278
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700279static void option_rx_unthrottle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700280{
281 dbg("%s", __FUNCTION__);
282}
283
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700284static void option_break_ctl(struct usb_serial_port *port, int break_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700285{
286 /* Unfortunately, I don't know how to send a break */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700287 dbg("%s", __FUNCTION__);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700288}
289
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700290static void option_set_termios(struct usb_serial_port *port,
291 struct termios *old_termios)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700292{
293 dbg("%s", __FUNCTION__);
294
295 option_send_setup(port);
296}
297
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700298static int option_tiocmget(struct usb_serial_port *port, struct file *file)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700299{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700300 unsigned int value;
301 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700302
303 portdata = usb_get_serial_port_data(port);
304
305 value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
306 ((portdata->dtr_state) ? TIOCM_DTR : 0) |
307 ((portdata->cts_state) ? TIOCM_CTS : 0) |
308 ((portdata->dsr_state) ? TIOCM_DSR : 0) |
309 ((portdata->dcd_state) ? TIOCM_CAR : 0) |
310 ((portdata->ri_state) ? TIOCM_RNG : 0);
311
312 return value;
313}
314
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700315static int option_tiocmset(struct usb_serial_port *port, struct file *file,
316 unsigned int set, unsigned int clear)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700317{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700318 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700319
320 portdata = usb_get_serial_port_data(port);
321
322 if (set & TIOCM_RTS)
323 portdata->rts_state = 1;
324 if (set & TIOCM_DTR)
325 portdata->dtr_state = 1;
326
327 if (clear & TIOCM_RTS)
328 portdata->rts_state = 0;
329 if (clear & TIOCM_DTR)
330 portdata->dtr_state = 0;
331 return option_send_setup(port);
332}
333
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700334static int option_ioctl(struct usb_serial_port *port, struct file *file,
335 unsigned int cmd, unsigned long arg)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700336{
337 return -ENOIOCTLCMD;
338}
339
340/* Write */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700341static int option_write(struct usb_serial_port *port,
342 const unsigned char *buf, int count)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700343{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700344 struct option_port_private *portdata;
345 int i;
346 int left, todo;
347 struct urb *this_urb = NULL; /* spurious */
348 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700349
350 portdata = usb_get_serial_port_data(port);
351
352 dbg("%s: write (%d chars)", __FUNCTION__, count);
353
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700354 i = 0;
355 left = count;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700356 for (i=0; left > 0 && i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700357 todo = left;
358 if (todo > OUT_BUFLEN)
359 todo = OUT_BUFLEN;
360
Matthias Urlichsba460e42005-07-14 00:33:47 -0700361 this_urb = portdata->out_urbs[i];
362 if (this_urb->status == -EINPROGRESS) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700363 if (time_before(jiffies,
364 portdata->tx_start_time[i] + 10 * HZ))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700365 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700366 usb_unlink_urb(this_urb);
Matthias Urlichsba460e42005-07-14 00:33:47 -0700367 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700368 }
Matthias Urlichsba460e42005-07-14 00:33:47 -0700369 if (this_urb->status != 0)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700370 dbg("usb_write %p failed (err=%d)",
371 this_urb, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700372
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700373 dbg("%s: endpoint %d buf %d", __FUNCTION__,
374 usb_pipeendpoint(this_urb->pipe), i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700375
Matthias Urlichsba460e42005-07-14 00:33:47 -0700376 /* send the data */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700377 memcpy (this_urb->transfer_buffer, buf, todo);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700378 this_urb->transfer_buffer_length = todo;
379
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700380 this_urb->dev = port->serial->dev;
381 err = usb_submit_urb(this_urb, GFP_ATOMIC);
382 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700383 dbg("usb_submit_urb %p (write bulk) failed "
384 "(%d, has %d)", this_urb,
385 err, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700386 continue;
387 }
388 portdata->tx_start_time[i] = jiffies;
389 buf += todo;
390 left -= todo;
391 }
392
393 count -= left;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700394 dbg("%s: wrote (did %d)", __FUNCTION__, count);
395 return count;
396}
397
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700398static void option_indat_callback(struct urb *urb, struct pt_regs *regs)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700399{
Alan Cox33f0f882006-01-09 20:54:13 -0800400 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700401 int endpoint;
402 struct usb_serial_port *port;
403 struct tty_struct *tty;
404 unsigned char *data = urb->transfer_buffer;
405
406 dbg("%s: %p", __FUNCTION__, urb);
407
408 endpoint = usb_pipeendpoint(urb->pipe);
409 port = (struct usb_serial_port *) urb->context;
410
411 if (urb->status) {
412 dbg("%s: nonzero status: %d on endpoint %02x.",
413 __FUNCTION__, urb->status, endpoint);
414 } else {
415 tty = port->tty;
416 if (urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -0800417 tty_buffer_request_room(tty, urb->actual_length);
418 tty_insert_flip_string(tty, data, urb->actual_length);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700419 tty_flip_buffer_push(tty);
420 } else {
421 dbg("%s: empty read urb received", __FUNCTION__);
422 }
423
424 /* Resubmit urb so we continue receiving */
425 if (port->open_count && urb->status != -ESHUTDOWN) {
426 err = usb_submit_urb(urb, GFP_ATOMIC);
427 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700428 printk(KERN_ERR "%s: resubmit read urb failed. "
429 "(%d)", __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700430 }
431 }
432 return;
433}
434
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700435static void option_outdat_callback(struct urb *urb, struct pt_regs *regs)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700436{
437 struct usb_serial_port *port;
438
439 dbg("%s", __FUNCTION__);
440
441 port = (struct usb_serial_port *) urb->context;
442
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700443 usb_serial_port_softint(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700444}
445
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700446static void option_instat_callback(struct urb *urb, struct pt_regs *regs)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700447{
448 int err;
449 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
450 struct option_port_private *portdata = usb_get_serial_port_data(port);
451 struct usb_serial *serial = port->serial;
452
453 dbg("%s", __FUNCTION__);
454 dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
455
456 if (urb->status == 0) {
457 struct usb_ctrlrequest *req_pkt =
458 (struct usb_ctrlrequest *)urb->transfer_buffer;
459
460 if (!req_pkt) {
461 dbg("%s: NULL req_pkt\n", __FUNCTION__);
462 return;
463 }
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700464 if ((req_pkt->bRequestType == 0xA1) &&
465 (req_pkt->bRequest == 0x20)) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700466 int old_dcd_state;
467 unsigned char signals = *((unsigned char *)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700468 urb->transfer_buffer +
469 sizeof(struct usb_ctrlrequest));
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700470
471 dbg("%s: signal x%x", __FUNCTION__, signals);
472
473 old_dcd_state = portdata->dcd_state;
474 portdata->cts_state = 1;
475 portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
476 portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
477 portdata->ri_state = ((signals & 0x08) ? 1 : 0);
478
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700479 if (port->tty && !C_CLOCAL(port->tty) &&
480 old_dcd_state && !portdata->dcd_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700481 tty_hangup(port->tty);
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700482 } else {
483 dbg("%s: type %x req %x", __FUNCTION__,
484 req_pkt->bRequestType,req_pkt->bRequest);
485 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700486 } else
487 dbg("%s: error %d", __FUNCTION__, urb->status);
488
489 /* Resubmit urb so we continue receiving IRQ data */
490 if (urb->status != -ESHUTDOWN) {
491 urb->dev = serial->dev;
492 err = usb_submit_urb(urb, GFP_ATOMIC);
493 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700494 dbg("%s: resubmit intr urb failed. (%d)",
495 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700496 }
497}
498
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700499static int option_write_room(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700500{
501 struct option_port_private *portdata;
502 int i;
503 int data_len = 0;
504 struct urb *this_urb;
505
506 portdata = usb_get_serial_port_data(port);
507
Matthias Urlichsba460e42005-07-14 00:33:47 -0700508 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700509 this_urb = portdata->out_urbs[i];
510 if (this_urb && this_urb->status != -EINPROGRESS)
511 data_len += OUT_BUFLEN;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700512 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700513
514 dbg("%s: %d", __FUNCTION__, data_len);
515 return data_len;
516}
517
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700518static int option_chars_in_buffer(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700519{
520 struct option_port_private *portdata;
521 int i;
522 int data_len = 0;
523 struct urb *this_urb;
524
525 portdata = usb_get_serial_port_data(port);
526
Matthias Urlichsba460e42005-07-14 00:33:47 -0700527 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700528 this_urb = portdata->out_urbs[i];
529 if (this_urb && this_urb->status == -EINPROGRESS)
530 data_len += this_urb->transfer_buffer_length;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700531 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700532 dbg("%s: %d", __FUNCTION__, data_len);
533 return data_len;
534}
535
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700536static int option_open(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700537{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700538 struct option_port_private *portdata;
539 struct usb_serial *serial = port->serial;
540 int i, err;
541 struct urb *urb;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700542
543 portdata = usb_get_serial_port_data(port);
544
545 dbg("%s", __FUNCTION__);
546
547 /* Set some sane defaults */
548 portdata->rts_state = 1;
549 portdata->dtr_state = 1;
550
551 /* Reset low level data toggle and start reading from endpoints */
552 for (i = 0; i < N_IN_URB; i++) {
553 urb = portdata->in_urbs[i];
554 if (! urb)
555 continue;
556 if (urb->dev != serial->dev) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700557 dbg("%s: dev %p != %p", __FUNCTION__,
558 urb->dev, serial->dev);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700559 continue;
560 }
561
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700562 /*
563 * make sure endpoint data toggle is synchronized with the
564 * device
565 */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700566 usb_clear_halt(urb->dev, urb->pipe);
567
568 err = usb_submit_urb(urb, GFP_KERNEL);
569 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700570 dbg("%s: submit urb %d failed (%d) %d",
571 __FUNCTION__, i, err,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700572 urb->transfer_buffer_length);
573 }
574 }
575
576 /* Reset low level data toggle on out endpoints */
577 for (i = 0; i < N_OUT_URB; i++) {
578 urb = portdata->out_urbs[i];
579 if (! urb)
580 continue;
581 urb->dev = serial->dev;
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700582 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
583 usb_pipeout(urb->pipe), 0); */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700584 }
585
586 port->tty->low_latency = 1;
587
588 option_send_setup(port);
589
590 return (0);
591}
592
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700593static inline void stop_urb(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700594{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -0400595 if (urb && urb->status == -EINPROGRESS)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700596 usb_kill_urb(urb);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700597}
598
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700599static void option_close(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700600{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700601 int i;
602 struct usb_serial *serial = port->serial;
603 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700604
605 dbg("%s", __FUNCTION__);
606 portdata = usb_get_serial_port_data(port);
607
608 portdata->rts_state = 0;
609 portdata->dtr_state = 0;
610
611 if (serial->dev) {
612 option_send_setup(port);
613
614 /* Stop reading/writing urbs */
615 for (i = 0; i < N_IN_URB; i++)
616 stop_urb(portdata->in_urbs[i]);
617 for (i = 0; i < N_OUT_URB; i++)
618 stop_urb(portdata->out_urbs[i]);
619 }
620 port->tty = NULL;
621}
622
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700623/* Helper functions used by option_setup_urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700624static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
625 int dir, void *ctx, char *buf, int len,
626 void (*callback)(struct urb *, struct pt_regs *regs))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700627{
628 struct urb *urb;
629
630 if (endpoint == -1)
631 return NULL; /* endpoint not needed */
632
633 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
634 if (urb == NULL) {
635 dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
636 return NULL;
637 }
638
639 /* Fill URB using supplied data. */
640 usb_fill_bulk_urb(urb, serial->dev,
641 usb_sndbulkpipe(serial->dev, endpoint) | dir,
642 buf, len, callback, ctx);
643
644 return urb;
645}
646
647/* Setup urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700648static void option_setup_urbs(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700649{
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200650 int i,j;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700651 struct usb_serial_port *port;
652 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700653
654 dbg("%s", __FUNCTION__);
655
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200656
657 for (i = 0; i < serial->num_ports; i++) {
658 port = serial->port[i];
659 portdata = usb_get_serial_port_data(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700660
661 /* Do indat endpoints first */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200662 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 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700667
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200668 /* 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 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700674 }
675}
676
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700677static int option_send_setup(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700678{
679 struct usb_serial *serial = port->serial;
680 struct option_port_private *portdata;
681
682 dbg("%s", __FUNCTION__);
683
684 portdata = usb_get_serial_port_data(port);
685
686 if (port->tty) {
687 int val = 0;
688 if (portdata->dtr_state)
689 val |= 0x01;
690 if (portdata->rts_state)
691 val |= 0x02;
692
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700693 return usb_control_msg(serial->dev,
694 usb_rcvctrlpipe(serial->dev, 0),
695 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700696 }
697
698 return 0;
699}
700
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700701static int option_startup(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700702{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700703 int i, err;
704 struct usb_serial_port *port;
705 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700706
707 dbg("%s", __FUNCTION__);
708
709 /* Now setup per port private data */
710 for (i = 0; i < serial->num_ports; i++) {
711 port = serial->port[i];
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100712 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700713 if (!portdata) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700714 dbg("%s: kmalloc for option_port_private (%d) failed!.",
715 __FUNCTION__, i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700716 return (1);
717 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700718
719 usb_set_serial_port_data(port, portdata);
720
721 if (! port->interrupt_in_urb)
722 continue;
723 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
724 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700725 dbg("%s: submit irq_in urb failed %d",
726 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700727 }
728
729 option_setup_urbs(serial);
730
731 return (0);
732}
733
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700734static void option_shutdown(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700735{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700736 int i, j;
737 struct usb_serial_port *port;
738 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700739
740 dbg("%s", __FUNCTION__);
741
742 /* Stop reading/writing urbs */
743 for (i = 0; i < serial->num_ports; ++i) {
744 port = serial->port[i];
745 portdata = usb_get_serial_port_data(port);
746 for (j = 0; j < N_IN_URB; j++)
747 stop_urb(portdata->in_urbs[j]);
748 for (j = 0; j < N_OUT_URB; j++)
749 stop_urb(portdata->out_urbs[j]);
750 }
751
752 /* Now free them */
753 for (i = 0; i < serial->num_ports; ++i) {
754 port = serial->port[i];
755 portdata = usb_get_serial_port_data(port);
756
757 for (j = 0; j < N_IN_URB; j++) {
758 if (portdata->in_urbs[j]) {
759 usb_free_urb(portdata->in_urbs[j]);
760 portdata->in_urbs[j] = NULL;
761 }
762 }
763 for (j = 0; j < N_OUT_URB; j++) {
764 if (portdata->out_urbs[j]) {
765 usb_free_urb(portdata->out_urbs[j]);
766 portdata->out_urbs[j] = NULL;
767 }
768 }
769 }
770
771 /* Now free per port private data */
772 for (i = 0; i < serial->num_ports; i++) {
773 port = serial->port[i];
774 kfree(usb_get_serial_port_data(port));
775 }
776}
777
778MODULE_AUTHOR(DRIVER_AUTHOR);
779MODULE_DESCRIPTION(DRIVER_DESC);
780MODULE_VERSION(DRIVER_VERSION);
781MODULE_LICENSE("GPL");
782
Matthias Urlichsba460e42005-07-14 00:33:47 -0700783#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700784module_param(debug, bool, S_IRUGO | S_IWUSR);
785MODULE_PARM_DESC(debug, "Debug messages");
Matthias Urlichsba460e42005-07-14 00:33:47 -0700786#endif
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700787