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