blob: 2b1cfcbf8f9bcd2e8780a5c7390586ea174c604a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 Keyspan USB to Serial Converter driver
Alan Coxdeb91682008-07-22 11:13:08 +01003
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 (C) Copyright (C) 2000-2001 Hugh Blemings <hugh@blemings.org>
5 (C) Copyright (C) 2002 Greg Kroah-Hartman <greg@kroah.com>
Alan Coxdeb91682008-07-22 11:13:08 +01006
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 See http://misc.nu/hugh/keyspan.html for more information.
Alan Coxdeb91682008-07-22 11:13:08 +010013
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 Code in this driver inspired by and in a number of places taken
15 from Brian Warner's original Keyspan-PDA driver.
16
17 This driver has been put together with the support of Innosys, Inc.
18 and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
19 Thanks Guys :)
Alan Coxdeb91682008-07-22 11:13:08 +010020
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 Thanks to Paulus for miscellaneous tidy ups, some largish chunks
22 of much nicer and/or completely new code and (perhaps most uniquely)
23 having the patience to sit down and explain why and where he'd changed
Alan Coxdeb91682008-07-22 11:13:08 +010024 stuff.
25
26 Tip 'o the hat to IBM (and previously Linuxcare :) for supporting
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 staff in their work on open source projects.
28
29 Change History
30
31 2003sep04 LPM (Keyspan) add support for new single port product USA19HS.
32 Improve setup message handling for all devices.
33
34 Wed Feb 19 22:00:00 PST 2003 (Jeffrey S. Laing <keyspan@jsl.com>)
35 Merged the current (1/31/03) Keyspan code with the current (2.4.21-pre4)
36 Linux source tree. The Linux tree lacked support for the 49WLC and
37 others. The Keyspan patches didn't work with the current kernel.
38
39 2003jan30 LPM add support for the 49WLC and MPR
40
41 Wed Apr 25 12:00:00 PST 2002 (Keyspan)
42 Started with Hugh Blemings' code dated Jan 17, 2002. All adapters
43 now supported (including QI and QW). Modified port open, port
44 close, and send setup() logic to fix various data and endpoint
45 synchronization bugs and device LED status bugs. Changed keyspan_
46 write_room() to accurately return transmit buffer availability.
47 Changed forwardingLength from 1 to 16 for all adapters.
48
49 Fri Oct 12 16:45:00 EST 2001
50 Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV)
51
52 Wed Apr 25 12:00:00 PST 2002 (Keyspan)
53 Started with Hugh Blemings' code dated Jan 17, 2002. All adapters
54 now supported (including QI and QW). Modified port open, port
55 close, and send setup() logic to fix various data and endpoint
56 synchronization bugs and device LED status bugs. Changed keyspan_
57 write_room() to accurately return transmit buffer availability.
58 Changed forwardingLength from 1 to 16 for all adapters.
59
60 Fri Oct 12 16:45:00 EST 2001
61 Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV)
62
63 Mon Oct 8 14:29:00 EST 2001 hugh
64 Fixed bug that prevented mulitport devices operating correctly
65 if they weren't the first unit attached.
66
67 Sat Oct 6 12:31:21 EST 2001 hugh
68 Added support for USA-28XA and -28XB, misc cleanups, break support
69 for usa26 based models thanks to David Gibson.
70
71 Thu May 31 11:56:42 PDT 2001 gkh
72 switched from using spinlock to a semaphore
Alan Coxdeb91682008-07-22 11:13:08 +010073
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 (04/08/2001) gb
75 Identify version on module load.
Alan Coxdeb91682008-07-22 11:13:08 +010076
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 (11/01/2000) Adam J. Richter
78 usb_device_id table support.
Alan Coxdeb91682008-07-22 11:13:08 +010079
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 Tue Oct 10 23:15:33 EST 2000 Hugh
81 Merged Paul's changes with my USA-49W mods. Work in progress
82 still...
Alan Coxdeb91682008-07-22 11:13:08 +010083
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 Wed Jul 19 14:00:42 EST 2000 gkh
85 Added module_init and module_exit functions to handle the fact that
86 this driver is a loadable module now.
Alan Coxdeb91682008-07-22 11:13:08 +010087
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 Tue Jul 18 16:14:52 EST 2000 Hugh
89 Basic character input/output for USA-19 now mostly works,
90 fixed at 9600 baud for the moment.
91
92 Sat Jul 8 11:11:48 EST 2000 Hugh
93 First public release - nothing works except the firmware upload.
94 Tested on PPC and x86 architectures, seems to behave...
95*/
96
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098#include <linux/kernel.h>
99#include <linux/jiffies.h>
100#include <linux/errno.h>
101#include <linux/init.h>
102#include <linux/slab.h>
103#include <linux/tty.h>
104#include <linux/tty_driver.h>
105#include <linux/tty_flip.h>
106#include <linux/module.h>
107#include <linux/spinlock.h>
David Woodhouse2971c572008-05-30 14:04:03 +0300108#include <linux/firmware.h>
109#include <linux/ihex.h>
Alan Coxdeb91682008-07-22 11:13:08 +0100110#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -0700112#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113#include "keyspan.h"
114
115static int debug;
116
117/*
118 * Version Information
119 */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700120#define DRIVER_VERSION "v1.1.5"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
122#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
123
124#define INSTAT_BUFLEN 32
125#define GLOCONT_BUFLEN 64
Lucy McCoy0ca12682007-05-18 12:10:41 -0700126#define INDAT49W_BUFLEN 512
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128 /* Per device and per port private data */
129struct keyspan_serial_private {
130 const struct keyspan_device_details *device_details;
131
132 struct urb *instat_urb;
133 char instat_buf[INSTAT_BUFLEN];
134
Alan Coxdeb91682008-07-22 11:13:08 +0100135 /* added to support 49wg, where data from all 4 ports comes in
136 on 1 EP and high-speed supported */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700137 struct urb *indat_urb;
138 char indat_buf[INDAT49W_BUFLEN];
139
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 /* XXX this one probably will need a lock */
141 struct urb *glocont_urb;
142 char glocont_buf[GLOCONT_BUFLEN];
Alan Coxdeb91682008-07-22 11:13:08 +0100143 char ctrl_buf[8]; /* for EP0 control message */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144};
145
146struct keyspan_port_private {
147 /* Keep track of which input & output endpoints to use */
148 int in_flip;
149 int out_flip;
150
151 /* Keep duplicate of device details in each port
152 structure as well - simplifies some of the
153 callback functions etc. */
154 const struct keyspan_device_details *device_details;
155
156 /* Input endpoints and buffer for this port */
157 struct urb *in_urbs[2];
158 char in_buffer[2][64];
159 /* Output endpoints and buffer for this port */
160 struct urb *out_urbs[2];
161 char out_buffer[2][64];
162
163 /* Input ack endpoint */
164 struct urb *inack_urb;
165 char inack_buffer[1];
166
167 /* Output control endpoint */
168 struct urb *outcont_urb;
169 char outcont_buffer[64];
170
171 /* Settings for the port */
172 int baud;
173 int old_baud;
174 unsigned int cflag;
175 unsigned int old_cflag;
176 enum {flow_none, flow_cts, flow_xon} flow_control;
177 int rts_state; /* Handshaking pins (outputs) */
178 int dtr_state;
179 int cts_state; /* Handshaking pins (inputs) */
180 int dsr_state;
181 int dcd_state;
182 int ri_state;
183 int break_on;
184
185 unsigned long tx_start_time[2];
186 int resend_cont; /* need to resend control packet */
187};
188
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189/* Include Keyspan message headers. All current Keyspan Adapters
Lucy McCoy0ca12682007-05-18 12:10:41 -0700190 make use of one of five message formats which are referred
Alan Coxdeb91682008-07-22 11:13:08 +0100191 to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and
192 within this driver. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193#include "keyspan_usa26msg.h"
194#include "keyspan_usa28msg.h"
195#include "keyspan_usa49msg.h"
196#include "keyspan_usa90msg.h"
Lucy McCoy0ca12682007-05-18 12:10:41 -0700197#include "keyspan_usa67msg.h"
Alan Coxdeb91682008-07-22 11:13:08 +0100198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200/* Functions used by new usb-serial code. */
Alan Coxdeb91682008-07-22 11:13:08 +0100201static int __init keyspan_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202{
203 int retval;
204 retval = usb_serial_register(&keyspan_pre_device);
205 if (retval)
206 goto failed_pre_device_register;
207 retval = usb_serial_register(&keyspan_1port_device);
208 if (retval)
209 goto failed_1port_device_register;
210 retval = usb_serial_register(&keyspan_2port_device);
211 if (retval)
212 goto failed_2port_device_register;
213 retval = usb_serial_register(&keyspan_4port_device);
214 if (retval)
215 goto failed_4port_device_register;
216 retval = usb_register(&keyspan_driver);
Alan Coxdeb91682008-07-22 11:13:08 +0100217 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 goto failed_usb_register;
219
220 info(DRIVER_VERSION ":" DRIVER_DESC);
221
222 return 0;
223failed_usb_register:
224 usb_serial_deregister(&keyspan_4port_device);
225failed_4port_device_register:
226 usb_serial_deregister(&keyspan_2port_device);
227failed_2port_device_register:
228 usb_serial_deregister(&keyspan_1port_device);
229failed_1port_device_register:
230 usb_serial_deregister(&keyspan_pre_device);
231failed_pre_device_register:
232 return retval;
233}
234
Alan Coxdeb91682008-07-22 11:13:08 +0100235static void __exit keyspan_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{
Alan Coxdeb91682008-07-22 11:13:08 +0100237 usb_deregister(&keyspan_driver);
238 usb_serial_deregister(&keyspan_pre_device);
239 usb_serial_deregister(&keyspan_1port_device);
240 usb_serial_deregister(&keyspan_2port_device);
241 usb_serial_deregister(&keyspan_4port_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242}
243
244module_init(keyspan_init);
245module_exit(keyspan_exit);
246
Alan Cox95da3102008-07-22 11:09:07 +0100247static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
Alan Cox95da3102008-07-22 11:09:07 +0100249 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 struct keyspan_port_private *p_priv;
251
Alan Coxdeb91682008-07-22 11:13:08 +0100252 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
254 p_priv = usb_get_serial_port_data(port);
255
256 if (break_state == -1)
257 p_priv->break_on = 1;
258 else
259 p_priv->break_on = 0;
260
261 keyspan_send_setup(port, 0);
262}
263
264
Alan Coxdeb91682008-07-22 11:13:08 +0100265static void keyspan_set_termios(struct tty_struct *tty,
Alan Cox95da3102008-07-22 11:09:07 +0100266 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267{
268 int baud_rate, device_port;
269 struct keyspan_port_private *p_priv;
270 const struct keyspan_device_details *d_details;
271 unsigned int cflag;
272
Harvey Harrison441b62c2008-03-03 16:08:34 -0800273 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275 p_priv = usb_get_serial_port_data(port);
276 d_details = p_priv->device_details;
Alan Cox74240b02007-10-18 01:24:20 -0700277 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 device_port = port->number - port->serial->minor;
279
280 /* Baud rate calculation takes baud rate as an integer
281 so other rates can be generated if desired. */
Alan Cox74240b02007-10-18 01:24:20 -0700282 baud_rate = tty_get_baud_rate(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100283 /* If no match or invalid, don't change */
Alan Cox74240b02007-10-18 01:24:20 -0700284 if (d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
286 /* FIXME - more to do here to ensure rate changes cleanly */
Alan Cox74240b02007-10-18 01:24:20 -0700287 /* FIXME - calcuate exact rate from divisor ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 p_priv->baud = baud_rate;
Alan Cox74240b02007-10-18 01:24:20 -0700289 } else
290 baud_rate = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Alan Cox74240b02007-10-18 01:24:20 -0700292 tty_encode_baud_rate(tty, baud_rate, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 /* set CTS/RTS handshake etc. */
294 p_priv->cflag = cflag;
295 p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;
296
Alan Cox74240b02007-10-18 01:24:20 -0700297 /* Mark/Space not supported */
298 tty->termios->c_cflag &= ~CMSPAR;
299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 keyspan_send_setup(port, 0);
301}
302
Alan Cox95da3102008-07-22 11:09:07 +0100303static int keyspan_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
Alan Cox95da3102008-07-22 11:09:07 +0100305 struct usb_serial_port *port = tty->driver_data;
306 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 unsigned int value;
Alan Coxdeb91682008-07-22 11:13:08 +0100308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
310 ((p_priv->dtr_state) ? TIOCM_DTR : 0) |
311 ((p_priv->cts_state) ? TIOCM_CTS : 0) |
312 ((p_priv->dsr_state) ? TIOCM_DSR : 0) |
313 ((p_priv->dcd_state) ? TIOCM_CAR : 0) |
Alan Coxdeb91682008-07-22 11:13:08 +0100314 ((p_priv->ri_state) ? TIOCM_RNG : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 return value;
317}
318
Alan Cox95da3102008-07-22 11:09:07 +0100319static int keyspan_tiocmset(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 unsigned int set, unsigned int clear)
321{
Alan Cox95da3102008-07-22 11:09:07 +0100322 struct usb_serial_port *port = tty->driver_data;
323 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100324
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 if (set & TIOCM_RTS)
326 p_priv->rts_state = 1;
327 if (set & TIOCM_DTR)
328 p_priv->dtr_state = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 if (clear & TIOCM_RTS)
330 p_priv->rts_state = 0;
331 if (clear & TIOCM_DTR)
332 p_priv->dtr_state = 0;
333 keyspan_send_setup(port, 0);
334 return 0;
335}
336
Alan Cox95da3102008-07-22 11:09:07 +0100337/* Write function is similar for the four protocols used
338 with only a minor change for usa90 (usa19hs) required */
339static int keyspan_write(struct tty_struct *tty,
340 struct usb_serial_port *port, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
342 struct keyspan_port_private *p_priv;
343 const struct keyspan_device_details *d_details;
344 int flip;
345 int left, todo;
346 struct urb *this_urb;
Alan Coxdeb91682008-07-22 11:13:08 +0100347 int err, maxDataLen, dataOffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 p_priv = usb_get_serial_port_data(port);
350 d_details = p_priv->device_details;
351
352 if (d_details->msg_format == msg_usa90) {
Alan Coxdeb91682008-07-22 11:13:08 +0100353 maxDataLen = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 dataOffset = 0;
355 } else {
356 maxDataLen = 63;
357 dataOffset = 1;
358 }
Alan Coxdeb91682008-07-22 11:13:08 +0100359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 dbg("%s - for port %d (%d chars), flip=%d",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800361 __func__, port->number, count, p_priv->out_flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363 for (left = count; left > 0; left -= todo) {
364 todo = left;
365 if (todo > maxDataLen)
366 todo = maxDataLen;
367
368 flip = p_priv->out_flip;
Alan Coxdeb91682008-07-22 11:13:08 +0100369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 /* Check we have a valid urb/endpoint before we use it... */
Alan Coxdeb91682008-07-22 11:13:08 +0100371 this_urb = p_priv->out_urbs[flip];
372 if (this_urb == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 /* no bulk out, so return 0 bytes written */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800374 dbg("%s - no output urb :(", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 return count;
376 }
377
Alan Coxdeb91682008-07-22 11:13:08 +0100378 dbg("%s - endpoint %d flip %d",
379 __func__, usb_pipeendpoint(this_urb->pipe), flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
381 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +0100382 if (time_before(jiffies,
383 p_priv->tx_start_time[flip] + 10 * HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 usb_unlink_urb(this_urb);
386 break;
387 }
388
Alan Coxdeb91682008-07-22 11:13:08 +0100389 /* First byte in buffer is "last flag" (except for usa19hx)
390 - unused so for now so set to zero */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 ((char *)this_urb->transfer_buffer)[0] = 0;
392
Alan Coxdeb91682008-07-22 11:13:08 +0100393 memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 buf += todo;
395
396 /* send the data out the bulk port */
397 this_urb->transfer_buffer_length = todo + dataOffset;
398
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 this_urb->dev = port->serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +0100400 err = usb_submit_urb(this_urb, GFP_ATOMIC);
401 if (err != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 dbg("usb_submit_urb(write bulk) failed (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 p_priv->tx_start_time[flip] = jiffies;
404
405 /* Flip for next time if usa26 or usa28 interface
406 (not used on usa49) */
407 p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
408 }
409
410 return count - left;
411}
412
David Howells7d12e782006-10-05 14:55:46 +0100413static void usa26_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414{
415 int i, err;
416 int endpoint;
417 struct usb_serial_port *port;
418 struct tty_struct *tty;
419 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700420 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Alan Coxdeb91682008-07-22 11:13:08 +0100422 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424 endpoint = usb_pipeendpoint(urb->pipe);
425
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700426 if (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 dbg("%s - nonzero status: %x on endpoint %d.",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800428 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 return;
430 }
431
Ming Leicdc97792008-02-24 18:41:47 +0800432 port = urb->context;
Alan Cox95da3102008-07-22 11:09:07 +0100433 tty = port->port.tty;
Alan Coxa5569a52008-01-21 17:18:24 -0800434 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 /* 0x80 bit is error flag */
436 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100437 /* no errors on individual bytes, only
438 possible overrun err */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100440 err = TTY_OVERRUN;
441 else
442 err = 0;
443 for (i = 1; i < urb->actual_length ; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 tty_insert_flip_char(tty, data[i], err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 } else {
446 /* some bytes had errors, every byte has status */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800447 dbg("%s - RX error!!!!", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 for (i = 0; i + 1 < urb->actual_length; i += 2) {
449 int stat = data[i], flag = 0;
450 if (stat & RXERROR_OVERRUN)
451 flag |= TTY_OVERRUN;
452 if (stat & RXERROR_FRAMING)
453 flag |= TTY_FRAME;
454 if (stat & RXERROR_PARITY)
455 flag |= TTY_PARITY;
456 /* XXX should handle break (0x10) */
457 tty_insert_flip_char(tty, data[i+1], flag);
458 }
459 }
460 tty_flip_buffer_push(tty);
461 }
Alan Coxdeb91682008-07-22 11:13:08 +0100462
463 /* Resubmit urb so we continue receiving */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 urb->dev = port->serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +0100465 if (port->port.count) {
466 err = usb_submit_urb(urb, GFP_ATOMIC);
467 if (err != 0)
468 dbg("%s - resubmit read urb failed. (%d)",
469 __func__, err);
470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 return;
472}
473
Alan Coxdeb91682008-07-22 11:13:08 +0100474/* Outdat handling is common for all devices */
David Howells7d12e782006-10-05 14:55:46 +0100475static void usa2x_outdat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
477 struct usb_serial_port *port;
478 struct keyspan_port_private *p_priv;
479
Ming Leicdc97792008-02-24 18:41:47 +0800480 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100482 dbg("%s - urb %d", __func__, urb == p_priv->out_urbs[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Alan Cox95da3102008-07-22 11:09:07 +0100484 if (port->port.count)
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700485 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486}
487
David Howells7d12e782006-10-05 14:55:46 +0100488static void usa26_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489{
Alan Coxdeb91682008-07-22 11:13:08 +0100490 dbg("%s", __func__);
491
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493
David Howells7d12e782006-10-05 14:55:46 +0100494static void usa26_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
496 struct usb_serial_port *port;
497 struct keyspan_port_private *p_priv;
498
Ming Leicdc97792008-02-24 18:41:47 +0800499 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 p_priv = usb_get_serial_port_data(port);
501
502 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +0100503 dbg("%s - sending setup", __func__);
504 keyspan_usa26_send_setup(port->serial, port,
505 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 }
507}
508
David Howells7d12e782006-10-05 14:55:46 +0100509static void usa26_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
511 unsigned char *data = urb->transfer_buffer;
512 struct keyspan_usa26_portStatusMessage *msg;
513 struct usb_serial *serial;
514 struct usb_serial_port *port;
515 struct keyspan_port_private *p_priv;
516 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700517 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Ming Leicdc97792008-02-24 18:41:47 +0800519 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700521 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800522 dbg("%s - nonzero status: %x", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 return;
524 }
525 if (urb->actual_length != 9) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800526 dbg("%s - %d byte report??", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 goto exit;
528 }
529
530 msg = (struct keyspan_usa26_portStatusMessage *)data;
531
532#if 0
533 dbg("%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800534 __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 msg->_txXoff, msg->rxEnabled, msg->controlResponse);
536#endif
537
538 /* Now do something useful with the data */
539
540
Alan Coxdeb91682008-07-22 11:13:08 +0100541 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (msg->port >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +0100543 dbg("%s - Unexpected port number %d", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 goto exit;
545 }
546 port = serial->port[msg->port];
547 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100548
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 /* Update handshaking pin state information */
550 old_dcd_state = p_priv->dcd_state;
551 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
552 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
553 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
554 p_priv->ri_state = ((msg->ri) ? 1 : 0);
555
Alan Cox95da3102008-07-22 11:09:07 +0100556 if (port->port.tty && !C_CLOCAL(port->port.tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 && old_dcd_state != p_priv->dcd_state) {
558 if (old_dcd_state)
Alan Cox95da3102008-07-22 11:09:07 +0100559 tty_hangup(port->port.tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 /* else */
561 /* wake_up_interruptible(&p_priv->open_wait); */
562 }
Alan Coxdeb91682008-07-22 11:13:08 +0100563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 /* Resubmit urb so we continue receiving */
565 urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +0100566 err = usb_submit_urb(urb, GFP_ATOMIC);
567 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800568 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569exit: ;
570}
571
David Howells7d12e782006-10-05 14:55:46 +0100572static void usa26_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
Alan Coxdeb91682008-07-22 11:13:08 +0100574 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575}
576
577
David Howells7d12e782006-10-05 14:55:46 +0100578static void usa28_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
580 int i, err;
581 struct usb_serial_port *port;
582 struct tty_struct *tty;
583 unsigned char *data;
584 struct keyspan_port_private *p_priv;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700585 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Alan Coxdeb91682008-07-22 11:13:08 +0100587 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Ming Leicdc97792008-02-24 18:41:47 +0800589 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 p_priv = usb_get_serial_port_data(port);
591 data = urb->transfer_buffer;
592
593 if (urb != p_priv->in_urbs[p_priv->in_flip])
594 return;
595
596 do {
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700597 if (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 dbg("%s - nonzero status: %x on endpoint %d.",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800599 __func__, status, usb_pipeendpoint(urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 return;
601 }
602
Ming Leicdc97792008-02-24 18:41:47 +0800603 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 p_priv = usb_get_serial_port_data(port);
605 data = urb->transfer_buffer;
606
Alan Cox95da3102008-07-22 11:09:07 +0100607 tty = port->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 if (urb->actual_length) {
Alan Coxdeb91682008-07-22 11:13:08 +0100609 for (i = 0; i < urb->actual_length ; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 tty_insert_flip_char(tty, data[i], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 tty_flip_buffer_push(tty);
612 }
613
614 /* Resubmit urb so we continue receiving */
615 urb->dev = port->serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +0100616 if (port->port.count) {
617 err = usb_submit_urb(urb, GFP_ATOMIC);
618 if (err != 0)
619 dbg("%s - resubmit read urb failed. (%d)",
620 __func__, err);
621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 p_priv->in_flip ^= 1;
623
624 urb = p_priv->in_urbs[p_priv->in_flip];
625 } while (urb->status != -EINPROGRESS);
626}
627
David Howells7d12e782006-10-05 14:55:46 +0100628static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
Alan Coxdeb91682008-07-22 11:13:08 +0100630 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632
David Howells7d12e782006-10-05 14:55:46 +0100633static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
635 struct usb_serial_port *port;
636 struct keyspan_port_private *p_priv;
637
Ming Leicdc97792008-02-24 18:41:47 +0800638 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 p_priv = usb_get_serial_port_data(port);
640
641 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +0100642 dbg("%s - sending setup", __func__);
643 keyspan_usa28_send_setup(port->serial, port,
644 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
646}
647
David Howells7d12e782006-10-05 14:55:46 +0100648static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649{
650 int err;
651 unsigned char *data = urb->transfer_buffer;
652 struct keyspan_usa28_portStatusMessage *msg;
653 struct usb_serial *serial;
654 struct usb_serial_port *port;
655 struct keyspan_port_private *p_priv;
656 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700657 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Ming Leicdc97792008-02-24 18:41:47 +0800659 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700661 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800662 dbg("%s - nonzero status: %x", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 return;
664 }
665
666 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800667 dbg("%s - bad length %d", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 goto exit;
669 }
670
Harvey Harrison441b62c2008-03-03 16:08:34 -0800671 /*dbg("%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 data[0], data[1], data[2], data[3], data[4], data[5],
673 data[6], data[7], data[8], data[9], data[10], data[11]);*/
Alan Coxdeb91682008-07-22 11:13:08 +0100674
675 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 msg = (struct keyspan_usa28_portStatusMessage *)data;
677
Alan Coxdeb91682008-07-22 11:13:08 +0100678 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (msg->port >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +0100680 dbg("%s - Unexpected port number %d", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 goto exit;
682 }
683 port = serial->port[msg->port];
684 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100685
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 /* Update handshaking pin state information */
687 old_dcd_state = p_priv->dcd_state;
688 p_priv->cts_state = ((msg->cts) ? 1 : 0);
689 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
690 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
691 p_priv->ri_state = ((msg->ri) ? 1 : 0);
692
Alan Cox95da3102008-07-22 11:09:07 +0100693 if (port->port.tty && !C_CLOCAL(port->port.tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 && old_dcd_state != p_priv->dcd_state) {
695 if (old_dcd_state)
Alan Cox95da3102008-07-22 11:09:07 +0100696 tty_hangup(port->port.tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 /* else */
698 /* wake_up_interruptible(&p_priv->open_wait); */
699 }
700
701 /* Resubmit urb so we continue receiving */
702 urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +0100703 err = usb_submit_urb(urb, GFP_ATOMIC);
704 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800705 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706exit: ;
707}
708
David Howells7d12e782006-10-05 14:55:46 +0100709static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
Alan Coxdeb91682008-07-22 11:13:08 +0100711 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712}
713
714
David Howells7d12e782006-10-05 14:55:46 +0100715static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716{
717 struct usb_serial *serial;
718 struct usb_serial_port *port;
719 struct keyspan_port_private *p_priv;
720 int i;
721
Alan Coxdeb91682008-07-22 11:13:08 +0100722 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Ming Leicdc97792008-02-24 18:41:47 +0800724 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 for (i = 0; i < serial->num_ports; ++i) {
726 port = serial->port[i];
727 p_priv = usb_get_serial_port_data(port);
728
729 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +0100730 dbg("%s - sending setup", __func__);
731 keyspan_usa49_send_setup(serial, port,
732 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 break;
734 }
735 }
736}
737
738 /* This is actually called glostat in the Keyspan
739 doco */
David Howells7d12e782006-10-05 14:55:46 +0100740static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
742 int err;
743 unsigned char *data = urb->transfer_buffer;
744 struct keyspan_usa49_portStatusMessage *msg;
745 struct usb_serial *serial;
746 struct usb_serial_port *port;
747 struct keyspan_port_private *p_priv;
748 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700749 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Alan Coxdeb91682008-07-22 11:13:08 +0100751 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Ming Leicdc97792008-02-24 18:41:47 +0800753 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700755 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800756 dbg("%s - nonzero status: %x", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 return;
758 }
759
Alan Coxdeb91682008-07-22 11:13:08 +0100760 if (urb->actual_length !=
761 sizeof(struct keyspan_usa49_portStatusMessage)) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800762 dbg("%s - bad length %d", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 goto exit;
764 }
765
Harvey Harrison441b62c2008-03-03 16:08:34 -0800766 /*dbg(" %x %x %x %x %x %x %x %x %x %x %x", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 data[0], data[1], data[2], data[3], data[4], data[5],
768 data[6], data[7], data[8], data[9], data[10]);*/
Alan Coxdeb91682008-07-22 11:13:08 +0100769
770 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 msg = (struct keyspan_usa49_portStatusMessage *)data;
772
Alan Coxdeb91682008-07-22 11:13:08 +0100773 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 if (msg->portNumber >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +0100775 dbg("%s - Unexpected port number %d",
776 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 goto exit;
778 }
779 port = serial->port[msg->portNumber];
780 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 /* Update handshaking pin state information */
783 old_dcd_state = p_priv->dcd_state;
784 p_priv->cts_state = ((msg->cts) ? 1 : 0);
785 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
786 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
787 p_priv->ri_state = ((msg->ri) ? 1 : 0);
788
Alan Cox95da3102008-07-22 11:09:07 +0100789 if (port->port.tty && !C_CLOCAL(port->port.tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 && old_dcd_state != p_priv->dcd_state) {
791 if (old_dcd_state)
Alan Cox95da3102008-07-22 11:09:07 +0100792 tty_hangup(port->port.tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 /* else */
794 /* wake_up_interruptible(&p_priv->open_wait); */
795 }
796
Alan Coxdeb91682008-07-22 11:13:08 +0100797 /* Resubmit urb so we continue receiving */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 urb->dev = serial->dev;
799
Alan Coxdeb91682008-07-22 11:13:08 +0100800 err = usb_submit_urb(urb, GFP_ATOMIC);
801 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800802 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803exit: ;
804}
805
David Howells7d12e782006-10-05 14:55:46 +0100806static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807{
Alan Coxdeb91682008-07-22 11:13:08 +0100808 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809}
810
David Howells7d12e782006-10-05 14:55:46 +0100811static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812{
813 int i, err;
814 int endpoint;
815 struct usb_serial_port *port;
816 struct tty_struct *tty;
817 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700818 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Alan Coxdeb91682008-07-22 11:13:08 +0100820 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
822 endpoint = usb_pipeendpoint(urb->pipe);
823
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700824 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800825 dbg("%s - nonzero status: %x on endpoint %d.", __func__,
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700826 status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 return;
828 }
829
Ming Leicdc97792008-02-24 18:41:47 +0800830 port = urb->context;
Alan Cox95da3102008-07-22 11:09:07 +0100831 tty = port->port.tty;
Alan Cox3004e532008-01-03 16:59:04 +0000832 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 /* 0x80 bit is error flag */
834 if ((data[0] & 0x80) == 0) {
835 /* no error on any byte */
Alan Coxdeb91682008-07-22 11:13:08 +0100836 for (i = 1; i < urb->actual_length ; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 tty_insert_flip_char(tty, data[i], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 } else {
839 /* some bytes had errors, every byte has status */
840 for (i = 0; i + 1 < urb->actual_length; i += 2) {
841 int stat = data[i], flag = 0;
842 if (stat & RXERROR_OVERRUN)
843 flag |= TTY_OVERRUN;
844 if (stat & RXERROR_FRAMING)
845 flag |= TTY_FRAME;
846 if (stat & RXERROR_PARITY)
847 flag |= TTY_PARITY;
848 /* XXX should handle break (0x10) */
849 tty_insert_flip_char(tty, data[i+1], flag);
850 }
851 }
852 tty_flip_buffer_push(tty);
853 }
Alan Coxdeb91682008-07-22 11:13:08 +0100854
855 /* Resubmit urb so we continue receiving */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 urb->dev = port->serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +0100857 if (port->port.count) {
858 err = usb_submit_urb(urb, GFP_ATOMIC);
859 if (err != 0)
860 dbg("%s - resubmit read urb failed. (%d)",
861 __func__, err);
862 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863}
864
Lucy McCoy0ca12682007-05-18 12:10:41 -0700865static void usa49wg_indat_callback(struct urb *urb)
866{
867 int i, len, x, err;
868 struct usb_serial *serial;
869 struct usb_serial_port *port;
870 struct tty_struct *tty;
871 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700872 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700873
Alan Coxdeb91682008-07-22 11:13:08 +0100874 dbg("%s", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700875
876 serial = urb->context;
877
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700878 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800879 dbg("%s - nonzero status: %x", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700880 return;
881 }
882
883 /* inbound data is in the form P#, len, status, data */
884 i = 0;
885 len = 0;
886
887 if (urb->actual_length) {
888 while (i < urb->actual_length) {
889
890 /* Check port number from message*/
891 if (data[i] >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +0100892 dbg("%s - Unexpected port number %d",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800893 __func__, data[i]);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700894 return;
895 }
896 port = serial->port[data[i++]];
Alan Cox95da3102008-07-22 11:09:07 +0100897 tty = port->port.tty;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700898 len = data[i++];
899
900 /* 0x80 bit is error flag */
901 if ((data[i] & 0x80) == 0) {
902 /* no error on any byte */
903 i++;
904 for (x = 1; x < len ; ++x)
Alan Cox95da3102008-07-22 11:09:07 +0100905 if (port->port.count)
Lucy McCoy0ca12682007-05-18 12:10:41 -0700906 tty_insert_flip_char(tty,
907 data[i++], 0);
908 else
909 i++;
910 } else {
911 /*
912 * some bytes had errors, every byte has status
913 */
914 for (x = 0; x + 1 < len; x += 2) {
915 int stat = data[i], flag = 0;
916 if (stat & RXERROR_OVERRUN)
917 flag |= TTY_OVERRUN;
918 if (stat & RXERROR_FRAMING)
919 flag |= TTY_FRAME;
920 if (stat & RXERROR_PARITY)
921 flag |= TTY_PARITY;
922 /* XXX should handle break (0x10) */
Alan Cox95da3102008-07-22 11:09:07 +0100923 if (port->port.count)
Lucy McCoy0ca12682007-05-18 12:10:41 -0700924 tty_insert_flip_char(tty,
925 data[i+1], flag);
926 i += 2;
927 }
928 }
Alan Cox95da3102008-07-22 11:09:07 +0100929 if (port->port.count)
Lucy McCoy0ca12682007-05-18 12:10:41 -0700930 tty_flip_buffer_push(tty);
931 }
932 }
933
934 /* Resubmit urb so we continue receiving */
935 urb->dev = serial->dev;
936
937 err = usb_submit_urb(urb, GFP_ATOMIC);
938 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800939 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700940}
941
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700943static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944{
Alan Coxdeb91682008-07-22 11:13:08 +0100945 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946}
947
Lucy McCoy0ca12682007-05-18 12:10:41 -0700948static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949{
950 int i, err;
951 int endpoint;
952 struct usb_serial_port *port;
953 struct keyspan_port_private *p_priv;
954 struct tty_struct *tty;
955 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700956 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Alan Coxdeb91682008-07-22 11:13:08 +0100958 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 endpoint = usb_pipeendpoint(urb->pipe);
961
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700962 if (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 dbg("%s - nonzero status: %x on endpoint %d.",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800964 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 return;
966 }
967
Ming Leicdc97792008-02-24 18:41:47 +0800968 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 p_priv = usb_get_serial_port_data(port);
970
Alan Cox95da3102008-07-22 11:09:07 +0100971 tty = port->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100974 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976 if (p_priv->baud > 57600) {
Alan Coxdeb91682008-07-22 11:13:08 +0100977 for (i = 0; i < urb->actual_length ; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 tty_insert_flip_char(tty, data[i], 0);
Alan Coxdeb91682008-07-22 11:13:08 +0100979 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 /* 0x80 bit is error flag */
981 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100982 /* no errors on individual bytes, only
983 possible overrun err*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100985 err = TTY_OVERRUN;
986 else
987 err = 0;
988 for (i = 1; i < urb->actual_length ; ++i)
989 tty_insert_flip_char(tty, data[i],
990 err);
991 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 /* some bytes had errors, every byte has status */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800993 dbg("%s - RX error!!!!", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 for (i = 0; i + 1 < urb->actual_length; i += 2) {
995 int stat = data[i], flag = 0;
996 if (stat & RXERROR_OVERRUN)
997 flag |= TTY_OVERRUN;
998 if (stat & RXERROR_FRAMING)
999 flag |= TTY_FRAME;
1000 if (stat & RXERROR_PARITY)
1001 flag |= TTY_PARITY;
1002 /* XXX should handle break (0x10) */
Alan Coxdeb91682008-07-22 11:13:08 +01001003 tty_insert_flip_char(tty, data[i+1],
1004 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 }
1006 }
1007 }
1008 tty_flip_buffer_push(tty);
1009 }
Alan Coxdeb91682008-07-22 11:13:08 +01001010
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 /* Resubmit urb so we continue receiving */
1012 urb->dev = port->serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +01001013 if (port->port.count) {
1014 err = usb_submit_urb(urb, GFP_ATOMIC);
1015 if (err != 0)
1016 dbg("%s - resubmit read urb failed. (%d)",
1017 __func__, err);
1018 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return;
1020}
1021
1022
David Howells7d12e782006-10-05 14:55:46 +01001023static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
1025 unsigned char *data = urb->transfer_buffer;
1026 struct keyspan_usa90_portStatusMessage *msg;
1027 struct usb_serial *serial;
1028 struct usb_serial_port *port;
1029 struct keyspan_port_private *p_priv;
1030 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -07001031 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Ming Leicdc97792008-02-24 18:41:47 +08001033 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -07001035 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001036 dbg("%s - nonzero status: %x", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 return;
1038 }
1039 if (urb->actual_length < 14) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001040 dbg("%s - %d byte report??", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 goto exit;
1042 }
1043
1044 msg = (struct keyspan_usa90_portStatusMessage *)data;
1045
1046 /* Now do something useful with the data */
1047
1048 port = serial->port[0];
1049 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001050
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 /* Update handshaking pin state information */
1052 old_dcd_state = p_priv->dcd_state;
1053 p_priv->cts_state = ((msg->cts) ? 1 : 0);
1054 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
1055 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
1056 p_priv->ri_state = ((msg->ri) ? 1 : 0);
1057
Alan Cox95da3102008-07-22 11:09:07 +01001058 if (port->port.tty && !C_CLOCAL(port->port.tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 && old_dcd_state != p_priv->dcd_state) {
1060 if (old_dcd_state)
Alan Cox95da3102008-07-22 11:09:07 +01001061 tty_hangup(port->port.tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 /* else */
1063 /* wake_up_interruptible(&p_priv->open_wait); */
1064 }
Alan Coxdeb91682008-07-22 11:13:08 +01001065
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 /* Resubmit urb so we continue receiving */
1067 urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +01001068 err = usb_submit_urb(urb, GFP_ATOMIC);
1069 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08001070 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071exit:
1072 ;
1073}
1074
David Howells7d12e782006-10-05 14:55:46 +01001075static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076{
1077 struct usb_serial_port *port;
1078 struct keyspan_port_private *p_priv;
1079
Ming Leicdc97792008-02-24 18:41:47 +08001080 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 p_priv = usb_get_serial_port_data(port);
1082
1083 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +01001084 dbg("%s - sending setup", __func__);
1085 keyspan_usa90_send_setup(port->serial, port,
1086 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 }
1088}
1089
Lucy McCoy0ca12682007-05-18 12:10:41 -07001090/* Status messages from the 28xg */
1091static void usa67_instat_callback(struct urb *urb)
1092{
1093 int err;
1094 unsigned char *data = urb->transfer_buffer;
1095 struct keyspan_usa67_portStatusMessage *msg;
1096 struct usb_serial *serial;
1097 struct usb_serial_port *port;
1098 struct keyspan_port_private *p_priv;
1099 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -07001100 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001101
Alan Coxdeb91682008-07-22 11:13:08 +01001102 dbg("%s", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001103
1104 serial = urb->context;
1105
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -07001106 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001107 dbg("%s - nonzero status: %x", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001108 return;
1109 }
1110
Alan Coxdeb91682008-07-22 11:13:08 +01001111 if (urb->actual_length !=
1112 sizeof(struct keyspan_usa67_portStatusMessage)) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001113 dbg("%s - bad length %d", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001114 return;
1115 }
1116
1117
1118 /* Now do something useful with the data */
1119 msg = (struct keyspan_usa67_portStatusMessage *)data;
1120
1121 /* Check port number from message and retrieve private data */
1122 if (msg->port >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +01001123 dbg("%s - Unexpected port number %d", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001124 return;
1125 }
1126
1127 port = serial->port[msg->port];
1128 p_priv = usb_get_serial_port_data(port);
1129
1130 /* Update handshaking pin state information */
1131 old_dcd_state = p_priv->dcd_state;
1132 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
1133 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
1134
Alan Cox95da3102008-07-22 11:09:07 +01001135 if (port->port.tty && !C_CLOCAL(port->port.tty)
Lucy McCoy0ca12682007-05-18 12:10:41 -07001136 && old_dcd_state != p_priv->dcd_state) {
1137 if (old_dcd_state)
Alan Cox95da3102008-07-22 11:09:07 +01001138 tty_hangup(port->port.tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001139 /* else */
1140 /* wake_up_interruptible(&p_priv->open_wait); */
1141 }
1142
1143 /* Resubmit urb so we continue receiving */
1144 urb->dev = serial->dev;
1145 err = usb_submit_urb(urb, GFP_ATOMIC);
1146 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08001147 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001148}
1149
1150static void usa67_glocont_callback(struct urb *urb)
1151{
1152 struct usb_serial *serial;
1153 struct usb_serial_port *port;
1154 struct keyspan_port_private *p_priv;
1155 int i;
1156
Alan Coxdeb91682008-07-22 11:13:08 +01001157 dbg("%s", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001158
1159 serial = urb->context;
1160 for (i = 0; i < serial->num_ports; ++i) {
1161 port = serial->port[i];
1162 p_priv = usb_get_serial_port_data(port);
1163
1164 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +01001165 dbg("%s - sending setup", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001166 keyspan_usa67_send_setup(serial, port,
1167 p_priv->resend_cont - 1);
1168 break;
1169 }
1170 }
1171}
1172
Alan Cox95da3102008-07-22 11:09:07 +01001173static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174{
Alan Cox95da3102008-07-22 11:09:07 +01001175 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 struct keyspan_port_private *p_priv;
1177 const struct keyspan_device_details *d_details;
1178 int flip;
1179 int data_len;
1180 struct urb *this_urb;
1181
Harvey Harrison441b62c2008-03-03 16:08:34 -08001182 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 p_priv = usb_get_serial_port_data(port);
1184 d_details = p_priv->device_details;
1185
Alan Coxa5b6f602008-04-08 17:16:06 +01001186 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +01001188 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 else
1190 data_len = 63;
1191
1192 flip = p_priv->out_flip;
1193
1194 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +01001195 this_urb = p_priv->out_urbs[flip];
1196 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001198 return data_len;
1199 flip = (flip + 1) & d_details->outdat_endp_flip;
1200 this_urb = p_priv->out_urbs[flip];
1201 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001203 return data_len;
1204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 }
Alan Coxa5b6f602008-04-08 17:16:06 +01001206 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207}
1208
1209
Alan Cox95da3102008-07-22 11:09:07 +01001210static int keyspan_open(struct tty_struct *tty,
1211 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001213 struct keyspan_port_private *p_priv;
1214 struct keyspan_serial_private *s_priv;
1215 struct usb_serial *serial = port->serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 const struct keyspan_device_details *d_details;
1217 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001218 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001220 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221
1222 s_priv = usb_get_serial_data(serial);
1223 p_priv = usb_get_serial_port_data(port);
1224 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001225
Harvey Harrison441b62c2008-03-03 16:08:34 -08001226 dbg("%s - port%d.", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
1228 /* Set some sane defaults */
1229 p_priv->rts_state = 1;
1230 p_priv->dtr_state = 1;
1231 p_priv->baud = 9600;
1232
1233 /* force baud and lcr to be set on open */
1234 p_priv->old_baud = 0;
1235 p_priv->old_cflag = 0;
1236
1237 p_priv->out_flip = 0;
1238 p_priv->in_flip = 0;
1239
1240 /* Reset low level data toggle and start reading from endpoints */
1241 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001242 urb = p_priv->in_urbs[i];
1243 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 continue;
1245 urb->dev = serial->dev;
1246
Alan Coxdeb91682008-07-22 11:13:08 +01001247 /* make sure endpoint data toggle is synchronized
1248 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001250 err = usb_submit_urb(urb, GFP_KERNEL);
1251 if (err != 0)
1252 dbg("%s - submit urb %d failed (%d)",
1253 __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 }
1255
1256 /* Reset low level data toggle on out endpoints */
1257 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001258 urb = p_priv->out_urbs[i];
1259 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 continue;
1261 urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +01001262 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1263 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 }
1265
Andrew Mortonf78ba152007-11-28 16:21:54 -08001266 /* get the terminal config for the setup message now so we don't
1267 * need to send 2 of them */
1268
Andrew Mortonf78ba152007-11-28 16:21:54 -08001269 device_port = port->number - port->serial->minor;
Alan Cox95da3102008-07-22 11:09:07 +01001270 if (tty) {
1271 cflag = tty->termios->c_cflag;
1272 /* Baud rate calculation takes baud rate as an integer
1273 so other rates can be generated if desired. */
1274 baud_rate = tty_get_baud_rate(tty);
1275 /* If no match or invalid, leave as default */
1276 if (baud_rate >= 0
1277 && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
1278 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1279 p_priv->baud = baud_rate;
1280 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001281 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001282 /* set CTS/RTS handshake etc. */
1283 p_priv->cflag = cflag;
1284 p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;
1285
1286 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001287 /* mdelay(100); */
1288 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001289
Alan Coxa5b6f602008-04-08 17:16:06 +01001290 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291}
1292
1293static inline void stop_urb(struct urb *urb)
1294{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001295 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297}
1298
Alan Cox95da3102008-07-22 11:09:07 +01001299static void keyspan_close(struct tty_struct *tty,
1300 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301{
1302 int i;
1303 struct usb_serial *serial = port->serial;
1304 struct keyspan_serial_private *s_priv;
1305 struct keyspan_port_private *p_priv;
1306
Harvey Harrison441b62c2008-03-03 16:08:34 -08001307 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 s_priv = usb_get_serial_data(serial);
1309 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 p_priv->rts_state = 0;
1312 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001313
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 if (serial->dev) {
1315 keyspan_send_setup(port, 2);
1316 /* pilot-xfer seems to work best with this delay */
1317 mdelay(100);
Alan Coxdeb91682008-07-22 11:13:08 +01001318 /* keyspan_set_termios(port, NULL); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 }
1320
1321 /*while (p_priv->outcont_urb->status == -EINPROGRESS) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001322 dbg("%s - urb in progress", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 }*/
1324
1325 p_priv->out_flip = 0;
1326 p_priv->in_flip = 0;
1327
1328 if (serial->dev) {
1329 /* Stop reading/writing urbs */
1330 stop_urb(p_priv->inack_urb);
1331 /* stop_urb(p_priv->outcont_urb); */
1332 for (i = 0; i < 2; i++) {
1333 stop_urb(p_priv->in_urbs[i]);
1334 stop_urb(p_priv->out_urbs[i]);
1335 }
1336 }
Alan Cox95da3102008-07-22 11:09:07 +01001337 port->port.tty = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338}
1339
Alan Coxdeb91682008-07-22 11:13:08 +01001340/* download the firmware to a pre-renumeration device */
1341static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342{
1343 int response;
David Woodhouse2971c572008-05-30 14:04:03 +03001344 const struct ihex_binrec *record;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 char *fw_name;
David Woodhouse2971c572008-05-30 14:04:03 +03001346 const struct firmware *fw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
1348 dbg("Keyspan startup version %04x product %04x",
1349 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1350 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001351
1352 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1353 != 0x8000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 dbg("Firmware already loaded. Quitting.");
Alan Coxdeb91682008-07-22 11:13:08 +01001355 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 }
1357
1358 /* Select firmware image on the basis of idProduct */
1359 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1360 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001361 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 break;
1363
1364 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001365 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 break;
1367
1368 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001369 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 break;
1371
1372 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001373 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 break;
1375
1376 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001377 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001379
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001381 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001385 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 break;
1387
1388 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001389 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001391
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001393 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001397 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001399
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001401 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 break;
1403
1404 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001405 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 break;
1407
1408 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001409 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1410 le16_to_cpu(serial->dev->descriptor.idProduct));
1411 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 }
1413
David Woodhouse2971c572008-05-30 14:04:03 +03001414 if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 dev_err(&serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name);
1416 return(1);
1417 }
1418
1419 dbg("Uploading Keyspan %s firmware.", fw_name);
1420
1421 /* download the firmware image */
1422 response = ezusb_set_reset(serial, 1);
1423
David Woodhouse2971c572008-05-30 14:04:03 +03001424 record = (const struct ihex_binrec *)fw->data;
1425
1426 while (record) {
1427 response = ezusb_writememory(serial, be32_to_cpu(record->addr),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 (unsigned char *)record->data,
David Woodhouse2971c572008-05-30 14:04:03 +03001429 be16_to_cpu(record->len), 0xa0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 if (response < 0) {
Alan Coxdeb91682008-07-22 11:13:08 +01001431 dev_err(&serial->dev->dev, "ezusb_writememory failed for Keyspan firmware (%d %04X %p %d)\n",
David Woodhouse2971c572008-05-30 14:04:03 +03001432 response, be32_to_cpu(record->addr),
1433 record->data, be16_to_cpu(record->len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 break;
1435 }
David Woodhouse2971c572008-05-30 14:04:03 +03001436 record = ihex_next_binrec(record);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 }
David Woodhouse2971c572008-05-30 14:04:03 +03001438 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 /* bring device out of reset. Renumeration will occur in a
1440 moment and the new device will bind to the real driver */
1441 response = ezusb_set_reset(serial, 0);
1442
1443 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001444 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445}
1446
1447/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001448static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1449 int endpoint)
1450{
1451 struct usb_host_interface *iface_desc;
1452 struct usb_endpoint_descriptor *ep;
1453 int i;
1454
1455 iface_desc = serial->interface->cur_altsetting;
1456 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1457 ep = &iface_desc->endpoint[i].desc;
1458 if (ep->bEndpointAddress == endpoint)
1459 return ep;
1460 }
1461 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1462 "endpoint %x\n", endpoint);
1463 return NULL;
1464}
1465
Alan Coxdeb91682008-07-22 11:13:08 +01001466static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001468 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469{
1470 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001471 struct usb_endpoint_descriptor const *ep_desc;
1472 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
1474 if (endpoint == -1)
1475 return NULL; /* endpoint not needed */
1476
Alan Coxdeb91682008-07-22 11:13:08 +01001477 dbg("%s - alloc for endpoint %d.", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
1479 if (urb == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01001480 dbg("%s - alloc for endpoint %d failed.", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 return NULL;
1482 }
1483
Lucy McCoy0ca12682007-05-18 12:10:41 -07001484 if (endpoint == 0) {
1485 /* control EP filled in when used */
1486 return urb;
1487 }
1488
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001489 ep_desc = find_ep(serial, endpoint);
1490 if (!ep_desc) {
1491 /* leak the urb, something's wrong and the callers don't care */
1492 return urb;
1493 }
1494 if (usb_endpoint_xfer_int(ep_desc)) {
1495 ep_type_name = "INT";
1496 usb_fill_int_urb(urb, serial->dev,
1497 usb_sndintpipe(serial->dev, endpoint) | dir,
1498 buf, len, callback, ctx,
1499 ep_desc->bInterval);
1500 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1501 ep_type_name = "BULK";
1502 usb_fill_bulk_urb(urb, serial->dev,
1503 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1504 buf, len, callback, ctx);
1505 } else {
1506 dev_warn(&serial->interface->dev,
1507 "unsupported endpoint type %x\n",
1508 ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
1509 usb_free_urb(urb);
1510 return NULL;
1511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001513 dbg("%s - using urb %p for %s endpoint %x",
1514 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 return urb;
1516}
1517
1518static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001519 void (*instat_callback)(struct urb *);
1520 void (*glocont_callback)(struct urb *);
1521 void (*indat_callback)(struct urb *);
1522 void (*outdat_callback)(struct urb *);
1523 void (*inack_callback)(struct urb *);
1524 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525} keyspan_callbacks[] = {
1526 {
1527 /* msg_usa26 callbacks */
1528 .instat_callback = usa26_instat_callback,
1529 .glocont_callback = usa26_glocont_callback,
1530 .indat_callback = usa26_indat_callback,
1531 .outdat_callback = usa2x_outdat_callback,
1532 .inack_callback = usa26_inack_callback,
1533 .outcont_callback = usa26_outcont_callback,
1534 }, {
1535 /* msg_usa28 callbacks */
1536 .instat_callback = usa28_instat_callback,
1537 .glocont_callback = usa28_glocont_callback,
1538 .indat_callback = usa28_indat_callback,
1539 .outdat_callback = usa2x_outdat_callback,
1540 .inack_callback = usa28_inack_callback,
1541 .outcont_callback = usa28_outcont_callback,
1542 }, {
1543 /* msg_usa49 callbacks */
1544 .instat_callback = usa49_instat_callback,
1545 .glocont_callback = usa49_glocont_callback,
1546 .indat_callback = usa49_indat_callback,
1547 .outdat_callback = usa2x_outdat_callback,
1548 .inack_callback = usa49_inack_callback,
1549 .outcont_callback = usa49_outcont_callback,
1550 }, {
1551 /* msg_usa90 callbacks */
1552 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001553 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 .indat_callback = usa90_indat_callback,
1555 .outdat_callback = usa2x_outdat_callback,
1556 .inack_callback = usa28_inack_callback,
1557 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001558 }, {
1559 /* msg_usa67 callbacks */
1560 .instat_callback = usa67_instat_callback,
1561 .glocont_callback = usa67_glocont_callback,
1562 .indat_callback = usa26_indat_callback,
1563 .outdat_callback = usa2x_outdat_callback,
1564 .inack_callback = usa26_inack_callback,
1565 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 }
1567};
1568
1569 /* Generic setup urbs function that uses
1570 data in device_details */
1571static void keyspan_setup_urbs(struct usb_serial *serial)
1572{
1573 int i, j;
1574 struct keyspan_serial_private *s_priv;
1575 const struct keyspan_device_details *d_details;
1576 struct usb_serial_port *port;
1577 struct keyspan_port_private *p_priv;
1578 struct callbacks *cback;
1579 int endp;
1580
Alan Coxdeb91682008-07-22 11:13:08 +01001581 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
1583 s_priv = usb_get_serial_data(serial);
1584 d_details = s_priv->device_details;
1585
Alan Coxdeb91682008-07-22 11:13:08 +01001586 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 cback = &keyspan_callbacks[d_details->msg_format];
1588
Alan Coxdeb91682008-07-22 11:13:08 +01001589 /* Allocate and set up urbs for each one that is in use,
1590 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 s_priv->instat_urb = keyspan_setup_urb
1592 (serial, d_details->instat_endpoint, USB_DIR_IN,
1593 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1594 cback->instat_callback);
1595
Lucy McCoy0ca12682007-05-18 12:10:41 -07001596 s_priv->indat_urb = keyspan_setup_urb
1597 (serial, d_details->indat_endpoint, USB_DIR_IN,
1598 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1599 usa49wg_indat_callback);
1600
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 s_priv->glocont_urb = keyspan_setup_urb
1602 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1603 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1604 cback->glocont_callback);
1605
Alan Coxdeb91682008-07-22 11:13:08 +01001606 /* Setup endpoints for each port specific thing */
1607 for (i = 0; i < d_details->num_ports; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 port = serial->port[i];
1609 p_priv = usb_get_serial_port_data(port);
1610
1611 /* Do indat endpoints first, once for each flip */
1612 endp = d_details->indat_endpoints[i];
1613 for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) {
1614 p_priv->in_urbs[j] = keyspan_setup_urb
1615 (serial, endp, USB_DIR_IN, port,
1616 p_priv->in_buffer[j], 64,
1617 cback->indat_callback);
1618 }
1619 for (; j < 2; ++j)
1620 p_priv->in_urbs[j] = NULL;
1621
1622 /* outdat endpoints also have flip */
1623 endp = d_details->outdat_endpoints[i];
1624 for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) {
1625 p_priv->out_urbs[j] = keyspan_setup_urb
1626 (serial, endp, USB_DIR_OUT, port,
1627 p_priv->out_buffer[j], 64,
1628 cback->outdat_callback);
1629 }
1630 for (; j < 2; ++j)
1631 p_priv->out_urbs[j] = NULL;
1632
1633 /* inack endpoint */
1634 p_priv->inack_urb = keyspan_setup_urb
1635 (serial, d_details->inack_endpoints[i], USB_DIR_IN,
1636 port, p_priv->inack_buffer, 1, cback->inack_callback);
1637
1638 /* outcont endpoint */
1639 p_priv->outcont_urb = keyspan_setup_urb
1640 (serial, d_details->outcont_endpoints[i], USB_DIR_OUT,
1641 port, p_priv->outcont_buffer, 64,
1642 cback->outcont_callback);
Alan Coxdeb91682008-07-22 11:13:08 +01001643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644}
1645
1646/* usa19 function doesn't require prescaler */
1647static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
1648 u8 *rate_low, u8 *prescaler, int portnum)
1649{
1650 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001651 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
Alan Coxdeb91682008-07-22 11:13:08 +01001654 dbg("%s - %d.", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
Alan Coxdeb91682008-07-22 11:13:08 +01001656 /* prevent divide by zero... */
1657 b16 = baud_rate * 16L;
1658 if (b16 == 0)
1659 return KEYSPAN_INVALID_BAUD_RATE;
1660 /* Any "standard" rate over 57k6 is marginal on the USA-19
1661 as we run out of divisor resolution. */
1662 if (baud_rate > 57600)
1663 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
Alan Coxdeb91682008-07-22 11:13:08 +01001665 /* calculate the divisor and the counter (its inverse) */
1666 div = baudclk / b16;
1667 if (div == 0)
1668 return KEYSPAN_INVALID_BAUD_RATE;
1669 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
Alan Coxdeb91682008-07-22 11:13:08 +01001672 if (div > 0xffff)
1673 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
Alan Coxdeb91682008-07-22 11:13:08 +01001675 /* return the counter values if non-null */
1676 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001678 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001680 if (rate_low && rate_hi)
1681 dbg("%s - %d %02x %02x.",
1682 __func__, baud_rate, *rate_hi, *rate_low);
1683 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684}
1685
1686/* usa19hs function doesn't require prescaler */
1687static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
1688 u8 *rate_low, u8 *prescaler, int portnum)
1689{
1690 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001691 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
Alan Coxdeb91682008-07-22 11:13:08 +01001693 dbg("%s - %d.", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694
Alan Coxdeb91682008-07-22 11:13:08 +01001695 /* prevent divide by zero... */
1696 b16 = baud_rate * 16L;
1697 if (b16 == 0)
1698 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
Alan Coxdeb91682008-07-22 11:13:08 +01001700 /* calculate the divisor */
1701 div = baudclk / b16;
1702 if (div == 0)
1703 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704
Alan Coxdeb91682008-07-22 11:13:08 +01001705 if (div > 0xffff)
1706 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
Alan Coxdeb91682008-07-22 11:13:08 +01001708 /* return the counter values if non-null */
1709 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001711
1712 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001714
1715 if (rate_low && rate_hi)
1716 dbg("%s - %d %02x %02x.",
1717 __func__, baud_rate, *rate_hi, *rate_low);
1718
1719 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720}
1721
1722static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
1723 u8 *rate_low, u8 *prescaler, int portnum)
1724{
1725 u32 b16, /* baud rate times 16 (actual rate used internally) */
1726 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001727 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 res, /* resulting baud rate using 13/8 prescaler */
1729 diff, /* error using 13/8 prescaler */
1730 smallest_diff;
1731 u8 best_prescaler;
1732 int i;
1733
Alan Coxdeb91682008-07-22 11:13:08 +01001734 dbg("%s - %d.", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
Alan Coxdeb91682008-07-22 11:13:08 +01001736 /* prevent divide by zero */
1737 b16 = baud_rate * 16L;
1738 if (b16 == 0)
1739 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
Alan Coxdeb91682008-07-22 11:13:08 +01001741 /* Calculate prescaler by trying them all and looking
1742 for best fit */
1743
1744 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 smallest_diff = 0xffffffff;
1746
1747 /* 0 is an invalid prescaler, used as a flag */
1748 best_prescaler = 0;
1749
Alan Coxdeb91682008-07-22 11:13:08 +01001750 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001752
1753 div = clk / b16;
1754 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756
1757 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001758 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
Alan Coxdeb91682008-07-22 11:13:08 +01001760 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 best_prescaler = i;
1762 smallest_diff = diff;
1763 }
1764 }
1765
Alan Coxdeb91682008-07-22 11:13:08 +01001766 if (best_prescaler == 0)
1767 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768
1769 clk = (baudclk * 8) / (u32) best_prescaler;
1770 div = clk / b16;
1771
Alan Coxdeb91682008-07-22 11:13:08 +01001772 /* return the divisor and prescaler if non-null */
1773 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001775 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 if (prescaler) {
1778 *prescaler = best_prescaler;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001779 /* dbg("%s - %d %d", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 }
Alan Coxdeb91682008-07-22 11:13:08 +01001781 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782}
1783
1784 /* USA-28 supports different maximum baud rates on each port */
1785static int keyspan_usa28_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
1786 u8 *rate_low, u8 *prescaler, int portnum)
1787{
1788 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001789 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 cnt; /* inverse of divisor (programmed into 8051) */
1791
Alan Coxdeb91682008-07-22 11:13:08 +01001792 dbg("%s - %d.", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
1794 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001795 b16 = baud_rate * 16L;
1796 if (b16 == 0)
1797 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798
Alan Coxdeb91682008-07-22 11:13:08 +01001799 /* calculate the divisor and the counter (its inverse) */
1800 div = KEYSPAN_USA28_BAUDCLK / b16;
1801 if (div == 0)
1802 return KEYSPAN_INVALID_BAUD_RATE;
1803 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
Alan Coxdeb91682008-07-22 11:13:08 +01001806 /* check for out of range, based on portnum,
1807 and return result */
1808 if (portnum == 0) {
1809 if (div > 0xffff)
1810 return KEYSPAN_INVALID_BAUD_RATE;
1811 } else {
1812 if (portnum == 1) {
1813 if (div > 0xff)
1814 return KEYSPAN_INVALID_BAUD_RATE;
1815 } else
1816 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 }
1818
1819 /* return the counter values if not NULL
1820 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001821 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001823 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001825 dbg("%s - %d OK.", __func__, baud_rate);
1826 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827}
1828
1829static int keyspan_usa26_send_setup(struct usb_serial *serial,
1830 struct usb_serial_port *port,
1831 int reset_port)
1832{
Alan Coxdeb91682008-07-22 11:13:08 +01001833 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 struct keyspan_serial_private *s_priv;
1835 struct keyspan_port_private *p_priv;
1836 const struct keyspan_device_details *d_details;
1837 int outcont_urb;
1838 struct urb *this_urb;
1839 int device_port, err;
1840
Alan Coxdeb91682008-07-22 11:13:08 +01001841 dbg("%s reset=%d", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842
1843 s_priv = usb_get_serial_data(serial);
1844 p_priv = usb_get_serial_port_data(port);
1845 d_details = s_priv->device_details;
1846 device_port = port->number - port->serial->minor;
1847
1848 outcont_urb = d_details->outcont_endpoints[port->number];
1849 this_urb = p_priv->outcont_urb;
1850
Harvey Harrison441b62c2008-03-03 16:08:34 -08001851 dbg("%s - endpoint %d", __func__, usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
1853 /* Make sure we have an urb then send the message */
1854 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001855 dbg("%s - oops no urb.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 return -1;
1857 }
1858
1859 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001860 Don't overwrite resend for open/close condition. */
1861 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 p_priv->resend_cont = reset_port + 1;
1863 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01001864 /* dbg("%s - already writing", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001866 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 }
1868
Alan Coxdeb91682008-07-22 11:13:08 +01001869 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1870
1871 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 if (p_priv->old_baud != p_priv->baud) {
1873 p_priv->old_baud = p_priv->baud;
1874 msg.setClocking = 0xff;
1875 if (d_details->calculate_baud_rate
1876 (p_priv->baud, d_details->baudclk, &msg.baudHi,
Alan Coxdeb91682008-07-22 11:13:08 +01001877 &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1878 dbg("%s - Invalid baud rate %d requested, using 9600.",
1879 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 msg.baudLo = 0;
1881 msg.baudHi = 125; /* Values for 9600 baud */
1882 msg.prescaler = 10;
1883 }
1884 msg.setPrescaler = 0xff;
1885 }
1886
1887 msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
1888 switch (p_priv->cflag & CSIZE) {
1889 case CS5:
1890 msg.lcr |= USA_DATABITS_5;
1891 break;
1892 case CS6:
1893 msg.lcr |= USA_DATABITS_6;
1894 break;
1895 case CS7:
1896 msg.lcr |= USA_DATABITS_7;
1897 break;
1898 case CS8:
1899 msg.lcr |= USA_DATABITS_8;
1900 break;
1901 }
1902 if (p_priv->cflag & PARENB) {
1903 /* note USA_PARITY_NONE == 0 */
1904 msg.lcr |= (p_priv->cflag & PARODD)?
Alan Coxdeb91682008-07-22 11:13:08 +01001905 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 }
1907 msg.setLcr = 0xff;
1908
1909 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1910 msg.xonFlowControl = 0;
1911 msg.setFlowControl = 0xff;
1912 msg.forwardingLength = 16;
1913 msg.xonChar = 17;
1914 msg.xoffChar = 19;
1915
1916 /* Opening port */
1917 if (reset_port == 1) {
1918 msg._txOn = 1;
1919 msg._txOff = 0;
1920 msg.txFlush = 0;
1921 msg.txBreak = 0;
1922 msg.rxOn = 1;
1923 msg.rxOff = 0;
1924 msg.rxFlush = 1;
1925 msg.rxForward = 0;
1926 msg.returnStatus = 0;
1927 msg.resetDataToggle = 0xff;
1928 }
1929
1930 /* Closing port */
1931 else if (reset_port == 2) {
1932 msg._txOn = 0;
1933 msg._txOff = 1;
1934 msg.txFlush = 0;
1935 msg.txBreak = 0;
1936 msg.rxOn = 0;
1937 msg.rxOff = 1;
1938 msg.rxFlush = 1;
1939 msg.rxForward = 0;
1940 msg.returnStatus = 0;
1941 msg.resetDataToggle = 0;
1942 }
1943
1944 /* Sending intermediate configs */
1945 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001946 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 msg._txOff = 0;
1948 msg.txFlush = 0;
1949 msg.txBreak = (p_priv->break_on);
1950 msg.rxOn = 0;
1951 msg.rxOff = 0;
1952 msg.rxFlush = 0;
1953 msg.rxForward = 0;
1954 msg.returnStatus = 0;
1955 msg.resetDataToggle = 0x0;
1956 }
1957
Alan Coxdeb91682008-07-22 11:13:08 +01001958 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 msg.setTxTriState_setRts = 0xff;
1960 msg.txTriState_rts = p_priv->rts_state;
1961
1962 msg.setHskoa_setDtr = 0xff;
1963 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001964
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001966 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1967
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 /* send the data out the device on control endpoint */
1969 this_urb->transfer_buffer_length = sizeof(msg);
1970
1971 this_urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +01001972 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1973 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08001974 dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975#if 0
1976 else {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001977 dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 outcont_urb, this_urb->transfer_buffer_length,
1979 usb_pipeendpoint(this_urb->pipe));
1980 }
1981#endif
1982
Alan Coxa5b6f602008-04-08 17:16:06 +01001983 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984}
1985
1986static int keyspan_usa28_send_setup(struct usb_serial *serial,
1987 struct usb_serial_port *port,
1988 int reset_port)
1989{
Alan Coxdeb91682008-07-22 11:13:08 +01001990 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 struct keyspan_serial_private *s_priv;
1992 struct keyspan_port_private *p_priv;
1993 const struct keyspan_device_details *d_details;
1994 struct urb *this_urb;
1995 int device_port, err;
1996
Alan Coxdeb91682008-07-22 11:13:08 +01001997 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998
1999 s_priv = usb_get_serial_data(serial);
2000 p_priv = usb_get_serial_port_data(port);
2001 d_details = s_priv->device_details;
2002 device_port = port->number - port->serial->minor;
2003
2004 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002005 this_urb = p_priv->outcont_urb;
2006 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002007 dbg("%s - oops no urb.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 return -1;
2009 }
2010
2011 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07002012 Don't overwrite resend for open/close condition. */
2013 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 p_priv->resend_cont = reset_port + 1;
2015 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01002016 dbg("%s already writing", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002018 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 }
2020
Alan Coxdeb91682008-07-22 11:13:08 +01002021 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022
2023 msg.setBaudRate = 1;
2024 if (d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk,
Alan Coxdeb91682008-07-22 11:13:08 +01002025 &msg.baudHi, &msg.baudLo, NULL, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2026 dbg("%s - Invalid baud rate requested %d.",
2027 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 msg.baudLo = 0xff;
2029 msg.baudHi = 0xb2; /* Values for 9600 baud */
2030 }
2031
2032 /* If parity is enabled, we must calculate it ourselves. */
2033 msg.parity = 0; /* XXX for now */
2034
2035 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2036 msg.xonFlowControl = 0;
2037
Alan Coxdeb91682008-07-22 11:13:08 +01002038 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 msg.rts = p_priv->rts_state;
2040 msg.dtr = p_priv->dtr_state;
2041
2042 msg.forwardingLength = 16;
2043 msg.forwardMs = 10;
2044 msg.breakThreshold = 45;
2045 msg.xonChar = 17;
2046 msg.xoffChar = 19;
2047
2048 /*msg.returnStatus = 1;
2049 msg.resetDataToggle = 0xff;*/
2050 /* Opening port */
2051 if (reset_port == 1) {
2052 msg._txOn = 1;
2053 msg._txOff = 0;
2054 msg.txFlush = 0;
2055 msg.txForceXoff = 0;
2056 msg.txBreak = 0;
2057 msg.rxOn = 1;
2058 msg.rxOff = 0;
2059 msg.rxFlush = 1;
2060 msg.rxForward = 0;
2061 msg.returnStatus = 0;
2062 msg.resetDataToggle = 0xff;
2063 }
2064 /* Closing port */
2065 else if (reset_port == 2) {
2066 msg._txOn = 0;
2067 msg._txOff = 1;
2068 msg.txFlush = 0;
2069 msg.txForceXoff = 0;
2070 msg.txBreak = 0;
2071 msg.rxOn = 0;
2072 msg.rxOff = 1;
2073 msg.rxFlush = 1;
2074 msg.rxForward = 0;
2075 msg.returnStatus = 0;
2076 msg.resetDataToggle = 0;
2077 }
2078 /* Sending intermediate configs */
2079 else {
Alan Coxdeb91682008-07-22 11:13:08 +01002080 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 msg._txOff = 0;
2082 msg.txFlush = 0;
2083 msg.txForceXoff = 0;
2084 msg.txBreak = (p_priv->break_on);
2085 msg.rxOn = 0;
2086 msg.rxOff = 0;
2087 msg.rxFlush = 0;
2088 msg.rxForward = 0;
2089 msg.returnStatus = 0;
2090 msg.resetDataToggle = 0x0;
2091 }
2092
2093 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002094 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
2096 /* send the data out the device on control endpoint */
2097 this_urb->transfer_buffer_length = sizeof(msg);
2098
2099 this_urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +01002100 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2101 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002102 dbg("%s - usb_submit_urb(setup) failed", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103#if 0
2104 else {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002105 dbg("%s - usb_submit_urb(setup) OK %d bytes", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 this_urb->transfer_buffer_length);
2107 }
2108#endif
2109
Alan Coxa5b6f602008-04-08 17:16:06 +01002110 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111}
2112
2113static int keyspan_usa49_send_setup(struct usb_serial *serial,
2114 struct usb_serial_port *port,
2115 int reset_port)
2116{
Lucy McCoy0ca12682007-05-18 12:10:41 -07002117 struct keyspan_usa49_portControlMessage msg;
2118 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 struct keyspan_serial_private *s_priv;
2120 struct keyspan_port_private *p_priv;
2121 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 struct urb *this_urb;
2123 int err, device_port;
2124
Alan Coxdeb91682008-07-22 11:13:08 +01002125 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
2127 s_priv = usb_get_serial_data(serial);
2128 p_priv = usb_get_serial_port_data(port);
2129 d_details = s_priv->device_details;
2130
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 this_urb = s_priv->glocont_urb;
2132
Lucy McCoy0ca12682007-05-18 12:10:41 -07002133 /* Work out which port within the device is being setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 device_port = port->number - port->serial->minor;
2135
Alan Coxdeb91682008-07-22 11:13:08 +01002136 dbg("%s - endpoint %d port %d (%d)",
2137 __func__, usb_pipeendpoint(this_urb->pipe),
2138 port->number, device_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139
2140 /* Make sure we have an urb then send the message */
2141 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002142 dbg("%s - oops no urb for port %d.", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 return -1;
2144 }
2145
2146 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07002147 Don't overwrite resend for open/close condition. */
2148 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002150
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01002152 /* dbg("%s - already writing", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002154 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 }
2156
Alan Coxdeb91682008-07-22 11:13:08 +01002157 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158
2159 /*msg.portNumber = port->number;*/
2160 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01002161
2162 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 if (p_priv->old_baud != p_priv->baud) {
2164 p_priv->old_baud = p_priv->baud;
2165 msg.setClocking = 0xff;
2166 if (d_details->calculate_baud_rate
2167 (p_priv->baud, d_details->baudclk, &msg.baudHi,
Alan Coxdeb91682008-07-22 11:13:08 +01002168 &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2169 dbg("%s - Invalid baud rate %d requested, using 9600.",
2170 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 msg.baudLo = 0;
2172 msg.baudHi = 125; /* Values for 9600 baud */
2173 msg.prescaler = 10;
2174 }
Alan Coxdeb91682008-07-22 11:13:08 +01002175 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 }
2177
2178 msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
2179 switch (p_priv->cflag & CSIZE) {
2180 case CS5:
2181 msg.lcr |= USA_DATABITS_5;
2182 break;
2183 case CS6:
2184 msg.lcr |= USA_DATABITS_6;
2185 break;
2186 case CS7:
2187 msg.lcr |= USA_DATABITS_7;
2188 break;
2189 case CS8:
2190 msg.lcr |= USA_DATABITS_8;
2191 break;
2192 }
2193 if (p_priv->cflag & PARENB) {
2194 /* note USA_PARITY_NONE == 0 */
2195 msg.lcr |= (p_priv->cflag & PARODD)?
Alan Coxdeb91682008-07-22 11:13:08 +01002196 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 }
2198 msg.setLcr = 0xff;
2199
2200 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2201 msg.xonFlowControl = 0;
2202 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01002203
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 msg.forwardingLength = 16;
2205 msg.xonChar = 17;
2206 msg.xoffChar = 19;
2207
Alan Coxdeb91682008-07-22 11:13:08 +01002208 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 if (reset_port == 1) {
2210 msg._txOn = 1;
2211 msg._txOff = 0;
2212 msg.txFlush = 0;
2213 msg.txBreak = 0;
2214 msg.rxOn = 1;
2215 msg.rxOff = 0;
2216 msg.rxFlush = 1;
2217 msg.rxForward = 0;
2218 msg.returnStatus = 0;
2219 msg.resetDataToggle = 0xff;
2220 msg.enablePort = 1;
2221 msg.disablePort = 0;
2222 }
2223 /* Closing port */
2224 else if (reset_port == 2) {
2225 msg._txOn = 0;
2226 msg._txOff = 1;
2227 msg.txFlush = 0;
2228 msg.txBreak = 0;
2229 msg.rxOn = 0;
2230 msg.rxOff = 1;
2231 msg.rxFlush = 1;
2232 msg.rxForward = 0;
2233 msg.returnStatus = 0;
2234 msg.resetDataToggle = 0;
2235 msg.enablePort = 0;
2236 msg.disablePort = 1;
2237 }
2238 /* Sending intermediate configs */
2239 else {
Alan Coxdeb91682008-07-22 11:13:08 +01002240 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 msg._txOff = 0;
2242 msg.txFlush = 0;
2243 msg.txBreak = (p_priv->break_on);
2244 msg.rxOn = 0;
2245 msg.rxOff = 0;
2246 msg.rxFlush = 0;
2247 msg.rxForward = 0;
2248 msg.returnStatus = 0;
2249 msg.resetDataToggle = 0x0;
2250 msg.enablePort = 0;
2251 msg.disablePort = 0;
2252 }
2253
Alan Coxdeb91682008-07-22 11:13:08 +01002254 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 msg.setRts = 0xff;
2256 msg.rts = p_priv->rts_state;
2257
2258 msg.setDtr = 0xff;
2259 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002260
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262
Alan Coxdeb91682008-07-22 11:13:08 +01002263 /* if the device is a 49wg, we send control message on usb
2264 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002265
2266 if (d_details->product_id == keyspan_usa49wg_product_id) {
2267 dr = (void *)(s_priv->ctrl_buf);
2268 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
2269 dr->bRequest = 0xB0; /* 49wg control message */;
2270 dr->wValue = 0;
2271 dr->wIndex = 0;
2272 dr->wLength = cpu_to_le16(sizeof(msg));
2273
Alan Coxdeb91682008-07-22 11:13:08 +01002274 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07002275
Alan Coxdeb91682008-07-22 11:13:08 +01002276 usb_fill_control_urb(this_urb, serial->dev,
2277 usb_sndctrlpipe(serial->dev, 0),
2278 (unsigned char *)dr, s_priv->glocont_buf,
2279 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002280
2281 } else {
2282 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01002283
Lucy McCoy0ca12682007-05-18 12:10:41 -07002284 /* send the data out the device on control endpoint */
2285 this_urb->transfer_buffer_length = sizeof(msg);
2286
2287 this_urb->dev = serial->dev;
2288 }
Alan Coxdeb91682008-07-22 11:13:08 +01002289 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2290 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002291 dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292#if 0
2293 else {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002294 dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002295 outcont_urb, this_urb->transfer_buffer_length,
2296 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 }
2298#endif
2299
Alan Coxa5b6f602008-04-08 17:16:06 +01002300 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301}
2302
2303static int keyspan_usa90_send_setup(struct usb_serial *serial,
2304 struct usb_serial_port *port,
2305 int reset_port)
2306{
Alan Coxdeb91682008-07-22 11:13:08 +01002307 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 struct keyspan_serial_private *s_priv;
2309 struct keyspan_port_private *p_priv;
2310 const struct keyspan_device_details *d_details;
2311 struct urb *this_urb;
2312 int err;
2313 u8 prescaler;
2314
Alan Coxdeb91682008-07-22 11:13:08 +01002315 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
2317 s_priv = usb_get_serial_data(serial);
2318 p_priv = usb_get_serial_port_data(port);
2319 d_details = s_priv->device_details;
2320
2321 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002322 this_urb = p_priv->outcont_urb;
2323 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002324 dbg("%s - oops no urb.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 return -1;
2326 }
2327
2328 /* Save reset port val for resend.
2329 Don't overwrite resend for open/close condition. */
2330 if ((reset_port + 1) > p_priv->resend_cont)
2331 p_priv->resend_cont = reset_port + 1;
2332 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01002333 dbg("%s already writing", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002335 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 }
2337
Alan Coxdeb91682008-07-22 11:13:08 +01002338 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339
Alan Coxdeb91682008-07-22 11:13:08 +01002340 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 if (p_priv->old_baud != p_priv->baud) {
2342 p_priv->old_baud = p_priv->baud;
2343 msg.setClocking = 0x01;
2344 if (d_details->calculate_baud_rate
2345 (p_priv->baud, d_details->baudclk, &msg.baudHi,
Alan Coxdeb91682008-07-22 11:13:08 +01002346 &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2347 dbg("%s - Invalid baud rate %d requested, using 9600.",
2348 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 p_priv->baud = 9600;
Alan Coxdeb91682008-07-22 11:13:08 +01002350 d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2352 }
2353 msg.setRxMode = 1;
2354 msg.setTxMode = 1;
2355 }
2356
2357 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002358 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 msg.rxMode = RXMODE_DMA;
2360 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002361 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 msg.rxMode = RXMODE_BYHAND;
2363 msg.txMode = TXMODE_BYHAND;
2364 }
2365
2366 msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
2367 switch (p_priv->cflag & CSIZE) {
2368 case CS5:
2369 msg.lcr |= USA_DATABITS_5;
2370 break;
2371 case CS6:
2372 msg.lcr |= USA_DATABITS_6;
2373 break;
2374 case CS7:
2375 msg.lcr |= USA_DATABITS_7;
2376 break;
2377 case CS8:
2378 msg.lcr |= USA_DATABITS_8;
2379 break;
2380 }
2381 if (p_priv->cflag & PARENB) {
2382 /* note USA_PARITY_NONE == 0 */
2383 msg.lcr |= (p_priv->cflag & PARODD)?
Alan Coxdeb91682008-07-22 11:13:08 +01002384 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 }
2386 if (p_priv->old_cflag != p_priv->cflag) {
2387 p_priv->old_cflag = p_priv->cflag;
2388 msg.setLcr = 0x01;
2389 }
2390
2391 if (p_priv->flow_control == flow_cts)
2392 msg.txFlowControl = TXFLOW_CTS;
2393 msg.setTxFlowControl = 0x01;
2394 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002395
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002397 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 msg.txAckSetting = 0;
2399 msg.xonChar = 17;
2400 msg.xoffChar = 19;
2401
Alan Coxdeb91682008-07-22 11:13:08 +01002402 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 if (reset_port == 1) {
2404 msg.portEnabled = 1;
2405 msg.rxFlush = 1;
2406 msg.txBreak = (p_priv->break_on);
2407 }
2408 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002409 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 /* Sending intermediate configs */
2412 else {
Alan Cox95da3102008-07-22 11:09:07 +01002413 if (port->port.count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 msg.portEnabled = 1;
2415 msg.txBreak = (p_priv->break_on);
2416 }
2417
Alan Coxdeb91682008-07-22 11:13:08 +01002418 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 msg.setRts = 0x01;
2420 msg.rts = p_priv->rts_state;
2421
2422 msg.setDtr = 0x01;
2423 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002424
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002426 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2427
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 /* send the data out the device on control endpoint */
2429 this_urb->transfer_buffer_length = sizeof(msg);
2430
2431 this_urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +01002432 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2433 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002434 dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002435 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436}
2437
Lucy McCoy0ca12682007-05-18 12:10:41 -07002438static int keyspan_usa67_send_setup(struct usb_serial *serial,
2439 struct usb_serial_port *port,
2440 int reset_port)
2441{
2442 struct keyspan_usa67_portControlMessage msg;
2443 struct keyspan_serial_private *s_priv;
2444 struct keyspan_port_private *p_priv;
2445 const struct keyspan_device_details *d_details;
2446 struct urb *this_urb;
2447 int err, device_port;
2448
Alan Coxdeb91682008-07-22 11:13:08 +01002449 dbg("%s", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002450
2451 s_priv = usb_get_serial_data(serial);
2452 p_priv = usb_get_serial_port_data(port);
2453 d_details = s_priv->device_details;
2454
2455 this_urb = s_priv->glocont_urb;
2456
2457 /* Work out which port within the device is being setup */
2458 device_port = port->number - port->serial->minor;
2459
2460 /* Make sure we have an urb then send the message */
2461 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002462 dbg("%s - oops no urb for port %d.", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002463 port->number);
2464 return -1;
2465 }
2466
2467 /* Save reset port val for resend.
2468 Don't overwrite resend for open/close condition. */
2469 if ((reset_port + 1) > p_priv->resend_cont)
2470 p_priv->resend_cont = reset_port + 1;
2471 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01002472 /* dbg("%s - already writing", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002473 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002474 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002475 }
2476
2477 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2478
2479 msg.port = device_port;
2480
2481 /* Only set baud rate if it's changed */
2482 if (p_priv->old_baud != p_priv->baud) {
2483 p_priv->old_baud = p_priv->baud;
2484 msg.setClocking = 0xff;
2485 if (d_details->calculate_baud_rate
2486 (p_priv->baud, d_details->baudclk, &msg.baudHi,
Alan Coxdeb91682008-07-22 11:13:08 +01002487 &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2488 dbg("%s - Invalid baud rate %d requested, using 9600.",
2489 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002490 msg.baudLo = 0;
2491 msg.baudHi = 125; /* Values for 9600 baud */
2492 msg.prescaler = 10;
2493 }
2494 msg.setPrescaler = 0xff;
2495 }
2496
2497 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2498 switch (p_priv->cflag & CSIZE) {
2499 case CS5:
2500 msg.lcr |= USA_DATABITS_5;
2501 break;
2502 case CS6:
2503 msg.lcr |= USA_DATABITS_6;
2504 break;
2505 case CS7:
2506 msg.lcr |= USA_DATABITS_7;
2507 break;
2508 case CS8:
2509 msg.lcr |= USA_DATABITS_8;
2510 break;
2511 }
2512 if (p_priv->cflag & PARENB) {
2513 /* note USA_PARITY_NONE == 0 */
2514 msg.lcr |= (p_priv->cflag & PARODD)?
Alan Coxdeb91682008-07-22 11:13:08 +01002515 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002516 }
2517 msg.setLcr = 0xff;
2518
2519 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2520 msg.xonFlowControl = 0;
2521 msg.setFlowControl = 0xff;
2522 msg.forwardingLength = 16;
2523 msg.xonChar = 17;
2524 msg.xoffChar = 19;
2525
2526 if (reset_port == 1) {
2527 /* Opening port */
2528 msg._txOn = 1;
2529 msg._txOff = 0;
2530 msg.txFlush = 0;
2531 msg.txBreak = 0;
2532 msg.rxOn = 1;
2533 msg.rxOff = 0;
2534 msg.rxFlush = 1;
2535 msg.rxForward = 0;
2536 msg.returnStatus = 0;
2537 msg.resetDataToggle = 0xff;
2538 } else if (reset_port == 2) {
2539 /* Closing port */
2540 msg._txOn = 0;
2541 msg._txOff = 1;
2542 msg.txFlush = 0;
2543 msg.txBreak = 0;
2544 msg.rxOn = 0;
2545 msg.rxOff = 1;
2546 msg.rxFlush = 1;
2547 msg.rxForward = 0;
2548 msg.returnStatus = 0;
2549 msg.resetDataToggle = 0;
2550 } else {
2551 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002552 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002553 msg._txOff = 0;
2554 msg.txFlush = 0;
2555 msg.txBreak = (p_priv->break_on);
2556 msg.rxOn = 0;
2557 msg.rxOff = 0;
2558 msg.rxFlush = 0;
2559 msg.rxForward = 0;
2560 msg.returnStatus = 0;
2561 msg.resetDataToggle = 0x0;
2562 }
2563
2564 /* Do handshaking outputs */
2565 msg.setTxTriState_setRts = 0xff;
2566 msg.txTriState_rts = p_priv->rts_state;
2567
2568 msg.setHskoa_setDtr = 0xff;
2569 msg.hskoa_dtr = p_priv->dtr_state;
2570
2571 p_priv->resend_cont = 0;
2572
2573 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2574
2575 /* send the data out the device on control endpoint */
2576 this_urb->transfer_buffer_length = sizeof(msg);
2577 this_urb->dev = serial->dev;
2578
2579 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2580 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002581 dbg("%s - usb_submit_urb(setup) failed (%d)", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002582 err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002583 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002584}
2585
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2587{
2588 struct usb_serial *serial = port->serial;
2589 struct keyspan_serial_private *s_priv;
2590 const struct keyspan_device_details *d_details;
2591
Alan Coxdeb91682008-07-22 11:13:08 +01002592 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
2594 s_priv = usb_get_serial_data(serial);
2595 d_details = s_priv->device_details;
2596
2597 switch (d_details->msg_format) {
2598 case msg_usa26:
2599 keyspan_usa26_send_setup(serial, port, reset_port);
2600 break;
2601 case msg_usa28:
2602 keyspan_usa28_send_setup(serial, port, reset_port);
2603 break;
2604 case msg_usa49:
2605 keyspan_usa49_send_setup(serial, port, reset_port);
2606 break;
2607 case msg_usa90:
2608 keyspan_usa90_send_setup(serial, port, reset_port);
2609 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002610 case msg_usa67:
2611 keyspan_usa67_send_setup(serial, port, reset_port);
2612 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 }
2614}
2615
2616
2617/* Gets called by the "real" driver (ie once firmware is loaded
2618 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002619static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620{
2621 int i, err;
2622 struct usb_serial_port *port;
2623 struct keyspan_serial_private *s_priv;
2624 struct keyspan_port_private *p_priv;
2625 const struct keyspan_device_details *d_details;
2626
Harvey Harrison441b62c2008-03-03 16:08:34 -08002627 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628
2629 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002630 if (d_details->product_id ==
2631 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 break;
2633 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002634 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2635 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 return 1;
2637 }
2638
2639 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002640 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 if (!s_priv) {
Alan Coxdeb91682008-07-22 11:13:08 +01002642 dbg("%s - kmalloc for keyspan_serial_private failed.",
2643 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 return -ENOMEM;
2645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646
2647 s_priv->device_details = d_details;
2648 usb_set_serial_data(serial, s_priv);
2649
2650 /* Now setup per port private data */
2651 for (i = 0; i < serial->num_ports; i++) {
2652 port = serial->port[i];
Alan Coxdeb91682008-07-22 11:13:08 +01002653 p_priv = kzalloc(sizeof(struct keyspan_port_private),
2654 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 if (!p_priv) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002656 dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __func__, i);
Alan Coxdeb91682008-07-22 11:13:08 +01002657 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 p_priv->device_details = d_details;
2660 usb_set_serial_port_data(port, p_priv);
2661 }
2662
2663 keyspan_setup_urbs(serial);
2664
Lucy McCoy0ca12682007-05-18 12:10:41 -07002665 if (s_priv->instat_urb != NULL) {
2666 s_priv->instat_urb->dev = serial->dev;
2667 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2668 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002669 dbg("%s - submit instat urb failed %d", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002670 err);
2671 }
2672 if (s_priv->indat_urb != NULL) {
2673 s_priv->indat_urb->dev = serial->dev;
2674 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2675 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002676 dbg("%s - submit indat urb failed %d", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002677 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 }
Alan Coxdeb91682008-07-22 11:13:08 +01002679
Alan Coxa5b6f602008-04-08 17:16:06 +01002680 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681}
2682
Alan Coxdeb91682008-07-22 11:13:08 +01002683static void keyspan_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684{
2685 int i, j;
2686 struct usb_serial_port *port;
2687 struct keyspan_serial_private *s_priv;
2688 struct keyspan_port_private *p_priv;
2689
Harvey Harrison441b62c2008-03-03 16:08:34 -08002690 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691
2692 s_priv = usb_get_serial_data(serial);
2693
2694 /* Stop reading/writing urbs */
2695 stop_urb(s_priv->instat_urb);
2696 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002697 stop_urb(s_priv->indat_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 for (i = 0; i < serial->num_ports; ++i) {
2699 port = serial->port[i];
2700 p_priv = usb_get_serial_port_data(port);
2701 stop_urb(p_priv->inack_urb);
2702 stop_urb(p_priv->outcont_urb);
2703 for (j = 0; j < 2; j++) {
2704 stop_urb(p_priv->in_urbs[j]);
2705 stop_urb(p_priv->out_urbs[j]);
2706 }
2707 }
2708
2709 /* Now free them */
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002710 usb_free_urb(s_priv->instat_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002711 usb_free_urb(s_priv->indat_urb);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002712 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 for (i = 0; i < serial->num_ports; ++i) {
2714 port = serial->port[i];
2715 p_priv = usb_get_serial_port_data(port);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002716 usb_free_urb(p_priv->inack_urb);
2717 usb_free_urb(p_priv->outcont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 for (j = 0; j < 2; j++) {
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002719 usb_free_urb(p_priv->in_urbs[j]);
2720 usb_free_urb(p_priv->out_urbs[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 }
2722 }
2723
2724 /* dbg("Freeing serial->private."); */
2725 kfree(s_priv);
2726
2727 /* dbg("Freeing port->private."); */
2728 /* Now free per port private data */
2729 for (i = 0; i < serial->num_ports; i++) {
2730 port = serial->port[i];
2731 kfree(usb_get_serial_port_data(port));
2732 }
2733}
2734
Alan Coxdeb91682008-07-22 11:13:08 +01002735MODULE_AUTHOR(DRIVER_AUTHOR);
2736MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737MODULE_LICENSE("GPL");
2738
David Woodhouse2971c572008-05-30 14:04:03 +03002739MODULE_FIRMWARE("keyspan/usa28.fw");
2740MODULE_FIRMWARE("keyspan/usa28x.fw");
2741MODULE_FIRMWARE("keyspan/usa28xa.fw");
2742MODULE_FIRMWARE("keyspan/usa28xb.fw");
2743MODULE_FIRMWARE("keyspan/usa19.fw");
2744MODULE_FIRMWARE("keyspan/usa19qi.fw");
2745MODULE_FIRMWARE("keyspan/mpr.fw");
2746MODULE_FIRMWARE("keyspan/usa19qw.fw");
2747MODULE_FIRMWARE("keyspan/usa18x.fw");
2748MODULE_FIRMWARE("keyspan/usa19w.fw");
2749MODULE_FIRMWARE("keyspan/usa49w.fw");
2750MODULE_FIRMWARE("keyspan/usa49wlc.fw");
2751
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752module_param(debug, bool, S_IRUGO | S_IWUSR);
2753MODULE_PARM_DESC(debug, "Debug enabled or not");
2754