blob: 5d9967db6c2c3513eab21c6573bc32ea37bdf3a3 [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>
Alan Stern59c2afa2007-06-05 16:46:26 -070041#include <linux/bitops.h>
Matthias Urlichs58cfe912005-05-23 17:00:48 -070042#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070043#include <linux/usb/serial.h>
Matthias Urlichs58cfe912005-05-23 17:00:48 -070044
45/* Function prototypes */
Andrew Morton7bb75ae2005-07-27 01:08:30 -070046static int option_open(struct usb_serial_port *port, struct file *filp);
47static void option_close(struct usb_serial_port *port, struct file *filp);
48static int option_startup(struct usb_serial *serial);
49static void option_shutdown(struct usb_serial *serial);
50static void option_rx_throttle(struct usb_serial_port *port);
51static void option_rx_unthrottle(struct usb_serial_port *port);
52static int option_write_room(struct usb_serial_port *port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070053
David Howells7d12e782006-10-05 14:55:46 +010054static void option_instat_callback(struct urb *urb);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070055
Andrew Morton7bb75ae2005-07-27 01:08:30 -070056static int option_write(struct usb_serial_port *port,
57 const unsigned char *buf, int count);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070058
Andrew Morton7bb75ae2005-07-27 01:08:30 -070059static int option_chars_in_buffer(struct usb_serial_port *port);
60static int option_ioctl(struct usb_serial_port *port, struct file *file,
61 unsigned int cmd, unsigned long arg);
62static void option_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -080063 struct ktermios *old);
Andrew Morton7bb75ae2005-07-27 01:08:30 -070064static void option_break_ctl(struct usb_serial_port *port, int break_state);
65static int option_tiocmget(struct usb_serial_port *port, struct file *file);
66static int option_tiocmset(struct usb_serial_port *port, struct file *file,
67 unsigned int set, unsigned int clear);
68static int option_send_setup(struct usb_serial_port *port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -070069
70/* Vendor and product IDs */
Greg Kroah-Hartmanfd978bfa2007-02-21 12:53:17 -080071#define OPTION_VENDOR_ID 0x0AF0
72#define OPTION_PRODUCT_COLT 0x5000
73#define OPTION_PRODUCT_RICOLA 0x6000
74#define OPTION_PRODUCT_RICOLA_LIGHT 0x6100
75#define OPTION_PRODUCT_RICOLA_QUAD 0x6200
76#define OPTION_PRODUCT_RICOLA_QUAD_LIGHT 0x6300
77#define OPTION_PRODUCT_RICOLA_NDIS 0x6050
78#define OPTION_PRODUCT_RICOLA_NDIS_LIGHT 0x6150
79#define OPTION_PRODUCT_RICOLA_NDIS_QUAD 0x6250
80#define OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT 0x6350
81#define OPTION_PRODUCT_COBRA 0x6500
82#define OPTION_PRODUCT_COBRA_BUS 0x6501
83#define OPTION_PRODUCT_VIPER 0x6600
84#define OPTION_PRODUCT_VIPER_BUS 0x6601
85#define OPTION_PRODUCT_GT_MAX_READY 0x6701
86#define OPTION_PRODUCT_GT_MAX 0x6711
87#define OPTION_PRODUCT_FUJI_MODEM_LIGHT 0x6721
88#define OPTION_PRODUCT_FUJI_MODEM_GT 0x6741
89#define OPTION_PRODUCT_FUJI_MODEM_EX 0x6761
90#define OPTION_PRODUCT_FUJI_NETWORK_LIGHT 0x6731
91#define OPTION_PRODUCT_FUJI_NETWORK_GT 0x6751
92#define OPTION_PRODUCT_FUJI_NETWORK_EX 0x6771
93#define OPTION_PRODUCT_KOI_MODEM 0x6800
94#define OPTION_PRODUCT_KOI_NETWORK 0x6811
95#define OPTION_PRODUCT_SCORPION_MODEM 0x6901
96#define OPTION_PRODUCT_SCORPION_NETWORK 0x6911
97#define OPTION_PRODUCT_ETNA_MODEM 0x7001
98#define OPTION_PRODUCT_ETNA_NETWORK 0x7011
99#define OPTION_PRODUCT_ETNA_MODEM_LITE 0x7021
100#define OPTION_PRODUCT_ETNA_MODEM_GT 0x7041
101#define OPTION_PRODUCT_ETNA_MODEM_EX 0x7061
102#define OPTION_PRODUCT_ETNA_NETWORK_LITE 0x7031
103#define OPTION_PRODUCT_ETNA_NETWORK_GT 0x7051
104#define OPTION_PRODUCT_ETNA_NETWORK_EX 0x7071
105#define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100
106#define OPTION_PRODUCT_ETNA_KOI_NETWORK 0x7111
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700107
Greg Kroah-Hartmanfd978bfa2007-02-21 12:53:17 -0800108#define HUAWEI_VENDOR_ID 0x12D1
109#define HUAWEI_PRODUCT_E600 0x1001
110#define HUAWEI_PRODUCT_E220 0x1003
Jaime Velasco Juana3209a02007-09-07 19:06:39 +0100111#define HUAWEI_PRODUCT_E220BIS 0x1004
Greg Kroah-Hartmanfd978bfa2007-02-21 12:53:17 -0800112
113#define NOVATELWIRELESS_VENDOR_ID 0x1410
Faidon Liambotis96443212007-08-07 05:46:05 +0300114#define DELL_VENDOR_ID 0x413C
Greg Kroah-Hartmanfd978bfa2007-02-21 12:53:17 -0800115
116#define ANYDATA_VENDOR_ID 0x16d5
Alexander Gattin46269db2007-06-20 00:48:10 +0300117#define ANYDATA_PRODUCT_ADU_E100A 0x6501
118#define ANYDATA_PRODUCT_ADU_500A 0x6502
Matthias Urlichsba460e42005-07-14 00:33:47 -0700119
Leon Leong3f6e5842007-04-26 00:38:02 -0700120#define BANDRICH_VENDOR_ID 0x1A8D
121#define BANDRICH_PRODUCT_C100_1 0x1002
122#define BANDRICH_PRODUCT_C100_2 0x1003
123
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700124static struct usb_device_id option_ids[] = {
Greg Kroah-Hartmanfd978bfa2007-02-21 12:53:17 -0800125 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
126 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
127 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
128 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD) },
129 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD_LIGHT) },
130 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS) },
131 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_LIGHT) },
132 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD) },
133 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200134 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
Greg Kroah-Hartmanfd978bfa2007-02-21 12:53:17 -0800135 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA_BUS) },
136 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER) },
137 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER_BUS) },
138 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX_READY) },
139 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX) },
140 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_LIGHT) },
141 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_GT) },
142 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_EX) },
143 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_LIGHT) },
144 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_GT) },
145 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_EX) },
146 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_MODEM) },
147 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_NETWORK) },
148 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_MODEM) },
149 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_NETWORK) },
150 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM) },
151 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK) },
152 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_LITE) },
153 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_GT) },
154 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_EX) },
155 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_LITE) },
156 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_GT) },
157 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_EX) },
158 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) },
159 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) },
Matthias Urlichsb6137382005-09-22 00:48:40 -0700160 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
Johann Wilhelmab195892006-12-02 07:25:31 +0100161 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
Jaime Velasco Juana3209a02007-09-07 19:06:39 +0100162 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS) },
Greg Kroah-Hartman69806d52007-03-19 13:39:51 -0700163 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1100) }, /* Novatel Merlin XS620/S640 */
164 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1110) }, /* Novatel Merlin S620 */
165 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1120) }, /* Novatel Merlin EX720 */
166 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1130) }, /* Novatel Merlin S720 */
167 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1400) }, /* Novatel U730 */
168 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1410) }, /* Novatel U740 */
169 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1420) }, /* Novatel EU870 */
170 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1430) }, /* Novatel Merlin XU870 HSDPA/3G */
Greg Kroah-Hartman69806d52007-03-19 13:39:51 -0700171 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2100) }, /* Novatel EV620 CDMA/EV-DO */
172 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2110) }, /* Novatel Merlin ES620 / Merlin ES720 / Ovation U720 */
173 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2130) }, /* Novatel Merlin ES620 SM Bus */
174 { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2410) }, /* Novatel EU740 */
Faidon Liambotis96443212007-08-07 05:46:05 +0300175 { USB_DEVICE(DELL_VENDOR_ID, 0x8114) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite EV620 CDMA/EV-DO */
176 { USB_DEVICE(DELL_VENDOR_ID, 0x8115) }, /* Dell Wireless 5500 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */
177 { USB_DEVICE(DELL_VENDOR_ID, 0x8116) }, /* Dell Wireless 5505 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */
178 { USB_DEVICE(DELL_VENDOR_ID, 0x8117) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */
179 { USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */
180 { USB_DEVICE(DELL_VENDOR_ID, 0x8128) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */
Alexander Gattin46269db2007-06-20 00:48:10 +0300181 { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
182 { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
Leon Leong3f6e5842007-04-26 00:38:02 -0700183 { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
184 { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200185 { } /* Terminating entry */
186};
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700187MODULE_DEVICE_TABLE(usb, option_ids);
188
189static struct usb_driver option_driver = {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700190 .name = "option",
191 .probe = usb_serial_probe,
192 .disconnect = usb_serial_disconnect,
193 .id_table = option_ids,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800194 .no_dynamic_id = 1,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700195};
196
Uwe Zeisbergerc30fe7f2006-03-24 18:23:14 +0100197/* The card has three separate interfaces, which the serial driver
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700198 * recognizes separately, thus num_port=1.
199 */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200200
201static struct usb_serial_driver option_1port_device = {
202 .driver = {
203 .owner = THIS_MODULE,
Matthias Urlichs02b2ac52006-08-02 16:41:41 -0700204 .name = "option1",
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200205 },
206 .description = "GSM modem (1-port)",
Johannes Hölzld9b1b782006-12-17 21:50:24 +0100207 .usb_driver = &option_driver,
Greg Kroah-Hartmanb656b2c2007-02-21 12:53:17 -0800208 .id_table = option_ids,
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200209 .num_interrupt_in = NUM_DONT_CARE,
210 .num_bulk_in = NUM_DONT_CARE,
211 .num_bulk_out = NUM_DONT_CARE,
212 .num_ports = 1,
Matthias Urlichsba460e42005-07-14 00:33:47 -0700213 .open = option_open,
214 .close = option_close,
215 .write = option_write,
216 .write_room = option_write_room,
217 .chars_in_buffer = option_chars_in_buffer,
218 .throttle = option_rx_throttle,
219 .unthrottle = option_rx_unthrottle,
220 .ioctl = option_ioctl,
221 .set_termios = option_set_termios,
222 .break_ctl = option_break_ctl,
223 .tiocmget = option_tiocmget,
224 .tiocmset = option_tiocmset,
225 .attach = option_startup,
226 .shutdown = option_shutdown,
227 .read_int_callback = option_instat_callback,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700228};
229
Matthias Urlichsba460e42005-07-14 00:33:47 -0700230#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700231static int debug;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700232#else
233#define debug 0
234#endif
235
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700236/* per port private data */
237
Matthias Urlichsba460e42005-07-14 00:33:47 -0700238#define N_IN_URB 4
239#define N_OUT_URB 1
Matthias Urlichsb27c73d2005-09-22 00:49:33 -0700240#define IN_BUFLEN 4096
Matthias Urlichsba460e42005-07-14 00:33:47 -0700241#define OUT_BUFLEN 128
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700242
243struct option_port_private {
244 /* Input endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700245 struct urb *in_urbs[N_IN_URB];
246 char in_buffer[N_IN_URB][IN_BUFLEN];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700247 /* Output endpoints and buffer for this port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700248 struct urb *out_urbs[N_OUT_URB];
249 char out_buffer[N_OUT_URB][OUT_BUFLEN];
Alan Stern59c2afa2007-06-05 16:46:26 -0700250 unsigned long out_busy; /* Bit vector of URBs in use */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700251
252 /* Settings for the port */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700253 int rts_state; /* Handshaking pins (outputs) */
254 int dtr_state;
255 int cts_state; /* Handshaking pins (inputs) */
256 int dsr_state;
257 int dcd_state;
258 int ri_state;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700259
Matthias Urlichsba460e42005-07-14 00:33:47 -0700260 unsigned long tx_start_time[N_OUT_URB];
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700261};
262
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700263/* Functions used by new usb-serial code. */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700264static int __init option_init(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700265{
266 int retval;
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200267 retval = usb_serial_register(&option_1port_device);
268 if (retval)
269 goto failed_1port_device_register;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700270 retval = usb_register(&option_driver);
271 if (retval)
272 goto failed_driver_register;
273
274 info(DRIVER_DESC ": " DRIVER_VERSION);
275
276 return 0;
277
278failed_driver_register:
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200279 usb_serial_deregister (&option_1port_device);
280failed_1port_device_register:
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700281 return retval;
282}
283
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700284static void __exit option_exit(void)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700285{
286 usb_deregister (&option_driver);
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200287 usb_serial_deregister (&option_1port_device);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700288}
289
290module_init(option_init);
291module_exit(option_exit);
292
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700293static void option_rx_throttle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700294{
295 dbg("%s", __FUNCTION__);
296}
297
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700298static void option_rx_unthrottle(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700299{
300 dbg("%s", __FUNCTION__);
301}
302
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700303static void option_break_ctl(struct usb_serial_port *port, int break_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700304{
305 /* Unfortunately, I don't know how to send a break */
Matthias Urlichsba460e42005-07-14 00:33:47 -0700306 dbg("%s", __FUNCTION__);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700307}
308
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700309static void option_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -0800310 struct ktermios *old_termios)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700311{
312 dbg("%s", __FUNCTION__);
313
314 option_send_setup(port);
315}
316
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700317static int option_tiocmget(struct usb_serial_port *port, struct file *file)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700318{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700319 unsigned int value;
320 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700321
322 portdata = usb_get_serial_port_data(port);
323
324 value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
325 ((portdata->dtr_state) ? TIOCM_DTR : 0) |
326 ((portdata->cts_state) ? TIOCM_CTS : 0) |
327 ((portdata->dsr_state) ? TIOCM_DSR : 0) |
328 ((portdata->dcd_state) ? TIOCM_CAR : 0) |
329 ((portdata->ri_state) ? TIOCM_RNG : 0);
330
331 return value;
332}
333
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700334static int option_tiocmset(struct usb_serial_port *port, struct file *file,
335 unsigned int set, unsigned int clear)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700336{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700337 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700338
339 portdata = usb_get_serial_port_data(port);
340
341 if (set & TIOCM_RTS)
342 portdata->rts_state = 1;
343 if (set & TIOCM_DTR)
344 portdata->dtr_state = 1;
345
346 if (clear & TIOCM_RTS)
347 portdata->rts_state = 0;
348 if (clear & TIOCM_DTR)
349 portdata->dtr_state = 0;
350 return option_send_setup(port);
351}
352
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700353static int option_ioctl(struct usb_serial_port *port, struct file *file,
354 unsigned int cmd, unsigned long arg)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700355{
356 return -ENOIOCTLCMD;
357}
358
359/* Write */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700360static int option_write(struct usb_serial_port *port,
361 const unsigned char *buf, int count)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700362{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700363 struct option_port_private *portdata;
364 int i;
365 int left, todo;
366 struct urb *this_urb = NULL; /* spurious */
367 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700368
369 portdata = usb_get_serial_port_data(port);
370
371 dbg("%s: write (%d chars)", __FUNCTION__, count);
372
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700373 i = 0;
374 left = count;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700375 for (i=0; left > 0 && i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700376 todo = left;
377 if (todo > OUT_BUFLEN)
378 todo = OUT_BUFLEN;
379
Matthias Urlichsba460e42005-07-14 00:33:47 -0700380 this_urb = portdata->out_urbs[i];
Alan Stern59c2afa2007-06-05 16:46:26 -0700381 if (test_and_set_bit(i, &portdata->out_busy)) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700382 if (time_before(jiffies,
383 portdata->tx_start_time[i] + 10 * HZ))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700384 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700385 usb_unlink_urb(this_urb);
Matthias Urlichsba460e42005-07-14 00:33:47 -0700386 continue;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700387 }
Matthias Urlichsba460e42005-07-14 00:33:47 -0700388 if (this_urb->status != 0)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700389 dbg("usb_write %p failed (err=%d)",
390 this_urb, this_urb->status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700391
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700392 dbg("%s: endpoint %d buf %d", __FUNCTION__,
393 usb_pipeendpoint(this_urb->pipe), i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700394
Matthias Urlichsba460e42005-07-14 00:33:47 -0700395 /* send the data */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700396 memcpy (this_urb->transfer_buffer, buf, todo);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700397 this_urb->transfer_buffer_length = todo;
398
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700399 this_urb->dev = port->serial->dev;
400 err = usb_submit_urb(this_urb, GFP_ATOMIC);
401 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700402 dbg("usb_submit_urb %p (write bulk) failed "
403 "(%d, has %d)", this_urb,
404 err, this_urb->status);
Alan Stern59c2afa2007-06-05 16:46:26 -0700405 clear_bit(i, &portdata->out_busy);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700406 continue;
407 }
408 portdata->tx_start_time[i] = jiffies;
409 buf += todo;
410 left -= todo;
411 }
412
413 count -= left;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700414 dbg("%s: wrote (did %d)", __FUNCTION__, count);
415 return count;
416}
417
David Howells7d12e782006-10-05 14:55:46 +0100418static void option_indat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700419{
Alan Cox33f0f882006-01-09 20:54:13 -0800420 int err;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700421 int endpoint;
422 struct usb_serial_port *port;
423 struct tty_struct *tty;
424 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartmand6977b52007-06-15 15:44:13 -0700425 int status = urb->status;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700426
427 dbg("%s: %p", __FUNCTION__, urb);
428
429 endpoint = usb_pipeendpoint(urb->pipe);
430 port = (struct usb_serial_port *) urb->context;
431
Greg Kroah-Hartmand6977b52007-06-15 15:44:13 -0700432 if (status) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700433 dbg("%s: nonzero status: %d on endpoint %02x.",
Greg Kroah-Hartmand6977b52007-06-15 15:44:13 -0700434 __FUNCTION__, status, endpoint);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700435 } else {
436 tty = port->tty;
437 if (urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -0800438 tty_buffer_request_room(tty, urb->actual_length);
439 tty_insert_flip_string(tty, data, urb->actual_length);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700440 tty_flip_buffer_push(tty);
441 } else {
442 dbg("%s: empty read urb received", __FUNCTION__);
443 }
444
445 /* Resubmit urb so we continue receiving */
Greg Kroah-Hartmand6977b52007-06-15 15:44:13 -0700446 if (port->open_count && status != -ESHUTDOWN) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700447 err = usb_submit_urb(urb, GFP_ATOMIC);
448 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700449 printk(KERN_ERR "%s: resubmit read urb failed. "
450 "(%d)", __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700451 }
452 }
453 return;
454}
455
David Howells7d12e782006-10-05 14:55:46 +0100456static void option_outdat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700457{
458 struct usb_serial_port *port;
Alan Stern59c2afa2007-06-05 16:46:26 -0700459 struct option_port_private *portdata;
460 int i;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700461
462 dbg("%s", __FUNCTION__);
463
464 port = (struct usb_serial_port *) urb->context;
465
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700466 usb_serial_port_softint(port);
Alan Stern59c2afa2007-06-05 16:46:26 -0700467
468 portdata = usb_get_serial_port_data(port);
469 for (i = 0; i < N_OUT_URB; ++i) {
470 if (portdata->out_urbs[i] == urb) {
471 smp_mb__before_clear_bit();
472 clear_bit(i, &portdata->out_busy);
473 break;
474 }
475 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700476}
477
David Howells7d12e782006-10-05 14:55:46 +0100478static void option_instat_callback(struct urb *urb)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700479{
480 int err;
Greg Kroah-Hartmand6977b52007-06-15 15:44:13 -0700481 int status = urb->status;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700482 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
483 struct option_port_private *portdata = usb_get_serial_port_data(port);
484 struct usb_serial *serial = port->serial;
485
486 dbg("%s", __FUNCTION__);
487 dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
488
Greg Kroah-Hartmand6977b52007-06-15 15:44:13 -0700489 if (status == 0) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700490 struct usb_ctrlrequest *req_pkt =
491 (struct usb_ctrlrequest *)urb->transfer_buffer;
492
493 if (!req_pkt) {
494 dbg("%s: NULL req_pkt\n", __FUNCTION__);
495 return;
496 }
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700497 if ((req_pkt->bRequestType == 0xA1) &&
498 (req_pkt->bRequest == 0x20)) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700499 int old_dcd_state;
500 unsigned char signals = *((unsigned char *)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700501 urb->transfer_buffer +
502 sizeof(struct usb_ctrlrequest));
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700503
504 dbg("%s: signal x%x", __FUNCTION__, signals);
505
506 old_dcd_state = portdata->dcd_state;
507 portdata->cts_state = 1;
508 portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
509 portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
510 portdata->ri_state = ((signals & 0x08) ? 1 : 0);
511
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700512 if (port->tty && !C_CLOCAL(port->tty) &&
513 old_dcd_state && !portdata->dcd_state)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700514 tty_hangup(port->tty);
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700515 } else {
516 dbg("%s: type %x req %x", __FUNCTION__,
517 req_pkt->bRequestType,req_pkt->bRequest);
518 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700519 } else
Greg Kroah-Hartmand6977b52007-06-15 15:44:13 -0700520 dbg("%s: error %d", __FUNCTION__, status);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700521
522 /* Resubmit urb so we continue receiving IRQ data */
Greg Kroah-Hartmand6977b52007-06-15 15:44:13 -0700523 if (status != -ESHUTDOWN) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700524 urb->dev = serial->dev;
525 err = usb_submit_urb(urb, GFP_ATOMIC);
526 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700527 dbg("%s: resubmit intr urb failed. (%d)",
528 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700529 }
530}
531
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700532static int option_write_room(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700533{
534 struct option_port_private *portdata;
535 int i;
536 int data_len = 0;
537 struct urb *this_urb;
538
539 portdata = usb_get_serial_port_data(port);
540
Matthias Urlichsba460e42005-07-14 00:33:47 -0700541 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700542 this_urb = portdata->out_urbs[i];
Alan Stern59c2afa2007-06-05 16:46:26 -0700543 if (this_urb && !test_bit(i, &portdata->out_busy))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700544 data_len += OUT_BUFLEN;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700545 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700546
547 dbg("%s: %d", __FUNCTION__, data_len);
548 return data_len;
549}
550
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700551static int option_chars_in_buffer(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700552{
553 struct option_port_private *portdata;
554 int i;
555 int data_len = 0;
556 struct urb *this_urb;
557
558 portdata = usb_get_serial_port_data(port);
559
Matthias Urlichsba460e42005-07-14 00:33:47 -0700560 for (i=0; i < N_OUT_URB; i++) {
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700561 this_urb = portdata->out_urbs[i];
Alan Stern59c2afa2007-06-05 16:46:26 -0700562 if (this_urb && test_bit(i, &portdata->out_busy))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700563 data_len += this_urb->transfer_buffer_length;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700564 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700565 dbg("%s: %d", __FUNCTION__, data_len);
566 return data_len;
567}
568
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700569static int option_open(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700570{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700571 struct option_port_private *portdata;
572 struct usb_serial *serial = port->serial;
573 int i, err;
574 struct urb *urb;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700575
576 portdata = usb_get_serial_port_data(port);
577
578 dbg("%s", __FUNCTION__);
579
580 /* Set some sane defaults */
581 portdata->rts_state = 1;
582 portdata->dtr_state = 1;
583
584 /* Reset low level data toggle and start reading from endpoints */
585 for (i = 0; i < N_IN_URB; i++) {
586 urb = portdata->in_urbs[i];
587 if (! urb)
588 continue;
589 if (urb->dev != serial->dev) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700590 dbg("%s: dev %p != %p", __FUNCTION__,
591 urb->dev, serial->dev);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700592 continue;
593 }
594
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700595 /*
596 * make sure endpoint data toggle is synchronized with the
597 * device
598 */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700599 usb_clear_halt(urb->dev, urb->pipe);
600
601 err = usb_submit_urb(urb, GFP_KERNEL);
602 if (err) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700603 dbg("%s: submit urb %d failed (%d) %d",
604 __FUNCTION__, i, err,
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700605 urb->transfer_buffer_length);
606 }
607 }
608
609 /* Reset low level data toggle on out endpoints */
610 for (i = 0; i < N_OUT_URB; i++) {
611 urb = portdata->out_urbs[i];
612 if (! urb)
613 continue;
614 urb->dev = serial->dev;
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700615 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
616 usb_pipeout(urb->pipe), 0); */
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700617 }
618
619 port->tty->low_latency = 1;
620
621 option_send_setup(port);
622
623 return (0);
624}
625
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700626static void option_close(struct usb_serial_port *port, struct file *filp)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700627{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700628 int i;
629 struct usb_serial *serial = port->serial;
630 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700631
632 dbg("%s", __FUNCTION__);
633 portdata = usb_get_serial_port_data(port);
634
635 portdata->rts_state = 0;
636 portdata->dtr_state = 0;
637
638 if (serial->dev) {
639 option_send_setup(port);
640
641 /* Stop reading/writing urbs */
642 for (i = 0; i < N_IN_URB; i++)
Oliver Neukum7d28e742007-03-20 13:41:21 +0100643 usb_kill_urb(portdata->in_urbs[i]);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700644 for (i = 0; i < N_OUT_URB; i++)
Oliver Neukum7d28e742007-03-20 13:41:21 +0100645 usb_kill_urb(portdata->out_urbs[i]);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700646 }
647 port->tty = NULL;
648}
649
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700650/* Helper functions used by option_setup_urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700651static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
652 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +0100653 void (*callback)(struct urb *))
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700654{
655 struct urb *urb;
656
657 if (endpoint == -1)
658 return NULL; /* endpoint not needed */
659
660 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
661 if (urb == NULL) {
662 dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
663 return NULL;
664 }
665
666 /* Fill URB using supplied data. */
667 usb_fill_bulk_urb(urb, serial->dev,
668 usb_sndbulkpipe(serial->dev, endpoint) | dir,
669 buf, len, callback, ctx);
670
671 return urb;
672}
673
674/* Setup urbs */
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700675static void option_setup_urbs(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700676{
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200677 int i,j;
Matthias Urlichsba460e42005-07-14 00:33:47 -0700678 struct usb_serial_port *port;
679 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700680
681 dbg("%s", __FUNCTION__);
682
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200683 for (i = 0; i < serial->num_ports; i++) {
684 port = serial->port[i];
685 portdata = usb_get_serial_port_data(port);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700686
687 /* Do indat endpoints first */
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200688 for (j = 0; j < N_IN_URB; ++j) {
689 portdata->in_urbs[j] = option_setup_urb (serial,
690 port->bulk_in_endpointAddress, USB_DIR_IN, port,
691 portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
692 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700693
Matthias Urlichs14f76cc2006-06-02 11:48:56 +0200694 /* outdat endpoints */
695 for (j = 0; j < N_OUT_URB; ++j) {
696 portdata->out_urbs[j] = option_setup_urb (serial,
697 port->bulk_out_endpointAddress, USB_DIR_OUT, port,
698 portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
699 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700700 }
701}
702
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700703static int option_send_setup(struct usb_serial_port *port)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700704{
705 struct usb_serial *serial = port->serial;
706 struct option_port_private *portdata;
707
708 dbg("%s", __FUNCTION__);
709
Miguel Angel Alvarez8c152712006-12-14 19:49:35 +0100710 if (port->number != 0)
711 return 0;
712
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700713 portdata = usb_get_serial_port_data(port);
714
715 if (port->tty) {
716 int val = 0;
717 if (portdata->dtr_state)
718 val |= 0x01;
719 if (portdata->rts_state)
720 val |= 0x02;
721
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700722 return usb_control_msg(serial->dev,
723 usb_rcvctrlpipe(serial->dev, 0),
724 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700725 }
726
727 return 0;
728}
729
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700730static int option_startup(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700731{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700732 int i, err;
733 struct usb_serial_port *port;
734 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700735
736 dbg("%s", __FUNCTION__);
737
738 /* Now setup per port private data */
739 for (i = 0; i < serial->num_ports; i++) {
740 port = serial->port[i];
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100741 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700742 if (!portdata) {
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700743 dbg("%s: kmalloc for option_port_private (%d) failed!.",
744 __FUNCTION__, i);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700745 return (1);
746 }
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700747
748 usb_set_serial_port_data(port, portdata);
749
750 if (! port->interrupt_in_urb)
751 continue;
752 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
753 if (err)
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700754 dbg("%s: submit irq_in urb failed %d",
755 __FUNCTION__, err);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700756 }
757
758 option_setup_urbs(serial);
759
760 return (0);
761}
762
Andrew Morton7bb75ae2005-07-27 01:08:30 -0700763static void option_shutdown(struct usb_serial *serial)
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700764{
Matthias Urlichsba460e42005-07-14 00:33:47 -0700765 int i, j;
766 struct usb_serial_port *port;
767 struct option_port_private *portdata;
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700768
769 dbg("%s", __FUNCTION__);
770
771 /* Stop reading/writing urbs */
772 for (i = 0; i < serial->num_ports; ++i) {
773 port = serial->port[i];
774 portdata = usb_get_serial_port_data(port);
775 for (j = 0; j < N_IN_URB; j++)
Oliver Neukum7d28e742007-03-20 13:41:21 +0100776 usb_kill_urb(portdata->in_urbs[j]);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700777 for (j = 0; j < N_OUT_URB; j++)
Oliver Neukum7d28e742007-03-20 13:41:21 +0100778 usb_kill_urb(portdata->out_urbs[j]);
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700779 }
780
781 /* Now free them */
782 for (i = 0; i < serial->num_ports; ++i) {
783 port = serial->port[i];
784 portdata = usb_get_serial_port_data(port);
785
786 for (j = 0; j < N_IN_URB; j++) {
787 if (portdata->in_urbs[j]) {
788 usb_free_urb(portdata->in_urbs[j]);
789 portdata->in_urbs[j] = NULL;
790 }
791 }
792 for (j = 0; j < N_OUT_URB; j++) {
793 if (portdata->out_urbs[j]) {
794 usb_free_urb(portdata->out_urbs[j]);
795 portdata->out_urbs[j] = NULL;
796 }
797 }
798 }
799
800 /* Now free per port private data */
801 for (i = 0; i < serial->num_ports; i++) {
802 port = serial->port[i];
803 kfree(usb_get_serial_port_data(port));
804 }
805}
806
807MODULE_AUTHOR(DRIVER_AUTHOR);
808MODULE_DESCRIPTION(DRIVER_DESC);
809MODULE_VERSION(DRIVER_VERSION);
810MODULE_LICENSE("GPL");
811
Matthias Urlichsba460e42005-07-14 00:33:47 -0700812#ifdef CONFIG_USB_DEBUG
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700813module_param(debug, bool, S_IRUGO | S_IWUSR);
814MODULE_PARM_DESC(debug, "Debug messages");
Matthias Urlichsba460e42005-07-14 00:33:47 -0700815#endif
Matthias Urlichs58cfe912005-05-23 17:00:48 -0700816