blob: 566056cb04dc72d929019a70e2c5318737733525 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070048/*
49 * Version Information
50 */
Lucy McCoy0ca12682007-05-18 12:10:41 -070051#define DRIVER_VERSION "v1.1.5"
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
53#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
54
55#define INSTAT_BUFLEN 32
56#define GLOCONT_BUFLEN 64
Lucy McCoy0ca12682007-05-18 12:10:41 -070057#define INDAT49W_BUFLEN 512
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
59 /* Per device and per port private data */
60struct keyspan_serial_private {
61 const struct keyspan_device_details *device_details;
62
63 struct urb *instat_urb;
64 char instat_buf[INSTAT_BUFLEN];
65
Alan Coxdeb91682008-07-22 11:13:08 +010066 /* added to support 49wg, where data from all 4 ports comes in
67 on 1 EP and high-speed supported */
Lucy McCoy0ca12682007-05-18 12:10:41 -070068 struct urb *indat_urb;
69 char indat_buf[INDAT49W_BUFLEN];
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 /* XXX this one probably will need a lock */
72 struct urb *glocont_urb;
73 char glocont_buf[GLOCONT_BUFLEN];
Alan Coxdeb91682008-07-22 11:13:08 +010074 char ctrl_buf[8]; /* for EP0 control message */
Linus Torvalds1da177e2005-04-16 15:20:36 -070075};
76
77struct keyspan_port_private {
78 /* Keep track of which input & output endpoints to use */
79 int in_flip;
80 int out_flip;
81
82 /* Keep duplicate of device details in each port
83 structure as well - simplifies some of the
84 callback functions etc. */
85 const struct keyspan_device_details *device_details;
86
87 /* Input endpoints and buffer for this port */
88 struct urb *in_urbs[2];
89 char in_buffer[2][64];
90 /* Output endpoints and buffer for this port */
91 struct urb *out_urbs[2];
92 char out_buffer[2][64];
93
94 /* Input ack endpoint */
95 struct urb *inack_urb;
96 char inack_buffer[1];
97
98 /* Output control endpoint */
99 struct urb *outcont_urb;
100 char outcont_buffer[64];
101
102 /* Settings for the port */
103 int baud;
104 int old_baud;
105 unsigned int cflag;
106 unsigned int old_cflag;
107 enum {flow_none, flow_cts, flow_xon} flow_control;
108 int rts_state; /* Handshaking pins (outputs) */
109 int dtr_state;
110 int cts_state; /* Handshaking pins (inputs) */
111 int dsr_state;
112 int dcd_state;
113 int ri_state;
114 int break_on;
115
116 unsigned long tx_start_time[2];
117 int resend_cont; /* need to resend control packet */
118};
119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120/* Include Keyspan message headers. All current Keyspan Adapters
Lucy McCoy0ca12682007-05-18 12:10:41 -0700121 make use of one of five message formats which are referred
Alan Coxdeb91682008-07-22 11:13:08 +0100122 to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and
123 within this driver. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124#include "keyspan_usa26msg.h"
125#include "keyspan_usa28msg.h"
126#include "keyspan_usa49msg.h"
127#include "keyspan_usa90msg.h"
Lucy McCoy0ca12682007-05-18 12:10:41 -0700128#include "keyspan_usa67msg.h"
Alan Coxdeb91682008-07-22 11:13:08 +0100129
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -0700131module_usb_serial_driver(serial_drivers, keyspan_ids_combined);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Alan Cox95da3102008-07-22 11:09:07 +0100133static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134{
Alan Cox95da3102008-07-22 11:09:07 +0100135 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 struct keyspan_port_private *p_priv;
137
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 p_priv = usb_get_serial_port_data(port);
139
140 if (break_state == -1)
141 p_priv->break_on = 1;
142 else
143 p_priv->break_on = 0;
144
145 keyspan_send_setup(port, 0);
146}
147
148
Alan Coxdeb91682008-07-22 11:13:08 +0100149static void keyspan_set_termios(struct tty_struct *tty,
Alan Cox95da3102008-07-22 11:09:07 +0100150 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151{
152 int baud_rate, device_port;
153 struct keyspan_port_private *p_priv;
154 const struct keyspan_device_details *d_details;
155 unsigned int cflag;
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 p_priv = usb_get_serial_port_data(port);
158 d_details = p_priv->device_details;
Alan Cox74240b02007-10-18 01:24:20 -0700159 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 device_port = port->number - port->serial->minor;
161
162 /* Baud rate calculation takes baud rate as an integer
163 so other rates can be generated if desired. */
Alan Cox74240b02007-10-18 01:24:20 -0700164 baud_rate = tty_get_baud_rate(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100165 /* If no match or invalid, don't change */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700166 if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
168 /* FIXME - more to do here to ensure rate changes cleanly */
Alan Cox74240b02007-10-18 01:24:20 -0700169 /* FIXME - calcuate exact rate from divisor ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 p_priv->baud = baud_rate;
Alan Cox74240b02007-10-18 01:24:20 -0700171 } else
172 baud_rate = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Alan Cox74240b02007-10-18 01:24:20 -0700174 tty_encode_baud_rate(tty, baud_rate, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 /* set CTS/RTS handshake etc. */
176 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +1000177 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Alan Cox74240b02007-10-18 01:24:20 -0700179 /* Mark/Space not supported */
180 tty->termios->c_cflag &= ~CMSPAR;
181
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 keyspan_send_setup(port, 0);
183}
184
Alan Cox60b33c12011-02-14 16:26:14 +0000185static int keyspan_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186{
Alan Cox95da3102008-07-22 11:09:07 +0100187 struct usb_serial_port *port = tty->driver_data;
188 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 unsigned int value;
Alan Coxdeb91682008-07-22 11:13:08 +0100190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
192 ((p_priv->dtr_state) ? TIOCM_DTR : 0) |
193 ((p_priv->cts_state) ? TIOCM_CTS : 0) |
194 ((p_priv->dsr_state) ? TIOCM_DSR : 0) |
195 ((p_priv->dcd_state) ? TIOCM_CAR : 0) |
Alan Coxdeb91682008-07-22 11:13:08 +0100196 ((p_priv->ri_state) ? TIOCM_RNG : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198 return value;
199}
200
Alan Cox20b9d172011-02-14 16:26:50 +0000201static int keyspan_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 unsigned int set, unsigned int clear)
203{
Alan Cox95da3102008-07-22 11:09:07 +0100204 struct usb_serial_port *port = tty->driver_data;
205 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100206
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 if (set & TIOCM_RTS)
208 p_priv->rts_state = 1;
209 if (set & TIOCM_DTR)
210 p_priv->dtr_state = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 if (clear & TIOCM_RTS)
212 p_priv->rts_state = 0;
213 if (clear & TIOCM_DTR)
214 p_priv->dtr_state = 0;
215 keyspan_send_setup(port, 0);
216 return 0;
217}
218
Alan Cox95da3102008-07-22 11:09:07 +0100219/* Write function is similar for the four protocols used
220 with only a minor change for usa90 (usa19hs) required */
221static int keyspan_write(struct tty_struct *tty,
222 struct usb_serial_port *port, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223{
224 struct keyspan_port_private *p_priv;
225 const struct keyspan_device_details *d_details;
226 int flip;
227 int left, todo;
228 struct urb *this_urb;
Alan Coxdeb91682008-07-22 11:13:08 +0100229 int err, maxDataLen, dataOffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231 p_priv = usb_get_serial_port_data(port);
232 d_details = p_priv->device_details;
233
234 if (d_details->msg_format == msg_usa90) {
Alan Coxdeb91682008-07-22 11:13:08 +0100235 maxDataLen = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 dataOffset = 0;
237 } else {
238 maxDataLen = 63;
239 dataOffset = 1;
240 }
Alan Coxdeb91682008-07-22 11:13:08 +0100241
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700242 dev_dbg(&port->dev, "%s - for port %d (%d chars), flip=%d\n",
243 __func__, port->number, count, p_priv->out_flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
245 for (left = count; left > 0; left -= todo) {
246 todo = left;
247 if (todo > maxDataLen)
248 todo = maxDataLen;
249
250 flip = p_priv->out_flip;
Alan Coxdeb91682008-07-22 11:13:08 +0100251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 /* Check we have a valid urb/endpoint before we use it... */
Alan Coxdeb91682008-07-22 11:13:08 +0100253 this_urb = p_priv->out_urbs[flip];
254 if (this_urb == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 /* no bulk out, so return 0 bytes written */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700256 dev_dbg(&port->dev, "%s - no output urb :(\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 return count;
258 }
259
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700260 dev_dbg(&port->dev, "%s - endpoint %d flip %d\n",
Alan Coxdeb91682008-07-22 11:13:08 +0100261 __func__, usb_pipeendpoint(this_urb->pipe), flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
263 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +0100264 if (time_before(jiffies,
265 p_priv->tx_start_time[flip] + 10 * HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 usb_unlink_urb(this_urb);
268 break;
269 }
270
Alan Coxdeb91682008-07-22 11:13:08 +0100271 /* First byte in buffer is "last flag" (except for usa19hx)
272 - unused so for now so set to zero */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 ((char *)this_urb->transfer_buffer)[0] = 0;
274
Alan Coxdeb91682008-07-22 11:13:08 +0100275 memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 buf += todo;
277
278 /* send the data out the bulk port */
279 this_urb->transfer_buffer_length = todo + dataOffset;
280
Alan Coxdeb91682008-07-22 11:13:08 +0100281 err = usb_submit_urb(this_urb, GFP_ATOMIC);
282 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700283 dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 p_priv->tx_start_time[flip] = jiffies;
285
286 /* Flip for next time if usa26 or usa28 interface
287 (not used on usa49) */
288 p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
289 }
290
291 return count - left;
292}
293
David Howells7d12e782006-10-05 14:55:46 +0100294static void usa26_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295{
296 int i, err;
297 int endpoint;
298 struct usb_serial_port *port;
299 struct tty_struct *tty;
300 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700301 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 endpoint = usb_pipeendpoint(urb->pipe);
304
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700305 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700306 dev_dbg(&urb->dev->dev,"%s - nonzero status: %x on endpoint %d.\n",
307 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 return;
309 }
310
Ming Leicdc97792008-02-24 18:41:47 +0800311 port = urb->context;
Alan Cox4a90f092008-10-13 10:39:46 +0100312 tty = tty_port_tty_get(&port->port);
Alan Coxa5569a52008-01-21 17:18:24 -0800313 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 /* 0x80 bit is error flag */
315 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100316 /* no errors on individual bytes, only
317 possible overrun err */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100319 err = TTY_OVERRUN;
320 else
321 err = 0;
322 for (i = 1; i < urb->actual_length ; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 tty_insert_flip_char(tty, data[i], err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 } else {
325 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700326 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 for (i = 0; i + 1 < urb->actual_length; i += 2) {
328 int stat = data[i], flag = 0;
329 if (stat & RXERROR_OVERRUN)
330 flag |= TTY_OVERRUN;
331 if (stat & RXERROR_FRAMING)
332 flag |= TTY_FRAME;
333 if (stat & RXERROR_PARITY)
334 flag |= TTY_PARITY;
335 /* XXX should handle break (0x10) */
336 tty_insert_flip_char(tty, data[i+1], flag);
337 }
338 }
339 tty_flip_buffer_push(tty);
340 }
Alan Cox4a90f092008-10-13 10:39:46 +0100341 tty_kref_put(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100342
343 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500344 err = usb_submit_urb(urb, GFP_ATOMIC);
345 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700346 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347}
348
Alan Coxdeb91682008-07-22 11:13:08 +0100349/* Outdat handling is common for all devices */
David Howells7d12e782006-10-05 14:55:46 +0100350static void usa2x_outdat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351{
352 struct usb_serial_port *port;
353 struct keyspan_port_private *p_priv;
354
Ming Leicdc97792008-02-24 18:41:47 +0800355 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 p_priv = usb_get_serial_port_data(port);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700357 dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Alan Stern1f871582010-02-17 10:05:47 -0500359 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
David Howells7d12e782006-10-05 14:55:46 +0100362static void usa26_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364}
365
David Howells7d12e782006-10-05 14:55:46 +0100366static void usa26_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
368 struct usb_serial_port *port;
369 struct keyspan_port_private *p_priv;
370
Ming Leicdc97792008-02-24 18:41:47 +0800371 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 p_priv = usb_get_serial_port_data(port);
373
374 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700375 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100376 keyspan_usa26_send_setup(port->serial, port,
377 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 }
379}
380
David Howells7d12e782006-10-05 14:55:46 +0100381static void usa26_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382{
383 unsigned char *data = urb->transfer_buffer;
384 struct keyspan_usa26_portStatusMessage *msg;
385 struct usb_serial *serial;
386 struct usb_serial_port *port;
387 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100388 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700390 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Ming Leicdc97792008-02-24 18:41:47 +0800392 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700394 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700395 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 return;
397 }
398 if (urb->actual_length != 9) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700399 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 goto exit;
401 }
402
403 msg = (struct keyspan_usa26_portStatusMessage *)data;
404
405#if 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700406 dev_dbg(&urb->dev->dev,
407 "%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
408 __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr,
409 msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled,
410 msg->controlResponse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411#endif
412
413 /* Now do something useful with the data */
414
415
Alan Coxdeb91682008-07-22 11:13:08 +0100416 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700418 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 goto exit;
420 }
421 port = serial->port[msg->port];
422 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100423
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 /* Update handshaking pin state information */
425 old_dcd_state = p_priv->dcd_state;
426 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
427 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
428 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
429 p_priv->ri_state = ((msg->ri) ? 1 : 0);
430
Alan Cox4a90f092008-10-13 10:39:46 +0100431 if (old_dcd_state != p_priv->dcd_state) {
432 tty = tty_port_tty_get(&port->port);
433 if (tty && !C_CLOCAL(tty))
434 tty_hangup(tty);
435 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 }
Alan Coxdeb91682008-07-22 11:13:08 +0100437
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100439 err = usb_submit_urb(urb, GFP_ATOMIC);
440 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700441 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442exit: ;
443}
444
David Howells7d12e782006-10-05 14:55:46 +0100445static void usa26_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447}
448
449
David Howells7d12e782006-10-05 14:55:46 +0100450static void usa28_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
Alan Coxf035a8a2008-07-22 11:13:32 +0100452 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 struct usb_serial_port *port;
454 struct tty_struct *tty;
455 unsigned char *data;
456 struct keyspan_port_private *p_priv;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700457 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Ming Leicdc97792008-02-24 18:41:47 +0800459 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 p_priv = usb_get_serial_port_data(port);
461 data = urb->transfer_buffer;
462
463 if (urb != p_priv->in_urbs[p_priv->in_flip])
464 return;
465
466 do {
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700467 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700468 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
469 __func__, status, usb_pipeendpoint(urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 return;
471 }
472
Ming Leicdc97792008-02-24 18:41:47 +0800473 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 p_priv = usb_get_serial_port_data(port);
475 data = urb->transfer_buffer;
476
Ben Minerds40adac82012-07-12 00:10:17 +1000477 tty = tty_port_tty_get(&port->port);
Alan Cox4a90f092008-10-13 10:39:46 +0100478 if (tty && urb->actual_length) {
Alan Coxf035a8a2008-07-22 11:13:32 +0100479 tty_insert_flip_string(tty, data, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 tty_flip_buffer_push(tty);
481 }
Alan Cox4a90f092008-10-13 10:39:46 +0100482 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500485 err = usb_submit_urb(urb, GFP_ATOMIC);
486 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700487 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
Alan Stern1f871582010-02-17 10:05:47 -0500488 __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 p_priv->in_flip ^= 1;
490
491 urb = p_priv->in_urbs[p_priv->in_flip];
492 } while (urb->status != -EINPROGRESS);
493}
494
David Howells7d12e782006-10-05 14:55:46 +0100495static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}
498
David Howells7d12e782006-10-05 14:55:46 +0100499static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
501 struct usb_serial_port *port;
502 struct keyspan_port_private *p_priv;
503
Ming Leicdc97792008-02-24 18:41:47 +0800504 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 p_priv = usb_get_serial_port_data(port);
506
507 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700508 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100509 keyspan_usa28_send_setup(port->serial, port,
510 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 }
512}
513
David Howells7d12e782006-10-05 14:55:46 +0100514static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
516 int err;
517 unsigned char *data = urb->transfer_buffer;
518 struct keyspan_usa28_portStatusMessage *msg;
519 struct usb_serial *serial;
520 struct usb_serial_port *port;
521 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100522 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700524 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Ming Leicdc97792008-02-24 18:41:47 +0800526 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700528 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700529 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 return;
531 }
532
533 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700534 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 goto exit;
536 }
537
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700538 /*
539 dev_dbg(&urb->dev->dev,
540 "%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__,
541 data[0], data[1], data[2], data[3], data[4], data[5],
542 data[6], data[7], data[8], data[9], data[10], data[11]);
543 */
Alan Coxdeb91682008-07-22 11:13:08 +0100544
545 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 msg = (struct keyspan_usa28_portStatusMessage *)data;
547
Alan Coxdeb91682008-07-22 11:13:08 +0100548 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700550 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 goto exit;
552 }
553 port = serial->port[msg->port];
554 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 /* Update handshaking pin state information */
557 old_dcd_state = p_priv->dcd_state;
558 p_priv->cts_state = ((msg->cts) ? 1 : 0);
559 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
560 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
561 p_priv->ri_state = ((msg->ri) ? 1 : 0);
562
Ben Minerdsddc04ae2012-07-12 00:10:18 +1000563 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
Alan Cox4a90f092008-10-13 10:39:46 +0100564 tty = tty_port_tty_get(&port->port);
Ben Minerds878b5fd2012-07-12 00:10:19 +1000565 if (tty && !C_CLOCAL(tty))
Alan Cox4a90f092008-10-13 10:39:46 +0100566 tty_hangup(tty);
567 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 }
569
570 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100571 err = usb_submit_urb(urb, GFP_ATOMIC);
572 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700573 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574exit: ;
575}
576
David Howells7d12e782006-10-05 14:55:46 +0100577static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579}
580
581
David Howells7d12e782006-10-05 14:55:46 +0100582static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
584 struct usb_serial *serial;
585 struct usb_serial_port *port;
586 struct keyspan_port_private *p_priv;
587 int i;
588
Ming Leicdc97792008-02-24 18:41:47 +0800589 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 for (i = 0; i < serial->num_ports; ++i) {
591 port = serial->port[i];
592 p_priv = usb_get_serial_port_data(port);
593
594 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700595 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100596 keyspan_usa49_send_setup(serial, port,
597 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 break;
599 }
600 }
601}
602
603 /* This is actually called glostat in the Keyspan
604 doco */
David Howells7d12e782006-10-05 14:55:46 +0100605static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606{
607 int err;
608 unsigned char *data = urb->transfer_buffer;
609 struct keyspan_usa49_portStatusMessage *msg;
610 struct usb_serial *serial;
611 struct usb_serial_port *port;
612 struct keyspan_port_private *p_priv;
613 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700614 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Ming Leicdc97792008-02-24 18:41:47 +0800616 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700618 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700619 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 return;
621 }
622
Alan Coxdeb91682008-07-22 11:13:08 +0100623 if (urb->actual_length !=
624 sizeof(struct keyspan_usa49_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700625 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 goto exit;
627 }
628
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700629 /*
630 dev_dbg(&urb->dev->dev, "%s: %x %x %x %x %x %x %x %x %x %x %x",
631 __func__, data[0], data[1], data[2], data[3], data[4],
632 data[5], data[6], data[7], data[8], data[9], data[10]);
633 */
Alan Coxdeb91682008-07-22 11:13:08 +0100634
635 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 msg = (struct keyspan_usa49_portStatusMessage *)data;
637
Alan Coxdeb91682008-07-22 11:13:08 +0100638 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 if (msg->portNumber >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700640 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
641 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 goto exit;
643 }
644 port = serial->port[msg->portNumber];
645 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 /* Update handshaking pin state information */
648 old_dcd_state = p_priv->dcd_state;
649 p_priv->cts_state = ((msg->cts) ? 1 : 0);
650 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
651 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
652 p_priv->ri_state = ((msg->ri) ? 1 : 0);
653
Alan Cox4a90f092008-10-13 10:39:46 +0100654 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
655 struct tty_struct *tty = tty_port_tty_get(&port->port);
656 if (tty && !C_CLOCAL(tty))
657 tty_hangup(tty);
658 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
660
Alan Coxdeb91682008-07-22 11:13:08 +0100661 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100662 err = usb_submit_urb(urb, GFP_ATOMIC);
663 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700664 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665exit: ;
666}
667
David Howells7d12e782006-10-05 14:55:46 +0100668static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670}
671
David Howells7d12e782006-10-05 14:55:46 +0100672static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
674 int i, err;
675 int endpoint;
676 struct usb_serial_port *port;
677 struct tty_struct *tty;
678 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700679 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 endpoint = usb_pipeendpoint(urb->pipe);
682
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700683 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700684 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
685 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 return;
687 }
688
Ming Leicdc97792008-02-24 18:41:47 +0800689 port = urb->context;
Alan Cox4a90f092008-10-13 10:39:46 +0100690 tty = tty_port_tty_get(&port->port);
Alan Cox3004e532008-01-03 16:59:04 +0000691 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 /* 0x80 bit is error flag */
693 if ((data[0] & 0x80) == 0) {
694 /* no error on any byte */
Alan Coxf035a8a2008-07-22 11:13:32 +0100695 tty_insert_flip_string(tty, data + 1,
696 urb->actual_length - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 } else {
698 /* some bytes had errors, every byte has status */
699 for (i = 0; i + 1 < urb->actual_length; i += 2) {
700 int stat = data[i], flag = 0;
701 if (stat & RXERROR_OVERRUN)
702 flag |= TTY_OVERRUN;
703 if (stat & RXERROR_FRAMING)
704 flag |= TTY_FRAME;
705 if (stat & RXERROR_PARITY)
706 flag |= TTY_PARITY;
707 /* XXX should handle break (0x10) */
708 tty_insert_flip_char(tty, data[i+1], flag);
709 }
710 }
711 tty_flip_buffer_push(tty);
712 }
Alan Cox4a90f092008-10-13 10:39:46 +0100713 tty_kref_put(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100714
715 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500716 err = usb_submit_urb(urb, GFP_ATOMIC);
717 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700718 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719}
720
Lucy McCoy0ca12682007-05-18 12:10:41 -0700721static void usa49wg_indat_callback(struct urb *urb)
722{
723 int i, len, x, err;
724 struct usb_serial *serial;
725 struct usb_serial_port *port;
726 struct tty_struct *tty;
727 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700728 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700729
Lucy McCoy0ca12682007-05-18 12:10:41 -0700730 serial = urb->context;
731
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700732 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700733 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700734 return;
735 }
736
737 /* inbound data is in the form P#, len, status, data */
738 i = 0;
739 len = 0;
740
741 if (urb->actual_length) {
742 while (i < urb->actual_length) {
743
744 /* Check port number from message*/
745 if (data[i] >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700746 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800747 __func__, data[i]);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700748 return;
749 }
750 port = serial->port[data[i++]];
Alan Cox4a90f092008-10-13 10:39:46 +0100751 tty = tty_port_tty_get(&port->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700752 len = data[i++];
753
754 /* 0x80 bit is error flag */
755 if ((data[i] & 0x80) == 0) {
756 /* no error on any byte */
757 i++;
758 for (x = 1; x < len ; ++x)
Alan Stern1f871582010-02-17 10:05:47 -0500759 tty_insert_flip_char(tty, data[i++], 0);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700760 } else {
761 /*
762 * some bytes had errors, every byte has status
763 */
764 for (x = 0; x + 1 < len; x += 2) {
765 int stat = data[i], flag = 0;
766 if (stat & RXERROR_OVERRUN)
767 flag |= TTY_OVERRUN;
768 if (stat & RXERROR_FRAMING)
769 flag |= TTY_FRAME;
770 if (stat & RXERROR_PARITY)
771 flag |= TTY_PARITY;
772 /* XXX should handle break (0x10) */
Alan Stern1f871582010-02-17 10:05:47 -0500773 tty_insert_flip_char(tty,
Lucy McCoy0ca12682007-05-18 12:10:41 -0700774 data[i+1], flag);
775 i += 2;
776 }
777 }
Alan Stern1f871582010-02-17 10:05:47 -0500778 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100779 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700780 }
781 }
782
783 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700784 err = usb_submit_urb(urb, GFP_ATOMIC);
785 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700786 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700787}
788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700790static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792}
793
Lucy McCoy0ca12682007-05-18 12:10:41 -0700794static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
796 int i, err;
797 int endpoint;
798 struct usb_serial_port *port;
799 struct keyspan_port_private *p_priv;
800 struct tty_struct *tty;
801 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700802 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 endpoint = usb_pipeendpoint(urb->pipe);
805
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700806 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700807 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800808 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 return;
810 }
811
Ming Leicdc97792008-02-24 18:41:47 +0800812 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 p_priv = usb_get_serial_port_data(port);
814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 if (urb->actual_length) {
Alan Cox4a90f092008-10-13 10:39:46 +0100816 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100818 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Alan Coxf035a8a2008-07-22 11:13:32 +0100820 if (p_priv->baud > 57600)
821 tty_insert_flip_string(tty, data, urb->actual_length);
822 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 /* 0x80 bit is error flag */
824 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100825 /* no errors on individual bytes, only
826 possible overrun err*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100828 err = TTY_OVERRUN;
829 else
830 err = 0;
831 for (i = 1; i < urb->actual_length ; ++i)
832 tty_insert_flip_char(tty, data[i],
833 err);
834 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700836 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 for (i = 0; i + 1 < urb->actual_length; i += 2) {
838 int stat = data[i], flag = 0;
839 if (stat & RXERROR_OVERRUN)
840 flag |= TTY_OVERRUN;
841 if (stat & RXERROR_FRAMING)
842 flag |= TTY_FRAME;
843 if (stat & RXERROR_PARITY)
844 flag |= TTY_PARITY;
845 /* XXX should handle break (0x10) */
Alan Coxdeb91682008-07-22 11:13:08 +0100846 tty_insert_flip_char(tty, data[i+1],
847 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 }
849 }
850 }
851 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100852 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 }
Alan Coxdeb91682008-07-22 11:13:08 +0100854
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500856 err = usb_submit_urb(urb, GFP_ATOMIC);
857 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700858 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859}
860
861
David Howells7d12e782006-10-05 14:55:46 +0100862static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863{
864 unsigned char *data = urb->transfer_buffer;
865 struct keyspan_usa90_portStatusMessage *msg;
866 struct usb_serial *serial;
867 struct usb_serial_port *port;
868 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100869 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700871 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
Ming Leicdc97792008-02-24 18:41:47 +0800873 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700875 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700876 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 return;
878 }
879 if (urb->actual_length < 14) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700880 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 goto exit;
882 }
883
884 msg = (struct keyspan_usa90_portStatusMessage *)data;
885
886 /* Now do something useful with the data */
887
888 port = serial->port[0];
889 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100890
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 /* Update handshaking pin state information */
892 old_dcd_state = p_priv->dcd_state;
893 p_priv->cts_state = ((msg->cts) ? 1 : 0);
894 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
895 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
896 p_priv->ri_state = ((msg->ri) ? 1 : 0);
897
Alan Cox4a90f092008-10-13 10:39:46 +0100898 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
899 tty = tty_port_tty_get(&port->port);
900 if (tty && !C_CLOCAL(tty))
901 tty_hangup(tty);
902 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 }
Alan Coxdeb91682008-07-22 11:13:08 +0100904
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100906 err = usb_submit_urb(urb, GFP_ATOMIC);
907 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700908 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909exit:
910 ;
911}
912
David Howells7d12e782006-10-05 14:55:46 +0100913static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914{
915 struct usb_serial_port *port;
916 struct keyspan_port_private *p_priv;
917
Ming Leicdc97792008-02-24 18:41:47 +0800918 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 p_priv = usb_get_serial_port_data(port);
920
921 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700922 dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100923 keyspan_usa90_send_setup(port->serial, port,
924 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 }
926}
927
Lucy McCoy0ca12682007-05-18 12:10:41 -0700928/* Status messages from the 28xg */
929static void usa67_instat_callback(struct urb *urb)
930{
931 int err;
932 unsigned char *data = urb->transfer_buffer;
933 struct keyspan_usa67_portStatusMessage *msg;
934 struct usb_serial *serial;
935 struct usb_serial_port *port;
936 struct keyspan_port_private *p_priv;
937 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700938 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700939
Lucy McCoy0ca12682007-05-18 12:10:41 -0700940 serial = urb->context;
941
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700942 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700943 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700944 return;
945 }
946
Alan Coxdeb91682008-07-22 11:13:08 +0100947 if (urb->actual_length !=
948 sizeof(struct keyspan_usa67_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700949 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700950 return;
951 }
952
953
954 /* Now do something useful with the data */
955 msg = (struct keyspan_usa67_portStatusMessage *)data;
956
957 /* Check port number from message and retrieve private data */
958 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700959 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700960 return;
961 }
962
963 port = serial->port[msg->port];
964 p_priv = usb_get_serial_port_data(port);
965
966 /* Update handshaking pin state information */
967 old_dcd_state = p_priv->dcd_state;
968 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
969 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
970
Alan Cox4a90f092008-10-13 10:39:46 +0100971 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
972 struct tty_struct *tty = tty_port_tty_get(&port->port);
973 if (tty && !C_CLOCAL(tty))
974 tty_hangup(tty);
975 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700976 }
977
978 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700979 err = usb_submit_urb(urb, GFP_ATOMIC);
980 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700981 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700982}
983
984static void usa67_glocont_callback(struct urb *urb)
985{
986 struct usb_serial *serial;
987 struct usb_serial_port *port;
988 struct keyspan_port_private *p_priv;
989 int i;
990
Lucy McCoy0ca12682007-05-18 12:10:41 -0700991 serial = urb->context;
992 for (i = 0; i < serial->num_ports; ++i) {
993 port = serial->port[i];
994 p_priv = usb_get_serial_port_data(port);
995
996 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700997 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700998 keyspan_usa67_send_setup(serial, port,
999 p_priv->resend_cont - 1);
1000 break;
1001 }
1002 }
1003}
1004
Alan Cox95da3102008-07-22 11:09:07 +01001005static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006{
Alan Cox95da3102008-07-22 11:09:07 +01001007 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 struct keyspan_port_private *p_priv;
1009 const struct keyspan_device_details *d_details;
1010 int flip;
1011 int data_len;
1012 struct urb *this_urb;
1013
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 p_priv = usb_get_serial_port_data(port);
1015 d_details = p_priv->device_details;
1016
Alan Coxa5b6f602008-04-08 17:16:06 +01001017 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +01001019 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 else
1021 data_len = 63;
1022
1023 flip = p_priv->out_flip;
1024
1025 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +01001026 this_urb = p_priv->out_urbs[flip];
1027 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001029 return data_len;
1030 flip = (flip + 1) & d_details->outdat_endp_flip;
1031 this_urb = p_priv->out_urbs[flip];
1032 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001034 return data_len;
1035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 }
Alan Coxa5b6f602008-04-08 17:16:06 +01001037 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038}
1039
1040
Alan Coxa509a7e2009-09-19 13:13:26 -07001041static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001043 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 const struct keyspan_device_details *d_details;
1045 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001046 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001048 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 p_priv = usb_get_serial_port_data(port);
1051 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001052
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 /* Set some sane defaults */
1054 p_priv->rts_state = 1;
1055 p_priv->dtr_state = 1;
1056 p_priv->baud = 9600;
1057
1058 /* force baud and lcr to be set on open */
1059 p_priv->old_baud = 0;
1060 p_priv->old_cflag = 0;
1061
1062 p_priv->out_flip = 0;
1063 p_priv->in_flip = 0;
1064
1065 /* Reset low level data toggle and start reading from endpoints */
1066 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001067 urb = p_priv->in_urbs[i];
1068 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Alan Coxdeb91682008-07-22 11:13:08 +01001071 /* make sure endpoint data toggle is synchronized
1072 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001074 err = usb_submit_urb(urb, GFP_KERNEL);
1075 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001076 dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 }
1078
1079 /* Reset low level data toggle on out endpoints */
1080 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001081 urb = p_priv->out_urbs[i];
1082 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 continue;
Alan Coxdeb91682008-07-22 11:13:08 +01001084 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1085 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 }
1087
Andrew Mortonf78ba152007-11-28 16:21:54 -08001088 /* get the terminal config for the setup message now so we don't
1089 * need to send 2 of them */
1090
Andrew Mortonf78ba152007-11-28 16:21:54 -08001091 device_port = port->number - port->serial->minor;
Alan Cox95da3102008-07-22 11:09:07 +01001092 if (tty) {
1093 cflag = tty->termios->c_cflag;
1094 /* Baud rate calculation takes baud rate as an integer
1095 so other rates can be generated if desired. */
1096 baud_rate = tty_get_baud_rate(tty);
1097 /* If no match or invalid, leave as default */
1098 if (baud_rate >= 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001099 && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Alan Cox95da3102008-07-22 11:09:07 +01001100 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1101 p_priv->baud = baud_rate;
1102 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001103 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001104 /* set CTS/RTS handshake etc. */
1105 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +10001106 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001107
1108 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001109 /* mdelay(100); */
1110 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001111
Alan Coxa5b6f602008-04-08 17:16:06 +01001112 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113}
1114
1115static inline void stop_urb(struct urb *urb)
1116{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001117 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119}
1120
Alan Cox335f8512009-06-11 12:26:29 +01001121static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1122{
1123 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1124
1125 p_priv->rts_state = on;
1126 p_priv->dtr_state = on;
1127 keyspan_send_setup(port, 0);
1128}
1129
1130static void keyspan_close(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131{
1132 int i;
1133 struct usb_serial *serial = port->serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 struct keyspan_port_private *p_priv;
1135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 p_priv->rts_state = 0;
1139 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001140
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 if (serial->dev) {
1142 keyspan_send_setup(port, 2);
1143 /* pilot-xfer seems to work best with this delay */
1144 mdelay(100);
Alan Coxdeb91682008-07-22 11:13:08 +01001145 /* keyspan_set_termios(port, NULL); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 }
1147
1148 /*while (p_priv->outcont_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001149 dev_dbg(&port->dev, "%s - urb in progress\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }*/
1151
1152 p_priv->out_flip = 0;
1153 p_priv->in_flip = 0;
1154
1155 if (serial->dev) {
1156 /* Stop reading/writing urbs */
1157 stop_urb(p_priv->inack_urb);
1158 /* stop_urb(p_priv->outcont_urb); */
1159 for (i = 0; i < 2; i++) {
1160 stop_urb(p_priv->in_urbs[i]);
1161 stop_urb(p_priv->out_urbs[i]);
1162 }
1163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164}
1165
Alan Coxdeb91682008-07-22 11:13:08 +01001166/* download the firmware to a pre-renumeration device */
1167static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168{
1169 int response;
David Woodhouse2971c572008-05-30 14:04:03 +03001170 const struct ihex_binrec *record;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 char *fw_name;
David Woodhouse2971c572008-05-30 14:04:03 +03001172 const struct firmware *fw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001174 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
1175 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1176 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001177
1178 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1179 != 0x8000) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001180 dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n");
Alan Coxdeb91682008-07-22 11:13:08 +01001181 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 }
1183
1184 /* Select firmware image on the basis of idProduct */
1185 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1186 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001187 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 break;
1189
1190 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001191 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 break;
1193
1194 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001195 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 break;
1197
1198 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001199 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 break;
1201
1202 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001203 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001205
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001207 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001209
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001211 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 break;
1213
1214 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001215 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001217
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001219 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001223 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001227 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 break;
1229
1230 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001231 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 break;
1233
1234 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001235 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1236 le16_to_cpu(serial->dev->descriptor.idProduct));
1237 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 }
1239
David Woodhouse2971c572008-05-30 14:04:03 +03001240 if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 dev_err(&serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name);
Ben Minerdsf9943c22012-07-12 00:10:20 +10001242 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 }
1244
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001245 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247 /* download the firmware image */
Rene Buergel99495c72012-09-13 22:14:38 +02001248 response = ezusb_set_reset(serial->dev, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
David Woodhouse2971c572008-05-30 14:04:03 +03001250 record = (const struct ihex_binrec *)fw->data;
1251
1252 while (record) {
Rene Buergel99495c72012-09-13 22:14:38 +02001253 response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 (unsigned char *)record->data,
David Woodhouse2971c572008-05-30 14:04:03 +03001255 be16_to_cpu(record->len), 0xa0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 if (response < 0) {
Alan Coxdeb91682008-07-22 11:13:08 +01001257 dev_err(&serial->dev->dev, "ezusb_writememory failed for Keyspan firmware (%d %04X %p %d)\n",
David Woodhouse2971c572008-05-30 14:04:03 +03001258 response, be32_to_cpu(record->addr),
1259 record->data, be16_to_cpu(record->len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 break;
1261 }
David Woodhouse2971c572008-05-30 14:04:03 +03001262 record = ihex_next_binrec(record);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 }
David Woodhouse2971c572008-05-30 14:04:03 +03001264 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 /* bring device out of reset. Renumeration will occur in a
1266 moment and the new device will bind to the real driver */
Rene Buergel99495c72012-09-13 22:14:38 +02001267 response = ezusb_set_reset(serial->dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
1269 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001270 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271}
1272
1273/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001274static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1275 int endpoint)
1276{
1277 struct usb_host_interface *iface_desc;
1278 struct usb_endpoint_descriptor *ep;
1279 int i;
1280
1281 iface_desc = serial->interface->cur_altsetting;
1282 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1283 ep = &iface_desc->endpoint[i].desc;
1284 if (ep->bEndpointAddress == endpoint)
1285 return ep;
1286 }
1287 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1288 "endpoint %x\n", endpoint);
1289 return NULL;
1290}
1291
Alan Coxdeb91682008-07-22 11:13:08 +01001292static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001294 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295{
1296 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001297 struct usb_endpoint_descriptor const *ep_desc;
1298 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
1300 if (endpoint == -1)
1301 return NULL; /* endpoint not needed */
1302
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001303 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
1305 if (urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001306 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d failed.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 return NULL;
1308 }
1309
Lucy McCoy0ca12682007-05-18 12:10:41 -07001310 if (endpoint == 0) {
1311 /* control EP filled in when used */
1312 return urb;
1313 }
1314
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001315 ep_desc = find_ep(serial, endpoint);
1316 if (!ep_desc) {
1317 /* leak the urb, something's wrong and the callers don't care */
1318 return urb;
1319 }
1320 if (usb_endpoint_xfer_int(ep_desc)) {
1321 ep_type_name = "INT";
1322 usb_fill_int_urb(urb, serial->dev,
1323 usb_sndintpipe(serial->dev, endpoint) | dir,
1324 buf, len, callback, ctx,
1325 ep_desc->bInterval);
1326 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1327 ep_type_name = "BULK";
1328 usb_fill_bulk_urb(urb, serial->dev,
1329 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1330 buf, len, callback, ctx);
1331 } else {
1332 dev_warn(&serial->interface->dev,
1333 "unsupported endpoint type %x\n",
Julia Lawall2e0fe702008-12-29 11:22:14 +01001334 usb_endpoint_type(ep_desc));
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001335 usb_free_urb(urb);
1336 return NULL;
1337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001339 dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001340 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 return urb;
1342}
1343
1344static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001345 void (*instat_callback)(struct urb *);
1346 void (*glocont_callback)(struct urb *);
1347 void (*indat_callback)(struct urb *);
1348 void (*outdat_callback)(struct urb *);
1349 void (*inack_callback)(struct urb *);
1350 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351} keyspan_callbacks[] = {
1352 {
1353 /* msg_usa26 callbacks */
1354 .instat_callback = usa26_instat_callback,
1355 .glocont_callback = usa26_glocont_callback,
1356 .indat_callback = usa26_indat_callback,
1357 .outdat_callback = usa2x_outdat_callback,
1358 .inack_callback = usa26_inack_callback,
1359 .outcont_callback = usa26_outcont_callback,
1360 }, {
1361 /* msg_usa28 callbacks */
1362 .instat_callback = usa28_instat_callback,
1363 .glocont_callback = usa28_glocont_callback,
1364 .indat_callback = usa28_indat_callback,
1365 .outdat_callback = usa2x_outdat_callback,
1366 .inack_callback = usa28_inack_callback,
1367 .outcont_callback = usa28_outcont_callback,
1368 }, {
1369 /* msg_usa49 callbacks */
1370 .instat_callback = usa49_instat_callback,
1371 .glocont_callback = usa49_glocont_callback,
1372 .indat_callback = usa49_indat_callback,
1373 .outdat_callback = usa2x_outdat_callback,
1374 .inack_callback = usa49_inack_callback,
1375 .outcont_callback = usa49_outcont_callback,
1376 }, {
1377 /* msg_usa90 callbacks */
1378 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001379 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 .indat_callback = usa90_indat_callback,
1381 .outdat_callback = usa2x_outdat_callback,
1382 .inack_callback = usa28_inack_callback,
1383 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001384 }, {
1385 /* msg_usa67 callbacks */
1386 .instat_callback = usa67_instat_callback,
1387 .glocont_callback = usa67_glocont_callback,
1388 .indat_callback = usa26_indat_callback,
1389 .outdat_callback = usa2x_outdat_callback,
1390 .inack_callback = usa26_inack_callback,
1391 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 }
1393};
1394
1395 /* Generic setup urbs function that uses
1396 data in device_details */
1397static void keyspan_setup_urbs(struct usb_serial *serial)
1398{
1399 int i, j;
1400 struct keyspan_serial_private *s_priv;
1401 const struct keyspan_device_details *d_details;
1402 struct usb_serial_port *port;
1403 struct keyspan_port_private *p_priv;
1404 struct callbacks *cback;
1405 int endp;
1406
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 s_priv = usb_get_serial_data(serial);
1408 d_details = s_priv->device_details;
1409
Alan Coxdeb91682008-07-22 11:13:08 +01001410 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 cback = &keyspan_callbacks[d_details->msg_format];
1412
Alan Coxdeb91682008-07-22 11:13:08 +01001413 /* Allocate and set up urbs for each one that is in use,
1414 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 s_priv->instat_urb = keyspan_setup_urb
1416 (serial, d_details->instat_endpoint, USB_DIR_IN,
1417 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1418 cback->instat_callback);
1419
Lucy McCoy0ca12682007-05-18 12:10:41 -07001420 s_priv->indat_urb = keyspan_setup_urb
1421 (serial, d_details->indat_endpoint, USB_DIR_IN,
1422 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1423 usa49wg_indat_callback);
1424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 s_priv->glocont_urb = keyspan_setup_urb
1426 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1427 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1428 cback->glocont_callback);
1429
Alan Coxdeb91682008-07-22 11:13:08 +01001430 /* Setup endpoints for each port specific thing */
1431 for (i = 0; i < d_details->num_ports; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 port = serial->port[i];
1433 p_priv = usb_get_serial_port_data(port);
1434
1435 /* Do indat endpoints first, once for each flip */
1436 endp = d_details->indat_endpoints[i];
1437 for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) {
1438 p_priv->in_urbs[j] = keyspan_setup_urb
1439 (serial, endp, USB_DIR_IN, port,
1440 p_priv->in_buffer[j], 64,
1441 cback->indat_callback);
1442 }
1443 for (; j < 2; ++j)
1444 p_priv->in_urbs[j] = NULL;
1445
1446 /* outdat endpoints also have flip */
1447 endp = d_details->outdat_endpoints[i];
1448 for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) {
1449 p_priv->out_urbs[j] = keyspan_setup_urb
1450 (serial, endp, USB_DIR_OUT, port,
1451 p_priv->out_buffer[j], 64,
1452 cback->outdat_callback);
1453 }
1454 for (; j < 2; ++j)
1455 p_priv->out_urbs[j] = NULL;
1456
1457 /* inack endpoint */
1458 p_priv->inack_urb = keyspan_setup_urb
1459 (serial, d_details->inack_endpoints[i], USB_DIR_IN,
1460 port, p_priv->inack_buffer, 1, cback->inack_callback);
1461
1462 /* outcont endpoint */
1463 p_priv->outcont_urb = keyspan_setup_urb
1464 (serial, d_details->outcont_endpoints[i], USB_DIR_OUT,
1465 port, p_priv->outcont_buffer, 64,
1466 cback->outcont_callback);
Alan Coxdeb91682008-07-22 11:13:08 +01001467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468}
1469
1470/* usa19 function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001471static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1472 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 u8 *rate_low, u8 *prescaler, int portnum)
1474{
1475 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001476 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001479 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480
Alan Coxdeb91682008-07-22 11:13:08 +01001481 /* prevent divide by zero... */
1482 b16 = baud_rate * 16L;
1483 if (b16 == 0)
1484 return KEYSPAN_INVALID_BAUD_RATE;
1485 /* Any "standard" rate over 57k6 is marginal on the USA-19
1486 as we run out of divisor resolution. */
1487 if (baud_rate > 57600)
1488 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
Alan Coxdeb91682008-07-22 11:13:08 +01001490 /* calculate the divisor and the counter (its inverse) */
1491 div = baudclk / b16;
1492 if (div == 0)
1493 return KEYSPAN_INVALID_BAUD_RATE;
1494 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496
Alan Coxdeb91682008-07-22 11:13:08 +01001497 if (div > 0xffff)
1498 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499
Alan Coxdeb91682008-07-22 11:13:08 +01001500 /* return the counter values if non-null */
1501 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001503 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001505 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001506 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001507 __func__, baud_rate, *rate_hi, *rate_low);
1508 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509}
1510
1511/* usa19hs function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001512static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1513 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1514 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515{
1516 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001517 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001519 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520
Alan Coxdeb91682008-07-22 11:13:08 +01001521 /* prevent divide by zero... */
1522 b16 = baud_rate * 16L;
1523 if (b16 == 0)
1524 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525
Alan Coxdeb91682008-07-22 11:13:08 +01001526 /* calculate the divisor */
1527 div = baudclk / b16;
1528 if (div == 0)
1529 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
Alan Coxdeb91682008-07-22 11:13:08 +01001531 if (div > 0xffff)
1532 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
Alan Coxdeb91682008-07-22 11:13:08 +01001534 /* return the counter values if non-null */
1535 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001537
1538 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001540
1541 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001542 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001543 __func__, baud_rate, *rate_hi, *rate_low);
1544
1545 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546}
1547
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001548static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1549 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 u8 *rate_low, u8 *prescaler, int portnum)
1551{
1552 u32 b16, /* baud rate times 16 (actual rate used internally) */
1553 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001554 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 res, /* resulting baud rate using 13/8 prescaler */
1556 diff, /* error using 13/8 prescaler */
1557 smallest_diff;
1558 u8 best_prescaler;
1559 int i;
1560
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001561 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562
Alan Coxdeb91682008-07-22 11:13:08 +01001563 /* prevent divide by zero */
1564 b16 = baud_rate * 16L;
1565 if (b16 == 0)
1566 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
Alan Coxdeb91682008-07-22 11:13:08 +01001568 /* Calculate prescaler by trying them all and looking
1569 for best fit */
1570
1571 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 smallest_diff = 0xffffffff;
1573
1574 /* 0 is an invalid prescaler, used as a flag */
1575 best_prescaler = 0;
1576
Alan Coxdeb91682008-07-22 11:13:08 +01001577 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001579
1580 div = clk / b16;
1581 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
1584 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001585 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
Alan Coxdeb91682008-07-22 11:13:08 +01001587 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 best_prescaler = i;
1589 smallest_diff = diff;
1590 }
1591 }
1592
Alan Coxdeb91682008-07-22 11:13:08 +01001593 if (best_prescaler == 0)
1594 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596 clk = (baudclk * 8) / (u32) best_prescaler;
1597 div = clk / b16;
1598
Alan Coxdeb91682008-07-22 11:13:08 +01001599 /* return the divisor and prescaler if non-null */
1600 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001602 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 if (prescaler) {
1605 *prescaler = best_prescaler;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001606 /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 }
Alan Coxdeb91682008-07-22 11:13:08 +01001608 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609}
1610
1611 /* USA-28 supports different maximum baud rates on each port */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001612static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1613 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1614 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615{
1616 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001617 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 cnt; /* inverse of divisor (programmed into 8051) */
1619
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001620 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
1622 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001623 b16 = baud_rate * 16L;
1624 if (b16 == 0)
1625 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Alan Coxdeb91682008-07-22 11:13:08 +01001627 /* calculate the divisor and the counter (its inverse) */
1628 div = KEYSPAN_USA28_BAUDCLK / b16;
1629 if (div == 0)
1630 return KEYSPAN_INVALID_BAUD_RATE;
1631 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
Alan Coxdeb91682008-07-22 11:13:08 +01001634 /* check for out of range, based on portnum,
1635 and return result */
1636 if (portnum == 0) {
1637 if (div > 0xffff)
1638 return KEYSPAN_INVALID_BAUD_RATE;
1639 } else {
1640 if (portnum == 1) {
1641 if (div > 0xff)
1642 return KEYSPAN_INVALID_BAUD_RATE;
1643 } else
1644 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 }
1646
1647 /* return the counter values if not NULL
1648 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001649 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001651 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001653 dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
Alan Coxdeb91682008-07-22 11:13:08 +01001654 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655}
1656
1657static int keyspan_usa26_send_setup(struct usb_serial *serial,
1658 struct usb_serial_port *port,
1659 int reset_port)
1660{
Alan Coxdeb91682008-07-22 11:13:08 +01001661 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 struct keyspan_serial_private *s_priv;
1663 struct keyspan_port_private *p_priv;
1664 const struct keyspan_device_details *d_details;
1665 int outcont_urb;
1666 struct urb *this_urb;
1667 int device_port, err;
1668
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001669 dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 s_priv = usb_get_serial_data(serial);
1672 p_priv = usb_get_serial_port_data(port);
1673 d_details = s_priv->device_details;
1674 device_port = port->number - port->serial->minor;
1675
1676 outcont_urb = d_details->outcont_endpoints[port->number];
1677 this_urb = p_priv->outcont_urb;
1678
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001679 dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
1681 /* Make sure we have an urb then send the message */
1682 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001683 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 return -1;
1685 }
1686
1687 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001688 Don't overwrite resend for open/close condition. */
1689 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 p_priv->resend_cont = reset_port + 1;
1691 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001692 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001694 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 }
1696
Alan Coxdeb91682008-07-22 11:13:08 +01001697 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1698
1699 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 if (p_priv->old_baud != p_priv->baud) {
1701 p_priv->old_baud = p_priv->baud;
1702 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001703 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1704 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1705 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1706 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1707 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 msg.baudLo = 0;
1709 msg.baudHi = 125; /* Values for 9600 baud */
1710 msg.prescaler = 10;
1711 }
1712 msg.setPrescaler = 0xff;
1713 }
1714
Ben Minerds2b982ab2012-07-12 00:10:16 +10001715 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 switch (p_priv->cflag & CSIZE) {
1717 case CS5:
1718 msg.lcr |= USA_DATABITS_5;
1719 break;
1720 case CS6:
1721 msg.lcr |= USA_DATABITS_6;
1722 break;
1723 case CS7:
1724 msg.lcr |= USA_DATABITS_7;
1725 break;
1726 case CS8:
1727 msg.lcr |= USA_DATABITS_8;
1728 break;
1729 }
1730 if (p_priv->cflag & PARENB) {
1731 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001732 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001733 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 }
1735 msg.setLcr = 0xff;
1736
1737 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1738 msg.xonFlowControl = 0;
1739 msg.setFlowControl = 0xff;
1740 msg.forwardingLength = 16;
1741 msg.xonChar = 17;
1742 msg.xoffChar = 19;
1743
1744 /* Opening port */
1745 if (reset_port == 1) {
1746 msg._txOn = 1;
1747 msg._txOff = 0;
1748 msg.txFlush = 0;
1749 msg.txBreak = 0;
1750 msg.rxOn = 1;
1751 msg.rxOff = 0;
1752 msg.rxFlush = 1;
1753 msg.rxForward = 0;
1754 msg.returnStatus = 0;
1755 msg.resetDataToggle = 0xff;
1756 }
1757
1758 /* Closing port */
1759 else if (reset_port == 2) {
1760 msg._txOn = 0;
1761 msg._txOff = 1;
1762 msg.txFlush = 0;
1763 msg.txBreak = 0;
1764 msg.rxOn = 0;
1765 msg.rxOff = 1;
1766 msg.rxFlush = 1;
1767 msg.rxForward = 0;
1768 msg.returnStatus = 0;
1769 msg.resetDataToggle = 0;
1770 }
1771
1772 /* Sending intermediate configs */
1773 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001774 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 msg._txOff = 0;
1776 msg.txFlush = 0;
1777 msg.txBreak = (p_priv->break_on);
1778 msg.rxOn = 0;
1779 msg.rxOff = 0;
1780 msg.rxFlush = 0;
1781 msg.rxForward = 0;
1782 msg.returnStatus = 0;
1783 msg.resetDataToggle = 0x0;
1784 }
1785
Alan Coxdeb91682008-07-22 11:13:08 +01001786 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 msg.setTxTriState_setRts = 0xff;
1788 msg.txTriState_rts = p_priv->rts_state;
1789
1790 msg.setHskoa_setDtr = 0xff;
1791 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001792
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001794 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1795
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 /* send the data out the device on control endpoint */
1797 this_urb->transfer_buffer_length = sizeof(msg);
1798
Alan Coxdeb91682008-07-22 11:13:08 +01001799 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1800 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001801 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802#if 0
1803 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001804 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__
1805 outcont_urb, this_urb->transfer_buffer_length,
1806 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 }
1808#endif
1809
Alan Coxa5b6f602008-04-08 17:16:06 +01001810 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811}
1812
1813static int keyspan_usa28_send_setup(struct usb_serial *serial,
1814 struct usb_serial_port *port,
1815 int reset_port)
1816{
Alan Coxdeb91682008-07-22 11:13:08 +01001817 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 struct keyspan_serial_private *s_priv;
1819 struct keyspan_port_private *p_priv;
1820 const struct keyspan_device_details *d_details;
1821 struct urb *this_urb;
1822 int device_port, err;
1823
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 s_priv = usb_get_serial_data(serial);
1825 p_priv = usb_get_serial_port_data(port);
1826 d_details = s_priv->device_details;
1827 device_port = port->number - port->serial->minor;
1828
1829 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001830 this_urb = p_priv->outcont_urb;
1831 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001832 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 return -1;
1834 }
1835
1836 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001837 Don't overwrite resend for open/close condition. */
1838 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 p_priv->resend_cont = reset_port + 1;
1840 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001841 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001843 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 }
1845
Alan Coxdeb91682008-07-22 11:13:08 +01001846 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847
1848 msg.setBaudRate = 1;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001849 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1850 &msg.baudHi, &msg.baudLo, NULL,
1851 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1852 dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001853 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 msg.baudLo = 0xff;
1855 msg.baudHi = 0xb2; /* Values for 9600 baud */
1856 }
1857
1858 /* If parity is enabled, we must calculate it ourselves. */
1859 msg.parity = 0; /* XXX for now */
1860
1861 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1862 msg.xonFlowControl = 0;
1863
Alan Coxdeb91682008-07-22 11:13:08 +01001864 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 msg.rts = p_priv->rts_state;
1866 msg.dtr = p_priv->dtr_state;
1867
1868 msg.forwardingLength = 16;
1869 msg.forwardMs = 10;
1870 msg.breakThreshold = 45;
1871 msg.xonChar = 17;
1872 msg.xoffChar = 19;
1873
1874 /*msg.returnStatus = 1;
1875 msg.resetDataToggle = 0xff;*/
1876 /* Opening port */
1877 if (reset_port == 1) {
1878 msg._txOn = 1;
1879 msg._txOff = 0;
1880 msg.txFlush = 0;
1881 msg.txForceXoff = 0;
1882 msg.txBreak = 0;
1883 msg.rxOn = 1;
1884 msg.rxOff = 0;
1885 msg.rxFlush = 1;
1886 msg.rxForward = 0;
1887 msg.returnStatus = 0;
1888 msg.resetDataToggle = 0xff;
1889 }
1890 /* Closing port */
1891 else if (reset_port == 2) {
1892 msg._txOn = 0;
1893 msg._txOff = 1;
1894 msg.txFlush = 0;
1895 msg.txForceXoff = 0;
1896 msg.txBreak = 0;
1897 msg.rxOn = 0;
1898 msg.rxOff = 1;
1899 msg.rxFlush = 1;
1900 msg.rxForward = 0;
1901 msg.returnStatus = 0;
1902 msg.resetDataToggle = 0;
1903 }
1904 /* Sending intermediate configs */
1905 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001906 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 msg._txOff = 0;
1908 msg.txFlush = 0;
1909 msg.txForceXoff = 0;
1910 msg.txBreak = (p_priv->break_on);
1911 msg.rxOn = 0;
1912 msg.rxOff = 0;
1913 msg.rxFlush = 0;
1914 msg.rxForward = 0;
1915 msg.returnStatus = 0;
1916 msg.resetDataToggle = 0x0;
1917 }
1918
1919 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001920 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
1922 /* send the data out the device on control endpoint */
1923 this_urb->transfer_buffer_length = sizeof(msg);
1924
Alan Coxdeb91682008-07-22 11:13:08 +01001925 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1926 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001927 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928#if 0
1929 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001930 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 this_urb->transfer_buffer_length);
1932 }
1933#endif
1934
Alan Coxa5b6f602008-04-08 17:16:06 +01001935 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936}
1937
1938static int keyspan_usa49_send_setup(struct usb_serial *serial,
1939 struct usb_serial_port *port,
1940 int reset_port)
1941{
Lucy McCoy0ca12682007-05-18 12:10:41 -07001942 struct keyspan_usa49_portControlMessage msg;
1943 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 struct keyspan_serial_private *s_priv;
1945 struct keyspan_port_private *p_priv;
1946 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 struct urb *this_urb;
1948 int err, device_port;
1949
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 s_priv = usb_get_serial_data(serial);
1951 p_priv = usb_get_serial_port_data(port);
1952 d_details = s_priv->device_details;
1953
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 this_urb = s_priv->glocont_urb;
1955
Lucy McCoy0ca12682007-05-18 12:10:41 -07001956 /* Work out which port within the device is being setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 device_port = port->number - port->serial->minor;
1958
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301959 /* Make sure we have an urb then send the message */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001961 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 return -1;
1963 }
1964
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001965 dev_dbg(&port->dev, "%s - endpoint %d port %d (%d)\n",
1966 __func__, usb_pipeendpoint(this_urb->pipe),
1967 port->number, device_port);
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301968
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001970 Don't overwrite resend for open/close condition. */
1971 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001973
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001975 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001977 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 }
1979
Alan Coxdeb91682008-07-22 11:13:08 +01001980 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981
1982 /*msg.portNumber = port->number;*/
1983 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01001984
1985 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 if (p_priv->old_baud != p_priv->baud) {
1987 p_priv->old_baud = p_priv->baud;
1988 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001989 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1990 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1991 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1992 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1993 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 msg.baudLo = 0;
1995 msg.baudHi = 125; /* Values for 9600 baud */
1996 msg.prescaler = 10;
1997 }
Alan Coxdeb91682008-07-22 11:13:08 +01001998 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 }
2000
Ben Minerds2b982ab2012-07-12 00:10:16 +10002001 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 switch (p_priv->cflag & CSIZE) {
2003 case CS5:
2004 msg.lcr |= USA_DATABITS_5;
2005 break;
2006 case CS6:
2007 msg.lcr |= USA_DATABITS_6;
2008 break;
2009 case CS7:
2010 msg.lcr |= USA_DATABITS_7;
2011 break;
2012 case CS8:
2013 msg.lcr |= USA_DATABITS_8;
2014 break;
2015 }
2016 if (p_priv->cflag & PARENB) {
2017 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002018 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002019 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 }
2021 msg.setLcr = 0xff;
2022
2023 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2024 msg.xonFlowControl = 0;
2025 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01002026
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 msg.forwardingLength = 16;
2028 msg.xonChar = 17;
2029 msg.xoffChar = 19;
2030
Alan Coxdeb91682008-07-22 11:13:08 +01002031 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 if (reset_port == 1) {
2033 msg._txOn = 1;
2034 msg._txOff = 0;
2035 msg.txFlush = 0;
2036 msg.txBreak = 0;
2037 msg.rxOn = 1;
2038 msg.rxOff = 0;
2039 msg.rxFlush = 1;
2040 msg.rxForward = 0;
2041 msg.returnStatus = 0;
2042 msg.resetDataToggle = 0xff;
2043 msg.enablePort = 1;
2044 msg.disablePort = 0;
2045 }
2046 /* Closing port */
2047 else if (reset_port == 2) {
2048 msg._txOn = 0;
2049 msg._txOff = 1;
2050 msg.txFlush = 0;
2051 msg.txBreak = 0;
2052 msg.rxOn = 0;
2053 msg.rxOff = 1;
2054 msg.rxFlush = 1;
2055 msg.rxForward = 0;
2056 msg.returnStatus = 0;
2057 msg.resetDataToggle = 0;
2058 msg.enablePort = 0;
2059 msg.disablePort = 1;
2060 }
2061 /* Sending intermediate configs */
2062 else {
Alan Coxdeb91682008-07-22 11:13:08 +01002063 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 msg._txOff = 0;
2065 msg.txFlush = 0;
2066 msg.txBreak = (p_priv->break_on);
2067 msg.rxOn = 0;
2068 msg.rxOff = 0;
2069 msg.rxFlush = 0;
2070 msg.rxForward = 0;
2071 msg.returnStatus = 0;
2072 msg.resetDataToggle = 0x0;
2073 msg.enablePort = 0;
2074 msg.disablePort = 0;
2075 }
2076
Alan Coxdeb91682008-07-22 11:13:08 +01002077 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 msg.setRts = 0xff;
2079 msg.rts = p_priv->rts_state;
2080
2081 msg.setDtr = 0xff;
2082 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002083
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085
Alan Coxdeb91682008-07-22 11:13:08 +01002086 /* if the device is a 49wg, we send control message on usb
2087 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002088
2089 if (d_details->product_id == keyspan_usa49wg_product_id) {
2090 dr = (void *)(s_priv->ctrl_buf);
2091 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
2092 dr->bRequest = 0xB0; /* 49wg control message */;
2093 dr->wValue = 0;
2094 dr->wIndex = 0;
2095 dr->wLength = cpu_to_le16(sizeof(msg));
2096
Alan Coxdeb91682008-07-22 11:13:08 +01002097 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07002098
Alan Coxdeb91682008-07-22 11:13:08 +01002099 usb_fill_control_urb(this_urb, serial->dev,
2100 usb_sndctrlpipe(serial->dev, 0),
2101 (unsigned char *)dr, s_priv->glocont_buf,
2102 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002103
2104 } else {
2105 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01002106
Lucy McCoy0ca12682007-05-18 12:10:41 -07002107 /* send the data out the device on control endpoint */
2108 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002109 }
Alan Coxdeb91682008-07-22 11:13:08 +01002110 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2111 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002112 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113#if 0
2114 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002115 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__,
2116 outcont_urb, this_urb->transfer_buffer_length,
2117 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 }
2119#endif
2120
Alan Coxa5b6f602008-04-08 17:16:06 +01002121 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122}
2123
2124static int keyspan_usa90_send_setup(struct usb_serial *serial,
2125 struct usb_serial_port *port,
2126 int reset_port)
2127{
Alan Coxdeb91682008-07-22 11:13:08 +01002128 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 struct keyspan_serial_private *s_priv;
2130 struct keyspan_port_private *p_priv;
2131 const struct keyspan_device_details *d_details;
2132 struct urb *this_urb;
2133 int err;
2134 u8 prescaler;
2135
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 s_priv = usb_get_serial_data(serial);
2137 p_priv = usb_get_serial_port_data(port);
2138 d_details = s_priv->device_details;
2139
2140 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002141 this_urb = p_priv->outcont_urb;
2142 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002143 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 return -1;
2145 }
2146
2147 /* Save reset port val for resend.
2148 Don't overwrite resend for open/close condition. */
2149 if ((reset_port + 1) > p_priv->resend_cont)
2150 p_priv->resend_cont = reset_port + 1;
2151 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002152 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002154 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 }
2156
Alan Coxdeb91682008-07-22 11:13:08 +01002157 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158
Alan Coxdeb91682008-07-22 11:13:08 +01002159 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 if (p_priv->old_baud != p_priv->baud) {
2161 p_priv->old_baud = p_priv->baud;
2162 msg.setClocking = 0x01;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002163 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2164 &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2165 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2166 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 p_priv->baud = 9600;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002168 d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2170 }
2171 msg.setRxMode = 1;
2172 msg.setTxMode = 1;
2173 }
2174
2175 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002176 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 msg.rxMode = RXMODE_DMA;
2178 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002179 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 msg.rxMode = RXMODE_BYHAND;
2181 msg.txMode = TXMODE_BYHAND;
2182 }
2183
Ben Minerds2b982ab2012-07-12 00:10:16 +10002184 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 switch (p_priv->cflag & CSIZE) {
2186 case CS5:
2187 msg.lcr |= USA_DATABITS_5;
2188 break;
2189 case CS6:
2190 msg.lcr |= USA_DATABITS_6;
2191 break;
2192 case CS7:
2193 msg.lcr |= USA_DATABITS_7;
2194 break;
2195 case CS8:
2196 msg.lcr |= USA_DATABITS_8;
2197 break;
2198 }
2199 if (p_priv->cflag & PARENB) {
2200 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002201 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002202 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 }
2204 if (p_priv->old_cflag != p_priv->cflag) {
2205 p_priv->old_cflag = p_priv->cflag;
2206 msg.setLcr = 0x01;
2207 }
2208
2209 if (p_priv->flow_control == flow_cts)
2210 msg.txFlowControl = TXFLOW_CTS;
2211 msg.setTxFlowControl = 0x01;
2212 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002213
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002215 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 msg.txAckSetting = 0;
2217 msg.xonChar = 17;
2218 msg.xoffChar = 19;
2219
Alan Coxdeb91682008-07-22 11:13:08 +01002220 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 if (reset_port == 1) {
2222 msg.portEnabled = 1;
2223 msg.rxFlush = 1;
2224 msg.txBreak = (p_priv->break_on);
2225 }
2226 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002227 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 /* Sending intermediate configs */
2230 else {
Alan Stern1f871582010-02-17 10:05:47 -05002231 msg.portEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 msg.txBreak = (p_priv->break_on);
2233 }
2234
Alan Coxdeb91682008-07-22 11:13:08 +01002235 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 msg.setRts = 0x01;
2237 msg.rts = p_priv->rts_state;
2238
2239 msg.setDtr = 0x01;
2240 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002241
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002243 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2244
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 /* send the data out the device on control endpoint */
2246 this_urb->transfer_buffer_length = sizeof(msg);
2247
Alan Coxdeb91682008-07-22 11:13:08 +01002248 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2249 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002250 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002251 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252}
2253
Lucy McCoy0ca12682007-05-18 12:10:41 -07002254static int keyspan_usa67_send_setup(struct usb_serial *serial,
2255 struct usb_serial_port *port,
2256 int reset_port)
2257{
2258 struct keyspan_usa67_portControlMessage msg;
2259 struct keyspan_serial_private *s_priv;
2260 struct keyspan_port_private *p_priv;
2261 const struct keyspan_device_details *d_details;
2262 struct urb *this_urb;
2263 int err, device_port;
2264
Lucy McCoy0ca12682007-05-18 12:10:41 -07002265 s_priv = usb_get_serial_data(serial);
2266 p_priv = usb_get_serial_port_data(port);
2267 d_details = s_priv->device_details;
2268
2269 this_urb = s_priv->glocont_urb;
2270
2271 /* Work out which port within the device is being setup */
2272 device_port = port->number - port->serial->minor;
2273
2274 /* Make sure we have an urb then send the message */
2275 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002276 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002277 port->number);
2278 return -1;
2279 }
2280
2281 /* Save reset port val for resend.
2282 Don't overwrite resend for open/close condition. */
2283 if ((reset_port + 1) > p_priv->resend_cont)
2284 p_priv->resend_cont = reset_port + 1;
2285 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002286 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002287 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002288 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002289 }
2290
2291 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2292
2293 msg.port = device_port;
2294
2295 /* Only set baud rate if it's changed */
2296 if (p_priv->old_baud != p_priv->baud) {
2297 p_priv->old_baud = p_priv->baud;
2298 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002299 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2300 &msg.baudHi, &msg.baudLo, &msg.prescaler,
2301 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2302 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2303 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002304 msg.baudLo = 0;
2305 msg.baudHi = 125; /* Values for 9600 baud */
2306 msg.prescaler = 10;
2307 }
2308 msg.setPrescaler = 0xff;
2309 }
2310
2311 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2312 switch (p_priv->cflag & CSIZE) {
2313 case CS5:
2314 msg.lcr |= USA_DATABITS_5;
2315 break;
2316 case CS6:
2317 msg.lcr |= USA_DATABITS_6;
2318 break;
2319 case CS7:
2320 msg.lcr |= USA_DATABITS_7;
2321 break;
2322 case CS8:
2323 msg.lcr |= USA_DATABITS_8;
2324 break;
2325 }
2326 if (p_priv->cflag & PARENB) {
2327 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002328 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002329 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002330 }
2331 msg.setLcr = 0xff;
2332
2333 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2334 msg.xonFlowControl = 0;
2335 msg.setFlowControl = 0xff;
2336 msg.forwardingLength = 16;
2337 msg.xonChar = 17;
2338 msg.xoffChar = 19;
2339
2340 if (reset_port == 1) {
2341 /* Opening port */
2342 msg._txOn = 1;
2343 msg._txOff = 0;
2344 msg.txFlush = 0;
2345 msg.txBreak = 0;
2346 msg.rxOn = 1;
2347 msg.rxOff = 0;
2348 msg.rxFlush = 1;
2349 msg.rxForward = 0;
2350 msg.returnStatus = 0;
2351 msg.resetDataToggle = 0xff;
2352 } else if (reset_port == 2) {
2353 /* Closing port */
2354 msg._txOn = 0;
2355 msg._txOff = 1;
2356 msg.txFlush = 0;
2357 msg.txBreak = 0;
2358 msg.rxOn = 0;
2359 msg.rxOff = 1;
2360 msg.rxFlush = 1;
2361 msg.rxForward = 0;
2362 msg.returnStatus = 0;
2363 msg.resetDataToggle = 0;
2364 } else {
2365 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002366 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002367 msg._txOff = 0;
2368 msg.txFlush = 0;
2369 msg.txBreak = (p_priv->break_on);
2370 msg.rxOn = 0;
2371 msg.rxOff = 0;
2372 msg.rxFlush = 0;
2373 msg.rxForward = 0;
2374 msg.returnStatus = 0;
2375 msg.resetDataToggle = 0x0;
2376 }
2377
2378 /* Do handshaking outputs */
2379 msg.setTxTriState_setRts = 0xff;
2380 msg.txTriState_rts = p_priv->rts_state;
2381
2382 msg.setHskoa_setDtr = 0xff;
2383 msg.hskoa_dtr = p_priv->dtr_state;
2384
2385 p_priv->resend_cont = 0;
2386
2387 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2388
2389 /* send the data out the device on control endpoint */
2390 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002391
2392 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2393 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002394 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002395 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002396}
2397
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2399{
2400 struct usb_serial *serial = port->serial;
2401 struct keyspan_serial_private *s_priv;
2402 const struct keyspan_device_details *d_details;
2403
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 s_priv = usb_get_serial_data(serial);
2405 d_details = s_priv->device_details;
2406
2407 switch (d_details->msg_format) {
2408 case msg_usa26:
2409 keyspan_usa26_send_setup(serial, port, reset_port);
2410 break;
2411 case msg_usa28:
2412 keyspan_usa28_send_setup(serial, port, reset_port);
2413 break;
2414 case msg_usa49:
2415 keyspan_usa49_send_setup(serial, port, reset_port);
2416 break;
2417 case msg_usa90:
2418 keyspan_usa90_send_setup(serial, port, reset_port);
2419 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002420 case msg_usa67:
2421 keyspan_usa67_send_setup(serial, port, reset_port);
2422 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 }
2424}
2425
2426
2427/* Gets called by the "real" driver (ie once firmware is loaded
2428 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002429static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430{
2431 int i, err;
2432 struct usb_serial_port *port;
2433 struct keyspan_serial_private *s_priv;
2434 struct keyspan_port_private *p_priv;
2435 const struct keyspan_device_details *d_details;
2436
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002438 if (d_details->product_id ==
2439 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 break;
2441 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002442 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2443 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 return 1;
2445 }
2446
2447 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002448 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 if (!s_priv) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002450 dev_dbg(&serial->dev->dev, "%s - kmalloc for keyspan_serial_private failed.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 return -ENOMEM;
2452 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453
2454 s_priv->device_details = d_details;
2455 usb_set_serial_data(serial, s_priv);
2456
2457 /* Now setup per port private data */
2458 for (i = 0; i < serial->num_ports; i++) {
2459 port = serial->port[i];
Alan Coxdeb91682008-07-22 11:13:08 +01002460 p_priv = kzalloc(sizeof(struct keyspan_port_private),
2461 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 if (!p_priv) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002463 dev_dbg(&port->dev, "%s - kmalloc for keyspan_port_private (%d) failed!.\n", __func__, i);
Alan Coxdeb91682008-07-22 11:13:08 +01002464 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 p_priv->device_details = d_details;
2467 usb_set_serial_port_data(port, p_priv);
2468 }
2469
2470 keyspan_setup_urbs(serial);
2471
Lucy McCoy0ca12682007-05-18 12:10:41 -07002472 if (s_priv->instat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002473 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2474 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002475 dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002476 }
2477 if (s_priv->indat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002478 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2479 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002480 dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 }
Alan Coxdeb91682008-07-22 11:13:08 +01002482
Alan Coxa5b6f602008-04-08 17:16:06 +01002483 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484}
2485
Alan Sternf9c99bb2009-06-02 11:53:55 -04002486static void keyspan_disconnect(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487{
2488 int i, j;
2489 struct usb_serial_port *port;
2490 struct keyspan_serial_private *s_priv;
2491 struct keyspan_port_private *p_priv;
2492
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 s_priv = usb_get_serial_data(serial);
2494
2495 /* Stop reading/writing urbs */
2496 stop_urb(s_priv->instat_urb);
2497 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002498 stop_urb(s_priv->indat_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 for (i = 0; i < serial->num_ports; ++i) {
2500 port = serial->port[i];
2501 p_priv = usb_get_serial_port_data(port);
2502 stop_urb(p_priv->inack_urb);
2503 stop_urb(p_priv->outcont_urb);
2504 for (j = 0; j < 2; j++) {
2505 stop_urb(p_priv->in_urbs[j]);
2506 stop_urb(p_priv->out_urbs[j]);
2507 }
2508 }
2509
2510 /* Now free them */
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002511 usb_free_urb(s_priv->instat_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002512 usb_free_urb(s_priv->indat_urb);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002513 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 for (i = 0; i < serial->num_ports; ++i) {
2515 port = serial->port[i];
2516 p_priv = usb_get_serial_port_data(port);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002517 usb_free_urb(p_priv->inack_urb);
2518 usb_free_urb(p_priv->outcont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 for (j = 0; j < 2; j++) {
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002520 usb_free_urb(p_priv->in_urbs[j]);
2521 usb_free_urb(p_priv->out_urbs[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 }
2523 }
Alan Sternf9c99bb2009-06-02 11:53:55 -04002524}
2525
2526static void keyspan_release(struct usb_serial *serial)
2527{
2528 int i;
2529 struct usb_serial_port *port;
2530 struct keyspan_serial_private *s_priv;
2531
Alan Sternf9c99bb2009-06-02 11:53:55 -04002532 s_priv = usb_get_serial_data(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 kfree(s_priv);
2535
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 /* Now free per port private data */
2537 for (i = 0; i < serial->num_ports; i++) {
2538 port = serial->port[i];
2539 kfree(usb_get_serial_port_data(port));
2540 }
2541}
2542
Alan Coxdeb91682008-07-22 11:13:08 +01002543MODULE_AUTHOR(DRIVER_AUTHOR);
2544MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545MODULE_LICENSE("GPL");
2546
David Woodhouse2971c572008-05-30 14:04:03 +03002547MODULE_FIRMWARE("keyspan/usa28.fw");
2548MODULE_FIRMWARE("keyspan/usa28x.fw");
2549MODULE_FIRMWARE("keyspan/usa28xa.fw");
2550MODULE_FIRMWARE("keyspan/usa28xb.fw");
2551MODULE_FIRMWARE("keyspan/usa19.fw");
2552MODULE_FIRMWARE("keyspan/usa19qi.fw");
2553MODULE_FIRMWARE("keyspan/mpr.fw");
2554MODULE_FIRMWARE("keyspan/usa19qw.fw");
2555MODULE_FIRMWARE("keyspan/usa18x.fw");
2556MODULE_FIRMWARE("keyspan/usa19w.fw");
2557MODULE_FIRMWARE("keyspan/usa49w.fw");
2558MODULE_FIRMWARE("keyspan/usa49wlc.fw");