blob: 4f25849d343e093545cc4e10768949e830856098 [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>
Rene Buergelcc183e22012-09-18 09:00:41 +020046#include <linux/usb/ezusb.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include "keyspan.h"
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049/*
50 * Version Information
51 */
Lucy McCoy0ca12682007-05-18 12:10:41 -070052#define DRIVER_VERSION "v1.1.5"
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
54#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
55
56#define INSTAT_BUFLEN 32
57#define GLOCONT_BUFLEN 64
Lucy McCoy0ca12682007-05-18 12:10:41 -070058#define INDAT49W_BUFLEN 512
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60 /* Per device and per port private data */
61struct keyspan_serial_private {
62 const struct keyspan_device_details *device_details;
63
64 struct urb *instat_urb;
65 char instat_buf[INSTAT_BUFLEN];
66
Alan Coxdeb91682008-07-22 11:13:08 +010067 /* added to support 49wg, where data from all 4 ports comes in
68 on 1 EP and high-speed supported */
Lucy McCoy0ca12682007-05-18 12:10:41 -070069 struct urb *indat_urb;
70 char indat_buf[INDAT49W_BUFLEN];
71
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 /* XXX this one probably will need a lock */
73 struct urb *glocont_urb;
74 char glocont_buf[GLOCONT_BUFLEN];
Alan Coxdeb91682008-07-22 11:13:08 +010075 char ctrl_buf[8]; /* for EP0 control message */
Linus Torvalds1da177e2005-04-16 15:20:36 -070076};
77
78struct keyspan_port_private {
79 /* Keep track of which input & output endpoints to use */
80 int in_flip;
81 int out_flip;
82
83 /* Keep duplicate of device details in each port
84 structure as well - simplifies some of the
85 callback functions etc. */
86 const struct keyspan_device_details *device_details;
87
88 /* Input endpoints and buffer for this port */
89 struct urb *in_urbs[2];
90 char in_buffer[2][64];
91 /* Output endpoints and buffer for this port */
92 struct urb *out_urbs[2];
93 char out_buffer[2][64];
94
95 /* Input ack endpoint */
96 struct urb *inack_urb;
97 char inack_buffer[1];
98
99 /* Output control endpoint */
100 struct urb *outcont_urb;
101 char outcont_buffer[64];
102
103 /* Settings for the port */
104 int baud;
105 int old_baud;
106 unsigned int cflag;
107 unsigned int old_cflag;
108 enum {flow_none, flow_cts, flow_xon} flow_control;
109 int rts_state; /* Handshaking pins (outputs) */
110 int dtr_state;
111 int cts_state; /* Handshaking pins (inputs) */
112 int dsr_state;
113 int dcd_state;
114 int ri_state;
115 int break_on;
116
117 unsigned long tx_start_time[2];
118 int resend_cont; /* need to resend control packet */
119};
120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121/* Include Keyspan message headers. All current Keyspan Adapters
Lucy McCoy0ca12682007-05-18 12:10:41 -0700122 make use of one of five message formats which are referred
Alan Coxdeb91682008-07-22 11:13:08 +0100123 to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and
124 within this driver. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125#include "keyspan_usa26msg.h"
126#include "keyspan_usa28msg.h"
127#include "keyspan_usa49msg.h"
128#include "keyspan_usa90msg.h"
Lucy McCoy0ca12682007-05-18 12:10:41 -0700129#include "keyspan_usa67msg.h"
Alan Coxdeb91682008-07-22 11:13:08 +0100130
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -0700132module_usb_serial_driver(serial_drivers, keyspan_ids_combined);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
Alan Cox95da3102008-07-22 11:09:07 +0100134static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
Alan Cox95da3102008-07-22 11:09:07 +0100136 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 struct keyspan_port_private *p_priv;
138
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 p_priv = usb_get_serial_port_data(port);
140
141 if (break_state == -1)
142 p_priv->break_on = 1;
143 else
144 p_priv->break_on = 0;
145
146 keyspan_send_setup(port, 0);
147}
148
149
Alan Coxdeb91682008-07-22 11:13:08 +0100150static void keyspan_set_termios(struct tty_struct *tty,
Alan Cox95da3102008-07-22 11:09:07 +0100151 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152{
153 int baud_rate, device_port;
154 struct keyspan_port_private *p_priv;
155 const struct keyspan_device_details *d_details;
156 unsigned int cflag;
157
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 p_priv = usb_get_serial_port_data(port);
159 d_details = p_priv->device_details;
Alan Cox74240b02007-10-18 01:24:20 -0700160 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 device_port = port->number - port->serial->minor;
162
163 /* Baud rate calculation takes baud rate as an integer
164 so other rates can be generated if desired. */
Alan Cox74240b02007-10-18 01:24:20 -0700165 baud_rate = tty_get_baud_rate(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100166 /* If no match or invalid, don't change */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700167 if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
169 /* FIXME - more to do here to ensure rate changes cleanly */
Alan Cox74240b02007-10-18 01:24:20 -0700170 /* FIXME - calcuate exact rate from divisor ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 p_priv->baud = baud_rate;
Alan Cox74240b02007-10-18 01:24:20 -0700172 } else
173 baud_rate = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
Alan Cox74240b02007-10-18 01:24:20 -0700175 tty_encode_baud_rate(tty, baud_rate, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 /* set CTS/RTS handshake etc. */
177 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +1000178 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Alan Cox74240b02007-10-18 01:24:20 -0700180 /* Mark/Space not supported */
181 tty->termios->c_cflag &= ~CMSPAR;
182
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 keyspan_send_setup(port, 0);
184}
185
Alan Cox60b33c12011-02-14 16:26:14 +0000186static int keyspan_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
Alan Cox95da3102008-07-22 11:09:07 +0100188 struct usb_serial_port *port = tty->driver_data;
189 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 unsigned int value;
Alan Coxdeb91682008-07-22 11:13:08 +0100191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
193 ((p_priv->dtr_state) ? TIOCM_DTR : 0) |
194 ((p_priv->cts_state) ? TIOCM_CTS : 0) |
195 ((p_priv->dsr_state) ? TIOCM_DSR : 0) |
196 ((p_priv->dcd_state) ? TIOCM_CAR : 0) |
Alan Coxdeb91682008-07-22 11:13:08 +0100197 ((p_priv->ri_state) ? TIOCM_RNG : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199 return value;
200}
201
Alan Cox20b9d172011-02-14 16:26:50 +0000202static int keyspan_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 unsigned int set, unsigned int clear)
204{
Alan Cox95da3102008-07-22 11:09:07 +0100205 struct usb_serial_port *port = tty->driver_data;
206 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100207
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 if (set & TIOCM_RTS)
209 p_priv->rts_state = 1;
210 if (set & TIOCM_DTR)
211 p_priv->dtr_state = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 if (clear & TIOCM_RTS)
213 p_priv->rts_state = 0;
214 if (clear & TIOCM_DTR)
215 p_priv->dtr_state = 0;
216 keyspan_send_setup(port, 0);
217 return 0;
218}
219
Alan Cox95da3102008-07-22 11:09:07 +0100220/* Write function is similar for the four protocols used
221 with only a minor change for usa90 (usa19hs) required */
222static int keyspan_write(struct tty_struct *tty,
223 struct usb_serial_port *port, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
225 struct keyspan_port_private *p_priv;
226 const struct keyspan_device_details *d_details;
227 int flip;
228 int left, todo;
229 struct urb *this_urb;
Alan Coxdeb91682008-07-22 11:13:08 +0100230 int err, maxDataLen, dataOffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
232 p_priv = usb_get_serial_port_data(port);
233 d_details = p_priv->device_details;
234
235 if (d_details->msg_format == msg_usa90) {
Alan Coxdeb91682008-07-22 11:13:08 +0100236 maxDataLen = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 dataOffset = 0;
238 } else {
239 maxDataLen = 63;
240 dataOffset = 1;
241 }
Alan Coxdeb91682008-07-22 11:13:08 +0100242
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700243 dev_dbg(&port->dev, "%s - for port %d (%d chars), flip=%d\n",
244 __func__, port->number, count, p_priv->out_flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246 for (left = count; left > 0; left -= todo) {
247 todo = left;
248 if (todo > maxDataLen)
249 todo = maxDataLen;
250
251 flip = p_priv->out_flip;
Alan Coxdeb91682008-07-22 11:13:08 +0100252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 /* Check we have a valid urb/endpoint before we use it... */
Alan Coxdeb91682008-07-22 11:13:08 +0100254 this_urb = p_priv->out_urbs[flip];
255 if (this_urb == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 /* no bulk out, so return 0 bytes written */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700257 dev_dbg(&port->dev, "%s - no output urb :(\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 return count;
259 }
260
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700261 dev_dbg(&port->dev, "%s - endpoint %d flip %d\n",
Alan Coxdeb91682008-07-22 11:13:08 +0100262 __func__, usb_pipeendpoint(this_urb->pipe), flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +0100265 if (time_before(jiffies,
266 p_priv->tx_start_time[flip] + 10 * HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 usb_unlink_urb(this_urb);
269 break;
270 }
271
Alan Coxdeb91682008-07-22 11:13:08 +0100272 /* First byte in buffer is "last flag" (except for usa19hx)
273 - unused so for now so set to zero */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 ((char *)this_urb->transfer_buffer)[0] = 0;
275
Alan Coxdeb91682008-07-22 11:13:08 +0100276 memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 buf += todo;
278
279 /* send the data out the bulk port */
280 this_urb->transfer_buffer_length = todo + dataOffset;
281
Alan Coxdeb91682008-07-22 11:13:08 +0100282 err = usb_submit_urb(this_urb, GFP_ATOMIC);
283 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700284 dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 p_priv->tx_start_time[flip] = jiffies;
286
287 /* Flip for next time if usa26 or usa28 interface
288 (not used on usa49) */
289 p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
290 }
291
292 return count - left;
293}
294
David Howells7d12e782006-10-05 14:55:46 +0100295static void usa26_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
297 int i, err;
298 int endpoint;
299 struct usb_serial_port *port;
300 struct tty_struct *tty;
301 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700302 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 endpoint = usb_pipeendpoint(urb->pipe);
305
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700306 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700307 dev_dbg(&urb->dev->dev,"%s - nonzero status: %x on endpoint %d.\n",
308 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 return;
310 }
311
Ming Leicdc97792008-02-24 18:41:47 +0800312 port = urb->context;
Alan Cox4a90f092008-10-13 10:39:46 +0100313 tty = tty_port_tty_get(&port->port);
Alan Coxa5569a52008-01-21 17:18:24 -0800314 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 /* 0x80 bit is error flag */
316 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100317 /* no errors on individual bytes, only
318 possible overrun err */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100320 err = TTY_OVERRUN;
321 else
322 err = 0;
323 for (i = 1; i < urb->actual_length ; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 tty_insert_flip_char(tty, data[i], err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 } else {
326 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700327 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 for (i = 0; i + 1 < urb->actual_length; i += 2) {
329 int stat = data[i], flag = 0;
330 if (stat & RXERROR_OVERRUN)
331 flag |= TTY_OVERRUN;
332 if (stat & RXERROR_FRAMING)
333 flag |= TTY_FRAME;
334 if (stat & RXERROR_PARITY)
335 flag |= TTY_PARITY;
336 /* XXX should handle break (0x10) */
337 tty_insert_flip_char(tty, data[i+1], flag);
338 }
339 }
340 tty_flip_buffer_push(tty);
341 }
Alan Cox4a90f092008-10-13 10:39:46 +0100342 tty_kref_put(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100343
344 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500345 err = usb_submit_urb(urb, GFP_ATOMIC);
346 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700347 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348}
349
Alan Coxdeb91682008-07-22 11:13:08 +0100350/* Outdat handling is common for all devices */
David Howells7d12e782006-10-05 14:55:46 +0100351static void usa2x_outdat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
353 struct usb_serial_port *port;
354 struct keyspan_port_private *p_priv;
355
Ming Leicdc97792008-02-24 18:41:47 +0800356 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 p_priv = usb_get_serial_port_data(port);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700358 dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Alan Stern1f871582010-02-17 10:05:47 -0500360 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361}
362
David Howells7d12e782006-10-05 14:55:46 +0100363static void usa26_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365}
366
David Howells7d12e782006-10-05 14:55:46 +0100367static void usa26_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
369 struct usb_serial_port *port;
370 struct keyspan_port_private *p_priv;
371
Ming Leicdc97792008-02-24 18:41:47 +0800372 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 p_priv = usb_get_serial_port_data(port);
374
375 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700376 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100377 keyspan_usa26_send_setup(port->serial, port,
378 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 }
380}
381
David Howells7d12e782006-10-05 14:55:46 +0100382static void usa26_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383{
384 unsigned char *data = urb->transfer_buffer;
385 struct keyspan_usa26_portStatusMessage *msg;
386 struct usb_serial *serial;
387 struct usb_serial_port *port;
388 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100389 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700391 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Ming Leicdc97792008-02-24 18:41:47 +0800393 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700395 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700396 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 return;
398 }
399 if (urb->actual_length != 9) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700400 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 goto exit;
402 }
403
404 msg = (struct keyspan_usa26_portStatusMessage *)data;
405
406#if 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700407 dev_dbg(&urb->dev->dev,
408 "%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
409 __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr,
410 msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled,
411 msg->controlResponse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412#endif
413
414 /* Now do something useful with the data */
415
416
Alan Coxdeb91682008-07-22 11:13:08 +0100417 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700419 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 goto exit;
421 }
422 port = serial->port[msg->port];
423 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 /* Update handshaking pin state information */
426 old_dcd_state = p_priv->dcd_state;
427 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
428 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
429 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
430 p_priv->ri_state = ((msg->ri) ? 1 : 0);
431
Alan Cox4a90f092008-10-13 10:39:46 +0100432 if (old_dcd_state != p_priv->dcd_state) {
433 tty = tty_port_tty_get(&port->port);
434 if (tty && !C_CLOCAL(tty))
435 tty_hangup(tty);
436 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 }
Alan Coxdeb91682008-07-22 11:13:08 +0100438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100440 err = usb_submit_urb(urb, GFP_ATOMIC);
441 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700442 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443exit: ;
444}
445
David Howells7d12e782006-10-05 14:55:46 +0100446static void usa26_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448}
449
450
David Howells7d12e782006-10-05 14:55:46 +0100451static void usa28_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
Alan Coxf035a8a2008-07-22 11:13:32 +0100453 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 struct usb_serial_port *port;
455 struct tty_struct *tty;
456 unsigned char *data;
457 struct keyspan_port_private *p_priv;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700458 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
Ming Leicdc97792008-02-24 18:41:47 +0800460 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 p_priv = usb_get_serial_port_data(port);
462 data = urb->transfer_buffer;
463
464 if (urb != p_priv->in_urbs[p_priv->in_flip])
465 return;
466
467 do {
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700468 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700469 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
470 __func__, status, usb_pipeendpoint(urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 return;
472 }
473
Ming Leicdc97792008-02-24 18:41:47 +0800474 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 p_priv = usb_get_serial_port_data(port);
476 data = urb->transfer_buffer;
477
Ben Minerds40adac82012-07-12 00:10:17 +1000478 tty = tty_port_tty_get(&port->port);
Alan Cox4a90f092008-10-13 10:39:46 +0100479 if (tty && urb->actual_length) {
Alan Coxf035a8a2008-07-22 11:13:32 +0100480 tty_insert_flip_string(tty, data, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 tty_flip_buffer_push(tty);
482 }
Alan Cox4a90f092008-10-13 10:39:46 +0100483 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
485 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500486 err = usb_submit_urb(urb, GFP_ATOMIC);
487 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700488 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
Alan Stern1f871582010-02-17 10:05:47 -0500489 __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 p_priv->in_flip ^= 1;
491
492 urb = p_priv->in_urbs[p_priv->in_flip];
493 } while (urb->status != -EINPROGRESS);
494}
495
David Howells7d12e782006-10-05 14:55:46 +0100496static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498}
499
David Howells7d12e782006-10-05 14:55:46 +0100500static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
502 struct usb_serial_port *port;
503 struct keyspan_port_private *p_priv;
504
Ming Leicdc97792008-02-24 18:41:47 +0800505 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 p_priv = usb_get_serial_port_data(port);
507
508 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700509 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100510 keyspan_usa28_send_setup(port->serial, port,
511 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 }
513}
514
David Howells7d12e782006-10-05 14:55:46 +0100515static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
517 int err;
518 unsigned char *data = urb->transfer_buffer;
519 struct keyspan_usa28_portStatusMessage *msg;
520 struct usb_serial *serial;
521 struct usb_serial_port *port;
522 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100523 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700525 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Ming Leicdc97792008-02-24 18:41:47 +0800527 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700529 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700530 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return;
532 }
533
534 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700535 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 goto exit;
537 }
538
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700539 /*
540 dev_dbg(&urb->dev->dev,
541 "%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__,
542 data[0], data[1], data[2], data[3], data[4], data[5],
543 data[6], data[7], data[8], data[9], data[10], data[11]);
544 */
Alan Coxdeb91682008-07-22 11:13:08 +0100545
546 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 msg = (struct keyspan_usa28_portStatusMessage *)data;
548
Alan Coxdeb91682008-07-22 11:13:08 +0100549 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700551 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 goto exit;
553 }
554 port = serial->port[msg->port];
555 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100556
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 /* Update handshaking pin state information */
558 old_dcd_state = p_priv->dcd_state;
559 p_priv->cts_state = ((msg->cts) ? 1 : 0);
560 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
561 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
562 p_priv->ri_state = ((msg->ri) ? 1 : 0);
563
Ben Minerdsddc04ae2012-07-12 00:10:18 +1000564 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
Alan Cox4a90f092008-10-13 10:39:46 +0100565 tty = tty_port_tty_get(&port->port);
Ben Minerds878b5fd2012-07-12 00:10:19 +1000566 if (tty && !C_CLOCAL(tty))
Alan Cox4a90f092008-10-13 10:39:46 +0100567 tty_hangup(tty);
568 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 }
570
571 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100572 err = usb_submit_urb(urb, GFP_ATOMIC);
573 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700574 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575exit: ;
576}
577
David Howells7d12e782006-10-05 14:55:46 +0100578static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
582
David Howells7d12e782006-10-05 14:55:46 +0100583static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
585 struct usb_serial *serial;
586 struct usb_serial_port *port;
587 struct keyspan_port_private *p_priv;
588 int i;
589
Ming Leicdc97792008-02-24 18:41:47 +0800590 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 for (i = 0; i < serial->num_ports; ++i) {
592 port = serial->port[i];
593 p_priv = usb_get_serial_port_data(port);
594
595 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700596 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100597 keyspan_usa49_send_setup(serial, port,
598 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 break;
600 }
601 }
602}
603
604 /* This is actually called glostat in the Keyspan
605 doco */
David Howells7d12e782006-10-05 14:55:46 +0100606static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
608 int err;
609 unsigned char *data = urb->transfer_buffer;
610 struct keyspan_usa49_portStatusMessage *msg;
611 struct usb_serial *serial;
612 struct usb_serial_port *port;
613 struct keyspan_port_private *p_priv;
614 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700615 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
Ming Leicdc97792008-02-24 18:41:47 +0800617 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700619 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700620 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return;
622 }
623
Alan Coxdeb91682008-07-22 11:13:08 +0100624 if (urb->actual_length !=
625 sizeof(struct keyspan_usa49_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700626 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 goto exit;
628 }
629
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700630 /*
631 dev_dbg(&urb->dev->dev, "%s: %x %x %x %x %x %x %x %x %x %x %x",
632 __func__, data[0], data[1], data[2], data[3], data[4],
633 data[5], data[6], data[7], data[8], data[9], data[10]);
634 */
Alan Coxdeb91682008-07-22 11:13:08 +0100635
636 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 msg = (struct keyspan_usa49_portStatusMessage *)data;
638
Alan Coxdeb91682008-07-22 11:13:08 +0100639 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 if (msg->portNumber >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700641 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
642 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 goto exit;
644 }
645 port = serial->port[msg->portNumber];
646 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 /* Update handshaking pin state information */
649 old_dcd_state = p_priv->dcd_state;
650 p_priv->cts_state = ((msg->cts) ? 1 : 0);
651 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
652 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
653 p_priv->ri_state = ((msg->ri) ? 1 : 0);
654
Alan Cox4a90f092008-10-13 10:39:46 +0100655 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
656 struct tty_struct *tty = tty_port_tty_get(&port->port);
657 if (tty && !C_CLOCAL(tty))
658 tty_hangup(tty);
659 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 }
661
Alan Coxdeb91682008-07-22 11:13:08 +0100662 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100663 err = usb_submit_urb(urb, GFP_ATOMIC);
664 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700665 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666exit: ;
667}
668
David Howells7d12e782006-10-05 14:55:46 +0100669static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671}
672
David Howells7d12e782006-10-05 14:55:46 +0100673static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674{
675 int i, err;
676 int endpoint;
677 struct usb_serial_port *port;
678 struct tty_struct *tty;
679 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700680 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 endpoint = usb_pipeendpoint(urb->pipe);
683
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700684 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700685 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
686 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 return;
688 }
689
Ming Leicdc97792008-02-24 18:41:47 +0800690 port = urb->context;
Alan Cox4a90f092008-10-13 10:39:46 +0100691 tty = tty_port_tty_get(&port->port);
Alan Cox3004e532008-01-03 16:59:04 +0000692 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 /* 0x80 bit is error flag */
694 if ((data[0] & 0x80) == 0) {
695 /* no error on any byte */
Alan Coxf035a8a2008-07-22 11:13:32 +0100696 tty_insert_flip_string(tty, data + 1,
697 urb->actual_length - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 } else {
699 /* some bytes had errors, every byte has status */
700 for (i = 0; i + 1 < urb->actual_length; i += 2) {
701 int stat = data[i], flag = 0;
702 if (stat & RXERROR_OVERRUN)
703 flag |= TTY_OVERRUN;
704 if (stat & RXERROR_FRAMING)
705 flag |= TTY_FRAME;
706 if (stat & RXERROR_PARITY)
707 flag |= TTY_PARITY;
708 /* XXX should handle break (0x10) */
709 tty_insert_flip_char(tty, data[i+1], flag);
710 }
711 }
712 tty_flip_buffer_push(tty);
713 }
Alan Cox4a90f092008-10-13 10:39:46 +0100714 tty_kref_put(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100715
716 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500717 err = usb_submit_urb(urb, GFP_ATOMIC);
718 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700719 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720}
721
Lucy McCoy0ca12682007-05-18 12:10:41 -0700722static void usa49wg_indat_callback(struct urb *urb)
723{
724 int i, len, x, err;
725 struct usb_serial *serial;
726 struct usb_serial_port *port;
727 struct tty_struct *tty;
728 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700729 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700730
Lucy McCoy0ca12682007-05-18 12:10:41 -0700731 serial = urb->context;
732
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700733 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700734 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700735 return;
736 }
737
738 /* inbound data is in the form P#, len, status, data */
739 i = 0;
740 len = 0;
741
742 if (urb->actual_length) {
743 while (i < urb->actual_length) {
744
745 /* Check port number from message*/
746 if (data[i] >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700747 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800748 __func__, data[i]);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700749 return;
750 }
751 port = serial->port[data[i++]];
Alan Cox4a90f092008-10-13 10:39:46 +0100752 tty = tty_port_tty_get(&port->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700753 len = data[i++];
754
755 /* 0x80 bit is error flag */
756 if ((data[i] & 0x80) == 0) {
757 /* no error on any byte */
758 i++;
759 for (x = 1; x < len ; ++x)
Alan Stern1f871582010-02-17 10:05:47 -0500760 tty_insert_flip_char(tty, data[i++], 0);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700761 } else {
762 /*
763 * some bytes had errors, every byte has status
764 */
765 for (x = 0; x + 1 < len; x += 2) {
766 int stat = data[i], flag = 0;
767 if (stat & RXERROR_OVERRUN)
768 flag |= TTY_OVERRUN;
769 if (stat & RXERROR_FRAMING)
770 flag |= TTY_FRAME;
771 if (stat & RXERROR_PARITY)
772 flag |= TTY_PARITY;
773 /* XXX should handle break (0x10) */
Alan Stern1f871582010-02-17 10:05:47 -0500774 tty_insert_flip_char(tty,
Lucy McCoy0ca12682007-05-18 12:10:41 -0700775 data[i+1], flag);
776 i += 2;
777 }
778 }
Alan Stern1f871582010-02-17 10:05:47 -0500779 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100780 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700781 }
782 }
783
784 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700785 err = usb_submit_urb(urb, GFP_ATOMIC);
786 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700787 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700788}
789
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700791static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793}
794
Lucy McCoy0ca12682007-05-18 12:10:41 -0700795static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
797 int i, err;
798 int endpoint;
799 struct usb_serial_port *port;
800 struct keyspan_port_private *p_priv;
801 struct tty_struct *tty;
802 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700803 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 endpoint = usb_pipeendpoint(urb->pipe);
806
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700807 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700808 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800809 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return;
811 }
812
Ming Leicdc97792008-02-24 18:41:47 +0800813 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 p_priv = usb_get_serial_port_data(port);
815
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 if (urb->actual_length) {
Alan Cox4a90f092008-10-13 10:39:46 +0100817 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100819 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Alan Coxf035a8a2008-07-22 11:13:32 +0100821 if (p_priv->baud > 57600)
822 tty_insert_flip_string(tty, data, urb->actual_length);
823 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 /* 0x80 bit is error flag */
825 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100826 /* no errors on individual bytes, only
827 possible overrun err*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100829 err = TTY_OVERRUN;
830 else
831 err = 0;
832 for (i = 1; i < urb->actual_length ; ++i)
833 tty_insert_flip_char(tty, data[i],
834 err);
835 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700837 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 for (i = 0; i + 1 < urb->actual_length; i += 2) {
839 int stat = data[i], flag = 0;
840 if (stat & RXERROR_OVERRUN)
841 flag |= TTY_OVERRUN;
842 if (stat & RXERROR_FRAMING)
843 flag |= TTY_FRAME;
844 if (stat & RXERROR_PARITY)
845 flag |= TTY_PARITY;
846 /* XXX should handle break (0x10) */
Alan Coxdeb91682008-07-22 11:13:08 +0100847 tty_insert_flip_char(tty, data[i+1],
848 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 }
850 }
851 }
852 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100853 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
Alan Coxdeb91682008-07-22 11:13:08 +0100855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500857 err = usb_submit_urb(urb, GFP_ATOMIC);
858 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700859 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
862
David Howells7d12e782006-10-05 14:55:46 +0100863static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864{
865 unsigned char *data = urb->transfer_buffer;
866 struct keyspan_usa90_portStatusMessage *msg;
867 struct usb_serial *serial;
868 struct usb_serial_port *port;
869 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100870 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700872 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Ming Leicdc97792008-02-24 18:41:47 +0800874 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700876 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700877 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 return;
879 }
880 if (urb->actual_length < 14) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700881 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 goto exit;
883 }
884
885 msg = (struct keyspan_usa90_portStatusMessage *)data;
886
887 /* Now do something useful with the data */
888
889 port = serial->port[0];
890 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100891
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 /* Update handshaking pin state information */
893 old_dcd_state = p_priv->dcd_state;
894 p_priv->cts_state = ((msg->cts) ? 1 : 0);
895 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
896 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
897 p_priv->ri_state = ((msg->ri) ? 1 : 0);
898
Alan Cox4a90f092008-10-13 10:39:46 +0100899 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
900 tty = tty_port_tty_get(&port->port);
901 if (tty && !C_CLOCAL(tty))
902 tty_hangup(tty);
903 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 }
Alan Coxdeb91682008-07-22 11:13:08 +0100905
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100907 err = usb_submit_urb(urb, GFP_ATOMIC);
908 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700909 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910exit:
911 ;
912}
913
David Howells7d12e782006-10-05 14:55:46 +0100914static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915{
916 struct usb_serial_port *port;
917 struct keyspan_port_private *p_priv;
918
Ming Leicdc97792008-02-24 18:41:47 +0800919 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 p_priv = usb_get_serial_port_data(port);
921
922 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700923 dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100924 keyspan_usa90_send_setup(port->serial, port,
925 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 }
927}
928
Lucy McCoy0ca12682007-05-18 12:10:41 -0700929/* Status messages from the 28xg */
930static void usa67_instat_callback(struct urb *urb)
931{
932 int err;
933 unsigned char *data = urb->transfer_buffer;
934 struct keyspan_usa67_portStatusMessage *msg;
935 struct usb_serial *serial;
936 struct usb_serial_port *port;
937 struct keyspan_port_private *p_priv;
938 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700939 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700940
Lucy McCoy0ca12682007-05-18 12:10:41 -0700941 serial = urb->context;
942
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700943 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700944 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700945 return;
946 }
947
Alan Coxdeb91682008-07-22 11:13:08 +0100948 if (urb->actual_length !=
949 sizeof(struct keyspan_usa67_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700950 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700951 return;
952 }
953
954
955 /* Now do something useful with the data */
956 msg = (struct keyspan_usa67_portStatusMessage *)data;
957
958 /* Check port number from message and retrieve private data */
959 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700960 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700961 return;
962 }
963
964 port = serial->port[msg->port];
965 p_priv = usb_get_serial_port_data(port);
966
967 /* Update handshaking pin state information */
968 old_dcd_state = p_priv->dcd_state;
969 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
970 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
971
Alan Cox4a90f092008-10-13 10:39:46 +0100972 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
973 struct tty_struct *tty = tty_port_tty_get(&port->port);
974 if (tty && !C_CLOCAL(tty))
975 tty_hangup(tty);
976 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700977 }
978
979 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700980 err = usb_submit_urb(urb, GFP_ATOMIC);
981 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700982 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700983}
984
985static void usa67_glocont_callback(struct urb *urb)
986{
987 struct usb_serial *serial;
988 struct usb_serial_port *port;
989 struct keyspan_port_private *p_priv;
990 int i;
991
Lucy McCoy0ca12682007-05-18 12:10:41 -0700992 serial = urb->context;
993 for (i = 0; i < serial->num_ports; ++i) {
994 port = serial->port[i];
995 p_priv = usb_get_serial_port_data(port);
996
997 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700998 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700999 keyspan_usa67_send_setup(serial, port,
1000 p_priv->resend_cont - 1);
1001 break;
1002 }
1003 }
1004}
1005
Alan Cox95da3102008-07-22 11:09:07 +01001006static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007{
Alan Cox95da3102008-07-22 11:09:07 +01001008 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 struct keyspan_port_private *p_priv;
1010 const struct keyspan_device_details *d_details;
1011 int flip;
1012 int data_len;
1013 struct urb *this_urb;
1014
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 p_priv = usb_get_serial_port_data(port);
1016 d_details = p_priv->device_details;
1017
Alan Coxa5b6f602008-04-08 17:16:06 +01001018 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +01001020 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 else
1022 data_len = 63;
1023
1024 flip = p_priv->out_flip;
1025
1026 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +01001027 this_urb = p_priv->out_urbs[flip];
1028 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001030 return data_len;
1031 flip = (flip + 1) & d_details->outdat_endp_flip;
1032 this_urb = p_priv->out_urbs[flip];
1033 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001035 return data_len;
1036 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 }
Alan Coxa5b6f602008-04-08 17:16:06 +01001038 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039}
1040
1041
Alan Coxa509a7e2009-09-19 13:13:26 -07001042static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001044 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 const struct keyspan_device_details *d_details;
1046 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001047 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001049 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 p_priv = usb_get_serial_port_data(port);
1052 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001053
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 /* Set some sane defaults */
1055 p_priv->rts_state = 1;
1056 p_priv->dtr_state = 1;
1057 p_priv->baud = 9600;
1058
1059 /* force baud and lcr to be set on open */
1060 p_priv->old_baud = 0;
1061 p_priv->old_cflag = 0;
1062
1063 p_priv->out_flip = 0;
1064 p_priv->in_flip = 0;
1065
1066 /* Reset low level data toggle and start reading from endpoints */
1067 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001068 urb = p_priv->in_urbs[i];
1069 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Alan Coxdeb91682008-07-22 11:13:08 +01001072 /* make sure endpoint data toggle is synchronized
1073 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001075 err = usb_submit_urb(urb, GFP_KERNEL);
1076 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001077 dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 }
1079
1080 /* Reset low level data toggle on out endpoints */
1081 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001082 urb = p_priv->out_urbs[i];
1083 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 continue;
Alan Coxdeb91682008-07-22 11:13:08 +01001085 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1086 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 }
1088
Andrew Mortonf78ba152007-11-28 16:21:54 -08001089 /* get the terminal config for the setup message now so we don't
1090 * need to send 2 of them */
1091
Andrew Mortonf78ba152007-11-28 16:21:54 -08001092 device_port = port->number - port->serial->minor;
Alan Cox95da3102008-07-22 11:09:07 +01001093 if (tty) {
1094 cflag = tty->termios->c_cflag;
1095 /* Baud rate calculation takes baud rate as an integer
1096 so other rates can be generated if desired. */
1097 baud_rate = tty_get_baud_rate(tty);
1098 /* If no match or invalid, leave as default */
1099 if (baud_rate >= 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001100 && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Alan Cox95da3102008-07-22 11:09:07 +01001101 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1102 p_priv->baud = baud_rate;
1103 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001104 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001105 /* set CTS/RTS handshake etc. */
1106 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +10001107 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001108
1109 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001110 /* mdelay(100); */
1111 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001112
Alan Coxa5b6f602008-04-08 17:16:06 +01001113 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114}
1115
1116static inline void stop_urb(struct urb *urb)
1117{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001118 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120}
1121
Alan Cox335f8512009-06-11 12:26:29 +01001122static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1123{
1124 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1125
1126 p_priv->rts_state = on;
1127 p_priv->dtr_state = on;
1128 keyspan_send_setup(port, 0);
1129}
1130
1131static void keyspan_close(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132{
1133 int i;
1134 struct usb_serial *serial = port->serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 struct keyspan_port_private *p_priv;
1136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 p_priv->rts_state = 0;
1140 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001141
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 if (serial->dev) {
1143 keyspan_send_setup(port, 2);
1144 /* pilot-xfer seems to work best with this delay */
1145 mdelay(100);
Alan Coxdeb91682008-07-22 11:13:08 +01001146 /* keyspan_set_termios(port, NULL); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
1148
1149 /*while (p_priv->outcont_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001150 dev_dbg(&port->dev, "%s - urb in progress\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 }*/
1152
1153 p_priv->out_flip = 0;
1154 p_priv->in_flip = 0;
1155
1156 if (serial->dev) {
1157 /* Stop reading/writing urbs */
1158 stop_urb(p_priv->inack_urb);
1159 /* stop_urb(p_priv->outcont_urb); */
1160 for (i = 0; i < 2; i++) {
1161 stop_urb(p_priv->in_urbs[i]);
1162 stop_urb(p_priv->out_urbs[i]);
1163 }
1164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165}
1166
Alan Coxdeb91682008-07-22 11:13:08 +01001167/* download the firmware to a pre-renumeration device */
1168static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169{
1170 int response;
David Woodhouse2971c572008-05-30 14:04:03 +03001171 const struct ihex_binrec *record;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 char *fw_name;
David Woodhouse2971c572008-05-30 14:04:03 +03001173 const struct firmware *fw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001175 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
1176 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1177 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001178
1179 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1180 != 0x8000) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001181 dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n");
Alan Coxdeb91682008-07-22 11:13:08 +01001182 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 }
1184
1185 /* Select firmware image on the basis of idProduct */
1186 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1187 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001188 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 break;
1190
1191 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001192 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 break;
1194
1195 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001196 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 break;
1198
1199 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001200 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 break;
1202
1203 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001204 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001208 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001210
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001212 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 break;
1214
1215 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001216 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001218
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001220 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001224 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001228 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 break;
1230
1231 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001232 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 break;
1234
1235 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001236 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1237 le16_to_cpu(serial->dev->descriptor.idProduct));
1238 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 }
1240
David Woodhouse2971c572008-05-30 14:04:03 +03001241 if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 dev_err(&serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name);
Ben Minerdsf9943c22012-07-12 00:10:20 +10001243 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 }
1245
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001246 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
1248 /* download the firmware image */
Rene Buergelcc183e22012-09-18 09:00:41 +02001249 response = ezusb_fx1_set_reset(serial->dev, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
David Woodhouse2971c572008-05-30 14:04:03 +03001251 record = (const struct ihex_binrec *)fw->data;
1252
1253 while (record) {
Rene Buergel99495c72012-09-13 22:14:38 +02001254 response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 (unsigned char *)record->data,
David Woodhouse2971c572008-05-30 14:04:03 +03001256 be16_to_cpu(record->len), 0xa0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 if (response < 0) {
Alan Coxdeb91682008-07-22 11:13:08 +01001258 dev_err(&serial->dev->dev, "ezusb_writememory failed for Keyspan firmware (%d %04X %p %d)\n",
David Woodhouse2971c572008-05-30 14:04:03 +03001259 response, be32_to_cpu(record->addr),
1260 record->data, be16_to_cpu(record->len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 break;
1262 }
David Woodhouse2971c572008-05-30 14:04:03 +03001263 record = ihex_next_binrec(record);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 }
David Woodhouse2971c572008-05-30 14:04:03 +03001265 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 /* bring device out of reset. Renumeration will occur in a
1267 moment and the new device will bind to the real driver */
Rene Buergelcc183e22012-09-18 09:00:41 +02001268 response = ezusb_fx1_set_reset(serial->dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001271 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272}
1273
1274/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001275static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1276 int endpoint)
1277{
1278 struct usb_host_interface *iface_desc;
1279 struct usb_endpoint_descriptor *ep;
1280 int i;
1281
1282 iface_desc = serial->interface->cur_altsetting;
1283 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1284 ep = &iface_desc->endpoint[i].desc;
1285 if (ep->bEndpointAddress == endpoint)
1286 return ep;
1287 }
1288 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1289 "endpoint %x\n", endpoint);
1290 return NULL;
1291}
1292
Alan Coxdeb91682008-07-22 11:13:08 +01001293static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001295 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296{
1297 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001298 struct usb_endpoint_descriptor const *ep_desc;
1299 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
1301 if (endpoint == -1)
1302 return NULL; /* endpoint not needed */
1303
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001304 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
1306 if (urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001307 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d failed.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 return NULL;
1309 }
1310
Lucy McCoy0ca12682007-05-18 12:10:41 -07001311 if (endpoint == 0) {
1312 /* control EP filled in when used */
1313 return urb;
1314 }
1315
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001316 ep_desc = find_ep(serial, endpoint);
1317 if (!ep_desc) {
1318 /* leak the urb, something's wrong and the callers don't care */
1319 return urb;
1320 }
1321 if (usb_endpoint_xfer_int(ep_desc)) {
1322 ep_type_name = "INT";
1323 usb_fill_int_urb(urb, serial->dev,
1324 usb_sndintpipe(serial->dev, endpoint) | dir,
1325 buf, len, callback, ctx,
1326 ep_desc->bInterval);
1327 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1328 ep_type_name = "BULK";
1329 usb_fill_bulk_urb(urb, serial->dev,
1330 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1331 buf, len, callback, ctx);
1332 } else {
1333 dev_warn(&serial->interface->dev,
1334 "unsupported endpoint type %x\n",
Julia Lawall2e0fe702008-12-29 11:22:14 +01001335 usb_endpoint_type(ep_desc));
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001336 usb_free_urb(urb);
1337 return NULL;
1338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001340 dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001341 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 return urb;
1343}
1344
1345static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001346 void (*instat_callback)(struct urb *);
1347 void (*glocont_callback)(struct urb *);
1348 void (*indat_callback)(struct urb *);
1349 void (*outdat_callback)(struct urb *);
1350 void (*inack_callback)(struct urb *);
1351 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352} keyspan_callbacks[] = {
1353 {
1354 /* msg_usa26 callbacks */
1355 .instat_callback = usa26_instat_callback,
1356 .glocont_callback = usa26_glocont_callback,
1357 .indat_callback = usa26_indat_callback,
1358 .outdat_callback = usa2x_outdat_callback,
1359 .inack_callback = usa26_inack_callback,
1360 .outcont_callback = usa26_outcont_callback,
1361 }, {
1362 /* msg_usa28 callbacks */
1363 .instat_callback = usa28_instat_callback,
1364 .glocont_callback = usa28_glocont_callback,
1365 .indat_callback = usa28_indat_callback,
1366 .outdat_callback = usa2x_outdat_callback,
1367 .inack_callback = usa28_inack_callback,
1368 .outcont_callback = usa28_outcont_callback,
1369 }, {
1370 /* msg_usa49 callbacks */
1371 .instat_callback = usa49_instat_callback,
1372 .glocont_callback = usa49_glocont_callback,
1373 .indat_callback = usa49_indat_callback,
1374 .outdat_callback = usa2x_outdat_callback,
1375 .inack_callback = usa49_inack_callback,
1376 .outcont_callback = usa49_outcont_callback,
1377 }, {
1378 /* msg_usa90 callbacks */
1379 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001380 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 .indat_callback = usa90_indat_callback,
1382 .outdat_callback = usa2x_outdat_callback,
1383 .inack_callback = usa28_inack_callback,
1384 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001385 }, {
1386 /* msg_usa67 callbacks */
1387 .instat_callback = usa67_instat_callback,
1388 .glocont_callback = usa67_glocont_callback,
1389 .indat_callback = usa26_indat_callback,
1390 .outdat_callback = usa2x_outdat_callback,
1391 .inack_callback = usa26_inack_callback,
1392 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 }
1394};
1395
1396 /* Generic setup urbs function that uses
1397 data in device_details */
1398static void keyspan_setup_urbs(struct usb_serial *serial)
1399{
1400 int i, j;
1401 struct keyspan_serial_private *s_priv;
1402 const struct keyspan_device_details *d_details;
1403 struct usb_serial_port *port;
1404 struct keyspan_port_private *p_priv;
1405 struct callbacks *cback;
1406 int endp;
1407
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 s_priv = usb_get_serial_data(serial);
1409 d_details = s_priv->device_details;
1410
Alan Coxdeb91682008-07-22 11:13:08 +01001411 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 cback = &keyspan_callbacks[d_details->msg_format];
1413
Alan Coxdeb91682008-07-22 11:13:08 +01001414 /* Allocate and set up urbs for each one that is in use,
1415 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 s_priv->instat_urb = keyspan_setup_urb
1417 (serial, d_details->instat_endpoint, USB_DIR_IN,
1418 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1419 cback->instat_callback);
1420
Lucy McCoy0ca12682007-05-18 12:10:41 -07001421 s_priv->indat_urb = keyspan_setup_urb
1422 (serial, d_details->indat_endpoint, USB_DIR_IN,
1423 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1424 usa49wg_indat_callback);
1425
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 s_priv->glocont_urb = keyspan_setup_urb
1427 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1428 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1429 cback->glocont_callback);
1430
Alan Coxdeb91682008-07-22 11:13:08 +01001431 /* Setup endpoints for each port specific thing */
1432 for (i = 0; i < d_details->num_ports; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 port = serial->port[i];
1434 p_priv = usb_get_serial_port_data(port);
1435
1436 /* Do indat endpoints first, once for each flip */
1437 endp = d_details->indat_endpoints[i];
1438 for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) {
1439 p_priv->in_urbs[j] = keyspan_setup_urb
1440 (serial, endp, USB_DIR_IN, port,
1441 p_priv->in_buffer[j], 64,
1442 cback->indat_callback);
1443 }
1444 for (; j < 2; ++j)
1445 p_priv->in_urbs[j] = NULL;
1446
1447 /* outdat endpoints also have flip */
1448 endp = d_details->outdat_endpoints[i];
1449 for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) {
1450 p_priv->out_urbs[j] = keyspan_setup_urb
1451 (serial, endp, USB_DIR_OUT, port,
1452 p_priv->out_buffer[j], 64,
1453 cback->outdat_callback);
1454 }
1455 for (; j < 2; ++j)
1456 p_priv->out_urbs[j] = NULL;
1457
1458 /* inack endpoint */
1459 p_priv->inack_urb = keyspan_setup_urb
1460 (serial, d_details->inack_endpoints[i], USB_DIR_IN,
1461 port, p_priv->inack_buffer, 1, cback->inack_callback);
1462
1463 /* outcont endpoint */
1464 p_priv->outcont_urb = keyspan_setup_urb
1465 (serial, d_details->outcont_endpoints[i], USB_DIR_OUT,
1466 port, p_priv->outcont_buffer, 64,
1467 cback->outcont_callback);
Alan Coxdeb91682008-07-22 11:13:08 +01001468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469}
1470
1471/* usa19 function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001472static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1473 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 u8 *rate_low, u8 *prescaler, int portnum)
1475{
1476 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001477 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001480 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481
Alan Coxdeb91682008-07-22 11:13:08 +01001482 /* prevent divide by zero... */
1483 b16 = baud_rate * 16L;
1484 if (b16 == 0)
1485 return KEYSPAN_INVALID_BAUD_RATE;
1486 /* Any "standard" rate over 57k6 is marginal on the USA-19
1487 as we run out of divisor resolution. */
1488 if (baud_rate > 57600)
1489 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490
Alan Coxdeb91682008-07-22 11:13:08 +01001491 /* calculate the divisor and the counter (its inverse) */
1492 div = baudclk / b16;
1493 if (div == 0)
1494 return KEYSPAN_INVALID_BAUD_RATE;
1495 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
Alan Coxdeb91682008-07-22 11:13:08 +01001498 if (div > 0xffff)
1499 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
Alan Coxdeb91682008-07-22 11:13:08 +01001501 /* return the counter values if non-null */
1502 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001504 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001506 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001507 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001508 __func__, baud_rate, *rate_hi, *rate_low);
1509 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510}
1511
1512/* usa19hs function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001513static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1514 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1515 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
1517 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001518 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001520 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521
Alan Coxdeb91682008-07-22 11:13:08 +01001522 /* prevent divide by zero... */
1523 b16 = baud_rate * 16L;
1524 if (b16 == 0)
1525 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
Alan Coxdeb91682008-07-22 11:13:08 +01001527 /* calculate the divisor */
1528 div = baudclk / b16;
1529 if (div == 0)
1530 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
Alan Coxdeb91682008-07-22 11:13:08 +01001532 if (div > 0xffff)
1533 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
Alan Coxdeb91682008-07-22 11:13:08 +01001535 /* return the counter values if non-null */
1536 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001538
1539 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001541
1542 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001543 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001544 __func__, baud_rate, *rate_hi, *rate_low);
1545
1546 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547}
1548
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001549static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1550 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 u8 *rate_low, u8 *prescaler, int portnum)
1552{
1553 u32 b16, /* baud rate times 16 (actual rate used internally) */
1554 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001555 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 res, /* resulting baud rate using 13/8 prescaler */
1557 diff, /* error using 13/8 prescaler */
1558 smallest_diff;
1559 u8 best_prescaler;
1560 int i;
1561
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001562 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563
Alan Coxdeb91682008-07-22 11:13:08 +01001564 /* prevent divide by zero */
1565 b16 = baud_rate * 16L;
1566 if (b16 == 0)
1567 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568
Alan Coxdeb91682008-07-22 11:13:08 +01001569 /* Calculate prescaler by trying them all and looking
1570 for best fit */
1571
1572 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 smallest_diff = 0xffffffff;
1574
1575 /* 0 is an invalid prescaler, used as a flag */
1576 best_prescaler = 0;
1577
Alan Coxdeb91682008-07-22 11:13:08 +01001578 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001580
1581 div = clk / b16;
1582 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
1585 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001586 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
Alan Coxdeb91682008-07-22 11:13:08 +01001588 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 best_prescaler = i;
1590 smallest_diff = diff;
1591 }
1592 }
1593
Alan Coxdeb91682008-07-22 11:13:08 +01001594 if (best_prescaler == 0)
1595 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
1597 clk = (baudclk * 8) / (u32) best_prescaler;
1598 div = clk / b16;
1599
Alan Coxdeb91682008-07-22 11:13:08 +01001600 /* return the divisor and prescaler if non-null */
1601 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001603 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 if (prescaler) {
1606 *prescaler = best_prescaler;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001607 /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 }
Alan Coxdeb91682008-07-22 11:13:08 +01001609 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610}
1611
1612 /* USA-28 supports different maximum baud rates on each port */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001613static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1614 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1615 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616{
1617 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001618 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 cnt; /* inverse of divisor (programmed into 8051) */
1620
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001621 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622
1623 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001624 b16 = baud_rate * 16L;
1625 if (b16 == 0)
1626 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
Alan Coxdeb91682008-07-22 11:13:08 +01001628 /* calculate the divisor and the counter (its inverse) */
1629 div = KEYSPAN_USA28_BAUDCLK / b16;
1630 if (div == 0)
1631 return KEYSPAN_INVALID_BAUD_RATE;
1632 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
Alan Coxdeb91682008-07-22 11:13:08 +01001635 /* check for out of range, based on portnum,
1636 and return result */
1637 if (portnum == 0) {
1638 if (div > 0xffff)
1639 return KEYSPAN_INVALID_BAUD_RATE;
1640 } else {
1641 if (portnum == 1) {
1642 if (div > 0xff)
1643 return KEYSPAN_INVALID_BAUD_RATE;
1644 } else
1645 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 }
1647
1648 /* return the counter values if not NULL
1649 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001650 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001652 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001654 dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
Alan Coxdeb91682008-07-22 11:13:08 +01001655 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656}
1657
1658static int keyspan_usa26_send_setup(struct usb_serial *serial,
1659 struct usb_serial_port *port,
1660 int reset_port)
1661{
Alan Coxdeb91682008-07-22 11:13:08 +01001662 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 struct keyspan_serial_private *s_priv;
1664 struct keyspan_port_private *p_priv;
1665 const struct keyspan_device_details *d_details;
1666 int outcont_urb;
1667 struct urb *this_urb;
1668 int device_port, err;
1669
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001670 dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
1672 s_priv = usb_get_serial_data(serial);
1673 p_priv = usb_get_serial_port_data(port);
1674 d_details = s_priv->device_details;
1675 device_port = port->number - port->serial->minor;
1676
1677 outcont_urb = d_details->outcont_endpoints[port->number];
1678 this_urb = p_priv->outcont_urb;
1679
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001680 dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
1682 /* Make sure we have an urb then send the message */
1683 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001684 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 return -1;
1686 }
1687
1688 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001689 Don't overwrite resend for open/close condition. */
1690 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 p_priv->resend_cont = reset_port + 1;
1692 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001693 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001695 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 }
1697
Alan Coxdeb91682008-07-22 11:13:08 +01001698 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1699
1700 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 if (p_priv->old_baud != p_priv->baud) {
1702 p_priv->old_baud = p_priv->baud;
1703 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001704 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1705 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1706 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1707 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1708 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 msg.baudLo = 0;
1710 msg.baudHi = 125; /* Values for 9600 baud */
1711 msg.prescaler = 10;
1712 }
1713 msg.setPrescaler = 0xff;
1714 }
1715
Ben Minerds2b982ab2012-07-12 00:10:16 +10001716 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 switch (p_priv->cflag & CSIZE) {
1718 case CS5:
1719 msg.lcr |= USA_DATABITS_5;
1720 break;
1721 case CS6:
1722 msg.lcr |= USA_DATABITS_6;
1723 break;
1724 case CS7:
1725 msg.lcr |= USA_DATABITS_7;
1726 break;
1727 case CS8:
1728 msg.lcr |= USA_DATABITS_8;
1729 break;
1730 }
1731 if (p_priv->cflag & PARENB) {
1732 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001733 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001734 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 }
1736 msg.setLcr = 0xff;
1737
1738 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1739 msg.xonFlowControl = 0;
1740 msg.setFlowControl = 0xff;
1741 msg.forwardingLength = 16;
1742 msg.xonChar = 17;
1743 msg.xoffChar = 19;
1744
1745 /* Opening port */
1746 if (reset_port == 1) {
1747 msg._txOn = 1;
1748 msg._txOff = 0;
1749 msg.txFlush = 0;
1750 msg.txBreak = 0;
1751 msg.rxOn = 1;
1752 msg.rxOff = 0;
1753 msg.rxFlush = 1;
1754 msg.rxForward = 0;
1755 msg.returnStatus = 0;
1756 msg.resetDataToggle = 0xff;
1757 }
1758
1759 /* Closing port */
1760 else if (reset_port == 2) {
1761 msg._txOn = 0;
1762 msg._txOff = 1;
1763 msg.txFlush = 0;
1764 msg.txBreak = 0;
1765 msg.rxOn = 0;
1766 msg.rxOff = 1;
1767 msg.rxFlush = 1;
1768 msg.rxForward = 0;
1769 msg.returnStatus = 0;
1770 msg.resetDataToggle = 0;
1771 }
1772
1773 /* Sending intermediate configs */
1774 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001775 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 msg._txOff = 0;
1777 msg.txFlush = 0;
1778 msg.txBreak = (p_priv->break_on);
1779 msg.rxOn = 0;
1780 msg.rxOff = 0;
1781 msg.rxFlush = 0;
1782 msg.rxForward = 0;
1783 msg.returnStatus = 0;
1784 msg.resetDataToggle = 0x0;
1785 }
1786
Alan Coxdeb91682008-07-22 11:13:08 +01001787 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 msg.setTxTriState_setRts = 0xff;
1789 msg.txTriState_rts = p_priv->rts_state;
1790
1791 msg.setHskoa_setDtr = 0xff;
1792 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001793
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001795 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1796
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 /* send the data out the device on control endpoint */
1798 this_urb->transfer_buffer_length = sizeof(msg);
1799
Alan Coxdeb91682008-07-22 11:13:08 +01001800 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1801 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001802 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803#if 0
1804 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001805 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__
1806 outcont_urb, this_urb->transfer_buffer_length,
1807 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 }
1809#endif
1810
Alan Coxa5b6f602008-04-08 17:16:06 +01001811 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812}
1813
1814static int keyspan_usa28_send_setup(struct usb_serial *serial,
1815 struct usb_serial_port *port,
1816 int reset_port)
1817{
Alan Coxdeb91682008-07-22 11:13:08 +01001818 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 struct keyspan_serial_private *s_priv;
1820 struct keyspan_port_private *p_priv;
1821 const struct keyspan_device_details *d_details;
1822 struct urb *this_urb;
1823 int device_port, err;
1824
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 s_priv = usb_get_serial_data(serial);
1826 p_priv = usb_get_serial_port_data(port);
1827 d_details = s_priv->device_details;
1828 device_port = port->number - port->serial->minor;
1829
1830 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001831 this_urb = p_priv->outcont_urb;
1832 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001833 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 return -1;
1835 }
1836
1837 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001838 Don't overwrite resend for open/close condition. */
1839 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 p_priv->resend_cont = reset_port + 1;
1841 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001842 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001844 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 }
1846
Alan Coxdeb91682008-07-22 11:13:08 +01001847 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
1849 msg.setBaudRate = 1;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001850 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1851 &msg.baudHi, &msg.baudLo, NULL,
1852 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1853 dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001854 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 msg.baudLo = 0xff;
1856 msg.baudHi = 0xb2; /* Values for 9600 baud */
1857 }
1858
1859 /* If parity is enabled, we must calculate it ourselves. */
1860 msg.parity = 0; /* XXX for now */
1861
1862 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1863 msg.xonFlowControl = 0;
1864
Alan Coxdeb91682008-07-22 11:13:08 +01001865 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 msg.rts = p_priv->rts_state;
1867 msg.dtr = p_priv->dtr_state;
1868
1869 msg.forwardingLength = 16;
1870 msg.forwardMs = 10;
1871 msg.breakThreshold = 45;
1872 msg.xonChar = 17;
1873 msg.xoffChar = 19;
1874
1875 /*msg.returnStatus = 1;
1876 msg.resetDataToggle = 0xff;*/
1877 /* Opening port */
1878 if (reset_port == 1) {
1879 msg._txOn = 1;
1880 msg._txOff = 0;
1881 msg.txFlush = 0;
1882 msg.txForceXoff = 0;
1883 msg.txBreak = 0;
1884 msg.rxOn = 1;
1885 msg.rxOff = 0;
1886 msg.rxFlush = 1;
1887 msg.rxForward = 0;
1888 msg.returnStatus = 0;
1889 msg.resetDataToggle = 0xff;
1890 }
1891 /* Closing port */
1892 else if (reset_port == 2) {
1893 msg._txOn = 0;
1894 msg._txOff = 1;
1895 msg.txFlush = 0;
1896 msg.txForceXoff = 0;
1897 msg.txBreak = 0;
1898 msg.rxOn = 0;
1899 msg.rxOff = 1;
1900 msg.rxFlush = 1;
1901 msg.rxForward = 0;
1902 msg.returnStatus = 0;
1903 msg.resetDataToggle = 0;
1904 }
1905 /* Sending intermediate configs */
1906 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001907 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 msg._txOff = 0;
1909 msg.txFlush = 0;
1910 msg.txForceXoff = 0;
1911 msg.txBreak = (p_priv->break_on);
1912 msg.rxOn = 0;
1913 msg.rxOff = 0;
1914 msg.rxFlush = 0;
1915 msg.rxForward = 0;
1916 msg.returnStatus = 0;
1917 msg.resetDataToggle = 0x0;
1918 }
1919
1920 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001921 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
1923 /* send the data out the device on control endpoint */
1924 this_urb->transfer_buffer_length = sizeof(msg);
1925
Alan Coxdeb91682008-07-22 11:13:08 +01001926 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1927 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001928 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929#if 0
1930 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001931 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 this_urb->transfer_buffer_length);
1933 }
1934#endif
1935
Alan Coxa5b6f602008-04-08 17:16:06 +01001936 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937}
1938
1939static int keyspan_usa49_send_setup(struct usb_serial *serial,
1940 struct usb_serial_port *port,
1941 int reset_port)
1942{
Lucy McCoy0ca12682007-05-18 12:10:41 -07001943 struct keyspan_usa49_portControlMessage msg;
1944 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 struct keyspan_serial_private *s_priv;
1946 struct keyspan_port_private *p_priv;
1947 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 struct urb *this_urb;
1949 int err, device_port;
1950
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 s_priv = usb_get_serial_data(serial);
1952 p_priv = usb_get_serial_port_data(port);
1953 d_details = s_priv->device_details;
1954
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 this_urb = s_priv->glocont_urb;
1956
Lucy McCoy0ca12682007-05-18 12:10:41 -07001957 /* Work out which port within the device is being setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 device_port = port->number - port->serial->minor;
1959
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301960 /* Make sure we have an urb then send the message */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001962 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 return -1;
1964 }
1965
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001966 dev_dbg(&port->dev, "%s - endpoint %d port %d (%d)\n",
1967 __func__, usb_pipeendpoint(this_urb->pipe),
1968 port->number, device_port);
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301969
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001971 Don't overwrite resend for open/close condition. */
1972 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001974
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001976 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001978 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 }
1980
Alan Coxdeb91682008-07-22 11:13:08 +01001981 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982
1983 /*msg.portNumber = port->number;*/
1984 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01001985
1986 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 if (p_priv->old_baud != p_priv->baud) {
1988 p_priv->old_baud = p_priv->baud;
1989 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001990 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1991 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1992 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1993 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1994 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 msg.baudLo = 0;
1996 msg.baudHi = 125; /* Values for 9600 baud */
1997 msg.prescaler = 10;
1998 }
Alan Coxdeb91682008-07-22 11:13:08 +01001999 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 }
2001
Ben Minerds2b982ab2012-07-12 00:10:16 +10002002 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 switch (p_priv->cflag & CSIZE) {
2004 case CS5:
2005 msg.lcr |= USA_DATABITS_5;
2006 break;
2007 case CS6:
2008 msg.lcr |= USA_DATABITS_6;
2009 break;
2010 case CS7:
2011 msg.lcr |= USA_DATABITS_7;
2012 break;
2013 case CS8:
2014 msg.lcr |= USA_DATABITS_8;
2015 break;
2016 }
2017 if (p_priv->cflag & PARENB) {
2018 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002019 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002020 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 }
2022 msg.setLcr = 0xff;
2023
2024 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2025 msg.xonFlowControl = 0;
2026 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01002027
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 msg.forwardingLength = 16;
2029 msg.xonChar = 17;
2030 msg.xoffChar = 19;
2031
Alan Coxdeb91682008-07-22 11:13:08 +01002032 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 if (reset_port == 1) {
2034 msg._txOn = 1;
2035 msg._txOff = 0;
2036 msg.txFlush = 0;
2037 msg.txBreak = 0;
2038 msg.rxOn = 1;
2039 msg.rxOff = 0;
2040 msg.rxFlush = 1;
2041 msg.rxForward = 0;
2042 msg.returnStatus = 0;
2043 msg.resetDataToggle = 0xff;
2044 msg.enablePort = 1;
2045 msg.disablePort = 0;
2046 }
2047 /* Closing port */
2048 else if (reset_port == 2) {
2049 msg._txOn = 0;
2050 msg._txOff = 1;
2051 msg.txFlush = 0;
2052 msg.txBreak = 0;
2053 msg.rxOn = 0;
2054 msg.rxOff = 1;
2055 msg.rxFlush = 1;
2056 msg.rxForward = 0;
2057 msg.returnStatus = 0;
2058 msg.resetDataToggle = 0;
2059 msg.enablePort = 0;
2060 msg.disablePort = 1;
2061 }
2062 /* Sending intermediate configs */
2063 else {
Alan Coxdeb91682008-07-22 11:13:08 +01002064 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 msg._txOff = 0;
2066 msg.txFlush = 0;
2067 msg.txBreak = (p_priv->break_on);
2068 msg.rxOn = 0;
2069 msg.rxOff = 0;
2070 msg.rxFlush = 0;
2071 msg.rxForward = 0;
2072 msg.returnStatus = 0;
2073 msg.resetDataToggle = 0x0;
2074 msg.enablePort = 0;
2075 msg.disablePort = 0;
2076 }
2077
Alan Coxdeb91682008-07-22 11:13:08 +01002078 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 msg.setRts = 0xff;
2080 msg.rts = p_priv->rts_state;
2081
2082 msg.setDtr = 0xff;
2083 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002084
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
Alan Coxdeb91682008-07-22 11:13:08 +01002087 /* if the device is a 49wg, we send control message on usb
2088 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002089
2090 if (d_details->product_id == keyspan_usa49wg_product_id) {
2091 dr = (void *)(s_priv->ctrl_buf);
2092 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
2093 dr->bRequest = 0xB0; /* 49wg control message */;
2094 dr->wValue = 0;
2095 dr->wIndex = 0;
2096 dr->wLength = cpu_to_le16(sizeof(msg));
2097
Alan Coxdeb91682008-07-22 11:13:08 +01002098 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07002099
Alan Coxdeb91682008-07-22 11:13:08 +01002100 usb_fill_control_urb(this_urb, serial->dev,
2101 usb_sndctrlpipe(serial->dev, 0),
2102 (unsigned char *)dr, s_priv->glocont_buf,
2103 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002104
2105 } else {
2106 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01002107
Lucy McCoy0ca12682007-05-18 12:10:41 -07002108 /* send the data out the device on control endpoint */
2109 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002110 }
Alan Coxdeb91682008-07-22 11:13:08 +01002111 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2112 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002113 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114#if 0
2115 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002116 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__,
2117 outcont_urb, this_urb->transfer_buffer_length,
2118 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 }
2120#endif
2121
Alan Coxa5b6f602008-04-08 17:16:06 +01002122 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123}
2124
2125static int keyspan_usa90_send_setup(struct usb_serial *serial,
2126 struct usb_serial_port *port,
2127 int reset_port)
2128{
Alan Coxdeb91682008-07-22 11:13:08 +01002129 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 struct keyspan_serial_private *s_priv;
2131 struct keyspan_port_private *p_priv;
2132 const struct keyspan_device_details *d_details;
2133 struct urb *this_urb;
2134 int err;
2135 u8 prescaler;
2136
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 s_priv = usb_get_serial_data(serial);
2138 p_priv = usb_get_serial_port_data(port);
2139 d_details = s_priv->device_details;
2140
2141 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002142 this_urb = p_priv->outcont_urb;
2143 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002144 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 return -1;
2146 }
2147
2148 /* Save reset port val for resend.
2149 Don't overwrite resend for open/close condition. */
2150 if ((reset_port + 1) > p_priv->resend_cont)
2151 p_priv->resend_cont = reset_port + 1;
2152 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002153 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002155 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 }
2157
Alan Coxdeb91682008-07-22 11:13:08 +01002158 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159
Alan Coxdeb91682008-07-22 11:13:08 +01002160 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 if (p_priv->old_baud != p_priv->baud) {
2162 p_priv->old_baud = p_priv->baud;
2163 msg.setClocking = 0x01;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002164 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2165 &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2166 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2167 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 p_priv->baud = 9600;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002169 d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2171 }
2172 msg.setRxMode = 1;
2173 msg.setTxMode = 1;
2174 }
2175
2176 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002177 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 msg.rxMode = RXMODE_DMA;
2179 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002180 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 msg.rxMode = RXMODE_BYHAND;
2182 msg.txMode = TXMODE_BYHAND;
2183 }
2184
Ben Minerds2b982ab2012-07-12 00:10:16 +10002185 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 switch (p_priv->cflag & CSIZE) {
2187 case CS5:
2188 msg.lcr |= USA_DATABITS_5;
2189 break;
2190 case CS6:
2191 msg.lcr |= USA_DATABITS_6;
2192 break;
2193 case CS7:
2194 msg.lcr |= USA_DATABITS_7;
2195 break;
2196 case CS8:
2197 msg.lcr |= USA_DATABITS_8;
2198 break;
2199 }
2200 if (p_priv->cflag & PARENB) {
2201 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002202 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002203 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 }
2205 if (p_priv->old_cflag != p_priv->cflag) {
2206 p_priv->old_cflag = p_priv->cflag;
2207 msg.setLcr = 0x01;
2208 }
2209
2210 if (p_priv->flow_control == flow_cts)
2211 msg.txFlowControl = TXFLOW_CTS;
2212 msg.setTxFlowControl = 0x01;
2213 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002214
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002216 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 msg.txAckSetting = 0;
2218 msg.xonChar = 17;
2219 msg.xoffChar = 19;
2220
Alan Coxdeb91682008-07-22 11:13:08 +01002221 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 if (reset_port == 1) {
2223 msg.portEnabled = 1;
2224 msg.rxFlush = 1;
2225 msg.txBreak = (p_priv->break_on);
2226 }
2227 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002228 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 /* Sending intermediate configs */
2231 else {
Alan Stern1f871582010-02-17 10:05:47 -05002232 msg.portEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 msg.txBreak = (p_priv->break_on);
2234 }
2235
Alan Coxdeb91682008-07-22 11:13:08 +01002236 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 msg.setRts = 0x01;
2238 msg.rts = p_priv->rts_state;
2239
2240 msg.setDtr = 0x01;
2241 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002242
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002244 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2245
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 /* send the data out the device on control endpoint */
2247 this_urb->transfer_buffer_length = sizeof(msg);
2248
Alan Coxdeb91682008-07-22 11:13:08 +01002249 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2250 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002251 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002252 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253}
2254
Lucy McCoy0ca12682007-05-18 12:10:41 -07002255static int keyspan_usa67_send_setup(struct usb_serial *serial,
2256 struct usb_serial_port *port,
2257 int reset_port)
2258{
2259 struct keyspan_usa67_portControlMessage msg;
2260 struct keyspan_serial_private *s_priv;
2261 struct keyspan_port_private *p_priv;
2262 const struct keyspan_device_details *d_details;
2263 struct urb *this_urb;
2264 int err, device_port;
2265
Lucy McCoy0ca12682007-05-18 12:10:41 -07002266 s_priv = usb_get_serial_data(serial);
2267 p_priv = usb_get_serial_port_data(port);
2268 d_details = s_priv->device_details;
2269
2270 this_urb = s_priv->glocont_urb;
2271
2272 /* Work out which port within the device is being setup */
2273 device_port = port->number - port->serial->minor;
2274
2275 /* Make sure we have an urb then send the message */
2276 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002277 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002278 port->number);
2279 return -1;
2280 }
2281
2282 /* Save reset port val for resend.
2283 Don't overwrite resend for open/close condition. */
2284 if ((reset_port + 1) > p_priv->resend_cont)
2285 p_priv->resend_cont = reset_port + 1;
2286 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002287 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002288 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002289 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002290 }
2291
2292 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2293
2294 msg.port = device_port;
2295
2296 /* Only set baud rate if it's changed */
2297 if (p_priv->old_baud != p_priv->baud) {
2298 p_priv->old_baud = p_priv->baud;
2299 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002300 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2301 &msg.baudHi, &msg.baudLo, &msg.prescaler,
2302 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2303 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2304 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002305 msg.baudLo = 0;
2306 msg.baudHi = 125; /* Values for 9600 baud */
2307 msg.prescaler = 10;
2308 }
2309 msg.setPrescaler = 0xff;
2310 }
2311
2312 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2313 switch (p_priv->cflag & CSIZE) {
2314 case CS5:
2315 msg.lcr |= USA_DATABITS_5;
2316 break;
2317 case CS6:
2318 msg.lcr |= USA_DATABITS_6;
2319 break;
2320 case CS7:
2321 msg.lcr |= USA_DATABITS_7;
2322 break;
2323 case CS8:
2324 msg.lcr |= USA_DATABITS_8;
2325 break;
2326 }
2327 if (p_priv->cflag & PARENB) {
2328 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002329 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002330 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002331 }
2332 msg.setLcr = 0xff;
2333
2334 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2335 msg.xonFlowControl = 0;
2336 msg.setFlowControl = 0xff;
2337 msg.forwardingLength = 16;
2338 msg.xonChar = 17;
2339 msg.xoffChar = 19;
2340
2341 if (reset_port == 1) {
2342 /* Opening port */
2343 msg._txOn = 1;
2344 msg._txOff = 0;
2345 msg.txFlush = 0;
2346 msg.txBreak = 0;
2347 msg.rxOn = 1;
2348 msg.rxOff = 0;
2349 msg.rxFlush = 1;
2350 msg.rxForward = 0;
2351 msg.returnStatus = 0;
2352 msg.resetDataToggle = 0xff;
2353 } else if (reset_port == 2) {
2354 /* Closing port */
2355 msg._txOn = 0;
2356 msg._txOff = 1;
2357 msg.txFlush = 0;
2358 msg.txBreak = 0;
2359 msg.rxOn = 0;
2360 msg.rxOff = 1;
2361 msg.rxFlush = 1;
2362 msg.rxForward = 0;
2363 msg.returnStatus = 0;
2364 msg.resetDataToggle = 0;
2365 } else {
2366 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002367 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002368 msg._txOff = 0;
2369 msg.txFlush = 0;
2370 msg.txBreak = (p_priv->break_on);
2371 msg.rxOn = 0;
2372 msg.rxOff = 0;
2373 msg.rxFlush = 0;
2374 msg.rxForward = 0;
2375 msg.returnStatus = 0;
2376 msg.resetDataToggle = 0x0;
2377 }
2378
2379 /* Do handshaking outputs */
2380 msg.setTxTriState_setRts = 0xff;
2381 msg.txTriState_rts = p_priv->rts_state;
2382
2383 msg.setHskoa_setDtr = 0xff;
2384 msg.hskoa_dtr = p_priv->dtr_state;
2385
2386 p_priv->resend_cont = 0;
2387
2388 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2389
2390 /* send the data out the device on control endpoint */
2391 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002392
2393 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2394 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002395 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002396 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002397}
2398
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2400{
2401 struct usb_serial *serial = port->serial;
2402 struct keyspan_serial_private *s_priv;
2403 const struct keyspan_device_details *d_details;
2404
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 s_priv = usb_get_serial_data(serial);
2406 d_details = s_priv->device_details;
2407
2408 switch (d_details->msg_format) {
2409 case msg_usa26:
2410 keyspan_usa26_send_setup(serial, port, reset_port);
2411 break;
2412 case msg_usa28:
2413 keyspan_usa28_send_setup(serial, port, reset_port);
2414 break;
2415 case msg_usa49:
2416 keyspan_usa49_send_setup(serial, port, reset_port);
2417 break;
2418 case msg_usa90:
2419 keyspan_usa90_send_setup(serial, port, reset_port);
2420 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002421 case msg_usa67:
2422 keyspan_usa67_send_setup(serial, port, reset_port);
2423 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 }
2425}
2426
2427
2428/* Gets called by the "real" driver (ie once firmware is loaded
2429 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002430static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431{
2432 int i, err;
2433 struct usb_serial_port *port;
2434 struct keyspan_serial_private *s_priv;
2435 struct keyspan_port_private *p_priv;
2436 const struct keyspan_device_details *d_details;
2437
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002439 if (d_details->product_id ==
2440 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 break;
2442 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002443 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2444 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 return 1;
2446 }
2447
2448 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002449 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 if (!s_priv) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002451 dev_dbg(&serial->dev->dev, "%s - kmalloc for keyspan_serial_private failed.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 return -ENOMEM;
2453 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454
2455 s_priv->device_details = d_details;
2456 usb_set_serial_data(serial, s_priv);
2457
2458 /* Now setup per port private data */
2459 for (i = 0; i < serial->num_ports; i++) {
2460 port = serial->port[i];
Alan Coxdeb91682008-07-22 11:13:08 +01002461 p_priv = kzalloc(sizeof(struct keyspan_port_private),
2462 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 if (!p_priv) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002464 dev_dbg(&port->dev, "%s - kmalloc for keyspan_port_private (%d) failed!.\n", __func__, i);
Alan Coxdeb91682008-07-22 11:13:08 +01002465 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 p_priv->device_details = d_details;
2468 usb_set_serial_port_data(port, p_priv);
2469 }
2470
2471 keyspan_setup_urbs(serial);
2472
Lucy McCoy0ca12682007-05-18 12:10:41 -07002473 if (s_priv->instat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002474 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2475 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002476 dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002477 }
2478 if (s_priv->indat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002479 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2480 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002481 dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 }
Alan Coxdeb91682008-07-22 11:13:08 +01002483
Alan Coxa5b6f602008-04-08 17:16:06 +01002484 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485}
2486
Alan Sternf9c99bb2009-06-02 11:53:55 -04002487static void keyspan_disconnect(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488{
2489 int i, j;
2490 struct usb_serial_port *port;
2491 struct keyspan_serial_private *s_priv;
2492 struct keyspan_port_private *p_priv;
2493
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 s_priv = usb_get_serial_data(serial);
2495
2496 /* Stop reading/writing urbs */
2497 stop_urb(s_priv->instat_urb);
2498 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002499 stop_urb(s_priv->indat_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 for (i = 0; i < serial->num_ports; ++i) {
2501 port = serial->port[i];
2502 p_priv = usb_get_serial_port_data(port);
2503 stop_urb(p_priv->inack_urb);
2504 stop_urb(p_priv->outcont_urb);
2505 for (j = 0; j < 2; j++) {
2506 stop_urb(p_priv->in_urbs[j]);
2507 stop_urb(p_priv->out_urbs[j]);
2508 }
2509 }
2510
2511 /* Now free them */
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002512 usb_free_urb(s_priv->instat_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002513 usb_free_urb(s_priv->indat_urb);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002514 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 for (i = 0; i < serial->num_ports; ++i) {
2516 port = serial->port[i];
2517 p_priv = usb_get_serial_port_data(port);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002518 usb_free_urb(p_priv->inack_urb);
2519 usb_free_urb(p_priv->outcont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 for (j = 0; j < 2; j++) {
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002521 usb_free_urb(p_priv->in_urbs[j]);
2522 usb_free_urb(p_priv->out_urbs[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 }
2524 }
Alan Sternf9c99bb2009-06-02 11:53:55 -04002525}
2526
2527static void keyspan_release(struct usb_serial *serial)
2528{
2529 int i;
2530 struct usb_serial_port *port;
2531 struct keyspan_serial_private *s_priv;
2532
Alan Sternf9c99bb2009-06-02 11:53:55 -04002533 s_priv = usb_get_serial_data(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 kfree(s_priv);
2536
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 /* Now free per port private data */
2538 for (i = 0; i < serial->num_ports; i++) {
2539 port = serial->port[i];
2540 kfree(usb_get_serial_port_data(port));
2541 }
2542}
2543
Alan Coxdeb91682008-07-22 11:13:08 +01002544MODULE_AUTHOR(DRIVER_AUTHOR);
2545MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546MODULE_LICENSE("GPL");
2547
David Woodhouse2971c572008-05-30 14:04:03 +03002548MODULE_FIRMWARE("keyspan/usa28.fw");
2549MODULE_FIRMWARE("keyspan/usa28x.fw");
2550MODULE_FIRMWARE("keyspan/usa28xa.fw");
2551MODULE_FIRMWARE("keyspan/usa28xb.fw");
2552MODULE_FIRMWARE("keyspan/usa19.fw");
2553MODULE_FIRMWARE("keyspan/usa19qi.fw");
2554MODULE_FIRMWARE("keyspan/mpr.fw");
2555MODULE_FIRMWARE("keyspan/usa19qw.fw");
2556MODULE_FIRMWARE("keyspan/usa18x.fw");
2557MODULE_FIRMWARE("keyspan/usa19w.fw");
2558MODULE_FIRMWARE("keyspan/usa49w.fw");
2559MODULE_FIRMWARE("keyspan/usa49wlc.fw");