blob: db92a7fb1f7cbbe9782aef280d46799c7e8d7490 [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 */
Greg Kroah-Hartmanfd978bf2007-02-21 12:53:17 -080070#define OPTION_VENDOR_ID 0x0AF0
71#define OPTION_PRODUCT_COLT 0x5000
72#define OPTION_PRODUCT_RICOLA 0x6000
73#define OPTION_PRODUCT_RICOLA_LIGHT 0x6100
74#define OPTION_PRODUCT_RICOLA_QUAD 0x6200
75#define OPTION_PRODUCT_RICOLA_QUAD_LIGHT 0x6300
76#define OPTION_PRODUCT_RICOLA_NDIS 0x6050
77#define OPTION_PRODUCT_RICOLA_NDIS_LIGHT 0x6150
78#define OPTION_PRODUCT_RICOLA_NDIS_QUAD 0x6250
79#define OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT 0x6350
80#define OPTION_PRODUCT_COBRA 0x6500
81#define OPTION_PRODUCT_COBRA_BUS 0x6501
82#define OPTION_PRODUCT_VIPER 0x6600
83#define OPTION_PRODUCT_VIPER_BUS 0x6601
84#define OPTION_PRODUCT_GT_MAX_READY 0x6701
85#define OPTION_PRODUCT_GT_MAX 0x6711
86#define OPTION_PRODUCT_FUJI_MODEM_LIGHT 0x6721
87#define OPTION_PRODUCT_FUJI_MODEM_GT 0x6741
88#define OPTION_PRODUCT_FUJI_MODEM_EX 0x6761
89#define OPTION_PRODUCT_FUJI_NETWORK_LIGHT 0x6731
90#define OPTION_PRODUCT_FUJI_NETWORK_GT 0x6751
91#define OPTION_PRODUCT_FUJI_NETWORK_EX 0x6771
92#define OPTION_PRODUCT_KOI_MODEM 0x6800
93#define OPTION_PRODUCT_KOI_NETWORK 0x6811
94#define OPTION_PRODUCT_SCORPION_MODEM 0x6901
95#define OPTION_PRODUCT_SCORPION_NETWORK 0x6911
96#define OPTION_PRODUCT_ETNA_MODEM 0x7001
97#define OPTION_PRODUCT_ETNA_NETWORK 0x7011
98#define OPTION_PRODUCT_ETNA_MODEM_LITE 0x7021
99#define OPTION_PRODUCT_ETNA_MODEM_GT 0x7041
100#define OPTION_PRODUCT_ETNA_MODEM_EX 0x7061
101#define OPTION_PRODUCT_ETNA_NETWORK_LITE 0x7031
102#define OPTION_PRODUCT_ETNA_NETWORK_GT 0x7051
103#define OPTION_PRODUCT_ETNA_NETWORK_EX 0x7071
104#define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100
105#define OPTION_PRODUCT_ETNA_KOI_NETWORK 0x7111
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700106
Greg Kroah-Hartmanfd978bf2007-02-21 12:53:17 -0800107#define HUAWEI_VENDOR_ID 0x12D1
108#define HUAWEI_PRODUCT_E600 0x1001
109#define HUAWEI_PRODUCT_E220 0x1003
110
111#define NOVATELWIRELESS_VENDOR_ID 0x1410
112#define NOVATELWIRELESS_PRODUCT_U740 0x1400
113
114#define ANYDATA_VENDOR_ID 0x16d5
115#define ANYDATA_PRODUCT_ID 0x6501
Matthias Urlichsba460e42005-07-14 00:33:47 -0700116
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700117static struct usb_device_id option_ids[] = {
Greg Kroah-Hartmanfd978bf2007-02-21 12:53:17 -0800118 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
119 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
120 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
121 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD) },
122 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD_LIGHT) },
123 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS) },
124 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_LIGHT) },
125 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD) },
126 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200127 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
Greg Kroah-Hartmanfd978bf2007-02-21 12:53:17 -0800128 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA_BUS) },
129 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER) },
130 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER_BUS) },
131 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX_READY) },
132 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX) },
133 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_LIGHT) },
134 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_GT) },
135 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_EX) },
136 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_LIGHT) },
137 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_GT) },
138 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_EX) },
139 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_MODEM) },
140 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_NETWORK) },
141 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_MODEM) },
142 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_NETWORK) },
143 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM) },
144 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK) },
145 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_LITE) },
146 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_GT) },
147 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_EX) },
148 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_LITE) },
149 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_GT) },
150 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_EX) },
151 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) },
152 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) },
Matthias Urlichsb6137382005-09-22 00:48:40 -0700153 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
Johann Wilhelmab195892006-12-02 07:25:31 +0100154 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200155 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
Matthias Urlichs31fcbb72006-07-12 08:35:29 +0200156 { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200157 { } /* Terminating entry */
158};
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700159MODULE_DEVICE_TABLE(usb, option_ids);
160
161static struct usb_driver option_driver = {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700162 .name = "option",
163 .probe = usb_serial_probe,
164 .disconnect = usb_serial_disconnect,
165 .id_table = option_ids,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800166 .no_dynamic_id = 1,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700167};
168
Uwe Zeisbergerc30fe7f2006-03-24 18:23:14 +0100169/* The card has three separate interfaces, which the serial driver
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700170 * recognizes separately, thus num_port=1.
171 */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200172
173static struct usb_serial_driver option_1port_device = {
174 .driver = {
175 .owner = THIS_MODULE,
Matthias Urlichs02b2ac52006-08-02 16:41:41 -0700176 .name = "option1",
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200177 },
178 .description = "GSM modem (1-port)",
Johannes Hölzld9b1b782006-12-17 21:50:24 +0100179 .usb_driver = &option_driver,
Greg Kroah-Hartmanb656b2c2007-02-21 12:53:17 -0800180 .id_table = option_ids,
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200181 .num_interrupt_in = NUM_DONT_CARE,
182 .num_bulk_in = NUM_DONT_CARE,
183 .num_bulk_out = NUM_DONT_CARE,
184 .num_ports = 1,
Matthias Urlichsba460e42005-07-14 00:33:47 -0700185 .open = option_open,
186 .close = option_close,
187 .write = option_write,
188 .write_room = option_write_room,
189 .chars_in_buffer = option_chars_in_buffer,
190 .throttle = option_rx_throttle,
191 .unthrottle = option_rx_unthrottle,
192 .ioctl = option_ioctl,
193 .set_termios = option_set_termios,
194 .break_ctl = option_break_ctl,
195 .tiocmget = option_tiocmget,
196 .tiocmset = option_tiocmset,
197 .attach = option_startup,
198 .shutdown = option_shutdown,
199 .read_int_callback = option_instat_callback,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700200};
201
Matthias Urlichsba460e42005-07-14 00:33:47 -0700202#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700203static int debug;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700204#else
205#define debug 0
206#endif
207
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700208/* per port private data */
209
Matthias Urlichsba460e42005-07-14 00:33:47 -0700210#define N_IN_URB 4
211#define N_OUT_URB 1
Matthias Urlichsb27c73d2005-09-22 00:49:33 -0700212#define IN_BUFLEN 4096
Matthias Urlichsba460e42005-07-14 00:33:47 -0700213#define OUT_BUFLEN 128
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700214
215struct option_port_private {
216 /* Input endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700217 struct urb *in_urbs[N_IN_URB];
218 char in_buffer[N_IN_URB][IN_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700219 /* Output endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700220 struct urb *out_urbs[N_OUT_URB];
221 char out_buffer[N_OUT_URB][OUT_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700222
223 /* Settings for the port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700224 int rts_state; /* Handshaking pins (outputs) */
225 int dtr_state;
226 int cts_state; /* Handshaking pins (inputs) */
227 int dsr_state;
228 int dcd_state;
229 int ri_state;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700230
Matthias Urlichsba460e42005-07-14 00:33:47 -0700231 unsigned long tx_start_time[N_OUT_URB];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700232};
233
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700234/* Functions used by new usb-serial code. */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700235static int __init option_init(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700236{
237 int retval;
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200238 retval = usb_serial_register(&option_1port_device);
239 if (retval)
240 goto failed_1port_device_register;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700241 retval = usb_register(&option_driver);
242 if (retval)
243 goto failed_driver_register;
244
245 info(DRIVER_DESC ": " DRIVER_VERSION);
246
247 return 0;
248
249failed_driver_register:
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200250 usb_serial_deregister (&option_1port_device);
251failed_1port_device_register:
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700252 return retval;
253}
254
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700255static void __exit option_exit(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700256{
257 usb_deregister (&option_driver);
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200258 usb_serial_deregister (&option_1port_device);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700259}
260
261module_init(option_init);
262module_exit(option_exit);
263
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700264static void option_rx_throttle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700265{
266 dbg("%s", __FUNCTION__);
267}
268
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700269static void option_rx_unthrottle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700270{
271 dbg("%s", __FUNCTION__);
272}
273
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700274static void option_break_ctl(struct usb_serial_port *port, int break_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700275{
276 /* Unfortunately, I don't know how to send a break */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700277 dbg("%s", __FUNCTION__);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700278}
279
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700280static void option_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -0800281 struct ktermios *old_termios)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700282{
283 dbg("%s", __FUNCTION__);
284
285 option_send_setup(port);
286}
287
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700288static int option_tiocmget(struct usb_serial_port *port, struct file *file)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700289{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700290 unsigned int value;
291 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700292
293 portdata = usb_get_serial_port_data(port);
294
295 value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
296 ((portdata->dtr_state) ? TIOCM_DTR : 0) |
297 ((portdata->cts_state) ? TIOCM_CTS : 0) |
298 ((portdata->dsr_state) ? TIOCM_DSR : 0) |
299 ((portdata->dcd_state) ? TIOCM_CAR : 0) |
300 ((portdata->ri_state) ? TIOCM_RNG : 0);
301
302 return value;
303}
304
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700305static int option_tiocmset(struct usb_serial_port *port, struct file *file,
306 unsigned int set, unsigned int clear)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700307{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700308 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700309
310 portdata = usb_get_serial_port_data(port);
311
312 if (set & TIOCM_RTS)
313 portdata->rts_state = 1;
314 if (set & TIOCM_DTR)
315 portdata->dtr_state = 1;
316
317 if (clear & TIOCM_RTS)
318 portdata->rts_state = 0;
319 if (clear & TIOCM_DTR)
320 portdata->dtr_state = 0;
321 return option_send_setup(port);
322}
323
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700324static int option_ioctl(struct usb_serial_port *port, struct file *file,
325 unsigned int cmd, unsigned long arg)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700326{
327 return -ENOIOCTLCMD;
328}
329
330/* Write */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700331static int option_write(struct usb_serial_port *port,
332 const unsigned char *buf, int count)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700333{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700334 struct option_port_private *portdata;
335 int i;
336 int left, todo;
337 struct urb *this_urb = NULL; /* spurious */
338 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700339
340 portdata = usb_get_serial_port_data(port);
341
342 dbg("%s: write (%d chars)", __FUNCTION__, count);
343
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700344 i = 0;
345 left = count;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700346 for (i=0; left > 0 && i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700347 todo = left;
348 if (todo > OUT_BUFLEN)
349 todo = OUT_BUFLEN;
350
Matthias Urlichsba460e42005-07-14 00:33:47 -0700351 this_urb = portdata->out_urbs[i];
352 if (this_urb->status == -EINPROGRESS) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700353 if (time_before(jiffies,
354 portdata->tx_start_time[i] + 10 * HZ))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700355 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700356 usb_unlink_urb(this_urb);
Matthias Urlichsba460e42005-07-14 00:33:47 -0700357 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700358 }
Matthias Urlichsba460e42005-07-14 00:33:47 -0700359 if (this_urb->status != 0)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700360 dbg("usb_write %p failed (err=%d)",
361 this_urb, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700362
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700363 dbg("%s: endpoint %d buf %d", __FUNCTION__,
364 usb_pipeendpoint(this_urb->pipe), i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700365
Matthias Urlichsba460e42005-07-14 00:33:47 -0700366 /* send the data */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700367 memcpy (this_urb->transfer_buffer, buf, todo);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700368 this_urb->transfer_buffer_length = todo;
369
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700370 this_urb->dev = port->serial->dev;
371 err = usb_submit_urb(this_urb, GFP_ATOMIC);
372 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700373 dbg("usb_submit_urb %p (write bulk) failed "
374 "(%d, has %d)", this_urb,
375 err, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700376 continue;
377 }
378 portdata->tx_start_time[i] = jiffies;
379 buf += todo;
380 left -= todo;
381 }
382
383 count -= left;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700384 dbg("%s: wrote (did %d)", __FUNCTION__, count);
385 return count;
386}
387
David Howells7d12e782006-10-05 14:55:46 +0100388static void option_indat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700389{
Alan Cox33f0f882006-01-09 20:54:13 -0800390 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700391 int endpoint;
392 struct usb_serial_port *port;
393 struct tty_struct *tty;
394 unsigned char *data = urb->transfer_buffer;
395
396 dbg("%s: %p", __FUNCTION__, urb);
397
398 endpoint = usb_pipeendpoint(urb->pipe);
399 port = (struct usb_serial_port *) urb->context;
400
401 if (urb->status) {
402 dbg("%s: nonzero status: %d on endpoint %02x.",
403 __FUNCTION__, urb->status, endpoint);
404 } else {
405 tty = port->tty;
406 if (urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -0800407 tty_buffer_request_room(tty, urb->actual_length);
408 tty_insert_flip_string(tty, data, urb->actual_length);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700409 tty_flip_buffer_push(tty);
410 } else {
411 dbg("%s: empty read urb received", __FUNCTION__);
412 }
413
414 /* Resubmit urb so we continue receiving */
415 if (port->open_count && urb->status != -ESHUTDOWN) {
416 err = usb_submit_urb(urb, GFP_ATOMIC);
417 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700418 printk(KERN_ERR "%s: resubmit read urb failed. "
419 "(%d)", __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700420 }
421 }
422 return;
423}
424
David Howells7d12e782006-10-05 14:55:46 +0100425static void option_outdat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700426{
427 struct usb_serial_port *port;
428
429 dbg("%s", __FUNCTION__);
430
431 port = (struct usb_serial_port *) urb->context;
432
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700433 usb_serial_port_softint(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700434}
435
David Howells7d12e782006-10-05 14:55:46 +0100436static void option_instat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700437{
438 int err;
439 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
440 struct option_port_private *portdata = usb_get_serial_port_data(port);
441 struct usb_serial *serial = port->serial;
442
443 dbg("%s", __FUNCTION__);
444 dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
445
446 if (urb->status == 0) {
447 struct usb_ctrlrequest *req_pkt =
448 (struct usb_ctrlrequest *)urb->transfer_buffer;
449
450 if (!req_pkt) {
451 dbg("%s: NULL req_pkt\n", __FUNCTION__);
452 return;
453 }
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700454 if ((req_pkt->bRequestType == 0xA1) &&
455 (req_pkt->bRequest == 0x20)) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700456 int old_dcd_state;
457 unsigned char signals = *((unsigned char *)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700458 urb->transfer_buffer +
459 sizeof(struct usb_ctrlrequest));
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700460
461 dbg("%s: signal x%x", __FUNCTION__, signals);
462
463 old_dcd_state = portdata->dcd_state;
464 portdata->cts_state = 1;
465 portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
466 portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
467 portdata->ri_state = ((signals & 0x08) ? 1 : 0);
468
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700469 if (port->tty && !C_CLOCAL(port->tty) &&
470 old_dcd_state && !portdata->dcd_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700471 tty_hangup(port->tty);
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700472 } else {
473 dbg("%s: type %x req %x", __FUNCTION__,
474 req_pkt->bRequestType,req_pkt->bRequest);
475 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700476 } else
477 dbg("%s: error %d", __FUNCTION__, urb->status);
478
479 /* Resubmit urb so we continue receiving IRQ data */
480 if (urb->status != -ESHUTDOWN) {
481 urb->dev = serial->dev;
482 err = usb_submit_urb(urb, GFP_ATOMIC);
483 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700484 dbg("%s: resubmit intr urb failed. (%d)",
485 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700486 }
487}
488
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700489static int option_write_room(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700490{
491 struct option_port_private *portdata;
492 int i;
493 int data_len = 0;
494 struct urb *this_urb;
495
496 portdata = usb_get_serial_port_data(port);
497
Matthias Urlichsba460e42005-07-14 00:33:47 -0700498 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700499 this_urb = portdata->out_urbs[i];
500 if (this_urb && this_urb->status != -EINPROGRESS)
501 data_len += OUT_BUFLEN;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700502 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700503
504 dbg("%s: %d", __FUNCTION__, data_len);
505 return data_len;
506}
507
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700508static int option_chars_in_buffer(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700509{
510 struct option_port_private *portdata;
511 int i;
512 int data_len = 0;
513 struct urb *this_urb;
514
515 portdata = usb_get_serial_port_data(port);
516
Matthias Urlichsba460e42005-07-14 00:33:47 -0700517 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700518 this_urb = portdata->out_urbs[i];
519 if (this_urb && this_urb->status == -EINPROGRESS)
520 data_len += this_urb->transfer_buffer_length;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700521 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700522 dbg("%s: %d", __FUNCTION__, data_len);
523 return data_len;
524}
525
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700526static int option_open(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700527{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700528 struct option_port_private *portdata;
529 struct usb_serial *serial = port->serial;
530 int i, err;
531 struct urb *urb;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700532
533 portdata = usb_get_serial_port_data(port);
534
535 dbg("%s", __FUNCTION__);
536
537 /* Set some sane defaults */
538 portdata->rts_state = 1;
539 portdata->dtr_state = 1;
540
541 /* Reset low level data toggle and start reading from endpoints */
542 for (i = 0; i < N_IN_URB; i++) {
543 urb = portdata->in_urbs[i];
544 if (! urb)
545 continue;
546 if (urb->dev != serial->dev) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700547 dbg("%s: dev %p != %p", __FUNCTION__,
548 urb->dev, serial->dev);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700549 continue;
550 }
551
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700552 /*
553 * make sure endpoint data toggle is synchronized with the
554 * device
555 */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700556 usb_clear_halt(urb->dev, urb->pipe);
557
558 err = usb_submit_urb(urb, GFP_KERNEL);
559 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700560 dbg("%s: submit urb %d failed (%d) %d",
561 __FUNCTION__, i, err,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700562 urb->transfer_buffer_length);
563 }
564 }
565
566 /* Reset low level data toggle on out endpoints */
567 for (i = 0; i < N_OUT_URB; i++) {
568 urb = portdata->out_urbs[i];
569 if (! urb)
570 continue;
571 urb->dev = serial->dev;
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700572 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
573 usb_pipeout(urb->pipe), 0); */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700574 }
575
576 port->tty->low_latency = 1;
577
578 option_send_setup(port);
579
580 return (0);
581}
582
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700583static inline void stop_urb(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700584{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -0400585 if (urb && urb->status == -EINPROGRESS)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700586 usb_kill_urb(urb);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700587}
588
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700589static void option_close(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700590{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700591 int i;
592 struct usb_serial *serial = port->serial;
593 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700594
595 dbg("%s", __FUNCTION__);
596 portdata = usb_get_serial_port_data(port);
597
598 portdata->rts_state = 0;
599 portdata->dtr_state = 0;
600
601 if (serial->dev) {
602 option_send_setup(port);
603
604 /* Stop reading/writing urbs */
605 for (i = 0; i < N_IN_URB; i++)
606 stop_urb(portdata->in_urbs[i]);
607 for (i = 0; i < N_OUT_URB; i++)
608 stop_urb(portdata->out_urbs[i]);
609 }
610 port->tty = NULL;
611}
612
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700613/* Helper functions used by option_setup_urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700614static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
615 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +0100616 void (*callback)(struct urb *))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700617{
618 struct urb *urb;
619
620 if (endpoint == -1)
621 return NULL; /* endpoint not needed */
622
623 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
624 if (urb == NULL) {
625 dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
626 return NULL;
627 }
628
629 /* Fill URB using supplied data. */
630 usb_fill_bulk_urb(urb, serial->dev,
631 usb_sndbulkpipe(serial->dev, endpoint) | dir,
632 buf, len, callback, ctx);
633
634 return urb;
635}
636
637/* Setup urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700638static void option_setup_urbs(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700639{
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200640 int i,j;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700641 struct usb_serial_port *port;
642 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700643
644 dbg("%s", __FUNCTION__);
645
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200646 for (i = 0; i < serial->num_ports; i++) {
647 port = serial->port[i];
648 portdata = usb_get_serial_port_data(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700649
650 /* Do indat endpoints first */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200651 for (j = 0; j < N_IN_URB; ++j) {
652 portdata->in_urbs[j] = option_setup_urb (serial,
653 port->bulk_in_endpointAddress, USB_DIR_IN, port,
654 portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
655 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700656
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200657 /* outdat endpoints */
658 for (j = 0; j < N_OUT_URB; ++j) {
659 portdata->out_urbs[j] = option_setup_urb (serial,
660 port->bulk_out_endpointAddress, USB_DIR_OUT, port,
661 portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
662 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700663 }
664}
665
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700666static int option_send_setup(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700667{
668 struct usb_serial *serial = port->serial;
669 struct option_port_private *portdata;
670
671 dbg("%s", __FUNCTION__);
672
Miguel Angel Alvarez8c152712006-12-14 19:49:35 +0100673 if (port->number != 0)
674 return 0;
675
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700676 portdata = usb_get_serial_port_data(port);
677
678 if (port->tty) {
679 int val = 0;
680 if (portdata->dtr_state)
681 val |= 0x01;
682 if (portdata->rts_state)
683 val |= 0x02;
684
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700685 return usb_control_msg(serial->dev,
686 usb_rcvctrlpipe(serial->dev, 0),
687 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700688 }
689
690 return 0;
691}
692
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700693static int option_startup(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700694{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700695 int i, err;
696 struct usb_serial_port *port;
697 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700698
699 dbg("%s", __FUNCTION__);
700
701 /* Now setup per port private data */
702 for (i = 0; i < serial->num_ports; i++) {
703 port = serial->port[i];
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100704 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700705 if (!portdata) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700706 dbg("%s: kmalloc for option_port_private (%d) failed!.",
707 __FUNCTION__, i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700708 return (1);
709 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700710
711 usb_set_serial_port_data(port, portdata);
712
713 if (! port->interrupt_in_urb)
714 continue;
715 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
716 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700717 dbg("%s: submit irq_in urb failed %d",
718 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700719 }
720
721 option_setup_urbs(serial);
722
723 return (0);
724}
725
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700726static void option_shutdown(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700727{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700728 int i, j;
729 struct usb_serial_port *port;
730 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700731
732 dbg("%s", __FUNCTION__);
733
734 /* Stop reading/writing urbs */
735 for (i = 0; i < serial->num_ports; ++i) {
736 port = serial->port[i];
737 portdata = usb_get_serial_port_data(port);
738 for (j = 0; j < N_IN_URB; j++)
739 stop_urb(portdata->in_urbs[j]);
740 for (j = 0; j < N_OUT_URB; j++)
741 stop_urb(portdata->out_urbs[j]);
742 }
743
744 /* Now free them */
745 for (i = 0; i < serial->num_ports; ++i) {
746 port = serial->port[i];
747 portdata = usb_get_serial_port_data(port);
748
749 for (j = 0; j < N_IN_URB; j++) {
750 if (portdata->in_urbs[j]) {
751 usb_free_urb(portdata->in_urbs[j]);
752 portdata->in_urbs[j] = NULL;
753 }
754 }
755 for (j = 0; j < N_OUT_URB; j++) {
756 if (portdata->out_urbs[j]) {
757 usb_free_urb(portdata->out_urbs[j]);
758 portdata->out_urbs[j] = NULL;
759 }
760 }
761 }
762
763 /* Now free per port private data */
764 for (i = 0; i < serial->num_ports; i++) {
765 port = serial->port[i];
766 kfree(usb_get_serial_port_data(port));
767 }
768}
769
770MODULE_AUTHOR(DRIVER_AUTHOR);
771MODULE_DESCRIPTION(DRIVER_DESC);
772MODULE_VERSION(DRIVER_VERSION);
773MODULE_LICENSE("GPL");
774
Matthias Urlichsba460e42005-07-14 00:33:47 -0700775#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700776module_param(debug, bool, S_IRUGO | S_IWUSR);
777MODULE_PARM_DESC(debug, "Debug messages");
Matthias Urlichsba460e42005-07-14 00:33:47 -0700778#endif
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700779