blob: 3d95637f3d68d93d65257496587b2849ea8d0a60 [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>
Alan Coxdeb91682008-07-22 11:13:08 +010041#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070043#include <linux/usb/serial.h>
Rene Buergelcc183e22012-09-18 09:00:41 +020044#include <linux/usb/ezusb.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include "keyspan.h"
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
48#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
49
50#define INSTAT_BUFLEN 32
51#define GLOCONT_BUFLEN 64
Lucy McCoy0ca12682007-05-18 12:10:41 -070052#define INDAT49W_BUFLEN 512
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54 /* Per device and per port private data */
55struct keyspan_serial_private {
56 const struct keyspan_device_details *device_details;
57
58 struct urb *instat_urb;
59 char instat_buf[INSTAT_BUFLEN];
60
Alan Coxdeb91682008-07-22 11:13:08 +010061 /* added to support 49wg, where data from all 4 ports comes in
62 on 1 EP and high-speed supported */
Lucy McCoy0ca12682007-05-18 12:10:41 -070063 struct urb *indat_urb;
64 char indat_buf[INDAT49W_BUFLEN];
65
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 /* XXX this one probably will need a lock */
67 struct urb *glocont_urb;
68 char glocont_buf[GLOCONT_BUFLEN];
Alan Coxdeb91682008-07-22 11:13:08 +010069 char ctrl_buf[8]; /* for EP0 control message */
Linus Torvalds1da177e2005-04-16 15:20:36 -070070};
71
72struct keyspan_port_private {
73 /* Keep track of which input & output endpoints to use */
74 int in_flip;
75 int out_flip;
76
77 /* Keep duplicate of device details in each port
78 structure as well - simplifies some of the
79 callback functions etc. */
80 const struct keyspan_device_details *device_details;
81
82 /* Input endpoints and buffer for this port */
83 struct urb *in_urbs[2];
84 char in_buffer[2][64];
85 /* Output endpoints and buffer for this port */
86 struct urb *out_urbs[2];
87 char out_buffer[2][64];
88
89 /* Input ack endpoint */
90 struct urb *inack_urb;
91 char inack_buffer[1];
92
93 /* Output control endpoint */
94 struct urb *outcont_urb;
95 char outcont_buffer[64];
96
97 /* Settings for the port */
98 int baud;
99 int old_baud;
100 unsigned int cflag;
101 unsigned int old_cflag;
102 enum {flow_none, flow_cts, flow_xon} flow_control;
103 int rts_state; /* Handshaking pins (outputs) */
104 int dtr_state;
105 int cts_state; /* Handshaking pins (inputs) */
106 int dsr_state;
107 int dcd_state;
108 int ri_state;
109 int break_on;
110
111 unsigned long tx_start_time[2];
112 int resend_cont; /* need to resend control packet */
113};
114
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115/* Include Keyspan message headers. All current Keyspan Adapters
Lucy McCoy0ca12682007-05-18 12:10:41 -0700116 make use of one of five message formats which are referred
Alan Coxdeb91682008-07-22 11:13:08 +0100117 to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and
118 within this driver. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#include "keyspan_usa26msg.h"
120#include "keyspan_usa28msg.h"
121#include "keyspan_usa49msg.h"
122#include "keyspan_usa90msg.h"
Lucy McCoy0ca12682007-05-18 12:10:41 -0700123#include "keyspan_usa67msg.h"
Alan Coxdeb91682008-07-22 11:13:08 +0100124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -0700126module_usb_serial_driver(serial_drivers, keyspan_ids_combined);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
Alan Cox95da3102008-07-22 11:09:07 +0100128static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129{
Alan Cox95da3102008-07-22 11:09:07 +0100130 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 struct keyspan_port_private *p_priv;
132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 p_priv = usb_get_serial_port_data(port);
134
135 if (break_state == -1)
136 p_priv->break_on = 1;
137 else
138 p_priv->break_on = 0;
139
140 keyspan_send_setup(port, 0);
141}
142
143
Alan Coxdeb91682008-07-22 11:13:08 +0100144static void keyspan_set_termios(struct tty_struct *tty,
Alan Cox95da3102008-07-22 11:09:07 +0100145 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
147 int baud_rate, device_port;
148 struct keyspan_port_private *p_priv;
149 const struct keyspan_device_details *d_details;
150 unsigned int cflag;
151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 p_priv = usb_get_serial_port_data(port);
153 d_details = p_priv->device_details;
Alan Coxadc8d742012-07-14 15:31:47 +0100154 cflag = tty->termios.c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 device_port = port->number - port->serial->minor;
156
157 /* Baud rate calculation takes baud rate as an integer
158 so other rates can be generated if desired. */
Alan Cox74240b02007-10-18 01:24:20 -0700159 baud_rate = tty_get_baud_rate(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100160 /* If no match or invalid, don't change */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700161 if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
163 /* FIXME - more to do here to ensure rate changes cleanly */
Alan Cox74240b02007-10-18 01:24:20 -0700164 /* FIXME - calcuate exact rate from divisor ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 p_priv->baud = baud_rate;
Alan Cox74240b02007-10-18 01:24:20 -0700166 } else
167 baud_rate = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
Alan Cox74240b02007-10-18 01:24:20 -0700169 tty_encode_baud_rate(tty, baud_rate, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 /* set CTS/RTS handshake etc. */
171 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +1000172 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Alan Cox74240b02007-10-18 01:24:20 -0700174 /* Mark/Space not supported */
Alan Coxadc8d742012-07-14 15:31:47 +0100175 tty->termios.c_cflag &= ~CMSPAR;
Alan Cox74240b02007-10-18 01:24:20 -0700176
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 keyspan_send_setup(port, 0);
178}
179
Alan Cox60b33c12011-02-14 16:26:14 +0000180static int keyspan_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181{
Alan Cox95da3102008-07-22 11:09:07 +0100182 struct usb_serial_port *port = tty->driver_data;
183 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 unsigned int value;
Alan Coxdeb91682008-07-22 11:13:08 +0100185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
187 ((p_priv->dtr_state) ? TIOCM_DTR : 0) |
188 ((p_priv->cts_state) ? TIOCM_CTS : 0) |
189 ((p_priv->dsr_state) ? TIOCM_DSR : 0) |
190 ((p_priv->dcd_state) ? TIOCM_CAR : 0) |
Alan Coxdeb91682008-07-22 11:13:08 +0100191 ((p_priv->ri_state) ? TIOCM_RNG : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
193 return value;
194}
195
Alan Cox20b9d172011-02-14 16:26:50 +0000196static int keyspan_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 unsigned int set, unsigned int clear)
198{
Alan Cox95da3102008-07-22 11:09:07 +0100199 struct usb_serial_port *port = tty->driver_data;
200 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 if (set & TIOCM_RTS)
203 p_priv->rts_state = 1;
204 if (set & TIOCM_DTR)
205 p_priv->dtr_state = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 if (clear & TIOCM_RTS)
207 p_priv->rts_state = 0;
208 if (clear & TIOCM_DTR)
209 p_priv->dtr_state = 0;
210 keyspan_send_setup(port, 0);
211 return 0;
212}
213
Alan Cox95da3102008-07-22 11:09:07 +0100214/* Write function is similar for the four protocols used
215 with only a minor change for usa90 (usa19hs) required */
216static int keyspan_write(struct tty_struct *tty,
217 struct usb_serial_port *port, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218{
219 struct keyspan_port_private *p_priv;
220 const struct keyspan_device_details *d_details;
221 int flip;
222 int left, todo;
223 struct urb *this_urb;
Alan Coxdeb91682008-07-22 11:13:08 +0100224 int err, maxDataLen, dataOffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226 p_priv = usb_get_serial_port_data(port);
227 d_details = p_priv->device_details;
228
229 if (d_details->msg_format == msg_usa90) {
Alan Coxdeb91682008-07-22 11:13:08 +0100230 maxDataLen = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 dataOffset = 0;
232 } else {
233 maxDataLen = 63;
234 dataOffset = 1;
235 }
Alan Coxdeb91682008-07-22 11:13:08 +0100236
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700237 dev_dbg(&port->dev, "%s - for port %d (%d chars), flip=%d\n",
238 __func__, port->number, count, p_priv->out_flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240 for (left = count; left > 0; left -= todo) {
241 todo = left;
242 if (todo > maxDataLen)
243 todo = maxDataLen;
244
245 flip = p_priv->out_flip;
Alan Coxdeb91682008-07-22 11:13:08 +0100246
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 /* Check we have a valid urb/endpoint before we use it... */
Alan Coxdeb91682008-07-22 11:13:08 +0100248 this_urb = p_priv->out_urbs[flip];
249 if (this_urb == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 /* no bulk out, so return 0 bytes written */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700251 dev_dbg(&port->dev, "%s - no output urb :(\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 return count;
253 }
254
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700255 dev_dbg(&port->dev, "%s - endpoint %d flip %d\n",
Alan Coxdeb91682008-07-22 11:13:08 +0100256 __func__, usb_pipeendpoint(this_urb->pipe), flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +0100259 if (time_before(jiffies,
260 p_priv->tx_start_time[flip] + 10 * HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 usb_unlink_urb(this_urb);
263 break;
264 }
265
Alan Coxdeb91682008-07-22 11:13:08 +0100266 /* First byte in buffer is "last flag" (except for usa19hx)
267 - unused so for now so set to zero */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 ((char *)this_urb->transfer_buffer)[0] = 0;
269
Alan Coxdeb91682008-07-22 11:13:08 +0100270 memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 buf += todo;
272
273 /* send the data out the bulk port */
274 this_urb->transfer_buffer_length = todo + dataOffset;
275
Alan Coxdeb91682008-07-22 11:13:08 +0100276 err = usb_submit_urb(this_urb, GFP_ATOMIC);
277 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700278 dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 p_priv->tx_start_time[flip] = jiffies;
280
281 /* Flip for next time if usa26 or usa28 interface
282 (not used on usa49) */
283 p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
284 }
285
286 return count - left;
287}
288
David Howells7d12e782006-10-05 14:55:46 +0100289static void usa26_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
291 int i, err;
292 int endpoint;
293 struct usb_serial_port *port;
294 struct tty_struct *tty;
295 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700296 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 endpoint = usb_pipeendpoint(urb->pipe);
299
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700300 if (status) {
Stefan Hubnera8ffa0b2012-12-13 22:45:00 +0100301 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700302 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 return;
304 }
305
Ming Leicdc97792008-02-24 18:41:47 +0800306 port = urb->context;
Alan Cox4a90f092008-10-13 10:39:46 +0100307 tty = tty_port_tty_get(&port->port);
Alan Coxa5569a52008-01-21 17:18:24 -0800308 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 /* 0x80 bit is error flag */
310 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100311 /* no errors on individual bytes, only
312 possible overrun err */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100314 err = TTY_OVERRUN;
315 else
316 err = 0;
317 for (i = 1; i < urb->actual_length ; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 tty_insert_flip_char(tty, data[i], err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 } else {
320 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700321 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 for (i = 0; i + 1 < urb->actual_length; i += 2) {
323 int stat = data[i], flag = 0;
324 if (stat & RXERROR_OVERRUN)
325 flag |= TTY_OVERRUN;
326 if (stat & RXERROR_FRAMING)
327 flag |= TTY_FRAME;
328 if (stat & RXERROR_PARITY)
329 flag |= TTY_PARITY;
330 /* XXX should handle break (0x10) */
331 tty_insert_flip_char(tty, data[i+1], flag);
332 }
333 }
334 tty_flip_buffer_push(tty);
335 }
Alan Cox4a90f092008-10-13 10:39:46 +0100336 tty_kref_put(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100337
338 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500339 err = usb_submit_urb(urb, GFP_ATOMIC);
340 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700341 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342}
343
Alan Coxdeb91682008-07-22 11:13:08 +0100344/* Outdat handling is common for all devices */
David Howells7d12e782006-10-05 14:55:46 +0100345static void usa2x_outdat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
347 struct usb_serial_port *port;
348 struct keyspan_port_private *p_priv;
349
Ming Leicdc97792008-02-24 18:41:47 +0800350 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 p_priv = usb_get_serial_port_data(port);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700352 dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Alan Stern1f871582010-02-17 10:05:47 -0500354 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355}
356
David Howells7d12e782006-10-05 14:55:46 +0100357static void usa26_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
360
David Howells7d12e782006-10-05 14:55:46 +0100361static void usa26_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
363 struct usb_serial_port *port;
364 struct keyspan_port_private *p_priv;
365
Ming Leicdc97792008-02-24 18:41:47 +0800366 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 p_priv = usb_get_serial_port_data(port);
368
369 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700370 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100371 keyspan_usa26_send_setup(port->serial, port,
372 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 }
374}
375
David Howells7d12e782006-10-05 14:55:46 +0100376static void usa26_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
378 unsigned char *data = urb->transfer_buffer;
379 struct keyspan_usa26_portStatusMessage *msg;
380 struct usb_serial *serial;
381 struct usb_serial_port *port;
382 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100383 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700385 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Ming Leicdc97792008-02-24 18:41:47 +0800387 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700389 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700390 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 return;
392 }
393 if (urb->actual_length != 9) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700394 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 goto exit;
396 }
397
398 msg = (struct keyspan_usa26_portStatusMessage *)data;
399
400#if 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700401 dev_dbg(&urb->dev->dev,
402 "%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
403 __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr,
404 msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled,
405 msg->controlResponse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406#endif
407
408 /* Now do something useful with the data */
409
410
Alan Coxdeb91682008-07-22 11:13:08 +0100411 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700413 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 goto exit;
415 }
416 port = serial->port[msg->port];
417 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100418
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 /* Update handshaking pin state information */
420 old_dcd_state = p_priv->dcd_state;
421 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
422 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
423 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
424 p_priv->ri_state = ((msg->ri) ? 1 : 0);
425
Alan Cox4a90f092008-10-13 10:39:46 +0100426 if (old_dcd_state != p_priv->dcd_state) {
427 tty = tty_port_tty_get(&port->port);
428 if (tty && !C_CLOCAL(tty))
429 tty_hangup(tty);
430 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 }
Alan Coxdeb91682008-07-22 11:13:08 +0100432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100434 err = usb_submit_urb(urb, GFP_ATOMIC);
435 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700436 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437exit: ;
438}
439
David Howells7d12e782006-10-05 14:55:46 +0100440static void usa26_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442}
443
444
David Howells7d12e782006-10-05 14:55:46 +0100445static void usa28_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
Alan Coxf035a8a2008-07-22 11:13:32 +0100447 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 struct usb_serial_port *port;
449 struct tty_struct *tty;
450 unsigned char *data;
451 struct keyspan_port_private *p_priv;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700452 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
Ming Leicdc97792008-02-24 18:41:47 +0800454 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 p_priv = usb_get_serial_port_data(port);
456 data = urb->transfer_buffer;
457
458 if (urb != p_priv->in_urbs[p_priv->in_flip])
459 return;
460
461 do {
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700462 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700463 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
464 __func__, status, usb_pipeendpoint(urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 return;
466 }
467
Ming Leicdc97792008-02-24 18:41:47 +0800468 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 p_priv = usb_get_serial_port_data(port);
470 data = urb->transfer_buffer;
471
Ben Minerds40adac82012-07-12 00:10:17 +1000472 tty = tty_port_tty_get(&port->port);
Alan Cox4a90f092008-10-13 10:39:46 +0100473 if (tty && urb->actual_length) {
Alan Coxf035a8a2008-07-22 11:13:32 +0100474 tty_insert_flip_string(tty, data, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 tty_flip_buffer_push(tty);
476 }
Alan Cox4a90f092008-10-13 10:39:46 +0100477 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
479 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500480 err = usb_submit_urb(urb, GFP_ATOMIC);
481 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700482 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
Alan Stern1f871582010-02-17 10:05:47 -0500483 __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 p_priv->in_flip ^= 1;
485
486 urb = p_priv->in_urbs[p_priv->in_flip];
487 } while (urb->status != -EINPROGRESS);
488}
489
David Howells7d12e782006-10-05 14:55:46 +0100490static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493
David Howells7d12e782006-10-05 14:55:46 +0100494static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
496 struct usb_serial_port *port;
497 struct keyspan_port_private *p_priv;
498
Ming Leicdc97792008-02-24 18:41:47 +0800499 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 p_priv = usb_get_serial_port_data(port);
501
502 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700503 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100504 keyspan_usa28_send_setup(port->serial, port,
505 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 }
507}
508
David Howells7d12e782006-10-05 14:55:46 +0100509static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
511 int err;
512 unsigned char *data = urb->transfer_buffer;
513 struct keyspan_usa28_portStatusMessage *msg;
514 struct usb_serial *serial;
515 struct usb_serial_port *port;
516 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100517 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700519 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Ming Leicdc97792008-02-24 18:41:47 +0800521 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700523 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700524 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 return;
526 }
527
528 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700529 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 goto exit;
531 }
532
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700533 /*
534 dev_dbg(&urb->dev->dev,
Stefan Hubnera8ffa0b2012-12-13 22:45:00 +0100535 "%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__,
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700536 data[0], data[1], data[2], data[3], data[4], data[5],
537 data[6], data[7], data[8], data[9], data[10], data[11]);
538 */
Alan Coxdeb91682008-07-22 11:13:08 +0100539
540 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 msg = (struct keyspan_usa28_portStatusMessage *)data;
542
Alan Coxdeb91682008-07-22 11:13:08 +0100543 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700545 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 goto exit;
547 }
548 port = serial->port[msg->port];
549 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 /* Update handshaking pin state information */
552 old_dcd_state = p_priv->dcd_state;
553 p_priv->cts_state = ((msg->cts) ? 1 : 0);
554 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
555 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
556 p_priv->ri_state = ((msg->ri) ? 1 : 0);
557
Ben Minerdsddc04ae2012-07-12 00:10:18 +1000558 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
Alan Cox4a90f092008-10-13 10:39:46 +0100559 tty = tty_port_tty_get(&port->port);
Ben Minerds878b5fd2012-07-12 00:10:19 +1000560 if (tty && !C_CLOCAL(tty))
Alan Cox4a90f092008-10-13 10:39:46 +0100561 tty_hangup(tty);
562 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 }
564
565 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100566 err = usb_submit_urb(urb, GFP_ATOMIC);
567 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700568 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569exit: ;
570}
571
David Howells7d12e782006-10-05 14:55:46 +0100572static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574}
575
576
David Howells7d12e782006-10-05 14:55:46 +0100577static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
579 struct usb_serial *serial;
580 struct usb_serial_port *port;
581 struct keyspan_port_private *p_priv;
582 int i;
583
Ming Leicdc97792008-02-24 18:41:47 +0800584 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 for (i = 0; i < serial->num_ports; ++i) {
586 port = serial->port[i];
587 p_priv = usb_get_serial_port_data(port);
588
589 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700590 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100591 keyspan_usa49_send_setup(serial, port,
592 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 break;
594 }
595 }
596}
597
598 /* This is actually called glostat in the Keyspan
599 doco */
David Howells7d12e782006-10-05 14:55:46 +0100600static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
602 int err;
603 unsigned char *data = urb->transfer_buffer;
604 struct keyspan_usa49_portStatusMessage *msg;
605 struct usb_serial *serial;
606 struct usb_serial_port *port;
607 struct keyspan_port_private *p_priv;
608 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700609 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
Ming Leicdc97792008-02-24 18:41:47 +0800611 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700613 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700614 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 return;
616 }
617
Alan Coxdeb91682008-07-22 11:13:08 +0100618 if (urb->actual_length !=
619 sizeof(struct keyspan_usa49_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700620 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 goto exit;
622 }
623
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700624 /*
625 dev_dbg(&urb->dev->dev, "%s: %x %x %x %x %x %x %x %x %x %x %x",
626 __func__, data[0], data[1], data[2], data[3], data[4],
627 data[5], data[6], data[7], data[8], data[9], data[10]);
628 */
Alan Coxdeb91682008-07-22 11:13:08 +0100629
630 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 msg = (struct keyspan_usa49_portStatusMessage *)data;
632
Alan Coxdeb91682008-07-22 11:13:08 +0100633 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 if (msg->portNumber >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700635 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
636 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 goto exit;
638 }
639 port = serial->port[msg->portNumber];
640 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100641
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 /* Update handshaking pin state information */
643 old_dcd_state = p_priv->dcd_state;
644 p_priv->cts_state = ((msg->cts) ? 1 : 0);
645 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
646 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
647 p_priv->ri_state = ((msg->ri) ? 1 : 0);
648
Alan Cox4a90f092008-10-13 10:39:46 +0100649 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
650 struct tty_struct *tty = tty_port_tty_get(&port->port);
651 if (tty && !C_CLOCAL(tty))
652 tty_hangup(tty);
653 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
655
Alan Coxdeb91682008-07-22 11:13:08 +0100656 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100657 err = usb_submit_urb(urb, GFP_ATOMIC);
658 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700659 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660exit: ;
661}
662
David Howells7d12e782006-10-05 14:55:46 +0100663static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665}
666
David Howells7d12e782006-10-05 14:55:46 +0100667static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668{
669 int i, err;
670 int endpoint;
671 struct usb_serial_port *port;
672 struct tty_struct *tty;
673 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700674 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 endpoint = usb_pipeendpoint(urb->pipe);
677
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700678 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700679 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
680 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return;
682 }
683
Ming Leicdc97792008-02-24 18:41:47 +0800684 port = urb->context;
Alan Cox4a90f092008-10-13 10:39:46 +0100685 tty = tty_port_tty_get(&port->port);
Alan Cox3004e532008-01-03 16:59:04 +0000686 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 /* 0x80 bit is error flag */
688 if ((data[0] & 0x80) == 0) {
689 /* no error on any byte */
Alan Coxf035a8a2008-07-22 11:13:32 +0100690 tty_insert_flip_string(tty, data + 1,
691 urb->actual_length - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 } else {
693 /* some bytes had errors, every byte has status */
694 for (i = 0; i + 1 < urb->actual_length; i += 2) {
695 int stat = data[i], flag = 0;
696 if (stat & RXERROR_OVERRUN)
697 flag |= TTY_OVERRUN;
698 if (stat & RXERROR_FRAMING)
699 flag |= TTY_FRAME;
700 if (stat & RXERROR_PARITY)
701 flag |= TTY_PARITY;
702 /* XXX should handle break (0x10) */
703 tty_insert_flip_char(tty, data[i+1], flag);
704 }
705 }
706 tty_flip_buffer_push(tty);
707 }
Alan Cox4a90f092008-10-13 10:39:46 +0100708 tty_kref_put(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100709
710 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500711 err = usb_submit_urb(urb, GFP_ATOMIC);
712 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700713 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714}
715
Lucy McCoy0ca12682007-05-18 12:10:41 -0700716static void usa49wg_indat_callback(struct urb *urb)
717{
718 int i, len, x, err;
719 struct usb_serial *serial;
720 struct usb_serial_port *port;
721 struct tty_struct *tty;
722 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700723 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700724
Lucy McCoy0ca12682007-05-18 12:10:41 -0700725 serial = urb->context;
726
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700727 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700728 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700729 return;
730 }
731
732 /* inbound data is in the form P#, len, status, data */
733 i = 0;
734 len = 0;
735
736 if (urb->actual_length) {
737 while (i < urb->actual_length) {
738
739 /* Check port number from message*/
740 if (data[i] >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700741 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800742 __func__, data[i]);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700743 return;
744 }
745 port = serial->port[data[i++]];
Alan Cox4a90f092008-10-13 10:39:46 +0100746 tty = tty_port_tty_get(&port->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700747 len = data[i++];
748
749 /* 0x80 bit is error flag */
750 if ((data[i] & 0x80) == 0) {
751 /* no error on any byte */
752 i++;
753 for (x = 1; x < len ; ++x)
Alan Stern1f871582010-02-17 10:05:47 -0500754 tty_insert_flip_char(tty, data[i++], 0);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700755 } else {
756 /*
757 * some bytes had errors, every byte has status
758 */
759 for (x = 0; x + 1 < len; x += 2) {
760 int stat = data[i], flag = 0;
761 if (stat & RXERROR_OVERRUN)
762 flag |= TTY_OVERRUN;
763 if (stat & RXERROR_FRAMING)
764 flag |= TTY_FRAME;
765 if (stat & RXERROR_PARITY)
766 flag |= TTY_PARITY;
767 /* XXX should handle break (0x10) */
Alan Stern1f871582010-02-17 10:05:47 -0500768 tty_insert_flip_char(tty,
Lucy McCoy0ca12682007-05-18 12:10:41 -0700769 data[i+1], flag);
770 i += 2;
771 }
772 }
Alan Stern1f871582010-02-17 10:05:47 -0500773 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100774 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700775 }
776 }
777
778 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700779 err = usb_submit_urb(urb, GFP_ATOMIC);
780 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700781 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700782}
783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700785static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787}
788
Lucy McCoy0ca12682007-05-18 12:10:41 -0700789static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
791 int i, err;
792 int endpoint;
793 struct usb_serial_port *port;
794 struct keyspan_port_private *p_priv;
795 struct tty_struct *tty;
796 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700797 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 endpoint = usb_pipeendpoint(urb->pipe);
800
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700801 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700802 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800803 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 return;
805 }
806
Ming Leicdc97792008-02-24 18:41:47 +0800807 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 p_priv = usb_get_serial_port_data(port);
809
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 if (urb->actual_length) {
Alan Cox4a90f092008-10-13 10:39:46 +0100811 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100813 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
Alan Coxf035a8a2008-07-22 11:13:32 +0100815 if (p_priv->baud > 57600)
816 tty_insert_flip_string(tty, data, urb->actual_length);
817 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 /* 0x80 bit is error flag */
819 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100820 /* no errors on individual bytes, only
821 possible overrun err*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100823 err = TTY_OVERRUN;
824 else
825 err = 0;
826 for (i = 1; i < urb->actual_length ; ++i)
827 tty_insert_flip_char(tty, data[i],
828 err);
829 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700831 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 for (i = 0; i + 1 < urb->actual_length; i += 2) {
833 int stat = data[i], flag = 0;
834 if (stat & RXERROR_OVERRUN)
835 flag |= TTY_OVERRUN;
836 if (stat & RXERROR_FRAMING)
837 flag |= TTY_FRAME;
838 if (stat & RXERROR_PARITY)
839 flag |= TTY_PARITY;
840 /* XXX should handle break (0x10) */
Alan Coxdeb91682008-07-22 11:13:08 +0100841 tty_insert_flip_char(tty, data[i+1],
842 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 }
844 }
845 }
846 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100847 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 }
Alan Coxdeb91682008-07-22 11:13:08 +0100849
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500851 err = usb_submit_urb(urb, GFP_ATOMIC);
852 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700853 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854}
855
856
David Howells7d12e782006-10-05 14:55:46 +0100857static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858{
859 unsigned char *data = urb->transfer_buffer;
860 struct keyspan_usa90_portStatusMessage *msg;
861 struct usb_serial *serial;
862 struct usb_serial_port *port;
863 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100864 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700866 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
Ming Leicdc97792008-02-24 18:41:47 +0800868 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700870 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700871 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 return;
873 }
874 if (urb->actual_length < 14) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700875 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 goto exit;
877 }
878
879 msg = (struct keyspan_usa90_portStatusMessage *)data;
880
881 /* Now do something useful with the data */
882
883 port = serial->port[0];
884 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 /* Update handshaking pin state information */
887 old_dcd_state = p_priv->dcd_state;
888 p_priv->cts_state = ((msg->cts) ? 1 : 0);
889 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
890 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
891 p_priv->ri_state = ((msg->ri) ? 1 : 0);
892
Alan Cox4a90f092008-10-13 10:39:46 +0100893 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
894 tty = tty_port_tty_get(&port->port);
895 if (tty && !C_CLOCAL(tty))
896 tty_hangup(tty);
897 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 }
Alan Coxdeb91682008-07-22 11:13:08 +0100899
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100901 err = usb_submit_urb(urb, GFP_ATOMIC);
902 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700903 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904exit:
905 ;
906}
907
David Howells7d12e782006-10-05 14:55:46 +0100908static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909{
910 struct usb_serial_port *port;
911 struct keyspan_port_private *p_priv;
912
Ming Leicdc97792008-02-24 18:41:47 +0800913 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 p_priv = usb_get_serial_port_data(port);
915
916 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700917 dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100918 keyspan_usa90_send_setup(port->serial, port,
919 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 }
921}
922
Lucy McCoy0ca12682007-05-18 12:10:41 -0700923/* Status messages from the 28xg */
924static void usa67_instat_callback(struct urb *urb)
925{
926 int err;
927 unsigned char *data = urb->transfer_buffer;
928 struct keyspan_usa67_portStatusMessage *msg;
929 struct usb_serial *serial;
930 struct usb_serial_port *port;
931 struct keyspan_port_private *p_priv;
932 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700933 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700934
Lucy McCoy0ca12682007-05-18 12:10:41 -0700935 serial = urb->context;
936
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700937 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700938 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700939 return;
940 }
941
Alan Coxdeb91682008-07-22 11:13:08 +0100942 if (urb->actual_length !=
943 sizeof(struct keyspan_usa67_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700944 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700945 return;
946 }
947
948
949 /* Now do something useful with the data */
950 msg = (struct keyspan_usa67_portStatusMessage *)data;
951
952 /* Check port number from message and retrieve private data */
953 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700954 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700955 return;
956 }
957
958 port = serial->port[msg->port];
959 p_priv = usb_get_serial_port_data(port);
960
961 /* Update handshaking pin state information */
962 old_dcd_state = p_priv->dcd_state;
963 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
964 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
965
Alan Cox4a90f092008-10-13 10:39:46 +0100966 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
967 struct tty_struct *tty = tty_port_tty_get(&port->port);
968 if (tty && !C_CLOCAL(tty))
969 tty_hangup(tty);
970 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700971 }
972
973 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700974 err = usb_submit_urb(urb, GFP_ATOMIC);
975 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700976 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700977}
978
979static void usa67_glocont_callback(struct urb *urb)
980{
981 struct usb_serial *serial;
982 struct usb_serial_port *port;
983 struct keyspan_port_private *p_priv;
984 int i;
985
Lucy McCoy0ca12682007-05-18 12:10:41 -0700986 serial = urb->context;
987 for (i = 0; i < serial->num_ports; ++i) {
988 port = serial->port[i];
989 p_priv = usb_get_serial_port_data(port);
990
991 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700992 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700993 keyspan_usa67_send_setup(serial, port,
994 p_priv->resend_cont - 1);
995 break;
996 }
997 }
998}
999
Alan Cox95da3102008-07-22 11:09:07 +01001000static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001{
Alan Cox95da3102008-07-22 11:09:07 +01001002 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 struct keyspan_port_private *p_priv;
1004 const struct keyspan_device_details *d_details;
1005 int flip;
1006 int data_len;
1007 struct urb *this_urb;
1008
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 p_priv = usb_get_serial_port_data(port);
1010 d_details = p_priv->device_details;
1011
Alan Coxa5b6f602008-04-08 17:16:06 +01001012 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +01001014 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 else
1016 data_len = 63;
1017
1018 flip = p_priv->out_flip;
1019
1020 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +01001021 this_urb = p_priv->out_urbs[flip];
1022 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001024 return data_len;
1025 flip = (flip + 1) & d_details->outdat_endp_flip;
1026 this_urb = p_priv->out_urbs[flip];
1027 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001029 return data_len;
1030 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 }
Alan Coxa5b6f602008-04-08 17:16:06 +01001032 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033}
1034
1035
Alan Coxa509a7e2009-09-19 13:13:26 -07001036static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001038 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 const struct keyspan_device_details *d_details;
1040 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001041 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001043 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 p_priv = usb_get_serial_port_data(port);
1046 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001047
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 /* Set some sane defaults */
1049 p_priv->rts_state = 1;
1050 p_priv->dtr_state = 1;
1051 p_priv->baud = 9600;
1052
1053 /* force baud and lcr to be set on open */
1054 p_priv->old_baud = 0;
1055 p_priv->old_cflag = 0;
1056
1057 p_priv->out_flip = 0;
1058 p_priv->in_flip = 0;
1059
1060 /* Reset low level data toggle and start reading from endpoints */
1061 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001062 urb = p_priv->in_urbs[i];
1063 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Alan Coxdeb91682008-07-22 11:13:08 +01001066 /* make sure endpoint data toggle is synchronized
1067 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001069 err = usb_submit_urb(urb, GFP_KERNEL);
1070 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001071 dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 }
1073
1074 /* Reset low level data toggle on out endpoints */
1075 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001076 urb = p_priv->out_urbs[i];
1077 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 continue;
Alan Coxdeb91682008-07-22 11:13:08 +01001079 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1080 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 }
1082
Andrew Mortonf78ba152007-11-28 16:21:54 -08001083 /* get the terminal config for the setup message now so we don't
1084 * need to send 2 of them */
1085
Andrew Mortonf78ba152007-11-28 16:21:54 -08001086 device_port = port->number - port->serial->minor;
Alan Cox95da3102008-07-22 11:09:07 +01001087 if (tty) {
Alan Coxadc8d742012-07-14 15:31:47 +01001088 cflag = tty->termios.c_cflag;
Alan Cox95da3102008-07-22 11:09:07 +01001089 /* Baud rate calculation takes baud rate as an integer
1090 so other rates can be generated if desired. */
1091 baud_rate = tty_get_baud_rate(tty);
1092 /* If no match or invalid, leave as default */
1093 if (baud_rate >= 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001094 && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Alan Cox95da3102008-07-22 11:09:07 +01001095 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1096 p_priv->baud = baud_rate;
1097 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001098 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001099 /* set CTS/RTS handshake etc. */
1100 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +10001101 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001102
1103 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001104 /* mdelay(100); */
1105 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001106
Alan Coxa5b6f602008-04-08 17:16:06 +01001107 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108}
1109
1110static inline void stop_urb(struct urb *urb)
1111{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001112 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114}
1115
Alan Cox335f8512009-06-11 12:26:29 +01001116static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1117{
1118 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1119
1120 p_priv->rts_state = on;
1121 p_priv->dtr_state = on;
1122 keyspan_send_setup(port, 0);
1123}
1124
1125static void keyspan_close(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126{
1127 int i;
1128 struct usb_serial *serial = port->serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 struct keyspan_port_private *p_priv;
1130
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001132
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 p_priv->rts_state = 0;
1134 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 if (serial->dev) {
1137 keyspan_send_setup(port, 2);
1138 /* pilot-xfer seems to work best with this delay */
1139 mdelay(100);
Alan Coxdeb91682008-07-22 11:13:08 +01001140 /* keyspan_set_termios(port, NULL); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 }
1142
1143 /*while (p_priv->outcont_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001144 dev_dbg(&port->dev, "%s - urb in progress\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 }*/
1146
1147 p_priv->out_flip = 0;
1148 p_priv->in_flip = 0;
1149
1150 if (serial->dev) {
1151 /* Stop reading/writing urbs */
1152 stop_urb(p_priv->inack_urb);
1153 /* stop_urb(p_priv->outcont_urb); */
1154 for (i = 0; i < 2; i++) {
1155 stop_urb(p_priv->in_urbs[i]);
1156 stop_urb(p_priv->out_urbs[i]);
1157 }
1158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159}
1160
Alan Coxdeb91682008-07-22 11:13:08 +01001161/* download the firmware to a pre-renumeration device */
1162static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163{
Rene Buergel8d733e22012-09-18 09:02:01 +02001164 char *fw_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001166 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
1167 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1168 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001169
1170 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1171 != 0x8000) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001172 dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n");
Alan Coxdeb91682008-07-22 11:13:08 +01001173 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 }
1175
1176 /* Select firmware image on the basis of idProduct */
1177 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1178 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001179 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 break;
1181
1182 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001183 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 break;
1185
1186 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001187 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 break;
1189
1190 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001191 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 break;
1193
1194 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001195 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001197
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001199 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001201
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001203 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 break;
1205
1206 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001207 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001209
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001211 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001215 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001217
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001219 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 break;
1221
1222 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001223 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 break;
1225
1226 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001227 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1228 le16_to_cpu(serial->dev->descriptor.idProduct));
1229 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 }
1231
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001232 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Rene Buergel8d733e22012-09-18 09:02:01 +02001234 if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
1235 dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
1236 fw_name);
1237 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 }
1239
Rene Buergel8d733e22012-09-18 09:02:01 +02001240 /* after downloading firmware Renumeration will occur in a
1241 moment and the new device will bind to the real driver */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
1243 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001244 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245}
1246
1247/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001248static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1249 int endpoint)
1250{
1251 struct usb_host_interface *iface_desc;
1252 struct usb_endpoint_descriptor *ep;
1253 int i;
1254
1255 iface_desc = serial->interface->cur_altsetting;
1256 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1257 ep = &iface_desc->endpoint[i].desc;
1258 if (ep->bEndpointAddress == endpoint)
1259 return ep;
1260 }
1261 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1262 "endpoint %x\n", endpoint);
1263 return NULL;
1264}
1265
Alan Coxdeb91682008-07-22 11:13:08 +01001266static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001268 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269{
1270 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001271 struct usb_endpoint_descriptor const *ep_desc;
1272 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
1274 if (endpoint == -1)
1275 return NULL; /* endpoint not needed */
1276
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001277 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
1279 if (urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001280 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d failed.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 return NULL;
1282 }
1283
Lucy McCoy0ca12682007-05-18 12:10:41 -07001284 if (endpoint == 0) {
1285 /* control EP filled in when used */
1286 return urb;
1287 }
1288
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001289 ep_desc = find_ep(serial, endpoint);
1290 if (!ep_desc) {
1291 /* leak the urb, something's wrong and the callers don't care */
1292 return urb;
1293 }
1294 if (usb_endpoint_xfer_int(ep_desc)) {
1295 ep_type_name = "INT";
1296 usb_fill_int_urb(urb, serial->dev,
1297 usb_sndintpipe(serial->dev, endpoint) | dir,
1298 buf, len, callback, ctx,
1299 ep_desc->bInterval);
1300 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1301 ep_type_name = "BULK";
1302 usb_fill_bulk_urb(urb, serial->dev,
1303 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1304 buf, len, callback, ctx);
1305 } else {
1306 dev_warn(&serial->interface->dev,
1307 "unsupported endpoint type %x\n",
Julia Lawall2e0fe702008-12-29 11:22:14 +01001308 usb_endpoint_type(ep_desc));
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001309 usb_free_urb(urb);
1310 return NULL;
1311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001313 dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001314 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 return urb;
1316}
1317
1318static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001319 void (*instat_callback)(struct urb *);
1320 void (*glocont_callback)(struct urb *);
1321 void (*indat_callback)(struct urb *);
1322 void (*outdat_callback)(struct urb *);
1323 void (*inack_callback)(struct urb *);
1324 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325} keyspan_callbacks[] = {
1326 {
1327 /* msg_usa26 callbacks */
1328 .instat_callback = usa26_instat_callback,
1329 .glocont_callback = usa26_glocont_callback,
1330 .indat_callback = usa26_indat_callback,
1331 .outdat_callback = usa2x_outdat_callback,
1332 .inack_callback = usa26_inack_callback,
1333 .outcont_callback = usa26_outcont_callback,
1334 }, {
1335 /* msg_usa28 callbacks */
1336 .instat_callback = usa28_instat_callback,
1337 .glocont_callback = usa28_glocont_callback,
1338 .indat_callback = usa28_indat_callback,
1339 .outdat_callback = usa2x_outdat_callback,
1340 .inack_callback = usa28_inack_callback,
1341 .outcont_callback = usa28_outcont_callback,
1342 }, {
1343 /* msg_usa49 callbacks */
1344 .instat_callback = usa49_instat_callback,
1345 .glocont_callback = usa49_glocont_callback,
1346 .indat_callback = usa49_indat_callback,
1347 .outdat_callback = usa2x_outdat_callback,
1348 .inack_callback = usa49_inack_callback,
1349 .outcont_callback = usa49_outcont_callback,
1350 }, {
1351 /* msg_usa90 callbacks */
1352 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001353 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 .indat_callback = usa90_indat_callback,
1355 .outdat_callback = usa2x_outdat_callback,
1356 .inack_callback = usa28_inack_callback,
1357 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001358 }, {
1359 /* msg_usa67 callbacks */
1360 .instat_callback = usa67_instat_callback,
1361 .glocont_callback = usa67_glocont_callback,
1362 .indat_callback = usa26_indat_callback,
1363 .outdat_callback = usa2x_outdat_callback,
1364 .inack_callback = usa26_inack_callback,
1365 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 }
1367};
1368
1369 /* Generic setup urbs function that uses
1370 data in device_details */
1371static void keyspan_setup_urbs(struct usb_serial *serial)
1372{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 struct keyspan_serial_private *s_priv;
1374 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 struct callbacks *cback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 s_priv = usb_get_serial_data(serial);
1378 d_details = s_priv->device_details;
1379
Alan Coxdeb91682008-07-22 11:13:08 +01001380 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 cback = &keyspan_callbacks[d_details->msg_format];
1382
Alan Coxdeb91682008-07-22 11:13:08 +01001383 /* Allocate and set up urbs for each one that is in use,
1384 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 s_priv->instat_urb = keyspan_setup_urb
1386 (serial, d_details->instat_endpoint, USB_DIR_IN,
1387 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1388 cback->instat_callback);
1389
Lucy McCoy0ca12682007-05-18 12:10:41 -07001390 s_priv->indat_urb = keyspan_setup_urb
1391 (serial, d_details->indat_endpoint, USB_DIR_IN,
1392 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1393 usa49wg_indat_callback);
1394
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 s_priv->glocont_urb = keyspan_setup_urb
1396 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1397 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1398 cback->glocont_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399}
1400
1401/* usa19 function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001402static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1403 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 u8 *rate_low, u8 *prescaler, int portnum)
1405{
1406 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001407 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001410 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Alan Coxdeb91682008-07-22 11:13:08 +01001412 /* prevent divide by zero... */
1413 b16 = baud_rate * 16L;
1414 if (b16 == 0)
1415 return KEYSPAN_INVALID_BAUD_RATE;
1416 /* Any "standard" rate over 57k6 is marginal on the USA-19
1417 as we run out of divisor resolution. */
1418 if (baud_rate > 57600)
1419 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
Alan Coxdeb91682008-07-22 11:13:08 +01001421 /* calculate the divisor and the counter (its inverse) */
1422 div = baudclk / b16;
1423 if (div == 0)
1424 return KEYSPAN_INVALID_BAUD_RATE;
1425 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
Alan Coxdeb91682008-07-22 11:13:08 +01001428 if (div > 0xffff)
1429 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
Alan Coxdeb91682008-07-22 11:13:08 +01001431 /* return the counter values if non-null */
1432 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001434 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001436 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001437 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001438 __func__, baud_rate, *rate_hi, *rate_low);
1439 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440}
1441
1442/* usa19hs function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001443static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1444 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1445 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446{
1447 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001448 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001450 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
Alan Coxdeb91682008-07-22 11:13:08 +01001452 /* prevent divide by zero... */
1453 b16 = baud_rate * 16L;
1454 if (b16 == 0)
1455 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456
Alan Coxdeb91682008-07-22 11:13:08 +01001457 /* calculate the divisor */
1458 div = baudclk / b16;
1459 if (div == 0)
1460 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Alan Coxdeb91682008-07-22 11:13:08 +01001462 if (div > 0xffff)
1463 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Alan Coxdeb91682008-07-22 11:13:08 +01001465 /* return the counter values if non-null */
1466 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001468
1469 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001471
1472 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001473 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001474 __func__, baud_rate, *rate_hi, *rate_low);
1475
1476 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477}
1478
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001479static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1480 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 u8 *rate_low, u8 *prescaler, int portnum)
1482{
1483 u32 b16, /* baud rate times 16 (actual rate used internally) */
1484 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001485 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 res, /* resulting baud rate using 13/8 prescaler */
1487 diff, /* error using 13/8 prescaler */
1488 smallest_diff;
1489 u8 best_prescaler;
1490 int i;
1491
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001492 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493
Alan Coxdeb91682008-07-22 11:13:08 +01001494 /* prevent divide by zero */
1495 b16 = baud_rate * 16L;
1496 if (b16 == 0)
1497 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
Alan Coxdeb91682008-07-22 11:13:08 +01001499 /* Calculate prescaler by trying them all and looking
1500 for best fit */
1501
1502 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 smallest_diff = 0xffffffff;
1504
1505 /* 0 is an invalid prescaler, used as a flag */
1506 best_prescaler = 0;
1507
Alan Coxdeb91682008-07-22 11:13:08 +01001508 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001510
1511 div = clk / b16;
1512 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514
1515 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001516 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
Alan Coxdeb91682008-07-22 11:13:08 +01001518 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 best_prescaler = i;
1520 smallest_diff = diff;
1521 }
1522 }
1523
Alan Coxdeb91682008-07-22 11:13:08 +01001524 if (best_prescaler == 0)
1525 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
1527 clk = (baudclk * 8) / (u32) best_prescaler;
1528 div = clk / b16;
1529
Alan Coxdeb91682008-07-22 11:13:08 +01001530 /* return the divisor and prescaler if non-null */
1531 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001533 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 if (prescaler) {
1536 *prescaler = best_prescaler;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001537 /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 }
Alan Coxdeb91682008-07-22 11:13:08 +01001539 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540}
1541
1542 /* USA-28 supports different maximum baud rates on each port */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001543static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1544 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1545 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546{
1547 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001548 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 cnt; /* inverse of divisor (programmed into 8051) */
1550
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001551 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
1553 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001554 b16 = baud_rate * 16L;
1555 if (b16 == 0)
1556 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557
Alan Coxdeb91682008-07-22 11:13:08 +01001558 /* calculate the divisor and the counter (its inverse) */
1559 div = KEYSPAN_USA28_BAUDCLK / b16;
1560 if (div == 0)
1561 return KEYSPAN_INVALID_BAUD_RATE;
1562 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
Alan Coxdeb91682008-07-22 11:13:08 +01001565 /* check for out of range, based on portnum,
1566 and return result */
1567 if (portnum == 0) {
1568 if (div > 0xffff)
1569 return KEYSPAN_INVALID_BAUD_RATE;
1570 } else {
1571 if (portnum == 1) {
1572 if (div > 0xff)
1573 return KEYSPAN_INVALID_BAUD_RATE;
1574 } else
1575 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 }
1577
1578 /* return the counter values if not NULL
1579 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001580 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001582 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001584 dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
Alan Coxdeb91682008-07-22 11:13:08 +01001585 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586}
1587
1588static int keyspan_usa26_send_setup(struct usb_serial *serial,
1589 struct usb_serial_port *port,
1590 int reset_port)
1591{
Alan Coxdeb91682008-07-22 11:13:08 +01001592 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 struct keyspan_serial_private *s_priv;
1594 struct keyspan_port_private *p_priv;
1595 const struct keyspan_device_details *d_details;
1596 int outcont_urb;
1597 struct urb *this_urb;
1598 int device_port, err;
1599
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001600 dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
1602 s_priv = usb_get_serial_data(serial);
1603 p_priv = usb_get_serial_port_data(port);
1604 d_details = s_priv->device_details;
1605 device_port = port->number - port->serial->minor;
1606
1607 outcont_urb = d_details->outcont_endpoints[port->number];
1608 this_urb = p_priv->outcont_urb;
1609
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001610 dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
1612 /* Make sure we have an urb then send the message */
1613 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001614 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 return -1;
1616 }
1617
1618 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001619 Don't overwrite resend for open/close condition. */
1620 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 p_priv->resend_cont = reset_port + 1;
1622 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001623 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001625 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 }
1627
Alan Coxdeb91682008-07-22 11:13:08 +01001628 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1629
1630 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 if (p_priv->old_baud != p_priv->baud) {
1632 p_priv->old_baud = p_priv->baud;
1633 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001634 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1635 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1636 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1637 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1638 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 msg.baudLo = 0;
1640 msg.baudHi = 125; /* Values for 9600 baud */
1641 msg.prescaler = 10;
1642 }
1643 msg.setPrescaler = 0xff;
1644 }
1645
Ben Minerds2b982ab2012-07-12 00:10:16 +10001646 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 switch (p_priv->cflag & CSIZE) {
1648 case CS5:
1649 msg.lcr |= USA_DATABITS_5;
1650 break;
1651 case CS6:
1652 msg.lcr |= USA_DATABITS_6;
1653 break;
1654 case CS7:
1655 msg.lcr |= USA_DATABITS_7;
1656 break;
1657 case CS8:
1658 msg.lcr |= USA_DATABITS_8;
1659 break;
1660 }
1661 if (p_priv->cflag & PARENB) {
1662 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001663 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001664 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 }
1666 msg.setLcr = 0xff;
1667
1668 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1669 msg.xonFlowControl = 0;
1670 msg.setFlowControl = 0xff;
1671 msg.forwardingLength = 16;
1672 msg.xonChar = 17;
1673 msg.xoffChar = 19;
1674
1675 /* Opening port */
1676 if (reset_port == 1) {
1677 msg._txOn = 1;
1678 msg._txOff = 0;
1679 msg.txFlush = 0;
1680 msg.txBreak = 0;
1681 msg.rxOn = 1;
1682 msg.rxOff = 0;
1683 msg.rxFlush = 1;
1684 msg.rxForward = 0;
1685 msg.returnStatus = 0;
1686 msg.resetDataToggle = 0xff;
1687 }
1688
1689 /* Closing port */
1690 else if (reset_port == 2) {
1691 msg._txOn = 0;
1692 msg._txOff = 1;
1693 msg.txFlush = 0;
1694 msg.txBreak = 0;
1695 msg.rxOn = 0;
1696 msg.rxOff = 1;
1697 msg.rxFlush = 1;
1698 msg.rxForward = 0;
1699 msg.returnStatus = 0;
1700 msg.resetDataToggle = 0;
1701 }
1702
1703 /* Sending intermediate configs */
1704 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001705 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 msg._txOff = 0;
1707 msg.txFlush = 0;
1708 msg.txBreak = (p_priv->break_on);
1709 msg.rxOn = 0;
1710 msg.rxOff = 0;
1711 msg.rxFlush = 0;
1712 msg.rxForward = 0;
1713 msg.returnStatus = 0;
1714 msg.resetDataToggle = 0x0;
1715 }
1716
Alan Coxdeb91682008-07-22 11:13:08 +01001717 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 msg.setTxTriState_setRts = 0xff;
1719 msg.txTriState_rts = p_priv->rts_state;
1720
1721 msg.setHskoa_setDtr = 0xff;
1722 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001723
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001725 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1726
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 /* send the data out the device on control endpoint */
1728 this_urb->transfer_buffer_length = sizeof(msg);
1729
Alan Coxdeb91682008-07-22 11:13:08 +01001730 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1731 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001732 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733#if 0
1734 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001735 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__
1736 outcont_urb, this_urb->transfer_buffer_length,
1737 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 }
1739#endif
1740
Alan Coxa5b6f602008-04-08 17:16:06 +01001741 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742}
1743
1744static int keyspan_usa28_send_setup(struct usb_serial *serial,
1745 struct usb_serial_port *port,
1746 int reset_port)
1747{
Alan Coxdeb91682008-07-22 11:13:08 +01001748 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 struct keyspan_serial_private *s_priv;
1750 struct keyspan_port_private *p_priv;
1751 const struct keyspan_device_details *d_details;
1752 struct urb *this_urb;
1753 int device_port, err;
1754
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 s_priv = usb_get_serial_data(serial);
1756 p_priv = usb_get_serial_port_data(port);
1757 d_details = s_priv->device_details;
1758 device_port = port->number - port->serial->minor;
1759
1760 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001761 this_urb = p_priv->outcont_urb;
1762 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001763 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 return -1;
1765 }
1766
1767 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001768 Don't overwrite resend for open/close condition. */
1769 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 p_priv->resend_cont = reset_port + 1;
1771 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001772 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001774 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 }
1776
Alan Coxdeb91682008-07-22 11:13:08 +01001777 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778
1779 msg.setBaudRate = 1;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001780 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1781 &msg.baudHi, &msg.baudLo, NULL,
1782 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1783 dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001784 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 msg.baudLo = 0xff;
1786 msg.baudHi = 0xb2; /* Values for 9600 baud */
1787 }
1788
1789 /* If parity is enabled, we must calculate it ourselves. */
1790 msg.parity = 0; /* XXX for now */
1791
1792 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1793 msg.xonFlowControl = 0;
1794
Alan Coxdeb91682008-07-22 11:13:08 +01001795 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 msg.rts = p_priv->rts_state;
1797 msg.dtr = p_priv->dtr_state;
1798
1799 msg.forwardingLength = 16;
1800 msg.forwardMs = 10;
1801 msg.breakThreshold = 45;
1802 msg.xonChar = 17;
1803 msg.xoffChar = 19;
1804
1805 /*msg.returnStatus = 1;
1806 msg.resetDataToggle = 0xff;*/
1807 /* Opening port */
1808 if (reset_port == 1) {
1809 msg._txOn = 1;
1810 msg._txOff = 0;
1811 msg.txFlush = 0;
1812 msg.txForceXoff = 0;
1813 msg.txBreak = 0;
1814 msg.rxOn = 1;
1815 msg.rxOff = 0;
1816 msg.rxFlush = 1;
1817 msg.rxForward = 0;
1818 msg.returnStatus = 0;
1819 msg.resetDataToggle = 0xff;
1820 }
1821 /* Closing port */
1822 else if (reset_port == 2) {
1823 msg._txOn = 0;
1824 msg._txOff = 1;
1825 msg.txFlush = 0;
1826 msg.txForceXoff = 0;
1827 msg.txBreak = 0;
1828 msg.rxOn = 0;
1829 msg.rxOff = 1;
1830 msg.rxFlush = 1;
1831 msg.rxForward = 0;
1832 msg.returnStatus = 0;
1833 msg.resetDataToggle = 0;
1834 }
1835 /* Sending intermediate configs */
1836 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001837 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 msg._txOff = 0;
1839 msg.txFlush = 0;
1840 msg.txForceXoff = 0;
1841 msg.txBreak = (p_priv->break_on);
1842 msg.rxOn = 0;
1843 msg.rxOff = 0;
1844 msg.rxFlush = 0;
1845 msg.rxForward = 0;
1846 msg.returnStatus = 0;
1847 msg.resetDataToggle = 0x0;
1848 }
1849
1850 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001851 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
1853 /* send the data out the device on control endpoint */
1854 this_urb->transfer_buffer_length = sizeof(msg);
1855
Alan Coxdeb91682008-07-22 11:13:08 +01001856 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1857 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001858 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859#if 0
1860 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001861 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 this_urb->transfer_buffer_length);
1863 }
1864#endif
1865
Alan Coxa5b6f602008-04-08 17:16:06 +01001866 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867}
1868
1869static int keyspan_usa49_send_setup(struct usb_serial *serial,
1870 struct usb_serial_port *port,
1871 int reset_port)
1872{
Lucy McCoy0ca12682007-05-18 12:10:41 -07001873 struct keyspan_usa49_portControlMessage msg;
1874 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 struct keyspan_serial_private *s_priv;
1876 struct keyspan_port_private *p_priv;
1877 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 struct urb *this_urb;
1879 int err, device_port;
1880
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 s_priv = usb_get_serial_data(serial);
1882 p_priv = usb_get_serial_port_data(port);
1883 d_details = s_priv->device_details;
1884
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 this_urb = s_priv->glocont_urb;
1886
Lucy McCoy0ca12682007-05-18 12:10:41 -07001887 /* Work out which port within the device is being setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 device_port = port->number - port->serial->minor;
1889
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301890 /* Make sure we have an urb then send the message */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001892 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 return -1;
1894 }
1895
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001896 dev_dbg(&port->dev, "%s - endpoint %d port %d (%d)\n",
1897 __func__, usb_pipeendpoint(this_urb->pipe),
1898 port->number, device_port);
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301899
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001901 Don't overwrite resend for open/close condition. */
1902 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001904
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001906 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001908 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 }
1910
Alan Coxdeb91682008-07-22 11:13:08 +01001911 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
1913 /*msg.portNumber = port->number;*/
1914 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01001915
1916 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 if (p_priv->old_baud != p_priv->baud) {
1918 p_priv->old_baud = p_priv->baud;
1919 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001920 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1921 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1922 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1923 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1924 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 msg.baudLo = 0;
1926 msg.baudHi = 125; /* Values for 9600 baud */
1927 msg.prescaler = 10;
1928 }
Alan Coxdeb91682008-07-22 11:13:08 +01001929 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 }
1931
Ben Minerds2b982ab2012-07-12 00:10:16 +10001932 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 switch (p_priv->cflag & CSIZE) {
1934 case CS5:
1935 msg.lcr |= USA_DATABITS_5;
1936 break;
1937 case CS6:
1938 msg.lcr |= USA_DATABITS_6;
1939 break;
1940 case CS7:
1941 msg.lcr |= USA_DATABITS_7;
1942 break;
1943 case CS8:
1944 msg.lcr |= USA_DATABITS_8;
1945 break;
1946 }
1947 if (p_priv->cflag & PARENB) {
1948 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001949 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001950 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 }
1952 msg.setLcr = 0xff;
1953
1954 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1955 msg.xonFlowControl = 0;
1956 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01001957
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 msg.forwardingLength = 16;
1959 msg.xonChar = 17;
1960 msg.xoffChar = 19;
1961
Alan Coxdeb91682008-07-22 11:13:08 +01001962 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 if (reset_port == 1) {
1964 msg._txOn = 1;
1965 msg._txOff = 0;
1966 msg.txFlush = 0;
1967 msg.txBreak = 0;
1968 msg.rxOn = 1;
1969 msg.rxOff = 0;
1970 msg.rxFlush = 1;
1971 msg.rxForward = 0;
1972 msg.returnStatus = 0;
1973 msg.resetDataToggle = 0xff;
1974 msg.enablePort = 1;
1975 msg.disablePort = 0;
1976 }
1977 /* Closing port */
1978 else if (reset_port == 2) {
1979 msg._txOn = 0;
1980 msg._txOff = 1;
1981 msg.txFlush = 0;
1982 msg.txBreak = 0;
1983 msg.rxOn = 0;
1984 msg.rxOff = 1;
1985 msg.rxFlush = 1;
1986 msg.rxForward = 0;
1987 msg.returnStatus = 0;
1988 msg.resetDataToggle = 0;
1989 msg.enablePort = 0;
1990 msg.disablePort = 1;
1991 }
1992 /* Sending intermediate configs */
1993 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001994 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 msg._txOff = 0;
1996 msg.txFlush = 0;
1997 msg.txBreak = (p_priv->break_on);
1998 msg.rxOn = 0;
1999 msg.rxOff = 0;
2000 msg.rxFlush = 0;
2001 msg.rxForward = 0;
2002 msg.returnStatus = 0;
2003 msg.resetDataToggle = 0x0;
2004 msg.enablePort = 0;
2005 msg.disablePort = 0;
2006 }
2007
Alan Coxdeb91682008-07-22 11:13:08 +01002008 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 msg.setRts = 0xff;
2010 msg.rts = p_priv->rts_state;
2011
2012 msg.setDtr = 0xff;
2013 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002014
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
Alan Coxdeb91682008-07-22 11:13:08 +01002017 /* if the device is a 49wg, we send control message on usb
2018 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002019
2020 if (d_details->product_id == keyspan_usa49wg_product_id) {
2021 dr = (void *)(s_priv->ctrl_buf);
2022 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
2023 dr->bRequest = 0xB0; /* 49wg control message */;
2024 dr->wValue = 0;
2025 dr->wIndex = 0;
2026 dr->wLength = cpu_to_le16(sizeof(msg));
2027
Alan Coxdeb91682008-07-22 11:13:08 +01002028 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07002029
Alan Coxdeb91682008-07-22 11:13:08 +01002030 usb_fill_control_urb(this_urb, serial->dev,
2031 usb_sndctrlpipe(serial->dev, 0),
2032 (unsigned char *)dr, s_priv->glocont_buf,
2033 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002034
2035 } else {
2036 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01002037
Lucy McCoy0ca12682007-05-18 12:10:41 -07002038 /* send the data out the device on control endpoint */
2039 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002040 }
Alan Coxdeb91682008-07-22 11:13:08 +01002041 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2042 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002043 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044#if 0
2045 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002046 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__,
2047 outcont_urb, this_urb->transfer_buffer_length,
2048 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 }
2050#endif
2051
Alan Coxa5b6f602008-04-08 17:16:06 +01002052 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053}
2054
2055static int keyspan_usa90_send_setup(struct usb_serial *serial,
2056 struct usb_serial_port *port,
2057 int reset_port)
2058{
Alan Coxdeb91682008-07-22 11:13:08 +01002059 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 struct keyspan_serial_private *s_priv;
2061 struct keyspan_port_private *p_priv;
2062 const struct keyspan_device_details *d_details;
2063 struct urb *this_urb;
2064 int err;
2065 u8 prescaler;
2066
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 s_priv = usb_get_serial_data(serial);
2068 p_priv = usb_get_serial_port_data(port);
2069 d_details = s_priv->device_details;
2070
2071 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002072 this_urb = p_priv->outcont_urb;
2073 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002074 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 return -1;
2076 }
2077
2078 /* Save reset port val for resend.
2079 Don't overwrite resend for open/close condition. */
2080 if ((reset_port + 1) > p_priv->resend_cont)
2081 p_priv->resend_cont = reset_port + 1;
2082 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002083 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002085 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 }
2087
Alan Coxdeb91682008-07-22 11:13:08 +01002088 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089
Alan Coxdeb91682008-07-22 11:13:08 +01002090 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 if (p_priv->old_baud != p_priv->baud) {
2092 p_priv->old_baud = p_priv->baud;
2093 msg.setClocking = 0x01;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002094 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2095 &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2096 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2097 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 p_priv->baud = 9600;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002099 d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2101 }
2102 msg.setRxMode = 1;
2103 msg.setTxMode = 1;
2104 }
2105
2106 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002107 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 msg.rxMode = RXMODE_DMA;
2109 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002110 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 msg.rxMode = RXMODE_BYHAND;
2112 msg.txMode = TXMODE_BYHAND;
2113 }
2114
Ben Minerds2b982ab2012-07-12 00:10:16 +10002115 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 switch (p_priv->cflag & CSIZE) {
2117 case CS5:
2118 msg.lcr |= USA_DATABITS_5;
2119 break;
2120 case CS6:
2121 msg.lcr |= USA_DATABITS_6;
2122 break;
2123 case CS7:
2124 msg.lcr |= USA_DATABITS_7;
2125 break;
2126 case CS8:
2127 msg.lcr |= USA_DATABITS_8;
2128 break;
2129 }
2130 if (p_priv->cflag & PARENB) {
2131 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002132 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002133 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 }
2135 if (p_priv->old_cflag != p_priv->cflag) {
2136 p_priv->old_cflag = p_priv->cflag;
2137 msg.setLcr = 0x01;
2138 }
2139
2140 if (p_priv->flow_control == flow_cts)
2141 msg.txFlowControl = TXFLOW_CTS;
2142 msg.setTxFlowControl = 0x01;
2143 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002144
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002146 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 msg.txAckSetting = 0;
2148 msg.xonChar = 17;
2149 msg.xoffChar = 19;
2150
Alan Coxdeb91682008-07-22 11:13:08 +01002151 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 if (reset_port == 1) {
2153 msg.portEnabled = 1;
2154 msg.rxFlush = 1;
2155 msg.txBreak = (p_priv->break_on);
2156 }
2157 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002158 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 /* Sending intermediate configs */
2161 else {
Alan Stern1f871582010-02-17 10:05:47 -05002162 msg.portEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 msg.txBreak = (p_priv->break_on);
2164 }
2165
Alan Coxdeb91682008-07-22 11:13:08 +01002166 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 msg.setRts = 0x01;
2168 msg.rts = p_priv->rts_state;
2169
2170 msg.setDtr = 0x01;
2171 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002172
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002174 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2175
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 /* send the data out the device on control endpoint */
2177 this_urb->transfer_buffer_length = sizeof(msg);
2178
Alan Coxdeb91682008-07-22 11:13:08 +01002179 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2180 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002181 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002182 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183}
2184
Lucy McCoy0ca12682007-05-18 12:10:41 -07002185static int keyspan_usa67_send_setup(struct usb_serial *serial,
2186 struct usb_serial_port *port,
2187 int reset_port)
2188{
2189 struct keyspan_usa67_portControlMessage msg;
2190 struct keyspan_serial_private *s_priv;
2191 struct keyspan_port_private *p_priv;
2192 const struct keyspan_device_details *d_details;
2193 struct urb *this_urb;
2194 int err, device_port;
2195
Lucy McCoy0ca12682007-05-18 12:10:41 -07002196 s_priv = usb_get_serial_data(serial);
2197 p_priv = usb_get_serial_port_data(port);
2198 d_details = s_priv->device_details;
2199
2200 this_urb = s_priv->glocont_urb;
2201
2202 /* Work out which port within the device is being setup */
2203 device_port = port->number - port->serial->minor;
2204
2205 /* Make sure we have an urb then send the message */
2206 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002207 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002208 port->number);
2209 return -1;
2210 }
2211
2212 /* Save reset port val for resend.
2213 Don't overwrite resend for open/close condition. */
2214 if ((reset_port + 1) > p_priv->resend_cont)
2215 p_priv->resend_cont = reset_port + 1;
2216 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002217 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002218 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002219 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002220 }
2221
2222 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2223
2224 msg.port = device_port;
2225
2226 /* Only set baud rate if it's changed */
2227 if (p_priv->old_baud != p_priv->baud) {
2228 p_priv->old_baud = p_priv->baud;
2229 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002230 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2231 &msg.baudHi, &msg.baudLo, &msg.prescaler,
2232 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2233 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2234 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002235 msg.baudLo = 0;
2236 msg.baudHi = 125; /* Values for 9600 baud */
2237 msg.prescaler = 10;
2238 }
2239 msg.setPrescaler = 0xff;
2240 }
2241
2242 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2243 switch (p_priv->cflag & CSIZE) {
2244 case CS5:
2245 msg.lcr |= USA_DATABITS_5;
2246 break;
2247 case CS6:
2248 msg.lcr |= USA_DATABITS_6;
2249 break;
2250 case CS7:
2251 msg.lcr |= USA_DATABITS_7;
2252 break;
2253 case CS8:
2254 msg.lcr |= USA_DATABITS_8;
2255 break;
2256 }
2257 if (p_priv->cflag & PARENB) {
2258 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002259 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002260 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002261 }
2262 msg.setLcr = 0xff;
2263
2264 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2265 msg.xonFlowControl = 0;
2266 msg.setFlowControl = 0xff;
2267 msg.forwardingLength = 16;
2268 msg.xonChar = 17;
2269 msg.xoffChar = 19;
2270
2271 if (reset_port == 1) {
2272 /* Opening port */
2273 msg._txOn = 1;
2274 msg._txOff = 0;
2275 msg.txFlush = 0;
2276 msg.txBreak = 0;
2277 msg.rxOn = 1;
2278 msg.rxOff = 0;
2279 msg.rxFlush = 1;
2280 msg.rxForward = 0;
2281 msg.returnStatus = 0;
2282 msg.resetDataToggle = 0xff;
2283 } else if (reset_port == 2) {
2284 /* Closing port */
2285 msg._txOn = 0;
2286 msg._txOff = 1;
2287 msg.txFlush = 0;
2288 msg.txBreak = 0;
2289 msg.rxOn = 0;
2290 msg.rxOff = 1;
2291 msg.rxFlush = 1;
2292 msg.rxForward = 0;
2293 msg.returnStatus = 0;
2294 msg.resetDataToggle = 0;
2295 } else {
2296 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002297 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002298 msg._txOff = 0;
2299 msg.txFlush = 0;
2300 msg.txBreak = (p_priv->break_on);
2301 msg.rxOn = 0;
2302 msg.rxOff = 0;
2303 msg.rxFlush = 0;
2304 msg.rxForward = 0;
2305 msg.returnStatus = 0;
2306 msg.resetDataToggle = 0x0;
2307 }
2308
2309 /* Do handshaking outputs */
2310 msg.setTxTriState_setRts = 0xff;
2311 msg.txTriState_rts = p_priv->rts_state;
2312
2313 msg.setHskoa_setDtr = 0xff;
2314 msg.hskoa_dtr = p_priv->dtr_state;
2315
2316 p_priv->resend_cont = 0;
2317
2318 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2319
2320 /* send the data out the device on control endpoint */
2321 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002322
2323 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2324 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002325 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002326 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002327}
2328
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2330{
2331 struct usb_serial *serial = port->serial;
2332 struct keyspan_serial_private *s_priv;
2333 const struct keyspan_device_details *d_details;
2334
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 s_priv = usb_get_serial_data(serial);
2336 d_details = s_priv->device_details;
2337
2338 switch (d_details->msg_format) {
2339 case msg_usa26:
2340 keyspan_usa26_send_setup(serial, port, reset_port);
2341 break;
2342 case msg_usa28:
2343 keyspan_usa28_send_setup(serial, port, reset_port);
2344 break;
2345 case msg_usa49:
2346 keyspan_usa49_send_setup(serial, port, reset_port);
2347 break;
2348 case msg_usa90:
2349 keyspan_usa90_send_setup(serial, port, reset_port);
2350 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002351 case msg_usa67:
2352 keyspan_usa67_send_setup(serial, port, reset_port);
2353 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 }
2355}
2356
2357
2358/* Gets called by the "real" driver (ie once firmware is loaded
2359 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002360static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361{
2362 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 const struct keyspan_device_details *d_details;
2365
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002367 if (d_details->product_id ==
2368 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 break;
2370 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002371 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2372 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 return 1;
2374 }
2375
2376 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002377 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 if (!s_priv) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002379 dev_dbg(&serial->dev->dev, "%s - kmalloc for keyspan_serial_private failed.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 return -ENOMEM;
2381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
2383 s_priv->device_details = d_details;
2384 usb_set_serial_data(serial, s_priv);
2385
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 keyspan_setup_urbs(serial);
2387
Lucy McCoy0ca12682007-05-18 12:10:41 -07002388 if (s_priv->instat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002389 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2390 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002391 dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002392 }
2393 if (s_priv->indat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002394 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2395 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002396 dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 }
Alan Coxdeb91682008-07-22 11:13:08 +01002398
Alan Coxa5b6f602008-04-08 17:16:06 +01002399 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400}
2401
Alan Sternf9c99bb2009-06-02 11:53:55 -04002402static void keyspan_disconnect(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002404 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 s_priv = usb_get_serial_data(serial);
2407
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 stop_urb(s_priv->instat_urb);
2409 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002410 stop_urb(s_priv->indat_urb);
Alan Sternf9c99bb2009-06-02 11:53:55 -04002411}
2412
2413static void keyspan_release(struct usb_serial *serial)
2414{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002415 struct keyspan_serial_private *s_priv;
Alan Sternf9c99bb2009-06-02 11:53:55 -04002416
Alan Sternf9c99bb2009-06-02 11:53:55 -04002417 s_priv = usb_get_serial_data(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002419 usb_free_urb(s_priv->instat_urb);
2420 usb_free_urb(s_priv->indat_urb);
2421 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002423 kfree(s_priv);
2424}
2425
2426static int keyspan_port_probe(struct usb_serial_port *port)
2427{
2428 struct usb_serial *serial = port->serial;
Bjørn Morkf0e3e352012-11-10 10:13:42 +01002429 struct keyspan_serial_private *s_priv;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002430 struct keyspan_port_private *p_priv;
2431 const struct keyspan_device_details *d_details;
2432 struct callbacks *cback;
2433 int endp;
2434 int port_num;
2435 int i;
2436
2437 s_priv = usb_get_serial_data(serial);
2438 d_details = s_priv->device_details;
2439
2440 p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL);
2441 if (!p_priv)
2442 return -ENOMEM;
2443
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002444 p_priv->device_details = d_details;
2445
2446 /* Setup values for the various callback routines */
2447 cback = &keyspan_callbacks[d_details->msg_format];
2448
2449 port_num = port->number - port->serial->minor;
2450
2451 /* Do indat endpoints first, once for each flip */
2452 endp = d_details->indat_endpoints[port_num];
2453 for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
2454 p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
2455 USB_DIR_IN, port,
2456 p_priv->in_buffer[i], 64,
2457 cback->indat_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 }
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002459 /* outdat endpoints also have flip */
2460 endp = d_details->outdat_endpoints[port_num];
2461 for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
2462 p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
2463 USB_DIR_OUT, port,
2464 p_priv->out_buffer[i], 64,
2465 cback->outdat_callback);
2466 }
2467 /* inack endpoint */
2468 p_priv->inack_urb = keyspan_setup_urb(serial,
2469 d_details->inack_endpoints[port_num],
2470 USB_DIR_IN, port,
2471 p_priv->inack_buffer, 1,
2472 cback->inack_callback);
2473 /* outcont endpoint */
2474 p_priv->outcont_urb = keyspan_setup_urb(serial,
2475 d_details->outcont_endpoints[port_num],
2476 USB_DIR_OUT, port,
2477 p_priv->outcont_buffer, 64,
2478 cback->outcont_callback);
2479
2480 usb_set_serial_port_data(port, p_priv);
2481
2482 return 0;
2483}
2484
2485static int keyspan_port_remove(struct usb_serial_port *port)
2486{
2487 struct keyspan_port_private *p_priv;
2488 int i;
2489
2490 p_priv = usb_get_serial_port_data(port);
2491
2492 stop_urb(p_priv->inack_urb);
2493 stop_urb(p_priv->outcont_urb);
2494 for (i = 0; i < 2; i++) {
2495 stop_urb(p_priv->in_urbs[i]);
2496 stop_urb(p_priv->out_urbs[i]);
2497 }
2498
2499 usb_free_urb(p_priv->inack_urb);
2500 usb_free_urb(p_priv->outcont_urb);
2501 for (i = 0; i < 2; i++) {
2502 usb_free_urb(p_priv->in_urbs[i]);
2503 usb_free_urb(p_priv->out_urbs[i]);
2504 }
2505
2506 kfree(p_priv);
2507
2508 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509}
2510
Alan Coxdeb91682008-07-22 11:13:08 +01002511MODULE_AUTHOR(DRIVER_AUTHOR);
2512MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513MODULE_LICENSE("GPL");
2514
David Woodhouse2971c572008-05-30 14:04:03 +03002515MODULE_FIRMWARE("keyspan/usa28.fw");
2516MODULE_FIRMWARE("keyspan/usa28x.fw");
2517MODULE_FIRMWARE("keyspan/usa28xa.fw");
2518MODULE_FIRMWARE("keyspan/usa28xb.fw");
2519MODULE_FIRMWARE("keyspan/usa19.fw");
2520MODULE_FIRMWARE("keyspan/usa19qi.fw");
2521MODULE_FIRMWARE("keyspan/mpr.fw");
2522MODULE_FIRMWARE("keyspan/usa19qw.fw");
2523MODULE_FIRMWARE("keyspan/usa18x.fw");
2524MODULE_FIRMWARE("keyspan/usa19w.fw");
2525MODULE_FIRMWARE("keyspan/usa49w.fw");
2526MODULE_FIRMWARE("keyspan/usa49wlc.fw");