blob: a39ddd1b0dcac5e61149adb35bc056cb4b943940 [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
Justin P. Mattock631dd1a2010-10-18 11:03:14 +020012 See http://blemings.org/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.
Linus Torvalds1da177e2005-04-16 15:20:36 -070028*/
29
30
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/kernel.h>
32#include <linux/jiffies.h>
33#include <linux/errno.h>
34#include <linux/init.h>
35#include <linux/slab.h>
36#include <linux/tty.h>
37#include <linux/tty_driver.h>
38#include <linux/tty_flip.h>
39#include <linux/module.h>
40#include <linux/spinlock.h>
David Woodhouse2971c572008-05-30 14:04:03 +030041#include <linux/firmware.h>
42#include <linux/ihex.h>
Alan Coxdeb91682008-07-22 11:13:08 +010043#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070045#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include "keyspan.h"
47
Rusty Russell90ab5ee2012-01-13 09:32:20 +103048static bool debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50/*
51 * Version Information
52 */
Lucy McCoy0ca12682007-05-18 12:10:41 -070053#define DRIVER_VERSION "v1.1.5"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
55#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
56
57#define INSTAT_BUFLEN 32
58#define GLOCONT_BUFLEN 64
Lucy McCoy0ca12682007-05-18 12:10:41 -070059#define INDAT49W_BUFLEN 512
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
61 /* Per device and per port private data */
62struct keyspan_serial_private {
63 const struct keyspan_device_details *device_details;
64
65 struct urb *instat_urb;
66 char instat_buf[INSTAT_BUFLEN];
67
Alan Coxdeb91682008-07-22 11:13:08 +010068 /* added to support 49wg, where data from all 4 ports comes in
69 on 1 EP and high-speed supported */
Lucy McCoy0ca12682007-05-18 12:10:41 -070070 struct urb *indat_urb;
71 char indat_buf[INDAT49W_BUFLEN];
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 /* XXX this one probably will need a lock */
74 struct urb *glocont_urb;
75 char glocont_buf[GLOCONT_BUFLEN];
Alan Coxdeb91682008-07-22 11:13:08 +010076 char ctrl_buf[8]; /* for EP0 control message */
Linus Torvalds1da177e2005-04-16 15:20:36 -070077};
78
79struct keyspan_port_private {
80 /* Keep track of which input & output endpoints to use */
81 int in_flip;
82 int out_flip;
83
84 /* Keep duplicate of device details in each port
85 structure as well - simplifies some of the
86 callback functions etc. */
87 const struct keyspan_device_details *device_details;
88
89 /* Input endpoints and buffer for this port */
90 struct urb *in_urbs[2];
91 char in_buffer[2][64];
92 /* Output endpoints and buffer for this port */
93 struct urb *out_urbs[2];
94 char out_buffer[2][64];
95
96 /* Input ack endpoint */
97 struct urb *inack_urb;
98 char inack_buffer[1];
99
100 /* Output control endpoint */
101 struct urb *outcont_urb;
102 char outcont_buffer[64];
103
104 /* Settings for the port */
105 int baud;
106 int old_baud;
107 unsigned int cflag;
108 unsigned int old_cflag;
109 enum {flow_none, flow_cts, flow_xon} flow_control;
110 int rts_state; /* Handshaking pins (outputs) */
111 int dtr_state;
112 int cts_state; /* Handshaking pins (inputs) */
113 int dsr_state;
114 int dcd_state;
115 int ri_state;
116 int break_on;
117
118 unsigned long tx_start_time[2];
119 int resend_cont; /* need to resend control packet */
120};
121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122/* Include Keyspan message headers. All current Keyspan Adapters
Lucy McCoy0ca12682007-05-18 12:10:41 -0700123 make use of one of five message formats which are referred
Alan Coxdeb91682008-07-22 11:13:08 +0100124 to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and
125 within this driver. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126#include "keyspan_usa26msg.h"
127#include "keyspan_usa28msg.h"
128#include "keyspan_usa49msg.h"
129#include "keyspan_usa90msg.h"
Lucy McCoy0ca12682007-05-18 12:10:41 -0700130#include "keyspan_usa67msg.h"
Alan Coxdeb91682008-07-22 11:13:08 +0100131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Greg Kroah-Hartman165c7932012-02-28 13:11:59 -0800133module_usb_serial_driver(keyspan_driver, serial_drivers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Alan Cox95da3102008-07-22 11:09:07 +0100135static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136{
Alan Cox95da3102008-07-22 11:09:07 +0100137 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 struct keyspan_port_private *p_priv;
139
Alan Coxdeb91682008-07-22 11:13:08 +0100140 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142 p_priv = usb_get_serial_port_data(port);
143
144 if (break_state == -1)
145 p_priv->break_on = 1;
146 else
147 p_priv->break_on = 0;
148
149 keyspan_send_setup(port, 0);
150}
151
152
Alan Coxdeb91682008-07-22 11:13:08 +0100153static void keyspan_set_termios(struct tty_struct *tty,
Alan Cox95da3102008-07-22 11:09:07 +0100154 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155{
156 int baud_rate, device_port;
157 struct keyspan_port_private *p_priv;
158 const struct keyspan_device_details *d_details;
159 unsigned int cflag;
160
Harvey Harrison441b62c2008-03-03 16:08:34 -0800161 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
163 p_priv = usb_get_serial_port_data(port);
164 d_details = p_priv->device_details;
Alan Cox74240b02007-10-18 01:24:20 -0700165 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 device_port = port->number - port->serial->minor;
167
168 /* Baud rate calculation takes baud rate as an integer
169 so other rates can be generated if desired. */
Alan Cox74240b02007-10-18 01:24:20 -0700170 baud_rate = tty_get_baud_rate(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100171 /* If no match or invalid, don't change */
Alan Cox74240b02007-10-18 01:24:20 -0700172 if (d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
174 /* FIXME - more to do here to ensure rate changes cleanly */
Alan Cox74240b02007-10-18 01:24:20 -0700175 /* FIXME - calcuate exact rate from divisor ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 p_priv->baud = baud_rate;
Alan Cox74240b02007-10-18 01:24:20 -0700177 } else
178 baud_rate = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Alan Cox74240b02007-10-18 01:24:20 -0700180 tty_encode_baud_rate(tty, baud_rate, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 /* set CTS/RTS handshake etc. */
182 p_priv->cflag = cflag;
183 p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;
184
Alan Cox74240b02007-10-18 01:24:20 -0700185 /* Mark/Space not supported */
186 tty->termios->c_cflag &= ~CMSPAR;
187
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 keyspan_send_setup(port, 0);
189}
190
Alan Cox60b33c12011-02-14 16:26:14 +0000191static int keyspan_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192{
Alan Cox95da3102008-07-22 11:09:07 +0100193 struct usb_serial_port *port = tty->driver_data;
194 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 unsigned int value;
Alan Coxdeb91682008-07-22 11:13:08 +0100196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
198 ((p_priv->dtr_state) ? TIOCM_DTR : 0) |
199 ((p_priv->cts_state) ? TIOCM_CTS : 0) |
200 ((p_priv->dsr_state) ? TIOCM_DSR : 0) |
201 ((p_priv->dcd_state) ? TIOCM_CAR : 0) |
Alan Coxdeb91682008-07-22 11:13:08 +0100202 ((p_priv->ri_state) ? TIOCM_RNG : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
204 return value;
205}
206
Alan Cox20b9d172011-02-14 16:26:50 +0000207static int keyspan_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 unsigned int set, unsigned int clear)
209{
Alan Cox95da3102008-07-22 11:09:07 +0100210 struct usb_serial_port *port = tty->driver_data;
211 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100212
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 if (set & TIOCM_RTS)
214 p_priv->rts_state = 1;
215 if (set & TIOCM_DTR)
216 p_priv->dtr_state = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 if (clear & TIOCM_RTS)
218 p_priv->rts_state = 0;
219 if (clear & TIOCM_DTR)
220 p_priv->dtr_state = 0;
221 keyspan_send_setup(port, 0);
222 return 0;
223}
224
Alan Cox95da3102008-07-22 11:09:07 +0100225/* Write function is similar for the four protocols used
226 with only a minor change for usa90 (usa19hs) required */
227static int keyspan_write(struct tty_struct *tty,
228 struct usb_serial_port *port, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
230 struct keyspan_port_private *p_priv;
231 const struct keyspan_device_details *d_details;
232 int flip;
233 int left, todo;
234 struct urb *this_urb;
Alan Coxdeb91682008-07-22 11:13:08 +0100235 int err, maxDataLen, dataOffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237 p_priv = usb_get_serial_port_data(port);
238 d_details = p_priv->device_details;
239
240 if (d_details->msg_format == msg_usa90) {
Alan Coxdeb91682008-07-22 11:13:08 +0100241 maxDataLen = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 dataOffset = 0;
243 } else {
244 maxDataLen = 63;
245 dataOffset = 1;
246 }
Alan Coxdeb91682008-07-22 11:13:08 +0100247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 dbg("%s - for port %d (%d chars), flip=%d",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800249 __func__, port->number, count, p_priv->out_flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251 for (left = count; left > 0; left -= todo) {
252 todo = left;
253 if (todo > maxDataLen)
254 todo = maxDataLen;
255
256 flip = p_priv->out_flip;
Alan Coxdeb91682008-07-22 11:13:08 +0100257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 /* Check we have a valid urb/endpoint before we use it... */
Alan Coxdeb91682008-07-22 11:13:08 +0100259 this_urb = p_priv->out_urbs[flip];
260 if (this_urb == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 /* no bulk out, so return 0 bytes written */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800262 dbg("%s - no output urb :(", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 return count;
264 }
265
Alan Coxdeb91682008-07-22 11:13:08 +0100266 dbg("%s - endpoint %d flip %d",
267 __func__, usb_pipeendpoint(this_urb->pipe), flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
269 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +0100270 if (time_before(jiffies,
271 p_priv->tx_start_time[flip] + 10 * HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 usb_unlink_urb(this_urb);
274 break;
275 }
276
Alan Coxdeb91682008-07-22 11:13:08 +0100277 /* First byte in buffer is "last flag" (except for usa19hx)
278 - unused so for now so set to zero */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 ((char *)this_urb->transfer_buffer)[0] = 0;
280
Alan Coxdeb91682008-07-22 11:13:08 +0100281 memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 buf += todo;
283
284 /* send the data out the bulk port */
285 this_urb->transfer_buffer_length = todo + dataOffset;
286
Alan Coxdeb91682008-07-22 11:13:08 +0100287 err = usb_submit_urb(this_urb, GFP_ATOMIC);
288 if (err != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 dbg("usb_submit_urb(write bulk) failed (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 p_priv->tx_start_time[flip] = jiffies;
291
292 /* Flip for next time if usa26 or usa28 interface
293 (not used on usa49) */
294 p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
295 }
296
297 return count - left;
298}
299
David Howells7d12e782006-10-05 14:55:46 +0100300static void usa26_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
302 int i, err;
303 int endpoint;
304 struct usb_serial_port *port;
305 struct tty_struct *tty;
306 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700307 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Alan Coxdeb91682008-07-22 11:13:08 +0100309 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 endpoint = usb_pipeendpoint(urb->pipe);
312
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700313 if (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 dbg("%s - nonzero status: %x on endpoint %d.",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800315 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 return;
317 }
318
Ming Leicdc97792008-02-24 18:41:47 +0800319 port = urb->context;
Alan Cox4a90f092008-10-13 10:39:46 +0100320 tty = tty_port_tty_get(&port->port);
Alan Coxa5569a52008-01-21 17:18:24 -0800321 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 /* 0x80 bit is error flag */
323 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100324 /* no errors on individual bytes, only
325 possible overrun err */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100327 err = TTY_OVERRUN;
328 else
329 err = 0;
330 for (i = 1; i < urb->actual_length ; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 tty_insert_flip_char(tty, data[i], err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 } else {
333 /* some bytes had errors, every byte has status */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800334 dbg("%s - RX error!!!!", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 for (i = 0; i + 1 < urb->actual_length; i += 2) {
336 int stat = data[i], flag = 0;
337 if (stat & RXERROR_OVERRUN)
338 flag |= TTY_OVERRUN;
339 if (stat & RXERROR_FRAMING)
340 flag |= TTY_FRAME;
341 if (stat & RXERROR_PARITY)
342 flag |= TTY_PARITY;
343 /* XXX should handle break (0x10) */
344 tty_insert_flip_char(tty, data[i+1], flag);
345 }
346 }
347 tty_flip_buffer_push(tty);
348 }
Alan Cox4a90f092008-10-13 10:39:46 +0100349 tty_kref_put(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100350
351 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500352 err = usb_submit_urb(urb, GFP_ATOMIC);
353 if (err != 0)
354 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355}
356
Alan Coxdeb91682008-07-22 11:13:08 +0100357/* Outdat handling is common for all devices */
David Howells7d12e782006-10-05 14:55:46 +0100358static void usa2x_outdat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359{
360 struct usb_serial_port *port;
361 struct keyspan_port_private *p_priv;
362
Ming Leicdc97792008-02-24 18:41:47 +0800363 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100365 dbg("%s - urb %d", __func__, urb == p_priv->out_urbs[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Alan Stern1f871582010-02-17 10:05:47 -0500367 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368}
369
David Howells7d12e782006-10-05 14:55:46 +0100370static void usa26_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{
Alan Coxdeb91682008-07-22 11:13:08 +0100372 dbg("%s", __func__);
373
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374}
375
David Howells7d12e782006-10-05 14:55:46 +0100376static void usa26_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
378 struct usb_serial_port *port;
379 struct keyspan_port_private *p_priv;
380
Ming Leicdc97792008-02-24 18:41:47 +0800381 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 p_priv = usb_get_serial_port_data(port);
383
384 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +0100385 dbg("%s - sending setup", __func__);
386 keyspan_usa26_send_setup(port->serial, port,
387 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 }
389}
390
David Howells7d12e782006-10-05 14:55:46 +0100391static void usa26_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392{
393 unsigned char *data = urb->transfer_buffer;
394 struct keyspan_usa26_portStatusMessage *msg;
395 struct usb_serial *serial;
396 struct usb_serial_port *port;
397 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100398 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700400 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Ming Leicdc97792008-02-24 18:41:47 +0800402 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700404 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800405 dbg("%s - nonzero status: %x", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 return;
407 }
408 if (urb->actual_length != 9) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800409 dbg("%s - %d byte report??", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 goto exit;
411 }
412
413 msg = (struct keyspan_usa26_portStatusMessage *)data;
414
415#if 0
416 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 -0800417 __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 msg->_txXoff, msg->rxEnabled, msg->controlResponse);
419#endif
420
421 /* Now do something useful with the data */
422
423
Alan Coxdeb91682008-07-22 11:13:08 +0100424 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 if (msg->port >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +0100426 dbg("%s - Unexpected port number %d", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 goto exit;
428 }
429 port = serial->port[msg->port];
430 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100431
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 /* Update handshaking pin state information */
433 old_dcd_state = p_priv->dcd_state;
434 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
435 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
436 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
437 p_priv->ri_state = ((msg->ri) ? 1 : 0);
438
Alan Cox4a90f092008-10-13 10:39:46 +0100439 if (old_dcd_state != p_priv->dcd_state) {
440 tty = tty_port_tty_get(&port->port);
441 if (tty && !C_CLOCAL(tty))
442 tty_hangup(tty);
443 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 }
Alan Coxdeb91682008-07-22 11:13:08 +0100445
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100447 err = usb_submit_urb(urb, GFP_ATOMIC);
448 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800449 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450exit: ;
451}
452
David Howells7d12e782006-10-05 14:55:46 +0100453static void usa26_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454{
Alan Coxdeb91682008-07-22 11:13:08 +0100455 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456}
457
458
David Howells7d12e782006-10-05 14:55:46 +0100459static void usa28_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460{
Alan Coxf035a8a2008-07-22 11:13:32 +0100461 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 struct usb_serial_port *port;
463 struct tty_struct *tty;
464 unsigned char *data;
465 struct keyspan_port_private *p_priv;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700466 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Alan Coxdeb91682008-07-22 11:13:08 +0100468 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Ming Leicdc97792008-02-24 18:41:47 +0800470 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 p_priv = usb_get_serial_port_data(port);
472 data = urb->transfer_buffer;
473
474 if (urb != p_priv->in_urbs[p_priv->in_flip])
475 return;
476
477 do {
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700478 if (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 dbg("%s - nonzero status: %x on endpoint %d.",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800480 __func__, status, usb_pipeendpoint(urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 return;
482 }
483
Ming Leicdc97792008-02-24 18:41:47 +0800484 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 p_priv = usb_get_serial_port_data(port);
486 data = urb->transfer_buffer;
487
Alan Cox4a90f092008-10-13 10:39:46 +0100488 tty =tty_port_tty_get(&port->port);
489 if (tty && urb->actual_length) {
Alan Coxf035a8a2008-07-22 11:13:32 +0100490 tty_insert_flip_string(tty, data, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 tty_flip_buffer_push(tty);
492 }
Alan Cox4a90f092008-10-13 10:39:46 +0100493 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500496 err = usb_submit_urb(urb, GFP_ATOMIC);
497 if (err != 0)
498 dbg("%s - resubmit read urb failed. (%d)",
499 __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 p_priv->in_flip ^= 1;
501
502 urb = p_priv->in_urbs[p_priv->in_flip];
503 } while (urb->status != -EINPROGRESS);
504}
505
David Howells7d12e782006-10-05 14:55:46 +0100506static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507{
Alan Coxdeb91682008-07-22 11:13:08 +0100508 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509}
510
David Howells7d12e782006-10-05 14:55:46 +0100511static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
513 struct usb_serial_port *port;
514 struct keyspan_port_private *p_priv;
515
Ming Leicdc97792008-02-24 18:41:47 +0800516 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 p_priv = usb_get_serial_port_data(port);
518
519 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +0100520 dbg("%s - sending setup", __func__);
521 keyspan_usa28_send_setup(port->serial, port,
522 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 }
524}
525
David Howells7d12e782006-10-05 14:55:46 +0100526static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
528 int err;
529 unsigned char *data = urb->transfer_buffer;
530 struct keyspan_usa28_portStatusMessage *msg;
531 struct usb_serial *serial;
532 struct usb_serial_port *port;
533 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100534 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700536 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Ming Leicdc97792008-02-24 18:41:47 +0800538 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700540 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800541 dbg("%s - nonzero status: %x", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 return;
543 }
544
545 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800546 dbg("%s - bad length %d", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 goto exit;
548 }
549
Harvey Harrison441b62c2008-03-03 16:08:34 -0800550 /*dbg("%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 data[0], data[1], data[2], data[3], data[4], data[5],
552 data[6], data[7], data[8], data[9], data[10], data[11]);*/
Alan Coxdeb91682008-07-22 11:13:08 +0100553
554 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 msg = (struct keyspan_usa28_portStatusMessage *)data;
556
Alan Coxdeb91682008-07-22 11:13:08 +0100557 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 if (msg->port >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +0100559 dbg("%s - Unexpected port number %d", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 goto exit;
561 }
562 port = serial->port[msg->port];
563 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 /* Update handshaking pin state information */
566 old_dcd_state = p_priv->dcd_state;
567 p_priv->cts_state = ((msg->cts) ? 1 : 0);
568 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
569 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
570 p_priv->ri_state = ((msg->ri) ? 1 : 0);
571
Alan Cox4a90f092008-10-13 10:39:46 +0100572 if( old_dcd_state != p_priv->dcd_state && old_dcd_state) {
573 tty = tty_port_tty_get(&port->port);
574 if (tty && !C_CLOCAL(tty))
575 tty_hangup(tty);
576 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 }
578
579 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100580 err = usb_submit_urb(urb, GFP_ATOMIC);
581 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800582 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583exit: ;
584}
585
David Howells7d12e782006-10-05 14:55:46 +0100586static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587{
Alan Coxdeb91682008-07-22 11:13:08 +0100588 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589}
590
591
David Howells7d12e782006-10-05 14:55:46 +0100592static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593{
594 struct usb_serial *serial;
595 struct usb_serial_port *port;
596 struct keyspan_port_private *p_priv;
597 int i;
598
Alan Coxdeb91682008-07-22 11:13:08 +0100599 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Ming Leicdc97792008-02-24 18:41:47 +0800601 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 for (i = 0; i < serial->num_ports; ++i) {
603 port = serial->port[i];
604 p_priv = usb_get_serial_port_data(port);
605
606 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +0100607 dbg("%s - sending setup", __func__);
608 keyspan_usa49_send_setup(serial, port,
609 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 break;
611 }
612 }
613}
614
615 /* This is actually called glostat in the Keyspan
616 doco */
David Howells7d12e782006-10-05 14:55:46 +0100617static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618{
619 int err;
620 unsigned char *data = urb->transfer_buffer;
621 struct keyspan_usa49_portStatusMessage *msg;
622 struct usb_serial *serial;
623 struct usb_serial_port *port;
624 struct keyspan_port_private *p_priv;
625 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700626 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
Alan Coxdeb91682008-07-22 11:13:08 +0100628 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
Ming Leicdc97792008-02-24 18:41:47 +0800630 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700632 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800633 dbg("%s - nonzero status: %x", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 return;
635 }
636
Alan Coxdeb91682008-07-22 11:13:08 +0100637 if (urb->actual_length !=
638 sizeof(struct keyspan_usa49_portStatusMessage)) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800639 dbg("%s - bad length %d", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 goto exit;
641 }
642
Harvey Harrison441b62c2008-03-03 16:08:34 -0800643 /*dbg(" %x %x %x %x %x %x %x %x %x %x %x", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 data[0], data[1], data[2], data[3], data[4], data[5],
645 data[6], data[7], data[8], data[9], data[10]);*/
Alan Coxdeb91682008-07-22 11:13:08 +0100646
647 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 msg = (struct keyspan_usa49_portStatusMessage *)data;
649
Alan Coxdeb91682008-07-22 11:13:08 +0100650 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 if (msg->portNumber >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +0100652 dbg("%s - Unexpected port number %d",
653 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 goto exit;
655 }
656 port = serial->port[msg->portNumber];
657 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 /* Update handshaking pin state information */
660 old_dcd_state = p_priv->dcd_state;
661 p_priv->cts_state = ((msg->cts) ? 1 : 0);
662 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
663 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
664 p_priv->ri_state = ((msg->ri) ? 1 : 0);
665
Alan Cox4a90f092008-10-13 10:39:46 +0100666 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
667 struct tty_struct *tty = tty_port_tty_get(&port->port);
668 if (tty && !C_CLOCAL(tty))
669 tty_hangup(tty);
670 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 }
672
Alan Coxdeb91682008-07-22 11:13:08 +0100673 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100674 err = usb_submit_urb(urb, GFP_ATOMIC);
675 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800676 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677exit: ;
678}
679
David Howells7d12e782006-10-05 14:55:46 +0100680static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681{
Alan Coxdeb91682008-07-22 11:13:08 +0100682 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683}
684
David Howells7d12e782006-10-05 14:55:46 +0100685static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
687 int i, err;
688 int endpoint;
689 struct usb_serial_port *port;
690 struct tty_struct *tty;
691 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700692 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Alan Coxdeb91682008-07-22 11:13:08 +0100694 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
696 endpoint = usb_pipeendpoint(urb->pipe);
697
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700698 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800699 dbg("%s - nonzero status: %x on endpoint %d.", __func__,
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700700 status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 return;
702 }
703
Ming Leicdc97792008-02-24 18:41:47 +0800704 port = urb->context;
Alan Cox4a90f092008-10-13 10:39:46 +0100705 tty = tty_port_tty_get(&port->port);
Alan Cox3004e532008-01-03 16:59:04 +0000706 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 /* 0x80 bit is error flag */
708 if ((data[0] & 0x80) == 0) {
709 /* no error on any byte */
Alan Coxf035a8a2008-07-22 11:13:32 +0100710 tty_insert_flip_string(tty, data + 1,
711 urb->actual_length - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 } else {
713 /* some bytes had errors, every byte has status */
714 for (i = 0; i + 1 < urb->actual_length; i += 2) {
715 int stat = data[i], flag = 0;
716 if (stat & RXERROR_OVERRUN)
717 flag |= TTY_OVERRUN;
718 if (stat & RXERROR_FRAMING)
719 flag |= TTY_FRAME;
720 if (stat & RXERROR_PARITY)
721 flag |= TTY_PARITY;
722 /* XXX should handle break (0x10) */
723 tty_insert_flip_char(tty, data[i+1], flag);
724 }
725 }
726 tty_flip_buffer_push(tty);
727 }
Alan Cox4a90f092008-10-13 10:39:46 +0100728 tty_kref_put(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100729
730 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500731 err = usb_submit_urb(urb, GFP_ATOMIC);
732 if (err != 0)
733 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734}
735
Lucy McCoy0ca12682007-05-18 12:10:41 -0700736static void usa49wg_indat_callback(struct urb *urb)
737{
738 int i, len, x, err;
739 struct usb_serial *serial;
740 struct usb_serial_port *port;
741 struct tty_struct *tty;
742 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700743 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700744
Alan Coxdeb91682008-07-22 11:13:08 +0100745 dbg("%s", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700746
747 serial = urb->context;
748
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700749 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800750 dbg("%s - nonzero status: %x", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700751 return;
752 }
753
754 /* inbound data is in the form P#, len, status, data */
755 i = 0;
756 len = 0;
757
758 if (urb->actual_length) {
759 while (i < urb->actual_length) {
760
761 /* Check port number from message*/
762 if (data[i] >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +0100763 dbg("%s - Unexpected port number %d",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800764 __func__, data[i]);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700765 return;
766 }
767 port = serial->port[data[i++]];
Alan Cox4a90f092008-10-13 10:39:46 +0100768 tty = tty_port_tty_get(&port->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700769 len = data[i++];
770
771 /* 0x80 bit is error flag */
772 if ((data[i] & 0x80) == 0) {
773 /* no error on any byte */
774 i++;
775 for (x = 1; x < len ; ++x)
Alan Stern1f871582010-02-17 10:05:47 -0500776 tty_insert_flip_char(tty, data[i++], 0);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700777 } else {
778 /*
779 * some bytes had errors, every byte has status
780 */
781 for (x = 0; x + 1 < len; x += 2) {
782 int stat = data[i], flag = 0;
783 if (stat & RXERROR_OVERRUN)
784 flag |= TTY_OVERRUN;
785 if (stat & RXERROR_FRAMING)
786 flag |= TTY_FRAME;
787 if (stat & RXERROR_PARITY)
788 flag |= TTY_PARITY;
789 /* XXX should handle break (0x10) */
Alan Stern1f871582010-02-17 10:05:47 -0500790 tty_insert_flip_char(tty,
Lucy McCoy0ca12682007-05-18 12:10:41 -0700791 data[i+1], flag);
792 i += 2;
793 }
794 }
Alan Stern1f871582010-02-17 10:05:47 -0500795 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100796 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700797 }
798 }
799
800 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700801 err = usb_submit_urb(urb, GFP_ATOMIC);
802 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800803 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700804}
805
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700807static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808{
Alan Coxdeb91682008-07-22 11:13:08 +0100809 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810}
811
Lucy McCoy0ca12682007-05-18 12:10:41 -0700812static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813{
814 int i, err;
815 int endpoint;
816 struct usb_serial_port *port;
817 struct keyspan_port_private *p_priv;
818 struct tty_struct *tty;
819 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700820 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
Alan Coxdeb91682008-07-22 11:13:08 +0100822 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 endpoint = usb_pipeendpoint(urb->pipe);
825
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700826 if (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 dbg("%s - nonzero status: %x on endpoint %d.",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800828 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 return;
830 }
831
Ming Leicdc97792008-02-24 18:41:47 +0800832 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 p_priv = usb_get_serial_port_data(port);
834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 if (urb->actual_length) {
Alan Cox4a90f092008-10-13 10:39:46 +0100836 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100838 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
Alan Coxf035a8a2008-07-22 11:13:32 +0100840 if (p_priv->baud > 57600)
841 tty_insert_flip_string(tty, data, urb->actual_length);
842 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 /* 0x80 bit is error flag */
844 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100845 /* no errors on individual bytes, only
846 possible overrun err*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100848 err = TTY_OVERRUN;
849 else
850 err = 0;
851 for (i = 1; i < urb->actual_length ; ++i)
852 tty_insert_flip_char(tty, data[i],
853 err);
854 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 /* some bytes had errors, every byte has status */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800856 dbg("%s - RX error!!!!", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 for (i = 0; i + 1 < urb->actual_length; i += 2) {
858 int stat = data[i], flag = 0;
859 if (stat & RXERROR_OVERRUN)
860 flag |= TTY_OVERRUN;
861 if (stat & RXERROR_FRAMING)
862 flag |= TTY_FRAME;
863 if (stat & RXERROR_PARITY)
864 flag |= TTY_PARITY;
865 /* XXX should handle break (0x10) */
Alan Coxdeb91682008-07-22 11:13:08 +0100866 tty_insert_flip_char(tty, data[i+1],
867 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 }
869 }
870 }
871 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100872 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 }
Alan Coxdeb91682008-07-22 11:13:08 +0100874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500876 err = usb_submit_urb(urb, GFP_ATOMIC);
877 if (err != 0)
878 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879}
880
881
David Howells7d12e782006-10-05 14:55:46 +0100882static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
884 unsigned char *data = urb->transfer_buffer;
885 struct keyspan_usa90_portStatusMessage *msg;
886 struct usb_serial *serial;
887 struct usb_serial_port *port;
888 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100889 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700891 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
Ming Leicdc97792008-02-24 18:41:47 +0800893 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700895 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800896 dbg("%s - nonzero status: %x", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 return;
898 }
899 if (urb->actual_length < 14) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800900 dbg("%s - %d byte report??", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 goto exit;
902 }
903
904 msg = (struct keyspan_usa90_portStatusMessage *)data;
905
906 /* Now do something useful with the data */
907
908 port = serial->port[0];
909 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100910
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 /* Update handshaking pin state information */
912 old_dcd_state = p_priv->dcd_state;
913 p_priv->cts_state = ((msg->cts) ? 1 : 0);
914 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
915 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
916 p_priv->ri_state = ((msg->ri) ? 1 : 0);
917
Alan Cox4a90f092008-10-13 10:39:46 +0100918 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
919 tty = tty_port_tty_get(&port->port);
920 if (tty && !C_CLOCAL(tty))
921 tty_hangup(tty);
922 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 }
Alan Coxdeb91682008-07-22 11:13:08 +0100924
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100926 err = usb_submit_urb(urb, GFP_ATOMIC);
927 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800928 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929exit:
930 ;
931}
932
David Howells7d12e782006-10-05 14:55:46 +0100933static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934{
935 struct usb_serial_port *port;
936 struct keyspan_port_private *p_priv;
937
Ming Leicdc97792008-02-24 18:41:47 +0800938 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 p_priv = usb_get_serial_port_data(port);
940
941 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +0100942 dbg("%s - sending setup", __func__);
943 keyspan_usa90_send_setup(port->serial, port,
944 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 }
946}
947
Lucy McCoy0ca12682007-05-18 12:10:41 -0700948/* Status messages from the 28xg */
949static void usa67_instat_callback(struct urb *urb)
950{
951 int err;
952 unsigned char *data = urb->transfer_buffer;
953 struct keyspan_usa67_portStatusMessage *msg;
954 struct usb_serial *serial;
955 struct usb_serial_port *port;
956 struct keyspan_port_private *p_priv;
957 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700958 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700959
Alan Coxdeb91682008-07-22 11:13:08 +0100960 dbg("%s", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700961
962 serial = urb->context;
963
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700964 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800965 dbg("%s - nonzero status: %x", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700966 return;
967 }
968
Alan Coxdeb91682008-07-22 11:13:08 +0100969 if (urb->actual_length !=
970 sizeof(struct keyspan_usa67_portStatusMessage)) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800971 dbg("%s - bad length %d", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700972 return;
973 }
974
975
976 /* Now do something useful with the data */
977 msg = (struct keyspan_usa67_portStatusMessage *)data;
978
979 /* Check port number from message and retrieve private data */
980 if (msg->port >= serial->num_ports) {
Alan Coxdeb91682008-07-22 11:13:08 +0100981 dbg("%s - Unexpected port number %d", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700982 return;
983 }
984
985 port = serial->port[msg->port];
986 p_priv = usb_get_serial_port_data(port);
987
988 /* Update handshaking pin state information */
989 old_dcd_state = p_priv->dcd_state;
990 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
991 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
992
Alan Cox4a90f092008-10-13 10:39:46 +0100993 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
994 struct tty_struct *tty = tty_port_tty_get(&port->port);
995 if (tty && !C_CLOCAL(tty))
996 tty_hangup(tty);
997 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700998 }
999
1000 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -07001001 err = usb_submit_urb(urb, GFP_ATOMIC);
1002 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08001003 dbg("%s - resubmit read urb failed. (%d)", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001004}
1005
1006static void usa67_glocont_callback(struct urb *urb)
1007{
1008 struct usb_serial *serial;
1009 struct usb_serial_port *port;
1010 struct keyspan_port_private *p_priv;
1011 int i;
1012
Alan Coxdeb91682008-07-22 11:13:08 +01001013 dbg("%s", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001014
1015 serial = urb->context;
1016 for (i = 0; i < serial->num_ports; ++i) {
1017 port = serial->port[i];
1018 p_priv = usb_get_serial_port_data(port);
1019
1020 if (p_priv->resend_cont) {
Alan Coxdeb91682008-07-22 11:13:08 +01001021 dbg("%s - sending setup", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001022 keyspan_usa67_send_setup(serial, port,
1023 p_priv->resend_cont - 1);
1024 break;
1025 }
1026 }
1027}
1028
Alan Cox95da3102008-07-22 11:09:07 +01001029static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030{
Alan Cox95da3102008-07-22 11:09:07 +01001031 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 struct keyspan_port_private *p_priv;
1033 const struct keyspan_device_details *d_details;
1034 int flip;
1035 int data_len;
1036 struct urb *this_urb;
1037
Harvey Harrison441b62c2008-03-03 16:08:34 -08001038 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 p_priv = usb_get_serial_port_data(port);
1040 d_details = p_priv->device_details;
1041
Alan Coxa5b6f602008-04-08 17:16:06 +01001042 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +01001044 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 else
1046 data_len = 63;
1047
1048 flip = p_priv->out_flip;
1049
1050 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +01001051 this_urb = p_priv->out_urbs[flip];
1052 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001054 return data_len;
1055 flip = (flip + 1) & d_details->outdat_endp_flip;
1056 this_urb = p_priv->out_urbs[flip];
1057 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001059 return data_len;
1060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 }
Alan Coxa5b6f602008-04-08 17:16:06 +01001062 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063}
1064
1065
Alan Coxa509a7e2009-09-19 13:13:26 -07001066static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001068 struct keyspan_port_private *p_priv;
1069 struct keyspan_serial_private *s_priv;
1070 struct usb_serial *serial = port->serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 const struct keyspan_device_details *d_details;
1072 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001073 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001075 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
1077 s_priv = usb_get_serial_data(serial);
1078 p_priv = usb_get_serial_port_data(port);
1079 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001080
Harvey Harrison441b62c2008-03-03 16:08:34 -08001081 dbg("%s - port%d.", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
1083 /* Set some sane defaults */
1084 p_priv->rts_state = 1;
1085 p_priv->dtr_state = 1;
1086 p_priv->baud = 9600;
1087
1088 /* force baud and lcr to be set on open */
1089 p_priv->old_baud = 0;
1090 p_priv->old_cflag = 0;
1091
1092 p_priv->out_flip = 0;
1093 p_priv->in_flip = 0;
1094
1095 /* Reset low level data toggle and start reading from endpoints */
1096 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001097 urb = p_priv->in_urbs[i];
1098 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
Alan Coxdeb91682008-07-22 11:13:08 +01001101 /* make sure endpoint data toggle is synchronized
1102 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001104 err = usb_submit_urb(urb, GFP_KERNEL);
1105 if (err != 0)
1106 dbg("%s - submit urb %d failed (%d)",
1107 __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 }
1109
1110 /* Reset low level data toggle on out endpoints */
1111 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001112 urb = p_priv->out_urbs[i];
1113 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 continue;
Alan Coxdeb91682008-07-22 11:13:08 +01001115 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1116 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 }
1118
Andrew Mortonf78ba152007-11-28 16:21:54 -08001119 /* get the terminal config for the setup message now so we don't
1120 * need to send 2 of them */
1121
Andrew Mortonf78ba152007-11-28 16:21:54 -08001122 device_port = port->number - port->serial->minor;
Alan Cox95da3102008-07-22 11:09:07 +01001123 if (tty) {
1124 cflag = tty->termios->c_cflag;
1125 /* Baud rate calculation takes baud rate as an integer
1126 so other rates can be generated if desired. */
1127 baud_rate = tty_get_baud_rate(tty);
1128 /* If no match or invalid, leave as default */
1129 if (baud_rate >= 0
1130 && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
1131 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1132 p_priv->baud = baud_rate;
1133 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001134 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001135 /* set CTS/RTS handshake etc. */
1136 p_priv->cflag = cflag;
1137 p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;
1138
1139 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001140 /* mdelay(100); */
1141 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001142
Alan Coxa5b6f602008-04-08 17:16:06 +01001143 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144}
1145
1146static inline void stop_urb(struct urb *urb)
1147{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001148 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150}
1151
Alan Cox335f8512009-06-11 12:26:29 +01001152static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1153{
1154 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1155
1156 p_priv->rts_state = on;
1157 p_priv->dtr_state = on;
1158 keyspan_send_setup(port, 0);
1159}
1160
1161static void keyspan_close(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162{
1163 int i;
1164 struct usb_serial *serial = port->serial;
1165 struct keyspan_serial_private *s_priv;
1166 struct keyspan_port_private *p_priv;
1167
Harvey Harrison441b62c2008-03-03 16:08:34 -08001168 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 s_priv = usb_get_serial_data(serial);
1170 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001171
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 p_priv->rts_state = 0;
1173 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 if (serial->dev) {
1176 keyspan_send_setup(port, 2);
1177 /* pilot-xfer seems to work best with this delay */
1178 mdelay(100);
Alan Coxdeb91682008-07-22 11:13:08 +01001179 /* keyspan_set_termios(port, NULL); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 }
1181
1182 /*while (p_priv->outcont_urb->status == -EINPROGRESS) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001183 dbg("%s - urb in progress", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 }*/
1185
1186 p_priv->out_flip = 0;
1187 p_priv->in_flip = 0;
1188
1189 if (serial->dev) {
1190 /* Stop reading/writing urbs */
1191 stop_urb(p_priv->inack_urb);
1192 /* stop_urb(p_priv->outcont_urb); */
1193 for (i = 0; i < 2; i++) {
1194 stop_urb(p_priv->in_urbs[i]);
1195 stop_urb(p_priv->out_urbs[i]);
1196 }
1197 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198}
1199
Alan Coxdeb91682008-07-22 11:13:08 +01001200/* download the firmware to a pre-renumeration device */
1201static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
1203 int response;
David Woodhouse2971c572008-05-30 14:04:03 +03001204 const struct ihex_binrec *record;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 char *fw_name;
David Woodhouse2971c572008-05-30 14:04:03 +03001206 const struct firmware *fw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
1208 dbg("Keyspan startup version %04x product %04x",
1209 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1210 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001211
1212 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1213 != 0x8000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 dbg("Firmware already loaded. Quitting.");
Alan Coxdeb91682008-07-22 11:13:08 +01001215 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 }
1217
1218 /* Select firmware image on the basis of idProduct */
1219 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1220 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001221 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 break;
1223
1224 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001225 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 break;
1227
1228 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001229 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 break;
1231
1232 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001233 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 break;
1235
1236 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001237 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001239
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001241 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001243
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001245 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 break;
1247
1248 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001249 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001251
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001253 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001255
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001257 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001259
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001261 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 break;
1263
1264 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001265 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 break;
1267
1268 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001269 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1270 le16_to_cpu(serial->dev->descriptor.idProduct));
1271 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 }
1273
David Woodhouse2971c572008-05-30 14:04:03 +03001274 if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 dev_err(&serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name);
1276 return(1);
1277 }
1278
1279 dbg("Uploading Keyspan %s firmware.", fw_name);
1280
1281 /* download the firmware image */
1282 response = ezusb_set_reset(serial, 1);
1283
David Woodhouse2971c572008-05-30 14:04:03 +03001284 record = (const struct ihex_binrec *)fw->data;
1285
1286 while (record) {
1287 response = ezusb_writememory(serial, be32_to_cpu(record->addr),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 (unsigned char *)record->data,
David Woodhouse2971c572008-05-30 14:04:03 +03001289 be16_to_cpu(record->len), 0xa0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 if (response < 0) {
Alan Coxdeb91682008-07-22 11:13:08 +01001291 dev_err(&serial->dev->dev, "ezusb_writememory failed for Keyspan firmware (%d %04X %p %d)\n",
David Woodhouse2971c572008-05-30 14:04:03 +03001292 response, be32_to_cpu(record->addr),
1293 record->data, be16_to_cpu(record->len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 break;
1295 }
David Woodhouse2971c572008-05-30 14:04:03 +03001296 record = ihex_next_binrec(record);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 }
David Woodhouse2971c572008-05-30 14:04:03 +03001298 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 /* bring device out of reset. Renumeration will occur in a
1300 moment and the new device will bind to the real driver */
1301 response = ezusb_set_reset(serial, 0);
1302
1303 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001304 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305}
1306
1307/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001308static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1309 int endpoint)
1310{
1311 struct usb_host_interface *iface_desc;
1312 struct usb_endpoint_descriptor *ep;
1313 int i;
1314
1315 iface_desc = serial->interface->cur_altsetting;
1316 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1317 ep = &iface_desc->endpoint[i].desc;
1318 if (ep->bEndpointAddress == endpoint)
1319 return ep;
1320 }
1321 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1322 "endpoint %x\n", endpoint);
1323 return NULL;
1324}
1325
Alan Coxdeb91682008-07-22 11:13:08 +01001326static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001328 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329{
1330 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001331 struct usb_endpoint_descriptor const *ep_desc;
1332 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
1334 if (endpoint == -1)
1335 return NULL; /* endpoint not needed */
1336
Alan Coxdeb91682008-07-22 11:13:08 +01001337 dbg("%s - alloc for endpoint %d.", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
1339 if (urb == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01001340 dbg("%s - alloc for endpoint %d failed.", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 return NULL;
1342 }
1343
Lucy McCoy0ca12682007-05-18 12:10:41 -07001344 if (endpoint == 0) {
1345 /* control EP filled in when used */
1346 return urb;
1347 }
1348
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001349 ep_desc = find_ep(serial, endpoint);
1350 if (!ep_desc) {
1351 /* leak the urb, something's wrong and the callers don't care */
1352 return urb;
1353 }
1354 if (usb_endpoint_xfer_int(ep_desc)) {
1355 ep_type_name = "INT";
1356 usb_fill_int_urb(urb, serial->dev,
1357 usb_sndintpipe(serial->dev, endpoint) | dir,
1358 buf, len, callback, ctx,
1359 ep_desc->bInterval);
1360 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1361 ep_type_name = "BULK";
1362 usb_fill_bulk_urb(urb, serial->dev,
1363 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1364 buf, len, callback, ctx);
1365 } else {
1366 dev_warn(&serial->interface->dev,
1367 "unsupported endpoint type %x\n",
Julia Lawall2e0fe702008-12-29 11:22:14 +01001368 usb_endpoint_type(ep_desc));
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001369 usb_free_urb(urb);
1370 return NULL;
1371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001373 dbg("%s - using urb %p for %s endpoint %x",
1374 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 return urb;
1376}
1377
1378static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001379 void (*instat_callback)(struct urb *);
1380 void (*glocont_callback)(struct urb *);
1381 void (*indat_callback)(struct urb *);
1382 void (*outdat_callback)(struct urb *);
1383 void (*inack_callback)(struct urb *);
1384 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385} keyspan_callbacks[] = {
1386 {
1387 /* msg_usa26 callbacks */
1388 .instat_callback = usa26_instat_callback,
1389 .glocont_callback = usa26_glocont_callback,
1390 .indat_callback = usa26_indat_callback,
1391 .outdat_callback = usa2x_outdat_callback,
1392 .inack_callback = usa26_inack_callback,
1393 .outcont_callback = usa26_outcont_callback,
1394 }, {
1395 /* msg_usa28 callbacks */
1396 .instat_callback = usa28_instat_callback,
1397 .glocont_callback = usa28_glocont_callback,
1398 .indat_callback = usa28_indat_callback,
1399 .outdat_callback = usa2x_outdat_callback,
1400 .inack_callback = usa28_inack_callback,
1401 .outcont_callback = usa28_outcont_callback,
1402 }, {
1403 /* msg_usa49 callbacks */
1404 .instat_callback = usa49_instat_callback,
1405 .glocont_callback = usa49_glocont_callback,
1406 .indat_callback = usa49_indat_callback,
1407 .outdat_callback = usa2x_outdat_callback,
1408 .inack_callback = usa49_inack_callback,
1409 .outcont_callback = usa49_outcont_callback,
1410 }, {
1411 /* msg_usa90 callbacks */
1412 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001413 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 .indat_callback = usa90_indat_callback,
1415 .outdat_callback = usa2x_outdat_callback,
1416 .inack_callback = usa28_inack_callback,
1417 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001418 }, {
1419 /* msg_usa67 callbacks */
1420 .instat_callback = usa67_instat_callback,
1421 .glocont_callback = usa67_glocont_callback,
1422 .indat_callback = usa26_indat_callback,
1423 .outdat_callback = usa2x_outdat_callback,
1424 .inack_callback = usa26_inack_callback,
1425 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 }
1427};
1428
1429 /* Generic setup urbs function that uses
1430 data in device_details */
1431static void keyspan_setup_urbs(struct usb_serial *serial)
1432{
1433 int i, j;
1434 struct keyspan_serial_private *s_priv;
1435 const struct keyspan_device_details *d_details;
1436 struct usb_serial_port *port;
1437 struct keyspan_port_private *p_priv;
1438 struct callbacks *cback;
1439 int endp;
1440
Alan Coxdeb91682008-07-22 11:13:08 +01001441 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
1443 s_priv = usb_get_serial_data(serial);
1444 d_details = s_priv->device_details;
1445
Alan Coxdeb91682008-07-22 11:13:08 +01001446 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 cback = &keyspan_callbacks[d_details->msg_format];
1448
Alan Coxdeb91682008-07-22 11:13:08 +01001449 /* Allocate and set up urbs for each one that is in use,
1450 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 s_priv->instat_urb = keyspan_setup_urb
1452 (serial, d_details->instat_endpoint, USB_DIR_IN,
1453 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1454 cback->instat_callback);
1455
Lucy McCoy0ca12682007-05-18 12:10:41 -07001456 s_priv->indat_urb = keyspan_setup_urb
1457 (serial, d_details->indat_endpoint, USB_DIR_IN,
1458 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1459 usa49wg_indat_callback);
1460
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 s_priv->glocont_urb = keyspan_setup_urb
1462 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1463 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1464 cback->glocont_callback);
1465
Alan Coxdeb91682008-07-22 11:13:08 +01001466 /* Setup endpoints for each port specific thing */
1467 for (i = 0; i < d_details->num_ports; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 port = serial->port[i];
1469 p_priv = usb_get_serial_port_data(port);
1470
1471 /* Do indat endpoints first, once for each flip */
1472 endp = d_details->indat_endpoints[i];
1473 for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) {
1474 p_priv->in_urbs[j] = keyspan_setup_urb
1475 (serial, endp, USB_DIR_IN, port,
1476 p_priv->in_buffer[j], 64,
1477 cback->indat_callback);
1478 }
1479 for (; j < 2; ++j)
1480 p_priv->in_urbs[j] = NULL;
1481
1482 /* outdat endpoints also have flip */
1483 endp = d_details->outdat_endpoints[i];
1484 for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) {
1485 p_priv->out_urbs[j] = keyspan_setup_urb
1486 (serial, endp, USB_DIR_OUT, port,
1487 p_priv->out_buffer[j], 64,
1488 cback->outdat_callback);
1489 }
1490 for (; j < 2; ++j)
1491 p_priv->out_urbs[j] = NULL;
1492
1493 /* inack endpoint */
1494 p_priv->inack_urb = keyspan_setup_urb
1495 (serial, d_details->inack_endpoints[i], USB_DIR_IN,
1496 port, p_priv->inack_buffer, 1, cback->inack_callback);
1497
1498 /* outcont endpoint */
1499 p_priv->outcont_urb = keyspan_setup_urb
1500 (serial, d_details->outcont_endpoints[i], USB_DIR_OUT,
1501 port, p_priv->outcont_buffer, 64,
1502 cback->outcont_callback);
Alan Coxdeb91682008-07-22 11:13:08 +01001503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504}
1505
1506/* usa19 function doesn't require prescaler */
1507static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
1508 u8 *rate_low, u8 *prescaler, int portnum)
1509{
1510 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001511 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513
Alan Coxdeb91682008-07-22 11:13:08 +01001514 dbg("%s - %d.", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
Alan Coxdeb91682008-07-22 11:13:08 +01001516 /* prevent divide by zero... */
1517 b16 = baud_rate * 16L;
1518 if (b16 == 0)
1519 return KEYSPAN_INVALID_BAUD_RATE;
1520 /* Any "standard" rate over 57k6 is marginal on the USA-19
1521 as we run out of divisor resolution. */
1522 if (baud_rate > 57600)
1523 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
Alan Coxdeb91682008-07-22 11:13:08 +01001525 /* calculate the divisor and the counter (its inverse) */
1526 div = baudclk / b16;
1527 if (div == 0)
1528 return KEYSPAN_INVALID_BAUD_RATE;
1529 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
Alan Coxdeb91682008-07-22 11:13:08 +01001532 if (div > 0xffff)
1533 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
Alan Coxdeb91682008-07-22 11:13:08 +01001535 /* return the counter values if non-null */
1536 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001538 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001540 if (rate_low && rate_hi)
1541 dbg("%s - %d %02x %02x.",
1542 __func__, baud_rate, *rate_hi, *rate_low);
1543 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544}
1545
1546/* usa19hs function doesn't require prescaler */
1547static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
1548 u8 *rate_low, u8 *prescaler, int portnum)
1549{
1550 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001551 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
Alan Coxdeb91682008-07-22 11:13:08 +01001553 dbg("%s - %d.", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Alan Coxdeb91682008-07-22 11:13:08 +01001555 /* prevent divide by zero... */
1556 b16 = baud_rate * 16L;
1557 if (b16 == 0)
1558 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Alan Coxdeb91682008-07-22 11:13:08 +01001560 /* calculate the divisor */
1561 div = baudclk / b16;
1562 if (div == 0)
1563 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
Alan Coxdeb91682008-07-22 11:13:08 +01001565 if (div > 0xffff)
1566 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
Alan Coxdeb91682008-07-22 11:13:08 +01001568 /* return the counter values if non-null */
1569 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001571
1572 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001574
1575 if (rate_low && rate_hi)
1576 dbg("%s - %d %02x %02x.",
1577 __func__, baud_rate, *rate_hi, *rate_low);
1578
1579 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580}
1581
1582static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
1583 u8 *rate_low, u8 *prescaler, int portnum)
1584{
1585 u32 b16, /* baud rate times 16 (actual rate used internally) */
1586 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001587 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 res, /* resulting baud rate using 13/8 prescaler */
1589 diff, /* error using 13/8 prescaler */
1590 smallest_diff;
1591 u8 best_prescaler;
1592 int i;
1593
Alan Coxdeb91682008-07-22 11:13:08 +01001594 dbg("%s - %d.", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
Alan Coxdeb91682008-07-22 11:13:08 +01001596 /* prevent divide by zero */
1597 b16 = baud_rate * 16L;
1598 if (b16 == 0)
1599 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
Alan Coxdeb91682008-07-22 11:13:08 +01001601 /* Calculate prescaler by trying them all and looking
1602 for best fit */
1603
1604 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 smallest_diff = 0xffffffff;
1606
1607 /* 0 is an invalid prescaler, used as a flag */
1608 best_prescaler = 0;
1609
Alan Coxdeb91682008-07-22 11:13:08 +01001610 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001612
1613 div = clk / b16;
1614 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
1617 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001618 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
Alan Coxdeb91682008-07-22 11:13:08 +01001620 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 best_prescaler = i;
1622 smallest_diff = diff;
1623 }
1624 }
1625
Alan Coxdeb91682008-07-22 11:13:08 +01001626 if (best_prescaler == 0)
1627 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
1629 clk = (baudclk * 8) / (u32) best_prescaler;
1630 div = clk / b16;
1631
Alan Coxdeb91682008-07-22 11:13:08 +01001632 /* return the divisor and prescaler if non-null */
1633 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001635 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 if (prescaler) {
1638 *prescaler = best_prescaler;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001639 /* dbg("%s - %d %d", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 }
Alan Coxdeb91682008-07-22 11:13:08 +01001641 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642}
1643
1644 /* USA-28 supports different maximum baud rates on each port */
1645static int keyspan_usa28_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) */
1651
Alan Coxdeb91682008-07-22 11:13:08 +01001652 dbg("%s - %d.", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001655 b16 = baud_rate * 16L;
1656 if (b16 == 0)
1657 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
Alan Coxdeb91682008-07-22 11:13:08 +01001659 /* calculate the divisor and the counter (its inverse) */
1660 div = KEYSPAN_USA28_BAUDCLK / b16;
1661 if (div == 0)
1662 return KEYSPAN_INVALID_BAUD_RATE;
1663 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
Alan Coxdeb91682008-07-22 11:13:08 +01001666 /* check for out of range, based on portnum,
1667 and return result */
1668 if (portnum == 0) {
1669 if (div > 0xffff)
1670 return KEYSPAN_INVALID_BAUD_RATE;
1671 } else {
1672 if (portnum == 1) {
1673 if (div > 0xff)
1674 return KEYSPAN_INVALID_BAUD_RATE;
1675 } else
1676 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 }
1678
1679 /* return the counter values if not NULL
1680 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001681 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001683 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001685 dbg("%s - %d OK.", __func__, baud_rate);
1686 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687}
1688
1689static int keyspan_usa26_send_setup(struct usb_serial *serial,
1690 struct usb_serial_port *port,
1691 int reset_port)
1692{
Alan Coxdeb91682008-07-22 11:13:08 +01001693 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 struct keyspan_serial_private *s_priv;
1695 struct keyspan_port_private *p_priv;
1696 const struct keyspan_device_details *d_details;
1697 int outcont_urb;
1698 struct urb *this_urb;
1699 int device_port, err;
1700
Alan Coxdeb91682008-07-22 11:13:08 +01001701 dbg("%s reset=%d", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
1703 s_priv = usb_get_serial_data(serial);
1704 p_priv = usb_get_serial_port_data(port);
1705 d_details = s_priv->device_details;
1706 device_port = port->number - port->serial->minor;
1707
1708 outcont_urb = d_details->outcont_endpoints[port->number];
1709 this_urb = p_priv->outcont_urb;
1710
Harvey Harrison441b62c2008-03-03 16:08:34 -08001711 dbg("%s - endpoint %d", __func__, usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
1713 /* Make sure we have an urb then send the message */
1714 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001715 dbg("%s - oops no urb.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 return -1;
1717 }
1718
1719 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001720 Don't overwrite resend for open/close condition. */
1721 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 p_priv->resend_cont = reset_port + 1;
1723 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01001724 /* dbg("%s - already writing", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001726 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 }
1728
Alan Coxdeb91682008-07-22 11:13:08 +01001729 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1730
1731 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 if (p_priv->old_baud != p_priv->baud) {
1733 p_priv->old_baud = p_priv->baud;
1734 msg.setClocking = 0xff;
1735 if (d_details->calculate_baud_rate
1736 (p_priv->baud, d_details->baudclk, &msg.baudHi,
Alan Coxdeb91682008-07-22 11:13:08 +01001737 &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1738 dbg("%s - Invalid baud rate %d requested, using 9600.",
1739 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 msg.baudLo = 0;
1741 msg.baudHi = 125; /* Values for 9600 baud */
1742 msg.prescaler = 10;
1743 }
1744 msg.setPrescaler = 0xff;
1745 }
1746
1747 msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
1748 switch (p_priv->cflag & CSIZE) {
1749 case CS5:
1750 msg.lcr |= USA_DATABITS_5;
1751 break;
1752 case CS6:
1753 msg.lcr |= USA_DATABITS_6;
1754 break;
1755 case CS7:
1756 msg.lcr |= USA_DATABITS_7;
1757 break;
1758 case CS8:
1759 msg.lcr |= USA_DATABITS_8;
1760 break;
1761 }
1762 if (p_priv->cflag & PARENB) {
1763 /* note USA_PARITY_NONE == 0 */
1764 msg.lcr |= (p_priv->cflag & PARODD)?
Alan Coxdeb91682008-07-22 11:13:08 +01001765 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 }
1767 msg.setLcr = 0xff;
1768
1769 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1770 msg.xonFlowControl = 0;
1771 msg.setFlowControl = 0xff;
1772 msg.forwardingLength = 16;
1773 msg.xonChar = 17;
1774 msg.xoffChar = 19;
1775
1776 /* Opening port */
1777 if (reset_port == 1) {
1778 msg._txOn = 1;
1779 msg._txOff = 0;
1780 msg.txFlush = 0;
1781 msg.txBreak = 0;
1782 msg.rxOn = 1;
1783 msg.rxOff = 0;
1784 msg.rxFlush = 1;
1785 msg.rxForward = 0;
1786 msg.returnStatus = 0;
1787 msg.resetDataToggle = 0xff;
1788 }
1789
1790 /* Closing port */
1791 else if (reset_port == 2) {
1792 msg._txOn = 0;
1793 msg._txOff = 1;
1794 msg.txFlush = 0;
1795 msg.txBreak = 0;
1796 msg.rxOn = 0;
1797 msg.rxOff = 1;
1798 msg.rxFlush = 1;
1799 msg.rxForward = 0;
1800 msg.returnStatus = 0;
1801 msg.resetDataToggle = 0;
1802 }
1803
1804 /* Sending intermediate configs */
1805 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001806 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 msg._txOff = 0;
1808 msg.txFlush = 0;
1809 msg.txBreak = (p_priv->break_on);
1810 msg.rxOn = 0;
1811 msg.rxOff = 0;
1812 msg.rxFlush = 0;
1813 msg.rxForward = 0;
1814 msg.returnStatus = 0;
1815 msg.resetDataToggle = 0x0;
1816 }
1817
Alan Coxdeb91682008-07-22 11:13:08 +01001818 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 msg.setTxTriState_setRts = 0xff;
1820 msg.txTriState_rts = p_priv->rts_state;
1821
1822 msg.setHskoa_setDtr = 0xff;
1823 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001824
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001826 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1827
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 /* send the data out the device on control endpoint */
1829 this_urb->transfer_buffer_length = sizeof(msg);
1830
Alan Coxdeb91682008-07-22 11:13:08 +01001831 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1832 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08001833 dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834#if 0
1835 else {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001836 dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 outcont_urb, this_urb->transfer_buffer_length,
1838 usb_pipeendpoint(this_urb->pipe));
1839 }
1840#endif
1841
Alan Coxa5b6f602008-04-08 17:16:06 +01001842 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843}
1844
1845static int keyspan_usa28_send_setup(struct usb_serial *serial,
1846 struct usb_serial_port *port,
1847 int reset_port)
1848{
Alan Coxdeb91682008-07-22 11:13:08 +01001849 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 struct keyspan_serial_private *s_priv;
1851 struct keyspan_port_private *p_priv;
1852 const struct keyspan_device_details *d_details;
1853 struct urb *this_urb;
1854 int device_port, err;
1855
Alan Coxdeb91682008-07-22 11:13:08 +01001856 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857
1858 s_priv = usb_get_serial_data(serial);
1859 p_priv = usb_get_serial_port_data(port);
1860 d_details = s_priv->device_details;
1861 device_port = port->number - port->serial->minor;
1862
1863 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001864 this_urb = p_priv->outcont_urb;
1865 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001866 dbg("%s - oops no urb.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 return -1;
1868 }
1869
1870 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001871 Don't overwrite resend for open/close condition. */
1872 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 p_priv->resend_cont = reset_port + 1;
1874 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01001875 dbg("%s already writing", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001877 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 }
1879
Alan Coxdeb91682008-07-22 11:13:08 +01001880 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
1882 msg.setBaudRate = 1;
1883 if (d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk,
Alan Coxdeb91682008-07-22 11:13:08 +01001884 &msg.baudHi, &msg.baudLo, NULL, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1885 dbg("%s - Invalid baud rate requested %d.",
1886 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 msg.baudLo = 0xff;
1888 msg.baudHi = 0xb2; /* Values for 9600 baud */
1889 }
1890
1891 /* If parity is enabled, we must calculate it ourselves. */
1892 msg.parity = 0; /* XXX for now */
1893
1894 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1895 msg.xonFlowControl = 0;
1896
Alan Coxdeb91682008-07-22 11:13:08 +01001897 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 msg.rts = p_priv->rts_state;
1899 msg.dtr = p_priv->dtr_state;
1900
1901 msg.forwardingLength = 16;
1902 msg.forwardMs = 10;
1903 msg.breakThreshold = 45;
1904 msg.xonChar = 17;
1905 msg.xoffChar = 19;
1906
1907 /*msg.returnStatus = 1;
1908 msg.resetDataToggle = 0xff;*/
1909 /* Opening port */
1910 if (reset_port == 1) {
1911 msg._txOn = 1;
1912 msg._txOff = 0;
1913 msg.txFlush = 0;
1914 msg.txForceXoff = 0;
1915 msg.txBreak = 0;
1916 msg.rxOn = 1;
1917 msg.rxOff = 0;
1918 msg.rxFlush = 1;
1919 msg.rxForward = 0;
1920 msg.returnStatus = 0;
1921 msg.resetDataToggle = 0xff;
1922 }
1923 /* Closing port */
1924 else if (reset_port == 2) {
1925 msg._txOn = 0;
1926 msg._txOff = 1;
1927 msg.txFlush = 0;
1928 msg.txForceXoff = 0;
1929 msg.txBreak = 0;
1930 msg.rxOn = 0;
1931 msg.rxOff = 1;
1932 msg.rxFlush = 1;
1933 msg.rxForward = 0;
1934 msg.returnStatus = 0;
1935 msg.resetDataToggle = 0;
1936 }
1937 /* Sending intermediate configs */
1938 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001939 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 msg._txOff = 0;
1941 msg.txFlush = 0;
1942 msg.txForceXoff = 0;
1943 msg.txBreak = (p_priv->break_on);
1944 msg.rxOn = 0;
1945 msg.rxOff = 0;
1946 msg.rxFlush = 0;
1947 msg.rxForward = 0;
1948 msg.returnStatus = 0;
1949 msg.resetDataToggle = 0x0;
1950 }
1951
1952 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001953 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954
1955 /* send the data out the device on control endpoint */
1956 this_urb->transfer_buffer_length = sizeof(msg);
1957
Alan Coxdeb91682008-07-22 11:13:08 +01001958 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1959 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08001960 dbg("%s - usb_submit_urb(setup) failed", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961#if 0
1962 else {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001963 dbg("%s - usb_submit_urb(setup) OK %d bytes", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 this_urb->transfer_buffer_length);
1965 }
1966#endif
1967
Alan Coxa5b6f602008-04-08 17:16:06 +01001968 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969}
1970
1971static int keyspan_usa49_send_setup(struct usb_serial *serial,
1972 struct usb_serial_port *port,
1973 int reset_port)
1974{
Lucy McCoy0ca12682007-05-18 12:10:41 -07001975 struct keyspan_usa49_portControlMessage msg;
1976 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 struct keyspan_serial_private *s_priv;
1978 struct keyspan_port_private *p_priv;
1979 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 struct urb *this_urb;
1981 int err, device_port;
1982
Alan Coxdeb91682008-07-22 11:13:08 +01001983 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
1985 s_priv = usb_get_serial_data(serial);
1986 p_priv = usb_get_serial_port_data(port);
1987 d_details = s_priv->device_details;
1988
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 this_urb = s_priv->glocont_urb;
1990
Lucy McCoy0ca12682007-05-18 12:10:41 -07001991 /* Work out which port within the device is being setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 device_port = port->number - port->serial->minor;
1993
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301994 /* Make sure we have an urb then send the message */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001996 dbg("%s - oops no urb for port %d.", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 return -1;
1998 }
1999
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05302000 dbg("%s - endpoint %d port %d (%d)",
2001 __func__, usb_pipeendpoint(this_urb->pipe),
2002 port->number, device_port);
2003
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07002005 Don't overwrite resend for open/close condition. */
2006 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002008
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01002010 /* dbg("%s - already writing", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002012 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 }
2014
Alan Coxdeb91682008-07-22 11:13:08 +01002015 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
2017 /*msg.portNumber = port->number;*/
2018 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01002019
2020 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 if (p_priv->old_baud != p_priv->baud) {
2022 p_priv->old_baud = p_priv->baud;
2023 msg.setClocking = 0xff;
2024 if (d_details->calculate_baud_rate
2025 (p_priv->baud, d_details->baudclk, &msg.baudHi,
Alan Coxdeb91682008-07-22 11:13:08 +01002026 &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2027 dbg("%s - Invalid baud rate %d requested, using 9600.",
2028 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 msg.baudLo = 0;
2030 msg.baudHi = 125; /* Values for 9600 baud */
2031 msg.prescaler = 10;
2032 }
Alan Coxdeb91682008-07-22 11:13:08 +01002033 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 }
2035
2036 msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
2037 switch (p_priv->cflag & CSIZE) {
2038 case CS5:
2039 msg.lcr |= USA_DATABITS_5;
2040 break;
2041 case CS6:
2042 msg.lcr |= USA_DATABITS_6;
2043 break;
2044 case CS7:
2045 msg.lcr |= USA_DATABITS_7;
2046 break;
2047 case CS8:
2048 msg.lcr |= USA_DATABITS_8;
2049 break;
2050 }
2051 if (p_priv->cflag & PARENB) {
2052 /* note USA_PARITY_NONE == 0 */
2053 msg.lcr |= (p_priv->cflag & PARODD)?
Alan Coxdeb91682008-07-22 11:13:08 +01002054 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 }
2056 msg.setLcr = 0xff;
2057
2058 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2059 msg.xonFlowControl = 0;
2060 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01002061
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 msg.forwardingLength = 16;
2063 msg.xonChar = 17;
2064 msg.xoffChar = 19;
2065
Alan Coxdeb91682008-07-22 11:13:08 +01002066 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 if (reset_port == 1) {
2068 msg._txOn = 1;
2069 msg._txOff = 0;
2070 msg.txFlush = 0;
2071 msg.txBreak = 0;
2072 msg.rxOn = 1;
2073 msg.rxOff = 0;
2074 msg.rxFlush = 1;
2075 msg.rxForward = 0;
2076 msg.returnStatus = 0;
2077 msg.resetDataToggle = 0xff;
2078 msg.enablePort = 1;
2079 msg.disablePort = 0;
2080 }
2081 /* Closing port */
2082 else if (reset_port == 2) {
2083 msg._txOn = 0;
2084 msg._txOff = 1;
2085 msg.txFlush = 0;
2086 msg.txBreak = 0;
2087 msg.rxOn = 0;
2088 msg.rxOff = 1;
2089 msg.rxFlush = 1;
2090 msg.rxForward = 0;
2091 msg.returnStatus = 0;
2092 msg.resetDataToggle = 0;
2093 msg.enablePort = 0;
2094 msg.disablePort = 1;
2095 }
2096 /* Sending intermediate configs */
2097 else {
Alan Coxdeb91682008-07-22 11:13:08 +01002098 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 msg._txOff = 0;
2100 msg.txFlush = 0;
2101 msg.txBreak = (p_priv->break_on);
2102 msg.rxOn = 0;
2103 msg.rxOff = 0;
2104 msg.rxFlush = 0;
2105 msg.rxForward = 0;
2106 msg.returnStatus = 0;
2107 msg.resetDataToggle = 0x0;
2108 msg.enablePort = 0;
2109 msg.disablePort = 0;
2110 }
2111
Alan Coxdeb91682008-07-22 11:13:08 +01002112 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 msg.setRts = 0xff;
2114 msg.rts = p_priv->rts_state;
2115
2116 msg.setDtr = 0xff;
2117 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002118
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120
Alan Coxdeb91682008-07-22 11:13:08 +01002121 /* if the device is a 49wg, we send control message on usb
2122 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002123
2124 if (d_details->product_id == keyspan_usa49wg_product_id) {
2125 dr = (void *)(s_priv->ctrl_buf);
2126 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
2127 dr->bRequest = 0xB0; /* 49wg control message */;
2128 dr->wValue = 0;
2129 dr->wIndex = 0;
2130 dr->wLength = cpu_to_le16(sizeof(msg));
2131
Alan Coxdeb91682008-07-22 11:13:08 +01002132 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07002133
Alan Coxdeb91682008-07-22 11:13:08 +01002134 usb_fill_control_urb(this_urb, serial->dev,
2135 usb_sndctrlpipe(serial->dev, 0),
2136 (unsigned char *)dr, s_priv->glocont_buf,
2137 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002138
2139 } else {
2140 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01002141
Lucy McCoy0ca12682007-05-18 12:10:41 -07002142 /* send the data out the device on control endpoint */
2143 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002144 }
Alan Coxdeb91682008-07-22 11:13:08 +01002145 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2146 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002147 dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148#if 0
2149 else {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002150 dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002151 outcont_urb, this_urb->transfer_buffer_length,
2152 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 }
2154#endif
2155
Alan Coxa5b6f602008-04-08 17:16:06 +01002156 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157}
2158
2159static int keyspan_usa90_send_setup(struct usb_serial *serial,
2160 struct usb_serial_port *port,
2161 int reset_port)
2162{
Alan Coxdeb91682008-07-22 11:13:08 +01002163 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 struct keyspan_serial_private *s_priv;
2165 struct keyspan_port_private *p_priv;
2166 const struct keyspan_device_details *d_details;
2167 struct urb *this_urb;
2168 int err;
2169 u8 prescaler;
2170
Alan Coxdeb91682008-07-22 11:13:08 +01002171 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172
2173 s_priv = usb_get_serial_data(serial);
2174 p_priv = usb_get_serial_port_data(port);
2175 d_details = s_priv->device_details;
2176
2177 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002178 this_urb = p_priv->outcont_urb;
2179 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002180 dbg("%s - oops no urb.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 return -1;
2182 }
2183
2184 /* Save reset port val for resend.
2185 Don't overwrite resend for open/close condition. */
2186 if ((reset_port + 1) > p_priv->resend_cont)
2187 p_priv->resend_cont = reset_port + 1;
2188 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01002189 dbg("%s already writing", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002191 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 }
2193
Alan Coxdeb91682008-07-22 11:13:08 +01002194 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195
Alan Coxdeb91682008-07-22 11:13:08 +01002196 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 if (p_priv->old_baud != p_priv->baud) {
2198 p_priv->old_baud = p_priv->baud;
2199 msg.setClocking = 0x01;
2200 if (d_details->calculate_baud_rate
2201 (p_priv->baud, d_details->baudclk, &msg.baudHi,
Alan Coxdeb91682008-07-22 11:13:08 +01002202 &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2203 dbg("%s - Invalid baud rate %d requested, using 9600.",
2204 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 p_priv->baud = 9600;
Alan Coxdeb91682008-07-22 11:13:08 +01002206 d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2208 }
2209 msg.setRxMode = 1;
2210 msg.setTxMode = 1;
2211 }
2212
2213 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002214 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 msg.rxMode = RXMODE_DMA;
2216 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002217 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 msg.rxMode = RXMODE_BYHAND;
2219 msg.txMode = TXMODE_BYHAND;
2220 }
2221
2222 msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1;
2223 switch (p_priv->cflag & CSIZE) {
2224 case CS5:
2225 msg.lcr |= USA_DATABITS_5;
2226 break;
2227 case CS6:
2228 msg.lcr |= USA_DATABITS_6;
2229 break;
2230 case CS7:
2231 msg.lcr |= USA_DATABITS_7;
2232 break;
2233 case CS8:
2234 msg.lcr |= USA_DATABITS_8;
2235 break;
2236 }
2237 if (p_priv->cflag & PARENB) {
2238 /* note USA_PARITY_NONE == 0 */
2239 msg.lcr |= (p_priv->cflag & PARODD)?
Alan Coxdeb91682008-07-22 11:13:08 +01002240 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 }
2242 if (p_priv->old_cflag != p_priv->cflag) {
2243 p_priv->old_cflag = p_priv->cflag;
2244 msg.setLcr = 0x01;
2245 }
2246
2247 if (p_priv->flow_control == flow_cts)
2248 msg.txFlowControl = TXFLOW_CTS;
2249 msg.setTxFlowControl = 0x01;
2250 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002251
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002253 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 msg.txAckSetting = 0;
2255 msg.xonChar = 17;
2256 msg.xoffChar = 19;
2257
Alan Coxdeb91682008-07-22 11:13:08 +01002258 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 if (reset_port == 1) {
2260 msg.portEnabled = 1;
2261 msg.rxFlush = 1;
2262 msg.txBreak = (p_priv->break_on);
2263 }
2264 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002265 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 /* Sending intermediate configs */
2268 else {
Alan Stern1f871582010-02-17 10:05:47 -05002269 msg.portEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 msg.txBreak = (p_priv->break_on);
2271 }
2272
Alan Coxdeb91682008-07-22 11:13:08 +01002273 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 msg.setRts = 0x01;
2275 msg.rts = p_priv->rts_state;
2276
2277 msg.setDtr = 0x01;
2278 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002279
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002281 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2282
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 /* send the data out the device on control endpoint */
2284 this_urb->transfer_buffer_length = sizeof(msg);
2285
Alan Coxdeb91682008-07-22 11:13:08 +01002286 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2287 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002288 dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002289 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290}
2291
Lucy McCoy0ca12682007-05-18 12:10:41 -07002292static int keyspan_usa67_send_setup(struct usb_serial *serial,
2293 struct usb_serial_port *port,
2294 int reset_port)
2295{
2296 struct keyspan_usa67_portControlMessage msg;
2297 struct keyspan_serial_private *s_priv;
2298 struct keyspan_port_private *p_priv;
2299 const struct keyspan_device_details *d_details;
2300 struct urb *this_urb;
2301 int err, device_port;
2302
Alan Coxdeb91682008-07-22 11:13:08 +01002303 dbg("%s", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002304
2305 s_priv = usb_get_serial_data(serial);
2306 p_priv = usb_get_serial_port_data(port);
2307 d_details = s_priv->device_details;
2308
2309 this_urb = s_priv->glocont_urb;
2310
2311 /* Work out which port within the device is being setup */
2312 device_port = port->number - port->serial->minor;
2313
2314 /* Make sure we have an urb then send the message */
2315 if (this_urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002316 dbg("%s - oops no urb for port %d.", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002317 port->number);
2318 return -1;
2319 }
2320
2321 /* Save reset port val for resend.
2322 Don't overwrite resend for open/close condition. */
2323 if ((reset_port + 1) > p_priv->resend_cont)
2324 p_priv->resend_cont = reset_port + 1;
2325 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +01002326 /* dbg("%s - already writing", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002327 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002328 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002329 }
2330
2331 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2332
2333 msg.port = device_port;
2334
2335 /* Only set baud rate if it's changed */
2336 if (p_priv->old_baud != p_priv->baud) {
2337 p_priv->old_baud = p_priv->baud;
2338 msg.setClocking = 0xff;
2339 if (d_details->calculate_baud_rate
2340 (p_priv->baud, d_details->baudclk, &msg.baudHi,
Alan Coxdeb91682008-07-22 11:13:08 +01002341 &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2342 dbg("%s - Invalid baud rate %d requested, using 9600.",
2343 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002344 msg.baudLo = 0;
2345 msg.baudHi = 125; /* Values for 9600 baud */
2346 msg.prescaler = 10;
2347 }
2348 msg.setPrescaler = 0xff;
2349 }
2350
2351 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2352 switch (p_priv->cflag & CSIZE) {
2353 case CS5:
2354 msg.lcr |= USA_DATABITS_5;
2355 break;
2356 case CS6:
2357 msg.lcr |= USA_DATABITS_6;
2358 break;
2359 case CS7:
2360 msg.lcr |= USA_DATABITS_7;
2361 break;
2362 case CS8:
2363 msg.lcr |= USA_DATABITS_8;
2364 break;
2365 }
2366 if (p_priv->cflag & PARENB) {
2367 /* note USA_PARITY_NONE == 0 */
2368 msg.lcr |= (p_priv->cflag & PARODD)?
Alan Coxdeb91682008-07-22 11:13:08 +01002369 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002370 }
2371 msg.setLcr = 0xff;
2372
2373 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2374 msg.xonFlowControl = 0;
2375 msg.setFlowControl = 0xff;
2376 msg.forwardingLength = 16;
2377 msg.xonChar = 17;
2378 msg.xoffChar = 19;
2379
2380 if (reset_port == 1) {
2381 /* Opening port */
2382 msg._txOn = 1;
2383 msg._txOff = 0;
2384 msg.txFlush = 0;
2385 msg.txBreak = 0;
2386 msg.rxOn = 1;
2387 msg.rxOff = 0;
2388 msg.rxFlush = 1;
2389 msg.rxForward = 0;
2390 msg.returnStatus = 0;
2391 msg.resetDataToggle = 0xff;
2392 } else if (reset_port == 2) {
2393 /* Closing port */
2394 msg._txOn = 0;
2395 msg._txOff = 1;
2396 msg.txFlush = 0;
2397 msg.txBreak = 0;
2398 msg.rxOn = 0;
2399 msg.rxOff = 1;
2400 msg.rxFlush = 1;
2401 msg.rxForward = 0;
2402 msg.returnStatus = 0;
2403 msg.resetDataToggle = 0;
2404 } else {
2405 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002406 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002407 msg._txOff = 0;
2408 msg.txFlush = 0;
2409 msg.txBreak = (p_priv->break_on);
2410 msg.rxOn = 0;
2411 msg.rxOff = 0;
2412 msg.rxFlush = 0;
2413 msg.rxForward = 0;
2414 msg.returnStatus = 0;
2415 msg.resetDataToggle = 0x0;
2416 }
2417
2418 /* Do handshaking outputs */
2419 msg.setTxTriState_setRts = 0xff;
2420 msg.txTriState_rts = p_priv->rts_state;
2421
2422 msg.setHskoa_setDtr = 0xff;
2423 msg.hskoa_dtr = p_priv->dtr_state;
2424
2425 p_priv->resend_cont = 0;
2426
2427 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2428
2429 /* send the data out the device on control endpoint */
2430 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002431
2432 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2433 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002434 dbg("%s - usb_submit_urb(setup) failed (%d)", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002435 err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002436 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002437}
2438
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2440{
2441 struct usb_serial *serial = port->serial;
2442 struct keyspan_serial_private *s_priv;
2443 const struct keyspan_device_details *d_details;
2444
Alan Coxdeb91682008-07-22 11:13:08 +01002445 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446
2447 s_priv = usb_get_serial_data(serial);
2448 d_details = s_priv->device_details;
2449
2450 switch (d_details->msg_format) {
2451 case msg_usa26:
2452 keyspan_usa26_send_setup(serial, port, reset_port);
2453 break;
2454 case msg_usa28:
2455 keyspan_usa28_send_setup(serial, port, reset_port);
2456 break;
2457 case msg_usa49:
2458 keyspan_usa49_send_setup(serial, port, reset_port);
2459 break;
2460 case msg_usa90:
2461 keyspan_usa90_send_setup(serial, port, reset_port);
2462 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002463 case msg_usa67:
2464 keyspan_usa67_send_setup(serial, port, reset_port);
2465 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 }
2467}
2468
2469
2470/* Gets called by the "real" driver (ie once firmware is loaded
2471 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002472static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473{
2474 int i, err;
2475 struct usb_serial_port *port;
2476 struct keyspan_serial_private *s_priv;
2477 struct keyspan_port_private *p_priv;
2478 const struct keyspan_device_details *d_details;
2479
Harvey Harrison441b62c2008-03-03 16:08:34 -08002480 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002483 if (d_details->product_id ==
2484 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 break;
2486 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002487 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2488 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 return 1;
2490 }
2491
2492 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002493 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 if (!s_priv) {
Alan Coxdeb91682008-07-22 11:13:08 +01002495 dbg("%s - kmalloc for keyspan_serial_private failed.",
2496 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 return -ENOMEM;
2498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
2500 s_priv->device_details = d_details;
2501 usb_set_serial_data(serial, s_priv);
2502
2503 /* Now setup per port private data */
2504 for (i = 0; i < serial->num_ports; i++) {
2505 port = serial->port[i];
Alan Coxdeb91682008-07-22 11:13:08 +01002506 p_priv = kzalloc(sizeof(struct keyspan_port_private),
2507 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 if (!p_priv) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002509 dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __func__, i);
Alan Coxdeb91682008-07-22 11:13:08 +01002510 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 p_priv->device_details = d_details;
2513 usb_set_serial_port_data(port, p_priv);
2514 }
2515
2516 keyspan_setup_urbs(serial);
2517
Lucy McCoy0ca12682007-05-18 12:10:41 -07002518 if (s_priv->instat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002519 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2520 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002521 dbg("%s - submit instat urb failed %d", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002522 err);
2523 }
2524 if (s_priv->indat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002525 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2526 if (err != 0)
Harvey Harrison441b62c2008-03-03 16:08:34 -08002527 dbg("%s - submit indat urb failed %d", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002528 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 }
Alan Coxdeb91682008-07-22 11:13:08 +01002530
Alan Coxa5b6f602008-04-08 17:16:06 +01002531 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532}
2533
Alan Sternf9c99bb2009-06-02 11:53:55 -04002534static void keyspan_disconnect(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535{
2536 int i, j;
2537 struct usb_serial_port *port;
2538 struct keyspan_serial_private *s_priv;
2539 struct keyspan_port_private *p_priv;
2540
Harvey Harrison441b62c2008-03-03 16:08:34 -08002541 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
2543 s_priv = usb_get_serial_data(serial);
2544
2545 /* Stop reading/writing urbs */
2546 stop_urb(s_priv->instat_urb);
2547 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002548 stop_urb(s_priv->indat_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 for (i = 0; i < serial->num_ports; ++i) {
2550 port = serial->port[i];
2551 p_priv = usb_get_serial_port_data(port);
2552 stop_urb(p_priv->inack_urb);
2553 stop_urb(p_priv->outcont_urb);
2554 for (j = 0; j < 2; j++) {
2555 stop_urb(p_priv->in_urbs[j]);
2556 stop_urb(p_priv->out_urbs[j]);
2557 }
2558 }
2559
2560 /* Now free them */
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002561 usb_free_urb(s_priv->instat_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002562 usb_free_urb(s_priv->indat_urb);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002563 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 for (i = 0; i < serial->num_ports; ++i) {
2565 port = serial->port[i];
2566 p_priv = usb_get_serial_port_data(port);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002567 usb_free_urb(p_priv->inack_urb);
2568 usb_free_urb(p_priv->outcont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 for (j = 0; j < 2; j++) {
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002570 usb_free_urb(p_priv->in_urbs[j]);
2571 usb_free_urb(p_priv->out_urbs[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 }
2573 }
Alan Sternf9c99bb2009-06-02 11:53:55 -04002574}
2575
2576static void keyspan_release(struct usb_serial *serial)
2577{
2578 int i;
2579 struct usb_serial_port *port;
2580 struct keyspan_serial_private *s_priv;
2581
2582 dbg("%s", __func__);
2583
2584 s_priv = usb_get_serial_data(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585
2586 /* dbg("Freeing serial->private."); */
2587 kfree(s_priv);
2588
2589 /* dbg("Freeing port->private."); */
2590 /* Now free per port private data */
2591 for (i = 0; i < serial->num_ports; i++) {
2592 port = serial->port[i];
2593 kfree(usb_get_serial_port_data(port));
2594 }
2595}
2596
Alan Coxdeb91682008-07-22 11:13:08 +01002597MODULE_AUTHOR(DRIVER_AUTHOR);
2598MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599MODULE_LICENSE("GPL");
2600
David Woodhouse2971c572008-05-30 14:04:03 +03002601MODULE_FIRMWARE("keyspan/usa28.fw");
2602MODULE_FIRMWARE("keyspan/usa28x.fw");
2603MODULE_FIRMWARE("keyspan/usa28xa.fw");
2604MODULE_FIRMWARE("keyspan/usa28xb.fw");
2605MODULE_FIRMWARE("keyspan/usa19.fw");
2606MODULE_FIRMWARE("keyspan/usa19qi.fw");
2607MODULE_FIRMWARE("keyspan/mpr.fw");
2608MODULE_FIRMWARE("keyspan/usa19qw.fw");
2609MODULE_FIRMWARE("keyspan/usa18x.fw");
2610MODULE_FIRMWARE("keyspan/usa19w.fw");
2611MODULE_FIRMWARE("keyspan/usa49w.fw");
2612MODULE_FIRMWARE("keyspan/usa49wlc.fw");
2613
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614module_param(debug, bool, S_IRUGO | S_IWUSR);
2615MODULE_PARM_DESC(debug, "Debug enabled or not");
2616