xref: /linux/drivers/usb/serial/keyspan.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
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 
keyspan_break_ctl(struct tty_struct * tty,int break_state)602*6ff58ae1SJohan Hovold static int 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 
614*6ff58ae1SJohan Hovold 	/* FIXME: return errors */
6151da177e4SLinus Torvalds 	keyspan_send_setup(port, 0);
616*6ff58ae1SJohan Hovold 
617*6ff58ae1SJohan Hovold 	return 0;
6181da177e4SLinus Torvalds }
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds 
keyspan_set_termios(struct tty_struct * tty,struct usb_serial_port * port,const struct ktermios * old_termios)62195da310eSAlan Cox static void keyspan_set_termios(struct tty_struct *tty,
622f6d47fe5SIlpo Järvinen 				struct usb_serial_port *port,
623f6d47fe5SIlpo Järvinen 				const struct ktermios *old_termios)
6241da177e4SLinus Torvalds {
6251da177e4SLinus Torvalds 	int				baud_rate, device_port;
6261da177e4SLinus Torvalds 	struct keyspan_port_private 	*p_priv;
6271da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
6281da177e4SLinus Torvalds 	unsigned int 			cflag;
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
6311da177e4SLinus Torvalds 	d_details = p_priv->device_details;
632adc8d746SAlan Cox 	cflag = tty->termios.c_cflag;
6331143832eSGreg Kroah-Hartman 	device_port = port->port_number;
6341da177e4SLinus Torvalds 
6351da177e4SLinus Torvalds 	/* Baud rate calculation takes baud rate as an integer
6361da177e4SLinus Torvalds 	   so other rates can be generated if desired. */
63774240b07SAlan Cox 	baud_rate = tty_get_baud_rate(tty);
6381da177e4SLinus Torvalds 	/* If no match or invalid, don't change */
639049c6b4eSGreg Kroah-Hartman 	if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
6401da177e4SLinus Torvalds 				NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
6411da177e4SLinus Torvalds 		/* FIXME - more to do here to ensure rate changes cleanly */
642cd8c5053SRahul Bedarkar 		/* FIXME - calculate exact rate from divisor ? */
6431da177e4SLinus Torvalds 		p_priv->baud = baud_rate;
64474240b07SAlan Cox 	} else
64574240b07SAlan Cox 		baud_rate = tty_termios_baud_rate(old_termios);
6461da177e4SLinus Torvalds 
64774240b07SAlan Cox 	tty_encode_baud_rate(tty, baud_rate, baud_rate);
6481da177e4SLinus Torvalds 	/* set CTS/RTS handshake etc. */
6491da177e4SLinus Torvalds 	p_priv->cflag = cflag;
6501da177e4SLinus Torvalds 	p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
6511da177e4SLinus Torvalds 
65274240b07SAlan Cox 	/* Mark/Space not supported */
653adc8d746SAlan Cox 	tty->termios.c_cflag &= ~CMSPAR;
65474240b07SAlan Cox 
6551da177e4SLinus Torvalds 	keyspan_send_setup(port, 0);
6561da177e4SLinus Torvalds }
6571da177e4SLinus Torvalds 
keyspan_tiocmget(struct tty_struct * tty)65860b33c13SAlan Cox static int keyspan_tiocmget(struct tty_struct *tty)
6591da177e4SLinus Torvalds {
66095da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
66195da310eSAlan Cox 	struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
6621da177e4SLinus Torvalds 	unsigned int			value;
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 	value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
6651da177e4SLinus Torvalds 		((p_priv->dtr_state) ? TIOCM_DTR : 0) |
6661da177e4SLinus Torvalds 		((p_priv->cts_state) ? TIOCM_CTS : 0) |
6671da177e4SLinus Torvalds 		((p_priv->dsr_state) ? TIOCM_DSR : 0) |
6681da177e4SLinus Torvalds 		((p_priv->dcd_state) ? TIOCM_CAR : 0) |
6691da177e4SLinus Torvalds 		((p_priv->ri_state) ? TIOCM_RNG : 0);
6701da177e4SLinus Torvalds 
6711da177e4SLinus Torvalds 	return value;
6721da177e4SLinus Torvalds }
6731da177e4SLinus Torvalds 
keyspan_tiocmset(struct tty_struct * tty,unsigned int set,unsigned int clear)67420b9d177SAlan Cox static int keyspan_tiocmset(struct tty_struct *tty,
6751da177e4SLinus Torvalds 			    unsigned int set, unsigned int clear)
6761da177e4SLinus Torvalds {
67795da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
67895da310eSAlan Cox 	struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
6791da177e4SLinus Torvalds 
6801da177e4SLinus Torvalds 	if (set & TIOCM_RTS)
6811da177e4SLinus Torvalds 		p_priv->rts_state = 1;
6821da177e4SLinus Torvalds 	if (set & TIOCM_DTR)
6831da177e4SLinus Torvalds 		p_priv->dtr_state = 1;
6841da177e4SLinus Torvalds 	if (clear & TIOCM_RTS)
6851da177e4SLinus Torvalds 		p_priv->rts_state = 0;
6861da177e4SLinus Torvalds 	if (clear & TIOCM_DTR)
6871da177e4SLinus Torvalds 		p_priv->dtr_state = 0;
6881da177e4SLinus Torvalds 	keyspan_send_setup(port, 0);
6891da177e4SLinus Torvalds 	return 0;
6901da177e4SLinus Torvalds }
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds /* Write function is similar for the four protocols used
6931da177e4SLinus Torvalds    with only a minor change for usa90 (usa19hs) required */
keyspan_write(struct tty_struct * tty,struct usb_serial_port * port,const unsigned char * buf,int count)69495da310eSAlan Cox static int keyspan_write(struct tty_struct *tty,
69595da310eSAlan Cox 	struct usb_serial_port *port, const unsigned char *buf, int count)
6961da177e4SLinus Torvalds {
6971da177e4SLinus Torvalds 	struct keyspan_port_private 	*p_priv;
6981da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
6991da177e4SLinus Torvalds 	int				flip;
7001da177e4SLinus Torvalds 	int 				left, todo;
7011da177e4SLinus Torvalds 	struct urb			*this_urb;
7021da177e4SLinus Torvalds 	int 				err, maxDataLen, dataOffset;
7031da177e4SLinus Torvalds 
7041da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
7051da177e4SLinus Torvalds 	d_details = p_priv->device_details;
7061da177e4SLinus Torvalds 
7071da177e4SLinus Torvalds 	if (d_details->msg_format == msg_usa90) {
7081da177e4SLinus Torvalds 		maxDataLen = 64;
7091da177e4SLinus Torvalds 		dataOffset = 0;
7101da177e4SLinus Torvalds 	} else {
7111da177e4SLinus Torvalds 		maxDataLen = 63;
7121da177e4SLinus Torvalds 		dataOffset = 1;
7131da177e4SLinus Torvalds 	}
7141da177e4SLinus Torvalds 
7151143832eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - %d chars, flip=%d\n", __func__, count,
7161143832eSGreg Kroah-Hartman 		p_priv->out_flip);
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds 	for (left = count; left > 0; left -= todo) {
7191da177e4SLinus Torvalds 		todo = left;
7201da177e4SLinus Torvalds 		if (todo > maxDataLen)
7211da177e4SLinus Torvalds 			todo = maxDataLen;
7221da177e4SLinus Torvalds 
7231da177e4SLinus Torvalds 		flip = p_priv->out_flip;
7241da177e4SLinus Torvalds 
7251da177e4SLinus Torvalds 		/* Check we have a valid urb/endpoint before we use it... */
726deb91685SAlan Cox 		this_urb = p_priv->out_urbs[flip];
727deb91685SAlan Cox 		if (this_urb == NULL) {
7281da177e4SLinus Torvalds 			/* no bulk out, so return 0 bytes written */
729049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - no output urb :(\n", __func__);
7301da177e4SLinus Torvalds 			return count;
7311da177e4SLinus Torvalds 		}
7321da177e4SLinus Torvalds 
7330cd782b0SJohan Hovold 		dev_dbg(&port->dev, "%s - endpoint %x flip %d\n",
734deb91685SAlan Cox 			__func__, usb_pipeendpoint(this_urb->pipe), flip);
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds 		if (this_urb->status == -EINPROGRESS) {
737deb91685SAlan Cox 			if (time_before(jiffies,
738deb91685SAlan Cox 					p_priv->tx_start_time[flip] + 10 * HZ))
7391da177e4SLinus Torvalds 				break;
7401da177e4SLinus Torvalds 			usb_unlink_urb(this_urb);
7411da177e4SLinus Torvalds 			break;
7421da177e4SLinus Torvalds 		}
7431da177e4SLinus Torvalds 
744deb91685SAlan Cox 		/* First byte in buffer is "last flag" (except for usa19hx)
745deb91685SAlan Cox 		   - unused so for now so set to zero */
7461da177e4SLinus Torvalds 		((char *)this_urb->transfer_buffer)[0] = 0;
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds 		memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
7491da177e4SLinus Torvalds 		buf += todo;
7501da177e4SLinus Torvalds 
7511da177e4SLinus Torvalds 		/* send the data out the bulk port */
7521da177e4SLinus Torvalds 		this_urb->transfer_buffer_length = todo + dataOffset;
7531da177e4SLinus Torvalds 
754deb91685SAlan Cox 		err = usb_submit_urb(this_urb, GFP_ATOMIC);
755deb91685SAlan Cox 		if (err != 0)
756049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err);
7571da177e4SLinus Torvalds 		p_priv->tx_start_time[flip] = jiffies;
7581da177e4SLinus Torvalds 
7591da177e4SLinus Torvalds 		/* Flip for next time if usa26 or usa28 interface
7601da177e4SLinus Torvalds 		   (not used on usa49) */
7611da177e4SLinus Torvalds 		p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
7621da177e4SLinus Torvalds 	}
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 	return count - left;
7651da177e4SLinus Torvalds }
7661da177e4SLinus Torvalds 
usa26_indat_callback(struct urb * urb)7677d12e780SDavid Howells static void	usa26_indat_callback(struct urb *urb)
7681da177e4SLinus Torvalds {
7691da177e4SLinus Torvalds 	int			i, err;
7701da177e4SLinus Torvalds 	int			endpoint;
7711da177e4SLinus Torvalds 	struct usb_serial_port	*port;
7721da177e4SLinus Torvalds 	unsigned char 		*data = urb->transfer_buffer;
77395b93454SGreg Kroah-Hartman 	int status = urb->status;
7741da177e4SLinus Torvalds 
7751da177e4SLinus Torvalds 	endpoint = usb_pipeendpoint(urb->pipe);
7761da177e4SLinus Torvalds 
77795b93454SGreg Kroah-Hartman 	if (status) {
7780cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
779441b62c1SHarvey Harrison 			__func__, status, endpoint);
7801da177e4SLinus Torvalds 		return;
7811da177e4SLinus Torvalds 	}
7821da177e4SLinus Torvalds 
783cdc97792SMing Lei 	port =  urb->context;
7842e124b4aSJiri Slaby 	if (urb->actual_length) {
7851da177e4SLinus Torvalds 		/* 0x80 bit is error flag */
7861da177e4SLinus Torvalds 		if ((data[0] & 0x80) == 0) {
787deb91685SAlan Cox 			/* no errors on individual bytes, only
788deb91685SAlan Cox 			   possible overrun err */
789855515a6SJohan Hovold 			if (data[0] & RXERROR_OVERRUN) {
790855515a6SJohan Hovold 				tty_insert_flip_char(&port->port, 0,
791855515a6SJohan Hovold 								TTY_OVERRUN);
792855515a6SJohan Hovold 			}
793deb91685SAlan Cox 			for (i = 1; i < urb->actual_length ; ++i)
794855515a6SJohan Hovold 				tty_insert_flip_char(&port->port, data[i],
795855515a6SJohan Hovold 								TTY_NORMAL);
7961da177e4SLinus Torvalds 		} else {
7971da177e4SLinus Torvalds 			/* some bytes had errors, every byte has status */
798049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
7991da177e4SLinus Torvalds 			for (i = 0; i + 1 < urb->actual_length; i += 2) {
8005d1678a3SJohan Hovold 				int stat = data[i];
8015d1678a3SJohan Hovold 				int flag = TTY_NORMAL;
8025d1678a3SJohan Hovold 
8035d1678a3SJohan Hovold 				if (stat & RXERROR_OVERRUN) {
8045d1678a3SJohan Hovold 					tty_insert_flip_char(&port->port, 0,
8055d1678a3SJohan Hovold 								TTY_OVERRUN);
8065d1678a3SJohan Hovold 				}
8071da177e4SLinus Torvalds 				/* XXX should handle break (0x10) */
8085d1678a3SJohan Hovold 				if (stat & RXERROR_PARITY)
8095d1678a3SJohan Hovold 					flag = TTY_PARITY;
8105d1678a3SJohan Hovold 				else if (stat & RXERROR_FRAMING)
8115d1678a3SJohan Hovold 					flag = TTY_FRAME;
8125d1678a3SJohan Hovold 
81392a19f9cSJiri Slaby 				tty_insert_flip_char(&port->port, data[i+1],
81492a19f9cSJiri Slaby 						flag);
8151da177e4SLinus Torvalds 			}
8161da177e4SLinus Torvalds 		}
8172e124b4aSJiri Slaby 		tty_flip_buffer_push(&port->port);
8181da177e4SLinus Torvalds 	}
8191da177e4SLinus Torvalds 
8201da177e4SLinus Torvalds 	/* Resubmit urb so we continue receiving */
821deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
822deb91685SAlan Cox 	if (err != 0)
823049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
8241da177e4SLinus Torvalds }
8251da177e4SLinus Torvalds 
8261da177e4SLinus Torvalds /* Outdat handling is common for all devices */
usa2x_outdat_callback(struct urb * urb)8277d12e780SDavid Howells static void	usa2x_outdat_callback(struct urb *urb)
8281da177e4SLinus Torvalds {
8291da177e4SLinus Torvalds 	struct usb_serial_port *port;
8301da177e4SLinus Torvalds 	struct keyspan_port_private *p_priv;
8311da177e4SLinus Torvalds 
832cdc97792SMing Lei 	port =  urb->context;
8331da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
834049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
8351da177e4SLinus Torvalds 
836cf2c7481SPete Zaitcev 	usb_serial_port_softint(port);
8371da177e4SLinus Torvalds }
8381da177e4SLinus Torvalds 
usa26_inack_callback(struct urb * urb)8397d12e780SDavid Howells static void	usa26_inack_callback(struct urb *urb)
8401da177e4SLinus Torvalds {
8411da177e4SLinus Torvalds }
8421da177e4SLinus Torvalds 
usa26_outcont_callback(struct urb * urb)8437d12e780SDavid Howells static void	usa26_outcont_callback(struct urb *urb)
8441da177e4SLinus Torvalds {
8451da177e4SLinus Torvalds 	struct usb_serial_port *port;
8461da177e4SLinus Torvalds 	struct keyspan_port_private *p_priv;
8471da177e4SLinus Torvalds 
848cdc97792SMing Lei 	port =  urb->context;
8491da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
8501da177e4SLinus Torvalds 
8511da177e4SLinus Torvalds 	if (p_priv->resend_cont) {
852049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - sending setup\n", __func__);
853deb91685SAlan Cox 		keyspan_usa26_send_setup(port->serial, port,
854deb91685SAlan Cox 						p_priv->resend_cont - 1);
8551da177e4SLinus Torvalds 	}
8561da177e4SLinus Torvalds }
8571da177e4SLinus Torvalds 
usa26_instat_callback(struct urb * urb)8587d12e780SDavid Howells static void	usa26_instat_callback(struct urb *urb)
8591da177e4SLinus Torvalds {
8601da177e4SLinus Torvalds 	unsigned char 				*data = urb->transfer_buffer;
8611da177e4SLinus Torvalds 	struct keyspan_usa26_portStatusMessage	*msg;
8621da177e4SLinus Torvalds 	struct usb_serial			*serial;
8631da177e4SLinus Torvalds 	struct usb_serial_port			*port;
8641da177e4SLinus Torvalds 	struct keyspan_port_private	 	*p_priv;
8651da177e4SLinus Torvalds 	int old_dcd_state, err;
86695b93454SGreg Kroah-Hartman 	int status = urb->status;
8671da177e4SLinus Torvalds 
868cdc97792SMing Lei 	serial =  urb->context;
8691da177e4SLinus Torvalds 
87095b93454SGreg Kroah-Hartman 	if (status) {
8710cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
8720cd782b0SJohan Hovold 				__func__, status);
8731da177e4SLinus Torvalds 		return;
8741da177e4SLinus Torvalds 	}
8751da177e4SLinus Torvalds 	if (urb->actual_length != 9) {
876049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
8771da177e4SLinus Torvalds 		goto exit;
8781da177e4SLinus Torvalds 	}
8791da177e4SLinus Torvalds 
8801da177e4SLinus Torvalds 	msg = (struct keyspan_usa26_portStatusMessage *)data;
8811da177e4SLinus Torvalds 
8821da177e4SLinus Torvalds 	/* Check port number from message and retrieve private data */
8831da177e4SLinus Torvalds 	if (msg->port >= serial->num_ports) {
884049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
8851da177e4SLinus Torvalds 		goto exit;
8861da177e4SLinus Torvalds 	}
8871da177e4SLinus Torvalds 	port = serial->port[msg->port];
8881da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
889b5122236SJohan Hovold 	if (!p_priv)
890b5122236SJohan Hovold 		goto resubmit;
8911da177e4SLinus Torvalds 
8921da177e4SLinus Torvalds 	/* Update handshaking pin state information */
8931da177e4SLinus Torvalds 	old_dcd_state = p_priv->dcd_state;
8941da177e4SLinus Torvalds 	p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
8951da177e4SLinus Torvalds 	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
8961da177e4SLinus Torvalds 	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
8971da177e4SLinus Torvalds 	p_priv->ri_state = ((msg->ri) ? 1 : 0);
8981da177e4SLinus Torvalds 
899aa27a094SJiri Slaby 	if (old_dcd_state != p_priv->dcd_state)
900aa27a094SJiri Slaby 		tty_port_tty_hangup(&port->port, true);
901b5122236SJohan Hovold resubmit:
9021da177e4SLinus Torvalds 	/* Resubmit urb so we continue receiving */
903deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
904deb91685SAlan Cox 	if (err != 0)
905049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
9061da177e4SLinus Torvalds exit: ;
9071da177e4SLinus Torvalds }
9081da177e4SLinus Torvalds 
usa26_glocont_callback(struct urb * urb)9097d12e780SDavid Howells static void	usa26_glocont_callback(struct urb *urb)
9101da177e4SLinus Torvalds {
9111da177e4SLinus Torvalds }
9121da177e4SLinus Torvalds 
9131da177e4SLinus Torvalds 
usa28_indat_callback(struct urb * urb)9147d12e780SDavid Howells static void usa28_indat_callback(struct urb *urb)
9151da177e4SLinus Torvalds {
916f035a8adSAlan Cox 	int                     err;
9171da177e4SLinus Torvalds 	struct usb_serial_port  *port;
9181da177e4SLinus Torvalds 	unsigned char           *data;
9191da177e4SLinus Torvalds 	struct keyspan_port_private             *p_priv;
92095b93454SGreg Kroah-Hartman 	int status = urb->status;
9211da177e4SLinus Torvalds 
922cdc97792SMing Lei 	port =  urb->context;
9231da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
9241da177e4SLinus Torvalds 
9251da177e4SLinus Torvalds 	if (urb != p_priv->in_urbs[p_priv->in_flip])
9261da177e4SLinus Torvalds 		return;
9271da177e4SLinus Torvalds 
9281da177e4SLinus Torvalds 	do {
92995b93454SGreg Kroah-Hartman 		if (status) {
9300cd782b0SJohan Hovold 			dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
931441b62c1SHarvey Harrison 				__func__, status, usb_pipeendpoint(urb->pipe));
9321da177e4SLinus Torvalds 			return;
9331da177e4SLinus Torvalds 		}
9341da177e4SLinus Torvalds 
935cdc97792SMing Lei 		port =  urb->context;
9361da177e4SLinus Torvalds 		p_priv = usb_get_serial_port_data(port);
9371da177e4SLinus Torvalds 		data = urb->transfer_buffer;
9381da177e4SLinus Torvalds 
9392e124b4aSJiri Slaby 		if (urb->actual_length) {
94005c7cd39SJiri Slaby 			tty_insert_flip_string(&port->port, data,
94105c7cd39SJiri Slaby 					urb->actual_length);
9422e124b4aSJiri Slaby 			tty_flip_buffer_push(&port->port);
9431da177e4SLinus Torvalds 		}
9441da177e4SLinus Torvalds 
9451da177e4SLinus Torvalds 		/* Resubmit urb so we continue receiving */
946deb91685SAlan Cox 		err = usb_submit_urb(urb, GFP_ATOMIC);
947deb91685SAlan Cox 		if (err != 0)
948049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
949deb91685SAlan Cox 							__func__, err);
9501da177e4SLinus Torvalds 		p_priv->in_flip ^= 1;
9511da177e4SLinus Torvalds 
9521da177e4SLinus Torvalds 		urb = p_priv->in_urbs[p_priv->in_flip];
9531da177e4SLinus Torvalds 	} while (urb->status != -EINPROGRESS);
9541da177e4SLinus Torvalds }
9551da177e4SLinus Torvalds 
usa28_inack_callback(struct urb * urb)9567d12e780SDavid Howells static void	usa28_inack_callback(struct urb *urb)
9571da177e4SLinus Torvalds {
9581da177e4SLinus Torvalds }
9591da177e4SLinus Torvalds 
usa28_outcont_callback(struct urb * urb)9607d12e780SDavid Howells static void	usa28_outcont_callback(struct urb *urb)
9611da177e4SLinus Torvalds {
9621da177e4SLinus Torvalds 	struct usb_serial_port *port;
9631da177e4SLinus Torvalds 	struct keyspan_port_private *p_priv;
9641da177e4SLinus Torvalds 
965cdc97792SMing Lei 	port =  urb->context;
9661da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
9671da177e4SLinus Torvalds 
9681da177e4SLinus Torvalds 	if (p_priv->resend_cont) {
969049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - sending setup\n", __func__);
970deb91685SAlan Cox 		keyspan_usa28_send_setup(port->serial, port,
971deb91685SAlan Cox 						p_priv->resend_cont - 1);
9721da177e4SLinus Torvalds 	}
9731da177e4SLinus Torvalds }
9741da177e4SLinus Torvalds 
usa28_instat_callback(struct urb * urb)9757d12e780SDavid Howells static void	usa28_instat_callback(struct urb *urb)
9761da177e4SLinus Torvalds {
9771da177e4SLinus Torvalds 	int					err;
9781da177e4SLinus Torvalds 	unsigned char 				*data = urb->transfer_buffer;
9791da177e4SLinus Torvalds 	struct keyspan_usa28_portStatusMessage	*msg;
9801da177e4SLinus Torvalds 	struct usb_serial			*serial;
9811da177e4SLinus Torvalds 	struct usb_serial_port			*port;
9821da177e4SLinus Torvalds 	struct keyspan_port_private	 	*p_priv;
9831da177e4SLinus Torvalds 	int old_dcd_state;
98495b93454SGreg Kroah-Hartman 	int status = urb->status;
9851da177e4SLinus Torvalds 
986cdc97792SMing Lei 	serial =  urb->context;
9871da177e4SLinus Torvalds 
98895b93454SGreg Kroah-Hartman 	if (status) {
9890cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
9900cd782b0SJohan Hovold 				__func__, status);
9911da177e4SLinus Torvalds 		return;
9921da177e4SLinus Torvalds 	}
9931da177e4SLinus Torvalds 
9941da177e4SLinus Torvalds 	if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
995049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
9961da177e4SLinus Torvalds 		goto exit;
9971da177e4SLinus Torvalds 	}
9981da177e4SLinus Torvalds 
9991da177e4SLinus Torvalds 	msg = (struct keyspan_usa28_portStatusMessage *)data;
10001da177e4SLinus Torvalds 
10011da177e4SLinus Torvalds 	/* Check port number from message and retrieve private data */
10021da177e4SLinus Torvalds 	if (msg->port >= serial->num_ports) {
1003049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
10041da177e4SLinus Torvalds 		goto exit;
10051da177e4SLinus Torvalds 	}
10061da177e4SLinus Torvalds 	port = serial->port[msg->port];
10071da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
1008b5122236SJohan Hovold 	if (!p_priv)
1009b5122236SJohan Hovold 		goto resubmit;
10101da177e4SLinus Torvalds 
10111da177e4SLinus Torvalds 	/* Update handshaking pin state information */
10121da177e4SLinus Torvalds 	old_dcd_state = p_priv->dcd_state;
10131da177e4SLinus Torvalds 	p_priv->cts_state = ((msg->cts) ? 1 : 0);
10141da177e4SLinus Torvalds 	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
10151da177e4SLinus Torvalds 	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
10161da177e4SLinus Torvalds 	p_priv->ri_state = ((msg->ri) ? 1 : 0);
10171da177e4SLinus Torvalds 
1018aa27a094SJiri Slaby 	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
1019aa27a094SJiri Slaby 		tty_port_tty_hangup(&port->port, true);
1020b5122236SJohan Hovold resubmit:
10211da177e4SLinus Torvalds 		/* Resubmit urb so we continue receiving */
1022deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
1023deb91685SAlan Cox 	if (err != 0)
1024049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
10251da177e4SLinus Torvalds exit: ;
10261da177e4SLinus Torvalds }
10271da177e4SLinus Torvalds 
usa28_glocont_callback(struct urb * urb)10287d12e780SDavid Howells static void	usa28_glocont_callback(struct urb *urb)
10291da177e4SLinus Torvalds {
10301da177e4SLinus Torvalds }
10311da177e4SLinus Torvalds 
10321da177e4SLinus Torvalds 
usa49_glocont_callback(struct urb * urb)10337d12e780SDavid Howells static void	usa49_glocont_callback(struct urb *urb)
10341da177e4SLinus Torvalds {
10351da177e4SLinus Torvalds 	struct usb_serial *serial;
10361da177e4SLinus Torvalds 	struct usb_serial_port *port;
10371da177e4SLinus Torvalds 	struct keyspan_port_private *p_priv;
10381da177e4SLinus Torvalds 	int i;
10391da177e4SLinus Torvalds 
1040cdc97792SMing Lei 	serial =  urb->context;
10411da177e4SLinus Torvalds 	for (i = 0; i < serial->num_ports; ++i) {
10421da177e4SLinus Torvalds 		port = serial->port[i];
10431da177e4SLinus Torvalds 		p_priv = usb_get_serial_port_data(port);
10443018dd3fSJohan Hovold 		if (!p_priv)
10453018dd3fSJohan Hovold 			continue;
10461da177e4SLinus Torvalds 
10471da177e4SLinus Torvalds 		if (p_priv->resend_cont) {
1048049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - sending setup\n", __func__);
1049deb91685SAlan Cox 			keyspan_usa49_send_setup(serial, port,
1050deb91685SAlan Cox 						p_priv->resend_cont - 1);
10511da177e4SLinus Torvalds 			break;
10521da177e4SLinus Torvalds 		}
10531da177e4SLinus Torvalds 	}
10541da177e4SLinus Torvalds }
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds 	/* This is actually called glostat in the Keyspan
10571da177e4SLinus Torvalds 	   doco */
usa49_instat_callback(struct urb * urb)10587d12e780SDavid Howells static void	usa49_instat_callback(struct urb *urb)
10591da177e4SLinus Torvalds {
10601da177e4SLinus Torvalds 	int					err;
10611da177e4SLinus Torvalds 	unsigned char 				*data = urb->transfer_buffer;
10621da177e4SLinus Torvalds 	struct keyspan_usa49_portStatusMessage	*msg;
10631da177e4SLinus Torvalds 	struct usb_serial			*serial;
10641da177e4SLinus Torvalds 	struct usb_serial_port			*port;
10651da177e4SLinus Torvalds 	struct keyspan_port_private	 	*p_priv;
10661da177e4SLinus Torvalds 	int old_dcd_state;
106795b93454SGreg Kroah-Hartman 	int status = urb->status;
10681da177e4SLinus Torvalds 
1069cdc97792SMing Lei 	serial =  urb->context;
10701da177e4SLinus Torvalds 
107195b93454SGreg Kroah-Hartman 	if (status) {
10720cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
10730cd782b0SJohan Hovold 				__func__, status);
10741da177e4SLinus Torvalds 		return;
10751da177e4SLinus Torvalds 	}
10761da177e4SLinus Torvalds 
1077deb91685SAlan Cox 	if (urb->actual_length !=
1078deb91685SAlan Cox 			sizeof(struct keyspan_usa49_portStatusMessage)) {
1079049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
10801da177e4SLinus Torvalds 		goto exit;
10811da177e4SLinus Torvalds 	}
10821da177e4SLinus Torvalds 
10831da177e4SLinus Torvalds 	msg = (struct keyspan_usa49_portStatusMessage *)data;
10841da177e4SLinus Torvalds 
10851da177e4SLinus Torvalds 	/* Check port number from message and retrieve private data */
10861da177e4SLinus Torvalds 	if (msg->portNumber >= serial->num_ports) {
1087049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
1088deb91685SAlan Cox 			__func__, msg->portNumber);
10891da177e4SLinus Torvalds 		goto exit;
10901da177e4SLinus Torvalds 	}
10911da177e4SLinus Torvalds 	port = serial->port[msg->portNumber];
10921da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
1093b5122236SJohan Hovold 	if (!p_priv)
1094b5122236SJohan Hovold 		goto resubmit;
10951da177e4SLinus Torvalds 
10961da177e4SLinus Torvalds 	/* Update handshaking pin state information */
10971da177e4SLinus Torvalds 	old_dcd_state = p_priv->dcd_state;
10981da177e4SLinus Torvalds 	p_priv->cts_state = ((msg->cts) ? 1 : 0);
10991da177e4SLinus Torvalds 	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
11001da177e4SLinus Torvalds 	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
11011da177e4SLinus Torvalds 	p_priv->ri_state = ((msg->ri) ? 1 : 0);
11021da177e4SLinus Torvalds 
1103aa27a094SJiri Slaby 	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
1104aa27a094SJiri Slaby 		tty_port_tty_hangup(&port->port, true);
1105b5122236SJohan Hovold resubmit:
11061da177e4SLinus Torvalds 	/* Resubmit urb so we continue receiving */
1107deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
1108deb91685SAlan Cox 	if (err != 0)
1109049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
11101da177e4SLinus Torvalds exit:	;
11111da177e4SLinus Torvalds }
11121da177e4SLinus Torvalds 
usa49_inack_callback(struct urb * urb)11137d12e780SDavid Howells static void	usa49_inack_callback(struct urb *urb)
11141da177e4SLinus Torvalds {
11151da177e4SLinus Torvalds }
11161da177e4SLinus Torvalds 
usa49_indat_callback(struct urb * urb)11177d12e780SDavid Howells static void	usa49_indat_callback(struct urb *urb)
11181da177e4SLinus Torvalds {
11191da177e4SLinus Torvalds 	int			i, err;
11201da177e4SLinus Torvalds 	int			endpoint;
11211da177e4SLinus Torvalds 	struct usb_serial_port	*port;
11221da177e4SLinus Torvalds 	unsigned char 		*data = urb->transfer_buffer;
112395b93454SGreg Kroah-Hartman 	int status = urb->status;
11241da177e4SLinus Torvalds 
11251da177e4SLinus Torvalds 	endpoint = usb_pipeendpoint(urb->pipe);
11261da177e4SLinus Torvalds 
112795b93454SGreg Kroah-Hartman 	if (status) {
11280cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
1129049c6b4eSGreg Kroah-Hartman 			__func__, status, endpoint);
11301da177e4SLinus Torvalds 		return;
11311da177e4SLinus Torvalds 	}
11321da177e4SLinus Torvalds 
1133cdc97792SMing Lei 	port =  urb->context;
11342e124b4aSJiri Slaby 	if (urb->actual_length) {
11351da177e4SLinus Torvalds 		/* 0x80 bit is error flag */
11361da177e4SLinus Torvalds 		if ((data[0] & 0x80) == 0) {
11371da177e4SLinus Torvalds 			/* no error on any byte */
113805c7cd39SJiri Slaby 			tty_insert_flip_string(&port->port, data + 1,
1139f035a8adSAlan Cox 						urb->actual_length - 1);
11401da177e4SLinus Torvalds 		} else {
11411da177e4SLinus Torvalds 			/* some bytes had errors, every byte has status */
11421da177e4SLinus Torvalds 			for (i = 0; i + 1 < urb->actual_length; i += 2) {
11435d1678a3SJohan Hovold 				int stat = data[i];
11445d1678a3SJohan Hovold 				int flag = TTY_NORMAL;
11455d1678a3SJohan Hovold 
11465d1678a3SJohan Hovold 				if (stat & RXERROR_OVERRUN) {
11475d1678a3SJohan Hovold 					tty_insert_flip_char(&port->port, 0,
11485d1678a3SJohan Hovold 								TTY_OVERRUN);
11495d1678a3SJohan Hovold 				}
11501da177e4SLinus Torvalds 				/* XXX should handle break (0x10) */
11515d1678a3SJohan Hovold 				if (stat & RXERROR_PARITY)
11525d1678a3SJohan Hovold 					flag = TTY_PARITY;
11535d1678a3SJohan Hovold 				else if (stat & RXERROR_FRAMING)
11545d1678a3SJohan Hovold 					flag = TTY_FRAME;
11555d1678a3SJohan Hovold 
115692a19f9cSJiri Slaby 				tty_insert_flip_char(&port->port, data[i+1],
115792a19f9cSJiri Slaby 						flag);
11581da177e4SLinus Torvalds 			}
11591da177e4SLinus Torvalds 		}
11602e124b4aSJiri Slaby 		tty_flip_buffer_push(&port->port);
11611da177e4SLinus Torvalds 	}
11621da177e4SLinus Torvalds 
11631da177e4SLinus Torvalds 	/* Resubmit urb so we continue receiving */
1164deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
1165deb91685SAlan Cox 	if (err != 0)
1166049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
11671da177e4SLinus Torvalds }
11681da177e4SLinus Torvalds 
usa49wg_indat_callback(struct urb * urb)11690ca1268eSLucy McCoy static void usa49wg_indat_callback(struct urb *urb)
11700ca1268eSLucy McCoy {
11710ca1268eSLucy McCoy 	int			i, len, x, err;
11720ca1268eSLucy McCoy 	struct usb_serial	*serial;
11730ca1268eSLucy McCoy 	struct usb_serial_port	*port;
11740ca1268eSLucy McCoy 	unsigned char 		*data = urb->transfer_buffer;
117595b93454SGreg Kroah-Hartman 	int status = urb->status;
11760ca1268eSLucy McCoy 
11770ca1268eSLucy McCoy 	serial = urb->context;
11780ca1268eSLucy McCoy 
117995b93454SGreg Kroah-Hartman 	if (status) {
11800cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
11810cd782b0SJohan Hovold 				__func__, status);
11820ca1268eSLucy McCoy 		return;
11830ca1268eSLucy McCoy 	}
11840ca1268eSLucy McCoy 
11850ca1268eSLucy McCoy 	/* inbound data is in the form P#, len, status, data */
11860ca1268eSLucy McCoy 	i = 0;
11870ca1268eSLucy McCoy 	len = 0;
11880ca1268eSLucy McCoy 
11890ca1268eSLucy McCoy 	while (i < urb->actual_length) {
11900ca1268eSLucy McCoy 
11910ca1268eSLucy McCoy 		/* Check port number from message */
11920ca1268eSLucy McCoy 		if (data[i] >= serial->num_ports) {
1193049c6b4eSGreg Kroah-Hartman 			dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
1194441b62c1SHarvey Harrison 				__func__, data[i]);
11950ca1268eSLucy McCoy 			return;
11960ca1268eSLucy McCoy 		}
11970ca1268eSLucy McCoy 		port = serial->port[data[i++]];
11980ca1268eSLucy McCoy 		len = data[i++];
11990ca1268eSLucy McCoy 
12000ca1268eSLucy McCoy 		/* 0x80 bit is error flag */
12010ca1268eSLucy McCoy 		if ((data[i] & 0x80) == 0) {
12020ca1268eSLucy McCoy 			/* no error on any byte */
12030ca1268eSLucy McCoy 			i++;
120401a60e76SDan Carpenter 			for (x = 1; x < len && i < urb->actual_length; ++x)
120592a19f9cSJiri Slaby 				tty_insert_flip_char(&port->port,
120692a19f9cSJiri Slaby 						data[i++], 0);
12070ca1268eSLucy McCoy 		} else {
12080ca1268eSLucy McCoy 			/*
12090ca1268eSLucy McCoy 			 * some bytes had errors, every byte has status
12100ca1268eSLucy McCoy 			 */
121101a60e76SDan Carpenter 			for (x = 0; x + 1 < len &&
121201a60e76SDan Carpenter 				    i + 1 < urb->actual_length; x += 2) {
12135d1678a3SJohan Hovold 				int stat = data[i];
12145d1678a3SJohan Hovold 				int flag = TTY_NORMAL;
12156a3ae841SDan Carpenter 
12165d1678a3SJohan Hovold 				if (stat & RXERROR_OVERRUN) {
12175d1678a3SJohan Hovold 					tty_insert_flip_char(&port->port, 0,
12185d1678a3SJohan Hovold 								TTY_OVERRUN);
12195d1678a3SJohan Hovold 				}
12200ca1268eSLucy McCoy 				/* XXX should handle break (0x10) */
12215d1678a3SJohan Hovold 				if (stat & RXERROR_PARITY)
12225d1678a3SJohan Hovold 					flag = TTY_PARITY;
12235d1678a3SJohan Hovold 				else if (stat & RXERROR_FRAMING)
12245d1678a3SJohan Hovold 					flag = TTY_FRAME;
12255d1678a3SJohan Hovold 
12266a3ae841SDan Carpenter 				tty_insert_flip_char(&port->port, data[i+1],
12276a3ae841SDan Carpenter 						     flag);
12280ca1268eSLucy McCoy 				i += 2;
12290ca1268eSLucy McCoy 			}
12300ca1268eSLucy McCoy 		}
12312e124b4aSJiri Slaby 		tty_flip_buffer_push(&port->port);
12320ca1268eSLucy McCoy 	}
12330ca1268eSLucy McCoy 
12340ca1268eSLucy McCoy 	/* Resubmit urb so we continue receiving */
12350ca1268eSLucy McCoy 	err = usb_submit_urb(urb, GFP_ATOMIC);
12360ca1268eSLucy McCoy 	if (err != 0)
1237049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
12380ca1268eSLucy McCoy }
12390ca1268eSLucy McCoy 
12401da177e4SLinus Torvalds /* not used, usa-49 doesn't have per-port control endpoints */
usa49_outcont_callback(struct urb * urb)12417d12e780SDavid Howells static void usa49_outcont_callback(struct urb *urb)
12421da177e4SLinus Torvalds {
12431da177e4SLinus Torvalds }
12441da177e4SLinus Torvalds 
usa90_indat_callback(struct urb * urb)12457d12e780SDavid Howells static void usa90_indat_callback(struct urb *urb)
12461da177e4SLinus Torvalds {
12471da177e4SLinus Torvalds 	int			i, err;
12481da177e4SLinus Torvalds 	int			endpoint;
12491da177e4SLinus Torvalds 	struct usb_serial_port	*port;
12501da177e4SLinus Torvalds 	struct keyspan_port_private	 	*p_priv;
12511da177e4SLinus Torvalds 	unsigned char 		*data = urb->transfer_buffer;
125295b93454SGreg Kroah-Hartman 	int status = urb->status;
12531da177e4SLinus Torvalds 
12541da177e4SLinus Torvalds 	endpoint = usb_pipeendpoint(urb->pipe);
12551da177e4SLinus Torvalds 
125695b93454SGreg Kroah-Hartman 	if (status) {
12570cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
1258441b62c1SHarvey Harrison 			__func__, status, endpoint);
12591da177e4SLinus Torvalds 		return;
12601da177e4SLinus Torvalds 	}
12611da177e4SLinus Torvalds 
1262cdc97792SMing Lei 	port =  urb->context;
12631da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
12641da177e4SLinus Torvalds 
12651da177e4SLinus Torvalds 	if (urb->actual_length) {
12661da177e4SLinus Torvalds 		/* if current mode is DMA, looks like usa28 format
12671da177e4SLinus Torvalds 		   otherwise looks like usa26 data format */
12681da177e4SLinus Torvalds 
1269f035a8adSAlan Cox 		if (p_priv->baud > 57600)
127005c7cd39SJiri Slaby 			tty_insert_flip_string(&port->port, data,
127105c7cd39SJiri Slaby 					urb->actual_length);
1272f035a8adSAlan Cox 		else {
12731da177e4SLinus Torvalds 			/* 0x80 bit is error flag */
12741da177e4SLinus Torvalds 			if ((data[0] & 0x80) == 0) {
1275deb91685SAlan Cox 				/* no errors on individual bytes, only
1276deb91685SAlan Cox 				   possible overrun err*/
1277855515a6SJohan Hovold 				if (data[0] & RXERROR_OVERRUN) {
1278855515a6SJohan Hovold 					tty_insert_flip_char(&port->port, 0,
1279855515a6SJohan Hovold 								TTY_OVERRUN);
1280855515a6SJohan Hovold 				}
12811da177e4SLinus Torvalds 				for (i = 1; i < urb->actual_length ; ++i)
128292a19f9cSJiri Slaby 					tty_insert_flip_char(&port->port,
1283855515a6SJohan Hovold 							data[i], TTY_NORMAL);
1284deb91685SAlan Cox 			}  else {
12851da177e4SLinus Torvalds 			/* some bytes had errors, every byte has status */
1286049c6b4eSGreg Kroah-Hartman 				dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
12871da177e4SLinus Torvalds 				for (i = 0; i + 1 < urb->actual_length; i += 2) {
12885d1678a3SJohan Hovold 					int stat = data[i];
12895d1678a3SJohan Hovold 					int flag = TTY_NORMAL;
12905d1678a3SJohan Hovold 
12915d1678a3SJohan Hovold 					if (stat & RXERROR_OVERRUN) {
12925d1678a3SJohan Hovold 						tty_insert_flip_char(
12935d1678a3SJohan Hovold 								&port->port, 0,
12945d1678a3SJohan Hovold 								TTY_OVERRUN);
12955d1678a3SJohan Hovold 					}
12961da177e4SLinus Torvalds 					/* XXX should handle break (0x10) */
12975d1678a3SJohan Hovold 					if (stat & RXERROR_PARITY)
12985d1678a3SJohan Hovold 						flag = TTY_PARITY;
12995d1678a3SJohan Hovold 					else if (stat & RXERROR_FRAMING)
13005d1678a3SJohan Hovold 						flag = TTY_FRAME;
13015d1678a3SJohan Hovold 
130292a19f9cSJiri Slaby 					tty_insert_flip_char(&port->port,
130392a19f9cSJiri Slaby 							data[i+1], flag);
13041da177e4SLinus Torvalds 				}
13051da177e4SLinus Torvalds 			}
13061da177e4SLinus Torvalds 		}
13072e124b4aSJiri Slaby 		tty_flip_buffer_push(&port->port);
13081da177e4SLinus Torvalds 	}
13091da177e4SLinus Torvalds 
13101da177e4SLinus Torvalds 	/* Resubmit urb so we continue receiving */
1311deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
1312deb91685SAlan Cox 	if (err != 0)
1313049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
13141da177e4SLinus Torvalds }
13151da177e4SLinus Torvalds 
13161da177e4SLinus Torvalds 
usa90_instat_callback(struct urb * urb)13177d12e780SDavid Howells static void	usa90_instat_callback(struct urb *urb)
13181da177e4SLinus Torvalds {
13191da177e4SLinus Torvalds 	unsigned char 				*data = urb->transfer_buffer;
13201da177e4SLinus Torvalds 	struct keyspan_usa90_portStatusMessage	*msg;
13211da177e4SLinus Torvalds 	struct usb_serial			*serial;
13221da177e4SLinus Torvalds 	struct usb_serial_port			*port;
13231da177e4SLinus Torvalds 	struct keyspan_port_private	 	*p_priv;
13241da177e4SLinus Torvalds 	int old_dcd_state, err;
132595b93454SGreg Kroah-Hartman 	int status = urb->status;
13261da177e4SLinus Torvalds 
1327cdc97792SMing Lei 	serial =  urb->context;
13281da177e4SLinus Torvalds 
132995b93454SGreg Kroah-Hartman 	if (status) {
13300cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
13310cd782b0SJohan Hovold 				__func__, status);
13321da177e4SLinus Torvalds 		return;
13331da177e4SLinus Torvalds 	}
13341da177e4SLinus Torvalds 	if (urb->actual_length < 14) {
1335049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
13361da177e4SLinus Torvalds 		goto exit;
13371da177e4SLinus Torvalds 	}
13381da177e4SLinus Torvalds 
13391da177e4SLinus Torvalds 	msg = (struct keyspan_usa90_portStatusMessage *)data;
13401da177e4SLinus Torvalds 
13411da177e4SLinus Torvalds 	/* Now do something useful with the data */
13421da177e4SLinus Torvalds 
13431da177e4SLinus Torvalds 	port = serial->port[0];
13441da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
1345b5122236SJohan Hovold 	if (!p_priv)
1346b5122236SJohan Hovold 		goto resubmit;
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds 	/* Update handshaking pin state information */
13491da177e4SLinus Torvalds 	old_dcd_state = p_priv->dcd_state;
13501da177e4SLinus Torvalds 	p_priv->cts_state = ((msg->cts) ? 1 : 0);
13511da177e4SLinus Torvalds 	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
13521da177e4SLinus Torvalds 	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
13531da177e4SLinus Torvalds 	p_priv->ri_state = ((msg->ri) ? 1 : 0);
13541da177e4SLinus Torvalds 
1355aa27a094SJiri Slaby 	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
1356aa27a094SJiri Slaby 		tty_port_tty_hangup(&port->port, true);
1357b5122236SJohan Hovold resubmit:
13581da177e4SLinus Torvalds 	/* Resubmit urb so we continue receiving */
1359deb91685SAlan Cox 	err = usb_submit_urb(urb, GFP_ATOMIC);
1360deb91685SAlan Cox 	if (err != 0)
1361049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
13621da177e4SLinus Torvalds exit:
13631da177e4SLinus Torvalds 	;
13641da177e4SLinus Torvalds }
13651da177e4SLinus Torvalds 
usa90_outcont_callback(struct urb * urb)13667d12e780SDavid Howells static void	usa90_outcont_callback(struct urb *urb)
13671da177e4SLinus Torvalds {
13681da177e4SLinus Torvalds 	struct usb_serial_port *port;
13691da177e4SLinus Torvalds 	struct keyspan_port_private *p_priv;
13701da177e4SLinus Torvalds 
1371cdc97792SMing Lei 	port =  urb->context;
13721da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
13731da177e4SLinus Torvalds 
13741da177e4SLinus Torvalds 	if (p_priv->resend_cont) {
1375049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
1376deb91685SAlan Cox 		keyspan_usa90_send_setup(port->serial, port,
1377deb91685SAlan Cox 						p_priv->resend_cont - 1);
13781da177e4SLinus Torvalds 	}
13791da177e4SLinus Torvalds }
13801da177e4SLinus Torvalds 
13810ca1268eSLucy McCoy /* Status messages from the 28xg */
usa67_instat_callback(struct urb * urb)13820ca1268eSLucy McCoy static void	usa67_instat_callback(struct urb *urb)
13830ca1268eSLucy McCoy {
13840ca1268eSLucy McCoy 	int					err;
13850ca1268eSLucy McCoy 	unsigned char 				*data = urb->transfer_buffer;
13860ca1268eSLucy McCoy 	struct keyspan_usa67_portStatusMessage	*msg;
13870ca1268eSLucy McCoy 	struct usb_serial			*serial;
13880ca1268eSLucy McCoy 	struct usb_serial_port			*port;
13890ca1268eSLucy McCoy 	struct keyspan_port_private	 	*p_priv;
13900ca1268eSLucy McCoy 	int old_dcd_state;
139195b93454SGreg Kroah-Hartman 	int status = urb->status;
13920ca1268eSLucy McCoy 
13930ca1268eSLucy McCoy 	serial = urb->context;
13940ca1268eSLucy McCoy 
139595b93454SGreg Kroah-Hartman 	if (status) {
13960cd782b0SJohan Hovold 		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
13970cd782b0SJohan Hovold 				__func__, status);
13980ca1268eSLucy McCoy 		return;
13990ca1268eSLucy McCoy 	}
14000ca1268eSLucy McCoy 
1401deb91685SAlan Cox 	if (urb->actual_length !=
1402deb91685SAlan Cox 			sizeof(struct keyspan_usa67_portStatusMessage)) {
1403049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
14040ca1268eSLucy McCoy 		return;
14050ca1268eSLucy McCoy 	}
14060ca1268eSLucy McCoy 
14070ca1268eSLucy McCoy 
14080ca1268eSLucy McCoy 	/* Now do something useful with the data */
14090ca1268eSLucy McCoy 	msg = (struct keyspan_usa67_portStatusMessage *)data;
14100ca1268eSLucy McCoy 
14110ca1268eSLucy McCoy 	/* Check port number from message and retrieve private data */
14120ca1268eSLucy McCoy 	if (msg->port >= serial->num_ports) {
1413049c6b4eSGreg Kroah-Hartman 		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
14140ca1268eSLucy McCoy 		return;
14150ca1268eSLucy McCoy 	}
14160ca1268eSLucy McCoy 
14170ca1268eSLucy McCoy 	port = serial->port[msg->port];
14180ca1268eSLucy McCoy 	p_priv = usb_get_serial_port_data(port);
1419b5122236SJohan Hovold 	if (!p_priv)
1420b5122236SJohan Hovold 		goto resubmit;
14210ca1268eSLucy McCoy 
14220ca1268eSLucy McCoy 	/* Update handshaking pin state information */
14230ca1268eSLucy McCoy 	old_dcd_state = p_priv->dcd_state;
14240ca1268eSLucy McCoy 	p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
14250ca1268eSLucy McCoy 	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
14260ca1268eSLucy McCoy 
1427aa27a094SJiri Slaby 	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
1428aa27a094SJiri Slaby 		tty_port_tty_hangup(&port->port, true);
1429b5122236SJohan Hovold resubmit:
14300ca1268eSLucy McCoy 	/* Resubmit urb so we continue receiving */
14310ca1268eSLucy McCoy 	err = usb_submit_urb(urb, GFP_ATOMIC);
14320ca1268eSLucy McCoy 	if (err != 0)
1433049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
14340ca1268eSLucy McCoy }
14350ca1268eSLucy McCoy 
usa67_glocont_callback(struct urb * urb)14360ca1268eSLucy McCoy static void usa67_glocont_callback(struct urb *urb)
14370ca1268eSLucy McCoy {
14380ca1268eSLucy McCoy 	struct usb_serial *serial;
14390ca1268eSLucy McCoy 	struct usb_serial_port *port;
14400ca1268eSLucy McCoy 	struct keyspan_port_private *p_priv;
14410ca1268eSLucy McCoy 	int i;
14420ca1268eSLucy McCoy 
14430ca1268eSLucy McCoy 	serial = urb->context;
14440ca1268eSLucy McCoy 	for (i = 0; i < serial->num_ports; ++i) {
14450ca1268eSLucy McCoy 		port = serial->port[i];
14460ca1268eSLucy McCoy 		p_priv = usb_get_serial_port_data(port);
14473018dd3fSJohan Hovold 		if (!p_priv)
14483018dd3fSJohan Hovold 			continue;
14490ca1268eSLucy McCoy 
14500ca1268eSLucy McCoy 		if (p_priv->resend_cont) {
1451049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - sending setup\n", __func__);
14520ca1268eSLucy McCoy 			keyspan_usa67_send_setup(serial, port,
14530ca1268eSLucy McCoy 						p_priv->resend_cont - 1);
14540ca1268eSLucy McCoy 			break;
14550ca1268eSLucy McCoy 		}
14560ca1268eSLucy McCoy 	}
14570ca1268eSLucy McCoy }
14580ca1268eSLucy McCoy 
keyspan_write_room(struct tty_struct * tty)145994cc7aeaSJiri Slaby static unsigned int keyspan_write_room(struct tty_struct *tty)
14601da177e4SLinus Torvalds {
146195da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
14621da177e4SLinus Torvalds 	struct keyspan_port_private	*p_priv;
14631da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
14641da177e4SLinus Torvalds 	int				flip;
146594cc7aeaSJiri Slaby 	unsigned int			data_len;
14661da177e4SLinus Torvalds 	struct urb			*this_urb;
14671da177e4SLinus Torvalds 
14681da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
14691da177e4SLinus Torvalds 	d_details = p_priv->device_details;
14701da177e4SLinus Torvalds 
1471a5b6f60cSAlan Cox 	/* FIXME: locking */
14721da177e4SLinus Torvalds 	if (d_details->msg_format == msg_usa90)
14731da177e4SLinus Torvalds 		data_len = 64;
14741da177e4SLinus Torvalds 	else
14751da177e4SLinus Torvalds 		data_len = 63;
14761da177e4SLinus Torvalds 
14771da177e4SLinus Torvalds 	flip = p_priv->out_flip;
14781da177e4SLinus Torvalds 
14791da177e4SLinus Torvalds 	/* Check both endpoints to see if any are available. */
1480deb91685SAlan Cox 	this_urb = p_priv->out_urbs[flip];
1481deb91685SAlan Cox 	if (this_urb != NULL) {
14821da177e4SLinus Torvalds 		if (this_urb->status != -EINPROGRESS)
1483deb91685SAlan Cox 			return data_len;
14841da177e4SLinus Torvalds 		flip = (flip + 1) & d_details->outdat_endp_flip;
1485deb91685SAlan Cox 		this_urb = p_priv->out_urbs[flip];
1486deb91685SAlan Cox 		if (this_urb != NULL) {
14871da177e4SLinus Torvalds 			if (this_urb->status != -EINPROGRESS)
1488deb91685SAlan Cox 				return data_len;
1489deb91685SAlan Cox 		}
14901da177e4SLinus Torvalds 	}
1491a5b6f60cSAlan Cox 	return 0;
14921da177e4SLinus Torvalds }
14931da177e4SLinus Torvalds 
14941da177e4SLinus Torvalds 
keyspan_open(struct tty_struct * tty,struct usb_serial_port * port)1495a509a7e4SAlan Cox static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
14961da177e4SLinus Torvalds {
14971da177e4SLinus Torvalds 	struct keyspan_port_private 	*p_priv;
14981da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
14991da177e4SLinus Torvalds 	int				i, err;
1500f78ba157SAndrew Morton 	int				baud_rate, device_port;
15011da177e4SLinus Torvalds 	struct urb			*urb;
150295da310eSAlan Cox 	unsigned int			cflag = 0;
15031da177e4SLinus Torvalds 
15041da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
15051da177e4SLinus Torvalds 	d_details = p_priv->device_details;
15061da177e4SLinus Torvalds 
15071da177e4SLinus Torvalds 	/* Set some sane defaults */
15081da177e4SLinus Torvalds 	p_priv->rts_state = 1;
15091da177e4SLinus Torvalds 	p_priv->dtr_state = 1;
15101da177e4SLinus Torvalds 	p_priv->baud = 9600;
15111da177e4SLinus Torvalds 
15121da177e4SLinus Torvalds 	/* force baud and lcr to be set on open */
15131da177e4SLinus Torvalds 	p_priv->old_baud = 0;
15141da177e4SLinus Torvalds 	p_priv->old_cflag = 0;
15151da177e4SLinus Torvalds 
15161da177e4SLinus Torvalds 	p_priv->out_flip = 0;
15171da177e4SLinus Torvalds 	p_priv->in_flip = 0;
15181da177e4SLinus Torvalds 
15191da177e4SLinus Torvalds 	/* Reset low level data toggle and start reading from endpoints */
15201da177e4SLinus Torvalds 	for (i = 0; i < 2; i++) {
1521deb91685SAlan Cox 		urb = p_priv->in_urbs[i];
1522deb91685SAlan Cox 		if (urb == NULL)
15231da177e4SLinus Torvalds 			continue;
15241da177e4SLinus Torvalds 
1525deb91685SAlan Cox 		/* make sure endpoint data toggle is synchronized
1526deb91685SAlan Cox 		   with the device */
15271da177e4SLinus Torvalds 		usb_clear_halt(urb->dev, urb->pipe);
1528deb91685SAlan Cox 		err = usb_submit_urb(urb, GFP_KERNEL);
1529deb91685SAlan Cox 		if (err != 0)
1530049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
15311da177e4SLinus Torvalds 	}
15321da177e4SLinus Torvalds 
15331da177e4SLinus Torvalds 	/* Reset low level data toggle on out endpoints */
15341da177e4SLinus Torvalds 	for (i = 0; i < 2; i++) {
1535deb91685SAlan Cox 		urb = p_priv->out_urbs[i];
1536deb91685SAlan Cox 		if (urb == NULL)
15371da177e4SLinus Torvalds 			continue;
1538deb91685SAlan Cox 		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1539deb91685SAlan Cox 						usb_pipeout(urb->pipe), 0); */
15401da177e4SLinus Torvalds 	}
15411da177e4SLinus Torvalds 
1542f78ba157SAndrew Morton 	/* get the terminal config for the setup message now so we don't
1543f78ba157SAndrew Morton 	 * need to send 2 of them */
1544f78ba157SAndrew Morton 
15451143832eSGreg Kroah-Hartman 	device_port = port->port_number;
154695da310eSAlan Cox 	if (tty) {
1547adc8d746SAlan Cox 		cflag = tty->termios.c_cflag;
1548f78ba157SAndrew Morton 		/* Baud rate calculation takes baud rate as an integer
1549f78ba157SAndrew Morton 		   so other rates can be generated if desired. */
155095da310eSAlan Cox 		baud_rate = tty_get_baud_rate(tty);
1551f78ba157SAndrew Morton 		/* If no match or invalid, leave as default */
1552f78ba157SAndrew Morton 		if (baud_rate >= 0
1553049c6b4eSGreg Kroah-Hartman 		    && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
1554f78ba157SAndrew Morton 					NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1555f78ba157SAndrew Morton 			p_priv->baud = baud_rate;
1556f78ba157SAndrew Morton 		}
155795da310eSAlan Cox 	}
1558f78ba157SAndrew Morton 	/* set CTS/RTS handshake etc. */
1559f78ba157SAndrew Morton 	p_priv->cflag = cflag;
1560f78ba157SAndrew Morton 	p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
1561f78ba157SAndrew Morton 
1562f78ba157SAndrew Morton 	keyspan_send_setup(port, 1);
1563deb91685SAlan Cox 	/* mdelay(100); */
1564deb91685SAlan Cox 	/* keyspan_set_termios(port, NULL); */
1565f78ba157SAndrew Morton 
1566a5b6f60cSAlan Cox 	return 0;
15671da177e4SLinus Torvalds }
15681da177e4SLinus Torvalds 
keyspan_dtr_rts(struct usb_serial_port * port,int on)1569335f8514SAlan Cox static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1570335f8514SAlan Cox {
1571335f8514SAlan Cox 	struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1572335f8514SAlan Cox 
1573335f8514SAlan Cox 	p_priv->rts_state = on;
1574335f8514SAlan Cox 	p_priv->dtr_state = on;
1575335f8514SAlan Cox 	keyspan_send_setup(port, 0);
1576335f8514SAlan Cox }
1577335f8514SAlan Cox 
keyspan_close(struct usb_serial_port * port)1578335f8514SAlan Cox static void keyspan_close(struct usb_serial_port *port)
15791da177e4SLinus Torvalds {
15801da177e4SLinus Torvalds 	int			i;
15811da177e4SLinus Torvalds 	struct keyspan_port_private 	*p_priv;
15821da177e4SLinus Torvalds 
15831da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
15841da177e4SLinus Torvalds 
15851da177e4SLinus Torvalds 	p_priv->rts_state = 0;
15861da177e4SLinus Torvalds 	p_priv->dtr_state = 0;
15871da177e4SLinus Torvalds 
15881da177e4SLinus Torvalds 	keyspan_send_setup(port, 2);
15891da177e4SLinus Torvalds 	/* pilot-xfer seems to work best with this delay */
15901da177e4SLinus Torvalds 	mdelay(100);
15911da177e4SLinus Torvalds 
15921da177e4SLinus Torvalds 	p_priv->out_flip = 0;
15931da177e4SLinus Torvalds 	p_priv->in_flip = 0;
15941da177e4SLinus Torvalds 
159561924505SJohan Hovold 	usb_kill_urb(p_priv->inack_urb);
15961da177e4SLinus Torvalds 	for (i = 0; i < 2; i++) {
159761924505SJohan Hovold 		usb_kill_urb(p_priv->in_urbs[i]);
159861924505SJohan Hovold 		usb_kill_urb(p_priv->out_urbs[i]);
15991da177e4SLinus Torvalds 	}
16001da177e4SLinus Torvalds }
16011da177e4SLinus Torvalds 
16021da177e4SLinus Torvalds /* download the firmware to a pre-renumeration device */
keyspan_fake_startup(struct usb_serial * serial)16031da177e4SLinus Torvalds static int keyspan_fake_startup(struct usb_serial *serial)
16041da177e4SLinus Torvalds {
16051da177e4SLinus Torvalds 	char	*fw_name;
16061da177e4SLinus Torvalds 
1607049c6b4eSGreg Kroah-Hartman 	dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
16081da177e4SLinus Torvalds 		le16_to_cpu(serial->dev->descriptor.bcdDevice),
16091da177e4SLinus Torvalds 		le16_to_cpu(serial->dev->descriptor.idProduct));
16101da177e4SLinus Torvalds 
1611deb91685SAlan Cox 	if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1612deb91685SAlan Cox 								!= 0x8000) {
1613049c6b4eSGreg Kroah-Hartman 		dev_dbg(&serial->dev->dev, "Firmware already loaded.  Quitting.\n");
1614deb91685SAlan Cox 		return 1;
16151da177e4SLinus Torvalds 	}
16161da177e4SLinus Torvalds 
16171da177e4SLinus Torvalds 		/* Select firmware image on the basis of idProduct */
16181da177e4SLinus Torvalds 	switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
16191da177e4SLinus Torvalds 	case keyspan_usa28_pre_product_id:
16202971c579SDavid Woodhouse 		fw_name = "keyspan/usa28.fw";
16211da177e4SLinus Torvalds 		break;
16221da177e4SLinus Torvalds 
16231da177e4SLinus Torvalds 	case keyspan_usa28x_pre_product_id:
16242971c579SDavid Woodhouse 		fw_name = "keyspan/usa28x.fw";
16251da177e4SLinus Torvalds 		break;
16261da177e4SLinus Torvalds 
16271da177e4SLinus Torvalds 	case keyspan_usa28xa_pre_product_id:
16282971c579SDavid Woodhouse 		fw_name = "keyspan/usa28xa.fw";
16291da177e4SLinus Torvalds 		break;
16301da177e4SLinus Torvalds 
16311da177e4SLinus Torvalds 	case keyspan_usa28xb_pre_product_id:
16322971c579SDavid Woodhouse 		fw_name = "keyspan/usa28xb.fw";
16331da177e4SLinus Torvalds 		break;
16341da177e4SLinus Torvalds 
16351da177e4SLinus Torvalds 	case keyspan_usa19_pre_product_id:
16362971c579SDavid Woodhouse 		fw_name = "keyspan/usa19.fw";
16371da177e4SLinus Torvalds 		break;
16381da177e4SLinus Torvalds 
16391da177e4SLinus Torvalds 	case keyspan_usa19qi_pre_product_id:
16402971c579SDavid Woodhouse 		fw_name = "keyspan/usa19qi.fw";
16411da177e4SLinus Torvalds 		break;
16421da177e4SLinus Torvalds 
16431da177e4SLinus Torvalds 	case keyspan_mpr_pre_product_id:
16442971c579SDavid Woodhouse 		fw_name = "keyspan/mpr.fw";
16451da177e4SLinus Torvalds 		break;
16461da177e4SLinus Torvalds 
16471da177e4SLinus Torvalds 	case keyspan_usa19qw_pre_product_id:
16482971c579SDavid Woodhouse 		fw_name = "keyspan/usa19qw.fw";
16491da177e4SLinus Torvalds 		break;
16501da177e4SLinus Torvalds 
16511da177e4SLinus Torvalds 	case keyspan_usa18x_pre_product_id:
16522971c579SDavid Woodhouse 		fw_name = "keyspan/usa18x.fw";
16531da177e4SLinus Torvalds 		break;
16541da177e4SLinus Torvalds 
16551da177e4SLinus Torvalds 	case keyspan_usa19w_pre_product_id:
16562971c579SDavid Woodhouse 		fw_name = "keyspan/usa19w.fw";
16571da177e4SLinus Torvalds 		break;
16581da177e4SLinus Torvalds 
16591da177e4SLinus Torvalds 	case keyspan_usa49w_pre_product_id:
16602971c579SDavid Woodhouse 		fw_name = "keyspan/usa49w.fw";
16611da177e4SLinus Torvalds 		break;
16621da177e4SLinus Torvalds 
16631da177e4SLinus Torvalds 	case keyspan_usa49wlc_pre_product_id:
16642971c579SDavid Woodhouse 		fw_name = "keyspan/usa49wlc.fw";
16651da177e4SLinus Torvalds 		break;
16661da177e4SLinus Torvalds 
16671da177e4SLinus Torvalds 	default:
16682971c579SDavid Woodhouse 		dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
16692971c579SDavid Woodhouse 			le16_to_cpu(serial->dev->descriptor.idProduct));
16702971c579SDavid Woodhouse 		return 1;
16711da177e4SLinus Torvalds 	}
16721da177e4SLinus Torvalds 
1673049c6b4eSGreg Kroah-Hartman 	dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
16741da177e4SLinus Torvalds 
16758d733e26SRene Buergel 	if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
16768d733e26SRene Buergel 		dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
16778d733e26SRene Buergel 			fw_name);
16788d733e26SRene Buergel 		return -ENOENT;
16791da177e4SLinus Torvalds 	}
16801da177e4SLinus Torvalds 
16818d733e26SRene Buergel 	/* after downloading firmware Renumeration will occur in a
16821da177e4SLinus Torvalds 	  moment and the new device will bind to the real driver */
16831da177e4SLinus Torvalds 
16841da177e4SLinus Torvalds 	/* we don't want this device to have a driver assigned to it. */
1685deb91685SAlan Cox 	return 1;
16861da177e4SLinus Torvalds }
16871da177e4SLinus Torvalds 
16881da177e4SLinus Torvalds /* Helper functions used by keyspan_setup_urbs */
find_ep(struct usb_serial const * serial,int endpoint)1689fdcba53eSRainer Weikusat static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1690fdcba53eSRainer Weikusat 						     int endpoint)
1691fdcba53eSRainer Weikusat {
1692fdcba53eSRainer Weikusat 	struct usb_host_interface *iface_desc;
1693fdcba53eSRainer Weikusat 	struct usb_endpoint_descriptor *ep;
1694fdcba53eSRainer Weikusat 	int i;
1695fdcba53eSRainer Weikusat 
1696fdcba53eSRainer Weikusat 	iface_desc = serial->interface->cur_altsetting;
1697fdcba53eSRainer Weikusat 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1698fdcba53eSRainer Weikusat 		ep = &iface_desc->endpoint[i].desc;
1699fdcba53eSRainer Weikusat 		if (ep->bEndpointAddress == endpoint)
1700fdcba53eSRainer Weikusat 			return ep;
1701fdcba53eSRainer Weikusat 	}
17020cd782b0SJohan Hovold 	dev_warn(&serial->interface->dev, "found no endpoint descriptor for endpoint %x\n",
17030cd782b0SJohan Hovold 			endpoint);
1704fdcba53eSRainer Weikusat 	return NULL;
1705fdcba53eSRainer Weikusat }
1706fdcba53eSRainer Weikusat 
keyspan_setup_urb(struct usb_serial * serial,int endpoint,int dir,void * ctx,char * buf,int len,void (* callback)(struct urb *))17071da177e4SLinus Torvalds static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
17081da177e4SLinus Torvalds 				      int dir, void *ctx, char *buf, int len,
17097d12e780SDavid Howells 				      void (*callback)(struct urb *))
17101da177e4SLinus Torvalds {
17111da177e4SLinus Torvalds 	struct urb *urb;
1712fdcba53eSRainer Weikusat 	struct usb_endpoint_descriptor const *ep_desc;
1713fdcba53eSRainer Weikusat 	char const *ep_type_name;
17141da177e4SLinus Torvalds 
17151da177e4SLinus Torvalds 	if (endpoint == -1)
17161da177e4SLinus Torvalds 		return NULL;		/* endpoint not needed */
17171da177e4SLinus Torvalds 
17180cd782b0SJohan Hovold 	dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %x\n",
17190cd782b0SJohan Hovold 			__func__, endpoint);
17201da177e4SLinus Torvalds 	urb = usb_alloc_urb(0, GFP_KERNEL);		/* No ISO */
172110c642d0SJohan Hovold 	if (!urb)
17221da177e4SLinus Torvalds 		return NULL;
17231da177e4SLinus Torvalds 
17240ca1268eSLucy McCoy 	if (endpoint == 0) {
17250ca1268eSLucy McCoy 		/* control EP filled in when used */
17260ca1268eSLucy McCoy 		return urb;
17270ca1268eSLucy McCoy 	}
17280ca1268eSLucy McCoy 
1729fdcba53eSRainer Weikusat 	ep_desc = find_ep(serial, endpoint);
1730fdcba53eSRainer Weikusat 	if (!ep_desc) {
17317d7e21faSJohan Hovold 		usb_free_urb(urb);
17327d7e21faSJohan Hovold 		return NULL;
1733fdcba53eSRainer Weikusat 	}
1734fdcba53eSRainer Weikusat 	if (usb_endpoint_xfer_int(ep_desc)) {
1735fdcba53eSRainer Weikusat 		ep_type_name = "INT";
1736fdcba53eSRainer Weikusat 		usb_fill_int_urb(urb, serial->dev,
1737fdcba53eSRainer Weikusat 				 usb_sndintpipe(serial->dev, endpoint) | dir,
1738fdcba53eSRainer Weikusat 				 buf, len, callback, ctx,
1739fdcba53eSRainer Weikusat 				 ep_desc->bInterval);
1740fdcba53eSRainer Weikusat 	} else if (usb_endpoint_xfer_bulk(ep_desc)) {
1741fdcba53eSRainer Weikusat 		ep_type_name = "BULK";
17421da177e4SLinus Torvalds 		usb_fill_bulk_urb(urb, serial->dev,
17431da177e4SLinus Torvalds 				  usb_sndbulkpipe(serial->dev, endpoint) | dir,
17441da177e4SLinus Torvalds 				  buf, len, callback, ctx);
1745fdcba53eSRainer Weikusat 	} else {
1746fdcba53eSRainer Weikusat 		dev_warn(&serial->interface->dev,
1747fdcba53eSRainer Weikusat 			 "unsupported endpoint type %x\n",
17482e0fe709SJulia Lawall 			 usb_endpoint_type(ep_desc));
1749fdcba53eSRainer Weikusat 		usb_free_urb(urb);
1750fdcba53eSRainer Weikusat 		return NULL;
1751fdcba53eSRainer Weikusat 	}
17521da177e4SLinus Torvalds 
1753049c6b4eSGreg Kroah-Hartman 	dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
1754fdcba53eSRainer Weikusat 	    __func__, urb, ep_type_name, endpoint);
17551da177e4SLinus Torvalds 	return urb;
17561da177e4SLinus Torvalds }
17571da177e4SLinus Torvalds 
17581da177e4SLinus Torvalds static struct callbacks {
17597d12e780SDavid Howells 	void	(*instat_callback)(struct urb *);
17607d12e780SDavid Howells 	void	(*glocont_callback)(struct urb *);
17617d12e780SDavid Howells 	void	(*indat_callback)(struct urb *);
17627d12e780SDavid Howells 	void	(*outdat_callback)(struct urb *);
17637d12e780SDavid Howells 	void	(*inack_callback)(struct urb *);
17647d12e780SDavid Howells 	void	(*outcont_callback)(struct urb *);
17651da177e4SLinus Torvalds } keyspan_callbacks[] = {
17661da177e4SLinus Torvalds 	{
17671da177e4SLinus Torvalds 		/* msg_usa26 callbacks */
17681da177e4SLinus Torvalds 		.instat_callback =	usa26_instat_callback,
17691da177e4SLinus Torvalds 		.glocont_callback =	usa26_glocont_callback,
17701da177e4SLinus Torvalds 		.indat_callback =	usa26_indat_callback,
17711da177e4SLinus Torvalds 		.outdat_callback =	usa2x_outdat_callback,
17721da177e4SLinus Torvalds 		.inack_callback =	usa26_inack_callback,
17731da177e4SLinus Torvalds 		.outcont_callback =	usa26_outcont_callback,
17741da177e4SLinus Torvalds 	}, {
17751da177e4SLinus Torvalds 		/* msg_usa28 callbacks */
17761da177e4SLinus Torvalds 		.instat_callback =	usa28_instat_callback,
17771da177e4SLinus Torvalds 		.glocont_callback =	usa28_glocont_callback,
17781da177e4SLinus Torvalds 		.indat_callback =	usa28_indat_callback,
17791da177e4SLinus Torvalds 		.outdat_callback =	usa2x_outdat_callback,
17801da177e4SLinus Torvalds 		.inack_callback =	usa28_inack_callback,
17811da177e4SLinus Torvalds 		.outcont_callback =	usa28_outcont_callback,
17821da177e4SLinus Torvalds 	}, {
17831da177e4SLinus Torvalds 		/* msg_usa49 callbacks */
17841da177e4SLinus Torvalds 		.instat_callback =	usa49_instat_callback,
17851da177e4SLinus Torvalds 		.glocont_callback =	usa49_glocont_callback,
17861da177e4SLinus Torvalds 		.indat_callback =	usa49_indat_callback,
17871da177e4SLinus Torvalds 		.outdat_callback =	usa2x_outdat_callback,
17881da177e4SLinus Torvalds 		.inack_callback =	usa49_inack_callback,
17891da177e4SLinus Torvalds 		.outcont_callback =	usa49_outcont_callback,
17901da177e4SLinus Torvalds 	}, {
17911da177e4SLinus Torvalds 		/* msg_usa90 callbacks */
17921da177e4SLinus Torvalds 		.instat_callback =	usa90_instat_callback,
17931da177e4SLinus Torvalds 		.glocont_callback =	usa28_glocont_callback,
17941da177e4SLinus Torvalds 		.indat_callback =	usa90_indat_callback,
17951da177e4SLinus Torvalds 		.outdat_callback =	usa2x_outdat_callback,
17961da177e4SLinus Torvalds 		.inack_callback =	usa28_inack_callback,
17971da177e4SLinus Torvalds 		.outcont_callback =	usa90_outcont_callback,
17980ca1268eSLucy McCoy 	}, {
17990ca1268eSLucy McCoy 		/* msg_usa67 callbacks */
18000ca1268eSLucy McCoy 		.instat_callback =	usa67_instat_callback,
18010ca1268eSLucy McCoy 		.glocont_callback =	usa67_glocont_callback,
18020ca1268eSLucy McCoy 		.indat_callback =	usa26_indat_callback,
18030ca1268eSLucy McCoy 		.outdat_callback =	usa2x_outdat_callback,
18040ca1268eSLucy McCoy 		.inack_callback =	usa26_inack_callback,
18050ca1268eSLucy McCoy 		.outcont_callback =	usa26_outcont_callback,
18061da177e4SLinus Torvalds 	}
18071da177e4SLinus Torvalds };
18081da177e4SLinus Torvalds 
18091da177e4SLinus Torvalds 	/* Generic setup urbs function that uses
18101da177e4SLinus Torvalds 	   data in device_details */
keyspan_setup_urbs(struct usb_serial * serial)18111da177e4SLinus Torvalds static void keyspan_setup_urbs(struct usb_serial *serial)
18121da177e4SLinus Torvalds {
18131da177e4SLinus Torvalds 	struct keyspan_serial_private 	*s_priv;
18141da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
18151da177e4SLinus Torvalds 	struct callbacks		*cback;
18161da177e4SLinus Torvalds 
18171da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
18181da177e4SLinus Torvalds 	d_details = s_priv->device_details;
18191da177e4SLinus Torvalds 
18201da177e4SLinus Torvalds 	/* Setup values for the various callback routines */
18211da177e4SLinus Torvalds 	cback = &keyspan_callbacks[d_details->msg_format];
18221da177e4SLinus Torvalds 
18231da177e4SLinus Torvalds 	/* Allocate and set up urbs for each one that is in use,
18241da177e4SLinus Torvalds 	   starting with instat endpoints */
18251da177e4SLinus Torvalds 	s_priv->instat_urb = keyspan_setup_urb
18261da177e4SLinus Torvalds 		(serial, d_details->instat_endpoint, USB_DIR_IN,
18271da177e4SLinus Torvalds 		 serial, s_priv->instat_buf, INSTAT_BUFLEN,
18281da177e4SLinus Torvalds 		 cback->instat_callback);
18291da177e4SLinus Torvalds 
18300ca1268eSLucy McCoy 	s_priv->indat_urb = keyspan_setup_urb
18310ca1268eSLucy McCoy 		(serial, d_details->indat_endpoint, USB_DIR_IN,
18320ca1268eSLucy McCoy 		 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
18330ca1268eSLucy McCoy 		 usa49wg_indat_callback);
18340ca1268eSLucy McCoy 
18351da177e4SLinus Torvalds 	s_priv->glocont_urb = keyspan_setup_urb
18361da177e4SLinus Torvalds 		(serial, d_details->glocont_endpoint, USB_DIR_OUT,
18371da177e4SLinus Torvalds 		 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
18381da177e4SLinus Torvalds 		 cback->glocont_callback);
18391da177e4SLinus Torvalds }
18401da177e4SLinus Torvalds 
18411da177e4SLinus Torvalds /* usa19 function doesn't require prescaler */
keyspan_usa19_calc_baud(struct usb_serial_port * port,u32 baud_rate,u32 baudclk,u8 * rate_hi,u8 * rate_low,u8 * prescaler,int portnum)1842049c6b4eSGreg Kroah-Hartman static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1843049c6b4eSGreg Kroah-Hartman 				   u32 baud_rate, u32 baudclk, u8 *rate_hi,
18441da177e4SLinus Torvalds 				   u8 *rate_low, u8 *prescaler, int portnum)
18451da177e4SLinus Torvalds {
18461da177e4SLinus Torvalds 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
18471da177e4SLinus Torvalds 		div,	/* divisor */
18481da177e4SLinus Torvalds 		cnt;	/* inverse of divisor (programmed into 8051) */
18491da177e4SLinus Torvalds 
1850049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
18511da177e4SLinus Torvalds 
18521da177e4SLinus Torvalds 	/* prevent divide by zero...  */
1853deb91685SAlan Cox 	b16 = baud_rate * 16L;
1854deb91685SAlan Cox 	if (b16 == 0)
1855deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
18561da177e4SLinus Torvalds 	/* Any "standard" rate over 57k6 is marginal on the USA-19
18571da177e4SLinus Torvalds 	   as we run out of divisor resolution. */
1858deb91685SAlan Cox 	if (baud_rate > 57600)
1859deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
18601da177e4SLinus Torvalds 
18611da177e4SLinus Torvalds 	/* calculate the divisor and the counter (its inverse) */
1862deb91685SAlan Cox 	div = baudclk / b16;
1863deb91685SAlan Cox 	if (div == 0)
1864deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
1865deb91685SAlan Cox 	else
18661da177e4SLinus Torvalds 		cnt = 0 - div;
18671da177e4SLinus Torvalds 
1868deb91685SAlan Cox 	if (div > 0xffff)
1869deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
18701da177e4SLinus Torvalds 
18711da177e4SLinus Torvalds 	/* return the counter values if non-null */
1872deb91685SAlan Cox 	if (rate_low)
18731da177e4SLinus Torvalds 		*rate_low = (u8) (cnt & 0xff);
1874deb91685SAlan Cox 	if (rate_hi)
18751da177e4SLinus Torvalds 		*rate_hi = (u8) ((cnt >> 8) & 0xff);
1876deb91685SAlan Cox 	if (rate_low && rate_hi)
1877049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
1878deb91685SAlan Cox 				__func__, baud_rate, *rate_hi, *rate_low);
1879deb91685SAlan Cox 	return KEYSPAN_BAUD_RATE_OK;
18801da177e4SLinus Torvalds }
18811da177e4SLinus Torvalds 
18821da177e4SLinus Torvalds /* usa19hs function doesn't require prescaler */
keyspan_usa19hs_calc_baud(struct usb_serial_port * port,u32 baud_rate,u32 baudclk,u8 * rate_hi,u8 * rate_low,u8 * prescaler,int portnum)1883049c6b4eSGreg Kroah-Hartman static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1884049c6b4eSGreg Kroah-Hartman 				     u32 baud_rate, u32 baudclk, u8 *rate_hi,
18851da177e4SLinus Torvalds 				     u8 *rate_low, u8 *prescaler, int portnum)
18861da177e4SLinus Torvalds {
18871da177e4SLinus Torvalds 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
18881da177e4SLinus Torvalds 			div;	/* divisor */
18891da177e4SLinus Torvalds 
1890049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
18911da177e4SLinus Torvalds 
18921da177e4SLinus Torvalds 	/* prevent divide by zero...  */
1893deb91685SAlan Cox 	b16 = baud_rate * 16L;
1894deb91685SAlan Cox 	if (b16 == 0)
1895deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
18961da177e4SLinus Torvalds 
18971da177e4SLinus Torvalds 	/* calculate the divisor */
1898deb91685SAlan Cox 	div = baudclk / b16;
1899deb91685SAlan Cox 	if (div == 0)
1900deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
19011da177e4SLinus Torvalds 
19021da177e4SLinus Torvalds 	if (div > 0xffff)
1903deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
19041da177e4SLinus Torvalds 
19051da177e4SLinus Torvalds 	/* return the counter values if non-null */
19061da177e4SLinus Torvalds 	if (rate_low)
19071da177e4SLinus Torvalds 		*rate_low = (u8) (div & 0xff);
19081da177e4SLinus Torvalds 
19091da177e4SLinus Torvalds 	if (rate_hi)
19101da177e4SLinus Torvalds 		*rate_hi = (u8) ((div >> 8) & 0xff);
19111da177e4SLinus Torvalds 
19121da177e4SLinus Torvalds 	if (rate_low && rate_hi)
1913049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
1914deb91685SAlan Cox 			__func__, baud_rate, *rate_hi, *rate_low);
19151da177e4SLinus Torvalds 
1916deb91685SAlan Cox 	return KEYSPAN_BAUD_RATE_OK;
19171da177e4SLinus Torvalds }
19181da177e4SLinus Torvalds 
keyspan_usa19w_calc_baud(struct usb_serial_port * port,u32 baud_rate,u32 baudclk,u8 * rate_hi,u8 * rate_low,u8 * prescaler,int portnum)1919049c6b4eSGreg Kroah-Hartman static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1920049c6b4eSGreg Kroah-Hartman 				    u32 baud_rate, u32 baudclk, u8 *rate_hi,
19211da177e4SLinus Torvalds 				    u8 *rate_low, u8 *prescaler, int portnum)
19221da177e4SLinus Torvalds {
19231da177e4SLinus Torvalds 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
19241da177e4SLinus Torvalds 		clk,	/* clock with 13/8 prescaler */
19251da177e4SLinus Torvalds 		div,	/* divisor using 13/8 prescaler */
19261da177e4SLinus Torvalds 		res,	/* resulting baud rate using 13/8 prescaler */
19271da177e4SLinus Torvalds 		diff,	/* error using 13/8 prescaler */
19281da177e4SLinus Torvalds 		smallest_diff;
19291da177e4SLinus Torvalds 	u8	best_prescaler;
19301da177e4SLinus Torvalds 	int	i;
19311da177e4SLinus Torvalds 
1932049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
19331da177e4SLinus Torvalds 
19341da177e4SLinus Torvalds 	/* prevent divide by zero */
1935deb91685SAlan Cox 	b16 = baud_rate * 16L;
1936deb91685SAlan Cox 	if (b16 == 0)
1937deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
19381da177e4SLinus Torvalds 
19391da177e4SLinus Torvalds 	/* Calculate prescaler by trying them all and looking
19401da177e4SLinus Torvalds 	   for best fit */
19411da177e4SLinus Torvalds 
19421da177e4SLinus Torvalds 	/* start with largest possible difference */
19431da177e4SLinus Torvalds 	smallest_diff = 0xffffffff;
19441da177e4SLinus Torvalds 
19451da177e4SLinus Torvalds 		/* 0 is an invalid prescaler, used as a flag */
19461da177e4SLinus Torvalds 	best_prescaler = 0;
19471da177e4SLinus Torvalds 
19481da177e4SLinus Torvalds 	for (i = 8; i <= 0xff; ++i) {
19491da177e4SLinus Torvalds 		clk = (baudclk * 8) / (u32) i;
19501da177e4SLinus Torvalds 
1951deb91685SAlan Cox 		div = clk / b16;
1952deb91685SAlan Cox 		if (div == 0)
19531da177e4SLinus Torvalds 			continue;
19541da177e4SLinus Torvalds 
19551da177e4SLinus Torvalds 		res = clk / div;
19561da177e4SLinus Torvalds 		diff = (res > b16) ? (res-b16) : (b16-res);
19571da177e4SLinus Torvalds 
19581da177e4SLinus Torvalds 		if (diff < smallest_diff) {
19591da177e4SLinus Torvalds 			best_prescaler = i;
19601da177e4SLinus Torvalds 			smallest_diff = diff;
19611da177e4SLinus Torvalds 		}
19621da177e4SLinus Torvalds 	}
19631da177e4SLinus Torvalds 
1964deb91685SAlan Cox 	if (best_prescaler == 0)
1965deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
19661da177e4SLinus Torvalds 
19671da177e4SLinus Torvalds 	clk = (baudclk * 8) / (u32) best_prescaler;
19681da177e4SLinus Torvalds 	div = clk / b16;
19691da177e4SLinus Torvalds 
19701da177e4SLinus Torvalds 	/* return the divisor and prescaler if non-null */
1971deb91685SAlan Cox 	if (rate_low)
19721da177e4SLinus Torvalds 		*rate_low = (u8) (div & 0xff);
1973deb91685SAlan Cox 	if (rate_hi)
19741da177e4SLinus Torvalds 		*rate_hi = (u8) ((div >> 8) & 0xff);
19751da177e4SLinus Torvalds 	if (prescaler) {
19761da177e4SLinus Torvalds 		*prescaler = best_prescaler;
1977049c6b4eSGreg Kroah-Hartman 		/*  dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
19781da177e4SLinus Torvalds 	}
1979deb91685SAlan Cox 	return KEYSPAN_BAUD_RATE_OK;
19801da177e4SLinus Torvalds }
19811da177e4SLinus Torvalds 
19821da177e4SLinus Torvalds 	/* USA-28 supports different maximum baud rates on each port */
keyspan_usa28_calc_baud(struct usb_serial_port * port,u32 baud_rate,u32 baudclk,u8 * rate_hi,u8 * rate_low,u8 * prescaler,int portnum)1983049c6b4eSGreg Kroah-Hartman static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1984049c6b4eSGreg Kroah-Hartman 				   u32 baud_rate, u32 baudclk, u8 *rate_hi,
19851da177e4SLinus Torvalds 				   u8 *rate_low, u8 *prescaler, int portnum)
19861da177e4SLinus Torvalds {
19871da177e4SLinus Torvalds 	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
19881da177e4SLinus Torvalds 		div,	/* divisor */
19891da177e4SLinus Torvalds 		cnt;	/* inverse of divisor (programmed into 8051) */
19901da177e4SLinus Torvalds 
1991049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
19921da177e4SLinus Torvalds 
19931da177e4SLinus Torvalds 		/* prevent divide by zero */
1994deb91685SAlan Cox 	b16 = baud_rate * 16L;
1995deb91685SAlan Cox 	if (b16 == 0)
1996deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
19971da177e4SLinus Torvalds 
19981da177e4SLinus Torvalds 	/* calculate the divisor and the counter (its inverse) */
1999deb91685SAlan Cox 	div = KEYSPAN_USA28_BAUDCLK / b16;
2000deb91685SAlan Cox 	if (div == 0)
2001deb91685SAlan Cox 		return KEYSPAN_INVALID_BAUD_RATE;
2002deb91685SAlan Cox 	else
20031da177e4SLinus Torvalds 		cnt = 0 - div;
20041da177e4SLinus Torvalds 
20051da177e4SLinus Torvalds 	/* check for out of range, based on portnum,
20061da177e4SLinus Torvalds 	   and return result */
20071da177e4SLinus Torvalds 	if (portnum == 0) {
20081da177e4SLinus Torvalds 		if (div > 0xffff)
2009deb91685SAlan Cox 			return KEYSPAN_INVALID_BAUD_RATE;
2010deb91685SAlan Cox 	} else {
20111da177e4SLinus Torvalds 		if (portnum == 1) {
2012deb91685SAlan Cox 			if (div > 0xff)
2013deb91685SAlan Cox 				return KEYSPAN_INVALID_BAUD_RATE;
2014deb91685SAlan Cox 		} else
2015deb91685SAlan Cox 			return KEYSPAN_INVALID_BAUD_RATE;
20161da177e4SLinus Torvalds 	}
20171da177e4SLinus Torvalds 
20181da177e4SLinus Torvalds 		/* return the counter values if not NULL
20191da177e4SLinus Torvalds 		   (port 1 will ignore retHi) */
2020deb91685SAlan Cox 	if (rate_low)
20211da177e4SLinus Torvalds 		*rate_low = (u8) (cnt & 0xff);
2022deb91685SAlan Cox 	if (rate_hi)
20231da177e4SLinus Torvalds 		*rate_hi = (u8) ((cnt >> 8) & 0xff);
2024049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
2025deb91685SAlan Cox 	return KEYSPAN_BAUD_RATE_OK;
20261da177e4SLinus Torvalds }
20271da177e4SLinus Torvalds 
keyspan_usa26_send_setup(struct usb_serial * serial,struct usb_serial_port * port,int reset_port)20281da177e4SLinus Torvalds static int keyspan_usa26_send_setup(struct usb_serial *serial,
20291da177e4SLinus Torvalds 				    struct usb_serial_port *port,
20301da177e4SLinus Torvalds 				    int reset_port)
20311da177e4SLinus Torvalds {
20321da177e4SLinus Torvalds 	struct keyspan_usa26_portControlMessage	msg;
20331da177e4SLinus Torvalds 	struct keyspan_serial_private 		*s_priv;
20341da177e4SLinus Torvalds 	struct keyspan_port_private 		*p_priv;
20351da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
20361da177e4SLinus Torvalds 	struct urb				*this_urb;
20371da177e4SLinus Torvalds 	int 					device_port, err;
20381da177e4SLinus Torvalds 
2039049c6b4eSGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
20401da177e4SLinus Torvalds 
20411da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
20421da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
20431da177e4SLinus Torvalds 	d_details = s_priv->device_details;
20441143832eSGreg Kroah-Hartman 	device_port = port->port_number;
20451da177e4SLinus Torvalds 
20461da177e4SLinus Torvalds 	this_urb = p_priv->outcont_urb;
20471da177e4SLinus Torvalds 
20481da177e4SLinus Torvalds 		/* Make sure we have an urb then send the message */
20491da177e4SLinus Torvalds 	if (this_urb == NULL) {
2050049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
20511da177e4SLinus Torvalds 		return -1;
20521da177e4SLinus Torvalds 	}
20531da177e4SLinus Torvalds 
20540cd782b0SJohan Hovold 	dev_dbg(&port->dev, "%s - endpoint %x\n",
20550cd782b0SJohan Hovold 			__func__, usb_pipeendpoint(this_urb->pipe));
2056d5afce82SRickard Strandqvist 
20571da177e4SLinus Torvalds 	/* Save reset port val for resend.
20580ca1268eSLucy McCoy 	   Don't overwrite resend for open/close condition. */
20590ca1268eSLucy McCoy 	if ((reset_port + 1) > p_priv->resend_cont)
20601da177e4SLinus Torvalds 		p_priv->resend_cont = reset_port + 1;
20611da177e4SLinus Torvalds 	if (this_urb->status == -EINPROGRESS) {
2062049c6b4eSGreg Kroah-Hartman 		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
20631da177e4SLinus Torvalds 		mdelay(5);
2064deb91685SAlan Cox 		return -1;
20651da177e4SLinus Torvalds 	}
20661da177e4SLinus Torvalds 
20671da177e4SLinus Torvalds 	memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
20681da177e4SLinus Torvalds 
20691da177e4SLinus Torvalds 	/* Only set baud rate if it's changed */
20701da177e4SLinus Torvalds 	if (p_priv->old_baud != p_priv->baud) {
20711da177e4SLinus Torvalds 		p_priv->old_baud = p_priv->baud;
20721da177e4SLinus Torvalds 		msg.setClocking = 0xff;
2073049c6b4eSGreg Kroah-Hartman 		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2074049c6b4eSGreg Kroah-Hartman 						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
2075049c6b4eSGreg Kroah-Hartman 						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2076049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2077deb91685SAlan Cox 				__func__, p_priv->baud);
20781da177e4SLinus Torvalds 			msg.baudLo = 0;
20791da177e4SLinus Torvalds 			msg.baudHi = 125;	/* Values for 9600 baud */
20801da177e4SLinus Torvalds 			msg.prescaler = 10;
20811da177e4SLinus Torvalds 		}
20821da177e4SLinus Torvalds 		msg.setPrescaler = 0xff;
20831da177e4SLinus Torvalds 	}
20841da177e4SLinus Torvalds 
20851da177e4SLinus Torvalds 	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
20861da177e4SLinus Torvalds 	switch (p_priv->cflag & CSIZE) {
20871da177e4SLinus Torvalds 	case CS5:
20881da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_5;
20891da177e4SLinus Torvalds 		break;
20901da177e4SLinus Torvalds 	case CS6:
20911da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_6;
20921da177e4SLinus Torvalds 		break;
20931da177e4SLinus Torvalds 	case CS7:
20941da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_7;
20951da177e4SLinus Torvalds 		break;
20961da177e4SLinus Torvalds 	case CS8:
20971da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_8;
20981da177e4SLinus Torvalds 		break;
20991da177e4SLinus Torvalds 	}
21001da177e4SLinus Torvalds 	if (p_priv->cflag & PARENB) {
21011da177e4SLinus Torvalds 		/* note USA_PARITY_NONE == 0 */
21021da177e4SLinus Torvalds 		msg.lcr |= (p_priv->cflag & PARODD) ?
21031da177e4SLinus Torvalds 			USA_PARITY_ODD : USA_PARITY_EVEN;
21041da177e4SLinus Torvalds 	}
21051da177e4SLinus Torvalds 	msg.setLcr = 0xff;
21061da177e4SLinus Torvalds 
21071da177e4SLinus Torvalds 	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
21081da177e4SLinus Torvalds 	msg.xonFlowControl = 0;
21091da177e4SLinus Torvalds 	msg.setFlowControl = 0xff;
21101da177e4SLinus Torvalds 	msg.forwardingLength = 16;
21111da177e4SLinus Torvalds 	msg.xonChar = 17;
21121da177e4SLinus Torvalds 	msg.xoffChar = 19;
21131da177e4SLinus Torvalds 
21141da177e4SLinus Torvalds 	/* Opening port */
21151da177e4SLinus Torvalds 	if (reset_port == 1) {
21161da177e4SLinus Torvalds 		msg._txOn = 1;
21171da177e4SLinus Torvalds 		msg._txOff = 0;
21181da177e4SLinus Torvalds 		msg.txFlush = 0;
21191da177e4SLinus Torvalds 		msg.txBreak = 0;
21201da177e4SLinus Torvalds 		msg.rxOn = 1;
21211da177e4SLinus Torvalds 		msg.rxOff = 0;
21221da177e4SLinus Torvalds 		msg.rxFlush = 1;
21231da177e4SLinus Torvalds 		msg.rxForward = 0;
21241da177e4SLinus Torvalds 		msg.returnStatus = 0;
21251da177e4SLinus Torvalds 		msg.resetDataToggle = 0xff;
21261da177e4SLinus Torvalds 	}
21271da177e4SLinus Torvalds 
21281da177e4SLinus Torvalds 	/* Closing port */
21291da177e4SLinus Torvalds 	else if (reset_port == 2) {
21301da177e4SLinus Torvalds 		msg._txOn = 0;
21311da177e4SLinus Torvalds 		msg._txOff = 1;
21321da177e4SLinus Torvalds 		msg.txFlush = 0;
21331da177e4SLinus Torvalds 		msg.txBreak = 0;
21341da177e4SLinus Torvalds 		msg.rxOn = 0;
21351da177e4SLinus Torvalds 		msg.rxOff = 1;
21361da177e4SLinus Torvalds 		msg.rxFlush = 1;
21371da177e4SLinus Torvalds 		msg.rxForward = 0;
21381da177e4SLinus Torvalds 		msg.returnStatus = 0;
21391da177e4SLinus Torvalds 		msg.resetDataToggle = 0;
21401da177e4SLinus Torvalds 	}
21411da177e4SLinus Torvalds 
21421da177e4SLinus Torvalds 	/* Sending intermediate configs */
21431da177e4SLinus Torvalds 	else {
21441da177e4SLinus Torvalds 		msg._txOn = (!p_priv->break_on);
21451da177e4SLinus Torvalds 		msg._txOff = 0;
21461da177e4SLinus Torvalds 		msg.txFlush = 0;
21471da177e4SLinus Torvalds 		msg.txBreak = (p_priv->break_on);
21481da177e4SLinus Torvalds 		msg.rxOn = 0;
21491da177e4SLinus Torvalds 		msg.rxOff = 0;
21501da177e4SLinus Torvalds 		msg.rxFlush = 0;
21511da177e4SLinus Torvalds 		msg.rxForward = 0;
21521da177e4SLinus Torvalds 		msg.returnStatus = 0;
21531da177e4SLinus Torvalds 		msg.resetDataToggle = 0x0;
21541da177e4SLinus Torvalds 	}
21551da177e4SLinus Torvalds 
21561da177e4SLinus Torvalds 	/* Do handshaking outputs */
21571da177e4SLinus Torvalds 	msg.setTxTriState_setRts = 0xff;
21581da177e4SLinus Torvalds 	msg.txTriState_rts = p_priv->rts_state;
21591da177e4SLinus Torvalds 
21601da177e4SLinus Torvalds 	msg.setHskoa_setDtr = 0xff;
21611da177e4SLinus Torvalds 	msg.hskoa_dtr = p_priv->dtr_state;
21621da177e4SLinus Torvalds 
21631da177e4SLinus Torvalds 	p_priv->resend_cont = 0;
21641da177e4SLinus Torvalds 	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
21651da177e4SLinus Torvalds 
21661da177e4SLinus Torvalds 	/* send the data out the device on control endpoint */
21671da177e4SLinus Torvalds 	this_urb->transfer_buffer_length = sizeof(msg);
21681da177e4SLinus Torvalds 
2169deb91685SAlan Cox 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
2170deb91685SAlan Cox 	if (err != 0)
2171049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
2172a5b6f60cSAlan Cox 	return 0;
21731da177e4SLinus Torvalds }
21741da177e4SLinus Torvalds 
keyspan_usa28_send_setup(struct usb_serial * serial,struct usb_serial_port * port,int reset_port)21751da177e4SLinus Torvalds static int keyspan_usa28_send_setup(struct usb_serial *serial,
21761da177e4SLinus Torvalds 				    struct usb_serial_port *port,
21771da177e4SLinus Torvalds 				    int reset_port)
21781da177e4SLinus Torvalds {
21791da177e4SLinus Torvalds 	struct keyspan_usa28_portControlMessage	msg;
21801da177e4SLinus Torvalds 	struct keyspan_serial_private	 	*s_priv;
21811da177e4SLinus Torvalds 	struct keyspan_port_private 		*p_priv;
21821da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
21831da177e4SLinus Torvalds 	struct urb				*this_urb;
21841da177e4SLinus Torvalds 	int 					device_port, err;
21851da177e4SLinus Torvalds 
21861da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
21871da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
21881da177e4SLinus Torvalds 	d_details = s_priv->device_details;
21891143832eSGreg Kroah-Hartman 	device_port = port->port_number;
21901da177e4SLinus Torvalds 
21911da177e4SLinus Torvalds 	/* only do something if we have a bulk out endpoint */
2192deb91685SAlan Cox 	this_urb = p_priv->outcont_urb;
2193deb91685SAlan Cox 	if (this_urb == NULL) {
2194049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
21951da177e4SLinus Torvalds 		return -1;
21961da177e4SLinus Torvalds 	}
21971da177e4SLinus Torvalds 
21981da177e4SLinus Torvalds 	/* Save reset port val for resend.
21990ca1268eSLucy McCoy 	   Don't overwrite resend for open/close condition. */
22000ca1268eSLucy McCoy 	if ((reset_port + 1) > p_priv->resend_cont)
22011da177e4SLinus Torvalds 		p_priv->resend_cont = reset_port + 1;
22021da177e4SLinus Torvalds 	if (this_urb->status == -EINPROGRESS) {
2203049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s already writing\n", __func__);
22041da177e4SLinus Torvalds 		mdelay(5);
2205deb91685SAlan Cox 		return -1;
22061da177e4SLinus Torvalds 	}
22071da177e4SLinus Torvalds 
22081da177e4SLinus Torvalds 	memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
22091da177e4SLinus Torvalds 
22101da177e4SLinus Torvalds 	msg.setBaudRate = 1;
2211049c6b4eSGreg Kroah-Hartman 	if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2212049c6b4eSGreg Kroah-Hartman 					   &msg.baudHi, &msg.baudLo, NULL,
2213049c6b4eSGreg Kroah-Hartman 					   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2214049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
2215deb91685SAlan Cox 						__func__, p_priv->baud);
22161da177e4SLinus Torvalds 		msg.baudLo = 0xff;
22171da177e4SLinus Torvalds 		msg.baudHi = 0xb2;	/* Values for 9600 baud */
22181da177e4SLinus Torvalds 	}
22191da177e4SLinus Torvalds 
22201da177e4SLinus Torvalds 	/* If parity is enabled, we must calculate it ourselves. */
22211da177e4SLinus Torvalds 	msg.parity = 0;		/* XXX for now */
22221da177e4SLinus Torvalds 
22231da177e4SLinus Torvalds 	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
22241da177e4SLinus Torvalds 	msg.xonFlowControl = 0;
22251da177e4SLinus Torvalds 
22261da177e4SLinus Torvalds 	/* Do handshaking outputs, DTR is inverted relative to RTS */
22271da177e4SLinus Torvalds 	msg.rts = p_priv->rts_state;
22281da177e4SLinus Torvalds 	msg.dtr = p_priv->dtr_state;
22291da177e4SLinus Torvalds 
22301da177e4SLinus Torvalds 	msg.forwardingLength = 16;
22311da177e4SLinus Torvalds 	msg.forwardMs = 10;
22321da177e4SLinus Torvalds 	msg.breakThreshold = 45;
22331da177e4SLinus Torvalds 	msg.xonChar = 17;
22341da177e4SLinus Torvalds 	msg.xoffChar = 19;
22351da177e4SLinus Torvalds 
22361da177e4SLinus Torvalds 	/*msg.returnStatus = 1;
22371da177e4SLinus Torvalds 	msg.resetDataToggle = 0xff;*/
22381da177e4SLinus Torvalds 	/* Opening port */
22391da177e4SLinus Torvalds 	if (reset_port == 1) {
22401da177e4SLinus Torvalds 		msg._txOn = 1;
22411da177e4SLinus Torvalds 		msg._txOff = 0;
22421da177e4SLinus Torvalds 		msg.txFlush = 0;
22431da177e4SLinus Torvalds 		msg.txForceXoff = 0;
22441da177e4SLinus Torvalds 		msg.txBreak = 0;
22451da177e4SLinus Torvalds 		msg.rxOn = 1;
22461da177e4SLinus Torvalds 		msg.rxOff = 0;
22471da177e4SLinus Torvalds 		msg.rxFlush = 1;
22481da177e4SLinus Torvalds 		msg.rxForward = 0;
22491da177e4SLinus Torvalds 		msg.returnStatus = 0;
22501da177e4SLinus Torvalds 		msg.resetDataToggle = 0xff;
22511da177e4SLinus Torvalds 	}
22521da177e4SLinus Torvalds 	/* Closing port */
22531da177e4SLinus Torvalds 	else if (reset_port == 2) {
22541da177e4SLinus Torvalds 		msg._txOn = 0;
22551da177e4SLinus Torvalds 		msg._txOff = 1;
22561da177e4SLinus Torvalds 		msg.txFlush = 0;
22571da177e4SLinus Torvalds 		msg.txForceXoff = 0;
22581da177e4SLinus Torvalds 		msg.txBreak = 0;
22591da177e4SLinus Torvalds 		msg.rxOn = 0;
22601da177e4SLinus Torvalds 		msg.rxOff = 1;
22611da177e4SLinus Torvalds 		msg.rxFlush = 1;
22621da177e4SLinus Torvalds 		msg.rxForward = 0;
22631da177e4SLinus Torvalds 		msg.returnStatus = 0;
22641da177e4SLinus Torvalds 		msg.resetDataToggle = 0;
22651da177e4SLinus Torvalds 	}
22661da177e4SLinus Torvalds 	/* Sending intermediate configs */
22671da177e4SLinus Torvalds 	else {
22681da177e4SLinus Torvalds 		msg._txOn = (!p_priv->break_on);
22691da177e4SLinus Torvalds 		msg._txOff = 0;
22701da177e4SLinus Torvalds 		msg.txFlush = 0;
22711da177e4SLinus Torvalds 		msg.txForceXoff = 0;
22721da177e4SLinus Torvalds 		msg.txBreak = (p_priv->break_on);
22731da177e4SLinus Torvalds 		msg.rxOn = 0;
22741da177e4SLinus Torvalds 		msg.rxOff = 0;
22751da177e4SLinus Torvalds 		msg.rxFlush = 0;
22761da177e4SLinus Torvalds 		msg.rxForward = 0;
22771da177e4SLinus Torvalds 		msg.returnStatus = 0;
22781da177e4SLinus Torvalds 		msg.resetDataToggle = 0x0;
22791da177e4SLinus Torvalds 	}
22801da177e4SLinus Torvalds 
22811da177e4SLinus Torvalds 	p_priv->resend_cont = 0;
22821da177e4SLinus Torvalds 	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
22831da177e4SLinus Torvalds 
22841da177e4SLinus Torvalds 	/* send the data out the device on control endpoint */
22851da177e4SLinus Torvalds 	this_urb->transfer_buffer_length = sizeof(msg);
22861da177e4SLinus Torvalds 
2287deb91685SAlan Cox 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
2288deb91685SAlan Cox 	if (err != 0)
2289049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
22901da177e4SLinus Torvalds 
2291a5b6f60cSAlan Cox 	return 0;
22921da177e4SLinus Torvalds }
22931da177e4SLinus Torvalds 
keyspan_usa49_send_setup(struct usb_serial * serial,struct usb_serial_port * port,int reset_port)22941da177e4SLinus Torvalds static int keyspan_usa49_send_setup(struct usb_serial *serial,
22951da177e4SLinus Torvalds 				    struct usb_serial_port *port,
22961da177e4SLinus Torvalds 				    int reset_port)
22971da177e4SLinus Torvalds {
22981da177e4SLinus Torvalds 	struct keyspan_usa49_portControlMessage	msg;
22990ca1268eSLucy McCoy 	struct usb_ctrlrequest 			*dr = NULL;
23001da177e4SLinus Torvalds 	struct keyspan_serial_private 		*s_priv;
23011da177e4SLinus Torvalds 	struct keyspan_port_private 		*p_priv;
23021da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
23031da177e4SLinus Torvalds 	struct urb				*this_urb;
23041da177e4SLinus Torvalds 	int 					err, device_port;
23051da177e4SLinus Torvalds 
23061da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
23071da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
23081da177e4SLinus Torvalds 	d_details = s_priv->device_details;
23091da177e4SLinus Torvalds 
23101da177e4SLinus Torvalds 	this_urb = s_priv->glocont_urb;
23111da177e4SLinus Torvalds 
23121da177e4SLinus Torvalds 	/* Work out which port within the device is being setup */
23131143832eSGreg Kroah-Hartman 	device_port = port->port_number;
23141da177e4SLinus Torvalds 
23151da177e4SLinus Torvalds 	/* Make sure we have an urb then send the message */
23161da177e4SLinus Torvalds 	if (this_urb == NULL) {
23171143832eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
23181da177e4SLinus Torvalds 		return -1;
23191da177e4SLinus Torvalds 	}
23201da177e4SLinus Torvalds 
23210cd782b0SJohan Hovold 	dev_dbg(&port->dev, "%s - endpoint %x (%d)\n",
23221143832eSGreg Kroah-Hartman 		__func__, usb_pipeendpoint(this_urb->pipe), device_port);
2323d866150aSHuzaifa Sidhpurwala 
23241da177e4SLinus Torvalds 	/* Save reset port val for resend.
23250ca1268eSLucy McCoy 	   Don't overwrite resend for open/close condition. */
23260ca1268eSLucy McCoy 	if ((reset_port + 1) > p_priv->resend_cont)
23271da177e4SLinus Torvalds 		p_priv->resend_cont = reset_port + 1;
23280ca1268eSLucy McCoy 
23291da177e4SLinus Torvalds 	if (this_urb->status == -EINPROGRESS) {
2330049c6b4eSGreg Kroah-Hartman 		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
23311da177e4SLinus Torvalds 		mdelay(5);
2332deb91685SAlan Cox 		return -1;
23331da177e4SLinus Torvalds 	}
23341da177e4SLinus Torvalds 
23351da177e4SLinus Torvalds 	memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
23361da177e4SLinus Torvalds 
23371da177e4SLinus Torvalds 	msg.portNumber = device_port;
23381da177e4SLinus Torvalds 
23391da177e4SLinus Torvalds 	/* Only set baud rate if it's changed */
23401da177e4SLinus Torvalds 	if (p_priv->old_baud != p_priv->baud) {
23411da177e4SLinus Torvalds 		p_priv->old_baud = p_priv->baud;
23421da177e4SLinus Torvalds 		msg.setClocking = 0xff;
2343049c6b4eSGreg Kroah-Hartman 		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2344049c6b4eSGreg Kroah-Hartman 						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
2345049c6b4eSGreg Kroah-Hartman 						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2346049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2347deb91685SAlan Cox 				__func__, p_priv->baud);
23481da177e4SLinus Torvalds 			msg.baudLo = 0;
23491da177e4SLinus Torvalds 			msg.baudHi = 125;	/* Values for 9600 baud */
23501da177e4SLinus Torvalds 			msg.prescaler = 10;
23511da177e4SLinus Torvalds 		}
2352deb91685SAlan Cox 		/* msg.setPrescaler = 0xff; */
23531da177e4SLinus Torvalds 	}
23541da177e4SLinus Torvalds 
23551da177e4SLinus Torvalds 	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
23561da177e4SLinus Torvalds 	switch (p_priv->cflag & CSIZE) {
23571da177e4SLinus Torvalds 	case CS5:
23581da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_5;
23591da177e4SLinus Torvalds 		break;
23601da177e4SLinus Torvalds 	case CS6:
23611da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_6;
23621da177e4SLinus Torvalds 		break;
23631da177e4SLinus Torvalds 	case CS7:
23641da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_7;
23651da177e4SLinus Torvalds 		break;
23661da177e4SLinus Torvalds 	case CS8:
23671da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_8;
23681da177e4SLinus Torvalds 		break;
23691da177e4SLinus Torvalds 	}
23701da177e4SLinus Torvalds 	if (p_priv->cflag & PARENB) {
23711da177e4SLinus Torvalds 		/* note USA_PARITY_NONE == 0 */
23721da177e4SLinus Torvalds 		msg.lcr |= (p_priv->cflag & PARODD) ?
23731da177e4SLinus Torvalds 			USA_PARITY_ODD : USA_PARITY_EVEN;
23741da177e4SLinus Torvalds 	}
23751da177e4SLinus Torvalds 	msg.setLcr = 0xff;
23761da177e4SLinus Torvalds 
23771da177e4SLinus Torvalds 	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
23781da177e4SLinus Torvalds 	msg.xonFlowControl = 0;
23791da177e4SLinus Torvalds 	msg.setFlowControl = 0xff;
23801da177e4SLinus Torvalds 
23811da177e4SLinus Torvalds 	msg.forwardingLength = 16;
23821da177e4SLinus Torvalds 	msg.xonChar = 17;
23831da177e4SLinus Torvalds 	msg.xoffChar = 19;
23841da177e4SLinus Torvalds 
23851da177e4SLinus Torvalds 	/* Opening port */
23861da177e4SLinus Torvalds 	if (reset_port == 1) {
23871da177e4SLinus Torvalds 		msg._txOn = 1;
23881da177e4SLinus Torvalds 		msg._txOff = 0;
23891da177e4SLinus Torvalds 		msg.txFlush = 0;
23901da177e4SLinus Torvalds 		msg.txBreak = 0;
23911da177e4SLinus Torvalds 		msg.rxOn = 1;
23921da177e4SLinus Torvalds 		msg.rxOff = 0;
23931da177e4SLinus Torvalds 		msg.rxFlush = 1;
23941da177e4SLinus Torvalds 		msg.rxForward = 0;
23951da177e4SLinus Torvalds 		msg.returnStatus = 0;
23961da177e4SLinus Torvalds 		msg.resetDataToggle = 0xff;
23971da177e4SLinus Torvalds 		msg.enablePort = 1;
23981da177e4SLinus Torvalds 		msg.disablePort = 0;
23991da177e4SLinus Torvalds 	}
24001da177e4SLinus Torvalds 	/* Closing port */
24011da177e4SLinus Torvalds 	else if (reset_port == 2) {
24021da177e4SLinus Torvalds 		msg._txOn = 0;
24031da177e4SLinus Torvalds 		msg._txOff = 1;
24041da177e4SLinus Torvalds 		msg.txFlush = 0;
24051da177e4SLinus Torvalds 		msg.txBreak = 0;
24061da177e4SLinus Torvalds 		msg.rxOn = 0;
24071da177e4SLinus Torvalds 		msg.rxOff = 1;
24081da177e4SLinus Torvalds 		msg.rxFlush = 1;
24091da177e4SLinus Torvalds 		msg.rxForward = 0;
24101da177e4SLinus Torvalds 		msg.returnStatus = 0;
24111da177e4SLinus Torvalds 		msg.resetDataToggle = 0;
24121da177e4SLinus Torvalds 		msg.enablePort = 0;
24131da177e4SLinus Torvalds 		msg.disablePort = 1;
24141da177e4SLinus Torvalds 	}
24151da177e4SLinus Torvalds 	/* Sending intermediate configs */
24161da177e4SLinus Torvalds 	else {
24171da177e4SLinus Torvalds 		msg._txOn = (!p_priv->break_on);
24181da177e4SLinus Torvalds 		msg._txOff = 0;
24191da177e4SLinus Torvalds 		msg.txFlush = 0;
24201da177e4SLinus Torvalds 		msg.txBreak = (p_priv->break_on);
24211da177e4SLinus Torvalds 		msg.rxOn = 0;
24221da177e4SLinus Torvalds 		msg.rxOff = 0;
24231da177e4SLinus Torvalds 		msg.rxFlush = 0;
24241da177e4SLinus Torvalds 		msg.rxForward = 0;
24251da177e4SLinus Torvalds 		msg.returnStatus = 0;
24261da177e4SLinus Torvalds 		msg.resetDataToggle = 0x0;
24271da177e4SLinus Torvalds 		msg.enablePort = 0;
24281da177e4SLinus Torvalds 		msg.disablePort = 0;
24291da177e4SLinus Torvalds 	}
24301da177e4SLinus Torvalds 
24311da177e4SLinus Torvalds 	/* Do handshaking outputs */
24321da177e4SLinus Torvalds 	msg.setRts = 0xff;
24331da177e4SLinus Torvalds 	msg.rts = p_priv->rts_state;
24341da177e4SLinus Torvalds 
24351da177e4SLinus Torvalds 	msg.setDtr = 0xff;
24361da177e4SLinus Torvalds 	msg.dtr = p_priv->dtr_state;
24371da177e4SLinus Torvalds 
24381da177e4SLinus Torvalds 	p_priv->resend_cont = 0;
24390ca1268eSLucy McCoy 
2440deb91685SAlan Cox 	/* if the device is a 49wg, we send control message on usb
2441deb91685SAlan Cox 	   control EP 0 */
24420ca1268eSLucy McCoy 
24430ca1268eSLucy McCoy 	if (d_details->product_id == keyspan_usa49wg_product_id) {
24440ca1268eSLucy McCoy 		dr = (void *)(s_priv->ctrl_buf);
24450ca1268eSLucy McCoy 		dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
24466424839cSMathieu OTHACEHE 		dr->bRequest = 0xB0;	/* 49wg control message */
24470ca1268eSLucy McCoy 		dr->wValue = 0;
24480ca1268eSLucy McCoy 		dr->wIndex = 0;
24490ca1268eSLucy McCoy 		dr->wLength = cpu_to_le16(sizeof(msg));
24500ca1268eSLucy McCoy 
24510ca1268eSLucy McCoy 		memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
24520ca1268eSLucy McCoy 
2453deb91685SAlan Cox 		usb_fill_control_urb(this_urb, serial->dev,
2454deb91685SAlan Cox 				usb_sndctrlpipe(serial->dev, 0),
2455deb91685SAlan Cox 				(unsigned char *)dr, s_priv->glocont_buf,
2456deb91685SAlan Cox 				sizeof(msg), usa49_glocont_callback, serial);
24570ca1268eSLucy McCoy 
24580ca1268eSLucy McCoy 	} else {
24591da177e4SLinus Torvalds 		memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
24601da177e4SLinus Torvalds 
24611da177e4SLinus Torvalds 		/* send the data out the device on control endpoint */
24621da177e4SLinus Torvalds 		this_urb->transfer_buffer_length = sizeof(msg);
24630ca1268eSLucy McCoy 	}
2464deb91685SAlan Cox 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
2465deb91685SAlan Cox 	if (err != 0)
2466049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
24671da177e4SLinus Torvalds 
2468a5b6f60cSAlan Cox 	return 0;
24691da177e4SLinus Torvalds }
24701da177e4SLinus Torvalds 
keyspan_usa90_send_setup(struct usb_serial * serial,struct usb_serial_port * port,int reset_port)24711da177e4SLinus Torvalds static int keyspan_usa90_send_setup(struct usb_serial *serial,
24721da177e4SLinus Torvalds 				    struct usb_serial_port *port,
24731da177e4SLinus Torvalds 				    int reset_port)
24741da177e4SLinus Torvalds {
24751da177e4SLinus Torvalds 	struct keyspan_usa90_portControlMessage	msg;
24761da177e4SLinus Torvalds 	struct keyspan_serial_private 		*s_priv;
24771da177e4SLinus Torvalds 	struct keyspan_port_private 		*p_priv;
24781da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
24791da177e4SLinus Torvalds 	struct urb				*this_urb;
24801da177e4SLinus Torvalds 	int 					err;
24811da177e4SLinus Torvalds 	u8						prescaler;
24821da177e4SLinus Torvalds 
24831da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
24841da177e4SLinus Torvalds 	p_priv = usb_get_serial_port_data(port);
24851da177e4SLinus Torvalds 	d_details = s_priv->device_details;
24861da177e4SLinus Torvalds 
24871da177e4SLinus Torvalds 	/* only do something if we have a bulk out endpoint */
2488deb91685SAlan Cox 	this_urb = p_priv->outcont_urb;
2489deb91685SAlan Cox 	if (this_urb == NULL) {
2490049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
24911da177e4SLinus Torvalds 		return -1;
24921da177e4SLinus Torvalds 	}
24931da177e4SLinus Torvalds 
24941da177e4SLinus Torvalds 	/* Save reset port val for resend.
24951da177e4SLinus Torvalds 	   Don't overwrite resend for open/close condition. */
24961da177e4SLinus Torvalds 	if ((reset_port + 1) > p_priv->resend_cont)
24971da177e4SLinus Torvalds 		p_priv->resend_cont = reset_port + 1;
24981da177e4SLinus Torvalds 	if (this_urb->status == -EINPROGRESS) {
2499049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s already writing\n", __func__);
25001da177e4SLinus Torvalds 		mdelay(5);
2501deb91685SAlan Cox 		return -1;
25021da177e4SLinus Torvalds 	}
25031da177e4SLinus Torvalds 
25041da177e4SLinus Torvalds 	memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
25051da177e4SLinus Torvalds 
25061da177e4SLinus Torvalds 	/* Only set baud rate if it's changed */
25071da177e4SLinus Torvalds 	if (p_priv->old_baud != p_priv->baud) {
25081da177e4SLinus Torvalds 		p_priv->old_baud = p_priv->baud;
25091da177e4SLinus Torvalds 		msg.setClocking = 0x01;
2510049c6b4eSGreg Kroah-Hartman 		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2511049c6b4eSGreg Kroah-Hartman 						   &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2512049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2513deb91685SAlan Cox 				__func__, p_priv->baud);
25141da177e4SLinus Torvalds 			p_priv->baud = 9600;
2515049c6b4eSGreg Kroah-Hartman 			d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
25161da177e4SLinus Torvalds 				&msg.baudHi, &msg.baudLo, &prescaler, 0);
25171da177e4SLinus Torvalds 		}
25181da177e4SLinus Torvalds 		msg.setRxMode = 1;
25191da177e4SLinus Torvalds 		msg.setTxMode = 1;
25201da177e4SLinus Torvalds 	}
25211da177e4SLinus Torvalds 
25221da177e4SLinus Torvalds 	/* modes must always be correctly specified */
2523deb91685SAlan Cox 	if (p_priv->baud > 57600) {
25241da177e4SLinus Torvalds 		msg.rxMode = RXMODE_DMA;
25251da177e4SLinus Torvalds 		msg.txMode = TXMODE_DMA;
2526deb91685SAlan Cox 	} else {
25271da177e4SLinus Torvalds 		msg.rxMode = RXMODE_BYHAND;
25281da177e4SLinus Torvalds 		msg.txMode = TXMODE_BYHAND;
25291da177e4SLinus Torvalds 	}
25301da177e4SLinus Torvalds 
25311da177e4SLinus Torvalds 	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
25321da177e4SLinus Torvalds 	switch (p_priv->cflag & CSIZE) {
25331da177e4SLinus Torvalds 	case CS5:
25341da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_5;
25351da177e4SLinus Torvalds 		break;
25361da177e4SLinus Torvalds 	case CS6:
25371da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_6;
25381da177e4SLinus Torvalds 		break;
25391da177e4SLinus Torvalds 	case CS7:
25401da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_7;
25411da177e4SLinus Torvalds 		break;
25421da177e4SLinus Torvalds 	case CS8:
25431da177e4SLinus Torvalds 		msg.lcr |= USA_DATABITS_8;
25441da177e4SLinus Torvalds 		break;
25451da177e4SLinus Torvalds 	}
25461da177e4SLinus Torvalds 	if (p_priv->cflag & PARENB) {
25471da177e4SLinus Torvalds 		/* note USA_PARITY_NONE == 0 */
25481da177e4SLinus Torvalds 		msg.lcr |= (p_priv->cflag & PARODD) ?
25491da177e4SLinus Torvalds 			USA_PARITY_ODD : USA_PARITY_EVEN;
25501da177e4SLinus Torvalds 	}
25511da177e4SLinus Torvalds 	if (p_priv->old_cflag != p_priv->cflag) {
25521da177e4SLinus Torvalds 		p_priv->old_cflag = p_priv->cflag;
25531da177e4SLinus Torvalds 		msg.setLcr = 0x01;
25541da177e4SLinus Torvalds 	}
25551da177e4SLinus Torvalds 
25561da177e4SLinus Torvalds 	if (p_priv->flow_control == flow_cts)
25571da177e4SLinus Torvalds 		msg.txFlowControl = TXFLOW_CTS;
25581da177e4SLinus Torvalds 	msg.setTxFlowControl = 0x01;
25591da177e4SLinus Torvalds 	msg.setRxFlowControl = 0x01;
25601da177e4SLinus Torvalds 
25611da177e4SLinus Torvalds 	msg.rxForwardingLength = 16;
25621da177e4SLinus Torvalds 	msg.rxForwardingTimeout = 16;
25631da177e4SLinus Torvalds 	msg.txAckSetting = 0;
25641da177e4SLinus Torvalds 	msg.xonChar = 17;
25651da177e4SLinus Torvalds 	msg.xoffChar = 19;
25661da177e4SLinus Torvalds 
25671da177e4SLinus Torvalds 	/* Opening port */
25681da177e4SLinus Torvalds 	if (reset_port == 1) {
25691da177e4SLinus Torvalds 		msg.portEnabled = 1;
25701da177e4SLinus Torvalds 		msg.rxFlush = 1;
25711da177e4SLinus Torvalds 		msg.txBreak = (p_priv->break_on);
25721da177e4SLinus Torvalds 	}
25731da177e4SLinus Torvalds 	/* Closing port */
2574deb91685SAlan Cox 	else if (reset_port == 2)
25751da177e4SLinus Torvalds 		msg.portEnabled = 0;
25761da177e4SLinus Torvalds 	/* Sending intermediate configs */
25771da177e4SLinus Torvalds 	else {
25781da177e4SLinus Torvalds 		msg.portEnabled = 1;
25791da177e4SLinus Torvalds 		msg.txBreak = (p_priv->break_on);
25801da177e4SLinus Torvalds 	}
25811da177e4SLinus Torvalds 
25821da177e4SLinus Torvalds 	/* Do handshaking outputs */
25831da177e4SLinus Torvalds 	msg.setRts = 0x01;
25841da177e4SLinus Torvalds 	msg.rts = p_priv->rts_state;
25851da177e4SLinus Torvalds 
25861da177e4SLinus Torvalds 	msg.setDtr = 0x01;
25871da177e4SLinus Torvalds 	msg.dtr = p_priv->dtr_state;
25881da177e4SLinus Torvalds 
25891da177e4SLinus Torvalds 	p_priv->resend_cont = 0;
25901da177e4SLinus Torvalds 	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
25911da177e4SLinus Torvalds 
25921da177e4SLinus Torvalds 	/* send the data out the device on control endpoint */
25931da177e4SLinus Torvalds 	this_urb->transfer_buffer_length = sizeof(msg);
25941da177e4SLinus Torvalds 
2595deb91685SAlan Cox 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
2596deb91685SAlan Cox 	if (err != 0)
2597049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
2598a5b6f60cSAlan Cox 	return 0;
25991da177e4SLinus Torvalds }
26001da177e4SLinus Torvalds 
keyspan_usa67_send_setup(struct usb_serial * serial,struct usb_serial_port * port,int reset_port)26010ca1268eSLucy McCoy static int keyspan_usa67_send_setup(struct usb_serial *serial,
26020ca1268eSLucy McCoy 				    struct usb_serial_port *port,
26030ca1268eSLucy McCoy 				    int reset_port)
26040ca1268eSLucy McCoy {
26050ca1268eSLucy McCoy 	struct keyspan_usa67_portControlMessage	msg;
26060ca1268eSLucy McCoy 	struct keyspan_serial_private 		*s_priv;
26070ca1268eSLucy McCoy 	struct keyspan_port_private 		*p_priv;
26080ca1268eSLucy McCoy 	const struct keyspan_device_details	*d_details;
26090ca1268eSLucy McCoy 	struct urb				*this_urb;
26100ca1268eSLucy McCoy 	int 					err, device_port;
26110ca1268eSLucy McCoy 
26120ca1268eSLucy McCoy 	s_priv = usb_get_serial_data(serial);
26130ca1268eSLucy McCoy 	p_priv = usb_get_serial_port_data(port);
26140ca1268eSLucy McCoy 	d_details = s_priv->device_details;
26150ca1268eSLucy McCoy 
26160ca1268eSLucy McCoy 	this_urb = s_priv->glocont_urb;
26170ca1268eSLucy McCoy 
26180ca1268eSLucy McCoy 	/* Work out which port within the device is being setup */
26191143832eSGreg Kroah-Hartman 	device_port = port->port_number;
26200ca1268eSLucy McCoy 
26210ca1268eSLucy McCoy 	/* Make sure we have an urb then send the message */
26220ca1268eSLucy McCoy 	if (this_urb == NULL) {
26231143832eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
26240ca1268eSLucy McCoy 		return -1;
26250ca1268eSLucy McCoy 	}
26260ca1268eSLucy McCoy 
26270ca1268eSLucy McCoy 	/* Save reset port val for resend.
26280ca1268eSLucy McCoy 	   Don't overwrite resend for open/close condition. */
26290ca1268eSLucy McCoy 	if ((reset_port + 1) > p_priv->resend_cont)
26300ca1268eSLucy McCoy 		p_priv->resend_cont = reset_port + 1;
26310ca1268eSLucy McCoy 	if (this_urb->status == -EINPROGRESS) {
2632049c6b4eSGreg Kroah-Hartman 		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
26330ca1268eSLucy McCoy 		mdelay(5);
2634deb91685SAlan Cox 		return -1;
26350ca1268eSLucy McCoy 	}
26360ca1268eSLucy McCoy 
26370ca1268eSLucy McCoy 	memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
26380ca1268eSLucy McCoy 
26390ca1268eSLucy McCoy 	msg.port = device_port;
26400ca1268eSLucy McCoy 
26410ca1268eSLucy McCoy 	/* Only set baud rate if it's changed */
26420ca1268eSLucy McCoy 	if (p_priv->old_baud != p_priv->baud) {
26430ca1268eSLucy McCoy 		p_priv->old_baud = p_priv->baud;
26440ca1268eSLucy McCoy 		msg.setClocking = 0xff;
2645049c6b4eSGreg Kroah-Hartman 		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2646049c6b4eSGreg Kroah-Hartman 						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
2647049c6b4eSGreg Kroah-Hartman 						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2648049c6b4eSGreg Kroah-Hartman 			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2649deb91685SAlan Cox 				__func__, p_priv->baud);
26500ca1268eSLucy McCoy 			msg.baudLo = 0;
26510ca1268eSLucy McCoy 			msg.baudHi = 125;	/* Values for 9600 baud */
26520ca1268eSLucy McCoy 			msg.prescaler = 10;
26530ca1268eSLucy McCoy 		}
26540ca1268eSLucy McCoy 		msg.setPrescaler = 0xff;
26550ca1268eSLucy McCoy 	}
26560ca1268eSLucy McCoy 
26570ca1268eSLucy McCoy 	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
26580ca1268eSLucy McCoy 	switch (p_priv->cflag & CSIZE) {
26590ca1268eSLucy McCoy 	case CS5:
26600ca1268eSLucy McCoy 		msg.lcr |= USA_DATABITS_5;
26610ca1268eSLucy McCoy 		break;
26620ca1268eSLucy McCoy 	case CS6:
26630ca1268eSLucy McCoy 		msg.lcr |= USA_DATABITS_6;
26640ca1268eSLucy McCoy 		break;
26650ca1268eSLucy McCoy 	case CS7:
26660ca1268eSLucy McCoy 		msg.lcr |= USA_DATABITS_7;
26670ca1268eSLucy McCoy 		break;
26680ca1268eSLucy McCoy 	case CS8:
26690ca1268eSLucy McCoy 		msg.lcr |= USA_DATABITS_8;
26700ca1268eSLucy McCoy 		break;
26710ca1268eSLucy McCoy 	}
26720ca1268eSLucy McCoy 	if (p_priv->cflag & PARENB) {
26730ca1268eSLucy McCoy 		/* note USA_PARITY_NONE == 0 */
26740ca1268eSLucy McCoy 		msg.lcr |= (p_priv->cflag & PARODD) ?
26750ca1268eSLucy McCoy 					USA_PARITY_ODD : USA_PARITY_EVEN;
26760ca1268eSLucy McCoy 	}
26770ca1268eSLucy McCoy 	msg.setLcr = 0xff;
26780ca1268eSLucy McCoy 
26790ca1268eSLucy McCoy 	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
26800ca1268eSLucy McCoy 	msg.xonFlowControl = 0;
26810ca1268eSLucy McCoy 	msg.setFlowControl = 0xff;
26820ca1268eSLucy McCoy 	msg.forwardingLength = 16;
26830ca1268eSLucy McCoy 	msg.xonChar = 17;
26840ca1268eSLucy McCoy 	msg.xoffChar = 19;
26850ca1268eSLucy McCoy 
26860ca1268eSLucy McCoy 	if (reset_port == 1) {
26870ca1268eSLucy McCoy 		/* Opening port */
26880ca1268eSLucy McCoy 		msg._txOn = 1;
26890ca1268eSLucy McCoy 		msg._txOff = 0;
26900ca1268eSLucy McCoy 		msg.txFlush = 0;
26910ca1268eSLucy McCoy 		msg.txBreak = 0;
26920ca1268eSLucy McCoy 		msg.rxOn = 1;
26930ca1268eSLucy McCoy 		msg.rxOff = 0;
26940ca1268eSLucy McCoy 		msg.rxFlush = 1;
26950ca1268eSLucy McCoy 		msg.rxForward = 0;
26960ca1268eSLucy McCoy 		msg.returnStatus = 0;
26970ca1268eSLucy McCoy 		msg.resetDataToggle = 0xff;
26980ca1268eSLucy McCoy 	} else if (reset_port == 2) {
26990ca1268eSLucy McCoy 		/* Closing port */
27000ca1268eSLucy McCoy 		msg._txOn = 0;
27010ca1268eSLucy McCoy 		msg._txOff = 1;
27020ca1268eSLucy McCoy 		msg.txFlush = 0;
27030ca1268eSLucy McCoy 		msg.txBreak = 0;
27040ca1268eSLucy McCoy 		msg.rxOn = 0;
27050ca1268eSLucy McCoy 		msg.rxOff = 1;
27060ca1268eSLucy McCoy 		msg.rxFlush = 1;
27070ca1268eSLucy McCoy 		msg.rxForward = 0;
27080ca1268eSLucy McCoy 		msg.returnStatus = 0;
27090ca1268eSLucy McCoy 		msg.resetDataToggle = 0;
27100ca1268eSLucy McCoy 	} else {
27110ca1268eSLucy McCoy 		/* Sending intermediate configs */
27120ca1268eSLucy McCoy 		msg._txOn = (!p_priv->break_on);
27130ca1268eSLucy McCoy 		msg._txOff = 0;
27140ca1268eSLucy McCoy 		msg.txFlush = 0;
27150ca1268eSLucy McCoy 		msg.txBreak = (p_priv->break_on);
27160ca1268eSLucy McCoy 		msg.rxOn = 0;
27170ca1268eSLucy McCoy 		msg.rxOff = 0;
27180ca1268eSLucy McCoy 		msg.rxFlush = 0;
27190ca1268eSLucy McCoy 		msg.rxForward = 0;
27200ca1268eSLucy McCoy 		msg.returnStatus = 0;
27210ca1268eSLucy McCoy 		msg.resetDataToggle = 0x0;
27220ca1268eSLucy McCoy 	}
27230ca1268eSLucy McCoy 
27240ca1268eSLucy McCoy 	/* Do handshaking outputs */
27250ca1268eSLucy McCoy 	msg.setTxTriState_setRts = 0xff;
27260ca1268eSLucy McCoy 	msg.txTriState_rts = p_priv->rts_state;
27270ca1268eSLucy McCoy 
27280ca1268eSLucy McCoy 	msg.setHskoa_setDtr = 0xff;
27290ca1268eSLucy McCoy 	msg.hskoa_dtr = p_priv->dtr_state;
27300ca1268eSLucy McCoy 
27310ca1268eSLucy McCoy 	p_priv->resend_cont = 0;
27320ca1268eSLucy McCoy 
27330ca1268eSLucy McCoy 	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
27340ca1268eSLucy McCoy 
27350ca1268eSLucy McCoy 	/* send the data out the device on control endpoint */
27360ca1268eSLucy McCoy 	this_urb->transfer_buffer_length = sizeof(msg);
27370ca1268eSLucy McCoy 
27380ca1268eSLucy McCoy 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
27390ca1268eSLucy McCoy 	if (err != 0)
2740049c6b4eSGreg Kroah-Hartman 		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
2741a5b6f60cSAlan Cox 	return 0;
27420ca1268eSLucy McCoy }
27430ca1268eSLucy McCoy 
keyspan_send_setup(struct usb_serial_port * port,int reset_port)27441da177e4SLinus Torvalds static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
27451da177e4SLinus Torvalds {
27461da177e4SLinus Torvalds 	struct usb_serial *serial = port->serial;
27471da177e4SLinus Torvalds 	struct keyspan_serial_private *s_priv;
27481da177e4SLinus Torvalds 	const struct keyspan_device_details *d_details;
27491da177e4SLinus Torvalds 
27501da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
27511da177e4SLinus Torvalds 	d_details = s_priv->device_details;
27521da177e4SLinus Torvalds 
27531da177e4SLinus Torvalds 	switch (d_details->msg_format) {
27541da177e4SLinus Torvalds 	case msg_usa26:
27551da177e4SLinus Torvalds 		keyspan_usa26_send_setup(serial, port, reset_port);
27561da177e4SLinus Torvalds 		break;
27571da177e4SLinus Torvalds 	case msg_usa28:
27581da177e4SLinus Torvalds 		keyspan_usa28_send_setup(serial, port, reset_port);
27591da177e4SLinus Torvalds 		break;
27601da177e4SLinus Torvalds 	case msg_usa49:
27611da177e4SLinus Torvalds 		keyspan_usa49_send_setup(serial, port, reset_port);
27621da177e4SLinus Torvalds 		break;
27631da177e4SLinus Torvalds 	case msg_usa90:
27641da177e4SLinus Torvalds 		keyspan_usa90_send_setup(serial, port, reset_port);
27651da177e4SLinus Torvalds 		break;
27660ca1268eSLucy McCoy 	case msg_usa67:
27670ca1268eSLucy McCoy 		keyspan_usa67_send_setup(serial, port, reset_port);
27680ca1268eSLucy McCoy 		break;
27691da177e4SLinus Torvalds 	}
27701da177e4SLinus Torvalds }
27711da177e4SLinus Torvalds 
27721da177e4SLinus Torvalds 
27731da177e4SLinus Torvalds /* Gets called by the "real" driver (ie once firmware is loaded
27741da177e4SLinus Torvalds    and renumeration has taken place. */
keyspan_startup(struct usb_serial * serial)27751da177e4SLinus Torvalds static int keyspan_startup(struct usb_serial *serial)
27761da177e4SLinus Torvalds {
27771da177e4SLinus Torvalds 	int				i, err;
27781da177e4SLinus Torvalds 	struct keyspan_serial_private 	*s_priv;
27791da177e4SLinus Torvalds 	const struct keyspan_device_details	*d_details;
27801da177e4SLinus Torvalds 
27811da177e4SLinus Torvalds 	for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
2782deb91685SAlan Cox 		if (d_details->product_id ==
2783deb91685SAlan Cox 				le16_to_cpu(serial->dev->descriptor.idProduct))
27841da177e4SLinus Torvalds 			break;
27851da177e4SLinus Torvalds 	if (d_details == NULL) {
2786deb91685SAlan Cox 		dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2787deb91685SAlan Cox 		    __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
2788ff8a43c1SJohan Hovold 		return -ENODEV;
27891da177e4SLinus Torvalds 	}
27901da177e4SLinus Torvalds 
27911da177e4SLinus Torvalds 	/* Setup private data for serial driver */
279280b6ca48SEric Sesterhenn 	s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
279310c642d0SJohan Hovold 	if (!s_priv)
27941da177e4SLinus Torvalds 		return -ENOMEM;
27951da177e4SLinus Torvalds 
27962fcd1c9bSJohan Hovold 	s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);
27972fcd1c9bSJohan Hovold 	if (!s_priv->instat_buf)
27982fcd1c9bSJohan Hovold 		goto err_instat_buf;
27992fcd1c9bSJohan Hovold 
28002fcd1c9bSJohan Hovold 	s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL);
28012fcd1c9bSJohan Hovold 	if (!s_priv->indat_buf)
28022fcd1c9bSJohan Hovold 		goto err_indat_buf;
28032fcd1c9bSJohan Hovold 
28042fcd1c9bSJohan Hovold 	s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL);
28052fcd1c9bSJohan Hovold 	if (!s_priv->glocont_buf)
28062fcd1c9bSJohan Hovold 		goto err_glocont_buf;
28072fcd1c9bSJohan Hovold 
28082fcd1c9bSJohan Hovold 	s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
28092fcd1c9bSJohan Hovold 	if (!s_priv->ctrl_buf)
28102fcd1c9bSJohan Hovold 		goto err_ctrl_buf;
28112fcd1c9bSJohan Hovold 
28121da177e4SLinus Torvalds 	s_priv->device_details = d_details;
28131da177e4SLinus Torvalds 	usb_set_serial_data(serial, s_priv);
28141da177e4SLinus Torvalds 
28151da177e4SLinus Torvalds 	keyspan_setup_urbs(serial);
28161da177e4SLinus Torvalds 
28170ca1268eSLucy McCoy 	if (s_priv->instat_urb != NULL) {
28180ca1268eSLucy McCoy 		err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
28190ca1268eSLucy McCoy 		if (err != 0)
28207ebcb334SGreg Kroah-Hartman 			dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
28210ca1268eSLucy McCoy 	}
28220ca1268eSLucy McCoy 	if (s_priv->indat_urb != NULL) {
28230ca1268eSLucy McCoy 		err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
28240ca1268eSLucy McCoy 		if (err != 0)
28257ebcb334SGreg Kroah-Hartman 			dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
28261da177e4SLinus Torvalds 	}
28271da177e4SLinus Torvalds 
2828a5b6f60cSAlan Cox 	return 0;
28292fcd1c9bSJohan Hovold 
28302fcd1c9bSJohan Hovold err_ctrl_buf:
28312fcd1c9bSJohan Hovold 	kfree(s_priv->glocont_buf);
28322fcd1c9bSJohan Hovold err_glocont_buf:
28332fcd1c9bSJohan Hovold 	kfree(s_priv->indat_buf);
28342fcd1c9bSJohan Hovold err_indat_buf:
28352fcd1c9bSJohan Hovold 	kfree(s_priv->instat_buf);
28362fcd1c9bSJohan Hovold err_instat_buf:
28372fcd1c9bSJohan Hovold 	kfree(s_priv);
28382fcd1c9bSJohan Hovold 
28392fcd1c9bSJohan Hovold 	return -ENOMEM;
28401da177e4SLinus Torvalds }
28411da177e4SLinus Torvalds 
keyspan_disconnect(struct usb_serial * serial)2842f9c99bb8SAlan Stern static void keyspan_disconnect(struct usb_serial *serial)
28431da177e4SLinus Torvalds {
28441da177e4SLinus Torvalds 	struct keyspan_serial_private *s_priv;
28451da177e4SLinus Torvalds 
28461da177e4SLinus Torvalds 	s_priv = usb_get_serial_data(serial);
28471da177e4SLinus Torvalds 
284861924505SJohan Hovold 	usb_kill_urb(s_priv->instat_urb);
284961924505SJohan Hovold 	usb_kill_urb(s_priv->glocont_urb);
285061924505SJohan Hovold 	usb_kill_urb(s_priv->indat_urb);
2851f9c99bb8SAlan Stern }
2852f9c99bb8SAlan Stern 
keyspan_release(struct usb_serial * serial)2853f9c99bb8SAlan Stern static void keyspan_release(struct usb_serial *serial)
2854f9c99bb8SAlan Stern {
2855f9c99bb8SAlan Stern 	struct keyspan_serial_private *s_priv;
2856f9c99bb8SAlan Stern 
2857f9c99bb8SAlan Stern 	s_priv = usb_get_serial_data(serial);
28581da177e4SLinus Torvalds 
285935be1a71SJohan Hovold 	/* Make sure to unlink the URBs submitted in attach. */
286035be1a71SJohan Hovold 	usb_kill_urb(s_priv->instat_urb);
286135be1a71SJohan Hovold 	usb_kill_urb(s_priv->indat_urb);
286235be1a71SJohan Hovold 
2863f79b2d0fSJohan Hovold 	usb_free_urb(s_priv->instat_urb);
2864f79b2d0fSJohan Hovold 	usb_free_urb(s_priv->indat_urb);
2865f79b2d0fSJohan Hovold 	usb_free_urb(s_priv->glocont_urb);
28661da177e4SLinus Torvalds 
28672fcd1c9bSJohan Hovold 	kfree(s_priv->ctrl_buf);
28682fcd1c9bSJohan Hovold 	kfree(s_priv->glocont_buf);
28692fcd1c9bSJohan Hovold 	kfree(s_priv->indat_buf);
28702fcd1c9bSJohan Hovold 	kfree(s_priv->instat_buf);
28712fcd1c9bSJohan Hovold 
2872f79b2d0fSJohan Hovold 	kfree(s_priv);
28731da177e4SLinus Torvalds }
2874f79b2d0fSJohan Hovold 
keyspan_port_probe(struct usb_serial_port * port)2875f79b2d0fSJohan Hovold static int keyspan_port_probe(struct usb_serial_port *port)
2876f79b2d0fSJohan Hovold {
2877f79b2d0fSJohan Hovold 	struct usb_serial *serial = port->serial;
2878f0e3e35cSBjørn Mork 	struct keyspan_serial_private *s_priv;
2879f79b2d0fSJohan Hovold 	struct keyspan_port_private *p_priv;
2880f79b2d0fSJohan Hovold 	const struct keyspan_device_details *d_details;
2881f79b2d0fSJohan Hovold 	struct callbacks *cback;
2882f79b2d0fSJohan Hovold 	int endp;
2883f79b2d0fSJohan Hovold 	int port_num;
2884f79b2d0fSJohan Hovold 	int i;
2885f79b2d0fSJohan Hovold 
2886f79b2d0fSJohan Hovold 	s_priv = usb_get_serial_data(serial);
2887f79b2d0fSJohan Hovold 	d_details = s_priv->device_details;
2888f79b2d0fSJohan Hovold 
2889f79b2d0fSJohan Hovold 	p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL);
2890f79b2d0fSJohan Hovold 	if (!p_priv)
2891f79b2d0fSJohan Hovold 		return -ENOMEM;
2892f79b2d0fSJohan Hovold 
2893bad41a5bSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
2894bad41a5bSJohan Hovold 		p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
2895bad41a5bSJohan Hovold 		if (!p_priv->in_buffer[i])
2896910c9963SWang Hai 			goto err_free_in_buffer;
2897bad41a5bSJohan Hovold 	}
2898bad41a5bSJohan Hovold 
2899bad41a5bSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
2900bad41a5bSJohan Hovold 		p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
2901bad41a5bSJohan Hovold 		if (!p_priv->out_buffer[i])
2902910c9963SWang Hai 			goto err_free_out_buffer;
2903bad41a5bSJohan Hovold 	}
2904bad41a5bSJohan Hovold 
2905bad41a5bSJohan Hovold 	p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
2906bad41a5bSJohan Hovold 	if (!p_priv->inack_buffer)
2907910c9963SWang Hai 		goto err_free_out_buffer;
2908bad41a5bSJohan Hovold 
2909bad41a5bSJohan Hovold 	p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
2910bad41a5bSJohan Hovold 	if (!p_priv->outcont_buffer)
2911910c9963SWang Hai 		goto err_free_inack_buffer;
2912bad41a5bSJohan Hovold 
2913f79b2d0fSJohan Hovold 	p_priv->device_details = d_details;
2914f79b2d0fSJohan Hovold 
2915f79b2d0fSJohan Hovold 	/* Setup values for the various callback routines */
2916f79b2d0fSJohan Hovold 	cback = &keyspan_callbacks[d_details->msg_format];
2917f79b2d0fSJohan Hovold 
29181143832eSGreg Kroah-Hartman 	port_num = port->port_number;
2919f79b2d0fSJohan Hovold 
2920f79b2d0fSJohan Hovold 	/* Do indat endpoints first, once for each flip */
2921f79b2d0fSJohan Hovold 	endp = d_details->indat_endpoints[port_num];
2922f79b2d0fSJohan Hovold 	for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
2923f79b2d0fSJohan Hovold 		p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
2924f79b2d0fSJohan Hovold 						USB_DIR_IN, port,
2925bad41a5bSJohan Hovold 						p_priv->in_buffer[i],
2926bad41a5bSJohan Hovold 						IN_BUFLEN,
2927f79b2d0fSJohan Hovold 						cback->indat_callback);
2928f79b2d0fSJohan Hovold 	}
2929f79b2d0fSJohan Hovold 	/* outdat endpoints also have flip */
2930f79b2d0fSJohan Hovold 	endp = d_details->outdat_endpoints[port_num];
2931f79b2d0fSJohan Hovold 	for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
2932f79b2d0fSJohan Hovold 		p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
2933f79b2d0fSJohan Hovold 						USB_DIR_OUT, port,
2934bad41a5bSJohan Hovold 						p_priv->out_buffer[i],
2935bad41a5bSJohan Hovold 						OUT_BUFLEN,
2936f79b2d0fSJohan Hovold 						cback->outdat_callback);
2937f79b2d0fSJohan Hovold 	}
2938f79b2d0fSJohan Hovold 	/* inack endpoint */
2939f79b2d0fSJohan Hovold 	p_priv->inack_urb = keyspan_setup_urb(serial,
2940f79b2d0fSJohan Hovold 					d_details->inack_endpoints[port_num],
2941f79b2d0fSJohan Hovold 					USB_DIR_IN, port,
2942bad41a5bSJohan Hovold 					p_priv->inack_buffer,
2943bad41a5bSJohan Hovold 					INACK_BUFLEN,
2944f79b2d0fSJohan Hovold 					cback->inack_callback);
2945f79b2d0fSJohan Hovold 	/* outcont endpoint */
2946f79b2d0fSJohan Hovold 	p_priv->outcont_urb = keyspan_setup_urb(serial,
2947f79b2d0fSJohan Hovold 					d_details->outcont_endpoints[port_num],
2948f79b2d0fSJohan Hovold 					USB_DIR_OUT, port,
2949bad41a5bSJohan Hovold 					p_priv->outcont_buffer,
2950bad41a5bSJohan Hovold 					OUTCONT_BUFLEN,
2951f79b2d0fSJohan Hovold 					 cback->outcont_callback);
2952f79b2d0fSJohan Hovold 
2953f79b2d0fSJohan Hovold 	usb_set_serial_port_data(port, p_priv);
2954f79b2d0fSJohan Hovold 
2955f79b2d0fSJohan Hovold 	return 0;
2956bad41a5bSJohan Hovold 
2957910c9963SWang Hai err_free_inack_buffer:
2958bad41a5bSJohan Hovold 	kfree(p_priv->inack_buffer);
2959910c9963SWang Hai err_free_out_buffer:
2960bad41a5bSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
2961bad41a5bSJohan Hovold 		kfree(p_priv->out_buffer[i]);
2962910c9963SWang Hai err_free_in_buffer:
2963bad41a5bSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
2964bad41a5bSJohan Hovold 		kfree(p_priv->in_buffer[i]);
2965bad41a5bSJohan Hovold 	kfree(p_priv);
2966bad41a5bSJohan Hovold 
2967bad41a5bSJohan Hovold 	return -ENOMEM;
2968f79b2d0fSJohan Hovold }
2969f79b2d0fSJohan Hovold 
keyspan_port_remove(struct usb_serial_port * port)2970c5d1448fSUwe Kleine-König static void keyspan_port_remove(struct usb_serial_port *port)
2971f79b2d0fSJohan Hovold {
2972f79b2d0fSJohan Hovold 	struct keyspan_port_private *p_priv;
2973f79b2d0fSJohan Hovold 	int i;
2974f79b2d0fSJohan Hovold 
2975f79b2d0fSJohan Hovold 	p_priv = usb_get_serial_port_data(port);
2976f79b2d0fSJohan Hovold 
297761924505SJohan Hovold 	usb_kill_urb(p_priv->inack_urb);
297861924505SJohan Hovold 	usb_kill_urb(p_priv->outcont_urb);
2979f79b2d0fSJohan Hovold 	for (i = 0; i < 2; i++) {
298061924505SJohan Hovold 		usb_kill_urb(p_priv->in_urbs[i]);
298161924505SJohan Hovold 		usb_kill_urb(p_priv->out_urbs[i]);
2982f79b2d0fSJohan Hovold 	}
2983f79b2d0fSJohan Hovold 
2984f79b2d0fSJohan Hovold 	usb_free_urb(p_priv->inack_urb);
2985f79b2d0fSJohan Hovold 	usb_free_urb(p_priv->outcont_urb);
2986f79b2d0fSJohan Hovold 	for (i = 0; i < 2; i++) {
2987f79b2d0fSJohan Hovold 		usb_free_urb(p_priv->in_urbs[i]);
2988f79b2d0fSJohan Hovold 		usb_free_urb(p_priv->out_urbs[i]);
2989f79b2d0fSJohan Hovold 	}
2990f79b2d0fSJohan Hovold 
2991bad41a5bSJohan Hovold 	kfree(p_priv->outcont_buffer);
2992bad41a5bSJohan Hovold 	kfree(p_priv->inack_buffer);
2993bad41a5bSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
2994bad41a5bSJohan Hovold 		kfree(p_priv->out_buffer[i]);
2995bad41a5bSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
2996bad41a5bSJohan Hovold 		kfree(p_priv->in_buffer[i]);
2997bad41a5bSJohan Hovold 
2998f79b2d0fSJohan Hovold 	kfree(p_priv);
29991da177e4SLinus Torvalds }
30001da177e4SLinus Torvalds 
3001beabdc3cSJohan Hovold /* Structs for the devices, pre and post renumeration. */
3002beabdc3cSJohan Hovold static struct usb_serial_driver keyspan_pre_device = {
3003beabdc3cSJohan Hovold 	.driver = {
3004beabdc3cSJohan Hovold 		.owner		= THIS_MODULE,
3005beabdc3cSJohan Hovold 		.name		= "keyspan_no_firm",
3006beabdc3cSJohan Hovold 	},
3007beabdc3cSJohan Hovold 	.description		= "Keyspan - (without firmware)",
3008beabdc3cSJohan Hovold 	.id_table		= keyspan_pre_ids,
3009beabdc3cSJohan Hovold 	.num_ports		= 1,
3010beabdc3cSJohan Hovold 	.attach			= keyspan_fake_startup,
3011beabdc3cSJohan Hovold };
3012beabdc3cSJohan Hovold 
3013beabdc3cSJohan Hovold static struct usb_serial_driver keyspan_1port_device = {
3014beabdc3cSJohan Hovold 	.driver = {
3015beabdc3cSJohan Hovold 		.owner		= THIS_MODULE,
3016beabdc3cSJohan Hovold 		.name		= "keyspan_1",
3017beabdc3cSJohan Hovold 	},
3018beabdc3cSJohan Hovold 	.description		= "Keyspan 1 port adapter",
3019beabdc3cSJohan Hovold 	.id_table		= keyspan_1port_ids,
3020beabdc3cSJohan Hovold 	.num_ports		= 1,
3021beabdc3cSJohan Hovold 	.open			= keyspan_open,
3022beabdc3cSJohan Hovold 	.close			= keyspan_close,
3023beabdc3cSJohan Hovold 	.dtr_rts		= keyspan_dtr_rts,
3024beabdc3cSJohan Hovold 	.write			= keyspan_write,
3025beabdc3cSJohan Hovold 	.write_room		= keyspan_write_room,
3026beabdc3cSJohan Hovold 	.set_termios		= keyspan_set_termios,
3027beabdc3cSJohan Hovold 	.break_ctl		= keyspan_break_ctl,
3028beabdc3cSJohan Hovold 	.tiocmget		= keyspan_tiocmget,
3029beabdc3cSJohan Hovold 	.tiocmset		= keyspan_tiocmset,
3030beabdc3cSJohan Hovold 	.attach			= keyspan_startup,
3031beabdc3cSJohan Hovold 	.disconnect		= keyspan_disconnect,
3032beabdc3cSJohan Hovold 	.release		= keyspan_release,
3033beabdc3cSJohan Hovold 	.port_probe		= keyspan_port_probe,
3034beabdc3cSJohan Hovold 	.port_remove		= keyspan_port_remove,
3035beabdc3cSJohan Hovold };
3036beabdc3cSJohan Hovold 
3037beabdc3cSJohan Hovold static struct usb_serial_driver keyspan_2port_device = {
3038beabdc3cSJohan Hovold 	.driver = {
3039beabdc3cSJohan Hovold 		.owner		= THIS_MODULE,
3040beabdc3cSJohan Hovold 		.name		= "keyspan_2",
3041beabdc3cSJohan Hovold 	},
3042beabdc3cSJohan Hovold 	.description		= "Keyspan 2 port adapter",
3043beabdc3cSJohan Hovold 	.id_table		= keyspan_2port_ids,
3044beabdc3cSJohan Hovold 	.num_ports		= 2,
3045beabdc3cSJohan Hovold 	.open			= keyspan_open,
3046beabdc3cSJohan Hovold 	.close			= keyspan_close,
3047beabdc3cSJohan Hovold 	.dtr_rts		= keyspan_dtr_rts,
3048beabdc3cSJohan Hovold 	.write			= keyspan_write,
3049beabdc3cSJohan Hovold 	.write_room		= keyspan_write_room,
3050beabdc3cSJohan Hovold 	.set_termios		= keyspan_set_termios,
3051beabdc3cSJohan Hovold 	.break_ctl		= keyspan_break_ctl,
3052beabdc3cSJohan Hovold 	.tiocmget		= keyspan_tiocmget,
3053beabdc3cSJohan Hovold 	.tiocmset		= keyspan_tiocmset,
3054beabdc3cSJohan Hovold 	.attach			= keyspan_startup,
3055beabdc3cSJohan Hovold 	.disconnect		= keyspan_disconnect,
3056beabdc3cSJohan Hovold 	.release		= keyspan_release,
3057beabdc3cSJohan Hovold 	.port_probe		= keyspan_port_probe,
3058beabdc3cSJohan Hovold 	.port_remove		= keyspan_port_remove,
3059beabdc3cSJohan Hovold };
3060beabdc3cSJohan Hovold 
3061beabdc3cSJohan Hovold static struct usb_serial_driver keyspan_4port_device = {
3062beabdc3cSJohan Hovold 	.driver = {
3063beabdc3cSJohan Hovold 		.owner		= THIS_MODULE,
3064beabdc3cSJohan Hovold 		.name		= "keyspan_4",
3065beabdc3cSJohan Hovold 	},
3066beabdc3cSJohan Hovold 	.description		= "Keyspan 4 port adapter",
3067beabdc3cSJohan Hovold 	.id_table		= keyspan_4port_ids,
3068beabdc3cSJohan Hovold 	.num_ports		= 4,
3069beabdc3cSJohan Hovold 	.open			= keyspan_open,
3070beabdc3cSJohan Hovold 	.close			= keyspan_close,
3071beabdc3cSJohan Hovold 	.dtr_rts		= keyspan_dtr_rts,
3072beabdc3cSJohan Hovold 	.write			= keyspan_write,
3073beabdc3cSJohan Hovold 	.write_room		= keyspan_write_room,
3074beabdc3cSJohan Hovold 	.set_termios		= keyspan_set_termios,
3075beabdc3cSJohan Hovold 	.break_ctl		= keyspan_break_ctl,
3076beabdc3cSJohan Hovold 	.tiocmget		= keyspan_tiocmget,
3077beabdc3cSJohan Hovold 	.tiocmset		= keyspan_tiocmset,
3078beabdc3cSJohan Hovold 	.attach			= keyspan_startup,
3079beabdc3cSJohan Hovold 	.disconnect		= keyspan_disconnect,
3080beabdc3cSJohan Hovold 	.release		= keyspan_release,
3081beabdc3cSJohan Hovold 	.port_probe		= keyspan_port_probe,
3082beabdc3cSJohan Hovold 	.port_remove		= keyspan_port_remove,
3083beabdc3cSJohan Hovold };
3084beabdc3cSJohan Hovold 
3085beabdc3cSJohan Hovold static struct usb_serial_driver * const serial_drivers[] = {
3086beabdc3cSJohan Hovold 	&keyspan_pre_device, &keyspan_1port_device,
3087beabdc3cSJohan Hovold 	&keyspan_2port_device, &keyspan_4port_device, NULL
3088beabdc3cSJohan Hovold };
3089beabdc3cSJohan Hovold 
3090beabdc3cSJohan Hovold module_usb_serial_driver(serial_drivers, keyspan_ids_combined);
3091beabdc3cSJohan Hovold 
30921da177e4SLinus Torvalds MODULE_AUTHOR(DRIVER_AUTHOR);
30931da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC);
30941da177e4SLinus Torvalds MODULE_LICENSE("GPL");
30951da177e4SLinus Torvalds 
30962971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa28.fw");
30972971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa28x.fw");
30982971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa28xa.fw");
30992971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa28xb.fw");
31002971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa19.fw");
31012971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa19qi.fw");
31022971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/mpr.fw");
31032971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa19qw.fw");
31042971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa18x.fw");
31052971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa19w.fw");
31062971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa49w.fw");
31072971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa49wlc.fw");
3108