option.c revision 7d28e74b97c8eb859fd9f5eb018bb1c75627bd55
158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/*
214f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs  USB Driver for GSM modems
358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs  Copyright (C) 2005  Matthias Urlichs <smurf@smurf.noris.de>
558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs  This driver is free software; you can redistribute it and/or modify
758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs  it under the terms of Version 2 of the GNU General Public License as
858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs  published by the Free Software Foundation.
958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
1058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs  Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
1158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
12b3fdab59b8f5d8e42fa339be74cd015dc1a3192fMatthias Urlichs  History: see the git log.
13ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs
14ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs  Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
15ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs
1614f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs  This driver exists because the "normal" serial driver doesn't work too well
1714f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs  with GSM modems. Issues:
1814f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs  - data loss -- one single Receive URB is not nearly enough
197c1c2f73e00b5d0413399a14b7ab9e80db94926fMatthias Urlichs  - nonstandard flow (Option devices) control
2014f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs  - controlling the baud rate doesn't make sense
2114f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs
2214f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs  This driver is named "option" because the most common device it's
2314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs  used for is a PC-Card (with an internal OHCI-USB interface, behind
2414f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs  which the GSM interface sits), made by Option Inc.
2514f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs
2614f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs  Some of the "one port" devices actually exhibit multiple USB instances
2714f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs  on the USB bus. This is not a bug, these ports are used for different
2814f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs  device features.
2958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs*/
30ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs
31e37de9e0d6591706a76cff63582cbc721c317333Matthias Urlichs#define DRIVER_VERSION "v0.7.1"
3258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
3314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs#define DRIVER_DESC "USB Driver for GSM modems"
3458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
3558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs#include <linux/kernel.h>
3658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs#include <linux/jiffies.h>
3758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs#include <linux/errno.h>
3858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs#include <linux/tty.h>
3958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs#include <linux/tty_flip.h>
4058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs#include <linux/module.h>
4158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs#include <linux/usb.h>
42a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h>
4358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
4458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/* Function prototypes */
457bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int  option_open(struct usb_serial_port *port, struct file *filp);
467bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_close(struct usb_serial_port *port, struct file *filp);
477bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int  option_startup(struct usb_serial *serial);
487bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_shutdown(struct usb_serial *serial);
497bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_rx_throttle(struct usb_serial_port *port);
507bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_rx_unthrottle(struct usb_serial_port *port);
517bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int  option_write_room(struct usb_serial_port *port);
5258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
537d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void option_instat_callback(struct urb *urb);
5458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
557bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_write(struct usb_serial_port *port,
567bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			const unsigned char *buf, int count);
5758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
587bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int  option_chars_in_buffer(struct usb_serial_port *port);
597bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int  option_ioctl(struct usb_serial_port *port, struct file *file,
607bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			unsigned int cmd, unsigned long arg);
617bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_set_termios(struct usb_serial_port *port,
62606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox				struct ktermios *old);
637bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_break_ctl(struct usb_serial_port *port, int break_state);
647bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int  option_tiocmget(struct usb_serial_port *port, struct file *file);
657bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int  option_tiocmset(struct usb_serial_port *port, struct file *file,
667bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				unsigned int set, unsigned int clear);
677bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int  option_send_setup(struct usb_serial_port *port);
6858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
6958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/* Vendor and product IDs */
70fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_VENDOR_ID			0x0AF0
71fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_COLT			0x5000
72fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_RICOLA			0x6000
73fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_RICOLA_LIGHT		0x6100
74fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_RICOLA_QUAD		0x6200
75fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_RICOLA_QUAD_LIGHT	0x6300
76fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_RICOLA_NDIS		0x6050
77fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_RICOLA_NDIS_LIGHT	0x6150
78fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_RICOLA_NDIS_QUAD		0x6250
79fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT	0x6350
80fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_COBRA			0x6500
81fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_COBRA_BUS		0x6501
82fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_VIPER			0x6600
83fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_VIPER_BUS		0x6601
84fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_GT_MAX_READY		0x6701
85fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_GT_MAX			0x6711
86fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_FUJI_MODEM_LIGHT		0x6721
87fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_FUJI_MODEM_GT		0x6741
88fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_FUJI_MODEM_EX		0x6761
89fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_FUJI_NETWORK_LIGHT	0x6731
90fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_FUJI_NETWORK_GT		0x6751
91fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_FUJI_NETWORK_EX		0x6771
92fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_KOI_MODEM		0x6800
93fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_KOI_NETWORK		0x6811
94fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_SCORPION_MODEM		0x6901
95fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_SCORPION_NETWORK		0x6911
96fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_ETNA_MODEM		0x7001
97fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_ETNA_NETWORK		0x7011
98fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_ETNA_MODEM_LITE		0x7021
99fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_ETNA_MODEM_GT		0x7041
100fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_ETNA_MODEM_EX		0x7061
101fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_ETNA_NETWORK_LITE	0x7031
102fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_ETNA_NETWORK_GT		0x7051
103fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_ETNA_NETWORK_EX		0x7071
104fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_ETNA_KOI_MODEM		0x7100
105fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define OPTION_PRODUCT_ETNA_KOI_NETWORK		0x7111
106fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman
107fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define HUAWEI_VENDOR_ID			0x12D1
108fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define HUAWEI_PRODUCT_E600			0x1001
109fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define HUAWEI_PRODUCT_E220			0x1003
110fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman
111fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define NOVATELWIRELESS_VENDOR_ID		0x1410
112fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman
113fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define ANYDATA_VENDOR_ID			0x16d5
114fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman#define ANYDATA_PRODUCT_ID			0x6501
11558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
11658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsstatic struct usb_device_id option_ids[] = {
117fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
118fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
119fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
120fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD) },
121fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD_LIGHT) },
122fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS) },
123fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_LIGHT) },
124fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD) },
125fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT) },
12614f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
127fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA_BUS) },
128fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER) },
129fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER_BUS) },
130fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX_READY) },
131fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX) },
132fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_LIGHT) },
133fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_GT) },
134fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_EX) },
135fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_LIGHT) },
136fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_GT) },
137fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_EX) },
138fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_MODEM) },
139fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_NETWORK) },
140fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_MODEM) },
141fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_NETWORK) },
142fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM) },
143fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK) },
144fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_LITE) },
145fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_GT) },
146fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_EX) },
147fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_LITE) },
148fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_GT) },
149fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_EX) },
150fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) },
151fd978bfa127a0b8c0bdbbbc9d64f3c73bf080f61Greg Kroah-Hartman	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) },
152b6137383bda844a433d65e027502df7b20ba45c2Matthias Urlichs	{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
153ab1958905514da3b6c06d61523ebed142a16cc72Johann Wilhelm	{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
15469806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1100) }, /* Novatel Merlin XS620/S640 */
15569806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1110) }, /* Novatel Merlin S620 */
15669806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1120) }, /* Novatel Merlin EX720 */
15769806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1130) }, /* Novatel Merlin S720 */
15869806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1400) }, /* Novatel U730 */
15969806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1410) }, /* Novatel U740 */
16069806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1420) }, /* Novatel EU870 */
16169806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1430) }, /* Novatel Merlin XU870 HSDPA/3G */
16269806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1430) }, /* Novatel XU870 */
16369806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2100) }, /* Novatel EV620 CDMA/EV-DO */
16469806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2110) }, /* Novatel Merlin ES620 / Merlin ES720 / Ovation U720 */
16569806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2130) }, /* Novatel Merlin ES620 SM Bus */
16669806d5631b79ed0c442ae5b15c46bcfd8662476Greg Kroah-Hartman	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2410) }, /* Novatel EU740 */
16731fcbb733812bca52e8bee96d62ba56df0fc408bMatthias Urlichs	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
16814f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ } /* Terminating entry */
16914f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs};
17058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias UrlichsMODULE_DEVICE_TABLE(usb, option_ids);
17158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
17258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsstatic struct usb_driver option_driver = {
17358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	.name       = "option",
17458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	.probe      = usb_serial_probe,
17558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	.disconnect = usb_serial_disconnect,
17658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	.id_table   = option_ids,
177ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman	.no_dynamic_id = 	1,
17858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs};
17958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
180c30fe7f73194650148b58ee80908c1bc38246397Uwe Zeisberger/* The card has three separate interfaces, which the serial driver
18158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs * recognizes separately, thus num_port=1.
18258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs */
18314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs
18414f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichsstatic struct usb_serial_driver option_1port_device = {
18514f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	.driver = {
18614f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		.owner =	THIS_MODULE,
18702b2ac5b0370b1157a5a99f2fdf006644b9b86d5Matthias Urlichs		.name =		"option1",
18814f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	},
18914f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	.description       = "GSM modem (1-port)",
190d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.usb_driver        = &option_driver,
191b656b2cbd74fb591d46e07c7c291791b280ad5b4Greg Kroah-Hartman	.id_table          = option_ids,
192ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.num_interrupt_in  = NUM_DONT_CARE,
193ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.num_bulk_in       = NUM_DONT_CARE,
194ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.num_bulk_out      = NUM_DONT_CARE,
19514f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	.num_ports         = 1,
196ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.open              = option_open,
197ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.close             = option_close,
198ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.write             = option_write,
199ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.write_room        = option_write_room,
200ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.chars_in_buffer   = option_chars_in_buffer,
201ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.throttle          = option_rx_throttle,
202ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.unthrottle        = option_rx_unthrottle,
203ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.ioctl             = option_ioctl,
204ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.set_termios       = option_set_termios,
205ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.break_ctl         = option_break_ctl,
206ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.tiocmget          = option_tiocmget,
207ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.tiocmset          = option_tiocmset,
208ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.attach            = option_startup,
209ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.shutdown          = option_shutdown,
210ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.read_int_callback = option_instat_callback,
21158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs};
21258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
213ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#ifdef CONFIG_USB_DEBUG
21458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsstatic int debug;
215ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#else
216ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#define debug 0
217ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#endif
218ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs
21958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/* per port private data */
22058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
221ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#define N_IN_URB 4
222ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#define N_OUT_URB 1
223b27c73dcab61826e5f1228d69d56f469b0abfc05Matthias Urlichs#define IN_BUFLEN 4096
224ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#define OUT_BUFLEN 128
22558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
22658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsstruct option_port_private {
22758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Input endpoints and buffer for this port */
228ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct urb *in_urbs[N_IN_URB];
229ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	char in_buffer[N_IN_URB][IN_BUFLEN];
23058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Output endpoints and buffer for this port */
231ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct urb *out_urbs[N_OUT_URB];
232ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	char out_buffer[N_OUT_URB][OUT_BUFLEN];
23358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
23458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Settings for the port */
235ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int rts_state;	/* Handshaking pins (outputs) */
236ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int dtr_state;
237ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int cts_state;	/* Handshaking pins (inputs) */
238ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int dsr_state;
239ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int dcd_state;
240ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int ri_state;
241ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs
242ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	unsigned long tx_start_time[N_OUT_URB];
24358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs};
24458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
24558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/* Functions used by new usb-serial code. */
2467bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int __init option_init(void)
24758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
24858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int retval;
24914f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	retval = usb_serial_register(&option_1port_device);
25014f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	if (retval)
25114f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		goto failed_1port_device_register;
25258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	retval = usb_register(&option_driver);
25358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (retval)
25458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		goto failed_driver_register;
25558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
25658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	info(DRIVER_DESC ": " DRIVER_VERSION);
25758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
25858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return 0;
25958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
26058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsfailed_driver_register:
26114f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	usb_serial_deregister (&option_1port_device);
26214f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichsfailed_1port_device_register:
26358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return retval;
26458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
26558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2667bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void __exit option_exit(void)
26758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
26858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	usb_deregister (&option_driver);
26914f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	usb_serial_deregister (&option_1port_device);
27058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
27158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
27258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsmodule_init(option_init);
27358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsmodule_exit(option_exit);
27458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2757bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_rx_throttle(struct usb_serial_port *port)
27658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
27758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
27858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
27958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2807bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_rx_unthrottle(struct usb_serial_port *port)
28158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
28258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
28358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
28458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2857bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_break_ctl(struct usb_serial_port *port, int break_state)
28658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
28758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Unfortunately, I don't know how to send a break */
288ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	dbg("%s", __FUNCTION__);
28958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
29058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2917bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_set_termios(struct usb_serial_port *port,
292606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox			struct ktermios *old_termios)
29358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
29458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
29558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
29658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	option_send_setup(port);
29758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
29858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2997bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_tiocmget(struct usb_serial_port *port, struct file *file)
30058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
301ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	unsigned int value;
302ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
30358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
30458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
30558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
30658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
30758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		((portdata->dtr_state) ? TIOCM_DTR : 0) |
30858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		((portdata->cts_state) ? TIOCM_CTS : 0) |
30958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		((portdata->dsr_state) ? TIOCM_DSR : 0) |
31058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		((portdata->dcd_state) ? TIOCM_CAR : 0) |
31158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		((portdata->ri_state) ? TIOCM_RNG : 0);
31258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
31358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return value;
31458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
31558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
3167bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_tiocmset(struct usb_serial_port *port, struct file *file,
3177bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			unsigned int set, unsigned int clear)
31858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
319ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
32058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
32158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
32258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
32358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (set & TIOCM_RTS)
32458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata->rts_state = 1;
32558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (set & TIOCM_DTR)
32658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata->dtr_state = 1;
32758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
32858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (clear & TIOCM_RTS)
32958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata->rts_state = 0;
33058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (clear & TIOCM_DTR)
33158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata->dtr_state = 0;
33258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return option_send_setup(port);
33358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
33458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
3357bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_ioctl(struct usb_serial_port *port, struct file *file,
3367bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			unsigned int cmd, unsigned long arg)
33758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
33858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return -ENOIOCTLCMD;
33958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
34058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
34158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/* Write */
3427bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_write(struct usb_serial_port *port,
3437bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			const unsigned char *buf, int count)
34458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
345ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
346ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int i;
347ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int left, todo;
348ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct urb *this_urb = NULL; /* spurious */
349ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int err;
35058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
35158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
35258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
35358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s: write (%d chars)", __FUNCTION__, count);
35458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
35558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	i = 0;
35658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	left = count;
357ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	for (i=0; left > 0 && i < N_OUT_URB; i++) {
35858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		todo = left;
35958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (todo > OUT_BUFLEN)
36058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			todo = OUT_BUFLEN;
36158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
362ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs		this_urb = portdata->out_urbs[i];
363ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs		if (this_urb->status == -EINPROGRESS) {
3647bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			if (time_before(jiffies,
3657bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton					portdata->tx_start_time[i] + 10 * HZ))
36658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				continue;
36758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			usb_unlink_urb(this_urb);
368ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs			continue;
36958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
370ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs		if (this_urb->status != 0)
3717bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("usb_write %p failed (err=%d)",
3727bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				this_urb, this_urb->status);
37358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
3747bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		dbg("%s: endpoint %d buf %d", __FUNCTION__,
3757bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			usb_pipeendpoint(this_urb->pipe), i);
37658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
377ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs		/* send the data */
37858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		memcpy (this_urb->transfer_buffer, buf, todo);
37958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		this_urb->transfer_buffer_length = todo;
38058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
38158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		this_urb->dev = port->serial->dev;
38258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		err = usb_submit_urb(this_urb, GFP_ATOMIC);
38358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (err) {
3847bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("usb_submit_urb %p (write bulk) failed "
3857bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				"(%d, has %d)", this_urb,
3867bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				err, this_urb->status);
38758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			continue;
38858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
38958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata->tx_start_time[i] = jiffies;
39058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		buf += todo;
39158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		left -= todo;
39258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
39358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
39458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	count -= left;
39558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s: wrote (did %d)", __FUNCTION__, count);
39658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return count;
39758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
39858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
3997d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void option_indat_callback(struct urb *urb)
40058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
40133f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	int err;
40258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int endpoint;
40358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct usb_serial_port *port;
40458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct tty_struct *tty;
40558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	unsigned char *data = urb->transfer_buffer;
40658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
40758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s: %p", __FUNCTION__, urb);
40858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
40958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	endpoint = usb_pipeendpoint(urb->pipe);
41058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	port = (struct usb_serial_port *) urb->context;
41158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
41258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (urb->status) {
41358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		dbg("%s: nonzero status: %d on endpoint %02x.",
41458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		    __FUNCTION__, urb->status, endpoint);
41558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	} else {
41658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		tty = port->tty;
41758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (urb->actual_length) {
41833f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox			tty_buffer_request_room(tty, urb->actual_length);
41933f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox			tty_insert_flip_string(tty, data, urb->actual_length);
42058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			tty_flip_buffer_push(tty);
42158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		} else {
42258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			dbg("%s: empty read urb received", __FUNCTION__);
42358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
42458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
42558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		/* Resubmit urb so we continue receiving */
42658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (port->open_count && urb->status != -ESHUTDOWN) {
42758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			err = usb_submit_urb(urb, GFP_ATOMIC);
42858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			if (err)
4297bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				printk(KERN_ERR "%s: resubmit read urb failed. "
4307bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton					"(%d)", __FUNCTION__, err);
43158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
43258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
43358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return;
43458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
43558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
4367d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void option_outdat_callback(struct urb *urb)
43758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
43858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct usb_serial_port *port;
43958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
44058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
44158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
44258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	port = (struct usb_serial_port *) urb->context;
44358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
444cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev	usb_serial_port_softint(port);
44558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
44658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
4477d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void option_instat_callback(struct urb *urb)
44858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
44958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int err;
45058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
45158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct option_port_private *portdata = usb_get_serial_port_data(port);
45258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct usb_serial *serial = port->serial;
45358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
45458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
45558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
45658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
45758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (urb->status == 0) {
45858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		struct usb_ctrlrequest *req_pkt =
45958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				(struct usb_ctrlrequest *)urb->transfer_buffer;
46058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
46158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (!req_pkt) {
46258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			dbg("%s: NULL req_pkt\n", __FUNCTION__);
46358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			return;
46458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
4657bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		if ((req_pkt->bRequestType == 0xA1) &&
4667bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				(req_pkt->bRequest == 0x20)) {
46758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			int old_dcd_state;
46858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			unsigned char signals = *((unsigned char *)
4697bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton					urb->transfer_buffer +
4707bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton					sizeof(struct usb_ctrlrequest));
47158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
47258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			dbg("%s: signal x%x", __FUNCTION__, signals);
47358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
47458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			old_dcd_state = portdata->dcd_state;
47558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			portdata->cts_state = 1;
47658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
47758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
47858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			portdata->ri_state = ((signals & 0x08) ? 1 : 0);
47958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
4807bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			if (port->tty && !C_CLOCAL(port->tty) &&
4817bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton					old_dcd_state && !portdata->dcd_state)
48258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				tty_hangup(port->tty);
4837bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		} else {
4847bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("%s: type %x req %x", __FUNCTION__,
4857bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				req_pkt->bRequestType,req_pkt->bRequest);
4867bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		}
48758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	} else
48858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		dbg("%s: error %d", __FUNCTION__, urb->status);
48958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
49058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Resubmit urb so we continue receiving IRQ data */
49158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (urb->status != -ESHUTDOWN) {
49258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		urb->dev = serial->dev;
49358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		err = usb_submit_urb(urb, GFP_ATOMIC);
49458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (err)
4957bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("%s: resubmit intr urb failed. (%d)",
4967bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				__FUNCTION__, err);
49758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
49858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
49958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
5007bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_write_room(struct usb_serial_port *port)
50158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
50258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct option_port_private *portdata;
50358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int i;
50458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int data_len = 0;
50558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct urb *this_urb;
50658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
50758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
50858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
509ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	for (i=0; i < N_OUT_URB; i++) {
51058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		this_urb = portdata->out_urbs[i];
51158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (this_urb && this_urb->status != -EINPROGRESS)
51258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			data_len += OUT_BUFLEN;
513ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	}
51458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
51558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s: %d", __FUNCTION__, data_len);
51658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return data_len;
51758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
51858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
5197bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_chars_in_buffer(struct usb_serial_port *port)
52058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
52158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct option_port_private *portdata;
52258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int i;
52358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int data_len = 0;
52458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct urb *this_urb;
52558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
52658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
52758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
528ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	for (i=0; i < N_OUT_URB; i++) {
52958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		this_urb = portdata->out_urbs[i];
53058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (this_urb && this_urb->status == -EINPROGRESS)
53158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			data_len += this_urb->transfer_buffer_length;
532ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	}
53358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s: %d", __FUNCTION__, data_len);
53458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return data_len;
53558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
53658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
5377bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_open(struct usb_serial_port *port, struct file *filp)
53858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
539ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
540ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct usb_serial *serial = port->serial;
541ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int i, err;
542ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct urb *urb;
54358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
54458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
54558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
54658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
54758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
54858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Set some sane defaults */
54958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata->rts_state = 1;
55058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata->dtr_state = 1;
55158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
55258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Reset low level data toggle and start reading from endpoints */
55358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	for (i = 0; i < N_IN_URB; i++) {
55458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		urb = portdata->in_urbs[i];
55558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (! urb)
55658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			continue;
55758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (urb->dev != serial->dev) {
5587bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("%s: dev %p != %p", __FUNCTION__,
5597bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				urb->dev, serial->dev);
56058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			continue;
56158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
56258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
5637bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		/*
5647bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		 * make sure endpoint data toggle is synchronized with the
5657bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		 * device
5667bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		 */
56758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		usb_clear_halt(urb->dev, urb->pipe);
56858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
56958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		err = usb_submit_urb(urb, GFP_KERNEL);
57058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (err) {
5717bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("%s: submit urb %d failed (%d) %d",
5727bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				__FUNCTION__, i, err,
57358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				urb->transfer_buffer_length);
57458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
57558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
57658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
57758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Reset low level data toggle on out endpoints */
57858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	for (i = 0; i < N_OUT_URB; i++) {
57958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		urb = portdata->out_urbs[i];
58058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (! urb)
58158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			continue;
58258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		urb->dev = serial->dev;
5837bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
5847bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				usb_pipeout(urb->pipe), 0); */
58558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
58658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
58758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	port->tty->low_latency = 1;
58858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
58958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	option_send_setup(port);
59058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
59158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return (0);
59258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
59358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
5947bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_close(struct usb_serial_port *port, struct file *filp)
59558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
596ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int i;
597ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct usb_serial *serial = port->serial;
598ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
59958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
60058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
60158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
60258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
60358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata->rts_state = 0;
60458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata->dtr_state = 0;
60558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
60658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (serial->dev) {
60758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		option_send_setup(port);
60858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
60958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		/* Stop reading/writing urbs */
61058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		for (i = 0; i < N_IN_URB; i++)
6117d28e74b97c8eb859fd9f5eb018bb1c75627bd55Oliver Neukum			usb_kill_urb(portdata->in_urbs[i]);
61258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		for (i = 0; i < N_OUT_URB; i++)
6137d28e74b97c8eb859fd9f5eb018bb1c75627bd55Oliver Neukum			usb_kill_urb(portdata->out_urbs[i]);
61458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
61558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	port->tty = NULL;
61658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
61758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
61858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/* Helper functions used by option_setup_urbs */
6197bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
6207bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		int dir, void *ctx, char *buf, int len,
6217d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells		void (*callback)(struct urb *))
62258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
62358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct urb *urb;
62458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
62558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (endpoint == -1)
62658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		return NULL;		/* endpoint not needed */
62758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
62858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	urb = usb_alloc_urb(0, GFP_KERNEL);		/* No ISO */
62958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (urb == NULL) {
63058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
63158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		return NULL;
63258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
63358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
63458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		/* Fill URB using supplied data. */
63558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	usb_fill_bulk_urb(urb, serial->dev,
63658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		      usb_sndbulkpipe(serial->dev, endpoint) | dir,
63758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		      buf, len, callback, ctx);
63858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
63958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return urb;
64058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
64158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
64258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/* Setup urbs */
6437bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_setup_urbs(struct usb_serial *serial)
64458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
64514f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	int i,j;
646ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct usb_serial_port *port;
647ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
64858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
64958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
65058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
65114f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	for (i = 0; i < serial->num_ports; i++) {
65214f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		port = serial->port[i];
65314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		portdata = usb_get_serial_port_data(port);
65458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
65558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Do indat endpoints first */
65614f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		for (j = 0; j < N_IN_URB; ++j) {
65714f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs			portdata->in_urbs[j] = option_setup_urb (serial,
65814f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs                  	port->bulk_in_endpointAddress, USB_DIR_IN, port,
65914f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs                  	portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
66014f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		}
66158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
66214f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		/* outdat endpoints */
66314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		for (j = 0; j < N_OUT_URB; ++j) {
66414f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs			portdata->out_urbs[j] = option_setup_urb (serial,
66514f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs                  	port->bulk_out_endpointAddress, USB_DIR_OUT, port,
66614f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs                  	portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
66714f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		}
66858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
66958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
67058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
6717bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_send_setup(struct usb_serial_port *port)
67258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
67358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct usb_serial *serial = port->serial;
67458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct option_port_private *portdata;
67558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
67658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
67758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
6788c1527132c25512563b197b35453c7da22b4d699Miguel Angel Alvarez	if (port->number != 0)
6798c1527132c25512563b197b35453c7da22b4d699Miguel Angel Alvarez		return 0;
6808c1527132c25512563b197b35453c7da22b4d699Miguel Angel Alvarez
68158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
68258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
68358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (port->tty) {
68458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		int val = 0;
68558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (portdata->dtr_state)
68658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			val |= 0x01;
68758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (portdata->rts_state)
68858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			val |= 0x02;
68958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
6907bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		return usb_control_msg(serial->dev,
6917bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				usb_rcvctrlpipe(serial->dev, 0),
6927bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
69358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
69458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
69558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return 0;
69658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
69758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
6987bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_startup(struct usb_serial *serial)
69958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
700ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int i, err;
701ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct usb_serial_port *port;
702ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
70358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
70458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
70558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
70658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Now setup per port private data */
70758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	for (i = 0; i < serial->num_ports; i++) {
70858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		port = serial->port[i];
70980b6ca48321974a6566a1c9048ba34f60420bca6Eric Sesterhenn		portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
71058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (!portdata) {
7117bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("%s: kmalloc for option_port_private (%d) failed!.",
7127bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton					__FUNCTION__, i);
71358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			return (1);
71458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
71558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
71658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		usb_set_serial_port_data(port, portdata);
71758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
71858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (! port->interrupt_in_urb)
71958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			continue;
72058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
72158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (err)
7227bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("%s: submit irq_in urb failed %d",
7237bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				__FUNCTION__, err);
72458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
72558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
72658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	option_setup_urbs(serial);
72758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
72858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return (0);
72958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
73058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
7317bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_shutdown(struct usb_serial *serial)
73258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
733ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int i, j;
734ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct usb_serial_port *port;
735ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
73658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
73758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
73858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
73958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Stop reading/writing urbs */
74058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	for (i = 0; i < serial->num_ports; ++i) {
74158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		port = serial->port[i];
74258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata = usb_get_serial_port_data(port);
74358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		for (j = 0; j < N_IN_URB; j++)
7447d28e74b97c8eb859fd9f5eb018bb1c75627bd55Oliver Neukum			usb_kill_urb(portdata->in_urbs[j]);
74558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		for (j = 0; j < N_OUT_URB; j++)
7467d28e74b97c8eb859fd9f5eb018bb1c75627bd55Oliver Neukum			usb_kill_urb(portdata->out_urbs[j]);
74758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
74858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
74958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Now free them */
75058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	for (i = 0; i < serial->num_ports; ++i) {
75158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		port = serial->port[i];
75258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata = usb_get_serial_port_data(port);
75358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
75458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		for (j = 0; j < N_IN_URB; j++) {
75558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			if (portdata->in_urbs[j]) {
75658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				usb_free_urb(portdata->in_urbs[j]);
75758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				portdata->in_urbs[j] = NULL;
75858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			}
75958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
76058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		for (j = 0; j < N_OUT_URB; j++) {
76158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			if (portdata->out_urbs[j]) {
76258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				usb_free_urb(portdata->out_urbs[j]);
76358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				portdata->out_urbs[j] = NULL;
76458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			}
76558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
76658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
76758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
76858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Now free per port private data */
76958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	for (i = 0; i < serial->num_ports; i++) {
77058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		port = serial->port[i];
77158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		kfree(usb_get_serial_port_data(port));
77258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
77358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
77458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
77558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias UrlichsMODULE_AUTHOR(DRIVER_AUTHOR);
77658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias UrlichsMODULE_DESCRIPTION(DRIVER_DESC);
77758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias UrlichsMODULE_VERSION(DRIVER_VERSION);
77858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias UrlichsMODULE_LICENSE("GPL");
77958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
780ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#ifdef CONFIG_USB_DEBUG
78158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsmodule_param(debug, bool, S_IRUGO | S_IWUSR);
78258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias UrlichsMODULE_PARM_DESC(debug, "Debug messages");
783ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#endif
78458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
785