blob: 2846656d8358c88002290ac4fff7ca8bb9fcc4f5 [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
Greg Kroah-Hartmanfd978bf2007-02-21 12:53:17 -0800112
113#define ANYDATA_VENDOR_ID 0x16d5
114#define ANYDATA_PRODUCT_ID 0x6501
Matthias Urlichsba460e42005-07-14 00:33:47 -0700115
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700116static struct usb_device_id option_ids[] = {
Greg Kroah-Hartmanfd978bf2007-02-21 12:53:17 -0800117 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
118 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
119 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
120 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD) },
121 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD_LIGHT) },
122 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS) },
123 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_LIGHT) },
124 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD) },
125 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200126 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
Greg Kroah-Hartmanfd978bf2007-02-21 12:53:17 -0800127 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA_BUS) },
128 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER) },
129 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER_BUS) },
130 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX_READY) },
131 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX) },
132 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_LIGHT) },
133 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_GT) },
134 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_EX) },
135 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_LIGHT) },
136 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_GT) },
137 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_EX) },
138 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_MODEM) },
139 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_NETWORK) },
140 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_MODEM) },
141 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_NETWORK) },
142 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM) },
143 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK) },
144 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_LITE) },
145 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_GT) },
146 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_EX) },
147 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_LITE) },
148 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_GT) },
149 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_EX) },
150 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) },
151 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) },
Matthias Urlichsb6137382005-09-22 00:48:40 -0700152 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
Johann Wilhelmab195892006-12-02 07:25:31 +0100153 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
Greg Kroah-Hartman69806d52007-03-19 13:39:51 -0700154 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1100) }, /* Novatel Merlin XS620/S640 */
155 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1110) }, /* Novatel Merlin S620 */
156 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1120) }, /* Novatel Merlin EX720 */
157 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1130) }, /* Novatel Merlin S720 */
158 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1400) }, /* Novatel U730 */
159 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1410) }, /* Novatel U740 */
160 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1420) }, /* Novatel EU870 */
161 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1430) }, /* Novatel Merlin XU870 HSDPA/3G */
162 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1430) }, /* Novatel XU870 */
163 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2100) }, /* Novatel EV620 CDMA/EV-DO */
164 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2110) }, /* Novatel Merlin ES620 / Merlin ES720 / Ovation U720 */
165 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2130) }, /* Novatel Merlin ES620 SM Bus */
166 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2410) }, /* Novatel EU740 */
Matthias Urlichs31fcbb72006-07-12 08:35:29 +0200167 { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200168 { } /* Terminating entry */
169};
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700170MODULE_DEVICE_TABLE(usb, option_ids);
171
172static struct usb_driver option_driver = {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700173 .name = "option",
174 .probe = usb_serial_probe,
175 .disconnect = usb_serial_disconnect,
176 .id_table = option_ids,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800177 .no_dynamic_id = 1,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700178};
179
Uwe Zeisbergerc30fe7f2006-03-24 18:23:14 +0100180/* The card has three separate interfaces, which the serial driver
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700181 * recognizes separately, thus num_port=1.
182 */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200183
184static struct usb_serial_driver option_1port_device = {
185 .driver = {
186 .owner = THIS_MODULE,
Matthias Urlichs02b2ac52006-08-02 16:41:41 -0700187 .name = "option1",
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200188 },
189 .description = "GSM modem (1-port)",
Johannes Hölzld9b1b782006-12-17 21:50:24 +0100190 .usb_driver = &option_driver,
Greg Kroah-Hartmanb656b2c2007-02-21 12:53:17 -0800191 .id_table = option_ids,
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200192 .num_interrupt_in = NUM_DONT_CARE,
193 .num_bulk_in = NUM_DONT_CARE,
194 .num_bulk_out = NUM_DONT_CARE,
195 .num_ports = 1,
Matthias Urlichsba460e42005-07-14 00:33:47 -0700196 .open = option_open,
197 .close = option_close,
198 .write = option_write,
199 .write_room = option_write_room,
200 .chars_in_buffer = option_chars_in_buffer,
201 .throttle = option_rx_throttle,
202 .unthrottle = option_rx_unthrottle,
203 .ioctl = option_ioctl,
204 .set_termios = option_set_termios,
205 .break_ctl = option_break_ctl,
206 .tiocmget = option_tiocmget,
207 .tiocmset = option_tiocmset,
208 .attach = option_startup,
209 .shutdown = option_shutdown,
210 .read_int_callback = option_instat_callback,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700211};
212
Matthias Urlichsba460e42005-07-14 00:33:47 -0700213#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700214static int debug;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700215#else
216#define debug 0
217#endif
218
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700219/* per port private data */
220
Matthias Urlichsba460e42005-07-14 00:33:47 -0700221#define N_IN_URB 4
222#define N_OUT_URB 1
Matthias Urlichsb27c73d2005-09-22 00:49:33 -0700223#define IN_BUFLEN 4096
Matthias Urlichsba460e42005-07-14 00:33:47 -0700224#define OUT_BUFLEN 128
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700225
226struct option_port_private {
227 /* Input endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700228 struct urb *in_urbs[N_IN_URB];
229 char in_buffer[N_IN_URB][IN_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700230 /* Output endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700231 struct urb *out_urbs[N_OUT_URB];
232 char out_buffer[N_OUT_URB][OUT_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700233
234 /* Settings for the port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700235 int rts_state; /* Handshaking pins (outputs) */
236 int dtr_state;
237 int cts_state; /* Handshaking pins (inputs) */
238 int dsr_state;
239 int dcd_state;
240 int ri_state;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700241
Matthias Urlichsba460e42005-07-14 00:33:47 -0700242 unsigned long tx_start_time[N_OUT_URB];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700243};
244
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700245/* Functions used by new usb-serial code. */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700246static int __init option_init(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700247{
248 int retval;
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200249 retval = usb_serial_register(&option_1port_device);
250 if (retval)
251 goto failed_1port_device_register;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700252 retval = usb_register(&option_driver);
253 if (retval)
254 goto failed_driver_register;
255
256 info(DRIVER_DESC ": " DRIVER_VERSION);
257
258 return 0;
259
260failed_driver_register:
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200261 usb_serial_deregister (&option_1port_device);
262failed_1port_device_register:
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700263 return retval;
264}
265
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700266static void __exit option_exit(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700267{
268 usb_deregister (&option_driver);
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200269 usb_serial_deregister (&option_1port_device);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700270}
271
272module_init(option_init);
273module_exit(option_exit);
274
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700275static void option_rx_throttle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700276{
277 dbg("%s", __FUNCTION__);
278}
279
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700280static void option_rx_unthrottle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700281{
282 dbg("%s", __FUNCTION__);
283}
284
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700285static void option_break_ctl(struct usb_serial_port *port, int break_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700286{
287 /* Unfortunately, I don't know how to send a break */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700288 dbg("%s", __FUNCTION__);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700289}
290
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700291static void option_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -0800292 struct ktermios *old_termios)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700293{
294 dbg("%s", __FUNCTION__);
295
296 option_send_setup(port);
297}
298
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700299static int option_tiocmget(struct usb_serial_port *port, struct file *file)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700300{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700301 unsigned int value;
302 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700303
304 portdata = usb_get_serial_port_data(port);
305
306 value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
307 ((portdata->dtr_state) ? TIOCM_DTR : 0) |
308 ((portdata->cts_state) ? TIOCM_CTS : 0) |
309 ((portdata->dsr_state) ? TIOCM_DSR : 0) |
310 ((portdata->dcd_state) ? TIOCM_CAR : 0) |
311 ((portdata->ri_state) ? TIOCM_RNG : 0);
312
313 return value;
314}
315
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700316static int option_tiocmset(struct usb_serial_port *port, struct file *file,
317 unsigned int set, unsigned int clear)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700318{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700319 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700320
321 portdata = usb_get_serial_port_data(port);
322
323 if (set & TIOCM_RTS)
324 portdata->rts_state = 1;
325 if (set & TIOCM_DTR)
326 portdata->dtr_state = 1;
327
328 if (clear & TIOCM_RTS)
329 portdata->rts_state = 0;
330 if (clear & TIOCM_DTR)
331 portdata->dtr_state = 0;
332 return option_send_setup(port);
333}
334
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700335static int option_ioctl(struct usb_serial_port *port, struct file *file,
336 unsigned int cmd, unsigned long arg)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700337{
338 return -ENOIOCTLCMD;
339}
340
341/* Write */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700342static int option_write(struct usb_serial_port *port,
343 const unsigned char *buf, int count)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700344{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700345 struct option_port_private *portdata;
346 int i;
347 int left, todo;
348 struct urb *this_urb = NULL; /* spurious */
349 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700350
351 portdata = usb_get_serial_port_data(port);
352
353 dbg("%s: write (%d chars)", __FUNCTION__, count);
354
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700355 i = 0;
356 left = count;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700357 for (i=0; left > 0 && i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700358 todo = left;
359 if (todo > OUT_BUFLEN)
360 todo = OUT_BUFLEN;
361
Matthias Urlichsba460e42005-07-14 00:33:47 -0700362 this_urb = portdata->out_urbs[i];
363 if (this_urb->status == -EINPROGRESS) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700364 if (time_before(jiffies,
365 portdata->tx_start_time[i] + 10 * HZ))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700366 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700367 usb_unlink_urb(this_urb);
Matthias Urlichsba460e42005-07-14 00:33:47 -0700368 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700369 }
Matthias Urlichsba460e42005-07-14 00:33:47 -0700370 if (this_urb->status != 0)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700371 dbg("usb_write %p failed (err=%d)",
372 this_urb, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700373
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700374 dbg("%s: endpoint %d buf %d", __FUNCTION__,
375 usb_pipeendpoint(this_urb->pipe), i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700376
Matthias Urlichsba460e42005-07-14 00:33:47 -0700377 /* send the data */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700378 memcpy (this_urb->transfer_buffer, buf, todo);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700379 this_urb->transfer_buffer_length = todo;
380
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700381 this_urb->dev = port->serial->dev;
382 err = usb_submit_urb(this_urb, GFP_ATOMIC);
383 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700384 dbg("usb_submit_urb %p (write bulk) failed "
385 "(%d, has %d)", this_urb,
386 err, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700387 continue;
388 }
389 portdata->tx_start_time[i] = jiffies;
390 buf += todo;
391 left -= todo;
392 }
393
394 count -= left;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700395 dbg("%s: wrote (did %d)", __FUNCTION__, count);
396 return count;
397}
398
David Howells7d12e782006-10-05 14:55:46 +0100399static void option_indat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700400{
Alan Cox33f0f882006-01-09 20:54:13 -0800401 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700402 int endpoint;
403 struct usb_serial_port *port;
404 struct tty_struct *tty;
405 unsigned char *data = urb->transfer_buffer;
406
407 dbg("%s: %p", __FUNCTION__, urb);
408
409 endpoint = usb_pipeendpoint(urb->pipe);
410 port = (struct usb_serial_port *) urb->context;
411
412 if (urb->status) {
413 dbg("%s: nonzero status: %d on endpoint %02x.",
414 __FUNCTION__, urb->status, endpoint);
415 } else {
416 tty = port->tty;
417 if (urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -0800418 tty_buffer_request_room(tty, urb->actual_length);
419 tty_insert_flip_string(tty, data, urb->actual_length);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700420 tty_flip_buffer_push(tty);
421 } else {
422 dbg("%s: empty read urb received", __FUNCTION__);
423 }
424
425 /* Resubmit urb so we continue receiving */
426 if (port->open_count && urb->status != -ESHUTDOWN) {
427 err = usb_submit_urb(urb, GFP_ATOMIC);
428 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700429 printk(KERN_ERR "%s: resubmit read urb failed. "
430 "(%d)", __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700431 }
432 }
433 return;
434}
435
David Howells7d12e782006-10-05 14:55:46 +0100436static void option_outdat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700437{
438 struct usb_serial_port *port;
439
440 dbg("%s", __FUNCTION__);
441
442 port = (struct usb_serial_port *) urb->context;
443
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700444 usb_serial_port_softint(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700445}
446
David Howells7d12e782006-10-05 14:55:46 +0100447static void option_instat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700448{
449 int err;
450 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
451 struct option_port_private *portdata = usb_get_serial_port_data(port);
452 struct usb_serial *serial = port->serial;
453
454 dbg("%s", __FUNCTION__);
455 dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
456
457 if (urb->status == 0) {
458 struct usb_ctrlrequest *req_pkt =
459 (struct usb_ctrlrequest *)urb->transfer_buffer;
460
461 if (!req_pkt) {
462 dbg("%s: NULL req_pkt\n", __FUNCTION__);
463 return;
464 }
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700465 if ((req_pkt->bRequestType == 0xA1) &&
466 (req_pkt->bRequest == 0x20)) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700467 int old_dcd_state;
468 unsigned char signals = *((unsigned char *)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700469 urb->transfer_buffer +
470 sizeof(struct usb_ctrlrequest));
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700471
472 dbg("%s: signal x%x", __FUNCTION__, signals);
473
474 old_dcd_state = portdata->dcd_state;
475 portdata->cts_state = 1;
476 portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
477 portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
478 portdata->ri_state = ((signals & 0x08) ? 1 : 0);
479
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700480 if (port->tty && !C_CLOCAL(port->tty) &&
481 old_dcd_state && !portdata->dcd_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700482 tty_hangup(port->tty);
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700483 } else {
484 dbg("%s: type %x req %x", __FUNCTION__,
485 req_pkt->bRequestType,req_pkt->bRequest);
486 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700487 } else
488 dbg("%s: error %d", __FUNCTION__, urb->status);
489
490 /* Resubmit urb so we continue receiving IRQ data */
491 if (urb->status != -ESHUTDOWN) {
492 urb->dev = serial->dev;
493 err = usb_submit_urb(urb, GFP_ATOMIC);
494 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700495 dbg("%s: resubmit intr urb failed. (%d)",
496 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700497 }
498}
499
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700500static int option_write_room(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700501{
502 struct option_port_private *portdata;
503 int i;
504 int data_len = 0;
505 struct urb *this_urb;
506
507 portdata = usb_get_serial_port_data(port);
508
Matthias Urlichsba460e42005-07-14 00:33:47 -0700509 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700510 this_urb = portdata->out_urbs[i];
511 if (this_urb && this_urb->status != -EINPROGRESS)
512 data_len += OUT_BUFLEN;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700513 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700514
515 dbg("%s: %d", __FUNCTION__, data_len);
516 return data_len;
517}
518
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700519static int option_chars_in_buffer(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700520{
521 struct option_port_private *portdata;
522 int i;
523 int data_len = 0;
524 struct urb *this_urb;
525
526 portdata = usb_get_serial_port_data(port);
527
Matthias Urlichsba460e42005-07-14 00:33:47 -0700528 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700529 this_urb = portdata->out_urbs[i];
530 if (this_urb && this_urb->status == -EINPROGRESS)
531 data_len += this_urb->transfer_buffer_length;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700532 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700533 dbg("%s: %d", __FUNCTION__, data_len);
534 return data_len;
535}
536
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700537static int option_open(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700538{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700539 struct option_port_private *portdata;
540 struct usb_serial *serial = port->serial;
541 int i, err;
542 struct urb *urb;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700543
544 portdata = usb_get_serial_port_data(port);
545
546 dbg("%s", __FUNCTION__);
547
548 /* Set some sane defaults */
549 portdata->rts_state = 1;
550 portdata->dtr_state = 1;
551
552 /* Reset low level data toggle and start reading from endpoints */
553 for (i = 0; i < N_IN_URB; i++) {
554 urb = portdata->in_urbs[i];
555 if (! urb)
556 continue;
557 if (urb->dev != serial->dev) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700558 dbg("%s: dev %p != %p", __FUNCTION__,
559 urb->dev, serial->dev);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700560 continue;
561 }
562
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700563 /*
564 * make sure endpoint data toggle is synchronized with the
565 * device
566 */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700567 usb_clear_halt(urb->dev, urb->pipe);
568
569 err = usb_submit_urb(urb, GFP_KERNEL);
570 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700571 dbg("%s: submit urb %d failed (%d) %d",
572 __FUNCTION__, i, err,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700573 urb->transfer_buffer_length);
574 }
575 }
576
577 /* Reset low level data toggle on out endpoints */
578 for (i = 0; i < N_OUT_URB; i++) {
579 urb = portdata->out_urbs[i];
580 if (! urb)
581 continue;
582 urb->dev = serial->dev;
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700583 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
584 usb_pipeout(urb->pipe), 0); */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700585 }
586
587 port->tty->low_latency = 1;
588
589 option_send_setup(port);
590
591 return (0);
592}
593
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700594static void option_close(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700595{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700596 int i;
597 struct usb_serial *serial = port->serial;
598 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700599
600 dbg("%s", __FUNCTION__);
601 portdata = usb_get_serial_port_data(port);
602
603 portdata->rts_state = 0;
604 portdata->dtr_state = 0;
605
606 if (serial->dev) {
607 option_send_setup(port);
608
609 /* Stop reading/writing urbs */
610 for (i = 0; i < N_IN_URB; i++)
Oliver Neukum7d28e742007-03-20 13:41:21 +0100611 usb_kill_urb(portdata->in_urbs[i]);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700612 for (i = 0; i < N_OUT_URB; i++)
Oliver Neukum7d28e742007-03-20 13:41:21 +0100613 usb_kill_urb(portdata->out_urbs[i]);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700614 }
615 port->tty = NULL;
616}
617
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700618/* Helper functions used by option_setup_urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700619static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
620 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +0100621 void (*callback)(struct urb *))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700622{
623 struct urb *urb;
624
625 if (endpoint == -1)
626 return NULL; /* endpoint not needed */
627
628 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
629 if (urb == NULL) {
630 dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
631 return NULL;
632 }
633
634 /* Fill URB using supplied data. */
635 usb_fill_bulk_urb(urb, serial->dev,
636 usb_sndbulkpipe(serial->dev, endpoint) | dir,
637 buf, len, callback, ctx);
638
639 return urb;
640}
641
642/* Setup urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700643static void option_setup_urbs(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700644{
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200645 int i,j;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700646 struct usb_serial_port *port;
647 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700648
649 dbg("%s", __FUNCTION__);
650
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200651 for (i = 0; i < serial->num_ports; i++) {
652 port = serial->port[i];
653 portdata = usb_get_serial_port_data(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700654
655 /* Do indat endpoints first */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200656 for (j = 0; j < N_IN_URB; ++j) {
657 portdata->in_urbs[j] = option_setup_urb (serial,
658 port->bulk_in_endpointAddress, USB_DIR_IN, port,
659 portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
660 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700661
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200662 /* outdat endpoints */
663 for (j = 0; j < N_OUT_URB; ++j) {
664 portdata->out_urbs[j] = option_setup_urb (serial,
665 port->bulk_out_endpointAddress, USB_DIR_OUT, port,
666 portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
667 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700668 }
669}
670
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700671static int option_send_setup(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700672{
673 struct usb_serial *serial = port->serial;
674 struct option_port_private *portdata;
675
676 dbg("%s", __FUNCTION__);
677
Miguel Angel Alvarez8c152712006-12-14 19:49:35 +0100678 if (port->number != 0)
679 return 0;
680
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700681 portdata = usb_get_serial_port_data(port);
682
683 if (port->tty) {
684 int val = 0;
685 if (portdata->dtr_state)
686 val |= 0x01;
687 if (portdata->rts_state)
688 val |= 0x02;
689
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700690 return usb_control_msg(serial->dev,
691 usb_rcvctrlpipe(serial->dev, 0),
692 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700693 }
694
695 return 0;
696}
697
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700698static int option_startup(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700699{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700700 int i, err;
701 struct usb_serial_port *port;
702 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700703
704 dbg("%s", __FUNCTION__);
705
706 /* Now setup per port private data */
707 for (i = 0; i < serial->num_ports; i++) {
708 port = serial->port[i];
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100709 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700710 if (!portdata) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700711 dbg("%s: kmalloc for option_port_private (%d) failed!.",
712 __FUNCTION__, i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700713 return (1);
714 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700715
716 usb_set_serial_port_data(port, portdata);
717
718 if (! port->interrupt_in_urb)
719 continue;
720 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
721 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700722 dbg("%s: submit irq_in urb failed %d",
723 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700724 }
725
726 option_setup_urbs(serial);
727
728 return (0);
729}
730
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700731static void option_shutdown(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700732{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700733 int i, j;
734 struct usb_serial_port *port;
735 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700736
737 dbg("%s", __FUNCTION__);
738
739 /* Stop reading/writing urbs */
740 for (i = 0; i < serial->num_ports; ++i) {
741 port = serial->port[i];
742 portdata = usb_get_serial_port_data(port);
743 for (j = 0; j < N_IN_URB; j++)
Oliver Neukum7d28e742007-03-20 13:41:21 +0100744 usb_kill_urb(portdata->in_urbs[j]);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700745 for (j = 0; j < N_OUT_URB; j++)
Oliver Neukum7d28e742007-03-20 13:41:21 +0100746 usb_kill_urb(portdata->out_urbs[j]);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700747 }
748
749 /* Now free them */
750 for (i = 0; i < serial->num_ports; ++i) {
751 port = serial->port[i];
752 portdata = usb_get_serial_port_data(port);
753
754 for (j = 0; j < N_IN_URB; j++) {
755 if (portdata->in_urbs[j]) {
756 usb_free_urb(portdata->in_urbs[j]);
757 portdata->in_urbs[j] = NULL;
758 }
759 }
760 for (j = 0; j < N_OUT_URB; j++) {
761 if (portdata->out_urbs[j]) {
762 usb_free_urb(portdata->out_urbs[j]);
763 portdata->out_urbs[j] = NULL;
764 }
765 }
766 }
767
768 /* Now free per port private data */
769 for (i = 0; i < serial->num_ports; i++) {
770 port = serial->port[i];
771 kfree(usb_get_serial_port_data(port));
772 }
773}
774
775MODULE_AUTHOR(DRIVER_AUTHOR);
776MODULE_DESCRIPTION(DRIVER_DESC);
777MODULE_VERSION(DRIVER_VERSION);
778MODULE_LICENSE("GPL");
779
Matthias Urlichsba460e42005-07-14 00:33:47 -0700780#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700781module_param(debug, bool, S_IRUGO | S_IWUSR);
782MODULE_PARM_DESC(debug, "Debug messages");
Matthias Urlichsba460e42005-07-14 00:33:47 -0700783#endif
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700784