option.c revision ab1958905514da3b6c06d61523ebed142a16cc72
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 */
7014f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs#define OPTION_VENDOR_ID                0x0AF0
7114f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs#define HUAWEI_VENDOR_ID                0x12D1
7214f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs#define AUDIOVOX_VENDOR_ID              0x0F3D
7314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs#define NOVATELWIRELESS_VENDOR_ID       0x1410
7431fcbb733812bca52e8bee96d62ba56df0fc408bMatthias Urlichs#define ANYDATA_VENDOR_ID               0x16d5
7514f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs
7614f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs#define OPTION_PRODUCT_OLD              0x5000
7714f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs#define OPTION_PRODUCT_FUSION           0x6000
7814f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs#define OPTION_PRODUCT_FUSION2          0x6300
7914f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs#define OPTION_PRODUCT_COBRA            0x6500
80e37de9e0d6591706a76cff63582cbc721c317333Matthias Urlichs#define OPTION_PRODUCT_COBRA2           0x6600
8114f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs#define HUAWEI_PRODUCT_E600             0x1001
82ab1958905514da3b6c06d61523ebed142a16cc72Johann Wilhelm#define HUAWEI_PRODUCT_E220             0x1003
8314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs#define AUDIOVOX_PRODUCT_AIRCARD        0x0112
8414f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs#define NOVATELWIRELESS_PRODUCT_U740    0x1400
8531fcbb733812bca52e8bee96d62ba56df0fc408bMatthias Urlichs#define ANYDATA_PRODUCT_ID              0x6501
8658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
8758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsstatic struct usb_device_id option_ids[] = {
8858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
89ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
90ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
9114f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
92e37de9e0d6591706a76cff63582cbc721c317333Matthias Urlichs	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
93b6137383bda844a433d65e027502df7b20ba45c2Matthias Urlichs	{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
94ab1958905514da3b6c06d61523ebed142a16cc72Johann Wilhelm	{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
95b6137383bda844a433d65e027502df7b20ba45c2Matthias Urlichs	{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
9614f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
9731fcbb733812bca52e8bee96d62ba56df0fc408bMatthias Urlichs	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
9814f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ } /* Terminating entry */
9914f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs};
10014f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs
10114f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichsstatic struct usb_device_id option_ids1[] = {
10214f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
10314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
10414f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
10514f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
106e37de9e0d6591706a76cff63582cbc721c317333Matthias Urlichs	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
10714f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
108ab1958905514da3b6c06d61523ebed142a16cc72Johann Wilhelm	{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
10914f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
11014f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
11131fcbb733812bca52e8bee96d62ba56df0fc408bMatthias Urlichs	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
11214f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	{ } /* Terminating entry */
11314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs};
11458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
11558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias UrlichsMODULE_DEVICE_TABLE(usb, option_ids);
11658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
11758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsstatic struct usb_driver option_driver = {
11858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	.name       = "option",
11958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	.probe      = usb_serial_probe,
12058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	.disconnect = usb_serial_disconnect,
12158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	.id_table   = option_ids,
122ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman	.no_dynamic_id = 	1,
12358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs};
12458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
125c30fe7f73194650148b58ee80908c1bc38246397Uwe Zeisberger/* The card has three separate interfaces, which the serial driver
12658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs * recognizes separately, thus num_port=1.
12758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs */
12814f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs
12914f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichsstatic struct usb_serial_driver option_1port_device = {
13014f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	.driver = {
13114f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		.owner =	THIS_MODULE,
13202b2ac5b0370b1157a5a99f2fdf006644b9b86d5Matthias Urlichs		.name =		"option1",
13314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	},
13414f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	.description       = "GSM modem (1-port)",
13514f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	.id_table          = option_ids1,
136ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.num_interrupt_in  = NUM_DONT_CARE,
137ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.num_bulk_in       = NUM_DONT_CARE,
138ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.num_bulk_out      = NUM_DONT_CARE,
13914f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	.num_ports         = 1,
140ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.open              = option_open,
141ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.close             = option_close,
142ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.write             = option_write,
143ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.write_room        = option_write_room,
144ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.chars_in_buffer   = option_chars_in_buffer,
145ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.throttle          = option_rx_throttle,
146ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.unthrottle        = option_rx_unthrottle,
147ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.ioctl             = option_ioctl,
148ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.set_termios       = option_set_termios,
149ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.break_ctl         = option_break_ctl,
150ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.tiocmget          = option_tiocmget,
151ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.tiocmset          = option_tiocmset,
152ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.attach            = option_startup,
153ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.shutdown          = option_shutdown,
154ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	.read_int_callback = option_instat_callback,
15558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs};
15658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
157ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#ifdef CONFIG_USB_DEBUG
15858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsstatic int debug;
159ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#else
160ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#define debug 0
161ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#endif
162ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs
16358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/* per port private data */
16458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
165ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#define N_IN_URB 4
166ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#define N_OUT_URB 1
167b27c73dcab61826e5f1228d69d56f469b0abfc05Matthias Urlichs#define IN_BUFLEN 4096
168ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#define OUT_BUFLEN 128
16958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
17058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsstruct option_port_private {
17158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Input endpoints and buffer for this port */
172ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct urb *in_urbs[N_IN_URB];
173ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	char in_buffer[N_IN_URB][IN_BUFLEN];
17458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Output endpoints and buffer for this port */
175ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct urb *out_urbs[N_OUT_URB];
176ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	char out_buffer[N_OUT_URB][OUT_BUFLEN];
17758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
17858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Settings for the port */
179ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int rts_state;	/* Handshaking pins (outputs) */
180ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int dtr_state;
181ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int cts_state;	/* Handshaking pins (inputs) */
182ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int dsr_state;
183ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int dcd_state;
184ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int ri_state;
185ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs
186ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	unsigned long tx_start_time[N_OUT_URB];
18758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs};
18858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
18958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/* Functions used by new usb-serial code. */
1907bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int __init option_init(void)
19158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
19258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int retval;
19314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	retval = usb_serial_register(&option_1port_device);
19414f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	if (retval)
19514f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		goto failed_1port_device_register;
19658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	retval = usb_register(&option_driver);
19758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (retval)
19858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		goto failed_driver_register;
19958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
20058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	info(DRIVER_DESC ": " DRIVER_VERSION);
20158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
20258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return 0;
20358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
20458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsfailed_driver_register:
20514f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	usb_serial_deregister (&option_1port_device);
20614f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichsfailed_1port_device_register:
20758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return retval;
20858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
20958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2107bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void __exit option_exit(void)
21158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
21258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	usb_deregister (&option_driver);
21314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	usb_serial_deregister (&option_1port_device);
21458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
21558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
21658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsmodule_init(option_init);
21758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsmodule_exit(option_exit);
21858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2197bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_rx_throttle(struct usb_serial_port *port)
22058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
22158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
22258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
22358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2247bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_rx_unthrottle(struct usb_serial_port *port)
22558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
22658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
22758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
22858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2297bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_break_ctl(struct usb_serial_port *port, int break_state)
23058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
23158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Unfortunately, I don't know how to send a break */
232ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	dbg("%s", __FUNCTION__);
23358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
23458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2357bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_set_termios(struct usb_serial_port *port,
236606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox			struct ktermios *old_termios)
23758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
23858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
23958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
24058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	option_send_setup(port);
24158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
24258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2437bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_tiocmget(struct usb_serial_port *port, struct file *file)
24458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
245ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	unsigned int value;
246ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
24758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
24858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
24958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
25058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
25158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		((portdata->dtr_state) ? TIOCM_DTR : 0) |
25258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		((portdata->cts_state) ? TIOCM_CTS : 0) |
25358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		((portdata->dsr_state) ? TIOCM_DSR : 0) |
25458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		((portdata->dcd_state) ? TIOCM_CAR : 0) |
25558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		((portdata->ri_state) ? TIOCM_RNG : 0);
25658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
25758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return value;
25858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
25958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2607bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_tiocmset(struct usb_serial_port *port, struct file *file,
2617bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			unsigned int set, unsigned int clear)
26258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
263ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
26458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
26558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
26658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
26758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (set & TIOCM_RTS)
26858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata->rts_state = 1;
26958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (set & TIOCM_DTR)
27058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata->dtr_state = 1;
27158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
27258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (clear & TIOCM_RTS)
27358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata->rts_state = 0;
27458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (clear & TIOCM_DTR)
27558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata->dtr_state = 0;
27658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return option_send_setup(port);
27758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
27858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
2797bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_ioctl(struct usb_serial_port *port, struct file *file,
2807bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			unsigned int cmd, unsigned long arg)
28158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
28258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return -ENOIOCTLCMD;
28358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
28458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
28558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/* Write */
2867bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_write(struct usb_serial_port *port,
2877bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			const unsigned char *buf, int count)
28858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
289ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
290ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int i;
291ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int left, todo;
292ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct urb *this_urb = NULL; /* spurious */
293ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int err;
29458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
29558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
29658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
29758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s: write (%d chars)", __FUNCTION__, count);
29858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
29958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	i = 0;
30058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	left = count;
301ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	for (i=0; left > 0 && i < N_OUT_URB; i++) {
30258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		todo = left;
30358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (todo > OUT_BUFLEN)
30458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			todo = OUT_BUFLEN;
30558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
306ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs		this_urb = portdata->out_urbs[i];
307ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs		if (this_urb->status == -EINPROGRESS) {
3087bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			if (time_before(jiffies,
3097bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton					portdata->tx_start_time[i] + 10 * HZ))
31058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				continue;
31158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			usb_unlink_urb(this_urb);
312ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs			continue;
31358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
314ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs		if (this_urb->status != 0)
3157bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("usb_write %p failed (err=%d)",
3167bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				this_urb, this_urb->status);
31758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
3187bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		dbg("%s: endpoint %d buf %d", __FUNCTION__,
3197bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			usb_pipeendpoint(this_urb->pipe), i);
32058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
321ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs		/* send the data */
32258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		memcpy (this_urb->transfer_buffer, buf, todo);
32358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		this_urb->transfer_buffer_length = todo;
32458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
32558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		this_urb->dev = port->serial->dev;
32658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		err = usb_submit_urb(this_urb, GFP_ATOMIC);
32758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (err) {
3287bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("usb_submit_urb %p (write bulk) failed "
3297bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				"(%d, has %d)", this_urb,
3307bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				err, this_urb->status);
33158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			continue;
33258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
33358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata->tx_start_time[i] = jiffies;
33458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		buf += todo;
33558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		left -= todo;
33658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
33758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
33858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	count -= left;
33958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s: wrote (did %d)", __FUNCTION__, count);
34058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return count;
34158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
34258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
3437d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void option_indat_callback(struct urb *urb)
34458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
34533f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox	int err;
34658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int endpoint;
34758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct usb_serial_port *port;
34858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct tty_struct *tty;
34958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	unsigned char *data = urb->transfer_buffer;
35058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
35158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s: %p", __FUNCTION__, urb);
35258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
35358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	endpoint = usb_pipeendpoint(urb->pipe);
35458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	port = (struct usb_serial_port *) urb->context;
35558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
35658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (urb->status) {
35758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		dbg("%s: nonzero status: %d on endpoint %02x.",
35858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		    __FUNCTION__, urb->status, endpoint);
35958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	} else {
36058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		tty = port->tty;
36158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (urb->actual_length) {
36233f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox			tty_buffer_request_room(tty, urb->actual_length);
36333f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox			tty_insert_flip_string(tty, data, urb->actual_length);
36458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			tty_flip_buffer_push(tty);
36558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		} else {
36658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			dbg("%s: empty read urb received", __FUNCTION__);
36758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
36858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
36958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		/* Resubmit urb so we continue receiving */
37058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (port->open_count && urb->status != -ESHUTDOWN) {
37158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			err = usb_submit_urb(urb, GFP_ATOMIC);
37258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			if (err)
3737bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				printk(KERN_ERR "%s: resubmit read urb failed. "
3747bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton					"(%d)", __FUNCTION__, err);
37558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
37658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
37758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return;
37858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
37958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
3807d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void option_outdat_callback(struct urb *urb)
38158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
38258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct usb_serial_port *port;
38358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
38458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
38558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
38658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	port = (struct usb_serial_port *) urb->context;
38758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
388cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev	usb_serial_port_softint(port);
38958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
39058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
3917d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void option_instat_callback(struct urb *urb)
39258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
39358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int err;
39458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
39558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct option_port_private *portdata = usb_get_serial_port_data(port);
39658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct usb_serial *serial = port->serial;
39758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
39858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
39958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
40058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
40158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (urb->status == 0) {
40258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		struct usb_ctrlrequest *req_pkt =
40358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				(struct usb_ctrlrequest *)urb->transfer_buffer;
40458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
40558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (!req_pkt) {
40658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			dbg("%s: NULL req_pkt\n", __FUNCTION__);
40758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			return;
40858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
4097bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		if ((req_pkt->bRequestType == 0xA1) &&
4107bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				(req_pkt->bRequest == 0x20)) {
41158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			int old_dcd_state;
41258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			unsigned char signals = *((unsigned char *)
4137bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton					urb->transfer_buffer +
4147bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton					sizeof(struct usb_ctrlrequest));
41558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
41658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			dbg("%s: signal x%x", __FUNCTION__, signals);
41758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
41858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			old_dcd_state = portdata->dcd_state;
41958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			portdata->cts_state = 1;
42058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
42158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
42258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			portdata->ri_state = ((signals & 0x08) ? 1 : 0);
42358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
4247bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			if (port->tty && !C_CLOCAL(port->tty) &&
4257bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton					old_dcd_state && !portdata->dcd_state)
42658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				tty_hangup(port->tty);
4277bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		} else {
4287bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("%s: type %x req %x", __FUNCTION__,
4297bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				req_pkt->bRequestType,req_pkt->bRequest);
4307bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		}
43158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	} else
43258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		dbg("%s: error %d", __FUNCTION__, urb->status);
43358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
43458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Resubmit urb so we continue receiving IRQ data */
43558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (urb->status != -ESHUTDOWN) {
43658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		urb->dev = serial->dev;
43758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		err = usb_submit_urb(urb, GFP_ATOMIC);
43858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (err)
4397bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("%s: resubmit intr urb failed. (%d)",
4407bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				__FUNCTION__, err);
44158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
44258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
44358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
4447bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_write_room(struct usb_serial_port *port)
44558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
44658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct option_port_private *portdata;
44758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int i;
44858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int data_len = 0;
44958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct urb *this_urb;
45058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
45158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
45258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
453ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	for (i=0; i < N_OUT_URB; i++) {
45458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		this_urb = portdata->out_urbs[i];
45558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (this_urb && this_urb->status != -EINPROGRESS)
45658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			data_len += OUT_BUFLEN;
457ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	}
45858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
45958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s: %d", __FUNCTION__, data_len);
46058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return data_len;
46158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
46258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
4637bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_chars_in_buffer(struct usb_serial_port *port)
46458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
46558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct option_port_private *portdata;
46658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int i;
46758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	int data_len = 0;
46858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct urb *this_urb;
46958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
47058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
47158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
472ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	for (i=0; i < N_OUT_URB; i++) {
47358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		this_urb = portdata->out_urbs[i];
47458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (this_urb && this_urb->status == -EINPROGRESS)
47558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			data_len += this_urb->transfer_buffer_length;
476ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	}
47758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s: %d", __FUNCTION__, data_len);
47858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return data_len;
47958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
48058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
4817bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_open(struct usb_serial_port *port, struct file *filp)
48258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
483ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
484ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct usb_serial *serial = port->serial;
485ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int i, err;
486ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct urb *urb;
48758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
48858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
48958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
49058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
49158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
49258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Set some sane defaults */
49358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata->rts_state = 1;
49458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata->dtr_state = 1;
49558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
49658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Reset low level data toggle and start reading from endpoints */
49758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	for (i = 0; i < N_IN_URB; i++) {
49858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		urb = portdata->in_urbs[i];
49958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (! urb)
50058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			continue;
50158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (urb->dev != serial->dev) {
5027bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("%s: dev %p != %p", __FUNCTION__,
5037bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				urb->dev, serial->dev);
50458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			continue;
50558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
50658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
5077bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		/*
5087bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		 * make sure endpoint data toggle is synchronized with the
5097bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		 * device
5107bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		 */
51158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		usb_clear_halt(urb->dev, urb->pipe);
51258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
51358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		err = usb_submit_urb(urb, GFP_KERNEL);
51458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (err) {
5157bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("%s: submit urb %d failed (%d) %d",
5167bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				__FUNCTION__, i, err,
51758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				urb->transfer_buffer_length);
51858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
51958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
52058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
52158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Reset low level data toggle on out endpoints */
52258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	for (i = 0; i < N_OUT_URB; i++) {
52358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		urb = portdata->out_urbs[i];
52458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (! urb)
52558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			continue;
52658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		urb->dev = serial->dev;
5277bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
5287bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				usb_pipeout(urb->pipe), 0); */
52958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
53058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
53158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	port->tty->low_latency = 1;
53258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
53358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	option_send_setup(port);
53458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
53558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return (0);
53658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
53758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
5387bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic inline void stop_urb(struct urb *urb)
53958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
540242cf670c09c05504ce53dfc27f8331a072f169dGreg Kroah-Hartman	if (urb && urb->status == -EINPROGRESS)
54158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		usb_kill_urb(urb);
54258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
54358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
5447bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_close(struct usb_serial_port *port, struct file *filp)
54558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
546ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int i;
547ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct usb_serial *serial = port->serial;
548ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
54958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
55058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
55158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
55258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
55358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata->rts_state = 0;
55458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata->dtr_state = 0;
55558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
55658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (serial->dev) {
55758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		option_send_setup(port);
55858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
55958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		/* Stop reading/writing urbs */
56058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		for (i = 0; i < N_IN_URB; i++)
56158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			stop_urb(portdata->in_urbs[i]);
56258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		for (i = 0; i < N_OUT_URB; i++)
56358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			stop_urb(portdata->out_urbs[i]);
56458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
56558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	port->tty = NULL;
56658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
56758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
56858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/* Helper functions used by option_setup_urbs */
5697bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
5707bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		int dir, void *ctx, char *buf, int len,
5717d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells		void (*callback)(struct urb *))
57258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
57358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct urb *urb;
57458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
57558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (endpoint == -1)
57658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		return NULL;		/* endpoint not needed */
57758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
57858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	urb = usb_alloc_urb(0, GFP_KERNEL);		/* No ISO */
57958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (urb == NULL) {
58058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
58158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		return NULL;
58258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
58358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
58458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		/* Fill URB using supplied data. */
58558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	usb_fill_bulk_urb(urb, serial->dev,
58658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		      usb_sndbulkpipe(serial->dev, endpoint) | dir,
58758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		      buf, len, callback, ctx);
58858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
58958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return urb;
59058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
59158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
59258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs/* Setup urbs */
5937bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_setup_urbs(struct usb_serial *serial)
59458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
59514f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	int i,j;
596ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct usb_serial_port *port;
597ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
59858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
59958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
60058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
60114f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs	for (i = 0; i < serial->num_ports; i++) {
60214f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		port = serial->port[i];
60314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		portdata = usb_get_serial_port_data(port);
60458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
60558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Do indat endpoints first */
60614f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		for (j = 0; j < N_IN_URB; ++j) {
60714f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs			portdata->in_urbs[j] = option_setup_urb (serial,
60814f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs                  	port->bulk_in_endpointAddress, USB_DIR_IN, port,
60914f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs                  	portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
61014f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		}
61158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
61214f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		/* outdat endpoints */
61314f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		for (j = 0; j < N_OUT_URB; ++j) {
61414f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs			portdata->out_urbs[j] = option_setup_urb (serial,
61514f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs                  	port->bulk_out_endpointAddress, USB_DIR_OUT, port,
61614f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs                  	portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
61714f76cc7ab75b1c9db036dcd6b247e0dcc8952beMatthias Urlichs		}
61858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
61958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
62058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
6217bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_send_setup(struct usb_serial_port *port)
62258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
62358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct usb_serial *serial = port->serial;
62458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	struct option_port_private *portdata;
62558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
62658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
62758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
62858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	portdata = usb_get_serial_port_data(port);
62958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
63058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	if (port->tty) {
63158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		int val = 0;
63258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (portdata->dtr_state)
63358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			val |= 0x01;
63458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (portdata->rts_state)
63558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			val |= 0x02;
63658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
6377bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton		return usb_control_msg(serial->dev,
6387bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				usb_rcvctrlpipe(serial->dev, 0),
6397bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
64058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
64158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
64258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return 0;
64358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
64458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
6457bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic int option_startup(struct usb_serial *serial)
64658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
647ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int i, err;
648ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct usb_serial_port *port;
649ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
65058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
65158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
65258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
65358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Now setup per port private data */
65458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	for (i = 0; i < serial->num_ports; i++) {
65558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		port = serial->port[i];
65680b6ca48321974a6566a1c9048ba34f60420bca6Eric Sesterhenn		portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
65758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (!portdata) {
6587bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("%s: kmalloc for option_port_private (%d) failed!.",
6597bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton					__FUNCTION__, i);
66058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			return (1);
66158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
66258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
66358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		usb_set_serial_port_data(port, portdata);
66458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
66558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (! port->interrupt_in_urb)
66658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			continue;
66758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
66858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		if (err)
6697bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton			dbg("%s: submit irq_in urb failed %d",
6707bb75aeeeec7417a961920b3f63a83007475260fAndrew Morton				__FUNCTION__, err);
67158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
67258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
67358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	option_setup_urbs(serial);
67458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
67558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	return (0);
67658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
67758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
6787bb75aeeeec7417a961920b3f63a83007475260fAndrew Mortonstatic void option_shutdown(struct usb_serial *serial)
67958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs{
680ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	int i, j;
681ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct usb_serial_port *port;
682ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs	struct option_port_private *portdata;
68358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
68458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	dbg("%s", __FUNCTION__);
68558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
68658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Stop reading/writing urbs */
68758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	for (i = 0; i < serial->num_ports; ++i) {
68858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		port = serial->port[i];
68958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata = usb_get_serial_port_data(port);
69058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		for (j = 0; j < N_IN_URB; j++)
69158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			stop_urb(portdata->in_urbs[j]);
69258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		for (j = 0; j < N_OUT_URB; j++)
69358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			stop_urb(portdata->out_urbs[j]);
69458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
69558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
69658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Now free them */
69758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	for (i = 0; i < serial->num_ports; ++i) {
69858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		port = serial->port[i];
69958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		portdata = usb_get_serial_port_data(port);
70058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
70158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		for (j = 0; j < N_IN_URB; j++) {
70258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			if (portdata->in_urbs[j]) {
70358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				usb_free_urb(portdata->in_urbs[j]);
70458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				portdata->in_urbs[j] = NULL;
70558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			}
70658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
70758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		for (j = 0; j < N_OUT_URB; j++) {
70858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			if (portdata->out_urbs[j]) {
70958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				usb_free_urb(portdata->out_urbs[j]);
71058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs				portdata->out_urbs[j] = NULL;
71158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs			}
71258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		}
71358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
71458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
71558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	/* Now free per port private data */
71658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	for (i = 0; i < serial->num_ports; i++) {
71758cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		port = serial->port[i];
71858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs		kfree(usb_get_serial_port_data(port));
71958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs	}
72058cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs}
72158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
72258cfe9113e485f7e04bd0eac4fc4251b330af501Matthias UrlichsMODULE_AUTHOR(DRIVER_AUTHOR);
72358cfe9113e485f7e04bd0eac4fc4251b330af501Matthias UrlichsMODULE_DESCRIPTION(DRIVER_DESC);
72458cfe9113e485f7e04bd0eac4fc4251b330af501Matthias UrlichsMODULE_VERSION(DRIVER_VERSION);
72558cfe9113e485f7e04bd0eac4fc4251b330af501Matthias UrlichsMODULE_LICENSE("GPL");
72658cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
727ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#ifdef CONFIG_USB_DEBUG
72858cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichsmodule_param(debug, bool, S_IRUGO | S_IWUSR);
72958cfe9113e485f7e04bd0eac4fc4251b330af501Matthias UrlichsMODULE_PARM_DESC(debug, "Debug messages");
730ba460e48064edeb57e3398eb8972c58de33f11eaMatthias Urlichs#endif
73158cfe9113e485f7e04bd0eac4fc4251b330af501Matthias Urlichs
732