blob: 704716f6f6d378c825920c213f3cedd7585b0ab5 [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{
Alan Coxf035a8a2008-07-22 11:13:32 +0100580 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 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 Coxf035a8a2008-07-22 11:13:32 +0100609 tty_insert_flip_string(tty, data, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 tty_flip_buffer_push(tty);
611 }
612
613 /* Resubmit urb so we continue receiving */
614 urb->dev = port->serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +0100615 if (port->port.count) {
616 err = usb_submit_urb(urb, GFP_ATOMIC);
617 if (err != 0)
618 dbg("%s - resubmit read urb failed. (%d)",
619 __func__, err);
620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 p_priv->in_flip ^= 1;
622
623 urb = p_priv->in_urbs[p_priv->in_flip];
624 } while (urb->status != -EINPROGRESS);
625}
626
David Howells7d12e782006-10-05 14:55:46 +0100627static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
Alan Coxdeb91682008-07-22 11:13:08 +0100629 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630}
631
David Howells7d12e782006-10-05 14:55:46 +0100632static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
634 struct usb_serial_port *port;
635 struct keyspan_port_private *p_priv;
636
Ming Leicdc97792008-02-24 18:41:47 +0800637 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 p_priv = usb_get_serial_port_data(port);
639
640 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +0100641 dbg("%s - sending setup", __func__);
642 keyspan_usa28_send_setup(port->serial, port,
643 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 }
645}
646
David Howells7d12e782006-10-05 14:55:46 +0100647static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
649 int err;
650 unsigned char *data = urb->transfer_buffer;
651 struct keyspan_usa28_portStatusMessage *msg;
652 struct usb_serial *serial;
653 struct usb_serial_port *port;
654 struct keyspan_port_private *p_priv;
655 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700656 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
Ming Leicdc97792008-02-24 18:41:47 +0800658 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700660 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800661 dbg("%s - nonzero status: %x", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 return;
663 }
664
665 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800666 dbg("%s - bad length %d", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 goto exit;
668 }
669
Harvey Harrison441b62c2008-03-03 16:08:34 -0800670 /*dbg("%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 data[0], data[1], data[2], data[3], data[4], data[5],
672 data[6], data[7], data[8], data[9], data[10], data[11]);*/
Alan Coxdeb91682008-07-22 11:13:08 +0100673
674 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 msg = (struct keyspan_usa28_portStatusMessage *)data;
676
Alan Coxdeb91682008-07-22 11:13:08 +0100677 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 if (msg->port >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +0100679 dbg("%s - Unexpected port number %d", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 goto exit;
681 }
682 port = serial->port[msg->port];
683 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100684
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 /* Update handshaking pin state information */
686 old_dcd_state = p_priv->dcd_state;
687 p_priv->cts_state = ((msg->cts) ? 1 : 0);
688 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
689 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
690 p_priv->ri_state = ((msg->ri) ? 1 : 0);
691
Alan Cox95da3102008-07-22 11:09:07 +0100692 if (port->port.tty && !C_CLOCAL(port->port.tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 && old_dcd_state != p_priv->dcd_state) {
694 if (old_dcd_state)
Alan Cox95da3102008-07-22 11:09:07 +0100695 tty_hangup(port->port.tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 /* else */
697 /* wake_up_interruptible(&p_priv->open_wait); */
698 }
699
700 /* Resubmit urb so we continue receiving */
701 urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +0100702 err = usb_submit_urb(urb, GFP_ATOMIC);
703 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800704 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705exit: ;
706}
707
David Howells7d12e782006-10-05 14:55:46 +0100708static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709{
Alan Coxdeb91682008-07-22 11:13:08 +0100710 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711}
712
713
David Howells7d12e782006-10-05 14:55:46 +0100714static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715{
716 struct usb_serial *serial;
717 struct usb_serial_port *port;
718 struct keyspan_port_private *p_priv;
719 int i;
720
Alan Coxdeb91682008-07-22 11:13:08 +0100721 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
Ming Leicdc97792008-02-24 18:41:47 +0800723 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 for (i = 0; i < serial->num_ports; ++i) {
725 port = serial->port[i];
726 p_priv = usb_get_serial_port_data(port);
727
728 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +0100729 dbg("%s - sending setup", __func__);
730 keyspan_usa49_send_setup(serial, port,
731 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 break;
733 }
734 }
735}
736
737 /* This is actually called glostat in the Keyspan
738 doco */
David Howells7d12e782006-10-05 14:55:46 +0100739static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
741 int err;
742 unsigned char *data = urb->transfer_buffer;
743 struct keyspan_usa49_portStatusMessage *msg;
744 struct usb_serial *serial;
745 struct usb_serial_port *port;
746 struct keyspan_port_private *p_priv;
747 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700748 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Alan Coxdeb91682008-07-22 11:13:08 +0100750 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
Ming Leicdc97792008-02-24 18:41:47 +0800752 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700754 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800755 dbg("%s - nonzero status: %x", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 return;
757 }
758
Alan Coxdeb91682008-07-22 11:13:08 +0100759 if (urb->actual_length !=
760 sizeof(struct keyspan_usa49_portStatusMessage)) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800761 dbg("%s - bad length %d", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 goto exit;
763 }
764
Harvey Harrison441b62c2008-03-03 16:08:34 -0800765 /*dbg(" %x %x %x %x %x %x %x %x %x %x %x", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 data[0], data[1], data[2], data[3], data[4], data[5],
767 data[6], data[7], data[8], data[9], data[10]);*/
Alan Coxdeb91682008-07-22 11:13:08 +0100768
769 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 msg = (struct keyspan_usa49_portStatusMessage *)data;
771
Alan Coxdeb91682008-07-22 11:13:08 +0100772 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 if (msg->portNumber >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +0100774 dbg("%s - Unexpected port number %d",
775 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 goto exit;
777 }
778 port = serial->port[msg->portNumber];
779 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 /* Update handshaking pin state information */
782 old_dcd_state = p_priv->dcd_state;
783 p_priv->cts_state = ((msg->cts) ? 1 : 0);
784 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
785 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
786 p_priv->ri_state = ((msg->ri) ? 1 : 0);
787
Alan Cox95da3102008-07-22 11:09:07 +0100788 if (port->port.tty && !C_CLOCAL(port->port.tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 && old_dcd_state != p_priv->dcd_state) {
790 if (old_dcd_state)
Alan Cox95da3102008-07-22 11:09:07 +0100791 tty_hangup(port->port.tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 /* else */
793 /* wake_up_interruptible(&p_priv->open_wait); */
794 }
795
Alan Coxdeb91682008-07-22 11:13:08 +0100796 /* Resubmit urb so we continue receiving */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 urb->dev = serial->dev;
798
Alan Coxdeb91682008-07-22 11:13:08 +0100799 err = usb_submit_urb(urb, GFP_ATOMIC);
800 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800801 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802exit: ;
803}
804
David Howells7d12e782006-10-05 14:55:46 +0100805static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806{
Alan Coxdeb91682008-07-22 11:13:08 +0100807 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808}
809
David Howells7d12e782006-10-05 14:55:46 +0100810static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811{
812 int i, err;
813 int endpoint;
814 struct usb_serial_port *port;
815 struct tty_struct *tty;
816 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700817 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
Alan Coxdeb91682008-07-22 11:13:08 +0100819 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
821 endpoint = usb_pipeendpoint(urb->pipe);
822
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700823 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800824 dbg("%s - nonzero status: %x on endpoint %d.", __func__,
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700825 status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 return;
827 }
828
Ming Leicdc97792008-02-24 18:41:47 +0800829 port = urb->context;
Alan Cox95da3102008-07-22 11:09:07 +0100830 tty = port->port.tty;
Alan Cox3004e532008-01-03 16:59:04 +0000831 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 /* 0x80 bit is error flag */
833 if ((data[0] & 0x80) == 0) {
834 /* no error on any byte */
Alan Coxf035a8a2008-07-22 11:13:32 +0100835 tty_insert_flip_string(tty, data + 1,
836 urb->actual_length - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 } else {
838 /* some bytes had errors, every byte has status */
839 for (i = 0; i + 1 < urb->actual_length; i += 2) {
840 int stat = data[i], flag = 0;
841 if (stat & RXERROR_OVERRUN)
842 flag |= TTY_OVERRUN;
843 if (stat & RXERROR_FRAMING)
844 flag |= TTY_FRAME;
845 if (stat & RXERROR_PARITY)
846 flag |= TTY_PARITY;
847 /* XXX should handle break (0x10) */
848 tty_insert_flip_char(tty, data[i+1], flag);
849 }
850 }
851 tty_flip_buffer_push(tty);
852 }
Alan Coxdeb91682008-07-22 11:13:08 +0100853
854 /* Resubmit urb so we continue receiving */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 urb->dev = port->serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +0100856 if (port->port.count) {
857 err = usb_submit_urb(urb, GFP_ATOMIC);
858 if (err != 0)
859 dbg("%s - resubmit read urb failed. (%d)",
860 __func__, err);
861 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862}
863
Lucy McCoy0ca12682007-05-18 12:10:41 -0700864static void usa49wg_indat_callback(struct urb *urb)
865{
866 int i, len, x, err;
867 struct usb_serial *serial;
868 struct usb_serial_port *port;
869 struct tty_struct *tty;
870 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700871 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700872
Alan Coxdeb91682008-07-22 11:13:08 +0100873 dbg("%s", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700874
875 serial = urb->context;
876
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700877 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800878 dbg("%s - nonzero status: %x", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700879 return;
880 }
881
882 /* inbound data is in the form P#, len, status, data */
883 i = 0;
884 len = 0;
885
886 if (urb->actual_length) {
887 while (i < urb->actual_length) {
888
889 /* Check port number from message*/
890 if (data[i] >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +0100891 dbg("%s - Unexpected port number %d",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800892 __func__, data[i]);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700893 return;
894 }
895 port = serial->port[data[i++]];
Alan Cox95da3102008-07-22 11:09:07 +0100896 tty = port->port.tty;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700897 len = data[i++];
898
899 /* 0x80 bit is error flag */
900 if ((data[i] & 0x80) == 0) {
901 /* no error on any byte */
902 i++;
903 for (x = 1; x < len ; ++x)
Alan Cox95da3102008-07-22 11:09:07 +0100904 if (port->port.count)
Lucy McCoy0ca12682007-05-18 12:10:41 -0700905 tty_insert_flip_char(tty,
906 data[i++], 0);
907 else
908 i++;
909 } else {
910 /*
911 * some bytes had errors, every byte has status
912 */
913 for (x = 0; x + 1 < len; x += 2) {
914 int stat = data[i], flag = 0;
915 if (stat & RXERROR_OVERRUN)
916 flag |= TTY_OVERRUN;
917 if (stat & RXERROR_FRAMING)
918 flag |= TTY_FRAME;
919 if (stat & RXERROR_PARITY)
920 flag |= TTY_PARITY;
921 /* XXX should handle break (0x10) */
Alan Cox95da3102008-07-22 11:09:07 +0100922 if (port->port.count)
Lucy McCoy0ca12682007-05-18 12:10:41 -0700923 tty_insert_flip_char(tty,
924 data[i+1], flag);
925 i += 2;
926 }
927 }
Alan Cox95da3102008-07-22 11:09:07 +0100928 if (port->port.count)
Lucy McCoy0ca12682007-05-18 12:10:41 -0700929 tty_flip_buffer_push(tty);
930 }
931 }
932
933 /* Resubmit urb so we continue receiving */
934 urb->dev = serial->dev;
935
936 err = usb_submit_urb(urb, GFP_ATOMIC);
937 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800938 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700939}
940
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700942static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943{
Alan Coxdeb91682008-07-22 11:13:08 +0100944 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945}
946
Lucy McCoy0ca12682007-05-18 12:10:41 -0700947static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948{
949 int i, err;
950 int endpoint;
951 struct usb_serial_port *port;
952 struct keyspan_port_private *p_priv;
953 struct tty_struct *tty;
954 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700955 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Alan Coxdeb91682008-07-22 11:13:08 +0100957 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 endpoint = usb_pipeendpoint(urb->pipe);
960
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700961 if (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 dbg("%s - nonzero status: %x on endpoint %d.",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800963 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return;
965 }
966
Ming Leicdc97792008-02-24 18:41:47 +0800967 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 p_priv = usb_get_serial_port_data(port);
969
Alan Cox95da3102008-07-22 11:09:07 +0100970 tty = port->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100973 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Alan Coxf035a8a2008-07-22 11:13:32 +0100975 if (p_priv->baud > 57600)
976 tty_insert_flip_string(tty, data, urb->actual_length);
977 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 /* 0x80 bit is error flag */
979 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100980 /* no errors on individual bytes, only
981 possible overrun err*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100983 err = TTY_OVERRUN;
984 else
985 err = 0;
986 for (i = 1; i < urb->actual_length ; ++i)
987 tty_insert_flip_char(tty, data[i],
988 err);
989 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 /* some bytes had errors, every byte has status */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800991 dbg("%s - RX error!!!!", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 for (i = 0; i + 1 < urb->actual_length; i += 2) {
993 int stat = data[i], flag = 0;
994 if (stat & RXERROR_OVERRUN)
995 flag |= TTY_OVERRUN;
996 if (stat & RXERROR_FRAMING)
997 flag |= TTY_FRAME;
998 if (stat & RXERROR_PARITY)
999 flag |= TTY_PARITY;
1000 /* XXX should handle break (0x10) */
Alan Coxdeb91682008-07-22 11:13:08 +01001001 tty_insert_flip_char(tty, data[i+1],
1002 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 }
1004 }
1005 }
1006 tty_flip_buffer_push(tty);
1007 }
Alan Coxdeb91682008-07-22 11:13:08 +01001008
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 /* Resubmit urb so we continue receiving */
1010 urb->dev = port->serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +01001011 if (port->port.count) {
1012 err = usb_submit_urb(urb, GFP_ATOMIC);
1013 if (err != 0)
1014 dbg("%s - resubmit read urb failed. (%d)",
1015 __func__, err);
1016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 return;
1018}
1019
1020
David Howells7d12e782006-10-05 14:55:46 +01001021static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022{
1023 unsigned char *data = urb->transfer_buffer;
1024 struct keyspan_usa90_portStatusMessage *msg;
1025 struct usb_serial *serial;
1026 struct usb_serial_port *port;
1027 struct keyspan_port_private *p_priv;
1028 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -07001029 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
Ming Leicdc97792008-02-24 18:41:47 +08001031 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -07001033 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001034 dbg("%s - nonzero status: %x", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 return;
1036 }
1037 if (urb->actual_length < 14) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001038 dbg("%s - %d byte report??", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 goto exit;
1040 }
1041
1042 msg = (struct keyspan_usa90_portStatusMessage *)data;
1043
1044 /* Now do something useful with the data */
1045
1046 port = serial->port[0];
1047 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 /* Update handshaking pin state information */
1050 old_dcd_state = p_priv->dcd_state;
1051 p_priv->cts_state = ((msg->cts) ? 1 : 0);
1052 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
1053 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
1054 p_priv->ri_state = ((msg->ri) ? 1 : 0);
1055
Alan Cox95da3102008-07-22 11:09:07 +01001056 if (port->port.tty && !C_CLOCAL(port->port.tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 && old_dcd_state != p_priv->dcd_state) {
1058 if (old_dcd_state)
Alan Cox95da3102008-07-22 11:09:07 +01001059 tty_hangup(port->port.tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 /* else */
1061 /* wake_up_interruptible(&p_priv->open_wait); */
1062 }
Alan Coxdeb91682008-07-22 11:13:08 +01001063
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 /* Resubmit urb so we continue receiving */
1065 urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +01001066 err = usb_submit_urb(urb, GFP_ATOMIC);
1067 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08001068 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069exit:
1070 ;
1071}
1072
David Howells7d12e782006-10-05 14:55:46 +01001073static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074{
1075 struct usb_serial_port *port;
1076 struct keyspan_port_private *p_priv;
1077
Ming Leicdc97792008-02-24 18:41:47 +08001078 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 p_priv = usb_get_serial_port_data(port);
1080
1081 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +01001082 dbg("%s - sending setup", __func__);
1083 keyspan_usa90_send_setup(port->serial, port,
1084 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 }
1086}
1087
Lucy McCoy0ca12682007-05-18 12:10:41 -07001088/* Status messages from the 28xg */
1089static void usa67_instat_callback(struct urb *urb)
1090{
1091 int err;
1092 unsigned char *data = urb->transfer_buffer;
1093 struct keyspan_usa67_portStatusMessage *msg;
1094 struct usb_serial *serial;
1095 struct usb_serial_port *port;
1096 struct keyspan_port_private *p_priv;
1097 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -07001098 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001099
Alan Coxdeb91682008-07-22 11:13:08 +01001100 dbg("%s", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001101
1102 serial = urb->context;
1103
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -07001104 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001105 dbg("%s - nonzero status: %x", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001106 return;
1107 }
1108
Alan Coxdeb91682008-07-22 11:13:08 +01001109 if (urb->actual_length !=
1110 sizeof(struct keyspan_usa67_portStatusMessage)) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001111 dbg("%s - bad length %d", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001112 return;
1113 }
1114
1115
1116 /* Now do something useful with the data */
1117 msg = (struct keyspan_usa67_portStatusMessage *)data;
1118
1119 /* Check port number from message and retrieve private data */
1120 if (msg->port >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +01001121 dbg("%s - Unexpected port number %d", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001122 return;
1123 }
1124
1125 port = serial->port[msg->port];
1126 p_priv = usb_get_serial_port_data(port);
1127
1128 /* Update handshaking pin state information */
1129 old_dcd_state = p_priv->dcd_state;
1130 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
1131 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
1132
Alan Cox95da3102008-07-22 11:09:07 +01001133 if (port->port.tty && !C_CLOCAL(port->port.tty)
Lucy McCoy0ca12682007-05-18 12:10:41 -07001134 && old_dcd_state != p_priv->dcd_state) {
1135 if (old_dcd_state)
Alan Cox95da3102008-07-22 11:09:07 +01001136 tty_hangup(port->port.tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001137 /* else */
1138 /* wake_up_interruptible(&p_priv->open_wait); */
1139 }
1140
1141 /* Resubmit urb so we continue receiving */
1142 urb->dev = serial->dev;
1143 err = usb_submit_urb(urb, GFP_ATOMIC);
1144 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08001145 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001146}
1147
1148static void usa67_glocont_callback(struct urb *urb)
1149{
1150 struct usb_serial *serial;
1151 struct usb_serial_port *port;
1152 struct keyspan_port_private *p_priv;
1153 int i;
1154
Alan Coxdeb91682008-07-22 11:13:08 +01001155 dbg("%s", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001156
1157 serial = urb->context;
1158 for (i = 0; i < serial->num_ports; ++i) {
1159 port = serial->port[i];
1160 p_priv = usb_get_serial_port_data(port);
1161
1162 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +01001163 dbg("%s - sending setup", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001164 keyspan_usa67_send_setup(serial, port,
1165 p_priv->resend_cont - 1);
1166 break;
1167 }
1168 }
1169}
1170
Alan Cox95da3102008-07-22 11:09:07 +01001171static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172{
Alan Cox95da3102008-07-22 11:09:07 +01001173 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 struct keyspan_port_private *p_priv;
1175 const struct keyspan_device_details *d_details;
1176 int flip;
1177 int data_len;
1178 struct urb *this_urb;
1179
Harvey Harrison441b62c2008-03-03 16:08:34 -08001180 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 p_priv = usb_get_serial_port_data(port);
1182 d_details = p_priv->device_details;
1183
Alan Coxa5b6f602008-04-08 17:16:06 +01001184 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +01001186 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 else
1188 data_len = 63;
1189
1190 flip = p_priv->out_flip;
1191
1192 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +01001193 this_urb = p_priv->out_urbs[flip];
1194 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001196 return data_len;
1197 flip = (flip + 1) & d_details->outdat_endp_flip;
1198 this_urb = p_priv->out_urbs[flip];
1199 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001201 return data_len;
1202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 }
Alan Coxa5b6f602008-04-08 17:16:06 +01001204 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205}
1206
1207
Alan Cox95da3102008-07-22 11:09:07 +01001208static int keyspan_open(struct tty_struct *tty,
1209 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001211 struct keyspan_port_private *p_priv;
1212 struct keyspan_serial_private *s_priv;
1213 struct usb_serial *serial = port->serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 const struct keyspan_device_details *d_details;
1215 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001216 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001218 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
1220 s_priv = usb_get_serial_data(serial);
1221 p_priv = usb_get_serial_port_data(port);
1222 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001223
Harvey Harrison441b62c2008-03-03 16:08:34 -08001224 dbg("%s - port%d.", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
1226 /* Set some sane defaults */
1227 p_priv->rts_state = 1;
1228 p_priv->dtr_state = 1;
1229 p_priv->baud = 9600;
1230
1231 /* force baud and lcr to be set on open */
1232 p_priv->old_baud = 0;
1233 p_priv->old_cflag = 0;
1234
1235 p_priv->out_flip = 0;
1236 p_priv->in_flip = 0;
1237
1238 /* Reset low level data toggle and start reading from endpoints */
1239 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001240 urb = p_priv->in_urbs[i];
1241 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 continue;
1243 urb->dev = serial->dev;
1244
Alan Coxdeb91682008-07-22 11:13:08 +01001245 /* make sure endpoint data toggle is synchronized
1246 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001248 err = usb_submit_urb(urb, GFP_KERNEL);
1249 if (err != 0)
1250 dbg("%s - submit urb %d failed (%d)",
1251 __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 }
1253
1254 /* Reset low level data toggle on out endpoints */
1255 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001256 urb = p_priv->out_urbs[i];
1257 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 continue;
1259 urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +01001260 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1261 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 }
1263
Andrew Mortonf78ba152007-11-28 16:21:54 -08001264 /* get the terminal config for the setup message now so we don't
1265 * need to send 2 of them */
1266
Andrew Mortonf78ba152007-11-28 16:21:54 -08001267 device_port = port->number - port->serial->minor;
Alan Cox95da3102008-07-22 11:09:07 +01001268 if (tty) {
1269 cflag = tty->termios->c_cflag;
1270 /* Baud rate calculation takes baud rate as an integer
1271 so other rates can be generated if desired. */
1272 baud_rate = tty_get_baud_rate(tty);
1273 /* If no match or invalid, leave as default */
1274 if (baud_rate >= 0
1275 && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
1276 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1277 p_priv->baud = baud_rate;
1278 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001279 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001280 /* set CTS/RTS handshake etc. */
1281 p_priv->cflag = cflag;
1282 p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;
1283
1284 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001285 /* mdelay(100); */
1286 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001287
Alan Coxa5b6f602008-04-08 17:16:06 +01001288 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289}
1290
1291static inline void stop_urb(struct urb *urb)
1292{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001293 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295}
1296
Alan Cox95da3102008-07-22 11:09:07 +01001297static void keyspan_close(struct tty_struct *tty,
1298 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299{
1300 int i;
1301 struct usb_serial *serial = port->serial;
1302 struct keyspan_serial_private *s_priv;
1303 struct keyspan_port_private *p_priv;
1304
Harvey Harrison441b62c2008-03-03 16:08:34 -08001305 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 s_priv = usb_get_serial_data(serial);
1307 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001308
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 p_priv->rts_state = 0;
1310 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001311
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 if (serial->dev) {
1313 keyspan_send_setup(port, 2);
1314 /* pilot-xfer seems to work best with this delay */
1315 mdelay(100);
Alan Coxdeb91682008-07-22 11:13:08 +01001316 /* keyspan_set_termios(port, NULL); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 }
1318
1319 /*while (p_priv->outcont_urb->status == -EINPROGRESS) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001320 dbg("%s - urb in progress", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 }*/
1322
1323 p_priv->out_flip = 0;
1324 p_priv->in_flip = 0;
1325
1326 if (serial->dev) {
1327 /* Stop reading/writing urbs */
1328 stop_urb(p_priv->inack_urb);
1329 /* stop_urb(p_priv->outcont_urb); */
1330 for (i = 0; i < 2; i++) {
1331 stop_urb(p_priv->in_urbs[i]);
1332 stop_urb(p_priv->out_urbs[i]);
1333 }
1334 }
Alan Cox95da3102008-07-22 11:09:07 +01001335 port->port.tty = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336}
1337
Alan Coxdeb91682008-07-22 11:13:08 +01001338/* download the firmware to a pre-renumeration device */
1339static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340{
1341 int response;
David Woodhouse2971c572008-05-30 14:04:03 +03001342 const struct ihex_binrec *record;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 char *fw_name;
David Woodhouse2971c572008-05-30 14:04:03 +03001344 const struct firmware *fw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
1346 dbg("Keyspan startup version %04x product %04x",
1347 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1348 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001349
1350 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1351 != 0x8000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 dbg("Firmware already loaded. Quitting.");
Alan Coxdeb91682008-07-22 11:13:08 +01001353 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 }
1355
1356 /* Select firmware image on the basis of idProduct */
1357 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1358 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001359 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 break;
1361
1362 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001363 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 break;
1365
1366 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001367 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 break;
1369
1370 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001371 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 break;
1373
1374 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001375 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001379 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001383 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 break;
1385
1386 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001387 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001391 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001393
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001395 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001397
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001399 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 break;
1401
1402 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001403 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 break;
1405
1406 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001407 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1408 le16_to_cpu(serial->dev->descriptor.idProduct));
1409 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 }
1411
David Woodhouse2971c572008-05-30 14:04:03 +03001412 if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 dev_err(&serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name);
1414 return(1);
1415 }
1416
1417 dbg("Uploading Keyspan %s firmware.", fw_name);
1418
1419 /* download the firmware image */
1420 response = ezusb_set_reset(serial, 1);
1421
David Woodhouse2971c572008-05-30 14:04:03 +03001422 record = (const struct ihex_binrec *)fw->data;
1423
1424 while (record) {
1425 response = ezusb_writememory(serial, be32_to_cpu(record->addr),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 (unsigned char *)record->data,
David Woodhouse2971c572008-05-30 14:04:03 +03001427 be16_to_cpu(record->len), 0xa0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 if (response < 0) {
Alan Coxdeb91682008-07-22 11:13:08 +01001429 dev_err(&serial->dev->dev, "ezusb_writememory failed for Keyspan firmware (%d %04X %p %d)\n",
David Woodhouse2971c572008-05-30 14:04:03 +03001430 response, be32_to_cpu(record->addr),
1431 record->data, be16_to_cpu(record->len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 break;
1433 }
David Woodhouse2971c572008-05-30 14:04:03 +03001434 record = ihex_next_binrec(record);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 }
David Woodhouse2971c572008-05-30 14:04:03 +03001436 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 /* bring device out of reset. Renumeration will occur in a
1438 moment and the new device will bind to the real driver */
1439 response = ezusb_set_reset(serial, 0);
1440
1441 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001442 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443}
1444
1445/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001446static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1447 int endpoint)
1448{
1449 struct usb_host_interface *iface_desc;
1450 struct usb_endpoint_descriptor *ep;
1451 int i;
1452
1453 iface_desc = serial->interface->cur_altsetting;
1454 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1455 ep = &iface_desc->endpoint[i].desc;
1456 if (ep->bEndpointAddress == endpoint)
1457 return ep;
1458 }
1459 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1460 "endpoint %x\n", endpoint);
1461 return NULL;
1462}
1463
Alan Coxdeb91682008-07-22 11:13:08 +01001464static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001466 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467{
1468 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001469 struct usb_endpoint_descriptor const *ep_desc;
1470 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471
1472 if (endpoint == -1)
1473 return NULL; /* endpoint not needed */
1474
Alan Coxdeb91682008-07-22 11:13:08 +01001475 dbg("%s - alloc for endpoint %d.", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
1477 if (urb == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01001478 dbg("%s - alloc for endpoint %d failed.", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 return NULL;
1480 }
1481
Lucy McCoy0ca12682007-05-18 12:10:41 -07001482 if (endpoint == 0) {
1483 /* control EP filled in when used */
1484 return urb;
1485 }
1486
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001487 ep_desc = find_ep(serial, endpoint);
1488 if (!ep_desc) {
1489 /* leak the urb, something's wrong and the callers don't care */
1490 return urb;
1491 }
1492 if (usb_endpoint_xfer_int(ep_desc)) {
1493 ep_type_name = "INT";
1494 usb_fill_int_urb(urb, serial->dev,
1495 usb_sndintpipe(serial->dev, endpoint) | dir,
1496 buf, len, callback, ctx,
1497 ep_desc->bInterval);
1498 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1499 ep_type_name = "BULK";
1500 usb_fill_bulk_urb(urb, serial->dev,
1501 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1502 buf, len, callback, ctx);
1503 } else {
1504 dev_warn(&serial->interface->dev,
1505 "unsupported endpoint type %x\n",
1506 ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
1507 usb_free_urb(urb);
1508 return NULL;
1509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001511 dbg("%s - using urb %p for %s endpoint %x",
1512 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 return urb;
1514}
1515
1516static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001517 void (*instat_callback)(struct urb *);
1518 void (*glocont_callback)(struct urb *);
1519 void (*indat_callback)(struct urb *);
1520 void (*outdat_callback)(struct urb *);
1521 void (*inack_callback)(struct urb *);
1522 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523} keyspan_callbacks[] = {
1524 {
1525 /* msg_usa26 callbacks */
1526 .instat_callback = usa26_instat_callback,
1527 .glocont_callback = usa26_glocont_callback,
1528 .indat_callback = usa26_indat_callback,
1529 .outdat_callback = usa2x_outdat_callback,
1530 .inack_callback = usa26_inack_callback,
1531 .outcont_callback = usa26_outcont_callback,
1532 }, {
1533 /* msg_usa28 callbacks */
1534 .instat_callback = usa28_instat_callback,
1535 .glocont_callback = usa28_glocont_callback,
1536 .indat_callback = usa28_indat_callback,
1537 .outdat_callback = usa2x_outdat_callback,
1538 .inack_callback = usa28_inack_callback,
1539 .outcont_callback = usa28_outcont_callback,
1540 }, {
1541 /* msg_usa49 callbacks */
1542 .instat_callback = usa49_instat_callback,
1543 .glocont_callback = usa49_glocont_callback,
1544 .indat_callback = usa49_indat_callback,
1545 .outdat_callback = usa2x_outdat_callback,
1546 .inack_callback = usa49_inack_callback,
1547 .outcont_callback = usa49_outcont_callback,
1548 }, {
1549 /* msg_usa90 callbacks */
1550 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001551 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 .indat_callback = usa90_indat_callback,
1553 .outdat_callback = usa2x_outdat_callback,
1554 .inack_callback = usa28_inack_callback,
1555 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001556 }, {
1557 /* msg_usa67 callbacks */
1558 .instat_callback = usa67_instat_callback,
1559 .glocont_callback = usa67_glocont_callback,
1560 .indat_callback = usa26_indat_callback,
1561 .outdat_callback = usa2x_outdat_callback,
1562 .inack_callback = usa26_inack_callback,
1563 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 }
1565};
1566
1567 /* Generic setup urbs function that uses
1568 data in device_details */
1569static void keyspan_setup_urbs(struct usb_serial *serial)
1570{
1571 int i, j;
1572 struct keyspan_serial_private *s_priv;
1573 const struct keyspan_device_details *d_details;
1574 struct usb_serial_port *port;
1575 struct keyspan_port_private *p_priv;
1576 struct callbacks *cback;
1577 int endp;
1578
Alan Coxdeb91682008-07-22 11:13:08 +01001579 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
1581 s_priv = usb_get_serial_data(serial);
1582 d_details = s_priv->device_details;
1583
Alan Coxdeb91682008-07-22 11:13:08 +01001584 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 cback = &keyspan_callbacks[d_details->msg_format];
1586
Alan Coxdeb91682008-07-22 11:13:08 +01001587 /* Allocate and set up urbs for each one that is in use,
1588 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 s_priv->instat_urb = keyspan_setup_urb
1590 (serial, d_details->instat_endpoint, USB_DIR_IN,
1591 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1592 cback->instat_callback);
1593
Lucy McCoy0ca12682007-05-18 12:10:41 -07001594 s_priv->indat_urb = keyspan_setup_urb
1595 (serial, d_details->indat_endpoint, USB_DIR_IN,
1596 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1597 usa49wg_indat_callback);
1598
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 s_priv->glocont_urb = keyspan_setup_urb
1600 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1601 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1602 cback->glocont_callback);
1603
Alan Coxdeb91682008-07-22 11:13:08 +01001604 /* Setup endpoints for each port specific thing */
1605 for (i = 0; i < d_details->num_ports; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 port = serial->port[i];
1607 p_priv = usb_get_serial_port_data(port);
1608
1609 /* Do indat endpoints first, once for each flip */
1610 endp = d_details->indat_endpoints[i];
1611 for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) {
1612 p_priv->in_urbs[j] = keyspan_setup_urb
1613 (serial, endp, USB_DIR_IN, port,
1614 p_priv->in_buffer[j], 64,
1615 cback->indat_callback);
1616 }
1617 for (; j < 2; ++j)
1618 p_priv->in_urbs[j] = NULL;
1619
1620 /* outdat endpoints also have flip */
1621 endp = d_details->outdat_endpoints[i];
1622 for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) {
1623 p_priv->out_urbs[j] = keyspan_setup_urb
1624 (serial, endp, USB_DIR_OUT, port,
1625 p_priv->out_buffer[j], 64,
1626 cback->outdat_callback);
1627 }
1628 for (; j < 2; ++j)
1629 p_priv->out_urbs[j] = NULL;
1630
1631 /* inack endpoint */
1632 p_priv->inack_urb = keyspan_setup_urb
1633 (serial, d_details->inack_endpoints[i], USB_DIR_IN,
1634 port, p_priv->inack_buffer, 1, cback->inack_callback);
1635
1636 /* outcont endpoint */
1637 p_priv->outcont_urb = keyspan_setup_urb
1638 (serial, d_details->outcont_endpoints[i], USB_DIR_OUT,
1639 port, p_priv->outcont_buffer, 64,
1640 cback->outcont_callback);
Alan Coxdeb91682008-07-22 11:13:08 +01001641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642}
1643
1644/* usa19 function doesn't require prescaler */
1645static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
1646 u8 *rate_low, u8 *prescaler, int portnum)
1647{
1648 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001649 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
Alan Coxdeb91682008-07-22 11:13:08 +01001652 dbg("%s - %d.", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
Alan Coxdeb91682008-07-22 11:13:08 +01001654 /* prevent divide by zero... */
1655 b16 = baud_rate * 16L;
1656 if (b16 == 0)
1657 return KEYSPAN_INVALID_BAUD_RATE;
1658 /* Any "standard" rate over 57k6 is marginal on the USA-19
1659 as we run out of divisor resolution. */
1660 if (baud_rate > 57600)
1661 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
Alan Coxdeb91682008-07-22 11:13:08 +01001663 /* calculate the divisor and the counter (its inverse) */
1664 div = baudclk / b16;
1665 if (div == 0)
1666 return KEYSPAN_INVALID_BAUD_RATE;
1667 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
Alan Coxdeb91682008-07-22 11:13:08 +01001670 if (div > 0xffff)
1671 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
Alan Coxdeb91682008-07-22 11:13:08 +01001673 /* return the counter values if non-null */
1674 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001676 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001678 if (rate_low && rate_hi)
1679 dbg("%s - %d %02x %02x.",
1680 __func__, baud_rate, *rate_hi, *rate_low);
1681 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682}
1683
1684/* usa19hs function doesn't require prescaler */
1685static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
1686 u8 *rate_low, u8 *prescaler, int portnum)
1687{
1688 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001689 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
Alan Coxdeb91682008-07-22 11:13:08 +01001691 dbg("%s - %d.", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
Alan Coxdeb91682008-07-22 11:13:08 +01001693 /* prevent divide by zero... */
1694 b16 = baud_rate * 16L;
1695 if (b16 == 0)
1696 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697
Alan Coxdeb91682008-07-22 11:13:08 +01001698 /* calculate the divisor */
1699 div = baudclk / b16;
1700 if (div == 0)
1701 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
Alan Coxdeb91682008-07-22 11:13:08 +01001703 if (div > 0xffff)
1704 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705
Alan Coxdeb91682008-07-22 11:13:08 +01001706 /* return the counter values if non-null */
1707 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001709
1710 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001712
1713 if (rate_low && rate_hi)
1714 dbg("%s - %d %02x %02x.",
1715 __func__, baud_rate, *rate_hi, *rate_low);
1716
1717 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718}
1719
1720static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
1721 u8 *rate_low, u8 *prescaler, int portnum)
1722{
1723 u32 b16, /* baud rate times 16 (actual rate used internally) */
1724 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001725 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 res, /* resulting baud rate using 13/8 prescaler */
1727 diff, /* error using 13/8 prescaler */
1728 smallest_diff;
1729 u8 best_prescaler;
1730 int i;
1731
Alan Coxdeb91682008-07-22 11:13:08 +01001732 dbg("%s - %d.", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
Alan Coxdeb91682008-07-22 11:13:08 +01001734 /* prevent divide by zero */
1735 b16 = baud_rate * 16L;
1736 if (b16 == 0)
1737 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
Alan Coxdeb91682008-07-22 11:13:08 +01001739 /* Calculate prescaler by trying them all and looking
1740 for best fit */
1741
1742 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 smallest_diff = 0xffffffff;
1744
1745 /* 0 is an invalid prescaler, used as a flag */
1746 best_prescaler = 0;
1747
Alan Coxdeb91682008-07-22 11:13:08 +01001748 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001750
1751 div = clk / b16;
1752 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
1755 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001756 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
Alan Coxdeb91682008-07-22 11:13:08 +01001758 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 best_prescaler = i;
1760 smallest_diff = diff;
1761 }
1762 }
1763
Alan Coxdeb91682008-07-22 11:13:08 +01001764 if (best_prescaler == 0)
1765 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
1767 clk = (baudclk * 8) / (u32) best_prescaler;
1768 div = clk / b16;
1769
Alan Coxdeb91682008-07-22 11:13:08 +01001770 /* return the divisor and prescaler if non-null */
1771 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001773 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 if (prescaler) {
1776 *prescaler = best_prescaler;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001777 /* dbg("%s - %d %d", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 }
Alan Coxdeb91682008-07-22 11:13:08 +01001779 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780}
1781
1782 /* USA-28 supports different maximum baud rates on each port */
1783static int keyspan_usa28_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
1784 u8 *rate_low, u8 *prescaler, int portnum)
1785{
1786 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001787 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 cnt; /* inverse of divisor (programmed into 8051) */
1789
Alan Coxdeb91682008-07-22 11:13:08 +01001790 dbg("%s - %d.", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
1792 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001793 b16 = baud_rate * 16L;
1794 if (b16 == 0)
1795 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
Alan Coxdeb91682008-07-22 11:13:08 +01001797 /* calculate the divisor and the counter (its inverse) */
1798 div = KEYSPAN_USA28_BAUDCLK / b16;
1799 if (div == 0)
1800 return KEYSPAN_INVALID_BAUD_RATE;
1801 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Alan Coxdeb91682008-07-22 11:13:08 +01001804 /* check for out of range, based on portnum,
1805 and return result */
1806 if (portnum == 0) {
1807 if (div > 0xffff)
1808 return KEYSPAN_INVALID_BAUD_RATE;
1809 } else {
1810 if (portnum == 1) {
1811 if (div > 0xff)
1812 return KEYSPAN_INVALID_BAUD_RATE;
1813 } else
1814 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 }
1816
1817 /* return the counter values if not NULL
1818 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001819 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001821 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001823 dbg("%s - %d OK.", __func__, baud_rate);
1824 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825}
1826
1827static int keyspan_usa26_send_setup(struct usb_serial *serial,
1828 struct usb_serial_port *port,
1829 int reset_port)
1830{
Alan Coxdeb91682008-07-22 11:13:08 +01001831 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 struct keyspan_serial_private *s_priv;
1833 struct keyspan_port_private *p_priv;
1834 const struct keyspan_device_details *d_details;
1835 int outcont_urb;
1836 struct urb *this_urb;
1837 int device_port, err;
1838
Alan Coxdeb91682008-07-22 11:13:08 +01001839 dbg("%s reset=%d", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
1841 s_priv = usb_get_serial_data(serial);
1842 p_priv = usb_get_serial_port_data(port);
1843 d_details = s_priv->device_details;
1844 device_port = port->number - port->serial->minor;
1845
1846 outcont_urb = d_details->outcont_endpoints[port->number];
1847 this_urb = p_priv->outcont_urb;
1848
Harvey Harrison441b62c2008-03-03 16:08:34 -08001849 dbg("%s - endpoint %d", __func__, usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
1851 /* Make sure we have an urb then send the message */
1852 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001853 dbg("%s - oops no urb.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 return -1;
1855 }
1856
1857 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001858 Don't overwrite resend for open/close condition. */
1859 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 p_priv->resend_cont = reset_port + 1;
1861 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01001862 /* dbg("%s - already writing", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001864 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 }
1866
Alan Coxdeb91682008-07-22 11:13:08 +01001867 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1868
1869 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 if (p_priv->old_baud != p_priv->baud) {
1871 p_priv->old_baud = p_priv->baud;
1872 msg.setClocking = 0xff;
1873 if (d_details->calculate_baud_rate
1874 (p_priv->baud, d_details->baudclk, &msg.baudHi,
Alan Coxdeb91682008-07-22 11:13:08 +01001875 &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1876 dbg("%s - Invalid baud rate %d requested, using 9600.",
1877 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 msg.baudLo = 0;
1879 msg.baudHi = 125; /* Values for 9600 baud */
1880 msg.prescaler = 10;
1881 }
1882 msg.setPrescaler = 0xff;
1883 }
1884
1885 msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
1886 switch (p_priv->cflag & CSIZE) {
1887 case CS5:
1888 msg.lcr |= USA_DATABITS_5;
1889 break;
1890 case CS6:
1891 msg.lcr |= USA_DATABITS_6;
1892 break;
1893 case CS7:
1894 msg.lcr |= USA_DATABITS_7;
1895 break;
1896 case CS8:
1897 msg.lcr |= USA_DATABITS_8;
1898 break;
1899 }
1900 if (p_priv->cflag & PARENB) {
1901 /* note USA_PARITY_NONE == 0 */
1902 msg.lcr |= (p_priv->cflag & PARODD)?
Alan Coxdeb91682008-07-22 11:13:08 +01001903 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 }
1905 msg.setLcr = 0xff;
1906
1907 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1908 msg.xonFlowControl = 0;
1909 msg.setFlowControl = 0xff;
1910 msg.forwardingLength = 16;
1911 msg.xonChar = 17;
1912 msg.xoffChar = 19;
1913
1914 /* Opening port */
1915 if (reset_port == 1) {
1916 msg._txOn = 1;
1917 msg._txOff = 0;
1918 msg.txFlush = 0;
1919 msg.txBreak = 0;
1920 msg.rxOn = 1;
1921 msg.rxOff = 0;
1922 msg.rxFlush = 1;
1923 msg.rxForward = 0;
1924 msg.returnStatus = 0;
1925 msg.resetDataToggle = 0xff;
1926 }
1927
1928 /* Closing port */
1929 else if (reset_port == 2) {
1930 msg._txOn = 0;
1931 msg._txOff = 1;
1932 msg.txFlush = 0;
1933 msg.txBreak = 0;
1934 msg.rxOn = 0;
1935 msg.rxOff = 1;
1936 msg.rxFlush = 1;
1937 msg.rxForward = 0;
1938 msg.returnStatus = 0;
1939 msg.resetDataToggle = 0;
1940 }
1941
1942 /* Sending intermediate configs */
1943 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001944 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 msg._txOff = 0;
1946 msg.txFlush = 0;
1947 msg.txBreak = (p_priv->break_on);
1948 msg.rxOn = 0;
1949 msg.rxOff = 0;
1950 msg.rxFlush = 0;
1951 msg.rxForward = 0;
1952 msg.returnStatus = 0;
1953 msg.resetDataToggle = 0x0;
1954 }
1955
Alan Coxdeb91682008-07-22 11:13:08 +01001956 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 msg.setTxTriState_setRts = 0xff;
1958 msg.txTriState_rts = p_priv->rts_state;
1959
1960 msg.setHskoa_setDtr = 0xff;
1961 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001962
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001964 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1965
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 /* send the data out the device on control endpoint */
1967 this_urb->transfer_buffer_length = sizeof(msg);
1968
1969 this_urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +01001970 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1971 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08001972 dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973#if 0
1974 else {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001975 dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 outcont_urb, this_urb->transfer_buffer_length,
1977 usb_pipeendpoint(this_urb->pipe));
1978 }
1979#endif
1980
Alan Coxa5b6f602008-04-08 17:16:06 +01001981 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982}
1983
1984static int keyspan_usa28_send_setup(struct usb_serial *serial,
1985 struct usb_serial_port *port,
1986 int reset_port)
1987{
Alan Coxdeb91682008-07-22 11:13:08 +01001988 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 struct keyspan_serial_private *s_priv;
1990 struct keyspan_port_private *p_priv;
1991 const struct keyspan_device_details *d_details;
1992 struct urb *this_urb;
1993 int device_port, err;
1994
Alan Coxdeb91682008-07-22 11:13:08 +01001995 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
1997 s_priv = usb_get_serial_data(serial);
1998 p_priv = usb_get_serial_port_data(port);
1999 d_details = s_priv->device_details;
2000 device_port = port->number - port->serial->minor;
2001
2002 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002003 this_urb = p_priv->outcont_urb;
2004 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002005 dbg("%s - oops no urb.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 return -1;
2007 }
2008
2009 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07002010 Don't overwrite resend for open/close condition. */
2011 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 p_priv->resend_cont = reset_port + 1;
2013 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01002014 dbg("%s already writing", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002016 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 }
2018
Alan Coxdeb91682008-07-22 11:13:08 +01002019 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020
2021 msg.setBaudRate = 1;
2022 if (d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk,
Alan Coxdeb91682008-07-22 11:13:08 +01002023 &msg.baudHi, &msg.baudLo, NULL, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2024 dbg("%s - Invalid baud rate requested %d.",
2025 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 msg.baudLo = 0xff;
2027 msg.baudHi = 0xb2; /* Values for 9600 baud */
2028 }
2029
2030 /* If parity is enabled, we must calculate it ourselves. */
2031 msg.parity = 0; /* XXX for now */
2032
2033 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2034 msg.xonFlowControl = 0;
2035
Alan Coxdeb91682008-07-22 11:13:08 +01002036 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 msg.rts = p_priv->rts_state;
2038 msg.dtr = p_priv->dtr_state;
2039
2040 msg.forwardingLength = 16;
2041 msg.forwardMs = 10;
2042 msg.breakThreshold = 45;
2043 msg.xonChar = 17;
2044 msg.xoffChar = 19;
2045
2046 /*msg.returnStatus = 1;
2047 msg.resetDataToggle = 0xff;*/
2048 /* Opening port */
2049 if (reset_port == 1) {
2050 msg._txOn = 1;
2051 msg._txOff = 0;
2052 msg.txFlush = 0;
2053 msg.txForceXoff = 0;
2054 msg.txBreak = 0;
2055 msg.rxOn = 1;
2056 msg.rxOff = 0;
2057 msg.rxFlush = 1;
2058 msg.rxForward = 0;
2059 msg.returnStatus = 0;
2060 msg.resetDataToggle = 0xff;
2061 }
2062 /* Closing port */
2063 else if (reset_port == 2) {
2064 msg._txOn = 0;
2065 msg._txOff = 1;
2066 msg.txFlush = 0;
2067 msg.txForceXoff = 0;
2068 msg.txBreak = 0;
2069 msg.rxOn = 0;
2070 msg.rxOff = 1;
2071 msg.rxFlush = 1;
2072 msg.rxForward = 0;
2073 msg.returnStatus = 0;
2074 msg.resetDataToggle = 0;
2075 }
2076 /* Sending intermediate configs */
2077 else {
Alan Coxdeb91682008-07-22 11:13:08 +01002078 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 msg._txOff = 0;
2080 msg.txFlush = 0;
2081 msg.txForceXoff = 0;
2082 msg.txBreak = (p_priv->break_on);
2083 msg.rxOn = 0;
2084 msg.rxOff = 0;
2085 msg.rxFlush = 0;
2086 msg.rxForward = 0;
2087 msg.returnStatus = 0;
2088 msg.resetDataToggle = 0x0;
2089 }
2090
2091 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002092 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
2094 /* send the data out the device on control endpoint */
2095 this_urb->transfer_buffer_length = sizeof(msg);
2096
2097 this_urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +01002098 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2099 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002100 dbg("%s - usb_submit_urb(setup) failed", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101#if 0
2102 else {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002103 dbg("%s - usb_submit_urb(setup) OK %d bytes", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 this_urb->transfer_buffer_length);
2105 }
2106#endif
2107
Alan Coxa5b6f602008-04-08 17:16:06 +01002108 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109}
2110
2111static int keyspan_usa49_send_setup(struct usb_serial *serial,
2112 struct usb_serial_port *port,
2113 int reset_port)
2114{
Lucy McCoy0ca12682007-05-18 12:10:41 -07002115 struct keyspan_usa49_portControlMessage msg;
2116 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 struct keyspan_serial_private *s_priv;
2118 struct keyspan_port_private *p_priv;
2119 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 struct urb *this_urb;
2121 int err, device_port;
2122
Alan Coxdeb91682008-07-22 11:13:08 +01002123 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124
2125 s_priv = usb_get_serial_data(serial);
2126 p_priv = usb_get_serial_port_data(port);
2127 d_details = s_priv->device_details;
2128
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 this_urb = s_priv->glocont_urb;
2130
Lucy McCoy0ca12682007-05-18 12:10:41 -07002131 /* Work out which port within the device is being setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 device_port = port->number - port->serial->minor;
2133
Alan Coxdeb91682008-07-22 11:13:08 +01002134 dbg("%s - endpoint %d port %d (%d)",
2135 __func__, usb_pipeendpoint(this_urb->pipe),
2136 port->number, device_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137
2138 /* Make sure we have an urb then send the message */
2139 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002140 dbg("%s - oops no urb for port %d.", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 return -1;
2142 }
2143
2144 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07002145 Don't overwrite resend for open/close condition. */
2146 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002148
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01002150 /* dbg("%s - already writing", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002152 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 }
2154
Alan Coxdeb91682008-07-22 11:13:08 +01002155 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156
2157 /*msg.portNumber = port->number;*/
2158 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01002159
2160 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 if (p_priv->old_baud != p_priv->baud) {
2162 p_priv->old_baud = p_priv->baud;
2163 msg.setClocking = 0xff;
2164 if (d_details->calculate_baud_rate
2165 (p_priv->baud, d_details->baudclk, &msg.baudHi,
Alan Coxdeb91682008-07-22 11:13:08 +01002166 &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2167 dbg("%s - Invalid baud rate %d requested, using 9600.",
2168 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 msg.baudLo = 0;
2170 msg.baudHi = 125; /* Values for 9600 baud */
2171 msg.prescaler = 10;
2172 }
Alan Coxdeb91682008-07-22 11:13:08 +01002173 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 }
2175
2176 msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
2177 switch (p_priv->cflag & CSIZE) {
2178 case CS5:
2179 msg.lcr |= USA_DATABITS_5;
2180 break;
2181 case CS6:
2182 msg.lcr |= USA_DATABITS_6;
2183 break;
2184 case CS7:
2185 msg.lcr |= USA_DATABITS_7;
2186 break;
2187 case CS8:
2188 msg.lcr |= USA_DATABITS_8;
2189 break;
2190 }
2191 if (p_priv->cflag & PARENB) {
2192 /* note USA_PARITY_NONE == 0 */
2193 msg.lcr |= (p_priv->cflag & PARODD)?
Alan Coxdeb91682008-07-22 11:13:08 +01002194 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 }
2196 msg.setLcr = 0xff;
2197
2198 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2199 msg.xonFlowControl = 0;
2200 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01002201
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 msg.forwardingLength = 16;
2203 msg.xonChar = 17;
2204 msg.xoffChar = 19;
2205
Alan Coxdeb91682008-07-22 11:13:08 +01002206 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 if (reset_port == 1) {
2208 msg._txOn = 1;
2209 msg._txOff = 0;
2210 msg.txFlush = 0;
2211 msg.txBreak = 0;
2212 msg.rxOn = 1;
2213 msg.rxOff = 0;
2214 msg.rxFlush = 1;
2215 msg.rxForward = 0;
2216 msg.returnStatus = 0;
2217 msg.resetDataToggle = 0xff;
2218 msg.enablePort = 1;
2219 msg.disablePort = 0;
2220 }
2221 /* Closing port */
2222 else if (reset_port == 2) {
2223 msg._txOn = 0;
2224 msg._txOff = 1;
2225 msg.txFlush = 0;
2226 msg.txBreak = 0;
2227 msg.rxOn = 0;
2228 msg.rxOff = 1;
2229 msg.rxFlush = 1;
2230 msg.rxForward = 0;
2231 msg.returnStatus = 0;
2232 msg.resetDataToggle = 0;
2233 msg.enablePort = 0;
2234 msg.disablePort = 1;
2235 }
2236 /* Sending intermediate configs */
2237 else {
Alan Coxdeb91682008-07-22 11:13:08 +01002238 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 msg._txOff = 0;
2240 msg.txFlush = 0;
2241 msg.txBreak = (p_priv->break_on);
2242 msg.rxOn = 0;
2243 msg.rxOff = 0;
2244 msg.rxFlush = 0;
2245 msg.rxForward = 0;
2246 msg.returnStatus = 0;
2247 msg.resetDataToggle = 0x0;
2248 msg.enablePort = 0;
2249 msg.disablePort = 0;
2250 }
2251
Alan Coxdeb91682008-07-22 11:13:08 +01002252 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 msg.setRts = 0xff;
2254 msg.rts = p_priv->rts_state;
2255
2256 msg.setDtr = 0xff;
2257 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002258
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260
Alan Coxdeb91682008-07-22 11:13:08 +01002261 /* if the device is a 49wg, we send control message on usb
2262 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002263
2264 if (d_details->product_id == keyspan_usa49wg_product_id) {
2265 dr = (void *)(s_priv->ctrl_buf);
2266 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
2267 dr->bRequest = 0xB0; /* 49wg control message */;
2268 dr->wValue = 0;
2269 dr->wIndex = 0;
2270 dr->wLength = cpu_to_le16(sizeof(msg));
2271
Alan Coxdeb91682008-07-22 11:13:08 +01002272 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07002273
Alan Coxdeb91682008-07-22 11:13:08 +01002274 usb_fill_control_urb(this_urb, serial->dev,
2275 usb_sndctrlpipe(serial->dev, 0),
2276 (unsigned char *)dr, s_priv->glocont_buf,
2277 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002278
2279 } else {
2280 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01002281
Lucy McCoy0ca12682007-05-18 12:10:41 -07002282 /* send the data out the device on control endpoint */
2283 this_urb->transfer_buffer_length = sizeof(msg);
2284
2285 this_urb->dev = serial->dev;
2286 }
Alan Coxdeb91682008-07-22 11:13:08 +01002287 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2288 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002289 dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290#if 0
2291 else {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002292 dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002293 outcont_urb, this_urb->transfer_buffer_length,
2294 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 }
2296#endif
2297
Alan Coxa5b6f602008-04-08 17:16:06 +01002298 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299}
2300
2301static int keyspan_usa90_send_setup(struct usb_serial *serial,
2302 struct usb_serial_port *port,
2303 int reset_port)
2304{
Alan Coxdeb91682008-07-22 11:13:08 +01002305 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 struct keyspan_serial_private *s_priv;
2307 struct keyspan_port_private *p_priv;
2308 const struct keyspan_device_details *d_details;
2309 struct urb *this_urb;
2310 int err;
2311 u8 prescaler;
2312
Alan Coxdeb91682008-07-22 11:13:08 +01002313 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
2315 s_priv = usb_get_serial_data(serial);
2316 p_priv = usb_get_serial_port_data(port);
2317 d_details = s_priv->device_details;
2318
2319 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002320 this_urb = p_priv->outcont_urb;
2321 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002322 dbg("%s - oops no urb.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 return -1;
2324 }
2325
2326 /* Save reset port val for resend.
2327 Don't overwrite resend for open/close condition. */
2328 if ((reset_port + 1) > p_priv->resend_cont)
2329 p_priv->resend_cont = reset_port + 1;
2330 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01002331 dbg("%s already writing", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002333 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 }
2335
Alan Coxdeb91682008-07-22 11:13:08 +01002336 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337
Alan Coxdeb91682008-07-22 11:13:08 +01002338 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 if (p_priv->old_baud != p_priv->baud) {
2340 p_priv->old_baud = p_priv->baud;
2341 msg.setClocking = 0x01;
2342 if (d_details->calculate_baud_rate
2343 (p_priv->baud, d_details->baudclk, &msg.baudHi,
Alan Coxdeb91682008-07-22 11:13:08 +01002344 &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2345 dbg("%s - Invalid baud rate %d requested, using 9600.",
2346 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 p_priv->baud = 9600;
Alan Coxdeb91682008-07-22 11:13:08 +01002348 d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2350 }
2351 msg.setRxMode = 1;
2352 msg.setTxMode = 1;
2353 }
2354
2355 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002356 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 msg.rxMode = RXMODE_DMA;
2358 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002359 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 msg.rxMode = RXMODE_BYHAND;
2361 msg.txMode = TXMODE_BYHAND;
2362 }
2363
2364 msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
2365 switch (p_priv->cflag & CSIZE) {
2366 case CS5:
2367 msg.lcr |= USA_DATABITS_5;
2368 break;
2369 case CS6:
2370 msg.lcr |= USA_DATABITS_6;
2371 break;
2372 case CS7:
2373 msg.lcr |= USA_DATABITS_7;
2374 break;
2375 case CS8:
2376 msg.lcr |= USA_DATABITS_8;
2377 break;
2378 }
2379 if (p_priv->cflag & PARENB) {
2380 /* note USA_PARITY_NONE == 0 */
2381 msg.lcr |= (p_priv->cflag & PARODD)?
Alan Coxdeb91682008-07-22 11:13:08 +01002382 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 }
2384 if (p_priv->old_cflag != p_priv->cflag) {
2385 p_priv->old_cflag = p_priv->cflag;
2386 msg.setLcr = 0x01;
2387 }
2388
2389 if (p_priv->flow_control == flow_cts)
2390 msg.txFlowControl = TXFLOW_CTS;
2391 msg.setTxFlowControl = 0x01;
2392 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002393
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002395 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 msg.txAckSetting = 0;
2397 msg.xonChar = 17;
2398 msg.xoffChar = 19;
2399
Alan Coxdeb91682008-07-22 11:13:08 +01002400 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 if (reset_port == 1) {
2402 msg.portEnabled = 1;
2403 msg.rxFlush = 1;
2404 msg.txBreak = (p_priv->break_on);
2405 }
2406 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002407 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 /* Sending intermediate configs */
2410 else {
Alan Cox95da3102008-07-22 11:09:07 +01002411 if (port->port.count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 msg.portEnabled = 1;
2413 msg.txBreak = (p_priv->break_on);
2414 }
2415
Alan Coxdeb91682008-07-22 11:13:08 +01002416 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 msg.setRts = 0x01;
2418 msg.rts = p_priv->rts_state;
2419
2420 msg.setDtr = 0x01;
2421 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002422
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002424 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2425
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 /* send the data out the device on control endpoint */
2427 this_urb->transfer_buffer_length = sizeof(msg);
2428
2429 this_urb->dev = serial->dev;
Alan Coxdeb91682008-07-22 11:13:08 +01002430 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2431 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002432 dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002433 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434}
2435
Lucy McCoy0ca12682007-05-18 12:10:41 -07002436static int keyspan_usa67_send_setup(struct usb_serial *serial,
2437 struct usb_serial_port *port,
2438 int reset_port)
2439{
2440 struct keyspan_usa67_portControlMessage msg;
2441 struct keyspan_serial_private *s_priv;
2442 struct keyspan_port_private *p_priv;
2443 const struct keyspan_device_details *d_details;
2444 struct urb *this_urb;
2445 int err, device_port;
2446
Alan Coxdeb91682008-07-22 11:13:08 +01002447 dbg("%s", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002448
2449 s_priv = usb_get_serial_data(serial);
2450 p_priv = usb_get_serial_port_data(port);
2451 d_details = s_priv->device_details;
2452
2453 this_urb = s_priv->glocont_urb;
2454
2455 /* Work out which port within the device is being setup */
2456 device_port = port->number - port->serial->minor;
2457
2458 /* Make sure we have an urb then send the message */
2459 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002460 dbg("%s - oops no urb for port %d.", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002461 port->number);
2462 return -1;
2463 }
2464
2465 /* Save reset port val for resend.
2466 Don't overwrite resend for open/close condition. */
2467 if ((reset_port + 1) > p_priv->resend_cont)
2468 p_priv->resend_cont = reset_port + 1;
2469 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01002470 /* dbg("%s - already writing", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002471 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002472 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002473 }
2474
2475 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2476
2477 msg.port = device_port;
2478
2479 /* Only set baud rate if it's changed */
2480 if (p_priv->old_baud != p_priv->baud) {
2481 p_priv->old_baud = p_priv->baud;
2482 msg.setClocking = 0xff;
2483 if (d_details->calculate_baud_rate
2484 (p_priv->baud, d_details->baudclk, &msg.baudHi,
Alan Coxdeb91682008-07-22 11:13:08 +01002485 &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2486 dbg("%s - Invalid baud rate %d requested, using 9600.",
2487 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002488 msg.baudLo = 0;
2489 msg.baudHi = 125; /* Values for 9600 baud */
2490 msg.prescaler = 10;
2491 }
2492 msg.setPrescaler = 0xff;
2493 }
2494
2495 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2496 switch (p_priv->cflag & CSIZE) {
2497 case CS5:
2498 msg.lcr |= USA_DATABITS_5;
2499 break;
2500 case CS6:
2501 msg.lcr |= USA_DATABITS_6;
2502 break;
2503 case CS7:
2504 msg.lcr |= USA_DATABITS_7;
2505 break;
2506 case CS8:
2507 msg.lcr |= USA_DATABITS_8;
2508 break;
2509 }
2510 if (p_priv->cflag & PARENB) {
2511 /* note USA_PARITY_NONE == 0 */
2512 msg.lcr |= (p_priv->cflag & PARODD)?
Alan Coxdeb91682008-07-22 11:13:08 +01002513 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002514 }
2515 msg.setLcr = 0xff;
2516
2517 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2518 msg.xonFlowControl = 0;
2519 msg.setFlowControl = 0xff;
2520 msg.forwardingLength = 16;
2521 msg.xonChar = 17;
2522 msg.xoffChar = 19;
2523
2524 if (reset_port == 1) {
2525 /* Opening port */
2526 msg._txOn = 1;
2527 msg._txOff = 0;
2528 msg.txFlush = 0;
2529 msg.txBreak = 0;
2530 msg.rxOn = 1;
2531 msg.rxOff = 0;
2532 msg.rxFlush = 1;
2533 msg.rxForward = 0;
2534 msg.returnStatus = 0;
2535 msg.resetDataToggle = 0xff;
2536 } else if (reset_port == 2) {
2537 /* Closing port */
2538 msg._txOn = 0;
2539 msg._txOff = 1;
2540 msg.txFlush = 0;
2541 msg.txBreak = 0;
2542 msg.rxOn = 0;
2543 msg.rxOff = 1;
2544 msg.rxFlush = 1;
2545 msg.rxForward = 0;
2546 msg.returnStatus = 0;
2547 msg.resetDataToggle = 0;
2548 } else {
2549 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002550 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002551 msg._txOff = 0;
2552 msg.txFlush = 0;
2553 msg.txBreak = (p_priv->break_on);
2554 msg.rxOn = 0;
2555 msg.rxOff = 0;
2556 msg.rxFlush = 0;
2557 msg.rxForward = 0;
2558 msg.returnStatus = 0;
2559 msg.resetDataToggle = 0x0;
2560 }
2561
2562 /* Do handshaking outputs */
2563 msg.setTxTriState_setRts = 0xff;
2564 msg.txTriState_rts = p_priv->rts_state;
2565
2566 msg.setHskoa_setDtr = 0xff;
2567 msg.hskoa_dtr = p_priv->dtr_state;
2568
2569 p_priv->resend_cont = 0;
2570
2571 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2572
2573 /* send the data out the device on control endpoint */
2574 this_urb->transfer_buffer_length = sizeof(msg);
2575 this_urb->dev = serial->dev;
2576
2577 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2578 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002579 dbg("%s - usb_submit_urb(setup) failed (%d)", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002580 err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002581 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002582}
2583
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2585{
2586 struct usb_serial *serial = port->serial;
2587 struct keyspan_serial_private *s_priv;
2588 const struct keyspan_device_details *d_details;
2589
Alan Coxdeb91682008-07-22 11:13:08 +01002590 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591
2592 s_priv = usb_get_serial_data(serial);
2593 d_details = s_priv->device_details;
2594
2595 switch (d_details->msg_format) {
2596 case msg_usa26:
2597 keyspan_usa26_send_setup(serial, port, reset_port);
2598 break;
2599 case msg_usa28:
2600 keyspan_usa28_send_setup(serial, port, reset_port);
2601 break;
2602 case msg_usa49:
2603 keyspan_usa49_send_setup(serial, port, reset_port);
2604 break;
2605 case msg_usa90:
2606 keyspan_usa90_send_setup(serial, port, reset_port);
2607 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002608 case msg_usa67:
2609 keyspan_usa67_send_setup(serial, port, reset_port);
2610 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 }
2612}
2613
2614
2615/* Gets called by the "real" driver (ie once firmware is loaded
2616 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002617static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618{
2619 int i, err;
2620 struct usb_serial_port *port;
2621 struct keyspan_serial_private *s_priv;
2622 struct keyspan_port_private *p_priv;
2623 const struct keyspan_device_details *d_details;
2624
Harvey Harrison441b62c2008-03-03 16:08:34 -08002625 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626
2627 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002628 if (d_details->product_id ==
2629 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 break;
2631 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002632 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2633 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 return 1;
2635 }
2636
2637 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002638 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 if (!s_priv) {
Alan Coxdeb91682008-07-22 11:13:08 +01002640 dbg("%s - kmalloc for keyspan_serial_private failed.",
2641 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 return -ENOMEM;
2643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
2645 s_priv->device_details = d_details;
2646 usb_set_serial_data(serial, s_priv);
2647
2648 /* Now setup per port private data */
2649 for (i = 0; i < serial->num_ports; i++) {
2650 port = serial->port[i];
Alan Coxdeb91682008-07-22 11:13:08 +01002651 p_priv = kzalloc(sizeof(struct keyspan_port_private),
2652 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 if (!p_priv) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002654 dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __func__, i);
Alan Coxdeb91682008-07-22 11:13:08 +01002655 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 p_priv->device_details = d_details;
2658 usb_set_serial_port_data(port, p_priv);
2659 }
2660
2661 keyspan_setup_urbs(serial);
2662
Lucy McCoy0ca12682007-05-18 12:10:41 -07002663 if (s_priv->instat_urb != NULL) {
2664 s_priv->instat_urb->dev = serial->dev;
2665 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2666 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002667 dbg("%s - submit instat urb failed %d", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002668 err);
2669 }
2670 if (s_priv->indat_urb != NULL) {
2671 s_priv->indat_urb->dev = serial->dev;
2672 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2673 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002674 dbg("%s - submit indat urb failed %d", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002675 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 }
Alan Coxdeb91682008-07-22 11:13:08 +01002677
Alan Coxa5b6f602008-04-08 17:16:06 +01002678 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679}
2680
Alan Coxdeb91682008-07-22 11:13:08 +01002681static void keyspan_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682{
2683 int i, j;
2684 struct usb_serial_port *port;
2685 struct keyspan_serial_private *s_priv;
2686 struct keyspan_port_private *p_priv;
2687
Harvey Harrison441b62c2008-03-03 16:08:34 -08002688 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
2690 s_priv = usb_get_serial_data(serial);
2691
2692 /* Stop reading/writing urbs */
2693 stop_urb(s_priv->instat_urb);
2694 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002695 stop_urb(s_priv->indat_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 for (i = 0; i < serial->num_ports; ++i) {
2697 port = serial->port[i];
2698 p_priv = usb_get_serial_port_data(port);
2699 stop_urb(p_priv->inack_urb);
2700 stop_urb(p_priv->outcont_urb);
2701 for (j = 0; j < 2; j++) {
2702 stop_urb(p_priv->in_urbs[j]);
2703 stop_urb(p_priv->out_urbs[j]);
2704 }
2705 }
2706
2707 /* Now free them */
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002708 usb_free_urb(s_priv->instat_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002709 usb_free_urb(s_priv->indat_urb);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002710 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 for (i = 0; i < serial->num_ports; ++i) {
2712 port = serial->port[i];
2713 p_priv = usb_get_serial_port_data(port);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002714 usb_free_urb(p_priv->inack_urb);
2715 usb_free_urb(p_priv->outcont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 for (j = 0; j < 2; j++) {
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002717 usb_free_urb(p_priv->in_urbs[j]);
2718 usb_free_urb(p_priv->out_urbs[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 }
2720 }
2721
2722 /* dbg("Freeing serial->private."); */
2723 kfree(s_priv);
2724
2725 /* dbg("Freeing port->private."); */
2726 /* Now free per port private data */
2727 for (i = 0; i < serial->num_ports; i++) {
2728 port = serial->port[i];
2729 kfree(usb_get_serial_port_data(port));
2730 }
2731}
2732
Alan Coxdeb91682008-07-22 11:13:08 +01002733MODULE_AUTHOR(DRIVER_AUTHOR);
2734MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735MODULE_LICENSE("GPL");
2736
David Woodhouse2971c572008-05-30 14:04:03 +03002737MODULE_FIRMWARE("keyspan/usa28.fw");
2738MODULE_FIRMWARE("keyspan/usa28x.fw");
2739MODULE_FIRMWARE("keyspan/usa28xa.fw");
2740MODULE_FIRMWARE("keyspan/usa28xb.fw");
2741MODULE_FIRMWARE("keyspan/usa19.fw");
2742MODULE_FIRMWARE("keyspan/usa19qi.fw");
2743MODULE_FIRMWARE("keyspan/mpr.fw");
2744MODULE_FIRMWARE("keyspan/usa19qw.fw");
2745MODULE_FIRMWARE("keyspan/usa18x.fw");
2746MODULE_FIRMWARE("keyspan/usa19w.fw");
2747MODULE_FIRMWARE("keyspan/usa49w.fw");
2748MODULE_FIRMWARE("keyspan/usa49wlc.fw");
2749
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750module_param(debug, bool, S_IRUGO | S_IWUSR);
2751MODULE_PARM_DESC(debug, "Debug enabled or not");
2752