blob: 43be23a24575f4101dae9e9168c0afa37a7b8972 [file] [log] [blame]
Matthias Urlichs58cfe912005-05-23 17:00:48 -07001/*
Matthias Urlichs14f76cc2006-06-02 11:48:56 +02002 USB Driver for GSM modems
Matthias Urlichs58cfe912005-05-23 17:00:48 -07003
4 Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de>
5
6 This driver is free software; you can redistribute it and/or modify
7 it under the terms of Version 2 of the GNU General Public License as
8 published by the Free Software Foundation.
9
10 Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
11
Matthias Urlichsb3fdab52006-08-02 16:41:41 -070012 History: see the git log.
Matthias Urlichsba460e42005-07-14 00:33:47 -070013
14 Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
15
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020016 This driver exists because the "normal" serial driver doesn't work too well
17 with GSM modems. Issues:
18 - data loss -- one single Receive URB is not nearly enough
Matthias Urlichs7c1c2f72006-07-20 04:56:00 +020019 - nonstandard flow (Option devices) control
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020020 - controlling the baud rate doesn't make sense
21
22 This driver is named "option" because the most common device it's
23 used for is a PC-Card (with an internal OHCI-USB interface, behind
24 which the GSM interface sits), made by Option Inc.
25
26 Some of the "one port" devices actually exhibit multiple USB instances
27 on the USB bus. This is not a bug, these ports are used for different
28 device features.
Matthias Urlichs58cfe912005-05-23 17:00:48 -070029*/
Matthias Urlichsba460e42005-07-14 00:33:47 -070030
Matthias Urlichse37de9e2006-07-06 13:12:53 +020031#define DRIVER_VERSION "v0.7.1"
Matthias Urlichs58cfe912005-05-23 17:00:48 -070032#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020033#define DRIVER_DESC "USB Driver for GSM modems"
Matthias Urlichs58cfe912005-05-23 17:00:48 -070034
Matthias Urlichs58cfe912005-05-23 17:00:48 -070035#include <linux/kernel.h>
36#include <linux/jiffies.h>
37#include <linux/errno.h>
38#include <linux/tty.h>
39#include <linux/tty_flip.h>
40#include <linux/module.h>
41#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070042#include <linux/usb/serial.h>
Matthias Urlichs58cfe912005-05-23 17:00:48 -070043
44/* Function prototypes */
Andrew Morton7bb75ae2005-07-27 01:08:30 -070045static int option_open(struct usb_serial_port *port, struct file *filp);
46static void option_close(struct usb_serial_port *port, struct file *filp);
47static int option_startup(struct usb_serial *serial);
48static void option_shutdown(struct usb_serial *serial);
49static void option_rx_throttle(struct usb_serial_port *port);
50static void option_rx_unthrottle(struct usb_serial_port *port);
51static int option_write_room(struct usb_serial_port *port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070052
David Howells7d12e782006-10-05 14:55:46 +010053static void option_instat_callback(struct urb *urb);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070054
Andrew Morton7bb75ae2005-07-27 01:08:30 -070055static int option_write(struct usb_serial_port *port,
56 const unsigned char *buf, int count);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070057
Andrew Morton7bb75ae2005-07-27 01:08:30 -070058static int option_chars_in_buffer(struct usb_serial_port *port);
59static int option_ioctl(struct usb_serial_port *port, struct file *file,
60 unsigned int cmd, unsigned long arg);
61static void option_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -080062 struct ktermios *old);
Andrew Morton7bb75ae2005-07-27 01:08:30 -070063static void option_break_ctl(struct usb_serial_port *port, int break_state);
64static int option_tiocmget(struct usb_serial_port *port, struct file *file);
65static int option_tiocmset(struct usb_serial_port *port, struct file *file,
66 unsigned int set, unsigned int clear);
67static int option_send_setup(struct usb_serial_port *port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070068
69/* Vendor and product IDs */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020070#define OPTION_VENDOR_ID 0x0AF0
71#define HUAWEI_VENDOR_ID 0x12D1
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020072#define NOVATELWIRELESS_VENDOR_ID 0x1410
Matthias Urlichs31fcbb72006-07-12 08:35:29 +020073#define ANYDATA_VENDOR_ID 0x16d5
Matthias Urlichs58cfe912005-05-23 17:00:48 -070074
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020075#define OPTION_PRODUCT_OLD 0x5000
76#define OPTION_PRODUCT_FUSION 0x6000
77#define OPTION_PRODUCT_FUSION2 0x6300
78#define OPTION_PRODUCT_COBRA 0x6500
Matthias Urlichse37de9e2006-07-06 13:12:53 +020079#define OPTION_PRODUCT_COBRA2 0x6600
garrett_damore@tadpole.com53e8f842007-01-12 17:10:28 -080080#define OPTION_PRODUCT_GTMAX36 0x6701
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020081#define HUAWEI_PRODUCT_E600 0x1001
Johann Wilhelmab195892006-12-02 07:25:31 +010082#define HUAWEI_PRODUCT_E220 0x1003
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020083#define NOVATELWIRELESS_PRODUCT_U740 0x1400
Matthias Urlichs31fcbb72006-07-12 08:35:29 +020084#define ANYDATA_PRODUCT_ID 0x6501
Matthias Urlichsba460e42005-07-14 00:33:47 -070085
Matthias Urlichs58cfe912005-05-23 17:00:48 -070086static struct usb_device_id option_ids[] = {
87 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
Matthias Urlichsba460e42005-07-14 00:33:47 -070088 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
89 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020090 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
Matthias Urlichse37de9e2006-07-06 13:12:53 +020091 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
garrett_damore@tadpole.com53e8f842007-01-12 17:10:28 -080092 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
Matthias Urlichsb6137382005-09-22 00:48:40 -070093 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
Johann Wilhelmab195892006-12-02 07:25:31 +010094 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020095 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
Matthias Urlichs31fcbb72006-07-12 08:35:29 +020096 { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +020097 { } /* Terminating entry */
98};
Matthias Urlichs58cfe912005-05-23 17:00:48 -070099MODULE_DEVICE_TABLE(usb, option_ids);
100
101static struct usb_driver option_driver = {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700102 .name = "option",
103 .probe = usb_serial_probe,
104 .disconnect = usb_serial_disconnect,
105 .id_table = option_ids,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800106 .no_dynamic_id = 1,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700107};
108
Uwe Zeisbergerc30fe7f2006-03-24 18:23:14 +0100109/* The card has three separate interfaces, which the serial driver
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700110 * recognizes separately, thus num_port=1.
111 */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200112
113static struct usb_serial_driver option_1port_device = {
114 .driver = {
115 .owner = THIS_MODULE,
Matthias Urlichs02b2ac52006-08-02 16:41:41 -0700116 .name = "option1",
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200117 },
118 .description = "GSM modem (1-port)",
Johannes Hölzld9b1b782006-12-17 21:50:24 +0100119 .usb_driver = &option_driver,
Greg Kroah-Hartmanb656b2c2007-02-21 12:53:17 -0800120 .id_table = option_ids,
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200121 .num_interrupt_in = NUM_DONT_CARE,
122 .num_bulk_in = NUM_DONT_CARE,
123 .num_bulk_out = NUM_DONT_CARE,
124 .num_ports = 1,
Matthias Urlichsba460e42005-07-14 00:33:47 -0700125 .open = option_open,
126 .close = option_close,
127 .write = option_write,
128 .write_room = option_write_room,
129 .chars_in_buffer = option_chars_in_buffer,
130 .throttle = option_rx_throttle,
131 .unthrottle = option_rx_unthrottle,
132 .ioctl = option_ioctl,
133 .set_termios = option_set_termios,
134 .break_ctl = option_break_ctl,
135 .tiocmget = option_tiocmget,
136 .tiocmset = option_tiocmset,
137 .attach = option_startup,
138 .shutdown = option_shutdown,
139 .read_int_callback = option_instat_callback,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700140};
141
Matthias Urlichsba460e42005-07-14 00:33:47 -0700142#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700143static int debug;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700144#else
145#define debug 0
146#endif
147
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700148/* per port private data */
149
Matthias Urlichsba460e42005-07-14 00:33:47 -0700150#define N_IN_URB 4
151#define N_OUT_URB 1
Matthias Urlichsb27c73d2005-09-22 00:49:33 -0700152#define IN_BUFLEN 4096
Matthias Urlichsba460e42005-07-14 00:33:47 -0700153#define OUT_BUFLEN 128
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700154
155struct option_port_private {
156 /* Input endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700157 struct urb *in_urbs[N_IN_URB];
158 char in_buffer[N_IN_URB][IN_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700159 /* Output endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700160 struct urb *out_urbs[N_OUT_URB];
161 char out_buffer[N_OUT_URB][OUT_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700162
163 /* Settings for the port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700164 int rts_state; /* Handshaking pins (outputs) */
165 int dtr_state;
166 int cts_state; /* Handshaking pins (inputs) */
167 int dsr_state;
168 int dcd_state;
169 int ri_state;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700170
Matthias Urlichsba460e42005-07-14 00:33:47 -0700171 unsigned long tx_start_time[N_OUT_URB];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700172};
173
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700174/* Functions used by new usb-serial code. */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700175static int __init option_init(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700176{
177 int retval;
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200178 retval = usb_serial_register(&option_1port_device);
179 if (retval)
180 goto failed_1port_device_register;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700181 retval = usb_register(&option_driver);
182 if (retval)
183 goto failed_driver_register;
184
185 info(DRIVER_DESC ": " DRIVER_VERSION);
186
187 return 0;
188
189failed_driver_register:
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200190 usb_serial_deregister (&option_1port_device);
191failed_1port_device_register:
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700192 return retval;
193}
194
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700195static void __exit option_exit(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700196{
197 usb_deregister (&option_driver);
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200198 usb_serial_deregister (&option_1port_device);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700199}
200
201module_init(option_init);
202module_exit(option_exit);
203
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700204static void option_rx_throttle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700205{
206 dbg("%s", __FUNCTION__);
207}
208
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700209static void option_rx_unthrottle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700210{
211 dbg("%s", __FUNCTION__);
212}
213
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700214static void option_break_ctl(struct usb_serial_port *port, int break_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700215{
216 /* Unfortunately, I don't know how to send a break */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700217 dbg("%s", __FUNCTION__);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700218}
219
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700220static void option_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -0800221 struct ktermios *old_termios)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700222{
223 dbg("%s", __FUNCTION__);
224
225 option_send_setup(port);
226}
227
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700228static int option_tiocmget(struct usb_serial_port *port, struct file *file)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700229{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700230 unsigned int value;
231 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700232
233 portdata = usb_get_serial_port_data(port);
234
235 value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
236 ((portdata->dtr_state) ? TIOCM_DTR : 0) |
237 ((portdata->cts_state) ? TIOCM_CTS : 0) |
238 ((portdata->dsr_state) ? TIOCM_DSR : 0) |
239 ((portdata->dcd_state) ? TIOCM_CAR : 0) |
240 ((portdata->ri_state) ? TIOCM_RNG : 0);
241
242 return value;
243}
244
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700245static int option_tiocmset(struct usb_serial_port *port, struct file *file,
246 unsigned int set, unsigned int clear)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700247{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700248 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700249
250 portdata = usb_get_serial_port_data(port);
251
252 if (set & TIOCM_RTS)
253 portdata->rts_state = 1;
254 if (set & TIOCM_DTR)
255 portdata->dtr_state = 1;
256
257 if (clear & TIOCM_RTS)
258 portdata->rts_state = 0;
259 if (clear & TIOCM_DTR)
260 portdata->dtr_state = 0;
261 return option_send_setup(port);
262}
263
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700264static int option_ioctl(struct usb_serial_port *port, struct file *file,
265 unsigned int cmd, unsigned long arg)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700266{
267 return -ENOIOCTLCMD;
268}
269
270/* Write */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700271static int option_write(struct usb_serial_port *port,
272 const unsigned char *buf, int count)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700273{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700274 struct option_port_private *portdata;
275 int i;
276 int left, todo;
277 struct urb *this_urb = NULL; /* spurious */
278 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700279
280 portdata = usb_get_serial_port_data(port);
281
282 dbg("%s: write (%d chars)", __FUNCTION__, count);
283
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700284 i = 0;
285 left = count;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700286 for (i=0; left > 0 && i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700287 todo = left;
288 if (todo > OUT_BUFLEN)
289 todo = OUT_BUFLEN;
290
Matthias Urlichsba460e42005-07-14 00:33:47 -0700291 this_urb = portdata->out_urbs[i];
292 if (this_urb->status == -EINPROGRESS) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700293 if (time_before(jiffies,
294 portdata->tx_start_time[i] + 10 * HZ))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700295 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700296 usb_unlink_urb(this_urb);
Matthias Urlichsba460e42005-07-14 00:33:47 -0700297 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700298 }
Matthias Urlichsba460e42005-07-14 00:33:47 -0700299 if (this_urb->status != 0)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700300 dbg("usb_write %p failed (err=%d)",
301 this_urb, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700302
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700303 dbg("%s: endpoint %d buf %d", __FUNCTION__,
304 usb_pipeendpoint(this_urb->pipe), i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700305
Matthias Urlichsba460e42005-07-14 00:33:47 -0700306 /* send the data */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700307 memcpy (this_urb->transfer_buffer, buf, todo);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700308 this_urb->transfer_buffer_length = todo;
309
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700310 this_urb->dev = port->serial->dev;
311 err = usb_submit_urb(this_urb, GFP_ATOMIC);
312 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700313 dbg("usb_submit_urb %p (write bulk) failed "
314 "(%d, has %d)", this_urb,
315 err, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700316 continue;
317 }
318 portdata->tx_start_time[i] = jiffies;
319 buf += todo;
320 left -= todo;
321 }
322
323 count -= left;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700324 dbg("%s: wrote (did %d)", __FUNCTION__, count);
325 return count;
326}
327
David Howells7d12e782006-10-05 14:55:46 +0100328static void option_indat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700329{
Alan Cox33f0f882006-01-09 20:54:13 -0800330 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700331 int endpoint;
332 struct usb_serial_port *port;
333 struct tty_struct *tty;
334 unsigned char *data = urb->transfer_buffer;
335
336 dbg("%s: %p", __FUNCTION__, urb);
337
338 endpoint = usb_pipeendpoint(urb->pipe);
339 port = (struct usb_serial_port *) urb->context;
340
341 if (urb->status) {
342 dbg("%s: nonzero status: %d on endpoint %02x.",
343 __FUNCTION__, urb->status, endpoint);
344 } else {
345 tty = port->tty;
346 if (urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -0800347 tty_buffer_request_room(tty, urb->actual_length);
348 tty_insert_flip_string(tty, data, urb->actual_length);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700349 tty_flip_buffer_push(tty);
350 } else {
351 dbg("%s: empty read urb received", __FUNCTION__);
352 }
353
354 /* Resubmit urb so we continue receiving */
355 if (port->open_count && urb->status != -ESHUTDOWN) {
356 err = usb_submit_urb(urb, GFP_ATOMIC);
357 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700358 printk(KERN_ERR "%s: resubmit read urb failed. "
359 "(%d)", __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700360 }
361 }
362 return;
363}
364
David Howells7d12e782006-10-05 14:55:46 +0100365static void option_outdat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700366{
367 struct usb_serial_port *port;
368
369 dbg("%s", __FUNCTION__);
370
371 port = (struct usb_serial_port *) urb->context;
372
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700373 usb_serial_port_softint(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700374}
375
David Howells7d12e782006-10-05 14:55:46 +0100376static void option_instat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700377{
378 int err;
379 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
380 struct option_port_private *portdata = usb_get_serial_port_data(port);
381 struct usb_serial *serial = port->serial;
382
383 dbg("%s", __FUNCTION__);
384 dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
385
386 if (urb->status == 0) {
387 struct usb_ctrlrequest *req_pkt =
388 (struct usb_ctrlrequest *)urb->transfer_buffer;
389
390 if (!req_pkt) {
391 dbg("%s: NULL req_pkt\n", __FUNCTION__);
392 return;
393 }
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700394 if ((req_pkt->bRequestType == 0xA1) &&
395 (req_pkt->bRequest == 0x20)) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700396 int old_dcd_state;
397 unsigned char signals = *((unsigned char *)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700398 urb->transfer_buffer +
399 sizeof(struct usb_ctrlrequest));
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700400
401 dbg("%s: signal x%x", __FUNCTION__, signals);
402
403 old_dcd_state = portdata->dcd_state;
404 portdata->cts_state = 1;
405 portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
406 portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
407 portdata->ri_state = ((signals & 0x08) ? 1 : 0);
408
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700409 if (port->tty && !C_CLOCAL(port->tty) &&
410 old_dcd_state && !portdata->dcd_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700411 tty_hangup(port->tty);
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700412 } else {
413 dbg("%s: type %x req %x", __FUNCTION__,
414 req_pkt->bRequestType,req_pkt->bRequest);
415 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700416 } else
417 dbg("%s: error %d", __FUNCTION__, urb->status);
418
419 /* Resubmit urb so we continue receiving IRQ data */
420 if (urb->status != -ESHUTDOWN) {
421 urb->dev = serial->dev;
422 err = usb_submit_urb(urb, GFP_ATOMIC);
423 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700424 dbg("%s: resubmit intr urb failed. (%d)",
425 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700426 }
427}
428
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700429static int option_write_room(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700430{
431 struct option_port_private *portdata;
432 int i;
433 int data_len = 0;
434 struct urb *this_urb;
435
436 portdata = usb_get_serial_port_data(port);
437
Matthias Urlichsba460e42005-07-14 00:33:47 -0700438 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700439 this_urb = portdata->out_urbs[i];
440 if (this_urb && this_urb->status != -EINPROGRESS)
441 data_len += OUT_BUFLEN;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700442 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700443
444 dbg("%s: %d", __FUNCTION__, data_len);
445 return data_len;
446}
447
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700448static int option_chars_in_buffer(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700449{
450 struct option_port_private *portdata;
451 int i;
452 int data_len = 0;
453 struct urb *this_urb;
454
455 portdata = usb_get_serial_port_data(port);
456
Matthias Urlichsba460e42005-07-14 00:33:47 -0700457 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700458 this_urb = portdata->out_urbs[i];
459 if (this_urb && this_urb->status == -EINPROGRESS)
460 data_len += this_urb->transfer_buffer_length;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700461 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700462 dbg("%s: %d", __FUNCTION__, data_len);
463 return data_len;
464}
465
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700466static int option_open(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700467{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700468 struct option_port_private *portdata;
469 struct usb_serial *serial = port->serial;
470 int i, err;
471 struct urb *urb;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700472
473 portdata = usb_get_serial_port_data(port);
474
475 dbg("%s", __FUNCTION__);
476
477 /* Set some sane defaults */
478 portdata->rts_state = 1;
479 portdata->dtr_state = 1;
480
481 /* Reset low level data toggle and start reading from endpoints */
482 for (i = 0; i < N_IN_URB; i++) {
483 urb = portdata->in_urbs[i];
484 if (! urb)
485 continue;
486 if (urb->dev != serial->dev) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700487 dbg("%s: dev %p != %p", __FUNCTION__,
488 urb->dev, serial->dev);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700489 continue;
490 }
491
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700492 /*
493 * make sure endpoint data toggle is synchronized with the
494 * device
495 */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700496 usb_clear_halt(urb->dev, urb->pipe);
497
498 err = usb_submit_urb(urb, GFP_KERNEL);
499 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700500 dbg("%s: submit urb %d failed (%d) %d",
501 __FUNCTION__, i, err,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700502 urb->transfer_buffer_length);
503 }
504 }
505
506 /* Reset low level data toggle on out endpoints */
507 for (i = 0; i < N_OUT_URB; i++) {
508 urb = portdata->out_urbs[i];
509 if (! urb)
510 continue;
511 urb->dev = serial->dev;
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700512 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
513 usb_pipeout(urb->pipe), 0); */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700514 }
515
516 port->tty->low_latency = 1;
517
518 option_send_setup(port);
519
520 return (0);
521}
522
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700523static inline void stop_urb(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700524{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -0400525 if (urb && urb->status == -EINPROGRESS)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700526 usb_kill_urb(urb);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700527}
528
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700529static void option_close(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700530{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700531 int i;
532 struct usb_serial *serial = port->serial;
533 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700534
535 dbg("%s", __FUNCTION__);
536 portdata = usb_get_serial_port_data(port);
537
538 portdata->rts_state = 0;
539 portdata->dtr_state = 0;
540
541 if (serial->dev) {
542 option_send_setup(port);
543
544 /* Stop reading/writing urbs */
545 for (i = 0; i < N_IN_URB; i++)
546 stop_urb(portdata->in_urbs[i]);
547 for (i = 0; i < N_OUT_URB; i++)
548 stop_urb(portdata->out_urbs[i]);
549 }
550 port->tty = NULL;
551}
552
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700553/* Helper functions used by option_setup_urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700554static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
555 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +0100556 void (*callback)(struct urb *))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700557{
558 struct urb *urb;
559
560 if (endpoint == -1)
561 return NULL; /* endpoint not needed */
562
563 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
564 if (urb == NULL) {
565 dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
566 return NULL;
567 }
568
569 /* Fill URB using supplied data. */
570 usb_fill_bulk_urb(urb, serial->dev,
571 usb_sndbulkpipe(serial->dev, endpoint) | dir,
572 buf, len, callback, ctx);
573
574 return urb;
575}
576
577/* Setup urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700578static void option_setup_urbs(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700579{
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200580 int i,j;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700581 struct usb_serial_port *port;
582 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700583
584 dbg("%s", __FUNCTION__);
585
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200586 for (i = 0; i < serial->num_ports; i++) {
587 port = serial->port[i];
588 portdata = usb_get_serial_port_data(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700589
590 /* Do indat endpoints first */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200591 for (j = 0; j < N_IN_URB; ++j) {
592 portdata->in_urbs[j] = option_setup_urb (serial,
593 port->bulk_in_endpointAddress, USB_DIR_IN, port,
594 portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
595 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700596
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200597 /* outdat endpoints */
598 for (j = 0; j < N_OUT_URB; ++j) {
599 portdata->out_urbs[j] = option_setup_urb (serial,
600 port->bulk_out_endpointAddress, USB_DIR_OUT, port,
601 portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
602 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700603 }
604}
605
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700606static int option_send_setup(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700607{
608 struct usb_serial *serial = port->serial;
609 struct option_port_private *portdata;
610
611 dbg("%s", __FUNCTION__);
612
Miguel Angel Alvarez8c152712006-12-14 19:49:35 +0100613 if (port->number != 0)
614 return 0;
615
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700616 portdata = usb_get_serial_port_data(port);
617
618 if (port->tty) {
619 int val = 0;
620 if (portdata->dtr_state)
621 val |= 0x01;
622 if (portdata->rts_state)
623 val |= 0x02;
624
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700625 return usb_control_msg(serial->dev,
626 usb_rcvctrlpipe(serial->dev, 0),
627 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700628 }
629
630 return 0;
631}
632
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700633static int option_startup(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700634{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700635 int i, err;
636 struct usb_serial_port *port;
637 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700638
639 dbg("%s", __FUNCTION__);
640
641 /* Now setup per port private data */
642 for (i = 0; i < serial->num_ports; i++) {
643 port = serial->port[i];
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100644 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700645 if (!portdata) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700646 dbg("%s: kmalloc for option_port_private (%d) failed!.",
647 __FUNCTION__, i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700648 return (1);
649 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700650
651 usb_set_serial_port_data(port, portdata);
652
653 if (! port->interrupt_in_urb)
654 continue;
655 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
656 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700657 dbg("%s: submit irq_in urb failed %d",
658 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700659 }
660
661 option_setup_urbs(serial);
662
663 return (0);
664}
665
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700666static void option_shutdown(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700667{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700668 int i, j;
669 struct usb_serial_port *port;
670 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700671
672 dbg("%s", __FUNCTION__);
673
674 /* Stop reading/writing urbs */
675 for (i = 0; i < serial->num_ports; ++i) {
676 port = serial->port[i];
677 portdata = usb_get_serial_port_data(port);
678 for (j = 0; j < N_IN_URB; j++)
679 stop_urb(portdata->in_urbs[j]);
680 for (j = 0; j < N_OUT_URB; j++)
681 stop_urb(portdata->out_urbs[j]);
682 }
683
684 /* Now free them */
685 for (i = 0; i < serial->num_ports; ++i) {
686 port = serial->port[i];
687 portdata = usb_get_serial_port_data(port);
688
689 for (j = 0; j < N_IN_URB; j++) {
690 if (portdata->in_urbs[j]) {
691 usb_free_urb(portdata->in_urbs[j]);
692 portdata->in_urbs[j] = NULL;
693 }
694 }
695 for (j = 0; j < N_OUT_URB; j++) {
696 if (portdata->out_urbs[j]) {
697 usb_free_urb(portdata->out_urbs[j]);
698 portdata->out_urbs[j] = NULL;
699 }
700 }
701 }
702
703 /* Now free per port private data */
704 for (i = 0; i < serial->num_ports; i++) {
705 port = serial->port[i];
706 kfree(usb_get_serial_port_data(port));
707 }
708}
709
710MODULE_AUTHOR(DRIVER_AUTHOR);
711MODULE_DESCRIPTION(DRIVER_DESC);
712MODULE_VERSION(DRIVER_VERSION);
713MODULE_LICENSE("GPL");
714
Matthias Urlichsba460e42005-07-14 00:33:47 -0700715#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700716module_param(debug, bool, S_IRUGO | S_IWUSR);
717MODULE_PARM_DESC(debug, "Debug messages");
Matthias Urlichsba460e42005-07-14 00:33:47 -0700718#endif
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700719