xref: /linux/drivers/usb/serial/keyspan.c (revision f6d47fe5921a6d3f5a1a3d0b9a3dd34b8e295722)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds   Keyspan USB to Serial Converter driver
41da177e4SLinus Torvalds 
51da177e4SLinus Torvalds   (C) Copyright (C) 2000-2001	Hugh Blemings <hugh@blemings.org>
61da177e4SLinus Torvalds   (C) Copyright (C) 2002	Greg Kroah-Hartman <greg@kroah.com>
71da177e4SLinus Torvalds 
8631dd1a8SJustin P. Mattock   See http://blemings.org/hugh/keyspan.html for more information.
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds   Code in this driver inspired by and in a number of places taken
111da177e4SLinus Torvalds   from Brian Warner's original Keyspan-PDA driver.
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds   This driver has been put together with the support of Innosys, Inc.
141da177e4SLinus Torvalds   and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
151da177e4SLinus Torvalds   Thanks Guys :)
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds   Thanks to Paulus for miscellaneous tidy ups, some largish chunks
181da177e4SLinus Torvalds   of much nicer and/or completely new code and (perhaps most uniquely)
191da177e4SLinus Torvalds   having the patience to sit down and explain why and where he'd changed
201da177e4SLinus Torvalds   stuff.
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds   Tip 'o the hat to IBM (and previously Linuxcare :) for supporting
231da177e4SLinus Torvalds   staff in their work on open source projects.
241da177e4SLinus Torvalds */
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds #include <linux/kernel.h>
281da177e4SLinus Torvalds #include <linux/jiffies.h>
291da177e4SLinus Torvalds #include <linux/errno.h>
301da177e4SLinus Torvalds #include <linux/slab.h>
311da177e4SLinus Torvalds #include <linux/tty.h>
321da177e4SLinus Torvalds #include <linux/tty_driver.h>
331da177e4SLinus Torvalds #include <linux/tty_flip.h>
341da177e4SLinus Torvalds #include <linux/module.h>
351da177e4SLinus Torvalds #include <linux/spinlock.h>
36deb91685SAlan Cox #include <linux/uaccess.h>
371da177e4SLinus Torvalds #include <linux/usb.h>
38a969888cSGreg Kroah-Hartman #include <linux/usb/serial.h>
39cc183e2aSRene Buergel #include <linux/usb/ezusb.h>
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds #define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
421da177e4SLinus Torvalds #define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
431da177e4SLinus Torvalds 
44beabdc3cSJohan Hovold static void keyspan_send_setup(struct usb_serial_port *port, int reset_port);
45beabdc3cSJohan Hovold 
46beabdc3cSJohan Hovold static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
47beabdc3cSJohan Hovold 				   u32 baud_rate, u32 baudclk,
48beabdc3cSJohan Hovold 				   u8 *rate_hi, u8 *rate_low,
49beabdc3cSJohan Hovold 				   u8 *prescaler, int portnum);
50beabdc3cSJohan Hovold static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
51beabdc3cSJohan Hovold 				    u32 baud_rate, u32 baudclk,
52beabdc3cSJohan Hovold 				    u8 *rate_hi, u8 *rate_low,
53beabdc3cSJohan Hovold 				    u8 *prescaler, int portnum);
54beabdc3cSJohan Hovold static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
55beabdc3cSJohan Hovold 				   u32 baud_rate, u32 baudclk,
56beabdc3cSJohan Hovold 				   u8 *rate_hi, u8 *rate_low,
57beabdc3cSJohan Hovold 				   u8 *prescaler, int portnum);
58beabdc3cSJohan Hovold static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
59beabdc3cSJohan Hovold 				     u32 baud_rate, u32 baudclk,
60beabdc3cSJohan Hovold 				     u8 *rate_hi, u8 *rate_low,
61beabdc3cSJohan Hovold 				     u8 *prescaler, int portnum);
62beabdc3cSJohan Hovold 
63beabdc3cSJohan Hovold static int keyspan_usa28_send_setup(struct usb_serial *serial,
64beabdc3cSJohan Hovold 				    struct usb_serial_port *port,
65beabdc3cSJohan Hovold 				    int reset_port);
66beabdc3cSJohan Hovold static int keyspan_usa26_send_setup(struct usb_serial *serial,
67beabdc3cSJohan Hovold 				    struct usb_serial_port *port,
68beabdc3cSJohan Hovold 				    int reset_port);
69beabdc3cSJohan Hovold static int keyspan_usa49_send_setup(struct usb_serial *serial,
70beabdc3cSJohan Hovold 				    struct usb_serial_port *port,
71beabdc3cSJohan Hovold 				    int reset_port);
72beabdc3cSJohan Hovold static int keyspan_usa90_send_setup(struct usb_serial *serial,
73beabdc3cSJohan Hovold 				    struct usb_serial_port *port,
74beabdc3cSJohan Hovold 				    int reset_port);
75beabdc3cSJohan Hovold static int keyspan_usa67_send_setup(struct usb_serial *serial,
76beabdc3cSJohan Hovold 				    struct usb_serial_port *port,
77beabdc3cSJohan Hovold 				    int reset_port);
78beabdc3cSJohan Hovold 
79beabdc3cSJohan Hovold /* Values used for baud rate calculation - device specific */
80beabdc3cSJohan Hovold #define KEYSPAN_INVALID_BAUD_RATE		(-1)
81beabdc3cSJohan Hovold #define KEYSPAN_BAUD_RATE_OK			(0)
82beabdc3cSJohan Hovold #define KEYSPAN_USA18X_BAUDCLK			(12000000L)	/* a guess */
83beabdc3cSJohan Hovold #define KEYSPAN_USA19_BAUDCLK			(12000000L)
84beabdc3cSJohan Hovold #define KEYSPAN_USA19W_BAUDCLK			(24000000L)
85beabdc3cSJohan Hovold #define KEYSPAN_USA19HS_BAUDCLK			(14769231L)
86beabdc3cSJohan Hovold #define KEYSPAN_USA28_BAUDCLK			(1843200L)
87beabdc3cSJohan Hovold #define KEYSPAN_USA28X_BAUDCLK			(12000000L)
88beabdc3cSJohan Hovold #define KEYSPAN_USA49W_BAUDCLK			(48000000L)
89beabdc3cSJohan Hovold 
90beabdc3cSJohan Hovold /* Some constants used to characterise each device.  */
91beabdc3cSJohan Hovold #define KEYSPAN_MAX_NUM_PORTS			(4)
92beabdc3cSJohan Hovold #define KEYSPAN_MAX_FLIPS			(2)
93beabdc3cSJohan Hovold 
94beabdc3cSJohan Hovold /*
95beabdc3cSJohan Hovold  * Device info for the Keyspan serial converter, used by the overall
96beabdc3cSJohan Hovold  * usb-serial probe function.
97beabdc3cSJohan Hovold  */
98beabdc3cSJohan Hovold #define KEYSPAN_VENDOR_ID			(0x06cd)
99beabdc3cSJohan Hovold 
100beabdc3cSJohan Hovold /* Product IDs for the products supported, pre-renumeration */
101beabdc3cSJohan Hovold #define keyspan_usa18x_pre_product_id		0x0105
102beabdc3cSJohan Hovold #define keyspan_usa19_pre_product_id		0x0103
103beabdc3cSJohan Hovold #define keyspan_usa19qi_pre_product_id		0x010b
104beabdc3cSJohan Hovold #define keyspan_mpr_pre_product_id		0x011b
105beabdc3cSJohan Hovold #define keyspan_usa19qw_pre_product_id		0x0118
106beabdc3cSJohan Hovold #define keyspan_usa19w_pre_product_id		0x0106
107beabdc3cSJohan Hovold #define keyspan_usa28_pre_product_id		0x0101
108beabdc3cSJohan Hovold #define keyspan_usa28x_pre_product_id		0x0102
109beabdc3cSJohan Hovold #define keyspan_usa28xa_pre_product_id		0x0114
110beabdc3cSJohan Hovold #define keyspan_usa28xb_pre_product_id		0x0113
111beabdc3cSJohan Hovold #define keyspan_usa49w_pre_product_id		0x0109
112beabdc3cSJohan Hovold #define keyspan_usa49wlc_pre_product_id		0x011a
113beabdc3cSJohan Hovold 
114beabdc3cSJohan Hovold /*
115beabdc3cSJohan Hovold  * Product IDs post-renumeration.  Note that the 28x and 28xb have the same
116beabdc3cSJohan Hovold  * id's post-renumeration but behave identically so it's not an issue. As
117beabdc3cSJohan Hovold  * such, the 28xb is not listed in any of the device tables.
118beabdc3cSJohan Hovold  */
119beabdc3cSJohan Hovold #define keyspan_usa18x_product_id		0x0112
120beabdc3cSJohan Hovold #define keyspan_usa19_product_id		0x0107
121beabdc3cSJohan Hovold #define keyspan_usa19qi_product_id		0x010c
122beabdc3cSJohan Hovold #define keyspan_usa19hs_product_id		0x0121
123beabdc3cSJohan Hovold #define keyspan_mpr_product_id			0x011c
124beabdc3cSJohan Hovold #define keyspan_usa19qw_product_id		0x0119
125beabdc3cSJohan Hovold #define keyspan_usa19w_product_id		0x0108
126beabdc3cSJohan Hovold #define keyspan_usa28_product_id		0x010f
127beabdc3cSJohan Hovold #define keyspan_usa28x_product_id		0x0110
128beabdc3cSJohan Hovold #define keyspan_usa28xa_product_id		0x0115
129beabdc3cSJohan Hovold #define keyspan_usa28xb_product_id		0x0110
130beabdc3cSJohan Hovold #define keyspan_usa28xg_product_id		0x0135
131beabdc3cSJohan Hovold #define keyspan_usa49w_product_id		0x010a
132beabdc3cSJohan Hovold #define keyspan_usa49wlc_product_id		0x012a
133beabdc3cSJohan Hovold #define keyspan_usa49wg_product_id		0x0131
134beabdc3cSJohan Hovold 
135beabdc3cSJohan Hovold struct keyspan_device_details {
136beabdc3cSJohan Hovold 	/* product ID value */
137beabdc3cSJohan Hovold 	int	product_id;
138beabdc3cSJohan Hovold 
139beabdc3cSJohan Hovold 	enum	{msg_usa26, msg_usa28, msg_usa49, msg_usa90, msg_usa67} msg_format;
140beabdc3cSJohan Hovold 
141beabdc3cSJohan Hovold 		/* Number of physical ports */
142beabdc3cSJohan Hovold 	int	num_ports;
143beabdc3cSJohan Hovold 
144beabdc3cSJohan Hovold 		/* 1 if endpoint flipping used on input, 0 if not */
145beabdc3cSJohan Hovold 	int	indat_endp_flip;
146beabdc3cSJohan Hovold 
147beabdc3cSJohan Hovold 		/* 1 if endpoint flipping used on output, 0 if not */
148beabdc3cSJohan Hovold 	int	outdat_endp_flip;
149beabdc3cSJohan Hovold 
150beabdc3cSJohan Hovold 		/*
151beabdc3cSJohan Hovold 		 * Table mapping input data endpoint IDs to physical port
152beabdc3cSJohan Hovold 		 * number and flip if used
153beabdc3cSJohan Hovold 		 */
154beabdc3cSJohan Hovold 	int	indat_endpoints[KEYSPAN_MAX_NUM_PORTS];
155beabdc3cSJohan Hovold 
156beabdc3cSJohan Hovold 		/* Same for output endpoints */
157beabdc3cSJohan Hovold 	int	outdat_endpoints[KEYSPAN_MAX_NUM_PORTS];
158beabdc3cSJohan Hovold 
159beabdc3cSJohan Hovold 		/* Input acknowledge endpoints */
160beabdc3cSJohan Hovold 	int	inack_endpoints[KEYSPAN_MAX_NUM_PORTS];
161beabdc3cSJohan Hovold 
162beabdc3cSJohan Hovold 		/* Output control endpoints */
163beabdc3cSJohan Hovold 	int	outcont_endpoints[KEYSPAN_MAX_NUM_PORTS];
164beabdc3cSJohan Hovold 
165beabdc3cSJohan Hovold 		/* Endpoint used for input status */
166beabdc3cSJohan Hovold 	int	instat_endpoint;
167beabdc3cSJohan Hovold 
168beabdc3cSJohan Hovold 		/* Endpoint used for input data 49WG only */
169beabdc3cSJohan Hovold 	int	indat_endpoint;
170beabdc3cSJohan Hovold 
171beabdc3cSJohan Hovold 		/* Endpoint used for global control functions */
172beabdc3cSJohan Hovold 	int	glocont_endpoint;
173beabdc3cSJohan Hovold 
174beabdc3cSJohan Hovold 	int	(*calculate_baud_rate)(struct usb_serial_port *port,
175beabdc3cSJohan Hovold 				       u32 baud_rate, u32 baudclk,
176beabdc3cSJohan Hovold 				       u8 *rate_hi, u8 *rate_low, u8 *prescaler,
177beabdc3cSJohan Hovold 				       int portnum);
178beabdc3cSJohan Hovold 	u32	baudclk;
179beabdc3cSJohan Hovold };
180beabdc3cSJohan Hovold 
181beabdc3cSJohan Hovold /*
182beabdc3cSJohan Hovold  * Now for each device type we setup the device detail structure with the
183beabdc3cSJohan Hovold  * appropriate information (provided in Keyspan's documentation)
184beabdc3cSJohan Hovold  */
185beabdc3cSJohan Hovold 
186beabdc3cSJohan Hovold static const struct keyspan_device_details usa18x_device_details = {
187beabdc3cSJohan Hovold 	.product_id		= keyspan_usa18x_product_id,
188beabdc3cSJohan Hovold 	.msg_format		= msg_usa26,
189beabdc3cSJohan Hovold 	.num_ports		= 1,
190beabdc3cSJohan Hovold 	.indat_endp_flip	= 0,
191beabdc3cSJohan Hovold 	.outdat_endp_flip	= 1,
192beabdc3cSJohan Hovold 	.indat_endpoints	= {0x81},
193beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01},
194beabdc3cSJohan Hovold 	.inack_endpoints	= {0x85},
195beabdc3cSJohan Hovold 	.outcont_endpoints	= {0x05},
196beabdc3cSJohan Hovold 	.instat_endpoint	= 0x87,
197beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
198beabdc3cSJohan Hovold 	.glocont_endpoint	= 0x07,
199beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
200beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA18X_BAUDCLK,
201beabdc3cSJohan Hovold };
202beabdc3cSJohan Hovold 
203beabdc3cSJohan Hovold static const struct keyspan_device_details usa19_device_details = {
204beabdc3cSJohan Hovold 	.product_id		= keyspan_usa19_product_id,
205beabdc3cSJohan Hovold 	.msg_format		= msg_usa28,
206beabdc3cSJohan Hovold 	.num_ports		= 1,
207beabdc3cSJohan Hovold 	.indat_endp_flip	= 1,
208beabdc3cSJohan Hovold 	.outdat_endp_flip	= 1,
209beabdc3cSJohan Hovold 	.indat_endpoints	= {0x81},
210beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01},
211beabdc3cSJohan Hovold 	.inack_endpoints	= {0x83},
212beabdc3cSJohan Hovold 	.outcont_endpoints	= {0x03},
213beabdc3cSJohan Hovold 	.instat_endpoint	= 0x84,
214beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
215beabdc3cSJohan Hovold 	.glocont_endpoint	= -1,
216beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa19_calc_baud,
217beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA19_BAUDCLK,
218beabdc3cSJohan Hovold };
219beabdc3cSJohan Hovold 
220beabdc3cSJohan Hovold static const struct keyspan_device_details usa19qi_device_details = {
221beabdc3cSJohan Hovold 	.product_id		= keyspan_usa19qi_product_id,
222beabdc3cSJohan Hovold 	.msg_format		= msg_usa28,
223beabdc3cSJohan Hovold 	.num_ports		= 1,
224beabdc3cSJohan Hovold 	.indat_endp_flip	= 1,
225beabdc3cSJohan Hovold 	.outdat_endp_flip	= 1,
226beabdc3cSJohan Hovold 	.indat_endpoints	= {0x81},
227beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01},
228beabdc3cSJohan Hovold 	.inack_endpoints	= {0x83},
229beabdc3cSJohan Hovold 	.outcont_endpoints	= {0x03},
230beabdc3cSJohan Hovold 	.instat_endpoint	= 0x84,
231beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
232beabdc3cSJohan Hovold 	.glocont_endpoint	= -1,
233beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa28_calc_baud,
234beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA19_BAUDCLK,
235beabdc3cSJohan Hovold };
236beabdc3cSJohan Hovold 
237beabdc3cSJohan Hovold static const struct keyspan_device_details mpr_device_details = {
238beabdc3cSJohan Hovold 	.product_id		= keyspan_mpr_product_id,
239beabdc3cSJohan Hovold 	.msg_format		= msg_usa28,
240beabdc3cSJohan Hovold 	.num_ports		= 1,
241beabdc3cSJohan Hovold 	.indat_endp_flip	= 1,
242beabdc3cSJohan Hovold 	.outdat_endp_flip	= 1,
243beabdc3cSJohan Hovold 	.indat_endpoints	= {0x81},
244beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01},
245beabdc3cSJohan Hovold 	.inack_endpoints	= {0x83},
246beabdc3cSJohan Hovold 	.outcont_endpoints	= {0x03},
247beabdc3cSJohan Hovold 	.instat_endpoint	= 0x84,
248beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
249beabdc3cSJohan Hovold 	.glocont_endpoint	= -1,
250beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa28_calc_baud,
251beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA19_BAUDCLK,
252beabdc3cSJohan Hovold };
253beabdc3cSJohan Hovold 
254beabdc3cSJohan Hovold static const struct keyspan_device_details usa19qw_device_details = {
255beabdc3cSJohan Hovold 	.product_id		= keyspan_usa19qw_product_id,
256beabdc3cSJohan Hovold 	.msg_format		= msg_usa26,
257beabdc3cSJohan Hovold 	.num_ports		= 1,
258beabdc3cSJohan Hovold 	.indat_endp_flip	= 0,
259beabdc3cSJohan Hovold 	.outdat_endp_flip	= 1,
260beabdc3cSJohan Hovold 	.indat_endpoints	= {0x81},
261beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01},
262beabdc3cSJohan Hovold 	.inack_endpoints	= {0x85},
263beabdc3cSJohan Hovold 	.outcont_endpoints	= {0x05},
264beabdc3cSJohan Hovold 	.instat_endpoint	= 0x87,
265beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
266beabdc3cSJohan Hovold 	.glocont_endpoint	= 0x07,
267beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
268beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA19W_BAUDCLK,
269beabdc3cSJohan Hovold };
270beabdc3cSJohan Hovold 
271beabdc3cSJohan Hovold static const struct keyspan_device_details usa19w_device_details = {
272beabdc3cSJohan Hovold 	.product_id		= keyspan_usa19w_product_id,
273beabdc3cSJohan Hovold 	.msg_format		= msg_usa26,
274beabdc3cSJohan Hovold 	.num_ports		= 1,
275beabdc3cSJohan Hovold 	.indat_endp_flip	= 0,
276beabdc3cSJohan Hovold 	.outdat_endp_flip	= 1,
277beabdc3cSJohan Hovold 	.indat_endpoints	= {0x81},
278beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01},
279beabdc3cSJohan Hovold 	.inack_endpoints	= {0x85},
280beabdc3cSJohan Hovold 	.outcont_endpoints	= {0x05},
281beabdc3cSJohan Hovold 	.instat_endpoint	= 0x87,
282beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
283beabdc3cSJohan Hovold 	.glocont_endpoint	= 0x07,
284beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
285beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA19W_BAUDCLK,
286beabdc3cSJohan Hovold };
287beabdc3cSJohan Hovold 
288beabdc3cSJohan Hovold static const struct keyspan_device_details usa19hs_device_details = {
289beabdc3cSJohan Hovold 	.product_id		= keyspan_usa19hs_product_id,
290beabdc3cSJohan Hovold 	.msg_format		= msg_usa90,
291beabdc3cSJohan Hovold 	.num_ports		= 1,
292beabdc3cSJohan Hovold 	.indat_endp_flip	= 0,
293beabdc3cSJohan Hovold 	.outdat_endp_flip	= 0,
294beabdc3cSJohan Hovold 	.indat_endpoints	= {0x81},
295beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01},
296beabdc3cSJohan Hovold 	.inack_endpoints	= {-1},
297beabdc3cSJohan Hovold 	.outcont_endpoints	= {0x02},
298beabdc3cSJohan Hovold 	.instat_endpoint	= 0x82,
299beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
300beabdc3cSJohan Hovold 	.glocont_endpoint	= -1,
301beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa19hs_calc_baud,
302beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA19HS_BAUDCLK,
303beabdc3cSJohan Hovold };
304beabdc3cSJohan Hovold 
305beabdc3cSJohan Hovold static const struct keyspan_device_details usa28_device_details = {
306beabdc3cSJohan Hovold 	.product_id		= keyspan_usa28_product_id,
307beabdc3cSJohan Hovold 	.msg_format		= msg_usa28,
308beabdc3cSJohan Hovold 	.num_ports		= 2,
309beabdc3cSJohan Hovold 	.indat_endp_flip	= 1,
310beabdc3cSJohan Hovold 	.outdat_endp_flip	= 1,
311beabdc3cSJohan Hovold 	.indat_endpoints	= {0x81, 0x83},
312beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01, 0x03},
313beabdc3cSJohan Hovold 	.inack_endpoints	= {0x85, 0x86},
314beabdc3cSJohan Hovold 	.outcont_endpoints	= {0x05, 0x06},
315beabdc3cSJohan Hovold 	.instat_endpoint	= 0x87,
316beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
317beabdc3cSJohan Hovold 	.glocont_endpoint	= 0x07,
318beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa28_calc_baud,
319beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA28_BAUDCLK,
320beabdc3cSJohan Hovold };
321beabdc3cSJohan Hovold 
322beabdc3cSJohan Hovold static const struct keyspan_device_details usa28x_device_details = {
323beabdc3cSJohan Hovold 	.product_id		= keyspan_usa28x_product_id,
324beabdc3cSJohan Hovold 	.msg_format		= msg_usa26,
325beabdc3cSJohan Hovold 	.num_ports		= 2,
326beabdc3cSJohan Hovold 	.indat_endp_flip	= 0,
327beabdc3cSJohan Hovold 	.outdat_endp_flip	= 1,
328beabdc3cSJohan Hovold 	.indat_endpoints	= {0x81, 0x83},
329beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01, 0x03},
330beabdc3cSJohan Hovold 	.inack_endpoints	= {0x85, 0x86},
331beabdc3cSJohan Hovold 	.outcont_endpoints	= {0x05, 0x06},
332beabdc3cSJohan Hovold 	.instat_endpoint	= 0x87,
333beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
334beabdc3cSJohan Hovold 	.glocont_endpoint	= 0x07,
335beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
336beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA28X_BAUDCLK,
337beabdc3cSJohan Hovold };
338beabdc3cSJohan Hovold 
339beabdc3cSJohan Hovold static const struct keyspan_device_details usa28xa_device_details = {
340beabdc3cSJohan Hovold 	.product_id		= keyspan_usa28xa_product_id,
341beabdc3cSJohan Hovold 	.msg_format		= msg_usa26,
342beabdc3cSJohan Hovold 	.num_ports		= 2,
343beabdc3cSJohan Hovold 	.indat_endp_flip	= 0,
344beabdc3cSJohan Hovold 	.outdat_endp_flip	= 1,
345beabdc3cSJohan Hovold 	.indat_endpoints	= {0x81, 0x83},
346beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01, 0x03},
347beabdc3cSJohan Hovold 	.inack_endpoints	= {0x85, 0x86},
348beabdc3cSJohan Hovold 	.outcont_endpoints	= {0x05, 0x06},
349beabdc3cSJohan Hovold 	.instat_endpoint	= 0x87,
350beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
351beabdc3cSJohan Hovold 	.glocont_endpoint	= 0x07,
352beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
353beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA28X_BAUDCLK,
354beabdc3cSJohan Hovold };
355beabdc3cSJohan Hovold 
356beabdc3cSJohan Hovold static const struct keyspan_device_details usa28xg_device_details = {
357beabdc3cSJohan Hovold 	.product_id		= keyspan_usa28xg_product_id,
358beabdc3cSJohan Hovold 	.msg_format		= msg_usa67,
359beabdc3cSJohan Hovold 	.num_ports		= 2,
360beabdc3cSJohan Hovold 	.indat_endp_flip	= 0,
361beabdc3cSJohan Hovold 	.outdat_endp_flip	= 0,
362beabdc3cSJohan Hovold 	.indat_endpoints	= {0x84, 0x88},
363beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x02, 0x06},
364beabdc3cSJohan Hovold 	.inack_endpoints	= {-1, -1},
365beabdc3cSJohan Hovold 	.outcont_endpoints	= {-1, -1},
366beabdc3cSJohan Hovold 	.instat_endpoint	= 0x81,
367beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
368beabdc3cSJohan Hovold 	.glocont_endpoint	= 0x01,
369beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
370beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA28X_BAUDCLK,
371beabdc3cSJohan Hovold };
372beabdc3cSJohan Hovold /*
373beabdc3cSJohan Hovold  * We don't need a separate entry for the usa28xb as it appears as a 28x
374beabdc3cSJohan Hovold  * anyway.
375beabdc3cSJohan Hovold  */
376beabdc3cSJohan Hovold 
377beabdc3cSJohan Hovold static const struct keyspan_device_details usa49w_device_details = {
378beabdc3cSJohan Hovold 	.product_id		= keyspan_usa49w_product_id,
379beabdc3cSJohan Hovold 	.msg_format		= msg_usa49,
380beabdc3cSJohan Hovold 	.num_ports		= 4,
381beabdc3cSJohan Hovold 	.indat_endp_flip	= 0,
382beabdc3cSJohan Hovold 	.outdat_endp_flip	= 0,
383beabdc3cSJohan Hovold 	.indat_endpoints	= {0x81, 0x82, 0x83, 0x84},
384beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01, 0x02, 0x03, 0x04},
385beabdc3cSJohan Hovold 	.inack_endpoints	= {-1, -1, -1, -1},
386beabdc3cSJohan Hovold 	.outcont_endpoints	= {-1, -1, -1, -1},
387beabdc3cSJohan Hovold 	.instat_endpoint	= 0x87,
388beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
389beabdc3cSJohan Hovold 	.glocont_endpoint	= 0x07,
390beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
391beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA49W_BAUDCLK,
392beabdc3cSJohan Hovold };
393beabdc3cSJohan Hovold 
394beabdc3cSJohan Hovold static const struct keyspan_device_details usa49wlc_device_details = {
395beabdc3cSJohan Hovold 	.product_id		= keyspan_usa49wlc_product_id,
396beabdc3cSJohan Hovold 	.msg_format		= msg_usa49,
397beabdc3cSJohan Hovold 	.num_ports		= 4,
398beabdc3cSJohan Hovold 	.indat_endp_flip	= 0,
399beabdc3cSJohan Hovold 	.outdat_endp_flip	= 0,
400beabdc3cSJohan Hovold 	.indat_endpoints	= {0x81, 0x82, 0x83, 0x84},
401beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01, 0x02, 0x03, 0x04},
402beabdc3cSJohan Hovold 	.inack_endpoints	= {-1, -1, -1, -1},
403beabdc3cSJohan Hovold 	.outcont_endpoints	= {-1, -1, -1, -1},
404beabdc3cSJohan Hovold 	.instat_endpoint	= 0x87,
405beabdc3cSJohan Hovold 	.indat_endpoint		= -1,
406beabdc3cSJohan Hovold 	.glocont_endpoint	= 0x07,
407beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
408beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA19W_BAUDCLK,
409beabdc3cSJohan Hovold };
410beabdc3cSJohan Hovold 
411beabdc3cSJohan Hovold static const struct keyspan_device_details usa49wg_device_details = {
412beabdc3cSJohan Hovold 	.product_id		= keyspan_usa49wg_product_id,
413beabdc3cSJohan Hovold 	.msg_format		= msg_usa49,
414beabdc3cSJohan Hovold 	.num_ports		= 4,
415beabdc3cSJohan Hovold 	.indat_endp_flip	= 0,
416beabdc3cSJohan Hovold 	.outdat_endp_flip	= 0,
417beabdc3cSJohan Hovold 	.indat_endpoints	= {-1, -1, -1, -1},	/* single 'global' data in EP */
418beabdc3cSJohan Hovold 	.outdat_endpoints	= {0x01, 0x02, 0x04, 0x06},
419beabdc3cSJohan Hovold 	.inack_endpoints	= {-1, -1, -1, -1},
420beabdc3cSJohan Hovold 	.outcont_endpoints	= {-1, -1, -1, -1},
421beabdc3cSJohan Hovold 	.instat_endpoint	= 0x81,
422beabdc3cSJohan Hovold 	.indat_endpoint		= 0x88,
423beabdc3cSJohan Hovold 	.glocont_endpoint	= 0x00,			/* uses control EP */
424beabdc3cSJohan Hovold 	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
425beabdc3cSJohan Hovold 	.baudclk		= KEYSPAN_USA19W_BAUDCLK,
426beabdc3cSJohan Hovold };
427beabdc3cSJohan Hovold 
428beabdc3cSJohan Hovold static const struct keyspan_device_details *keyspan_devices[] = {
429beabdc3cSJohan Hovold 	&usa18x_device_details,
430beabdc3cSJohan Hovold 	&usa19_device_details,
431beabdc3cSJohan Hovold 	&usa19qi_device_details,
432beabdc3cSJohan Hovold 	&mpr_device_details,
433beabdc3cSJohan Hovold 	&usa19qw_device_details,
434beabdc3cSJohan Hovold 	&usa19w_device_details,
435beabdc3cSJohan Hovold 	&usa19hs_device_details,
436beabdc3cSJohan Hovold 	&usa28_device_details,
437beabdc3cSJohan Hovold 	&usa28x_device_details,
438beabdc3cSJohan Hovold 	&usa28xa_device_details,
439beabdc3cSJohan Hovold 	&usa28xg_device_details,
440beabdc3cSJohan Hovold 	/* 28xb not required as it renumerates as a 28x */
441beabdc3cSJohan Hovold 	&usa49w_device_details,
442beabdc3cSJohan Hovold 	&usa49wlc_device_details,
443beabdc3cSJohan Hovold 	&usa49wg_device_details,
444beabdc3cSJohan Hovold 	NULL,
445beabdc3cSJohan Hovold };
446beabdc3cSJohan Hovold 
447beabdc3cSJohan Hovold static const struct usb_device_id keyspan_ids_combined[] = {
448beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
449beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
450beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
451beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) },
452beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) },
453beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) },
454beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
455beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
456beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
457beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
458beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
459beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) },
460beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) },
461beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) },
462beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
463beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
464beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
465beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) },
466beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) },
467beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
468beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
469beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
470beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) },
471beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
472beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
473beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)},
474beabdc3cSJohan Hovold 	{ } /* Terminating entry */
475beabdc3cSJohan Hovold };
476beabdc3cSJohan Hovold 
477beabdc3cSJohan Hovold MODULE_DEVICE_TABLE(usb, keyspan_ids_combined);
478beabdc3cSJohan Hovold 
479beabdc3cSJohan Hovold /* usb_device_id table for the pre-firmware download keyspan devices */
480beabdc3cSJohan Hovold static const struct usb_device_id keyspan_pre_ids[] = {
481beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
482beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
483beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) },
484beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) },
485beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
486beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) },
487beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
488beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
489beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
490beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
491beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
492beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) },
493beabdc3cSJohan Hovold 	{ } /* Terminating entry */
494beabdc3cSJohan Hovold };
495beabdc3cSJohan Hovold 
496beabdc3cSJohan Hovold static const struct usb_device_id keyspan_1port_ids[] = {
497beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) },
498beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) },
499beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
500beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
501beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
502beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) },
503beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) },
504beabdc3cSJohan Hovold 	{ } /* Terminating entry */
505beabdc3cSJohan Hovold };
506beabdc3cSJohan Hovold 
507beabdc3cSJohan Hovold static const struct usb_device_id keyspan_2port_ids[] = {
508beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
509beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
510beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
511beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) },
512beabdc3cSJohan Hovold 	{ } /* Terminating entry */
513beabdc3cSJohan Hovold };
514beabdc3cSJohan Hovold 
515beabdc3cSJohan Hovold static const struct usb_device_id keyspan_4port_ids[] = {
516beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) },
517beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
518beabdc3cSJohan Hovold 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)},
519beabdc3cSJohan Hovold 	{ } /* Terminating entry */
520beabdc3cSJohan Hovold };
521beabdc3cSJohan Hovold 
5221da177e4SLinus Torvalds #define INSTAT_BUFLEN	32
5231da177e4SLinus Torvalds #define GLOCONT_BUFLEN	64
5240ca1268eSLucy McCoy #define INDAT49W_BUFLEN	512
525bad41a5bSJohan Hovold #define IN_BUFLEN	64
526bad41a5bSJohan Hovold #define OUT_BUFLEN	64
527bad41a5bSJohan Hovold #define INACK_BUFLEN	1
528bad41a5bSJohan Hovold #define OUTCONT_BUFLEN	64
5291da177e4SLinus Torvalds 
5301da177e4SLinus Torvalds 	/* Per device and per port private data */
5311da177e4SLinus Torvalds struct keyspan_serial_private {
5321da177e4SLinus Torvalds 	const struct keyspan_device_details	*device_details;
5331da177e4SLinus Torvalds 
5341da177e4SLinus Torvalds 	struct urb	*instat_urb;
5352fcd1c9bSJohan Hovold 	char		*instat_buf;
5361da177e4SLinus Torvalds 
537deb91685SAlan Cox 	/* added to support 49wg, where data from all 4 ports comes in
538deb91685SAlan Cox 	   on 1 EP and high-speed supported */
5390ca1268eSLucy McCoy 	struct urb	*indat_urb;
5402fcd1c9bSJohan Hovold 	char		*indat_buf;
5410ca1268eSLucy McCoy 
5421da177e4SLinus Torvalds 	/* XXX this one probably will need a lock */
5431da177e4SLinus Torvalds 	struct urb	*glocont_urb;
5442fcd1c9bSJohan Hovold 	char		*glocont_buf;
5452fcd1c9bSJohan Hovold 	char		*ctrl_buf;	/* for EP0 control message */
5461da177e4SLinus Torvalds };
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds struct keyspan_port_private {
5491da177e4SLinus Torvalds 	/* Keep track of which input & output endpoints to use */
5501da177e4SLinus Torvalds 	int		in_flip;
5511da177e4SLinus Torvalds 	int		out_flip;
5521da177e4SLinus Torvalds 
5531da177e4SLinus Torvalds 	/* Keep duplicate of device details in each port
5541da177e4SLinus Torvalds 	   structure as well - simplifies some of the
5551da177e4SLinus Torvalds 	   callback functions etc. */
5561da177e4SLinus Torvalds 	const struct keyspan_device_details	*device_details;
5571da177e4SLinus Torvalds 
5581da177e4SLinus Torvalds 	/* Input endpoints and buffer for this port */
5591da177e4SLinus Torvalds 	struct urb	*in_urbs[2];
560bad41a5bSJohan Hovold 	char		*in_buffer[2];
5611da177e4SLinus Torvalds 	/* Output endpoints and buffer for this port */
5621da177e4SLinus Torvalds 	struct urb	*out_urbs[2];
563bad41a5bSJohan Hovold 	char		*out_buffer[2];
5641da177e4SLinus Torvalds 
5651da177e4SLinus Torvalds 	/* Input ack endpoint */
5661da177e4SLinus Torvalds 	struct urb	*inack_urb;
567bad41a5bSJohan Hovold 	char		*inack_buffer;
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 	/* Output control endpoint */
5701da177e4SLinus Torvalds 	struct urb	*outcont_urb;
571bad41a5bSJohan Hovold 	char		*outcont_buffer;
5721da177e4SLinus Torvalds 
5731da177e4SLinus Torvalds 	/* Settings for the port */
5741da177e4SLinus Torvalds 	int		baud;
5751da177e4SLinus Torvalds 	int		old_baud;
5761da177e4SLinus Torvalds 	unsigned int	cflag;
5771da177e4SLinus Torvalds 	unsigned int	old_cflag;
5781da177e4SLinus Torvalds 	enum		{flow_none, flow_cts, flow_xon} flow_control;
5791da177e4SLinus Torvalds 	int		rts_state;	/* Handshaking pins (outputs) */
5801da177e4SLinus Torvalds 	int		dtr_state;
5811da177e4SLinus Torvalds 	int		cts_state;	/* Handshaking pins (inputs) */
5821da177e4SLinus Torvalds 	int		dsr_state;
5831da177e4SLinus Torvalds 	int		dcd_state;
5841da177e4SLinus Torvalds 	int		ri_state;
5851da177e4SLinus Torvalds 	int		break_on;
5861da177e4SLinus Torvalds 
5871da177e4SLinus Torvalds 	unsigned long	tx_start_time[2];
5881da177e4SLinus Torvalds 	int		resend_cont;	/* need to resend control packet */
5891da177e4SLinus Torvalds };
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds /* Include Keyspan message headers.  All current Keyspan Adapters
5920ca1268eSLucy McCoy    make use of one of five message formats which are referred
593deb91685SAlan Cox    to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and
594deb91685SAlan Cox    within this driver. */
5951da177e4SLinus Torvalds #include "keyspan_usa26msg.h"
5961da177e4SLinus Torvalds #include "keyspan_usa28msg.h"
5971da177e4SLinus Torvalds #include "keyspan_usa49msg.h"
5981da177e4SLinus Torvalds #include "keyspan_usa90msg.h"
5990ca1268eSLucy McCoy #include "keyspan_usa67msg.h"
6001da177e4SLinus Torvalds 
6011da177e4SLinus Torvalds 
60295da310eSAlan Cox static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
6031da177e4SLinus Torvalds {
60495da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
6051da177e4SLinus Torvalds 	struct keyspan_port_private 	*p_priv;
6061da177e4SLinus Torvalds 
6071da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
6081da177e4SLinus Torvalds 
6091da177e4SLinus Torvalds 	if (break_state == -1)
6101da177e4SLinus Torvalds 		p_priv->break_on = 1;
6111da177e4SLinus Torvalds 	else
6121da177e4SLinus Torvalds 		p_priv->break_on = 0;
6131da177e4SLinus Torvalds 
6141da177e4SLinus Torvalds 	keyspan_send_setup(port, 0);
6151da177e4SLinus Torvalds }
6161da177e4SLinus Torvalds 
6171da177e4SLinus Torvalds 
61895da310eSAlan Cox static void keyspan_set_termios(struct tty_struct *tty,
619*f6d47fe5SIlpo Järvinen 				struct usb_serial_port *port,
620*f6d47fe5SIlpo Järvinen 				const struct ktermios *old_termios)
6211da177e4SLinus Torvalds {
6221da177e4SLinus Torvalds 	int				baud_rate, device_port;
6231da177e4SLinus Torvalds 	struct keyspan_port_private 	*p_priv;
6241da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
6251da177e4SLinus Torvalds 	unsigned int 			cflag;
6261da177e4SLinus Torvalds 
6271da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
6281da177e4SLinus Torvalds 	d_details = p_priv->device_details;
629adc8d746SAlan Cox 	cflag = tty->termios.c_cflag;
6301143832eSGreg Kroah-Hartman 	device_port = port->port_number;
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds 	/* Baud rate calculation takes baud rate as an integer
6331da177e4SLinus Torvalds 	   so other rates can be generated if desired. */
63474240b07SAlan Cox 	baud_rate = tty_get_baud_rate(tty);
6351da177e4SLinus Torvalds 	/* If no match or invalid, don't change */
636049c6b4eSGreg Kroah-Hartman 	if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
6371da177e4SLinus Torvalds 				NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
6381da177e4SLinus Torvalds 		/* FIXME - more to do here to ensure rate changes cleanly */
639cd8c5053SRahul Bedarkar 		/* FIXME - calculate exact rate from divisor ? */
6401da177e4SLinus Torvalds 		p_priv->baud = baud_rate;
64174240b07SAlan Cox 	} else
64274240b07SAlan Cox 		baud_rate = tty_termios_baud_rate(old_termios);
6431da177e4SLinus Torvalds 
64474240b07SAlan Cox 	tty_encode_baud_rate(tty, baud_rate, baud_rate);
6451da177e4SLinus Torvalds 	/* set CTS/RTS handshake etc. */
6461da177e4SLinus Torvalds 	p_priv->cflag = cflag;
6471da177e4SLinus Torvalds 	p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
6481da177e4SLinus Torvalds 
64974240b07SAlan Cox 	/* Mark/Space not supported */
650adc8d746SAlan Cox 	tty->termios.c_cflag &= ~CMSPAR;
65174240b07SAlan Cox 
6521da177e4SLinus Torvalds 	keyspan_send_setup(port, 0);
6531da177e4SLinus Torvalds }
6541da177e4SLinus Torvalds 
65560b33c13SAlan Cox static int keyspan_tiocmget(struct tty_struct *tty)
6561da177e4SLinus Torvalds {
65795da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
65895da310eSAlan Cox 	struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
6591da177e4SLinus Torvalds 	unsigned int			value;
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 	value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
6621da177e4SLinus Torvalds 		((p_priv->dtr_state) ? TIOCM_DTR : 0) |
6631da177e4SLinus Torvalds 		((p_priv->cts_state) ? TIOCM_CTS : 0) |
6641da177e4SLinus Torvalds 		((p_priv->dsr_state) ? TIOCM_DSR : 0) |
6651da177e4SLinus Torvalds 		((p_priv->dcd_state) ? TIOCM_CAR : 0) |
6661da177e4SLinus Torvalds 		((p_priv->ri_state) ? TIOCM_RNG : 0);
6671da177e4SLinus Torvalds 
6681da177e4SLinus Torvalds 	return value;
6691da177e4SLinus Torvalds }
6701da177e4SLinus Torvalds 
67120b9d177SAlan Cox static int keyspan_tiocmset(struct tty_struct *tty,
6721da177e4SLinus Torvalds 			    unsigned int set, unsigned int clear)
6731da177e4SLinus Torvalds {
67495da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
67595da310eSAlan Cox 	struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds 	if (set & TIOCM_RTS)
6781da177e4SLinus Torvalds 		p_priv->rts_state = 1;
6791da177e4SLinus Torvalds 	if (set & TIOCM_DTR)
6801da177e4SLinus Torvalds 		p_priv->dtr_state = 1;
6811da177e4SLinus Torvalds 	if (clear & TIOCM_RTS)
6821da177e4SLinus Torvalds 		p_priv->rts_state = 0;
6831da177e4SLinus Torvalds 	if (clear & TIOCM_DTR)
6841da177e4SLinus Torvalds 		p_priv->dtr_state = 0;
6851da177e4SLinus Torvalds 	keyspan_send_setup(port, 0);
6861da177e4SLinus Torvalds 	return 0;
6871da177e4SLinus Torvalds }
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds /* Write function is similar for the four protocols used
6901da177e4SLinus Torvalds    with only a minor change for usa90 (usa19hs) required */
69195da310eSAlan Cox static int keyspan_write(struct tty_struct *tty,
69295da310eSAlan Cox 	struct usb_serial_port *port, const unsigned char *buf, int count)
6931da177e4SLinus Torvalds {
6941da177e4SLinus Torvalds 	struct keyspan_port_private 	*p_priv;
6951da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
6961da177e4SLinus Torvalds 	int				flip;
6971da177e4SLinus Torvalds 	int 				left, todo;
6981da177e4SLinus Torvalds 	struct urb			*this_urb;
6991da177e4SLinus Torvalds 	int 				err, maxDataLen, dataOffset;
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
7021da177e4SLinus Torvalds 	d_details = p_priv->device_details;
7031da177e4SLinus Torvalds 
7041da177e4SLinus Torvalds 	if (d_details->msg_format == msg_usa90) {
7051da177e4SLinus Torvalds 		maxDataLen = 64;
7061da177e4SLinus Torvalds 		dataOffset = 0;
7071da177e4SLinus Torvalds 	} else {
7081da177e4SLinus Torvalds 		maxDataLen = 63;
7091da177e4SLinus Torvalds 		dataOffset = 1;
7101da177e4SLinus Torvalds 	}
7111da177e4SLinus Torvalds 
7121143832eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - %d chars, flip=%d\n", __func__, count,
7131143832eSGreg Kroah-Hartman 		p_priv->out_flip);
7141da177e4SLinus Torvalds 
7151da177e4SLinus Torvalds 	for (left = count; left > 0; left -= todo) {
7161da177e4SLinus Torvalds 		todo = left;
7171da177e4SLinus Torvalds 		if (todo > maxDataLen)
7181da177e4SLinus Torvalds 			todo = maxDataLen;
7191da177e4SLinus Torvalds 
7201da177e4SLinus Torvalds 		flip = p_priv->out_flip;
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds 		/* Check we have a valid urb/endpoint before we use it... */
723deb91685SAlan Cox 		this_urb = p_priv->out_urbs[flip];
724deb91685SAlan Cox 		if (this_urb == NULL) {
7251da177e4SLinus Torvalds 			/* no bulk out, so return 0 bytes written */
726049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - no output urb :(\n", __func__);
7271da177e4SLinus Torvalds 			return count;
7281da177e4SLinus Torvalds 		}
7291da177e4SLinus Torvalds 
7300cd782b0SJohan Hovold 		dev_dbg(&port->dev, "%s - endpoint %x flip %d\n",
731deb91685SAlan Cox 			__func__, usb_pipeendpoint(this_urb->pipe), flip);
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds 		if (this_urb->status == -EINPROGRESS) {
734deb91685SAlan Cox 			if (time_before(jiffies,
735deb91685SAlan Cox 					p_priv->tx_start_time[flip] + 10 * HZ))
7361da177e4SLinus Torvalds 				break;
7371da177e4SLinus Torvalds 			usb_unlink_urb(this_urb);
7381da177e4SLinus Torvalds 			break;
7391da177e4SLinus Torvalds 		}
7401da177e4SLinus Torvalds 
741deb91685SAlan Cox 		/* First byte in buffer is "last flag" (except for usa19hx)
742deb91685SAlan Cox 		   - unused so for now so set to zero */
7431da177e4SLinus Torvalds 		((char *)this_urb->transfer_buffer)[0] = 0;
7441da177e4SLinus Torvalds 
7451da177e4SLinus Torvalds 		memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
7461da177e4SLinus Torvalds 		buf += todo;
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds 		/* send the data out the bulk port */
7491da177e4SLinus Torvalds 		this_urb->transfer_buffer_length = todo + dataOffset;
7501da177e4SLinus Torvalds 
751deb91685SAlan Cox 		err = usb_submit_urb(this_urb, GFP_ATOMIC);
752deb91685SAlan Cox 		if (err != 0)
753049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err);
7541da177e4SLinus Torvalds 		p_priv->tx_start_time[flip] = jiffies;
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds 		/* Flip for next time if usa26 or usa28 interface
7571da177e4SLinus Torvalds 		   (not used on usa49) */
7581da177e4SLinus Torvalds 		p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
7591da177e4SLinus Torvalds 	}
7601da177e4SLinus Torvalds 
7611da177e4SLinus Torvalds 	return count - left;
7621da177e4SLinus Torvalds }
7631da177e4SLinus Torvalds 
7647d12e780SDavid Howells static void	usa26_indat_callback(struct urb *urb)
7651da177e4SLinus Torvalds {
7661da177e4SLinus Torvalds 	int			i, err;
7671da177e4SLinus Torvalds 	int			endpoint;
7681da177e4SLinus Torvalds 	struct usb_serial_port	*port;
7691da177e4SLinus Torvalds 	unsigned char 		*data = urb->transfer_buffer;
77095b93454SGreg Kroah-Hartman 	int status = urb->status;
7711da177e4SLinus Torvalds 
7721da177e4SLinus Torvalds 	endpoint = usb_pipeendpoint(urb->pipe);
7731da177e4SLinus Torvalds 
77495b93454SGreg Kroah-Hartman 	if (status) {
7750cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
776441b62c1SHarvey Harrison 			__func__, status, endpoint);
7771da177e4SLinus Torvalds 		return;
7781da177e4SLinus Torvalds 	}
7791da177e4SLinus Torvalds 
780cdc97792SMing Lei 	port =  urb->context;
7812e124b4aSJiri Slaby 	if (urb->actual_length) {
7821da177e4SLinus Torvalds 		/* 0x80 bit is error flag */
7831da177e4SLinus Torvalds 		if ((data[0] & 0x80) == 0) {
784deb91685SAlan Cox 			/* no errors on individual bytes, only
785deb91685SAlan Cox 			   possible overrun err */
786855515a6SJohan Hovold 			if (data[0] & RXERROR_OVERRUN) {
787855515a6SJohan Hovold 				tty_insert_flip_char(&port->port, 0,
788855515a6SJohan Hovold 								TTY_OVERRUN);
789855515a6SJohan Hovold 			}
790deb91685SAlan Cox 			for (i = 1; i < urb->actual_length ; ++i)
791855515a6SJohan Hovold 				tty_insert_flip_char(&port->port, data[i],
792855515a6SJohan Hovold 								TTY_NORMAL);
7931da177e4SLinus Torvalds 		} else {
7941da177e4SLinus Torvalds 			/* some bytes had errors, every byte has status */
795049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
7961da177e4SLinus Torvalds 			for (i = 0; i + 1 < urb->actual_length; i += 2) {
7975d1678a3SJohan Hovold 				int stat = data[i];
7985d1678a3SJohan Hovold 				int flag = TTY_NORMAL;
7995d1678a3SJohan Hovold 
8005d1678a3SJohan Hovold 				if (stat & RXERROR_OVERRUN) {
8015d1678a3SJohan Hovold 					tty_insert_flip_char(&port->port, 0,
8025d1678a3SJohan Hovold 								TTY_OVERRUN);
8035d1678a3SJohan Hovold 				}
8041da177e4SLinus Torvalds 				/* XXX should handle break (0x10) */
8055d1678a3SJohan Hovold 				if (stat & RXERROR_PARITY)
8065d1678a3SJohan Hovold 					flag = TTY_PARITY;
8075d1678a3SJohan Hovold 				else if (stat & RXERROR_FRAMING)
8085d1678a3SJohan Hovold 					flag = TTY_FRAME;
8095d1678a3SJohan Hovold 
81092a19f9cSJiri Slaby 				tty_insert_flip_char(&port->port, data[i+1],
81192a19f9cSJiri Slaby 						flag);
8121da177e4SLinus Torvalds 			}
8131da177e4SLinus Torvalds 		}
8142e124b4aSJiri Slaby 		tty_flip_buffer_push(&port->port);
8151da177e4SLinus Torvalds 	}
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds 	/* Resubmit urb so we continue receiving */
818deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
819deb91685SAlan Cox 	if (err != 0)
820049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
8211da177e4SLinus Torvalds }
8221da177e4SLinus Torvalds 
8231da177e4SLinus Torvalds /* Outdat handling is common for all devices */
8247d12e780SDavid Howells static void	usa2x_outdat_callback(struct urb *urb)
8251da177e4SLinus Torvalds {
8261da177e4SLinus Torvalds 	struct usb_serial_port *port;
8271da177e4SLinus Torvalds 	struct keyspan_port_private *p_priv;
8281da177e4SLinus Torvalds 
829cdc97792SMing Lei 	port =  urb->context;
8301da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
831049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
8321da177e4SLinus Torvalds 
833cf2c7481SPete Zaitcev 	usb_serial_port_softint(port);
8341da177e4SLinus Torvalds }
8351da177e4SLinus Torvalds 
8367d12e780SDavid Howells static void	usa26_inack_callback(struct urb *urb)
8371da177e4SLinus Torvalds {
8381da177e4SLinus Torvalds }
8391da177e4SLinus Torvalds 
8407d12e780SDavid Howells static void	usa26_outcont_callback(struct urb *urb)
8411da177e4SLinus Torvalds {
8421da177e4SLinus Torvalds 	struct usb_serial_port *port;
8431da177e4SLinus Torvalds 	struct keyspan_port_private *p_priv;
8441da177e4SLinus Torvalds 
845cdc97792SMing Lei 	port =  urb->context;
8461da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 	if (p_priv->resend_cont) {
849049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - sending setup\n", __func__);
850deb91685SAlan Cox 		keyspan_usa26_send_setup(port->serial, port,
851deb91685SAlan Cox 						p_priv->resend_cont - 1);
8521da177e4SLinus Torvalds 	}
8531da177e4SLinus Torvalds }
8541da177e4SLinus Torvalds 
8557d12e780SDavid Howells static void	usa26_instat_callback(struct urb *urb)
8561da177e4SLinus Torvalds {
8571da177e4SLinus Torvalds 	unsigned char 				*data = urb->transfer_buffer;
8581da177e4SLinus Torvalds 	struct keyspan_usa26_portStatusMessage	*msg;
8591da177e4SLinus Torvalds 	struct usb_serial			*serial;
8601da177e4SLinus Torvalds 	struct usb_serial_port			*port;
8611da177e4SLinus Torvalds 	struct keyspan_port_private	 	*p_priv;
8621da177e4SLinus Torvalds 	int old_dcd_state, err;
86395b93454SGreg Kroah-Hartman 	int status = urb->status;
8641da177e4SLinus Torvalds 
865cdc97792SMing Lei 	serial =  urb->context;
8661da177e4SLinus Torvalds 
86795b93454SGreg Kroah-Hartman 	if (status) {
8680cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
8690cd782b0SJohan Hovold 				__func__, status);
8701da177e4SLinus Torvalds 		return;
8711da177e4SLinus Torvalds 	}
8721da177e4SLinus Torvalds 	if (urb->actual_length != 9) {
873049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
8741da177e4SLinus Torvalds 		goto exit;
8751da177e4SLinus Torvalds 	}
8761da177e4SLinus Torvalds 
8771da177e4SLinus Torvalds 	msg = (struct keyspan_usa26_portStatusMessage *)data;
8781da177e4SLinus Torvalds 
8791da177e4SLinus Torvalds 	/* Check port number from message and retrieve private data */
8801da177e4SLinus Torvalds 	if (msg->port >= serial->num_ports) {
881049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
8821da177e4SLinus Torvalds 		goto exit;
8831da177e4SLinus Torvalds 	}
8841da177e4SLinus Torvalds 	port = serial->port[msg->port];
8851da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
886b5122236SJohan Hovold 	if (!p_priv)
887b5122236SJohan Hovold 		goto resubmit;
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds 	/* Update handshaking pin state information */
8901da177e4SLinus Torvalds 	old_dcd_state = p_priv->dcd_state;
8911da177e4SLinus Torvalds 	p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
8921da177e4SLinus Torvalds 	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
8931da177e4SLinus Torvalds 	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
8941da177e4SLinus Torvalds 	p_priv->ri_state = ((msg->ri) ? 1 : 0);
8951da177e4SLinus Torvalds 
896aa27a094SJiri Slaby 	if (old_dcd_state != p_priv->dcd_state)
897aa27a094SJiri Slaby 		tty_port_tty_hangup(&port->port, true);
898b5122236SJohan Hovold resubmit:
8991da177e4SLinus Torvalds 	/* Resubmit urb so we continue receiving */
900deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
901deb91685SAlan Cox 	if (err != 0)
902049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
9031da177e4SLinus Torvalds exit: ;
9041da177e4SLinus Torvalds }
9051da177e4SLinus Torvalds 
9067d12e780SDavid Howells static void	usa26_glocont_callback(struct urb *urb)
9071da177e4SLinus Torvalds {
9081da177e4SLinus Torvalds }
9091da177e4SLinus Torvalds 
9101da177e4SLinus Torvalds 
9117d12e780SDavid Howells static void usa28_indat_callback(struct urb *urb)
9121da177e4SLinus Torvalds {
913f035a8adSAlan Cox 	int                     err;
9141da177e4SLinus Torvalds 	struct usb_serial_port  *port;
9151da177e4SLinus Torvalds 	unsigned char           *data;
9161da177e4SLinus Torvalds 	struct keyspan_port_private             *p_priv;
91795b93454SGreg Kroah-Hartman 	int status = urb->status;
9181da177e4SLinus Torvalds 
919cdc97792SMing Lei 	port =  urb->context;
9201da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
9211da177e4SLinus Torvalds 	data = urb->transfer_buffer;
9221da177e4SLinus Torvalds 
9231da177e4SLinus Torvalds 	if (urb != p_priv->in_urbs[p_priv->in_flip])
9241da177e4SLinus Torvalds 		return;
9251da177e4SLinus Torvalds 
9261da177e4SLinus Torvalds 	do {
92795b93454SGreg Kroah-Hartman 		if (status) {
9280cd782b0SJohan Hovold 			dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
929441b62c1SHarvey Harrison 				__func__, status, usb_pipeendpoint(urb->pipe));
9301da177e4SLinus Torvalds 			return;
9311da177e4SLinus Torvalds 		}
9321da177e4SLinus Torvalds 
933cdc97792SMing Lei 		port =  urb->context;
9341da177e4SLinus Torvalds 		p_priv = usb_get_serial_port_data(port);
9351da177e4SLinus Torvalds 		data = urb->transfer_buffer;
9361da177e4SLinus Torvalds 
9372e124b4aSJiri Slaby 		if (urb->actual_length) {
93805c7cd39SJiri Slaby 			tty_insert_flip_string(&port->port, data,
93905c7cd39SJiri Slaby 					urb->actual_length);
9402e124b4aSJiri Slaby 			tty_flip_buffer_push(&port->port);
9411da177e4SLinus Torvalds 		}
9421da177e4SLinus Torvalds 
9431da177e4SLinus Torvalds 		/* Resubmit urb so we continue receiving */
944deb91685SAlan Cox 		err = usb_submit_urb(urb, GFP_ATOMIC);
945deb91685SAlan Cox 		if (err != 0)
946049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
947deb91685SAlan Cox 							__func__, err);
9481da177e4SLinus Torvalds 		p_priv->in_flip ^= 1;
9491da177e4SLinus Torvalds 
9501da177e4SLinus Torvalds 		urb = p_priv->in_urbs[p_priv->in_flip];
9511da177e4SLinus Torvalds 	} while (urb->status != -EINPROGRESS);
9521da177e4SLinus Torvalds }
9531da177e4SLinus Torvalds 
9547d12e780SDavid Howells static void	usa28_inack_callback(struct urb *urb)
9551da177e4SLinus Torvalds {
9561da177e4SLinus Torvalds }
9571da177e4SLinus Torvalds 
9587d12e780SDavid Howells static void	usa28_outcont_callback(struct urb *urb)
9591da177e4SLinus Torvalds {
9601da177e4SLinus Torvalds 	struct usb_serial_port *port;
9611da177e4SLinus Torvalds 	struct keyspan_port_private *p_priv;
9621da177e4SLinus Torvalds 
963cdc97792SMing Lei 	port =  urb->context;
9641da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
9651da177e4SLinus Torvalds 
9661da177e4SLinus Torvalds 	if (p_priv->resend_cont) {
967049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - sending setup\n", __func__);
968deb91685SAlan Cox 		keyspan_usa28_send_setup(port->serial, port,
969deb91685SAlan Cox 						p_priv->resend_cont - 1);
9701da177e4SLinus Torvalds 	}
9711da177e4SLinus Torvalds }
9721da177e4SLinus Torvalds 
9737d12e780SDavid Howells static void	usa28_instat_callback(struct urb *urb)
9741da177e4SLinus Torvalds {
9751da177e4SLinus Torvalds 	int					err;
9761da177e4SLinus Torvalds 	unsigned char 				*data = urb->transfer_buffer;
9771da177e4SLinus Torvalds 	struct keyspan_usa28_portStatusMessage	*msg;
9781da177e4SLinus Torvalds 	struct usb_serial			*serial;
9791da177e4SLinus Torvalds 	struct usb_serial_port			*port;
9801da177e4SLinus Torvalds 	struct keyspan_port_private	 	*p_priv;
9811da177e4SLinus Torvalds 	int old_dcd_state;
98295b93454SGreg Kroah-Hartman 	int status = urb->status;
9831da177e4SLinus Torvalds 
984cdc97792SMing Lei 	serial =  urb->context;
9851da177e4SLinus Torvalds 
98695b93454SGreg Kroah-Hartman 	if (status) {
9870cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
9880cd782b0SJohan Hovold 				__func__, status);
9891da177e4SLinus Torvalds 		return;
9901da177e4SLinus Torvalds 	}
9911da177e4SLinus Torvalds 
9921da177e4SLinus Torvalds 	if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
993049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
9941da177e4SLinus Torvalds 		goto exit;
9951da177e4SLinus Torvalds 	}
9961da177e4SLinus Torvalds 
9971da177e4SLinus Torvalds 	msg = (struct keyspan_usa28_portStatusMessage *)data;
9981da177e4SLinus Torvalds 
9991da177e4SLinus Torvalds 	/* Check port number from message and retrieve private data */
10001da177e4SLinus Torvalds 	if (msg->port >= serial->num_ports) {
1001049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
10021da177e4SLinus Torvalds 		goto exit;
10031da177e4SLinus Torvalds 	}
10041da177e4SLinus Torvalds 	port = serial->port[msg->port];
10051da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
1006b5122236SJohan Hovold 	if (!p_priv)
1007b5122236SJohan Hovold 		goto resubmit;
10081da177e4SLinus Torvalds 
10091da177e4SLinus Torvalds 	/* Update handshaking pin state information */
10101da177e4SLinus Torvalds 	old_dcd_state = p_priv->dcd_state;
10111da177e4SLinus Torvalds 	p_priv->cts_state = ((msg->cts) ? 1 : 0);
10121da177e4SLinus Torvalds 	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
10131da177e4SLinus Torvalds 	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
10141da177e4SLinus Torvalds 	p_priv->ri_state = ((msg->ri) ? 1 : 0);
10151da177e4SLinus Torvalds 
1016aa27a094SJiri Slaby 	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
1017aa27a094SJiri Slaby 		tty_port_tty_hangup(&port->port, true);
1018b5122236SJohan Hovold resubmit:
10191da177e4SLinus Torvalds 		/* Resubmit urb so we continue receiving */
1020deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
1021deb91685SAlan Cox 	if (err != 0)
1022049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
10231da177e4SLinus Torvalds exit: ;
10241da177e4SLinus Torvalds }
10251da177e4SLinus Torvalds 
10267d12e780SDavid Howells static void	usa28_glocont_callback(struct urb *urb)
10271da177e4SLinus Torvalds {
10281da177e4SLinus Torvalds }
10291da177e4SLinus Torvalds 
10301da177e4SLinus Torvalds 
10317d12e780SDavid Howells static void	usa49_glocont_callback(struct urb *urb)
10321da177e4SLinus Torvalds {
10331da177e4SLinus Torvalds 	struct usb_serial *serial;
10341da177e4SLinus Torvalds 	struct usb_serial_port *port;
10351da177e4SLinus Torvalds 	struct keyspan_port_private *p_priv;
10361da177e4SLinus Torvalds 	int i;
10371da177e4SLinus Torvalds 
1038cdc97792SMing Lei 	serial =  urb->context;
10391da177e4SLinus Torvalds 	for (i = 0; i < serial->num_ports; ++i) {
10401da177e4SLinus Torvalds 		port = serial->port[i];
10411da177e4SLinus Torvalds 		p_priv = usb_get_serial_port_data(port);
10423018dd3fSJohan Hovold 		if (!p_priv)
10433018dd3fSJohan Hovold 			continue;
10441da177e4SLinus Torvalds 
10451da177e4SLinus Torvalds 		if (p_priv->resend_cont) {
1046049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - sending setup\n", __func__);
1047deb91685SAlan Cox 			keyspan_usa49_send_setup(serial, port,
1048deb91685SAlan Cox 						p_priv->resend_cont - 1);
10491da177e4SLinus Torvalds 			break;
10501da177e4SLinus Torvalds 		}
10511da177e4SLinus Torvalds 	}
10521da177e4SLinus Torvalds }
10531da177e4SLinus Torvalds 
10541da177e4SLinus Torvalds 	/* This is actually called glostat in the Keyspan
10551da177e4SLinus Torvalds 	   doco */
10567d12e780SDavid Howells static void	usa49_instat_callback(struct urb *urb)
10571da177e4SLinus Torvalds {
10581da177e4SLinus Torvalds 	int					err;
10591da177e4SLinus Torvalds 	unsigned char 				*data = urb->transfer_buffer;
10601da177e4SLinus Torvalds 	struct keyspan_usa49_portStatusMessage	*msg;
10611da177e4SLinus Torvalds 	struct usb_serial			*serial;
10621da177e4SLinus Torvalds 	struct usb_serial_port			*port;
10631da177e4SLinus Torvalds 	struct keyspan_port_private	 	*p_priv;
10641da177e4SLinus Torvalds 	int old_dcd_state;
106595b93454SGreg Kroah-Hartman 	int status = urb->status;
10661da177e4SLinus Torvalds 
1067cdc97792SMing Lei 	serial =  urb->context;
10681da177e4SLinus Torvalds 
106995b93454SGreg Kroah-Hartman 	if (status) {
10700cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
10710cd782b0SJohan Hovold 				__func__, status);
10721da177e4SLinus Torvalds 		return;
10731da177e4SLinus Torvalds 	}
10741da177e4SLinus Torvalds 
1075deb91685SAlan Cox 	if (urb->actual_length !=
1076deb91685SAlan Cox 			sizeof(struct keyspan_usa49_portStatusMessage)) {
1077049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
10781da177e4SLinus Torvalds 		goto exit;
10791da177e4SLinus Torvalds 	}
10801da177e4SLinus Torvalds 
10811da177e4SLinus Torvalds 	msg = (struct keyspan_usa49_portStatusMessage *)data;
10821da177e4SLinus Torvalds 
10831da177e4SLinus Torvalds 	/* Check port number from message and retrieve private data */
10841da177e4SLinus Torvalds 	if (msg->portNumber >= serial->num_ports) {
1085049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
1086deb91685SAlan Cox 			__func__, msg->portNumber);
10871da177e4SLinus Torvalds 		goto exit;
10881da177e4SLinus Torvalds 	}
10891da177e4SLinus Torvalds 	port = serial->port[msg->portNumber];
10901da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
1091b5122236SJohan Hovold 	if (!p_priv)
1092b5122236SJohan Hovold 		goto resubmit;
10931da177e4SLinus Torvalds 
10941da177e4SLinus Torvalds 	/* Update handshaking pin state information */
10951da177e4SLinus Torvalds 	old_dcd_state = p_priv->dcd_state;
10961da177e4SLinus Torvalds 	p_priv->cts_state = ((msg->cts) ? 1 : 0);
10971da177e4SLinus Torvalds 	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
10981da177e4SLinus Torvalds 	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
10991da177e4SLinus Torvalds 	p_priv->ri_state = ((msg->ri) ? 1 : 0);
11001da177e4SLinus Torvalds 
1101aa27a094SJiri Slaby 	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
1102aa27a094SJiri Slaby 		tty_port_tty_hangup(&port->port, true);
1103b5122236SJohan Hovold resubmit:
11041da177e4SLinus Torvalds 	/* Resubmit urb so we continue receiving */
1105deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
1106deb91685SAlan Cox 	if (err != 0)
1107049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
11081da177e4SLinus Torvalds exit:	;
11091da177e4SLinus Torvalds }
11101da177e4SLinus Torvalds 
11117d12e780SDavid Howells static void	usa49_inack_callback(struct urb *urb)
11121da177e4SLinus Torvalds {
11131da177e4SLinus Torvalds }
11141da177e4SLinus Torvalds 
11157d12e780SDavid Howells static void	usa49_indat_callback(struct urb *urb)
11161da177e4SLinus Torvalds {
11171da177e4SLinus Torvalds 	int			i, err;
11181da177e4SLinus Torvalds 	int			endpoint;
11191da177e4SLinus Torvalds 	struct usb_serial_port	*port;
11201da177e4SLinus Torvalds 	unsigned char 		*data = urb->transfer_buffer;
112195b93454SGreg Kroah-Hartman 	int status = urb->status;
11221da177e4SLinus Torvalds 
11231da177e4SLinus Torvalds 	endpoint = usb_pipeendpoint(urb->pipe);
11241da177e4SLinus Torvalds 
112595b93454SGreg Kroah-Hartman 	if (status) {
11260cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
1127049c6b4eSGreg Kroah-Hartman 			__func__, status, endpoint);
11281da177e4SLinus Torvalds 		return;
11291da177e4SLinus Torvalds 	}
11301da177e4SLinus Torvalds 
1131cdc97792SMing Lei 	port =  urb->context;
11322e124b4aSJiri Slaby 	if (urb->actual_length) {
11331da177e4SLinus Torvalds 		/* 0x80 bit is error flag */
11341da177e4SLinus Torvalds 		if ((data[0] & 0x80) == 0) {
11351da177e4SLinus Torvalds 			/* no error on any byte */
113605c7cd39SJiri Slaby 			tty_insert_flip_string(&port->port, data + 1,
1137f035a8adSAlan Cox 						urb->actual_length - 1);
11381da177e4SLinus Torvalds 		} else {
11391da177e4SLinus Torvalds 			/* some bytes had errors, every byte has status */
11401da177e4SLinus Torvalds 			for (i = 0; i + 1 < urb->actual_length; i += 2) {
11415d1678a3SJohan Hovold 				int stat = data[i];
11425d1678a3SJohan Hovold 				int flag = TTY_NORMAL;
11435d1678a3SJohan Hovold 
11445d1678a3SJohan Hovold 				if (stat & RXERROR_OVERRUN) {
11455d1678a3SJohan Hovold 					tty_insert_flip_char(&port->port, 0,
11465d1678a3SJohan Hovold 								TTY_OVERRUN);
11475d1678a3SJohan Hovold 				}
11481da177e4SLinus Torvalds 				/* XXX should handle break (0x10) */
11495d1678a3SJohan Hovold 				if (stat & RXERROR_PARITY)
11505d1678a3SJohan Hovold 					flag = TTY_PARITY;
11515d1678a3SJohan Hovold 				else if (stat & RXERROR_FRAMING)
11525d1678a3SJohan Hovold 					flag = TTY_FRAME;
11535d1678a3SJohan Hovold 
115492a19f9cSJiri Slaby 				tty_insert_flip_char(&port->port, data[i+1],
115592a19f9cSJiri Slaby 						flag);
11561da177e4SLinus Torvalds 			}
11571da177e4SLinus Torvalds 		}
11582e124b4aSJiri Slaby 		tty_flip_buffer_push(&port->port);
11591da177e4SLinus Torvalds 	}
11601da177e4SLinus Torvalds 
11611da177e4SLinus Torvalds 	/* Resubmit urb so we continue receiving */
1162deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
1163deb91685SAlan Cox 	if (err != 0)
1164049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
11651da177e4SLinus Torvalds }
11661da177e4SLinus Torvalds 
11670ca1268eSLucy McCoy static void usa49wg_indat_callback(struct urb *urb)
11680ca1268eSLucy McCoy {
11690ca1268eSLucy McCoy 	int			i, len, x, err;
11700ca1268eSLucy McCoy 	struct usb_serial	*serial;
11710ca1268eSLucy McCoy 	struct usb_serial_port	*port;
11720ca1268eSLucy McCoy 	unsigned char 		*data = urb->transfer_buffer;
117395b93454SGreg Kroah-Hartman 	int status = urb->status;
11740ca1268eSLucy McCoy 
11750ca1268eSLucy McCoy 	serial = urb->context;
11760ca1268eSLucy McCoy 
117795b93454SGreg Kroah-Hartman 	if (status) {
11780cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
11790cd782b0SJohan Hovold 				__func__, status);
11800ca1268eSLucy McCoy 		return;
11810ca1268eSLucy McCoy 	}
11820ca1268eSLucy McCoy 
11830ca1268eSLucy McCoy 	/* inbound data is in the form P#, len, status, data */
11840ca1268eSLucy McCoy 	i = 0;
11850ca1268eSLucy McCoy 	len = 0;
11860ca1268eSLucy McCoy 
11870ca1268eSLucy McCoy 	while (i < urb->actual_length) {
11880ca1268eSLucy McCoy 
11890ca1268eSLucy McCoy 		/* Check port number from message */
11900ca1268eSLucy McCoy 		if (data[i] >= serial->num_ports) {
1191049c6b4eSGreg Kroah-Hartman 			dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
1192441b62c1SHarvey Harrison 				__func__, data[i]);
11930ca1268eSLucy McCoy 			return;
11940ca1268eSLucy McCoy 		}
11950ca1268eSLucy McCoy 		port = serial->port[data[i++]];
11960ca1268eSLucy McCoy 		len = data[i++];
11970ca1268eSLucy McCoy 
11980ca1268eSLucy McCoy 		/* 0x80 bit is error flag */
11990ca1268eSLucy McCoy 		if ((data[i] & 0x80) == 0) {
12000ca1268eSLucy McCoy 			/* no error on any byte */
12010ca1268eSLucy McCoy 			i++;
120201a60e76SDan Carpenter 			for (x = 1; x < len && i < urb->actual_length; ++x)
120392a19f9cSJiri Slaby 				tty_insert_flip_char(&port->port,
120492a19f9cSJiri Slaby 						data[i++], 0);
12050ca1268eSLucy McCoy 		} else {
12060ca1268eSLucy McCoy 			/*
12070ca1268eSLucy McCoy 			 * some bytes had errors, every byte has status
12080ca1268eSLucy McCoy 			 */
120901a60e76SDan Carpenter 			for (x = 0; x + 1 < len &&
121001a60e76SDan Carpenter 				    i + 1 < urb->actual_length; x += 2) {
12115d1678a3SJohan Hovold 				int stat = data[i];
12125d1678a3SJohan Hovold 				int flag = TTY_NORMAL;
12136a3ae841SDan Carpenter 
12145d1678a3SJohan Hovold 				if (stat & RXERROR_OVERRUN) {
12155d1678a3SJohan Hovold 					tty_insert_flip_char(&port->port, 0,
12165d1678a3SJohan Hovold 								TTY_OVERRUN);
12175d1678a3SJohan Hovold 				}
12180ca1268eSLucy McCoy 				/* XXX should handle break (0x10) */
12195d1678a3SJohan Hovold 				if (stat & RXERROR_PARITY)
12205d1678a3SJohan Hovold 					flag = TTY_PARITY;
12215d1678a3SJohan Hovold 				else if (stat & RXERROR_FRAMING)
12225d1678a3SJohan Hovold 					flag = TTY_FRAME;
12235d1678a3SJohan Hovold 
12246a3ae841SDan Carpenter 				tty_insert_flip_char(&port->port, data[i+1],
12256a3ae841SDan Carpenter 						     flag);
12260ca1268eSLucy McCoy 				i += 2;
12270ca1268eSLucy McCoy 			}
12280ca1268eSLucy McCoy 		}
12292e124b4aSJiri Slaby 		tty_flip_buffer_push(&port->port);
12300ca1268eSLucy McCoy 	}
12310ca1268eSLucy McCoy 
12320ca1268eSLucy McCoy 	/* Resubmit urb so we continue receiving */
12330ca1268eSLucy McCoy 	err = usb_submit_urb(urb, GFP_ATOMIC);
12340ca1268eSLucy McCoy 	if (err != 0)
1235049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
12360ca1268eSLucy McCoy }
12370ca1268eSLucy McCoy 
12381da177e4SLinus Torvalds /* not used, usa-49 doesn't have per-port control endpoints */
12397d12e780SDavid Howells static void usa49_outcont_callback(struct urb *urb)
12401da177e4SLinus Torvalds {
12411da177e4SLinus Torvalds }
12421da177e4SLinus Torvalds 
12437d12e780SDavid Howells static void usa90_indat_callback(struct urb *urb)
12441da177e4SLinus Torvalds {
12451da177e4SLinus Torvalds 	int			i, err;
12461da177e4SLinus Torvalds 	int			endpoint;
12471da177e4SLinus Torvalds 	struct usb_serial_port	*port;
12481da177e4SLinus Torvalds 	struct keyspan_port_private	 	*p_priv;
12491da177e4SLinus Torvalds 	unsigned char 		*data = urb->transfer_buffer;
125095b93454SGreg Kroah-Hartman 	int status = urb->status;
12511da177e4SLinus Torvalds 
12521da177e4SLinus Torvalds 	endpoint = usb_pipeendpoint(urb->pipe);
12531da177e4SLinus Torvalds 
125495b93454SGreg Kroah-Hartman 	if (status) {
12550cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
1256441b62c1SHarvey Harrison 			__func__, status, endpoint);
12571da177e4SLinus Torvalds 		return;
12581da177e4SLinus Torvalds 	}
12591da177e4SLinus Torvalds 
1260cdc97792SMing Lei 	port =  urb->context;
12611da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
12621da177e4SLinus Torvalds 
12631da177e4SLinus Torvalds 	if (urb->actual_length) {
12641da177e4SLinus Torvalds 		/* if current mode is DMA, looks like usa28 format
12651da177e4SLinus Torvalds 		   otherwise looks like usa26 data format */
12661da177e4SLinus Torvalds 
1267f035a8adSAlan Cox 		if (p_priv->baud > 57600)
126805c7cd39SJiri Slaby 			tty_insert_flip_string(&port->port, data,
126905c7cd39SJiri Slaby 					urb->actual_length);
1270f035a8adSAlan Cox 		else {
12711da177e4SLinus Torvalds 			/* 0x80 bit is error flag */
12721da177e4SLinus Torvalds 			if ((data[0] & 0x80) == 0) {
1273deb91685SAlan Cox 				/* no errors on individual bytes, only
1274deb91685SAlan Cox 				   possible overrun err*/
1275855515a6SJohan Hovold 				if (data[0] & RXERROR_OVERRUN) {
1276855515a6SJohan Hovold 					tty_insert_flip_char(&port->port, 0,
1277855515a6SJohan Hovold 								TTY_OVERRUN);
1278855515a6SJohan Hovold 				}
12791da177e4SLinus Torvalds 				for (i = 1; i < urb->actual_length ; ++i)
128092a19f9cSJiri Slaby 					tty_insert_flip_char(&port->port,
1281855515a6SJohan Hovold 							data[i], TTY_NORMAL);
1282deb91685SAlan Cox 			}  else {
12831da177e4SLinus Torvalds 			/* some bytes had errors, every byte has status */
1284049c6b4eSGreg Kroah-Hartman 				dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
12851da177e4SLinus Torvalds 				for (i = 0; i + 1 < urb->actual_length; i += 2) {
12865d1678a3SJohan Hovold 					int stat = data[i];
12875d1678a3SJohan Hovold 					int flag = TTY_NORMAL;
12885d1678a3SJohan Hovold 
12895d1678a3SJohan Hovold 					if (stat & RXERROR_OVERRUN) {
12905d1678a3SJohan Hovold 						tty_insert_flip_char(
12915d1678a3SJohan Hovold 								&port->port, 0,
12925d1678a3SJohan Hovold 								TTY_OVERRUN);
12935d1678a3SJohan Hovold 					}
12941da177e4SLinus Torvalds 					/* XXX should handle break (0x10) */
12955d1678a3SJohan Hovold 					if (stat & RXERROR_PARITY)
12965d1678a3SJohan Hovold 						flag = TTY_PARITY;
12975d1678a3SJohan Hovold 					else if (stat & RXERROR_FRAMING)
12985d1678a3SJohan Hovold 						flag = TTY_FRAME;
12995d1678a3SJohan Hovold 
130092a19f9cSJiri Slaby 					tty_insert_flip_char(&port->port,
130192a19f9cSJiri Slaby 							data[i+1], flag);
13021da177e4SLinus Torvalds 				}
13031da177e4SLinus Torvalds 			}
13041da177e4SLinus Torvalds 		}
13052e124b4aSJiri Slaby 		tty_flip_buffer_push(&port->port);
13061da177e4SLinus Torvalds 	}
13071da177e4SLinus Torvalds 
13081da177e4SLinus Torvalds 	/* Resubmit urb so we continue receiving */
1309deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
1310deb91685SAlan Cox 	if (err != 0)
1311049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
13121da177e4SLinus Torvalds }
13131da177e4SLinus Torvalds 
13141da177e4SLinus Torvalds 
13157d12e780SDavid Howells static void	usa90_instat_callback(struct urb *urb)
13161da177e4SLinus Torvalds {
13171da177e4SLinus Torvalds 	unsigned char 				*data = urb->transfer_buffer;
13181da177e4SLinus Torvalds 	struct keyspan_usa90_portStatusMessage	*msg;
13191da177e4SLinus Torvalds 	struct usb_serial			*serial;
13201da177e4SLinus Torvalds 	struct usb_serial_port			*port;
13211da177e4SLinus Torvalds 	struct keyspan_port_private	 	*p_priv;
13221da177e4SLinus Torvalds 	int old_dcd_state, err;
132395b93454SGreg Kroah-Hartman 	int status = urb->status;
13241da177e4SLinus Torvalds 
1325cdc97792SMing Lei 	serial =  urb->context;
13261da177e4SLinus Torvalds 
132795b93454SGreg Kroah-Hartman 	if (status) {
13280cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
13290cd782b0SJohan Hovold 				__func__, status);
13301da177e4SLinus Torvalds 		return;
13311da177e4SLinus Torvalds 	}
13321da177e4SLinus Torvalds 	if (urb->actual_length < 14) {
1333049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
13341da177e4SLinus Torvalds 		goto exit;
13351da177e4SLinus Torvalds 	}
13361da177e4SLinus Torvalds 
13371da177e4SLinus Torvalds 	msg = (struct keyspan_usa90_portStatusMessage *)data;
13381da177e4SLinus Torvalds 
13391da177e4SLinus Torvalds 	/* Now do something useful with the data */
13401da177e4SLinus Torvalds 
13411da177e4SLinus Torvalds 	port = serial->port[0];
13421da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
1343b5122236SJohan Hovold 	if (!p_priv)
1344b5122236SJohan Hovold 		goto resubmit;
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds 	/* Update handshaking pin state information */
13471da177e4SLinus Torvalds 	old_dcd_state = p_priv->dcd_state;
13481da177e4SLinus Torvalds 	p_priv->cts_state = ((msg->cts) ? 1 : 0);
13491da177e4SLinus Torvalds 	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
13501da177e4SLinus Torvalds 	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
13511da177e4SLinus Torvalds 	p_priv->ri_state = ((msg->ri) ? 1 : 0);
13521da177e4SLinus Torvalds 
1353aa27a094SJiri Slaby 	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
1354aa27a094SJiri Slaby 		tty_port_tty_hangup(&port->port, true);
1355b5122236SJohan Hovold resubmit:
13561da177e4SLinus Torvalds 	/* Resubmit urb so we continue receiving */
1357deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
1358deb91685SAlan Cox 	if (err != 0)
1359049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
13601da177e4SLinus Torvalds exit:
13611da177e4SLinus Torvalds 	;
13621da177e4SLinus Torvalds }
13631da177e4SLinus Torvalds 
13647d12e780SDavid Howells static void	usa90_outcont_callback(struct urb *urb)
13651da177e4SLinus Torvalds {
13661da177e4SLinus Torvalds 	struct usb_serial_port *port;
13671da177e4SLinus Torvalds 	struct keyspan_port_private *p_priv;
13681da177e4SLinus Torvalds 
1369cdc97792SMing Lei 	port =  urb->context;
13701da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
13711da177e4SLinus Torvalds 
13721da177e4SLinus Torvalds 	if (p_priv->resend_cont) {
1373049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
1374deb91685SAlan Cox 		keyspan_usa90_send_setup(port->serial, port,
1375deb91685SAlan Cox 						p_priv->resend_cont - 1);
13761da177e4SLinus Torvalds 	}
13771da177e4SLinus Torvalds }
13781da177e4SLinus Torvalds 
13790ca1268eSLucy McCoy /* Status messages from the 28xg */
13800ca1268eSLucy McCoy static void	usa67_instat_callback(struct urb *urb)
13810ca1268eSLucy McCoy {
13820ca1268eSLucy McCoy 	int					err;
13830ca1268eSLucy McCoy 	unsigned char 				*data = urb->transfer_buffer;
13840ca1268eSLucy McCoy 	struct keyspan_usa67_portStatusMessage	*msg;
13850ca1268eSLucy McCoy 	struct usb_serial			*serial;
13860ca1268eSLucy McCoy 	struct usb_serial_port			*port;
13870ca1268eSLucy McCoy 	struct keyspan_port_private	 	*p_priv;
13880ca1268eSLucy McCoy 	int old_dcd_state;
138995b93454SGreg Kroah-Hartman 	int status = urb->status;
13900ca1268eSLucy McCoy 
13910ca1268eSLucy McCoy 	serial = urb->context;
13920ca1268eSLucy McCoy 
139395b93454SGreg Kroah-Hartman 	if (status) {
13940cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
13950cd782b0SJohan Hovold 				__func__, status);
13960ca1268eSLucy McCoy 		return;
13970ca1268eSLucy McCoy 	}
13980ca1268eSLucy McCoy 
1399deb91685SAlan Cox 	if (urb->actual_length !=
1400deb91685SAlan Cox 			sizeof(struct keyspan_usa67_portStatusMessage)) {
1401049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
14020ca1268eSLucy McCoy 		return;
14030ca1268eSLucy McCoy 	}
14040ca1268eSLucy McCoy 
14050ca1268eSLucy McCoy 
14060ca1268eSLucy McCoy 	/* Now do something useful with the data */
14070ca1268eSLucy McCoy 	msg = (struct keyspan_usa67_portStatusMessage *)data;
14080ca1268eSLucy McCoy 
14090ca1268eSLucy McCoy 	/* Check port number from message and retrieve private data */
14100ca1268eSLucy McCoy 	if (msg->port >= serial->num_ports) {
1411049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
14120ca1268eSLucy McCoy 		return;
14130ca1268eSLucy McCoy 	}
14140ca1268eSLucy McCoy 
14150ca1268eSLucy McCoy 	port = serial->port[msg->port];
14160ca1268eSLucy McCoy 	p_priv = usb_get_serial_port_data(port);
1417b5122236SJohan Hovold 	if (!p_priv)
1418b5122236SJohan Hovold 		goto resubmit;
14190ca1268eSLucy McCoy 
14200ca1268eSLucy McCoy 	/* Update handshaking pin state information */
14210ca1268eSLucy McCoy 	old_dcd_state = p_priv->dcd_state;
14220ca1268eSLucy McCoy 	p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
14230ca1268eSLucy McCoy 	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
14240ca1268eSLucy McCoy 
1425aa27a094SJiri Slaby 	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
1426aa27a094SJiri Slaby 		tty_port_tty_hangup(&port->port, true);
1427b5122236SJohan Hovold resubmit:
14280ca1268eSLucy McCoy 	/* Resubmit urb so we continue receiving */
14290ca1268eSLucy McCoy 	err = usb_submit_urb(urb, GFP_ATOMIC);
14300ca1268eSLucy McCoy 	if (err != 0)
1431049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
14320ca1268eSLucy McCoy }
14330ca1268eSLucy McCoy 
14340ca1268eSLucy McCoy static void usa67_glocont_callback(struct urb *urb)
14350ca1268eSLucy McCoy {
14360ca1268eSLucy McCoy 	struct usb_serial *serial;
14370ca1268eSLucy McCoy 	struct usb_serial_port *port;
14380ca1268eSLucy McCoy 	struct keyspan_port_private *p_priv;
14390ca1268eSLucy McCoy 	int i;
14400ca1268eSLucy McCoy 
14410ca1268eSLucy McCoy 	serial = urb->context;
14420ca1268eSLucy McCoy 	for (i = 0; i < serial->num_ports; ++i) {
14430ca1268eSLucy McCoy 		port = serial->port[i];
14440ca1268eSLucy McCoy 		p_priv = usb_get_serial_port_data(port);
14453018dd3fSJohan Hovold 		if (!p_priv)
14463018dd3fSJohan Hovold 			continue;
14470ca1268eSLucy McCoy 
14480ca1268eSLucy McCoy 		if (p_priv->resend_cont) {
1449049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - sending setup\n", __func__);
14500ca1268eSLucy McCoy 			keyspan_usa67_send_setup(serial, port,
14510ca1268eSLucy McCoy 						p_priv->resend_cont - 1);
14520ca1268eSLucy McCoy 			break;
14530ca1268eSLucy McCoy 		}
14540ca1268eSLucy McCoy 	}
14550ca1268eSLucy McCoy }
14560ca1268eSLucy McCoy 
145794cc7aeaSJiri Slaby static unsigned int keyspan_write_room(struct tty_struct *tty)
14581da177e4SLinus Torvalds {
145995da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
14601da177e4SLinus Torvalds 	struct keyspan_port_private	*p_priv;
14611da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
14621da177e4SLinus Torvalds 	int				flip;
146394cc7aeaSJiri Slaby 	unsigned int			data_len;
14641da177e4SLinus Torvalds 	struct urb			*this_urb;
14651da177e4SLinus Torvalds 
14661da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
14671da177e4SLinus Torvalds 	d_details = p_priv->device_details;
14681da177e4SLinus Torvalds 
1469a5b6f60cSAlan Cox 	/* FIXME: locking */
14701da177e4SLinus Torvalds 	if (d_details->msg_format == msg_usa90)
14711da177e4SLinus Torvalds 		data_len = 64;
14721da177e4SLinus Torvalds 	else
14731da177e4SLinus Torvalds 		data_len = 63;
14741da177e4SLinus Torvalds 
14751da177e4SLinus Torvalds 	flip = p_priv->out_flip;
14761da177e4SLinus Torvalds 
14771da177e4SLinus Torvalds 	/* Check both endpoints to see if any are available. */
1478deb91685SAlan Cox 	this_urb = p_priv->out_urbs[flip];
1479deb91685SAlan Cox 	if (this_urb != NULL) {
14801da177e4SLinus Torvalds 		if (this_urb->status != -EINPROGRESS)
1481deb91685SAlan Cox 			return data_len;
14821da177e4SLinus Torvalds 		flip = (flip + 1) & d_details->outdat_endp_flip;
1483deb91685SAlan Cox 		this_urb = p_priv->out_urbs[flip];
1484deb91685SAlan Cox 		if (this_urb != NULL) {
14851da177e4SLinus Torvalds 			if (this_urb->status != -EINPROGRESS)
1486deb91685SAlan Cox 				return data_len;
1487deb91685SAlan Cox 		}
14881da177e4SLinus Torvalds 	}
1489a5b6f60cSAlan Cox 	return 0;
14901da177e4SLinus Torvalds }
14911da177e4SLinus Torvalds 
14921da177e4SLinus Torvalds 
1493a509a7e4SAlan Cox static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
14941da177e4SLinus Torvalds {
14951da177e4SLinus Torvalds 	struct keyspan_port_private 	*p_priv;
14961da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
14971da177e4SLinus Torvalds 	int				i, err;
1498f78ba157SAndrew Morton 	int				baud_rate, device_port;
14991da177e4SLinus Torvalds 	struct urb			*urb;
150095da310eSAlan Cox 	unsigned int			cflag = 0;
15011da177e4SLinus Torvalds 
15021da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
15031da177e4SLinus Torvalds 	d_details = p_priv->device_details;
15041da177e4SLinus Torvalds 
15051da177e4SLinus Torvalds 	/* Set some sane defaults */
15061da177e4SLinus Torvalds 	p_priv->rts_state = 1;
15071da177e4SLinus Torvalds 	p_priv->dtr_state = 1;
15081da177e4SLinus Torvalds 	p_priv->baud = 9600;
15091da177e4SLinus Torvalds 
15101da177e4SLinus Torvalds 	/* force baud and lcr to be set on open */
15111da177e4SLinus Torvalds 	p_priv->old_baud = 0;
15121da177e4SLinus Torvalds 	p_priv->old_cflag = 0;
15131da177e4SLinus Torvalds 
15141da177e4SLinus Torvalds 	p_priv->out_flip = 0;
15151da177e4SLinus Torvalds 	p_priv->in_flip = 0;
15161da177e4SLinus Torvalds 
15171da177e4SLinus Torvalds 	/* Reset low level data toggle and start reading from endpoints */
15181da177e4SLinus Torvalds 	for (i = 0; i < 2; i++) {
1519deb91685SAlan Cox 		urb = p_priv->in_urbs[i];
1520deb91685SAlan Cox 		if (urb == NULL)
15211da177e4SLinus Torvalds 			continue;
15221da177e4SLinus Torvalds 
1523deb91685SAlan Cox 		/* make sure endpoint data toggle is synchronized
1524deb91685SAlan Cox 		   with the device */
15251da177e4SLinus Torvalds 		usb_clear_halt(urb->dev, urb->pipe);
1526deb91685SAlan Cox 		err = usb_submit_urb(urb, GFP_KERNEL);
1527deb91685SAlan Cox 		if (err != 0)
1528049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
15291da177e4SLinus Torvalds 	}
15301da177e4SLinus Torvalds 
15311da177e4SLinus Torvalds 	/* Reset low level data toggle on out endpoints */
15321da177e4SLinus Torvalds 	for (i = 0; i < 2; i++) {
1533deb91685SAlan Cox 		urb = p_priv->out_urbs[i];
1534deb91685SAlan Cox 		if (urb == NULL)
15351da177e4SLinus Torvalds 			continue;
1536deb91685SAlan Cox 		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1537deb91685SAlan Cox 						usb_pipeout(urb->pipe), 0); */
15381da177e4SLinus Torvalds 	}
15391da177e4SLinus Torvalds 
1540f78ba157SAndrew Morton 	/* get the terminal config for the setup message now so we don't
1541f78ba157SAndrew Morton 	 * need to send 2 of them */
1542f78ba157SAndrew Morton 
15431143832eSGreg Kroah-Hartman 	device_port = port->port_number;
154495da310eSAlan Cox 	if (tty) {
1545adc8d746SAlan Cox 		cflag = tty->termios.c_cflag;
1546f78ba157SAndrew Morton 		/* Baud rate calculation takes baud rate as an integer
1547f78ba157SAndrew Morton 		   so other rates can be generated if desired. */
154895da310eSAlan Cox 		baud_rate = tty_get_baud_rate(tty);
1549f78ba157SAndrew Morton 		/* If no match or invalid, leave as default */
1550f78ba157SAndrew Morton 		if (baud_rate >= 0
1551049c6b4eSGreg Kroah-Hartman 		    && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
1552f78ba157SAndrew Morton 					NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1553f78ba157SAndrew Morton 			p_priv->baud = baud_rate;
1554f78ba157SAndrew Morton 		}
155595da310eSAlan Cox 	}
1556f78ba157SAndrew Morton 	/* set CTS/RTS handshake etc. */
1557f78ba157SAndrew Morton 	p_priv->cflag = cflag;
1558f78ba157SAndrew Morton 	p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
1559f78ba157SAndrew Morton 
1560f78ba157SAndrew Morton 	keyspan_send_setup(port, 1);
1561deb91685SAlan Cox 	/* mdelay(100); */
1562deb91685SAlan Cox 	/* keyspan_set_termios(port, NULL); */
1563f78ba157SAndrew Morton 
1564a5b6f60cSAlan Cox 	return 0;
15651da177e4SLinus Torvalds }
15661da177e4SLinus Torvalds 
1567335f8514SAlan Cox static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1568335f8514SAlan Cox {
1569335f8514SAlan Cox 	struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1570335f8514SAlan Cox 
1571335f8514SAlan Cox 	p_priv->rts_state = on;
1572335f8514SAlan Cox 	p_priv->dtr_state = on;
1573335f8514SAlan Cox 	keyspan_send_setup(port, 0);
1574335f8514SAlan Cox }
1575335f8514SAlan Cox 
1576335f8514SAlan Cox static void keyspan_close(struct usb_serial_port *port)
15771da177e4SLinus Torvalds {
15781da177e4SLinus Torvalds 	int			i;
15791da177e4SLinus Torvalds 	struct keyspan_port_private 	*p_priv;
15801da177e4SLinus Torvalds 
15811da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
15821da177e4SLinus Torvalds 
15831da177e4SLinus Torvalds 	p_priv->rts_state = 0;
15841da177e4SLinus Torvalds 	p_priv->dtr_state = 0;
15851da177e4SLinus Torvalds 
15861da177e4SLinus Torvalds 	keyspan_send_setup(port, 2);
15871da177e4SLinus Torvalds 	/* pilot-xfer seems to work best with this delay */
15881da177e4SLinus Torvalds 	mdelay(100);
15891da177e4SLinus Torvalds 
15901da177e4SLinus Torvalds 	p_priv->out_flip = 0;
15911da177e4SLinus Torvalds 	p_priv->in_flip = 0;
15921da177e4SLinus Torvalds 
159361924505SJohan Hovold 	usb_kill_urb(p_priv->inack_urb);
15941da177e4SLinus Torvalds 	for (i = 0; i < 2; i++) {
159561924505SJohan Hovold 		usb_kill_urb(p_priv->in_urbs[i]);
159661924505SJohan Hovold 		usb_kill_urb(p_priv->out_urbs[i]);
15971da177e4SLinus Torvalds 	}
15981da177e4SLinus Torvalds }
15991da177e4SLinus Torvalds 
16001da177e4SLinus Torvalds /* download the firmware to a pre-renumeration device */
16011da177e4SLinus Torvalds static int keyspan_fake_startup(struct usb_serial *serial)
16021da177e4SLinus Torvalds {
16031da177e4SLinus Torvalds 	char	*fw_name;
16041da177e4SLinus Torvalds 
1605049c6b4eSGreg Kroah-Hartman 	dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
16061da177e4SLinus Torvalds 		le16_to_cpu(serial->dev->descriptor.bcdDevice),
16071da177e4SLinus Torvalds 		le16_to_cpu(serial->dev->descriptor.idProduct));
16081da177e4SLinus Torvalds 
1609deb91685SAlan Cox 	if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1610deb91685SAlan Cox 								!= 0x8000) {
1611049c6b4eSGreg Kroah-Hartman 		dev_dbg(&serial->dev->dev, "Firmware already loaded.  Quitting.\n");
1612deb91685SAlan Cox 		return 1;
16131da177e4SLinus Torvalds 	}
16141da177e4SLinus Torvalds 
16151da177e4SLinus Torvalds 		/* Select firmware image on the basis of idProduct */
16161da177e4SLinus Torvalds 	switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
16171da177e4SLinus Torvalds 	case keyspan_usa28_pre_product_id:
16182971c579SDavid Woodhouse 		fw_name = "keyspan/usa28.fw";
16191da177e4SLinus Torvalds 		break;
16201da177e4SLinus Torvalds 
16211da177e4SLinus Torvalds 	case keyspan_usa28x_pre_product_id:
16222971c579SDavid Woodhouse 		fw_name = "keyspan/usa28x.fw";
16231da177e4SLinus Torvalds 		break;
16241da177e4SLinus Torvalds 
16251da177e4SLinus Torvalds 	case keyspan_usa28xa_pre_product_id:
16262971c579SDavid Woodhouse 		fw_name = "keyspan/usa28xa.fw";
16271da177e4SLinus Torvalds 		break;
16281da177e4SLinus Torvalds 
16291da177e4SLinus Torvalds 	case keyspan_usa28xb_pre_product_id:
16302971c579SDavid Woodhouse 		fw_name = "keyspan/usa28xb.fw";
16311da177e4SLinus Torvalds 		break;
16321da177e4SLinus Torvalds 
16331da177e4SLinus Torvalds 	case keyspan_usa19_pre_product_id:
16342971c579SDavid Woodhouse 		fw_name = "keyspan/usa19.fw";
16351da177e4SLinus Torvalds 		break;
16361da177e4SLinus Torvalds 
16371da177e4SLinus Torvalds 	case keyspan_usa19qi_pre_product_id:
16382971c579SDavid Woodhouse 		fw_name = "keyspan/usa19qi.fw";
16391da177e4SLinus Torvalds 		break;
16401da177e4SLinus Torvalds 
16411da177e4SLinus Torvalds 	case keyspan_mpr_pre_product_id:
16422971c579SDavid Woodhouse 		fw_name = "keyspan/mpr.fw";
16431da177e4SLinus Torvalds 		break;
16441da177e4SLinus Torvalds 
16451da177e4SLinus Torvalds 	case keyspan_usa19qw_pre_product_id:
16462971c579SDavid Woodhouse 		fw_name = "keyspan/usa19qw.fw";
16471da177e4SLinus Torvalds 		break;
16481da177e4SLinus Torvalds 
16491da177e4SLinus Torvalds 	case keyspan_usa18x_pre_product_id:
16502971c579SDavid Woodhouse 		fw_name = "keyspan/usa18x.fw";
16511da177e4SLinus Torvalds 		break;
16521da177e4SLinus Torvalds 
16531da177e4SLinus Torvalds 	case keyspan_usa19w_pre_product_id:
16542971c579SDavid Woodhouse 		fw_name = "keyspan/usa19w.fw";
16551da177e4SLinus Torvalds 		break;
16561da177e4SLinus Torvalds 
16571da177e4SLinus Torvalds 	case keyspan_usa49w_pre_product_id:
16582971c579SDavid Woodhouse 		fw_name = "keyspan/usa49w.fw";
16591da177e4SLinus Torvalds 		break;
16601da177e4SLinus Torvalds 
16611da177e4SLinus Torvalds 	case keyspan_usa49wlc_pre_product_id:
16622971c579SDavid Woodhouse 		fw_name = "keyspan/usa49wlc.fw";
16631da177e4SLinus Torvalds 		break;
16641da177e4SLinus Torvalds 
16651da177e4SLinus Torvalds 	default:
16662971c579SDavid Woodhouse 		dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
16672971c579SDavid Woodhouse 			le16_to_cpu(serial->dev->descriptor.idProduct));
16682971c579SDavid Woodhouse 		return 1;
16691da177e4SLinus Torvalds 	}
16701da177e4SLinus Torvalds 
1671049c6b4eSGreg Kroah-Hartman 	dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
16721da177e4SLinus Torvalds 
16738d733e26SRene Buergel 	if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
16748d733e26SRene Buergel 		dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
16758d733e26SRene Buergel 			fw_name);
16768d733e26SRene Buergel 		return -ENOENT;
16771da177e4SLinus Torvalds 	}
16781da177e4SLinus Torvalds 
16798d733e26SRene Buergel 	/* after downloading firmware Renumeration will occur in a
16801da177e4SLinus Torvalds 	  moment and the new device will bind to the real driver */
16811da177e4SLinus Torvalds 
16821da177e4SLinus Torvalds 	/* we don't want this device to have a driver assigned to it. */
1683deb91685SAlan Cox 	return 1;
16841da177e4SLinus Torvalds }
16851da177e4SLinus Torvalds 
16861da177e4SLinus Torvalds /* Helper functions used by keyspan_setup_urbs */
1687fdcba53eSRainer Weikusat static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1688fdcba53eSRainer Weikusat 						     int endpoint)
1689fdcba53eSRainer Weikusat {
1690fdcba53eSRainer Weikusat 	struct usb_host_interface *iface_desc;
1691fdcba53eSRainer Weikusat 	struct usb_endpoint_descriptor *ep;
1692fdcba53eSRainer Weikusat 	int i;
1693fdcba53eSRainer Weikusat 
1694fdcba53eSRainer Weikusat 	iface_desc = serial->interface->cur_altsetting;
1695fdcba53eSRainer Weikusat 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1696fdcba53eSRainer Weikusat 		ep = &iface_desc->endpoint[i].desc;
1697fdcba53eSRainer Weikusat 		if (ep->bEndpointAddress == endpoint)
1698fdcba53eSRainer Weikusat 			return ep;
1699fdcba53eSRainer Weikusat 	}
17000cd782b0SJohan Hovold 	dev_warn(&serial->interface->dev, "found no endpoint descriptor for endpoint %x\n",
17010cd782b0SJohan Hovold 			endpoint);
1702fdcba53eSRainer Weikusat 	return NULL;
1703fdcba53eSRainer Weikusat }
1704fdcba53eSRainer Weikusat 
17051da177e4SLinus Torvalds static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
17061da177e4SLinus Torvalds 				      int dir, void *ctx, char *buf, int len,
17077d12e780SDavid Howells 				      void (*callback)(struct urb *))
17081da177e4SLinus Torvalds {
17091da177e4SLinus Torvalds 	struct urb *urb;
1710fdcba53eSRainer Weikusat 	struct usb_endpoint_descriptor const *ep_desc;
1711fdcba53eSRainer Weikusat 	char const *ep_type_name;
17121da177e4SLinus Torvalds 
17131da177e4SLinus Torvalds 	if (endpoint == -1)
17141da177e4SLinus Torvalds 		return NULL;		/* endpoint not needed */
17151da177e4SLinus Torvalds 
17160cd782b0SJohan Hovold 	dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %x\n",
17170cd782b0SJohan Hovold 			__func__, endpoint);
17181da177e4SLinus Torvalds 	urb = usb_alloc_urb(0, GFP_KERNEL);		/* No ISO */
171910c642d0SJohan Hovold 	if (!urb)
17201da177e4SLinus Torvalds 		return NULL;
17211da177e4SLinus Torvalds 
17220ca1268eSLucy McCoy 	if (endpoint == 0) {
17230ca1268eSLucy McCoy 		/* control EP filled in when used */
17240ca1268eSLucy McCoy 		return urb;
17250ca1268eSLucy McCoy 	}
17260ca1268eSLucy McCoy 
1727fdcba53eSRainer Weikusat 	ep_desc = find_ep(serial, endpoint);
1728fdcba53eSRainer Weikusat 	if (!ep_desc) {
17297d7e21faSJohan Hovold 		usb_free_urb(urb);
17307d7e21faSJohan Hovold 		return NULL;
1731fdcba53eSRainer Weikusat 	}
1732fdcba53eSRainer Weikusat 	if (usb_endpoint_xfer_int(ep_desc)) {
1733fdcba53eSRainer Weikusat 		ep_type_name = "INT";
1734fdcba53eSRainer Weikusat 		usb_fill_int_urb(urb, serial->dev,
1735fdcba53eSRainer Weikusat 				 usb_sndintpipe(serial->dev, endpoint) | dir,
1736fdcba53eSRainer Weikusat 				 buf, len, callback, ctx,
1737fdcba53eSRainer Weikusat 				 ep_desc->bInterval);
1738fdcba53eSRainer Weikusat 	} else if (usb_endpoint_xfer_bulk(ep_desc)) {
1739fdcba53eSRainer Weikusat 		ep_type_name = "BULK";
17401da177e4SLinus Torvalds 		usb_fill_bulk_urb(urb, serial->dev,
17411da177e4SLinus Torvalds 				  usb_sndbulkpipe(serial->dev, endpoint) | dir,
17421da177e4SLinus Torvalds 				  buf, len, callback, ctx);
1743fdcba53eSRainer Weikusat 	} else {
1744fdcba53eSRainer Weikusat 		dev_warn(&serial->interface->dev,
1745fdcba53eSRainer Weikusat 			 "unsupported endpoint type %x\n",
17462e0fe709SJulia Lawall 			 usb_endpoint_type(ep_desc));
1747fdcba53eSRainer Weikusat 		usb_free_urb(urb);
1748fdcba53eSRainer Weikusat 		return NULL;
1749fdcba53eSRainer Weikusat 	}
17501da177e4SLinus Torvalds 
1751049c6b4eSGreg Kroah-Hartman 	dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
1752fdcba53eSRainer Weikusat 	    __func__, urb, ep_type_name, endpoint);
17531da177e4SLinus Torvalds 	return urb;
17541da177e4SLinus Torvalds }
17551da177e4SLinus Torvalds 
17561da177e4SLinus Torvalds static struct callbacks {
17577d12e780SDavid Howells 	void	(*instat_callback)(struct urb *);
17587d12e780SDavid Howells 	void	(*glocont_callback)(struct urb *);
17597d12e780SDavid Howells 	void	(*indat_callback)(struct urb *);
17607d12e780SDavid Howells 	void	(*outdat_callback)(struct urb *);
17617d12e780SDavid Howells 	void	(*inack_callback)(struct urb *);
17627d12e780SDavid Howells 	void	(*outcont_callback)(struct urb *);
17631da177e4SLinus Torvalds } keyspan_callbacks[] = {
17641da177e4SLinus Torvalds 	{
17651da177e4SLinus Torvalds 		/* msg_usa26 callbacks */
17661da177e4SLinus Torvalds 		.instat_callback =	usa26_instat_callback,
17671da177e4SLinus Torvalds 		.glocont_callback =	usa26_glocont_callback,
17681da177e4SLinus Torvalds 		.indat_callback =	usa26_indat_callback,
17691da177e4SLinus Torvalds 		.outdat_callback =	usa2x_outdat_callback,
17701da177e4SLinus Torvalds 		.inack_callback =	usa26_inack_callback,
17711da177e4SLinus Torvalds 		.outcont_callback =	usa26_outcont_callback,
17721da177e4SLinus Torvalds 	}, {
17731da177e4SLinus Torvalds 		/* msg_usa28 callbacks */
17741da177e4SLinus Torvalds 		.instat_callback =	usa28_instat_callback,
17751da177e4SLinus Torvalds 		.glocont_callback =	usa28_glocont_callback,
17761da177e4SLinus Torvalds 		.indat_callback =	usa28_indat_callback,
17771da177e4SLinus Torvalds 		.outdat_callback =	usa2x_outdat_callback,
17781da177e4SLinus Torvalds 		.inack_callback =	usa28_inack_callback,
17791da177e4SLinus Torvalds 		.outcont_callback =	usa28_outcont_callback,
17801da177e4SLinus Torvalds 	}, {
17811da177e4SLinus Torvalds 		/* msg_usa49 callbacks */
17821da177e4SLinus Torvalds 		.instat_callback =	usa49_instat_callback,
17831da177e4SLinus Torvalds 		.glocont_callback =	usa49_glocont_callback,
17841da177e4SLinus Torvalds 		.indat_callback =	usa49_indat_callback,
17851da177e4SLinus Torvalds 		.outdat_callback =	usa2x_outdat_callback,
17861da177e4SLinus Torvalds 		.inack_callback =	usa49_inack_callback,
17871da177e4SLinus Torvalds 		.outcont_callback =	usa49_outcont_callback,
17881da177e4SLinus Torvalds 	}, {
17891da177e4SLinus Torvalds 		/* msg_usa90 callbacks */
17901da177e4SLinus Torvalds 		.instat_callback =	usa90_instat_callback,
17911da177e4SLinus Torvalds 		.glocont_callback =	usa28_glocont_callback,
17921da177e4SLinus Torvalds 		.indat_callback =	usa90_indat_callback,
17931da177e4SLinus Torvalds 		.outdat_callback =	usa2x_outdat_callback,
17941da177e4SLinus Torvalds 		.inack_callback =	usa28_inack_callback,
17951da177e4SLinus Torvalds 		.outcont_callback =	usa90_outcont_callback,
17960ca1268eSLucy McCoy 	}, {
17970ca1268eSLucy McCoy 		/* msg_usa67 callbacks */
17980ca1268eSLucy McCoy 		.instat_callback =	usa67_instat_callback,
17990ca1268eSLucy McCoy 		.glocont_callback =	usa67_glocont_callback,
18000ca1268eSLucy McCoy 		.indat_callback =	usa26_indat_callback,
18010ca1268eSLucy McCoy 		.outdat_callback =	usa2x_outdat_callback,
18020ca1268eSLucy McCoy 		.inack_callback =	usa26_inack_callback,
18030ca1268eSLucy McCoy 		.outcont_callback =	usa26_outcont_callback,
18041da177e4SLinus Torvalds 	}
18051da177e4SLinus Torvalds };
18061da177e4SLinus Torvalds 
18071da177e4SLinus Torvalds 	/* Generic setup urbs function that uses
18081da177e4SLinus Torvalds 	   data in device_details */
18091da177e4SLinus Torvalds static void keyspan_setup_urbs(struct usb_serial *serial)
18101da177e4SLinus Torvalds {
18111da177e4SLinus Torvalds 	struct keyspan_serial_private 	*s_priv;
18121da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
18131da177e4SLinus Torvalds 	struct callbacks		*cback;
18141da177e4SLinus Torvalds 
18151da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
18161da177e4SLinus Torvalds 	d_details = s_priv->device_details;
18171da177e4SLinus Torvalds 
18181da177e4SLinus Torvalds 	/* Setup values for the various callback routines */
18191da177e4SLinus Torvalds 	cback = &keyspan_callbacks[d_details->msg_format];
18201da177e4SLinus Torvalds 
18211da177e4SLinus Torvalds 	/* Allocate and set up urbs for each one that is in use,
18221da177e4SLinus Torvalds 	   starting with instat endpoints */
18231da177e4SLinus Torvalds 	s_priv->instat_urb = keyspan_setup_urb
18241da177e4SLinus Torvalds 		(serial, d_details->instat_endpoint, USB_DIR_IN,
18251da177e4SLinus Torvalds 		 serial, s_priv->instat_buf, INSTAT_BUFLEN,
18261da177e4SLinus Torvalds 		 cback->instat_callback);
18271da177e4SLinus Torvalds 
18280ca1268eSLucy McCoy 	s_priv->indat_urb = keyspan_setup_urb
18290ca1268eSLucy McCoy 		(serial, d_details->indat_endpoint, USB_DIR_IN,
18300ca1268eSLucy McCoy 		 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
18310ca1268eSLucy McCoy 		 usa49wg_indat_callback);
18320ca1268eSLucy McCoy 
18331da177e4SLinus Torvalds 	s_priv->glocont_urb = keyspan_setup_urb
18341da177e4SLinus Torvalds 		(serial, d_details->glocont_endpoint, USB_DIR_OUT,
18351da177e4SLinus Torvalds 		 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
18361da177e4SLinus Torvalds 		 cback->glocont_callback);
18371da177e4SLinus Torvalds }
18381da177e4SLinus Torvalds 
18391da177e4SLinus Torvalds /* usa19 function doesn't require prescaler */
1840049c6b4eSGreg Kroah-Hartman static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1841049c6b4eSGreg Kroah-Hartman 				   u32 baud_rate, u32 baudclk, u8 *rate_hi,
18421da177e4SLinus Torvalds 				   u8 *rate_low, u8 *prescaler, int portnum)
18431da177e4SLinus Torvalds {
18441da177e4SLinus Torvalds 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
18451da177e4SLinus Torvalds 		div,	/* divisor */
18461da177e4SLinus Torvalds 		cnt;	/* inverse of divisor (programmed into 8051) */
18471da177e4SLinus Torvalds 
1848049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
18491da177e4SLinus Torvalds 
18501da177e4SLinus Torvalds 	/* prevent divide by zero...  */
1851deb91685SAlan Cox 	b16 = baud_rate * 16L;
1852deb91685SAlan Cox 	if (b16 == 0)
1853deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
18541da177e4SLinus Torvalds 	/* Any "standard" rate over 57k6 is marginal on the USA-19
18551da177e4SLinus Torvalds 	   as we run out of divisor resolution. */
1856deb91685SAlan Cox 	if (baud_rate > 57600)
1857deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
18581da177e4SLinus Torvalds 
18591da177e4SLinus Torvalds 	/* calculate the divisor and the counter (its inverse) */
1860deb91685SAlan Cox 	div = baudclk / b16;
1861deb91685SAlan Cox 	if (div == 0)
1862deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
1863deb91685SAlan Cox 	else
18641da177e4SLinus Torvalds 		cnt = 0 - div;
18651da177e4SLinus Torvalds 
1866deb91685SAlan Cox 	if (div > 0xffff)
1867deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
18681da177e4SLinus Torvalds 
18691da177e4SLinus Torvalds 	/* return the counter values if non-null */
1870deb91685SAlan Cox 	if (rate_low)
18711da177e4SLinus Torvalds 		*rate_low = (u8) (cnt & 0xff);
1872deb91685SAlan Cox 	if (rate_hi)
18731da177e4SLinus Torvalds 		*rate_hi = (u8) ((cnt >> 8) & 0xff);
1874deb91685SAlan Cox 	if (rate_low && rate_hi)
1875049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
1876deb91685SAlan Cox 				__func__, baud_rate, *rate_hi, *rate_low);
1877deb91685SAlan Cox 	return KEYSPAN_BAUD_RATE_OK;
18781da177e4SLinus Torvalds }
18791da177e4SLinus Torvalds 
18801da177e4SLinus Torvalds /* usa19hs function doesn't require prescaler */
1881049c6b4eSGreg Kroah-Hartman static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1882049c6b4eSGreg Kroah-Hartman 				     u32 baud_rate, u32 baudclk, u8 *rate_hi,
18831da177e4SLinus Torvalds 				     u8 *rate_low, u8 *prescaler, int portnum)
18841da177e4SLinus Torvalds {
18851da177e4SLinus Torvalds 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
18861da177e4SLinus Torvalds 			div;	/* divisor */
18871da177e4SLinus Torvalds 
1888049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
18891da177e4SLinus Torvalds 
18901da177e4SLinus Torvalds 	/* prevent divide by zero...  */
1891deb91685SAlan Cox 	b16 = baud_rate * 16L;
1892deb91685SAlan Cox 	if (b16 == 0)
1893deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
18941da177e4SLinus Torvalds 
18951da177e4SLinus Torvalds 	/* calculate the divisor */
1896deb91685SAlan Cox 	div = baudclk / b16;
1897deb91685SAlan Cox 	if (div == 0)
1898deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
18991da177e4SLinus Torvalds 
19001da177e4SLinus Torvalds 	if (div > 0xffff)
1901deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
19021da177e4SLinus Torvalds 
19031da177e4SLinus Torvalds 	/* return the counter values if non-null */
19041da177e4SLinus Torvalds 	if (rate_low)
19051da177e4SLinus Torvalds 		*rate_low = (u8) (div & 0xff);
19061da177e4SLinus Torvalds 
19071da177e4SLinus Torvalds 	if (rate_hi)
19081da177e4SLinus Torvalds 		*rate_hi = (u8) ((div >> 8) & 0xff);
19091da177e4SLinus Torvalds 
19101da177e4SLinus Torvalds 	if (rate_low && rate_hi)
1911049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
1912deb91685SAlan Cox 			__func__, baud_rate, *rate_hi, *rate_low);
19131da177e4SLinus Torvalds 
1914deb91685SAlan Cox 	return KEYSPAN_BAUD_RATE_OK;
19151da177e4SLinus Torvalds }
19161da177e4SLinus Torvalds 
1917049c6b4eSGreg Kroah-Hartman static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1918049c6b4eSGreg Kroah-Hartman 				    u32 baud_rate, u32 baudclk, u8 *rate_hi,
19191da177e4SLinus Torvalds 				    u8 *rate_low, u8 *prescaler, int portnum)
19201da177e4SLinus Torvalds {
19211da177e4SLinus Torvalds 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
19221da177e4SLinus Torvalds 		clk,	/* clock with 13/8 prescaler */
19231da177e4SLinus Torvalds 		div,	/* divisor using 13/8 prescaler */
19241da177e4SLinus Torvalds 		res,	/* resulting baud rate using 13/8 prescaler */
19251da177e4SLinus Torvalds 		diff,	/* error using 13/8 prescaler */
19261da177e4SLinus Torvalds 		smallest_diff;
19271da177e4SLinus Torvalds 	u8	best_prescaler;
19281da177e4SLinus Torvalds 	int	i;
19291da177e4SLinus Torvalds 
1930049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
19311da177e4SLinus Torvalds 
19321da177e4SLinus Torvalds 	/* prevent divide by zero */
1933deb91685SAlan Cox 	b16 = baud_rate * 16L;
1934deb91685SAlan Cox 	if (b16 == 0)
1935deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
19361da177e4SLinus Torvalds 
19371da177e4SLinus Torvalds 	/* Calculate prescaler by trying them all and looking
19381da177e4SLinus Torvalds 	   for best fit */
19391da177e4SLinus Torvalds 
19401da177e4SLinus Torvalds 	/* start with largest possible difference */
19411da177e4SLinus Torvalds 	smallest_diff = 0xffffffff;
19421da177e4SLinus Torvalds 
19431da177e4SLinus Torvalds 		/* 0 is an invalid prescaler, used as a flag */
19441da177e4SLinus Torvalds 	best_prescaler = 0;
19451da177e4SLinus Torvalds 
19461da177e4SLinus Torvalds 	for (i = 8; i <= 0xff; ++i) {
19471da177e4SLinus Torvalds 		clk = (baudclk * 8) / (u32) i;
19481da177e4SLinus Torvalds 
1949deb91685SAlan Cox 		div = clk / b16;
1950deb91685SAlan Cox 		if (div == 0)
19511da177e4SLinus Torvalds 			continue;
19521da177e4SLinus Torvalds 
19531da177e4SLinus Torvalds 		res = clk / div;
19541da177e4SLinus Torvalds 		diff = (res > b16) ? (res-b16) : (b16-res);
19551da177e4SLinus Torvalds 
19561da177e4SLinus Torvalds 		if (diff < smallest_diff) {
19571da177e4SLinus Torvalds 			best_prescaler = i;
19581da177e4SLinus Torvalds 			smallest_diff = diff;
19591da177e4SLinus Torvalds 		}
19601da177e4SLinus Torvalds 	}
19611da177e4SLinus Torvalds 
1962deb91685SAlan Cox 	if (best_prescaler == 0)
1963deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
19641da177e4SLinus Torvalds 
19651da177e4SLinus Torvalds 	clk = (baudclk * 8) / (u32) best_prescaler;
19661da177e4SLinus Torvalds 	div = clk / b16;
19671da177e4SLinus Torvalds 
19681da177e4SLinus Torvalds 	/* return the divisor and prescaler if non-null */
1969deb91685SAlan Cox 	if (rate_low)
19701da177e4SLinus Torvalds 		*rate_low = (u8) (div & 0xff);
1971deb91685SAlan Cox 	if (rate_hi)
19721da177e4SLinus Torvalds 		*rate_hi = (u8) ((div >> 8) & 0xff);
19731da177e4SLinus Torvalds 	if (prescaler) {
19741da177e4SLinus Torvalds 		*prescaler = best_prescaler;
1975049c6b4eSGreg Kroah-Hartman 		/*  dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
19761da177e4SLinus Torvalds 	}
1977deb91685SAlan Cox 	return KEYSPAN_BAUD_RATE_OK;
19781da177e4SLinus Torvalds }
19791da177e4SLinus Torvalds 
19801da177e4SLinus Torvalds 	/* USA-28 supports different maximum baud rates on each port */
1981049c6b4eSGreg Kroah-Hartman static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1982049c6b4eSGreg Kroah-Hartman 				   u32 baud_rate, u32 baudclk, u8 *rate_hi,
19831da177e4SLinus Torvalds 				   u8 *rate_low, u8 *prescaler, int portnum)
19841da177e4SLinus Torvalds {
19851da177e4SLinus Torvalds 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
19861da177e4SLinus Torvalds 		div,	/* divisor */
19871da177e4SLinus Torvalds 		cnt;	/* inverse of divisor (programmed into 8051) */
19881da177e4SLinus Torvalds 
1989049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
19901da177e4SLinus Torvalds 
19911da177e4SLinus Torvalds 		/* prevent divide by zero */
1992deb91685SAlan Cox 	b16 = baud_rate * 16L;
1993deb91685SAlan Cox 	if (b16 == 0)
1994deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
19951da177e4SLinus Torvalds 
19961da177e4SLinus Torvalds 	/* calculate the divisor and the counter (its inverse) */
1997deb91685SAlan Cox 	div = KEYSPAN_USA28_BAUDCLK / b16;
1998deb91685SAlan Cox 	if (div == 0)
1999deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
2000deb91685SAlan Cox 	else
20011da177e4SLinus Torvalds 		cnt = 0 - div;
20021da177e4SLinus Torvalds 
20031da177e4SLinus Torvalds 	/* check for out of range, based on portnum,
20041da177e4SLinus Torvalds 	   and return result */
20051da177e4SLinus Torvalds 	if (portnum == 0) {
20061da177e4SLinus Torvalds 		if (div > 0xffff)
2007deb91685SAlan Cox 			return KEYSPAN_INVALID_BAUD_RATE;
2008deb91685SAlan Cox 	} else {
20091da177e4SLinus Torvalds 		if (portnum == 1) {
2010deb91685SAlan Cox 			if (div > 0xff)
2011deb91685SAlan Cox 				return KEYSPAN_INVALID_BAUD_RATE;
2012deb91685SAlan Cox 		} else
2013deb91685SAlan Cox 			return KEYSPAN_INVALID_BAUD_RATE;
20141da177e4SLinus Torvalds 	}
20151da177e4SLinus Torvalds 
20161da177e4SLinus Torvalds 		/* return the counter values if not NULL
20171da177e4SLinus Torvalds 		   (port 1 will ignore retHi) */
2018deb91685SAlan Cox 	if (rate_low)
20191da177e4SLinus Torvalds 		*rate_low = (u8) (cnt & 0xff);
2020deb91685SAlan Cox 	if (rate_hi)
20211da177e4SLinus Torvalds 		*rate_hi = (u8) ((cnt >> 8) & 0xff);
2022049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
2023deb91685SAlan Cox 	return KEYSPAN_BAUD_RATE_OK;
20241da177e4SLinus Torvalds }
20251da177e4SLinus Torvalds 
20261da177e4SLinus Torvalds static int keyspan_usa26_send_setup(struct usb_serial *serial,
20271da177e4SLinus Torvalds 				    struct usb_serial_port *port,
20281da177e4SLinus Torvalds 				    int reset_port)
20291da177e4SLinus Torvalds {
20301da177e4SLinus Torvalds 	struct keyspan_usa26_portControlMessage	msg;
20311da177e4SLinus Torvalds 	struct keyspan_serial_private 		*s_priv;
20321da177e4SLinus Torvalds 	struct keyspan_port_private 		*p_priv;
20331da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
20341da177e4SLinus Torvalds 	struct urb				*this_urb;
20351da177e4SLinus Torvalds 	int 					device_port, err;
20361da177e4SLinus Torvalds 
2037049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
20381da177e4SLinus Torvalds 
20391da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
20401da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
20411da177e4SLinus Torvalds 	d_details = s_priv->device_details;
20421143832eSGreg Kroah-Hartman 	device_port = port->port_number;
20431da177e4SLinus Torvalds 
20441da177e4SLinus Torvalds 	this_urb = p_priv->outcont_urb;
20451da177e4SLinus Torvalds 
20461da177e4SLinus Torvalds 		/* Make sure we have an urb then send the message */
20471da177e4SLinus Torvalds 	if (this_urb == NULL) {
2048049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
20491da177e4SLinus Torvalds 		return -1;
20501da177e4SLinus Torvalds 	}
20511da177e4SLinus Torvalds 
20520cd782b0SJohan Hovold 	dev_dbg(&port->dev, "%s - endpoint %x\n",
20530cd782b0SJohan Hovold 			__func__, usb_pipeendpoint(this_urb->pipe));
2054d5afce82SRickard Strandqvist 
20551da177e4SLinus Torvalds 	/* Save reset port val for resend.
20560ca1268eSLucy McCoy 	   Don't overwrite resend for open/close condition. */
20570ca1268eSLucy McCoy 	if ((reset_port + 1) > p_priv->resend_cont)
20581da177e4SLinus Torvalds 		p_priv->resend_cont = reset_port + 1;
20591da177e4SLinus Torvalds 	if (this_urb->status == -EINPROGRESS) {
2060049c6b4eSGreg Kroah-Hartman 		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
20611da177e4SLinus Torvalds 		mdelay(5);
2062deb91685SAlan Cox 		return -1;
20631da177e4SLinus Torvalds 	}
20641da177e4SLinus Torvalds 
20651da177e4SLinus Torvalds 	memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
20661da177e4SLinus Torvalds 
20671da177e4SLinus Torvalds 	/* Only set baud rate if it's changed */
20681da177e4SLinus Torvalds 	if (p_priv->old_baud != p_priv->baud) {
20691da177e4SLinus Torvalds 		p_priv->old_baud = p_priv->baud;
20701da177e4SLinus Torvalds 		msg.setClocking = 0xff;
2071049c6b4eSGreg Kroah-Hartman 		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2072049c6b4eSGreg Kroah-Hartman 						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
2073049c6b4eSGreg Kroah-Hartman 						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2074049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2075deb91685SAlan Cox 				__func__, p_priv->baud);
20761da177e4SLinus Torvalds 			msg.baudLo = 0;
20771da177e4SLinus Torvalds 			msg.baudHi = 125;	/* Values for 9600 baud */
20781da177e4SLinus Torvalds 			msg.prescaler = 10;
20791da177e4SLinus Torvalds 		}
20801da177e4SLinus Torvalds 		msg.setPrescaler = 0xff;
20811da177e4SLinus Torvalds 	}
20821da177e4SLinus Torvalds 
20831da177e4SLinus Torvalds 	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
20841da177e4SLinus Torvalds 	switch (p_priv->cflag & CSIZE) {
20851da177e4SLinus Torvalds 	case CS5:
20861da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_5;
20871da177e4SLinus Torvalds 		break;
20881da177e4SLinus Torvalds 	case CS6:
20891da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_6;
20901da177e4SLinus Torvalds 		break;
20911da177e4SLinus Torvalds 	case CS7:
20921da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_7;
20931da177e4SLinus Torvalds 		break;
20941da177e4SLinus Torvalds 	case CS8:
20951da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_8;
20961da177e4SLinus Torvalds 		break;
20971da177e4SLinus Torvalds 	}
20981da177e4SLinus Torvalds 	if (p_priv->cflag & PARENB) {
20991da177e4SLinus Torvalds 		/* note USA_PARITY_NONE == 0 */
21001da177e4SLinus Torvalds 		msg.lcr |= (p_priv->cflag & PARODD) ?
21011da177e4SLinus Torvalds 			USA_PARITY_ODD : USA_PARITY_EVEN;
21021da177e4SLinus Torvalds 	}
21031da177e4SLinus Torvalds 	msg.setLcr = 0xff;
21041da177e4SLinus Torvalds 
21051da177e4SLinus Torvalds 	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
21061da177e4SLinus Torvalds 	msg.xonFlowControl = 0;
21071da177e4SLinus Torvalds 	msg.setFlowControl = 0xff;
21081da177e4SLinus Torvalds 	msg.forwardingLength = 16;
21091da177e4SLinus Torvalds 	msg.xonChar = 17;
21101da177e4SLinus Torvalds 	msg.xoffChar = 19;
21111da177e4SLinus Torvalds 
21121da177e4SLinus Torvalds 	/* Opening port */
21131da177e4SLinus Torvalds 	if (reset_port == 1) {
21141da177e4SLinus Torvalds 		msg._txOn = 1;
21151da177e4SLinus Torvalds 		msg._txOff = 0;
21161da177e4SLinus Torvalds 		msg.txFlush = 0;
21171da177e4SLinus Torvalds 		msg.txBreak = 0;
21181da177e4SLinus Torvalds 		msg.rxOn = 1;
21191da177e4SLinus Torvalds 		msg.rxOff = 0;
21201da177e4SLinus Torvalds 		msg.rxFlush = 1;
21211da177e4SLinus Torvalds 		msg.rxForward = 0;
21221da177e4SLinus Torvalds 		msg.returnStatus = 0;
21231da177e4SLinus Torvalds 		msg.resetDataToggle = 0xff;
21241da177e4SLinus Torvalds 	}
21251da177e4SLinus Torvalds 
21261da177e4SLinus Torvalds 	/* Closing port */
21271da177e4SLinus Torvalds 	else if (reset_port == 2) {
21281da177e4SLinus Torvalds 		msg._txOn = 0;
21291da177e4SLinus Torvalds 		msg._txOff = 1;
21301da177e4SLinus Torvalds 		msg.txFlush = 0;
21311da177e4SLinus Torvalds 		msg.txBreak = 0;
21321da177e4SLinus Torvalds 		msg.rxOn = 0;
21331da177e4SLinus Torvalds 		msg.rxOff = 1;
21341da177e4SLinus Torvalds 		msg.rxFlush = 1;
21351da177e4SLinus Torvalds 		msg.rxForward = 0;
21361da177e4SLinus Torvalds 		msg.returnStatus = 0;
21371da177e4SLinus Torvalds 		msg.resetDataToggle = 0;
21381da177e4SLinus Torvalds 	}
21391da177e4SLinus Torvalds 
21401da177e4SLinus Torvalds 	/* Sending intermediate configs */
21411da177e4SLinus Torvalds 	else {
21421da177e4SLinus Torvalds 		msg._txOn = (!p_priv->break_on);
21431da177e4SLinus Torvalds 		msg._txOff = 0;
21441da177e4SLinus Torvalds 		msg.txFlush = 0;
21451da177e4SLinus Torvalds 		msg.txBreak = (p_priv->break_on);
21461da177e4SLinus Torvalds 		msg.rxOn = 0;
21471da177e4SLinus Torvalds 		msg.rxOff = 0;
21481da177e4SLinus Torvalds 		msg.rxFlush = 0;
21491da177e4SLinus Torvalds 		msg.rxForward = 0;
21501da177e4SLinus Torvalds 		msg.returnStatus = 0;
21511da177e4SLinus Torvalds 		msg.resetDataToggle = 0x0;
21521da177e4SLinus Torvalds 	}
21531da177e4SLinus Torvalds 
21541da177e4SLinus Torvalds 	/* Do handshaking outputs */
21551da177e4SLinus Torvalds 	msg.setTxTriState_setRts = 0xff;
21561da177e4SLinus Torvalds 	msg.txTriState_rts = p_priv->rts_state;
21571da177e4SLinus Torvalds 
21581da177e4SLinus Torvalds 	msg.setHskoa_setDtr = 0xff;
21591da177e4SLinus Torvalds 	msg.hskoa_dtr = p_priv->dtr_state;
21601da177e4SLinus Torvalds 
21611da177e4SLinus Torvalds 	p_priv->resend_cont = 0;
21621da177e4SLinus Torvalds 	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
21631da177e4SLinus Torvalds 
21641da177e4SLinus Torvalds 	/* send the data out the device on control endpoint */
21651da177e4SLinus Torvalds 	this_urb->transfer_buffer_length = sizeof(msg);
21661da177e4SLinus Torvalds 
2167deb91685SAlan Cox 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
2168deb91685SAlan Cox 	if (err != 0)
2169049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
2170a5b6f60cSAlan Cox 	return 0;
21711da177e4SLinus Torvalds }
21721da177e4SLinus Torvalds 
21731da177e4SLinus Torvalds static int keyspan_usa28_send_setup(struct usb_serial *serial,
21741da177e4SLinus Torvalds 				    struct usb_serial_port *port,
21751da177e4SLinus Torvalds 				    int reset_port)
21761da177e4SLinus Torvalds {
21771da177e4SLinus Torvalds 	struct keyspan_usa28_portControlMessage	msg;
21781da177e4SLinus Torvalds 	struct keyspan_serial_private	 	*s_priv;
21791da177e4SLinus Torvalds 	struct keyspan_port_private 		*p_priv;
21801da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
21811da177e4SLinus Torvalds 	struct urb				*this_urb;
21821da177e4SLinus Torvalds 	int 					device_port, err;
21831da177e4SLinus Torvalds 
21841da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
21851da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
21861da177e4SLinus Torvalds 	d_details = s_priv->device_details;
21871143832eSGreg Kroah-Hartman 	device_port = port->port_number;
21881da177e4SLinus Torvalds 
21891da177e4SLinus Torvalds 	/* only do something if we have a bulk out endpoint */
2190deb91685SAlan Cox 	this_urb = p_priv->outcont_urb;
2191deb91685SAlan Cox 	if (this_urb == NULL) {
2192049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
21931da177e4SLinus Torvalds 		return -1;
21941da177e4SLinus Torvalds 	}
21951da177e4SLinus Torvalds 
21961da177e4SLinus Torvalds 	/* Save reset port val for resend.
21970ca1268eSLucy McCoy 	   Don't overwrite resend for open/close condition. */
21980ca1268eSLucy McCoy 	if ((reset_port + 1) > p_priv->resend_cont)
21991da177e4SLinus Torvalds 		p_priv->resend_cont = reset_port + 1;
22001da177e4SLinus Torvalds 	if (this_urb->status == -EINPROGRESS) {
2201049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s already writing\n", __func__);
22021da177e4SLinus Torvalds 		mdelay(5);
2203deb91685SAlan Cox 		return -1;
22041da177e4SLinus Torvalds 	}
22051da177e4SLinus Torvalds 
22061da177e4SLinus Torvalds 	memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
22071da177e4SLinus Torvalds 
22081da177e4SLinus Torvalds 	msg.setBaudRate = 1;
2209049c6b4eSGreg Kroah-Hartman 	if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2210049c6b4eSGreg Kroah-Hartman 					   &msg.baudHi, &msg.baudLo, NULL,
2211049c6b4eSGreg Kroah-Hartman 					   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2212049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
2213deb91685SAlan Cox 						__func__, p_priv->baud);
22141da177e4SLinus Torvalds 		msg.baudLo = 0xff;
22151da177e4SLinus Torvalds 		msg.baudHi = 0xb2;	/* Values for 9600 baud */
22161da177e4SLinus Torvalds 	}
22171da177e4SLinus Torvalds 
22181da177e4SLinus Torvalds 	/* If parity is enabled, we must calculate it ourselves. */
22191da177e4SLinus Torvalds 	msg.parity = 0;		/* XXX for now */
22201da177e4SLinus Torvalds 
22211da177e4SLinus Torvalds 	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
22221da177e4SLinus Torvalds 	msg.xonFlowControl = 0;
22231da177e4SLinus Torvalds 
22241da177e4SLinus Torvalds 	/* Do handshaking outputs, DTR is inverted relative to RTS */
22251da177e4SLinus Torvalds 	msg.rts = p_priv->rts_state;
22261da177e4SLinus Torvalds 	msg.dtr = p_priv->dtr_state;
22271da177e4SLinus Torvalds 
22281da177e4SLinus Torvalds 	msg.forwardingLength = 16;
22291da177e4SLinus Torvalds 	msg.forwardMs = 10;
22301da177e4SLinus Torvalds 	msg.breakThreshold = 45;
22311da177e4SLinus Torvalds 	msg.xonChar = 17;
22321da177e4SLinus Torvalds 	msg.xoffChar = 19;
22331da177e4SLinus Torvalds 
22341da177e4SLinus Torvalds 	/*msg.returnStatus = 1;
22351da177e4SLinus Torvalds 	msg.resetDataToggle = 0xff;*/
22361da177e4SLinus Torvalds 	/* Opening port */
22371da177e4SLinus Torvalds 	if (reset_port == 1) {
22381da177e4SLinus Torvalds 		msg._txOn = 1;
22391da177e4SLinus Torvalds 		msg._txOff = 0;
22401da177e4SLinus Torvalds 		msg.txFlush = 0;
22411da177e4SLinus Torvalds 		msg.txForceXoff = 0;
22421da177e4SLinus Torvalds 		msg.txBreak = 0;
22431da177e4SLinus Torvalds 		msg.rxOn = 1;
22441da177e4SLinus Torvalds 		msg.rxOff = 0;
22451da177e4SLinus Torvalds 		msg.rxFlush = 1;
22461da177e4SLinus Torvalds 		msg.rxForward = 0;
22471da177e4SLinus Torvalds 		msg.returnStatus = 0;
22481da177e4SLinus Torvalds 		msg.resetDataToggle = 0xff;
22491da177e4SLinus Torvalds 	}
22501da177e4SLinus Torvalds 	/* Closing port */
22511da177e4SLinus Torvalds 	else if (reset_port == 2) {
22521da177e4SLinus Torvalds 		msg._txOn = 0;
22531da177e4SLinus Torvalds 		msg._txOff = 1;
22541da177e4SLinus Torvalds 		msg.txFlush = 0;
22551da177e4SLinus Torvalds 		msg.txForceXoff = 0;
22561da177e4SLinus Torvalds 		msg.txBreak = 0;
22571da177e4SLinus Torvalds 		msg.rxOn = 0;
22581da177e4SLinus Torvalds 		msg.rxOff = 1;
22591da177e4SLinus Torvalds 		msg.rxFlush = 1;
22601da177e4SLinus Torvalds 		msg.rxForward = 0;
22611da177e4SLinus Torvalds 		msg.returnStatus = 0;
22621da177e4SLinus Torvalds 		msg.resetDataToggle = 0;
22631da177e4SLinus Torvalds 	}
22641da177e4SLinus Torvalds 	/* Sending intermediate configs */
22651da177e4SLinus Torvalds 	else {
22661da177e4SLinus Torvalds 		msg._txOn = (!p_priv->break_on);
22671da177e4SLinus Torvalds 		msg._txOff = 0;
22681da177e4SLinus Torvalds 		msg.txFlush = 0;
22691da177e4SLinus Torvalds 		msg.txForceXoff = 0;
22701da177e4SLinus Torvalds 		msg.txBreak = (p_priv->break_on);
22711da177e4SLinus Torvalds 		msg.rxOn = 0;
22721da177e4SLinus Torvalds 		msg.rxOff = 0;
22731da177e4SLinus Torvalds 		msg.rxFlush = 0;
22741da177e4SLinus Torvalds 		msg.rxForward = 0;
22751da177e4SLinus Torvalds 		msg.returnStatus = 0;
22761da177e4SLinus Torvalds 		msg.resetDataToggle = 0x0;
22771da177e4SLinus Torvalds 	}
22781da177e4SLinus Torvalds 
22791da177e4SLinus Torvalds 	p_priv->resend_cont = 0;
22801da177e4SLinus Torvalds 	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
22811da177e4SLinus Torvalds 
22821da177e4SLinus Torvalds 	/* send the data out the device on control endpoint */
22831da177e4SLinus Torvalds 	this_urb->transfer_buffer_length = sizeof(msg);
22841da177e4SLinus Torvalds 
2285deb91685SAlan Cox 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
2286deb91685SAlan Cox 	if (err != 0)
2287049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
22881da177e4SLinus Torvalds 
2289a5b6f60cSAlan Cox 	return 0;
22901da177e4SLinus Torvalds }
22911da177e4SLinus Torvalds 
22921da177e4SLinus Torvalds static int keyspan_usa49_send_setup(struct usb_serial *serial,
22931da177e4SLinus Torvalds 				    struct usb_serial_port *port,
22941da177e4SLinus Torvalds 				    int reset_port)
22951da177e4SLinus Torvalds {
22961da177e4SLinus Torvalds 	struct keyspan_usa49_portControlMessage	msg;
22970ca1268eSLucy McCoy 	struct usb_ctrlrequest 			*dr = NULL;
22981da177e4SLinus Torvalds 	struct keyspan_serial_private 		*s_priv;
22991da177e4SLinus Torvalds 	struct keyspan_port_private 		*p_priv;
23001da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
23011da177e4SLinus Torvalds 	struct urb				*this_urb;
23021da177e4SLinus Torvalds 	int 					err, device_port;
23031da177e4SLinus Torvalds 
23041da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
23051da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
23061da177e4SLinus Torvalds 	d_details = s_priv->device_details;
23071da177e4SLinus Torvalds 
23081da177e4SLinus Torvalds 	this_urb = s_priv->glocont_urb;
23091da177e4SLinus Torvalds 
23101da177e4SLinus Torvalds 	/* Work out which port within the device is being setup */
23111143832eSGreg Kroah-Hartman 	device_port = port->port_number;
23121da177e4SLinus Torvalds 
23131da177e4SLinus Torvalds 	/* Make sure we have an urb then send the message */
23141da177e4SLinus Torvalds 	if (this_urb == NULL) {
23151143832eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
23161da177e4SLinus Torvalds 		return -1;
23171da177e4SLinus Torvalds 	}
23181da177e4SLinus Torvalds 
23190cd782b0SJohan Hovold 	dev_dbg(&port->dev, "%s - endpoint %x (%d)\n",
23201143832eSGreg Kroah-Hartman 		__func__, usb_pipeendpoint(this_urb->pipe), device_port);
2321d866150aSHuzaifa Sidhpurwala 
23221da177e4SLinus Torvalds 	/* Save reset port val for resend.
23230ca1268eSLucy McCoy 	   Don't overwrite resend for open/close condition. */
23240ca1268eSLucy McCoy 	if ((reset_port + 1) > p_priv->resend_cont)
23251da177e4SLinus Torvalds 		p_priv->resend_cont = reset_port + 1;
23260ca1268eSLucy McCoy 
23271da177e4SLinus Torvalds 	if (this_urb->status == -EINPROGRESS) {
2328049c6b4eSGreg Kroah-Hartman 		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
23291da177e4SLinus Torvalds 		mdelay(5);
2330deb91685SAlan Cox 		return -1;
23311da177e4SLinus Torvalds 	}
23321da177e4SLinus Torvalds 
23331da177e4SLinus Torvalds 	memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
23341da177e4SLinus Torvalds 
23351da177e4SLinus Torvalds 	msg.portNumber = device_port;
23361da177e4SLinus Torvalds 
23371da177e4SLinus Torvalds 	/* Only set baud rate if it's changed */
23381da177e4SLinus Torvalds 	if (p_priv->old_baud != p_priv->baud) {
23391da177e4SLinus Torvalds 		p_priv->old_baud = p_priv->baud;
23401da177e4SLinus Torvalds 		msg.setClocking = 0xff;
2341049c6b4eSGreg Kroah-Hartman 		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2342049c6b4eSGreg Kroah-Hartman 						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
2343049c6b4eSGreg Kroah-Hartman 						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2344049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2345deb91685SAlan Cox 				__func__, p_priv->baud);
23461da177e4SLinus Torvalds 			msg.baudLo = 0;
23471da177e4SLinus Torvalds 			msg.baudHi = 125;	/* Values for 9600 baud */
23481da177e4SLinus Torvalds 			msg.prescaler = 10;
23491da177e4SLinus Torvalds 		}
2350deb91685SAlan Cox 		/* msg.setPrescaler = 0xff; */
23511da177e4SLinus Torvalds 	}
23521da177e4SLinus Torvalds 
23531da177e4SLinus Torvalds 	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
23541da177e4SLinus Torvalds 	switch (p_priv->cflag & CSIZE) {
23551da177e4SLinus Torvalds 	case CS5:
23561da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_5;
23571da177e4SLinus Torvalds 		break;
23581da177e4SLinus Torvalds 	case CS6:
23591da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_6;
23601da177e4SLinus Torvalds 		break;
23611da177e4SLinus Torvalds 	case CS7:
23621da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_7;
23631da177e4SLinus Torvalds 		break;
23641da177e4SLinus Torvalds 	case CS8:
23651da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_8;
23661da177e4SLinus Torvalds 		break;
23671da177e4SLinus Torvalds 	}
23681da177e4SLinus Torvalds 	if (p_priv->cflag & PARENB) {
23691da177e4SLinus Torvalds 		/* note USA_PARITY_NONE == 0 */
23701da177e4SLinus Torvalds 		msg.lcr |= (p_priv->cflag & PARODD) ?
23711da177e4SLinus Torvalds 			USA_PARITY_ODD : USA_PARITY_EVEN;
23721da177e4SLinus Torvalds 	}
23731da177e4SLinus Torvalds 	msg.setLcr = 0xff;
23741da177e4SLinus Torvalds 
23751da177e4SLinus Torvalds 	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
23761da177e4SLinus Torvalds 	msg.xonFlowControl = 0;
23771da177e4SLinus Torvalds 	msg.setFlowControl = 0xff;
23781da177e4SLinus Torvalds 
23791da177e4SLinus Torvalds 	msg.forwardingLength = 16;
23801da177e4SLinus Torvalds 	msg.xonChar = 17;
23811da177e4SLinus Torvalds 	msg.xoffChar = 19;
23821da177e4SLinus Torvalds 
23831da177e4SLinus Torvalds 	/* Opening port */
23841da177e4SLinus Torvalds 	if (reset_port == 1) {
23851da177e4SLinus Torvalds 		msg._txOn = 1;
23861da177e4SLinus Torvalds 		msg._txOff = 0;
23871da177e4SLinus Torvalds 		msg.txFlush = 0;
23881da177e4SLinus Torvalds 		msg.txBreak = 0;
23891da177e4SLinus Torvalds 		msg.rxOn = 1;
23901da177e4SLinus Torvalds 		msg.rxOff = 0;
23911da177e4SLinus Torvalds 		msg.rxFlush = 1;
23921da177e4SLinus Torvalds 		msg.rxForward = 0;
23931da177e4SLinus Torvalds 		msg.returnStatus = 0;
23941da177e4SLinus Torvalds 		msg.resetDataToggle = 0xff;
23951da177e4SLinus Torvalds 		msg.enablePort = 1;
23961da177e4SLinus Torvalds 		msg.disablePort = 0;
23971da177e4SLinus Torvalds 	}
23981da177e4SLinus Torvalds 	/* Closing port */
23991da177e4SLinus Torvalds 	else if (reset_port == 2) {
24001da177e4SLinus Torvalds 		msg._txOn = 0;
24011da177e4SLinus Torvalds 		msg._txOff = 1;
24021da177e4SLinus Torvalds 		msg.txFlush = 0;
24031da177e4SLinus Torvalds 		msg.txBreak = 0;
24041da177e4SLinus Torvalds 		msg.rxOn = 0;
24051da177e4SLinus Torvalds 		msg.rxOff = 1;
24061da177e4SLinus Torvalds 		msg.rxFlush = 1;
24071da177e4SLinus Torvalds 		msg.rxForward = 0;
24081da177e4SLinus Torvalds 		msg.returnStatus = 0;
24091da177e4SLinus Torvalds 		msg.resetDataToggle = 0;
24101da177e4SLinus Torvalds 		msg.enablePort = 0;
24111da177e4SLinus Torvalds 		msg.disablePort = 1;
24121da177e4SLinus Torvalds 	}
24131da177e4SLinus Torvalds 	/* Sending intermediate configs */
24141da177e4SLinus Torvalds 	else {
24151da177e4SLinus Torvalds 		msg._txOn = (!p_priv->break_on);
24161da177e4SLinus Torvalds 		msg._txOff = 0;
24171da177e4SLinus Torvalds 		msg.txFlush = 0;
24181da177e4SLinus Torvalds 		msg.txBreak = (p_priv->break_on);
24191da177e4SLinus Torvalds 		msg.rxOn = 0;
24201da177e4SLinus Torvalds 		msg.rxOff = 0;
24211da177e4SLinus Torvalds 		msg.rxFlush = 0;
24221da177e4SLinus Torvalds 		msg.rxForward = 0;
24231da177e4SLinus Torvalds 		msg.returnStatus = 0;
24241da177e4SLinus Torvalds 		msg.resetDataToggle = 0x0;
24251da177e4SLinus Torvalds 		msg.enablePort = 0;
24261da177e4SLinus Torvalds 		msg.disablePort = 0;
24271da177e4SLinus Torvalds 	}
24281da177e4SLinus Torvalds 
24291da177e4SLinus Torvalds 	/* Do handshaking outputs */
24301da177e4SLinus Torvalds 	msg.setRts = 0xff;
24311da177e4SLinus Torvalds 	msg.rts = p_priv->rts_state;
24321da177e4SLinus Torvalds 
24331da177e4SLinus Torvalds 	msg.setDtr = 0xff;
24341da177e4SLinus Torvalds 	msg.dtr = p_priv->dtr_state;
24351da177e4SLinus Torvalds 
24361da177e4SLinus Torvalds 	p_priv->resend_cont = 0;
24370ca1268eSLucy McCoy 
2438deb91685SAlan Cox 	/* if the device is a 49wg, we send control message on usb
2439deb91685SAlan Cox 	   control EP 0 */
24400ca1268eSLucy McCoy 
24410ca1268eSLucy McCoy 	if (d_details->product_id == keyspan_usa49wg_product_id) {
24420ca1268eSLucy McCoy 		dr = (void *)(s_priv->ctrl_buf);
24430ca1268eSLucy McCoy 		dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
24446424839cSMathieu OTHACEHE 		dr->bRequest = 0xB0;	/* 49wg control message */
24450ca1268eSLucy McCoy 		dr->wValue = 0;
24460ca1268eSLucy McCoy 		dr->wIndex = 0;
24470ca1268eSLucy McCoy 		dr->wLength = cpu_to_le16(sizeof(msg));
24480ca1268eSLucy McCoy 
24490ca1268eSLucy McCoy 		memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
24500ca1268eSLucy McCoy 
2451deb91685SAlan Cox 		usb_fill_control_urb(this_urb, serial->dev,
2452deb91685SAlan Cox 				usb_sndctrlpipe(serial->dev, 0),
2453deb91685SAlan Cox 				(unsigned char *)dr, s_priv->glocont_buf,
2454deb91685SAlan Cox 				sizeof(msg), usa49_glocont_callback, serial);
24550ca1268eSLucy McCoy 
24560ca1268eSLucy McCoy 	} else {
24571da177e4SLinus Torvalds 		memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
24581da177e4SLinus Torvalds 
24591da177e4SLinus Torvalds 		/* send the data out the device on control endpoint */
24601da177e4SLinus Torvalds 		this_urb->transfer_buffer_length = sizeof(msg);
24610ca1268eSLucy McCoy 	}
2462deb91685SAlan Cox 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
2463deb91685SAlan Cox 	if (err != 0)
2464049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
24651da177e4SLinus Torvalds 
2466a5b6f60cSAlan Cox 	return 0;
24671da177e4SLinus Torvalds }
24681da177e4SLinus Torvalds 
24691da177e4SLinus Torvalds static int keyspan_usa90_send_setup(struct usb_serial *serial,
24701da177e4SLinus Torvalds 				    struct usb_serial_port *port,
24711da177e4SLinus Torvalds 				    int reset_port)
24721da177e4SLinus Torvalds {
24731da177e4SLinus Torvalds 	struct keyspan_usa90_portControlMessage	msg;
24741da177e4SLinus Torvalds 	struct keyspan_serial_private 		*s_priv;
24751da177e4SLinus Torvalds 	struct keyspan_port_private 		*p_priv;
24761da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
24771da177e4SLinus Torvalds 	struct urb				*this_urb;
24781da177e4SLinus Torvalds 	int 					err;
24791da177e4SLinus Torvalds 	u8						prescaler;
24801da177e4SLinus Torvalds 
24811da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
24821da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
24831da177e4SLinus Torvalds 	d_details = s_priv->device_details;
24841da177e4SLinus Torvalds 
24851da177e4SLinus Torvalds 	/* only do something if we have a bulk out endpoint */
2486deb91685SAlan Cox 	this_urb = p_priv->outcont_urb;
2487deb91685SAlan Cox 	if (this_urb == NULL) {
2488049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
24891da177e4SLinus Torvalds 		return -1;
24901da177e4SLinus Torvalds 	}
24911da177e4SLinus Torvalds 
24921da177e4SLinus Torvalds 	/* Save reset port val for resend.
24931da177e4SLinus Torvalds 	   Don't overwrite resend for open/close condition. */
24941da177e4SLinus Torvalds 	if ((reset_port + 1) > p_priv->resend_cont)
24951da177e4SLinus Torvalds 		p_priv->resend_cont = reset_port + 1;
24961da177e4SLinus Torvalds 	if (this_urb->status == -EINPROGRESS) {
2497049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s already writing\n", __func__);
24981da177e4SLinus Torvalds 		mdelay(5);
2499deb91685SAlan Cox 		return -1;
25001da177e4SLinus Torvalds 	}
25011da177e4SLinus Torvalds 
25021da177e4SLinus Torvalds 	memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
25031da177e4SLinus Torvalds 
25041da177e4SLinus Torvalds 	/* Only set baud rate if it's changed */
25051da177e4SLinus Torvalds 	if (p_priv->old_baud != p_priv->baud) {
25061da177e4SLinus Torvalds 		p_priv->old_baud = p_priv->baud;
25071da177e4SLinus Torvalds 		msg.setClocking = 0x01;
2508049c6b4eSGreg Kroah-Hartman 		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2509049c6b4eSGreg Kroah-Hartman 						   &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2510049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2511deb91685SAlan Cox 				__func__, p_priv->baud);
25121da177e4SLinus Torvalds 			p_priv->baud = 9600;
2513049c6b4eSGreg Kroah-Hartman 			d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
25141da177e4SLinus Torvalds 				&msg.baudHi, &msg.baudLo, &prescaler, 0);
25151da177e4SLinus Torvalds 		}
25161da177e4SLinus Torvalds 		msg.setRxMode = 1;
25171da177e4SLinus Torvalds 		msg.setTxMode = 1;
25181da177e4SLinus Torvalds 	}
25191da177e4SLinus Torvalds 
25201da177e4SLinus Torvalds 	/* modes must always be correctly specified */
2521deb91685SAlan Cox 	if (p_priv->baud > 57600) {
25221da177e4SLinus Torvalds 		msg.rxMode = RXMODE_DMA;
25231da177e4SLinus Torvalds 		msg.txMode = TXMODE_DMA;
2524deb91685SAlan Cox 	} else {
25251da177e4SLinus Torvalds 		msg.rxMode = RXMODE_BYHAND;
25261da177e4SLinus Torvalds 		msg.txMode = TXMODE_BYHAND;
25271da177e4SLinus Torvalds 	}
25281da177e4SLinus Torvalds 
25291da177e4SLinus Torvalds 	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
25301da177e4SLinus Torvalds 	switch (p_priv->cflag & CSIZE) {
25311da177e4SLinus Torvalds 	case CS5:
25321da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_5;
25331da177e4SLinus Torvalds 		break;
25341da177e4SLinus Torvalds 	case CS6:
25351da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_6;
25361da177e4SLinus Torvalds 		break;
25371da177e4SLinus Torvalds 	case CS7:
25381da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_7;
25391da177e4SLinus Torvalds 		break;
25401da177e4SLinus Torvalds 	case CS8:
25411da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_8;
25421da177e4SLinus Torvalds 		break;
25431da177e4SLinus Torvalds 	}
25441da177e4SLinus Torvalds 	if (p_priv->cflag & PARENB) {
25451da177e4SLinus Torvalds 		/* note USA_PARITY_NONE == 0 */
25461da177e4SLinus Torvalds 		msg.lcr |= (p_priv->cflag & PARODD) ?
25471da177e4SLinus Torvalds 			USA_PARITY_ODD : USA_PARITY_EVEN;
25481da177e4SLinus Torvalds 	}
25491da177e4SLinus Torvalds 	if (p_priv->old_cflag != p_priv->cflag) {
25501da177e4SLinus Torvalds 		p_priv->old_cflag = p_priv->cflag;
25511da177e4SLinus Torvalds 		msg.setLcr = 0x01;
25521da177e4SLinus Torvalds 	}
25531da177e4SLinus Torvalds 
25541da177e4SLinus Torvalds 	if (p_priv->flow_control == flow_cts)
25551da177e4SLinus Torvalds 		msg.txFlowControl = TXFLOW_CTS;
25561da177e4SLinus Torvalds 	msg.setTxFlowControl = 0x01;
25571da177e4SLinus Torvalds 	msg.setRxFlowControl = 0x01;
25581da177e4SLinus Torvalds 
25591da177e4SLinus Torvalds 	msg.rxForwardingLength = 16;
25601da177e4SLinus Torvalds 	msg.rxForwardingTimeout = 16;
25611da177e4SLinus Torvalds 	msg.txAckSetting = 0;
25621da177e4SLinus Torvalds 	msg.xonChar = 17;
25631da177e4SLinus Torvalds 	msg.xoffChar = 19;
25641da177e4SLinus Torvalds 
25651da177e4SLinus Torvalds 	/* Opening port */
25661da177e4SLinus Torvalds 	if (reset_port == 1) {
25671da177e4SLinus Torvalds 		msg.portEnabled = 1;
25681da177e4SLinus Torvalds 		msg.rxFlush = 1;
25691da177e4SLinus Torvalds 		msg.txBreak = (p_priv->break_on);
25701da177e4SLinus Torvalds 	}
25711da177e4SLinus Torvalds 	/* Closing port */
2572deb91685SAlan Cox 	else if (reset_port == 2)
25731da177e4SLinus Torvalds 		msg.portEnabled = 0;
25741da177e4SLinus Torvalds 	/* Sending intermediate configs */
25751da177e4SLinus Torvalds 	else {
25761da177e4SLinus Torvalds 		msg.portEnabled = 1;
25771da177e4SLinus Torvalds 		msg.txBreak = (p_priv->break_on);
25781da177e4SLinus Torvalds 	}
25791da177e4SLinus Torvalds 
25801da177e4SLinus Torvalds 	/* Do handshaking outputs */
25811da177e4SLinus Torvalds 	msg.setRts = 0x01;
25821da177e4SLinus Torvalds 	msg.rts = p_priv->rts_state;
25831da177e4SLinus Torvalds 
25841da177e4SLinus Torvalds 	msg.setDtr = 0x01;
25851da177e4SLinus Torvalds 	msg.dtr = p_priv->dtr_state;
25861da177e4SLinus Torvalds 
25871da177e4SLinus Torvalds 	p_priv->resend_cont = 0;
25881da177e4SLinus Torvalds 	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
25891da177e4SLinus Torvalds 
25901da177e4SLinus Torvalds 	/* send the data out the device on control endpoint */
25911da177e4SLinus Torvalds 	this_urb->transfer_buffer_length = sizeof(msg);
25921da177e4SLinus Torvalds 
2593deb91685SAlan Cox 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
2594deb91685SAlan Cox 	if (err != 0)
2595049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
2596a5b6f60cSAlan Cox 	return 0;
25971da177e4SLinus Torvalds }
25981da177e4SLinus Torvalds 
25990ca1268eSLucy McCoy static int keyspan_usa67_send_setup(struct usb_serial *serial,
26000ca1268eSLucy McCoy 				    struct usb_serial_port *port,
26010ca1268eSLucy McCoy 				    int reset_port)
26020ca1268eSLucy McCoy {
26030ca1268eSLucy McCoy 	struct keyspan_usa67_portControlMessage	msg;
26040ca1268eSLucy McCoy 	struct keyspan_serial_private 		*s_priv;
26050ca1268eSLucy McCoy 	struct keyspan_port_private 		*p_priv;
26060ca1268eSLucy McCoy 	const struct keyspan_device_details	*d_details;
26070ca1268eSLucy McCoy 	struct urb				*this_urb;
26080ca1268eSLucy McCoy 	int 					err, device_port;
26090ca1268eSLucy McCoy 
26100ca1268eSLucy McCoy 	s_priv = usb_get_serial_data(serial);
26110ca1268eSLucy McCoy 	p_priv = usb_get_serial_port_data(port);
26120ca1268eSLucy McCoy 	d_details = s_priv->device_details;
26130ca1268eSLucy McCoy 
26140ca1268eSLucy McCoy 	this_urb = s_priv->glocont_urb;
26150ca1268eSLucy McCoy 
26160ca1268eSLucy McCoy 	/* Work out which port within the device is being setup */
26171143832eSGreg Kroah-Hartman 	device_port = port->port_number;
26180ca1268eSLucy McCoy 
26190ca1268eSLucy McCoy 	/* Make sure we have an urb then send the message */
26200ca1268eSLucy McCoy 	if (this_urb == NULL) {
26211143832eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
26220ca1268eSLucy McCoy 		return -1;
26230ca1268eSLucy McCoy 	}
26240ca1268eSLucy McCoy 
26250ca1268eSLucy McCoy 	/* Save reset port val for resend.
26260ca1268eSLucy McCoy 	   Don't overwrite resend for open/close condition. */
26270ca1268eSLucy McCoy 	if ((reset_port + 1) > p_priv->resend_cont)
26280ca1268eSLucy McCoy 		p_priv->resend_cont = reset_port + 1;
26290ca1268eSLucy McCoy 	if (this_urb->status == -EINPROGRESS) {
2630049c6b4eSGreg Kroah-Hartman 		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
26310ca1268eSLucy McCoy 		mdelay(5);
2632deb91685SAlan Cox 		return -1;
26330ca1268eSLucy McCoy 	}
26340ca1268eSLucy McCoy 
26350ca1268eSLucy McCoy 	memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
26360ca1268eSLucy McCoy 
26370ca1268eSLucy McCoy 	msg.port = device_port;
26380ca1268eSLucy McCoy 
26390ca1268eSLucy McCoy 	/* Only set baud rate if it's changed */
26400ca1268eSLucy McCoy 	if (p_priv->old_baud != p_priv->baud) {
26410ca1268eSLucy McCoy 		p_priv->old_baud = p_priv->baud;
26420ca1268eSLucy McCoy 		msg.setClocking = 0xff;
2643049c6b4eSGreg Kroah-Hartman 		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2644049c6b4eSGreg Kroah-Hartman 						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
2645049c6b4eSGreg Kroah-Hartman 						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2646049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2647deb91685SAlan Cox 				__func__, p_priv->baud);
26480ca1268eSLucy McCoy 			msg.baudLo = 0;
26490ca1268eSLucy McCoy 			msg.baudHi = 125;	/* Values for 9600 baud */
26500ca1268eSLucy McCoy 			msg.prescaler = 10;
26510ca1268eSLucy McCoy 		}
26520ca1268eSLucy McCoy 		msg.setPrescaler = 0xff;
26530ca1268eSLucy McCoy 	}
26540ca1268eSLucy McCoy 
26550ca1268eSLucy McCoy 	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
26560ca1268eSLucy McCoy 	switch (p_priv->cflag & CSIZE) {
26570ca1268eSLucy McCoy 	case CS5:
26580ca1268eSLucy McCoy 		msg.lcr |= USA_DATABITS_5;
26590ca1268eSLucy McCoy 		break;
26600ca1268eSLucy McCoy 	case CS6:
26610ca1268eSLucy McCoy 		msg.lcr |= USA_DATABITS_6;
26620ca1268eSLucy McCoy 		break;
26630ca1268eSLucy McCoy 	case CS7:
26640ca1268eSLucy McCoy 		msg.lcr |= USA_DATABITS_7;
26650ca1268eSLucy McCoy 		break;
26660ca1268eSLucy McCoy 	case CS8:
26670ca1268eSLucy McCoy 		msg.lcr |= USA_DATABITS_8;
26680ca1268eSLucy McCoy 		break;
26690ca1268eSLucy McCoy 	}
26700ca1268eSLucy McCoy 	if (p_priv->cflag & PARENB) {
26710ca1268eSLucy McCoy 		/* note USA_PARITY_NONE == 0 */
26720ca1268eSLucy McCoy 		msg.lcr |= (p_priv->cflag & PARODD) ?
26730ca1268eSLucy McCoy 					USA_PARITY_ODD : USA_PARITY_EVEN;
26740ca1268eSLucy McCoy 	}
26750ca1268eSLucy McCoy 	msg.setLcr = 0xff;
26760ca1268eSLucy McCoy 
26770ca1268eSLucy McCoy 	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
26780ca1268eSLucy McCoy 	msg.xonFlowControl = 0;
26790ca1268eSLucy McCoy 	msg.setFlowControl = 0xff;
26800ca1268eSLucy McCoy 	msg.forwardingLength = 16;
26810ca1268eSLucy McCoy 	msg.xonChar = 17;
26820ca1268eSLucy McCoy 	msg.xoffChar = 19;
26830ca1268eSLucy McCoy 
26840ca1268eSLucy McCoy 	if (reset_port == 1) {
26850ca1268eSLucy McCoy 		/* Opening port */
26860ca1268eSLucy McCoy 		msg._txOn = 1;
26870ca1268eSLucy McCoy 		msg._txOff = 0;
26880ca1268eSLucy McCoy 		msg.txFlush = 0;
26890ca1268eSLucy McCoy 		msg.txBreak = 0;
26900ca1268eSLucy McCoy 		msg.rxOn = 1;
26910ca1268eSLucy McCoy 		msg.rxOff = 0;
26920ca1268eSLucy McCoy 		msg.rxFlush = 1;
26930ca1268eSLucy McCoy 		msg.rxForward = 0;
26940ca1268eSLucy McCoy 		msg.returnStatus = 0;
26950ca1268eSLucy McCoy 		msg.resetDataToggle = 0xff;
26960ca1268eSLucy McCoy 	} else if (reset_port == 2) {
26970ca1268eSLucy McCoy 		/* Closing port */
26980ca1268eSLucy McCoy 		msg._txOn = 0;
26990ca1268eSLucy McCoy 		msg._txOff = 1;
27000ca1268eSLucy McCoy 		msg.txFlush = 0;
27010ca1268eSLucy McCoy 		msg.txBreak = 0;
27020ca1268eSLucy McCoy 		msg.rxOn = 0;
27030ca1268eSLucy McCoy 		msg.rxOff = 1;
27040ca1268eSLucy McCoy 		msg.rxFlush = 1;
27050ca1268eSLucy McCoy 		msg.rxForward = 0;
27060ca1268eSLucy McCoy 		msg.returnStatus = 0;
27070ca1268eSLucy McCoy 		msg.resetDataToggle = 0;
27080ca1268eSLucy McCoy 	} else {
27090ca1268eSLucy McCoy 		/* Sending intermediate configs */
27100ca1268eSLucy McCoy 		msg._txOn = (!p_priv->break_on);
27110ca1268eSLucy McCoy 		msg._txOff = 0;
27120ca1268eSLucy McCoy 		msg.txFlush = 0;
27130ca1268eSLucy McCoy 		msg.txBreak = (p_priv->break_on);
27140ca1268eSLucy McCoy 		msg.rxOn = 0;
27150ca1268eSLucy McCoy 		msg.rxOff = 0;
27160ca1268eSLucy McCoy 		msg.rxFlush = 0;
27170ca1268eSLucy McCoy 		msg.rxForward = 0;
27180ca1268eSLucy McCoy 		msg.returnStatus = 0;
27190ca1268eSLucy McCoy 		msg.resetDataToggle = 0x0;
27200ca1268eSLucy McCoy 	}
27210ca1268eSLucy McCoy 
27220ca1268eSLucy McCoy 	/* Do handshaking outputs */
27230ca1268eSLucy McCoy 	msg.setTxTriState_setRts = 0xff;
27240ca1268eSLucy McCoy 	msg.txTriState_rts = p_priv->rts_state;
27250ca1268eSLucy McCoy 
27260ca1268eSLucy McCoy 	msg.setHskoa_setDtr = 0xff;
27270ca1268eSLucy McCoy 	msg.hskoa_dtr = p_priv->dtr_state;
27280ca1268eSLucy McCoy 
27290ca1268eSLucy McCoy 	p_priv->resend_cont = 0;
27300ca1268eSLucy McCoy 
27310ca1268eSLucy McCoy 	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
27320ca1268eSLucy McCoy 
27330ca1268eSLucy McCoy 	/* send the data out the device on control endpoint */
27340ca1268eSLucy McCoy 	this_urb->transfer_buffer_length = sizeof(msg);
27350ca1268eSLucy McCoy 
27360ca1268eSLucy McCoy 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
27370ca1268eSLucy McCoy 	if (err != 0)
2738049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
2739a5b6f60cSAlan Cox 	return 0;
27400ca1268eSLucy McCoy }
27410ca1268eSLucy McCoy 
27421da177e4SLinus Torvalds static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
27431da177e4SLinus Torvalds {
27441da177e4SLinus Torvalds 	struct usb_serial *serial = port->serial;
27451da177e4SLinus Torvalds 	struct keyspan_serial_private *s_priv;
27461da177e4SLinus Torvalds 	const struct keyspan_device_details *d_details;
27471da177e4SLinus Torvalds 
27481da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
27491da177e4SLinus Torvalds 	d_details = s_priv->device_details;
27501da177e4SLinus Torvalds 
27511da177e4SLinus Torvalds 	switch (d_details->msg_format) {
27521da177e4SLinus Torvalds 	case msg_usa26:
27531da177e4SLinus Torvalds 		keyspan_usa26_send_setup(serial, port, reset_port);
27541da177e4SLinus Torvalds 		break;
27551da177e4SLinus Torvalds 	case msg_usa28:
27561da177e4SLinus Torvalds 		keyspan_usa28_send_setup(serial, port, reset_port);
27571da177e4SLinus Torvalds 		break;
27581da177e4SLinus Torvalds 	case msg_usa49:
27591da177e4SLinus Torvalds 		keyspan_usa49_send_setup(serial, port, reset_port);
27601da177e4SLinus Torvalds 		break;
27611da177e4SLinus Torvalds 	case msg_usa90:
27621da177e4SLinus Torvalds 		keyspan_usa90_send_setup(serial, port, reset_port);
27631da177e4SLinus Torvalds 		break;
27640ca1268eSLucy McCoy 	case msg_usa67:
27650ca1268eSLucy McCoy 		keyspan_usa67_send_setup(serial, port, reset_port);
27660ca1268eSLucy McCoy 		break;
27671da177e4SLinus Torvalds 	}
27681da177e4SLinus Torvalds }
27691da177e4SLinus Torvalds 
27701da177e4SLinus Torvalds 
27711da177e4SLinus Torvalds /* Gets called by the "real" driver (ie once firmware is loaded
27721da177e4SLinus Torvalds    and renumeration has taken place. */
27731da177e4SLinus Torvalds static int keyspan_startup(struct usb_serial *serial)
27741da177e4SLinus Torvalds {
27751da177e4SLinus Torvalds 	int				i, err;
27761da177e4SLinus Torvalds 	struct keyspan_serial_private 	*s_priv;
27771da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
27781da177e4SLinus Torvalds 
27791da177e4SLinus Torvalds 	for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
2780deb91685SAlan Cox 		if (d_details->product_id ==
2781deb91685SAlan Cox 				le16_to_cpu(serial->dev->descriptor.idProduct))
27821da177e4SLinus Torvalds 			break;
27831da177e4SLinus Torvalds 	if (d_details == NULL) {
2784deb91685SAlan Cox 		dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2785deb91685SAlan Cox 		    __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
2786ff8a43c1SJohan Hovold 		return -ENODEV;
27871da177e4SLinus Torvalds 	}
27881da177e4SLinus Torvalds 
27891da177e4SLinus Torvalds 	/* Setup private data for serial driver */
279080b6ca48SEric Sesterhenn 	s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
279110c642d0SJohan Hovold 	if (!s_priv)
27921da177e4SLinus Torvalds 		return -ENOMEM;
27931da177e4SLinus Torvalds 
27942fcd1c9bSJohan Hovold 	s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);
27952fcd1c9bSJohan Hovold 	if (!s_priv->instat_buf)
27962fcd1c9bSJohan Hovold 		goto err_instat_buf;
27972fcd1c9bSJohan Hovold 
27982fcd1c9bSJohan Hovold 	s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL);
27992fcd1c9bSJohan Hovold 	if (!s_priv->indat_buf)
28002fcd1c9bSJohan Hovold 		goto err_indat_buf;
28012fcd1c9bSJohan Hovold 
28022fcd1c9bSJohan Hovold 	s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL);
28032fcd1c9bSJohan Hovold 	if (!s_priv->glocont_buf)
28042fcd1c9bSJohan Hovold 		goto err_glocont_buf;
28052fcd1c9bSJohan Hovold 
28062fcd1c9bSJohan Hovold 	s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
28072fcd1c9bSJohan Hovold 	if (!s_priv->ctrl_buf)
28082fcd1c9bSJohan Hovold 		goto err_ctrl_buf;
28092fcd1c9bSJohan Hovold 
28101da177e4SLinus Torvalds 	s_priv->device_details = d_details;
28111da177e4SLinus Torvalds 	usb_set_serial_data(serial, s_priv);
28121da177e4SLinus Torvalds 
28131da177e4SLinus Torvalds 	keyspan_setup_urbs(serial);
28141da177e4SLinus Torvalds 
28150ca1268eSLucy McCoy 	if (s_priv->instat_urb != NULL) {
28160ca1268eSLucy McCoy 		err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
28170ca1268eSLucy McCoy 		if (err != 0)
28187ebcb334SGreg Kroah-Hartman 			dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
28190ca1268eSLucy McCoy 	}
28200ca1268eSLucy McCoy 	if (s_priv->indat_urb != NULL) {
28210ca1268eSLucy McCoy 		err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
28220ca1268eSLucy McCoy 		if (err != 0)
28237ebcb334SGreg Kroah-Hartman 			dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
28241da177e4SLinus Torvalds 	}
28251da177e4SLinus Torvalds 
2826a5b6f60cSAlan Cox 	return 0;
28272fcd1c9bSJohan Hovold 
28282fcd1c9bSJohan Hovold err_ctrl_buf:
28292fcd1c9bSJohan Hovold 	kfree(s_priv->glocont_buf);
28302fcd1c9bSJohan Hovold err_glocont_buf:
28312fcd1c9bSJohan Hovold 	kfree(s_priv->indat_buf);
28322fcd1c9bSJohan Hovold err_indat_buf:
28332fcd1c9bSJohan Hovold 	kfree(s_priv->instat_buf);
28342fcd1c9bSJohan Hovold err_instat_buf:
28352fcd1c9bSJohan Hovold 	kfree(s_priv);
28362fcd1c9bSJohan Hovold 
28372fcd1c9bSJohan Hovold 	return -ENOMEM;
28381da177e4SLinus Torvalds }
28391da177e4SLinus Torvalds 
2840f9c99bb8SAlan Stern static void keyspan_disconnect(struct usb_serial *serial)
28411da177e4SLinus Torvalds {
28421da177e4SLinus Torvalds 	struct keyspan_serial_private *s_priv;
28431da177e4SLinus Torvalds 
28441da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
28451da177e4SLinus Torvalds 
284661924505SJohan Hovold 	usb_kill_urb(s_priv->instat_urb);
284761924505SJohan Hovold 	usb_kill_urb(s_priv->glocont_urb);
284861924505SJohan Hovold 	usb_kill_urb(s_priv->indat_urb);
2849f9c99bb8SAlan Stern }
2850f9c99bb8SAlan Stern 
2851f9c99bb8SAlan Stern static void keyspan_release(struct usb_serial *serial)
2852f9c99bb8SAlan Stern {
2853f9c99bb8SAlan Stern 	struct keyspan_serial_private *s_priv;
2854f9c99bb8SAlan Stern 
2855f9c99bb8SAlan Stern 	s_priv = usb_get_serial_data(serial);
28561da177e4SLinus Torvalds 
285735be1a71SJohan Hovold 	/* Make sure to unlink the URBs submitted in attach. */
285835be1a71SJohan Hovold 	usb_kill_urb(s_priv->instat_urb);
285935be1a71SJohan Hovold 	usb_kill_urb(s_priv->indat_urb);
286035be1a71SJohan Hovold 
2861f79b2d0fSJohan Hovold 	usb_free_urb(s_priv->instat_urb);
2862f79b2d0fSJohan Hovold 	usb_free_urb(s_priv->indat_urb);
2863f79b2d0fSJohan Hovold 	usb_free_urb(s_priv->glocont_urb);
28641da177e4SLinus Torvalds 
28652fcd1c9bSJohan Hovold 	kfree(s_priv->ctrl_buf);
28662fcd1c9bSJohan Hovold 	kfree(s_priv->glocont_buf);
28672fcd1c9bSJohan Hovold 	kfree(s_priv->indat_buf);
28682fcd1c9bSJohan Hovold 	kfree(s_priv->instat_buf);
28692fcd1c9bSJohan Hovold 
2870f79b2d0fSJohan Hovold 	kfree(s_priv);
28711da177e4SLinus Torvalds }
2872f79b2d0fSJohan Hovold 
2873f79b2d0fSJohan Hovold static int keyspan_port_probe(struct usb_serial_port *port)
2874f79b2d0fSJohan Hovold {
2875f79b2d0fSJohan Hovold 	struct usb_serial *serial = port->serial;
2876f0e3e35cSBjørn Mork 	struct keyspan_serial_private *s_priv;
2877f79b2d0fSJohan Hovold 	struct keyspan_port_private *p_priv;
2878f79b2d0fSJohan Hovold 	const struct keyspan_device_details *d_details;
2879f79b2d0fSJohan Hovold 	struct callbacks *cback;
2880f79b2d0fSJohan Hovold 	int endp;
2881f79b2d0fSJohan Hovold 	int port_num;
2882f79b2d0fSJohan Hovold 	int i;
2883f79b2d0fSJohan Hovold 
2884f79b2d0fSJohan Hovold 	s_priv = usb_get_serial_data(serial);
2885f79b2d0fSJohan Hovold 	d_details = s_priv->device_details;
2886f79b2d0fSJohan Hovold 
2887f79b2d0fSJohan Hovold 	p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL);
2888f79b2d0fSJohan Hovold 	if (!p_priv)
2889f79b2d0fSJohan Hovold 		return -ENOMEM;
2890f79b2d0fSJohan Hovold 
2891bad41a5bSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
2892bad41a5bSJohan Hovold 		p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
2893bad41a5bSJohan Hovold 		if (!p_priv->in_buffer[i])
2894910c9963SWang Hai 			goto err_free_in_buffer;
2895bad41a5bSJohan Hovold 	}
2896bad41a5bSJohan Hovold 
2897bad41a5bSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
2898bad41a5bSJohan Hovold 		p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
2899bad41a5bSJohan Hovold 		if (!p_priv->out_buffer[i])
2900910c9963SWang Hai 			goto err_free_out_buffer;
2901bad41a5bSJohan Hovold 	}
2902bad41a5bSJohan Hovold 
2903bad41a5bSJohan Hovold 	p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
2904bad41a5bSJohan Hovold 	if (!p_priv->inack_buffer)
2905910c9963SWang Hai 		goto err_free_out_buffer;
2906bad41a5bSJohan Hovold 
2907bad41a5bSJohan Hovold 	p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
2908bad41a5bSJohan Hovold 	if (!p_priv->outcont_buffer)
2909910c9963SWang Hai 		goto err_free_inack_buffer;
2910bad41a5bSJohan Hovold 
2911f79b2d0fSJohan Hovold 	p_priv->device_details = d_details;
2912f79b2d0fSJohan Hovold 
2913f79b2d0fSJohan Hovold 	/* Setup values for the various callback routines */
2914f79b2d0fSJohan Hovold 	cback = &keyspan_callbacks[d_details->msg_format];
2915f79b2d0fSJohan Hovold 
29161143832eSGreg Kroah-Hartman 	port_num = port->port_number;
2917f79b2d0fSJohan Hovold 
2918f79b2d0fSJohan Hovold 	/* Do indat endpoints first, once for each flip */
2919f79b2d0fSJohan Hovold 	endp = d_details->indat_endpoints[port_num];
2920f79b2d0fSJohan Hovold 	for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
2921f79b2d0fSJohan Hovold 		p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
2922f79b2d0fSJohan Hovold 						USB_DIR_IN, port,
2923bad41a5bSJohan Hovold 						p_priv->in_buffer[i],
2924bad41a5bSJohan Hovold 						IN_BUFLEN,
2925f79b2d0fSJohan Hovold 						cback->indat_callback);
2926f79b2d0fSJohan Hovold 	}
2927f79b2d0fSJohan Hovold 	/* outdat endpoints also have flip */
2928f79b2d0fSJohan Hovold 	endp = d_details->outdat_endpoints[port_num];
2929f79b2d0fSJohan Hovold 	for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
2930f79b2d0fSJohan Hovold 		p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
2931f79b2d0fSJohan Hovold 						USB_DIR_OUT, port,
2932bad41a5bSJohan Hovold 						p_priv->out_buffer[i],
2933bad41a5bSJohan Hovold 						OUT_BUFLEN,
2934f79b2d0fSJohan Hovold 						cback->outdat_callback);
2935f79b2d0fSJohan Hovold 	}
2936f79b2d0fSJohan Hovold 	/* inack endpoint */
2937f79b2d0fSJohan Hovold 	p_priv->inack_urb = keyspan_setup_urb(serial,
2938f79b2d0fSJohan Hovold 					d_details->inack_endpoints[port_num],
2939f79b2d0fSJohan Hovold 					USB_DIR_IN, port,
2940bad41a5bSJohan Hovold 					p_priv->inack_buffer,
2941bad41a5bSJohan Hovold 					INACK_BUFLEN,
2942f79b2d0fSJohan Hovold 					cback->inack_callback);
2943f79b2d0fSJohan Hovold 	/* outcont endpoint */
2944f79b2d0fSJohan Hovold 	p_priv->outcont_urb = keyspan_setup_urb(serial,
2945f79b2d0fSJohan Hovold 					d_details->outcont_endpoints[port_num],
2946f79b2d0fSJohan Hovold 					USB_DIR_OUT, port,
2947bad41a5bSJohan Hovold 					p_priv->outcont_buffer,
2948bad41a5bSJohan Hovold 					OUTCONT_BUFLEN,
2949f79b2d0fSJohan Hovold 					 cback->outcont_callback);
2950f79b2d0fSJohan Hovold 
2951f79b2d0fSJohan Hovold 	usb_set_serial_port_data(port, p_priv);
2952f79b2d0fSJohan Hovold 
2953f79b2d0fSJohan Hovold 	return 0;
2954bad41a5bSJohan Hovold 
2955910c9963SWang Hai err_free_inack_buffer:
2956bad41a5bSJohan Hovold 	kfree(p_priv->inack_buffer);
2957910c9963SWang Hai err_free_out_buffer:
2958bad41a5bSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
2959bad41a5bSJohan Hovold 		kfree(p_priv->out_buffer[i]);
2960910c9963SWang Hai err_free_in_buffer:
2961bad41a5bSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
2962bad41a5bSJohan Hovold 		kfree(p_priv->in_buffer[i]);
2963bad41a5bSJohan Hovold 	kfree(p_priv);
2964bad41a5bSJohan Hovold 
2965bad41a5bSJohan Hovold 	return -ENOMEM;
2966f79b2d0fSJohan Hovold }
2967f79b2d0fSJohan Hovold 
2968c5d1448fSUwe Kleine-König static void keyspan_port_remove(struct usb_serial_port *port)
2969f79b2d0fSJohan Hovold {
2970f79b2d0fSJohan Hovold 	struct keyspan_port_private *p_priv;
2971f79b2d0fSJohan Hovold 	int i;
2972f79b2d0fSJohan Hovold 
2973f79b2d0fSJohan Hovold 	p_priv = usb_get_serial_port_data(port);
2974f79b2d0fSJohan Hovold 
297561924505SJohan Hovold 	usb_kill_urb(p_priv->inack_urb);
297661924505SJohan Hovold 	usb_kill_urb(p_priv->outcont_urb);
2977f79b2d0fSJohan Hovold 	for (i = 0; i < 2; i++) {
297861924505SJohan Hovold 		usb_kill_urb(p_priv->in_urbs[i]);
297961924505SJohan Hovold 		usb_kill_urb(p_priv->out_urbs[i]);
2980f79b2d0fSJohan Hovold 	}
2981f79b2d0fSJohan Hovold 
2982f79b2d0fSJohan Hovold 	usb_free_urb(p_priv->inack_urb);
2983f79b2d0fSJohan Hovold 	usb_free_urb(p_priv->outcont_urb);
2984f79b2d0fSJohan Hovold 	for (i = 0; i < 2; i++) {
2985f79b2d0fSJohan Hovold 		usb_free_urb(p_priv->in_urbs[i]);
2986f79b2d0fSJohan Hovold 		usb_free_urb(p_priv->out_urbs[i]);
2987f79b2d0fSJohan Hovold 	}
2988f79b2d0fSJohan Hovold 
2989bad41a5bSJohan Hovold 	kfree(p_priv->outcont_buffer);
2990bad41a5bSJohan Hovold 	kfree(p_priv->inack_buffer);
2991bad41a5bSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
2992bad41a5bSJohan Hovold 		kfree(p_priv->out_buffer[i]);
2993bad41a5bSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
2994bad41a5bSJohan Hovold 		kfree(p_priv->in_buffer[i]);
2995bad41a5bSJohan Hovold 
2996f79b2d0fSJohan Hovold 	kfree(p_priv);
29971da177e4SLinus Torvalds }
29981da177e4SLinus Torvalds 
2999beabdc3cSJohan Hovold /* Structs for the devices, pre and post renumeration. */
3000beabdc3cSJohan Hovold static struct usb_serial_driver keyspan_pre_device = {
3001beabdc3cSJohan Hovold 	.driver = {
3002beabdc3cSJohan Hovold 		.owner		= THIS_MODULE,
3003beabdc3cSJohan Hovold 		.name		= "keyspan_no_firm",
3004beabdc3cSJohan Hovold 	},
3005beabdc3cSJohan Hovold 	.description		= "Keyspan - (without firmware)",
3006beabdc3cSJohan Hovold 	.id_table		= keyspan_pre_ids,
3007beabdc3cSJohan Hovold 	.num_ports		= 1,
3008beabdc3cSJohan Hovold 	.attach			= keyspan_fake_startup,
3009beabdc3cSJohan Hovold };
3010beabdc3cSJohan Hovold 
3011beabdc3cSJohan Hovold static struct usb_serial_driver keyspan_1port_device = {
3012beabdc3cSJohan Hovold 	.driver = {
3013beabdc3cSJohan Hovold 		.owner		= THIS_MODULE,
3014beabdc3cSJohan Hovold 		.name		= "keyspan_1",
3015beabdc3cSJohan Hovold 	},
3016beabdc3cSJohan Hovold 	.description		= "Keyspan 1 port adapter",
3017beabdc3cSJohan Hovold 	.id_table		= keyspan_1port_ids,
3018beabdc3cSJohan Hovold 	.num_ports		= 1,
3019beabdc3cSJohan Hovold 	.open			= keyspan_open,
3020beabdc3cSJohan Hovold 	.close			= keyspan_close,
3021beabdc3cSJohan Hovold 	.dtr_rts		= keyspan_dtr_rts,
3022beabdc3cSJohan Hovold 	.write			= keyspan_write,
3023beabdc3cSJohan Hovold 	.write_room		= keyspan_write_room,
3024beabdc3cSJohan Hovold 	.set_termios		= keyspan_set_termios,
3025beabdc3cSJohan Hovold 	.break_ctl		= keyspan_break_ctl,
3026beabdc3cSJohan Hovold 	.tiocmget		= keyspan_tiocmget,
3027beabdc3cSJohan Hovold 	.tiocmset		= keyspan_tiocmset,
3028beabdc3cSJohan Hovold 	.attach			= keyspan_startup,
3029beabdc3cSJohan Hovold 	.disconnect		= keyspan_disconnect,
3030beabdc3cSJohan Hovold 	.release		= keyspan_release,
3031beabdc3cSJohan Hovold 	.port_probe		= keyspan_port_probe,
3032beabdc3cSJohan Hovold 	.port_remove		= keyspan_port_remove,
3033beabdc3cSJohan Hovold };
3034beabdc3cSJohan Hovold 
3035beabdc3cSJohan Hovold static struct usb_serial_driver keyspan_2port_device = {
3036beabdc3cSJohan Hovold 	.driver = {
3037beabdc3cSJohan Hovold 		.owner		= THIS_MODULE,
3038beabdc3cSJohan Hovold 		.name		= "keyspan_2",
3039beabdc3cSJohan Hovold 	},
3040beabdc3cSJohan Hovold 	.description		= "Keyspan 2 port adapter",
3041beabdc3cSJohan Hovold 	.id_table		= keyspan_2port_ids,
3042beabdc3cSJohan Hovold 	.num_ports		= 2,
3043beabdc3cSJohan Hovold 	.open			= keyspan_open,
3044beabdc3cSJohan Hovold 	.close			= keyspan_close,
3045beabdc3cSJohan Hovold 	.dtr_rts		= keyspan_dtr_rts,
3046beabdc3cSJohan Hovold 	.write			= keyspan_write,
3047beabdc3cSJohan Hovold 	.write_room		= keyspan_write_room,
3048beabdc3cSJohan Hovold 	.set_termios		= keyspan_set_termios,
3049beabdc3cSJohan Hovold 	.break_ctl		= keyspan_break_ctl,
3050beabdc3cSJohan Hovold 	.tiocmget		= keyspan_tiocmget,
3051beabdc3cSJohan Hovold 	.tiocmset		= keyspan_tiocmset,
3052beabdc3cSJohan Hovold 	.attach			= keyspan_startup,
3053beabdc3cSJohan Hovold 	.disconnect		= keyspan_disconnect,
3054beabdc3cSJohan Hovold 	.release		= keyspan_release,
3055beabdc3cSJohan Hovold 	.port_probe		= keyspan_port_probe,
3056beabdc3cSJohan Hovold 	.port_remove		= keyspan_port_remove,
3057beabdc3cSJohan Hovold };
3058beabdc3cSJohan Hovold 
3059beabdc3cSJohan Hovold static struct usb_serial_driver keyspan_4port_device = {
3060beabdc3cSJohan Hovold 	.driver = {
3061beabdc3cSJohan Hovold 		.owner		= THIS_MODULE,
3062beabdc3cSJohan Hovold 		.name		= "keyspan_4",
3063beabdc3cSJohan Hovold 	},
3064beabdc3cSJohan Hovold 	.description		= "Keyspan 4 port adapter",
3065beabdc3cSJohan Hovold 	.id_table		= keyspan_4port_ids,
3066beabdc3cSJohan Hovold 	.num_ports		= 4,
3067beabdc3cSJohan Hovold 	.open			= keyspan_open,
3068beabdc3cSJohan Hovold 	.close			= keyspan_close,
3069beabdc3cSJohan Hovold 	.dtr_rts		= keyspan_dtr_rts,
3070beabdc3cSJohan Hovold 	.write			= keyspan_write,
3071beabdc3cSJohan Hovold 	.write_room		= keyspan_write_room,
3072beabdc3cSJohan Hovold 	.set_termios		= keyspan_set_termios,
3073beabdc3cSJohan Hovold 	.break_ctl		= keyspan_break_ctl,
3074beabdc3cSJohan Hovold 	.tiocmget		= keyspan_tiocmget,
3075beabdc3cSJohan Hovold 	.tiocmset		= keyspan_tiocmset,
3076beabdc3cSJohan Hovold 	.attach			= keyspan_startup,
3077beabdc3cSJohan Hovold 	.disconnect		= keyspan_disconnect,
3078beabdc3cSJohan Hovold 	.release		= keyspan_release,
3079beabdc3cSJohan Hovold 	.port_probe		= keyspan_port_probe,
3080beabdc3cSJohan Hovold 	.port_remove		= keyspan_port_remove,
3081beabdc3cSJohan Hovold };
3082beabdc3cSJohan Hovold 
3083beabdc3cSJohan Hovold static struct usb_serial_driver * const serial_drivers[] = {
3084beabdc3cSJohan Hovold 	&keyspan_pre_device, &keyspan_1port_device,
3085beabdc3cSJohan Hovold 	&keyspan_2port_device, &keyspan_4port_device, NULL
3086beabdc3cSJohan Hovold };
3087beabdc3cSJohan Hovold 
3088beabdc3cSJohan Hovold module_usb_serial_driver(serial_drivers, keyspan_ids_combined);
3089beabdc3cSJohan Hovold 
30901da177e4SLinus Torvalds MODULE_AUTHOR(DRIVER_AUTHOR);
30911da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC);
30921da177e4SLinus Torvalds MODULE_LICENSE("GPL");
30931da177e4SLinus Torvalds 
30942971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa28.fw");
30952971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa28x.fw");
30962971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa28xa.fw");
30972971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa28xb.fw");
30982971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa19.fw");
30992971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa19qi.fw");
31002971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/mpr.fw");
31012971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa19qw.fw");
31022971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa18x.fw");
31032971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa19w.fw");
31042971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa49w.fw");
31052971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa49wlc.fw");
3106