blob: 6abe8a4fee0ee2baf569e51b5c98ee7a86e711e4 [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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700295 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 endpoint = usb_pipeendpoint(urb->pipe);
298
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700299 if (status) {
Stefan Hubnera8ffa0b2012-12-13 22:45:00 +0100300 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700301 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 return;
303 }
304
Ming Leicdc97792008-02-24 18:41:47 +0800305 port = urb->context;
Jiri Slaby2e124b42013-01-03 15:53:06 +0100306 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 /* 0x80 bit is error flag */
308 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100309 /* no errors on individual bytes, only
310 possible overrun err */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100312 err = TTY_OVERRUN;
313 else
314 err = 0;
315 for (i = 1; i < urb->actual_length ; ++i)
Jiri Slaby92a19f92013-01-03 15:53:03 +0100316 tty_insert_flip_char(&port->port, data[i], err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 } else {
318 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700319 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 for (i = 0; i + 1 < urb->actual_length; i += 2) {
321 int stat = data[i], flag = 0;
322 if (stat & RXERROR_OVERRUN)
323 flag |= TTY_OVERRUN;
324 if (stat & RXERROR_FRAMING)
325 flag |= TTY_FRAME;
326 if (stat & RXERROR_PARITY)
327 flag |= TTY_PARITY;
328 /* XXX should handle break (0x10) */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100329 tty_insert_flip_char(&port->port, data[i+1],
330 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 }
332 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100333 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 }
Alan Coxdeb91682008-07-22 11:13:08 +0100335
336 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500337 err = usb_submit_urb(urb, GFP_ATOMIC);
338 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700339 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340}
341
Alan Coxdeb91682008-07-22 11:13:08 +0100342/* Outdat handling is common for all devices */
David Howells7d12e782006-10-05 14:55:46 +0100343static void usa2x_outdat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
345 struct usb_serial_port *port;
346 struct keyspan_port_private *p_priv;
347
Ming Leicdc97792008-02-24 18:41:47 +0800348 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 p_priv = usb_get_serial_port_data(port);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700350 dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Alan Stern1f871582010-02-17 10:05:47 -0500352 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353}
354
David Howells7d12e782006-10-05 14:55:46 +0100355static void usa26_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357}
358
David Howells7d12e782006-10-05 14:55:46 +0100359static void usa26_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
361 struct usb_serial_port *port;
362 struct keyspan_port_private *p_priv;
363
Ming Leicdc97792008-02-24 18:41:47 +0800364 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 p_priv = usb_get_serial_port_data(port);
366
367 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700368 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100369 keyspan_usa26_send_setup(port->serial, port,
370 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 }
372}
373
David Howells7d12e782006-10-05 14:55:46 +0100374static void usa26_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
376 unsigned char *data = urb->transfer_buffer;
377 struct keyspan_usa26_portStatusMessage *msg;
378 struct usb_serial *serial;
379 struct usb_serial_port *port;
380 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100381 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700383 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Ming Leicdc97792008-02-24 18:41:47 +0800385 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700387 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700388 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 return;
390 }
391 if (urb->actual_length != 9) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700392 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 goto exit;
394 }
395
396 msg = (struct keyspan_usa26_portStatusMessage *)data;
397
398#if 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700399 dev_dbg(&urb->dev->dev,
400 "%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
401 __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr,
402 msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled,
403 msg->controlResponse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404#endif
405
406 /* Now do something useful with the data */
407
408
Alan Coxdeb91682008-07-22 11:13:08 +0100409 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700411 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 goto exit;
413 }
414 port = serial->port[msg->port];
415 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 /* Update handshaking pin state information */
418 old_dcd_state = p_priv->dcd_state;
419 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
420 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
421 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
422 p_priv->ri_state = ((msg->ri) ? 1 : 0);
423
Alan Cox4a90f092008-10-13 10:39:46 +0100424 if (old_dcd_state != p_priv->dcd_state) {
425 tty = tty_port_tty_get(&port->port);
426 if (tty && !C_CLOCAL(tty))
427 tty_hangup(tty);
428 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 }
Alan Coxdeb91682008-07-22 11:13:08 +0100430
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100432 err = usb_submit_urb(urb, GFP_ATOMIC);
433 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700434 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435exit: ;
436}
437
David Howells7d12e782006-10-05 14:55:46 +0100438static void usa26_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440}
441
442
David Howells7d12e782006-10-05 14:55:46 +0100443static void usa28_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444{
Alan Coxf035a8a2008-07-22 11:13:32 +0100445 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 struct usb_serial_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 unsigned char *data;
448 struct keyspan_port_private *p_priv;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700449 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Ming Leicdc97792008-02-24 18:41:47 +0800451 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 p_priv = usb_get_serial_port_data(port);
453 data = urb->transfer_buffer;
454
455 if (urb != p_priv->in_urbs[p_priv->in_flip])
456 return;
457
458 do {
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700459 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700460 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
461 __func__, status, usb_pipeendpoint(urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 return;
463 }
464
Ming Leicdc97792008-02-24 18:41:47 +0800465 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 p_priv = usb_get_serial_port_data(port);
467 data = urb->transfer_buffer;
468
Jiri Slaby2e124b42013-01-03 15:53:06 +0100469 if (urb->actual_length) {
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100470 tty_insert_flip_string(&port->port, data,
471 urb->actual_length);
Jiri Slaby2e124b42013-01-03 15:53:06 +0100472 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 }
474
475 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500476 err = usb_submit_urb(urb, GFP_ATOMIC);
477 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700478 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
Alan Stern1f871582010-02-17 10:05:47 -0500479 __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 p_priv->in_flip ^= 1;
481
482 urb = p_priv->in_urbs[p_priv->in_flip];
483 } while (urb->status != -EINPROGRESS);
484}
485
David Howells7d12e782006-10-05 14:55:46 +0100486static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488}
489
David Howells7d12e782006-10-05 14:55:46 +0100490static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
492 struct usb_serial_port *port;
493 struct keyspan_port_private *p_priv;
494
Ming Leicdc97792008-02-24 18:41:47 +0800495 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 p_priv = usb_get_serial_port_data(port);
497
498 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700499 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100500 keyspan_usa28_send_setup(port->serial, port,
501 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 }
503}
504
David Howells7d12e782006-10-05 14:55:46 +0100505static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506{
507 int err;
508 unsigned char *data = urb->transfer_buffer;
509 struct keyspan_usa28_portStatusMessage *msg;
510 struct usb_serial *serial;
511 struct usb_serial_port *port;
512 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100513 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700515 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Ming Leicdc97792008-02-24 18:41:47 +0800517 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700519 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700520 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 return;
522 }
523
524 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700525 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 goto exit;
527 }
528
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700529 /*
530 dev_dbg(&urb->dev->dev,
Stefan Hubnera8ffa0b2012-12-13 22:45:00 +0100531 "%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__,
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700532 data[0], data[1], data[2], data[3], data[4], data[5],
533 data[6], data[7], data[8], data[9], data[10], data[11]);
534 */
Alan Coxdeb91682008-07-22 11:13:08 +0100535
536 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 msg = (struct keyspan_usa28_portStatusMessage *)data;
538
Alan Coxdeb91682008-07-22 11:13:08 +0100539 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700541 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 goto exit;
543 }
544 port = serial->port[msg->port];
545 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100546
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 /* Update handshaking pin state information */
548 old_dcd_state = p_priv->dcd_state;
549 p_priv->cts_state = ((msg->cts) ? 1 : 0);
550 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
551 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
552 p_priv->ri_state = ((msg->ri) ? 1 : 0);
553
Ben Minerdsddc04ae2012-07-12 00:10:18 +1000554 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
Alan Cox4a90f092008-10-13 10:39:46 +0100555 tty = tty_port_tty_get(&port->port);
Ben Minerds878b5fd2012-07-12 00:10:19 +1000556 if (tty && !C_CLOCAL(tty))
Alan Cox4a90f092008-10-13 10:39:46 +0100557 tty_hangup(tty);
558 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 }
560
561 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100562 err = usb_submit_urb(urb, GFP_ATOMIC);
563 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700564 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565exit: ;
566}
567
David Howells7d12e782006-10-05 14:55:46 +0100568static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570}
571
572
David Howells7d12e782006-10-05 14:55:46 +0100573static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574{
575 struct usb_serial *serial;
576 struct usb_serial_port *port;
577 struct keyspan_port_private *p_priv;
578 int i;
579
Ming Leicdc97792008-02-24 18:41:47 +0800580 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 for (i = 0; i < serial->num_ports; ++i) {
582 port = serial->port[i];
583 p_priv = usb_get_serial_port_data(port);
584
585 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700586 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100587 keyspan_usa49_send_setup(serial, port,
588 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 break;
590 }
591 }
592}
593
594 /* This is actually called glostat in the Keyspan
595 doco */
David Howells7d12e782006-10-05 14:55:46 +0100596static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
598 int err;
599 unsigned char *data = urb->transfer_buffer;
600 struct keyspan_usa49_portStatusMessage *msg;
601 struct usb_serial *serial;
602 struct usb_serial_port *port;
603 struct keyspan_port_private *p_priv;
604 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700605 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
Ming Leicdc97792008-02-24 18:41:47 +0800607 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700609 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700610 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 return;
612 }
613
Alan Coxdeb91682008-07-22 11:13:08 +0100614 if (urb->actual_length !=
615 sizeof(struct keyspan_usa49_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700616 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 goto exit;
618 }
619
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700620 /*
621 dev_dbg(&urb->dev->dev, "%s: %x %x %x %x %x %x %x %x %x %x %x",
622 __func__, data[0], data[1], data[2], data[3], data[4],
623 data[5], data[6], data[7], data[8], data[9], data[10]);
624 */
Alan Coxdeb91682008-07-22 11:13:08 +0100625
626 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 msg = (struct keyspan_usa49_portStatusMessage *)data;
628
Alan Coxdeb91682008-07-22 11:13:08 +0100629 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 if (msg->portNumber >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700631 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
632 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 goto exit;
634 }
635 port = serial->port[msg->portNumber];
636 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 /* Update handshaking pin state information */
639 old_dcd_state = p_priv->dcd_state;
640 p_priv->cts_state = ((msg->cts) ? 1 : 0);
641 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
642 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
643 p_priv->ri_state = ((msg->ri) ? 1 : 0);
644
Alan Cox4a90f092008-10-13 10:39:46 +0100645 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
646 struct tty_struct *tty = tty_port_tty_get(&port->port);
647 if (tty && !C_CLOCAL(tty))
648 tty_hangup(tty);
649 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 }
651
Alan Coxdeb91682008-07-22 11:13:08 +0100652 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100653 err = usb_submit_urb(urb, GFP_ATOMIC);
654 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700655 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656exit: ;
657}
658
David Howells7d12e782006-10-05 14:55:46 +0100659static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661}
662
David Howells7d12e782006-10-05 14:55:46 +0100663static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
665 int i, err;
666 int endpoint;
667 struct usb_serial_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700669 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 endpoint = usb_pipeendpoint(urb->pipe);
672
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700673 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700674 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
675 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 return;
677 }
678
Ming Leicdc97792008-02-24 18:41:47 +0800679 port = urb->context;
Jiri Slaby2e124b42013-01-03 15:53:06 +0100680 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 /* 0x80 bit is error flag */
682 if ((data[0] & 0x80) == 0) {
683 /* no error on any byte */
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100684 tty_insert_flip_string(&port->port, data + 1,
Alan Coxf035a8a2008-07-22 11:13:32 +0100685 urb->actual_length - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 } else {
687 /* some bytes had errors, every byte has status */
688 for (i = 0; i + 1 < urb->actual_length; i += 2) {
689 int stat = data[i], flag = 0;
690 if (stat & RXERROR_OVERRUN)
691 flag |= TTY_OVERRUN;
692 if (stat & RXERROR_FRAMING)
693 flag |= TTY_FRAME;
694 if (stat & RXERROR_PARITY)
695 flag |= TTY_PARITY;
696 /* XXX should handle break (0x10) */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100697 tty_insert_flip_char(&port->port, data[i+1],
698 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 }
700 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100701 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 }
Alan Coxdeb91682008-07-22 11:13:08 +0100703
704 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500705 err = usb_submit_urb(urb, GFP_ATOMIC);
706 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700707 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708}
709
Lucy McCoy0ca12682007-05-18 12:10:41 -0700710static void usa49wg_indat_callback(struct urb *urb)
711{
712 int i, len, x, err;
713 struct usb_serial *serial;
714 struct usb_serial_port *port;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700715 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700716 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700717
Lucy McCoy0ca12682007-05-18 12:10:41 -0700718 serial = urb->context;
719
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700720 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700721 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700722 return;
723 }
724
725 /* inbound data is in the form P#, len, status, data */
726 i = 0;
727 len = 0;
728
729 if (urb->actual_length) {
730 while (i < urb->actual_length) {
731
732 /* Check port number from message*/
733 if (data[i] >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700734 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800735 __func__, data[i]);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700736 return;
737 }
738 port = serial->port[data[i++]];
Lucy McCoy0ca12682007-05-18 12:10:41 -0700739 len = data[i++];
740
741 /* 0x80 bit is error flag */
742 if ((data[i] & 0x80) == 0) {
743 /* no error on any byte */
744 i++;
745 for (x = 1; x < len ; ++x)
Jiri Slaby92a19f92013-01-03 15:53:03 +0100746 tty_insert_flip_char(&port->port,
747 data[i++], 0);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700748 } else {
749 /*
750 * some bytes had errors, every byte has status
751 */
752 for (x = 0; x + 1 < len; x += 2) {
753 int stat = data[i], flag = 0;
754 if (stat & RXERROR_OVERRUN)
755 flag |= TTY_OVERRUN;
756 if (stat & RXERROR_FRAMING)
757 flag |= TTY_FRAME;
758 if (stat & RXERROR_PARITY)
759 flag |= TTY_PARITY;
760 /* XXX should handle break (0x10) */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100761 tty_insert_flip_char(&port->port,
Lucy McCoy0ca12682007-05-18 12:10:41 -0700762 data[i+1], flag);
763 i += 2;
764 }
765 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100766 tty_flip_buffer_push(&port->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700767 }
768 }
769
770 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700771 err = usb_submit_urb(urb, GFP_ATOMIC);
772 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700773 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700774}
775
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700777static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779}
780
Lucy McCoy0ca12682007-05-18 12:10:41 -0700781static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782{
783 int i, err;
784 int endpoint;
785 struct usb_serial_port *port;
786 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700788 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 endpoint = usb_pipeendpoint(urb->pipe);
791
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700792 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700793 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800794 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 return;
796 }
797
Ming Leicdc97792008-02-24 18:41:47 +0800798 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 p_priv = usb_get_serial_port_data(port);
800
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100803 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Alan Coxf035a8a2008-07-22 11:13:32 +0100805 if (p_priv->baud > 57600)
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100806 tty_insert_flip_string(&port->port, data,
807 urb->actual_length);
Alan Coxf035a8a2008-07-22 11:13:32 +0100808 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 /* 0x80 bit is error flag */
810 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100811 /* no errors on individual bytes, only
812 possible overrun err*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100814 err = TTY_OVERRUN;
815 else
816 err = 0;
817 for (i = 1; i < urb->actual_length ; ++i)
Jiri Slaby92a19f92013-01-03 15:53:03 +0100818 tty_insert_flip_char(&port->port,
819 data[i], err);
Alan Coxdeb91682008-07-22 11:13:08 +0100820 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700822 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 for (i = 0; i + 1 < urb->actual_length; i += 2) {
824 int stat = data[i], flag = 0;
825 if (stat & RXERROR_OVERRUN)
826 flag |= TTY_OVERRUN;
827 if (stat & RXERROR_FRAMING)
828 flag |= TTY_FRAME;
829 if (stat & RXERROR_PARITY)
830 flag |= TTY_PARITY;
831 /* XXX should handle break (0x10) */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100832 tty_insert_flip_char(&port->port,
833 data[i+1], flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 }
835 }
836 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100837 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 }
Alan Coxdeb91682008-07-22 11:13:08 +0100839
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500841 err = usb_submit_urb(urb, GFP_ATOMIC);
842 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700843 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844}
845
846
David Howells7d12e782006-10-05 14:55:46 +0100847static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848{
849 unsigned char *data = urb->transfer_buffer;
850 struct keyspan_usa90_portStatusMessage *msg;
851 struct usb_serial *serial;
852 struct usb_serial_port *port;
853 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100854 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700856 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Ming Leicdc97792008-02-24 18:41:47 +0800858 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700860 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700861 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 return;
863 }
864 if (urb->actual_length < 14) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700865 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 goto exit;
867 }
868
869 msg = (struct keyspan_usa90_portStatusMessage *)data;
870
871 /* Now do something useful with the data */
872
873 port = serial->port[0];
874 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 /* Update handshaking pin state information */
877 old_dcd_state = p_priv->dcd_state;
878 p_priv->cts_state = ((msg->cts) ? 1 : 0);
879 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
880 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
881 p_priv->ri_state = ((msg->ri) ? 1 : 0);
882
Alan Cox4a90f092008-10-13 10:39:46 +0100883 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
884 tty = tty_port_tty_get(&port->port);
885 if (tty && !C_CLOCAL(tty))
886 tty_hangup(tty);
887 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 }
Alan Coxdeb91682008-07-22 11:13:08 +0100889
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100891 err = usb_submit_urb(urb, GFP_ATOMIC);
892 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700893 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894exit:
895 ;
896}
897
David Howells7d12e782006-10-05 14:55:46 +0100898static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899{
900 struct usb_serial_port *port;
901 struct keyspan_port_private *p_priv;
902
Ming Leicdc97792008-02-24 18:41:47 +0800903 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 p_priv = usb_get_serial_port_data(port);
905
906 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700907 dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100908 keyspan_usa90_send_setup(port->serial, port,
909 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 }
911}
912
Lucy McCoy0ca12682007-05-18 12:10:41 -0700913/* Status messages from the 28xg */
914static void usa67_instat_callback(struct urb *urb)
915{
916 int err;
917 unsigned char *data = urb->transfer_buffer;
918 struct keyspan_usa67_portStatusMessage *msg;
919 struct usb_serial *serial;
920 struct usb_serial_port *port;
921 struct keyspan_port_private *p_priv;
922 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700923 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700924
Lucy McCoy0ca12682007-05-18 12:10:41 -0700925 serial = urb->context;
926
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700927 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700928 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700929 return;
930 }
931
Alan Coxdeb91682008-07-22 11:13:08 +0100932 if (urb->actual_length !=
933 sizeof(struct keyspan_usa67_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700934 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700935 return;
936 }
937
938
939 /* Now do something useful with the data */
940 msg = (struct keyspan_usa67_portStatusMessage *)data;
941
942 /* Check port number from message and retrieve private data */
943 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700944 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700945 return;
946 }
947
948 port = serial->port[msg->port];
949 p_priv = usb_get_serial_port_data(port);
950
951 /* Update handshaking pin state information */
952 old_dcd_state = p_priv->dcd_state;
953 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
954 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
955
Alan Cox4a90f092008-10-13 10:39:46 +0100956 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
957 struct tty_struct *tty = tty_port_tty_get(&port->port);
958 if (tty && !C_CLOCAL(tty))
959 tty_hangup(tty);
960 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700961 }
962
963 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700964 err = usb_submit_urb(urb, GFP_ATOMIC);
965 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700966 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700967}
968
969static void usa67_glocont_callback(struct urb *urb)
970{
971 struct usb_serial *serial;
972 struct usb_serial_port *port;
973 struct keyspan_port_private *p_priv;
974 int i;
975
Lucy McCoy0ca12682007-05-18 12:10:41 -0700976 serial = urb->context;
977 for (i = 0; i < serial->num_ports; ++i) {
978 port = serial->port[i];
979 p_priv = usb_get_serial_port_data(port);
980
981 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700982 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700983 keyspan_usa67_send_setup(serial, port,
984 p_priv->resend_cont - 1);
985 break;
986 }
987 }
988}
989
Alan Cox95da3102008-07-22 11:09:07 +0100990static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991{
Alan Cox95da3102008-07-22 11:09:07 +0100992 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 struct keyspan_port_private *p_priv;
994 const struct keyspan_device_details *d_details;
995 int flip;
996 int data_len;
997 struct urb *this_urb;
998
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 p_priv = usb_get_serial_port_data(port);
1000 d_details = p_priv->device_details;
1001
Alan Coxa5b6f602008-04-08 17:16:06 +01001002 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +01001004 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 else
1006 data_len = 63;
1007
1008 flip = p_priv->out_flip;
1009
1010 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +01001011 this_urb = p_priv->out_urbs[flip];
1012 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001014 return data_len;
1015 flip = (flip + 1) & d_details->outdat_endp_flip;
1016 this_urb = p_priv->out_urbs[flip];
1017 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001019 return data_len;
1020 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 }
Alan Coxa5b6f602008-04-08 17:16:06 +01001022 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023}
1024
1025
Alan Coxa509a7e2009-09-19 13:13:26 -07001026static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001028 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 const struct keyspan_device_details *d_details;
1030 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001031 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001033 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 p_priv = usb_get_serial_port_data(port);
1036 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001037
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 /* Set some sane defaults */
1039 p_priv->rts_state = 1;
1040 p_priv->dtr_state = 1;
1041 p_priv->baud = 9600;
1042
1043 /* force baud and lcr to be set on open */
1044 p_priv->old_baud = 0;
1045 p_priv->old_cflag = 0;
1046
1047 p_priv->out_flip = 0;
1048 p_priv->in_flip = 0;
1049
1050 /* Reset low level data toggle and start reading from endpoints */
1051 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001052 urb = p_priv->in_urbs[i];
1053 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
Alan Coxdeb91682008-07-22 11:13:08 +01001056 /* make sure endpoint data toggle is synchronized
1057 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001059 err = usb_submit_urb(urb, GFP_KERNEL);
1060 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001061 dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 }
1063
1064 /* Reset low level data toggle on out endpoints */
1065 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001066 urb = p_priv->out_urbs[i];
1067 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 continue;
Alan Coxdeb91682008-07-22 11:13:08 +01001069 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1070 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 }
1072
Andrew Mortonf78ba152007-11-28 16:21:54 -08001073 /* get the terminal config for the setup message now so we don't
1074 * need to send 2 of them */
1075
Andrew Mortonf78ba152007-11-28 16:21:54 -08001076 device_port = port->number - port->serial->minor;
Alan Cox95da3102008-07-22 11:09:07 +01001077 if (tty) {
Alan Coxadc8d742012-07-14 15:31:47 +01001078 cflag = tty->termios.c_cflag;
Alan Cox95da3102008-07-22 11:09:07 +01001079 /* Baud rate calculation takes baud rate as an integer
1080 so other rates can be generated if desired. */
1081 baud_rate = tty_get_baud_rate(tty);
1082 /* If no match or invalid, leave as default */
1083 if (baud_rate >= 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001084 && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Alan Cox95da3102008-07-22 11:09:07 +01001085 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1086 p_priv->baud = baud_rate;
1087 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001088 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001089 /* set CTS/RTS handshake etc. */
1090 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +10001091 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001092
1093 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001094 /* mdelay(100); */
1095 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001096
Alan Coxa5b6f602008-04-08 17:16:06 +01001097 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098}
1099
1100static inline void stop_urb(struct urb *urb)
1101{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001102 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104}
1105
Alan Cox335f8512009-06-11 12:26:29 +01001106static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1107{
1108 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1109
1110 p_priv->rts_state = on;
1111 p_priv->dtr_state = on;
1112 keyspan_send_setup(port, 0);
1113}
1114
1115static void keyspan_close(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116{
1117 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 struct keyspan_port_private *p_priv;
1119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001121
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 p_priv->rts_state = 0;
1123 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001124
Johan Hovold80dfe0c2013-03-21 12:36:32 +01001125 keyspan_send_setup(port, 2);
1126 /* pilot-xfer seems to work best with this delay */
1127 mdelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129 p_priv->out_flip = 0;
1130 p_priv->in_flip = 0;
1131
Johan Hovold80dfe0c2013-03-21 12:36:32 +01001132 stop_urb(p_priv->inack_urb);
1133 for (i = 0; i < 2; i++) {
1134 stop_urb(p_priv->in_urbs[i]);
1135 stop_urb(p_priv->out_urbs[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137}
1138
Alan Coxdeb91682008-07-22 11:13:08 +01001139/* download the firmware to a pre-renumeration device */
1140static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141{
Rene Buergel8d733e22012-09-18 09:02:01 +02001142 char *fw_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001144 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
1145 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1146 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001147
1148 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1149 != 0x8000) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001150 dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n");
Alan Coxdeb91682008-07-22 11:13:08 +01001151 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }
1153
1154 /* Select firmware image on the basis of idProduct */
1155 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1156 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001157 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 break;
1159
1160 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001161 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 break;
1163
1164 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001165 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 break;
1167
1168 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001169 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 break;
1171
1172 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001173 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001175
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001177 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001179
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001181 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 break;
1183
1184 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001185 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001187
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001189 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001191
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001193 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001195
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001197 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 break;
1199
1200 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001201 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 break;
1203
1204 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001205 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1206 le16_to_cpu(serial->dev->descriptor.idProduct));
1207 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 }
1209
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001210 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
Rene Buergel8d733e22012-09-18 09:02:01 +02001212 if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
1213 dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
1214 fw_name);
1215 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 }
1217
Rene Buergel8d733e22012-09-18 09:02:01 +02001218 /* after downloading firmware Renumeration will occur in a
1219 moment and the new device will bind to the real driver */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
1221 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001222 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223}
1224
1225/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001226static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1227 int endpoint)
1228{
1229 struct usb_host_interface *iface_desc;
1230 struct usb_endpoint_descriptor *ep;
1231 int i;
1232
1233 iface_desc = serial->interface->cur_altsetting;
1234 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1235 ep = &iface_desc->endpoint[i].desc;
1236 if (ep->bEndpointAddress == endpoint)
1237 return ep;
1238 }
1239 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1240 "endpoint %x\n", endpoint);
1241 return NULL;
1242}
1243
Alan Coxdeb91682008-07-22 11:13:08 +01001244static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001246 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247{
1248 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001249 struct usb_endpoint_descriptor const *ep_desc;
1250 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
1252 if (endpoint == -1)
1253 return NULL; /* endpoint not needed */
1254
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001255 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
1257 if (urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001258 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d failed.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 return NULL;
1260 }
1261
Lucy McCoy0ca12682007-05-18 12:10:41 -07001262 if (endpoint == 0) {
1263 /* control EP filled in when used */
1264 return urb;
1265 }
1266
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001267 ep_desc = find_ep(serial, endpoint);
1268 if (!ep_desc) {
1269 /* leak the urb, something's wrong and the callers don't care */
1270 return urb;
1271 }
1272 if (usb_endpoint_xfer_int(ep_desc)) {
1273 ep_type_name = "INT";
1274 usb_fill_int_urb(urb, serial->dev,
1275 usb_sndintpipe(serial->dev, endpoint) | dir,
1276 buf, len, callback, ctx,
1277 ep_desc->bInterval);
1278 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1279 ep_type_name = "BULK";
1280 usb_fill_bulk_urb(urb, serial->dev,
1281 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1282 buf, len, callback, ctx);
1283 } else {
1284 dev_warn(&serial->interface->dev,
1285 "unsupported endpoint type %x\n",
Julia Lawall2e0fe702008-12-29 11:22:14 +01001286 usb_endpoint_type(ep_desc));
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001287 usb_free_urb(urb);
1288 return NULL;
1289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001291 dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001292 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 return urb;
1294}
1295
1296static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001297 void (*instat_callback)(struct urb *);
1298 void (*glocont_callback)(struct urb *);
1299 void (*indat_callback)(struct urb *);
1300 void (*outdat_callback)(struct urb *);
1301 void (*inack_callback)(struct urb *);
1302 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303} keyspan_callbacks[] = {
1304 {
1305 /* msg_usa26 callbacks */
1306 .instat_callback = usa26_instat_callback,
1307 .glocont_callback = usa26_glocont_callback,
1308 .indat_callback = usa26_indat_callback,
1309 .outdat_callback = usa2x_outdat_callback,
1310 .inack_callback = usa26_inack_callback,
1311 .outcont_callback = usa26_outcont_callback,
1312 }, {
1313 /* msg_usa28 callbacks */
1314 .instat_callback = usa28_instat_callback,
1315 .glocont_callback = usa28_glocont_callback,
1316 .indat_callback = usa28_indat_callback,
1317 .outdat_callback = usa2x_outdat_callback,
1318 .inack_callback = usa28_inack_callback,
1319 .outcont_callback = usa28_outcont_callback,
1320 }, {
1321 /* msg_usa49 callbacks */
1322 .instat_callback = usa49_instat_callback,
1323 .glocont_callback = usa49_glocont_callback,
1324 .indat_callback = usa49_indat_callback,
1325 .outdat_callback = usa2x_outdat_callback,
1326 .inack_callback = usa49_inack_callback,
1327 .outcont_callback = usa49_outcont_callback,
1328 }, {
1329 /* msg_usa90 callbacks */
1330 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001331 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 .indat_callback = usa90_indat_callback,
1333 .outdat_callback = usa2x_outdat_callback,
1334 .inack_callback = usa28_inack_callback,
1335 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001336 }, {
1337 /* msg_usa67 callbacks */
1338 .instat_callback = usa67_instat_callback,
1339 .glocont_callback = usa67_glocont_callback,
1340 .indat_callback = usa26_indat_callback,
1341 .outdat_callback = usa2x_outdat_callback,
1342 .inack_callback = usa26_inack_callback,
1343 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 }
1345};
1346
1347 /* Generic setup urbs function that uses
1348 data in device_details */
1349static void keyspan_setup_urbs(struct usb_serial *serial)
1350{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 struct keyspan_serial_private *s_priv;
1352 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 struct callbacks *cback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 s_priv = usb_get_serial_data(serial);
1356 d_details = s_priv->device_details;
1357
Alan Coxdeb91682008-07-22 11:13:08 +01001358 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 cback = &keyspan_callbacks[d_details->msg_format];
1360
Alan Coxdeb91682008-07-22 11:13:08 +01001361 /* Allocate and set up urbs for each one that is in use,
1362 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 s_priv->instat_urb = keyspan_setup_urb
1364 (serial, d_details->instat_endpoint, USB_DIR_IN,
1365 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1366 cback->instat_callback);
1367
Lucy McCoy0ca12682007-05-18 12:10:41 -07001368 s_priv->indat_urb = keyspan_setup_urb
1369 (serial, d_details->indat_endpoint, USB_DIR_IN,
1370 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1371 usa49wg_indat_callback);
1372
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 s_priv->glocont_urb = keyspan_setup_urb
1374 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1375 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1376 cback->glocont_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377}
1378
1379/* usa19 function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001380static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1381 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 u8 *rate_low, u8 *prescaler, int portnum)
1383{
1384 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001385 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001388 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
Alan Coxdeb91682008-07-22 11:13:08 +01001390 /* prevent divide by zero... */
1391 b16 = baud_rate * 16L;
1392 if (b16 == 0)
1393 return KEYSPAN_INVALID_BAUD_RATE;
1394 /* Any "standard" rate over 57k6 is marginal on the USA-19
1395 as we run out of divisor resolution. */
1396 if (baud_rate > 57600)
1397 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Alan Coxdeb91682008-07-22 11:13:08 +01001399 /* calculate the divisor and the counter (its inverse) */
1400 div = baudclk / b16;
1401 if (div == 0)
1402 return KEYSPAN_INVALID_BAUD_RATE;
1403 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
Alan Coxdeb91682008-07-22 11:13:08 +01001406 if (div > 0xffff)
1407 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
Alan Coxdeb91682008-07-22 11:13:08 +01001409 /* return the counter values if non-null */
1410 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001412 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001414 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001415 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001416 __func__, baud_rate, *rate_hi, *rate_low);
1417 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418}
1419
1420/* usa19hs function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001421static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1422 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1423 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424{
1425 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001426 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001428 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
Alan Coxdeb91682008-07-22 11:13:08 +01001430 /* prevent divide by zero... */
1431 b16 = baud_rate * 16L;
1432 if (b16 == 0)
1433 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
Alan Coxdeb91682008-07-22 11:13:08 +01001435 /* calculate the divisor */
1436 div = baudclk / b16;
1437 if (div == 0)
1438 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
Alan Coxdeb91682008-07-22 11:13:08 +01001440 if (div > 0xffff)
1441 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
Alan Coxdeb91682008-07-22 11:13:08 +01001443 /* return the counter values if non-null */
1444 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001446
1447 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001449
1450 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001451 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001452 __func__, baud_rate, *rate_hi, *rate_low);
1453
1454 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455}
1456
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001457static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1458 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 u8 *rate_low, u8 *prescaler, int portnum)
1460{
1461 u32 b16, /* baud rate times 16 (actual rate used internally) */
1462 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001463 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 res, /* resulting baud rate using 13/8 prescaler */
1465 diff, /* error using 13/8 prescaler */
1466 smallest_diff;
1467 u8 best_prescaler;
1468 int i;
1469
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001470 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471
Alan Coxdeb91682008-07-22 11:13:08 +01001472 /* prevent divide by zero */
1473 b16 = baud_rate * 16L;
1474 if (b16 == 0)
1475 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
Alan Coxdeb91682008-07-22 11:13:08 +01001477 /* Calculate prescaler by trying them all and looking
1478 for best fit */
1479
1480 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 smallest_diff = 0xffffffff;
1482
1483 /* 0 is an invalid prescaler, used as a flag */
1484 best_prescaler = 0;
1485
Alan Coxdeb91682008-07-22 11:13:08 +01001486 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001488
1489 div = clk / b16;
1490 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
1493 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001494 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495
Alan Coxdeb91682008-07-22 11:13:08 +01001496 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 best_prescaler = i;
1498 smallest_diff = diff;
1499 }
1500 }
1501
Alan Coxdeb91682008-07-22 11:13:08 +01001502 if (best_prescaler == 0)
1503 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505 clk = (baudclk * 8) / (u32) best_prescaler;
1506 div = clk / b16;
1507
Alan Coxdeb91682008-07-22 11:13:08 +01001508 /* return the divisor and prescaler if non-null */
1509 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001511 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 if (prescaler) {
1514 *prescaler = best_prescaler;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001515 /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 }
Alan Coxdeb91682008-07-22 11:13:08 +01001517 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518}
1519
1520 /* USA-28 supports different maximum baud rates on each port */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001521static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1522 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1523 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524{
1525 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001526 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 cnt; /* inverse of divisor (programmed into 8051) */
1528
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001529 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
1531 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001532 b16 = baud_rate * 16L;
1533 if (b16 == 0)
1534 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
Alan Coxdeb91682008-07-22 11:13:08 +01001536 /* calculate the divisor and the counter (its inverse) */
1537 div = KEYSPAN_USA28_BAUDCLK / b16;
1538 if (div == 0)
1539 return KEYSPAN_INVALID_BAUD_RATE;
1540 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
Alan Coxdeb91682008-07-22 11:13:08 +01001543 /* check for out of range, based on portnum,
1544 and return result */
1545 if (portnum == 0) {
1546 if (div > 0xffff)
1547 return KEYSPAN_INVALID_BAUD_RATE;
1548 } else {
1549 if (portnum == 1) {
1550 if (div > 0xff)
1551 return KEYSPAN_INVALID_BAUD_RATE;
1552 } else
1553 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 }
1555
1556 /* return the counter values if not NULL
1557 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001558 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001560 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001562 dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
Alan Coxdeb91682008-07-22 11:13:08 +01001563 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564}
1565
1566static int keyspan_usa26_send_setup(struct usb_serial *serial,
1567 struct usb_serial_port *port,
1568 int reset_port)
1569{
Alan Coxdeb91682008-07-22 11:13:08 +01001570 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 struct keyspan_serial_private *s_priv;
1572 struct keyspan_port_private *p_priv;
1573 const struct keyspan_device_details *d_details;
1574 int outcont_urb;
1575 struct urb *this_urb;
1576 int device_port, err;
1577
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001578 dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
1580 s_priv = usb_get_serial_data(serial);
1581 p_priv = usb_get_serial_port_data(port);
1582 d_details = s_priv->device_details;
1583 device_port = port->number - port->serial->minor;
1584
1585 outcont_urb = d_details->outcont_endpoints[port->number];
1586 this_urb = p_priv->outcont_urb;
1587
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001588 dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
1590 /* Make sure we have an urb then send the message */
1591 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001592 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 return -1;
1594 }
1595
1596 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001597 Don't overwrite resend for open/close condition. */
1598 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 p_priv->resend_cont = reset_port + 1;
1600 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001601 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001603 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 }
1605
Alan Coxdeb91682008-07-22 11:13:08 +01001606 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1607
1608 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 if (p_priv->old_baud != p_priv->baud) {
1610 p_priv->old_baud = p_priv->baud;
1611 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001612 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1613 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1614 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1615 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1616 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 msg.baudLo = 0;
1618 msg.baudHi = 125; /* Values for 9600 baud */
1619 msg.prescaler = 10;
1620 }
1621 msg.setPrescaler = 0xff;
1622 }
1623
Ben Minerds2b982ab2012-07-12 00:10:16 +10001624 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 switch (p_priv->cflag & CSIZE) {
1626 case CS5:
1627 msg.lcr |= USA_DATABITS_5;
1628 break;
1629 case CS6:
1630 msg.lcr |= USA_DATABITS_6;
1631 break;
1632 case CS7:
1633 msg.lcr |= USA_DATABITS_7;
1634 break;
1635 case CS8:
1636 msg.lcr |= USA_DATABITS_8;
1637 break;
1638 }
1639 if (p_priv->cflag & PARENB) {
1640 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001641 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001642 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 }
1644 msg.setLcr = 0xff;
1645
1646 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1647 msg.xonFlowControl = 0;
1648 msg.setFlowControl = 0xff;
1649 msg.forwardingLength = 16;
1650 msg.xonChar = 17;
1651 msg.xoffChar = 19;
1652
1653 /* Opening port */
1654 if (reset_port == 1) {
1655 msg._txOn = 1;
1656 msg._txOff = 0;
1657 msg.txFlush = 0;
1658 msg.txBreak = 0;
1659 msg.rxOn = 1;
1660 msg.rxOff = 0;
1661 msg.rxFlush = 1;
1662 msg.rxForward = 0;
1663 msg.returnStatus = 0;
1664 msg.resetDataToggle = 0xff;
1665 }
1666
1667 /* Closing port */
1668 else if (reset_port == 2) {
1669 msg._txOn = 0;
1670 msg._txOff = 1;
1671 msg.txFlush = 0;
1672 msg.txBreak = 0;
1673 msg.rxOn = 0;
1674 msg.rxOff = 1;
1675 msg.rxFlush = 1;
1676 msg.rxForward = 0;
1677 msg.returnStatus = 0;
1678 msg.resetDataToggle = 0;
1679 }
1680
1681 /* Sending intermediate configs */
1682 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001683 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 msg._txOff = 0;
1685 msg.txFlush = 0;
1686 msg.txBreak = (p_priv->break_on);
1687 msg.rxOn = 0;
1688 msg.rxOff = 0;
1689 msg.rxFlush = 0;
1690 msg.rxForward = 0;
1691 msg.returnStatus = 0;
1692 msg.resetDataToggle = 0x0;
1693 }
1694
Alan Coxdeb91682008-07-22 11:13:08 +01001695 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 msg.setTxTriState_setRts = 0xff;
1697 msg.txTriState_rts = p_priv->rts_state;
1698
1699 msg.setHskoa_setDtr = 0xff;
1700 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001703 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 /* send the data out the device on control endpoint */
1706 this_urb->transfer_buffer_length = sizeof(msg);
1707
Alan Coxdeb91682008-07-22 11:13:08 +01001708 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1709 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001710 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711#if 0
1712 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001713 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__
1714 outcont_urb, this_urb->transfer_buffer_length,
1715 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 }
1717#endif
1718
Alan Coxa5b6f602008-04-08 17:16:06 +01001719 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720}
1721
1722static int keyspan_usa28_send_setup(struct usb_serial *serial,
1723 struct usb_serial_port *port,
1724 int reset_port)
1725{
Alan Coxdeb91682008-07-22 11:13:08 +01001726 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 struct keyspan_serial_private *s_priv;
1728 struct keyspan_port_private *p_priv;
1729 const struct keyspan_device_details *d_details;
1730 struct urb *this_urb;
1731 int device_port, err;
1732
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 s_priv = usb_get_serial_data(serial);
1734 p_priv = usb_get_serial_port_data(port);
1735 d_details = s_priv->device_details;
1736 device_port = port->number - port->serial->minor;
1737
1738 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001739 this_urb = p_priv->outcont_urb;
1740 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001741 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 return -1;
1743 }
1744
1745 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001746 Don't overwrite resend for open/close condition. */
1747 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 p_priv->resend_cont = reset_port + 1;
1749 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001750 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001752 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 }
1754
Alan Coxdeb91682008-07-22 11:13:08 +01001755 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756
1757 msg.setBaudRate = 1;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001758 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1759 &msg.baudHi, &msg.baudLo, NULL,
1760 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1761 dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001762 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 msg.baudLo = 0xff;
1764 msg.baudHi = 0xb2; /* Values for 9600 baud */
1765 }
1766
1767 /* If parity is enabled, we must calculate it ourselves. */
1768 msg.parity = 0; /* XXX for now */
1769
1770 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1771 msg.xonFlowControl = 0;
1772
Alan Coxdeb91682008-07-22 11:13:08 +01001773 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 msg.rts = p_priv->rts_state;
1775 msg.dtr = p_priv->dtr_state;
1776
1777 msg.forwardingLength = 16;
1778 msg.forwardMs = 10;
1779 msg.breakThreshold = 45;
1780 msg.xonChar = 17;
1781 msg.xoffChar = 19;
1782
1783 /*msg.returnStatus = 1;
1784 msg.resetDataToggle = 0xff;*/
1785 /* Opening port */
1786 if (reset_port == 1) {
1787 msg._txOn = 1;
1788 msg._txOff = 0;
1789 msg.txFlush = 0;
1790 msg.txForceXoff = 0;
1791 msg.txBreak = 0;
1792 msg.rxOn = 1;
1793 msg.rxOff = 0;
1794 msg.rxFlush = 1;
1795 msg.rxForward = 0;
1796 msg.returnStatus = 0;
1797 msg.resetDataToggle = 0xff;
1798 }
1799 /* Closing port */
1800 else if (reset_port == 2) {
1801 msg._txOn = 0;
1802 msg._txOff = 1;
1803 msg.txFlush = 0;
1804 msg.txForceXoff = 0;
1805 msg.txBreak = 0;
1806 msg.rxOn = 0;
1807 msg.rxOff = 1;
1808 msg.rxFlush = 1;
1809 msg.rxForward = 0;
1810 msg.returnStatus = 0;
1811 msg.resetDataToggle = 0;
1812 }
1813 /* Sending intermediate configs */
1814 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001815 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 msg._txOff = 0;
1817 msg.txFlush = 0;
1818 msg.txForceXoff = 0;
1819 msg.txBreak = (p_priv->break_on);
1820 msg.rxOn = 0;
1821 msg.rxOff = 0;
1822 msg.rxFlush = 0;
1823 msg.rxForward = 0;
1824 msg.returnStatus = 0;
1825 msg.resetDataToggle = 0x0;
1826 }
1827
1828 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001829 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
1831 /* send the data out the device on control endpoint */
1832 this_urb->transfer_buffer_length = sizeof(msg);
1833
Alan Coxdeb91682008-07-22 11:13:08 +01001834 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1835 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001836 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837#if 0
1838 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001839 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 this_urb->transfer_buffer_length);
1841 }
1842#endif
1843
Alan Coxa5b6f602008-04-08 17:16:06 +01001844 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845}
1846
1847static int keyspan_usa49_send_setup(struct usb_serial *serial,
1848 struct usb_serial_port *port,
1849 int reset_port)
1850{
Lucy McCoy0ca12682007-05-18 12:10:41 -07001851 struct keyspan_usa49_portControlMessage msg;
1852 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 struct keyspan_serial_private *s_priv;
1854 struct keyspan_port_private *p_priv;
1855 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 struct urb *this_urb;
1857 int err, device_port;
1858
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 s_priv = usb_get_serial_data(serial);
1860 p_priv = usb_get_serial_port_data(port);
1861 d_details = s_priv->device_details;
1862
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 this_urb = s_priv->glocont_urb;
1864
Lucy McCoy0ca12682007-05-18 12:10:41 -07001865 /* Work out which port within the device is being setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 device_port = port->number - port->serial->minor;
1867
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301868 /* Make sure we have an urb then send the message */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001870 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 return -1;
1872 }
1873
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001874 dev_dbg(&port->dev, "%s - endpoint %d port %d (%d)\n",
1875 __func__, usb_pipeendpoint(this_urb->pipe),
1876 port->number, device_port);
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301877
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001879 Don't overwrite resend for open/close condition. */
1880 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001882
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001884 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001886 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 }
1888
Alan Coxdeb91682008-07-22 11:13:08 +01001889 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
1891 /*msg.portNumber = port->number;*/
1892 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01001893
1894 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 if (p_priv->old_baud != p_priv->baud) {
1896 p_priv->old_baud = p_priv->baud;
1897 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001898 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1899 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1900 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1901 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1902 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 msg.baudLo = 0;
1904 msg.baudHi = 125; /* Values for 9600 baud */
1905 msg.prescaler = 10;
1906 }
Alan Coxdeb91682008-07-22 11:13:08 +01001907 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 }
1909
Ben Minerds2b982ab2012-07-12 00:10:16 +10001910 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 switch (p_priv->cflag & CSIZE) {
1912 case CS5:
1913 msg.lcr |= USA_DATABITS_5;
1914 break;
1915 case CS6:
1916 msg.lcr |= USA_DATABITS_6;
1917 break;
1918 case CS7:
1919 msg.lcr |= USA_DATABITS_7;
1920 break;
1921 case CS8:
1922 msg.lcr |= USA_DATABITS_8;
1923 break;
1924 }
1925 if (p_priv->cflag & PARENB) {
1926 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001927 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001928 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 }
1930 msg.setLcr = 0xff;
1931
1932 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1933 msg.xonFlowControl = 0;
1934 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01001935
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 msg.forwardingLength = 16;
1937 msg.xonChar = 17;
1938 msg.xoffChar = 19;
1939
Alan Coxdeb91682008-07-22 11:13:08 +01001940 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 if (reset_port == 1) {
1942 msg._txOn = 1;
1943 msg._txOff = 0;
1944 msg.txFlush = 0;
1945 msg.txBreak = 0;
1946 msg.rxOn = 1;
1947 msg.rxOff = 0;
1948 msg.rxFlush = 1;
1949 msg.rxForward = 0;
1950 msg.returnStatus = 0;
1951 msg.resetDataToggle = 0xff;
1952 msg.enablePort = 1;
1953 msg.disablePort = 0;
1954 }
1955 /* Closing port */
1956 else if (reset_port == 2) {
1957 msg._txOn = 0;
1958 msg._txOff = 1;
1959 msg.txFlush = 0;
1960 msg.txBreak = 0;
1961 msg.rxOn = 0;
1962 msg.rxOff = 1;
1963 msg.rxFlush = 1;
1964 msg.rxForward = 0;
1965 msg.returnStatus = 0;
1966 msg.resetDataToggle = 0;
1967 msg.enablePort = 0;
1968 msg.disablePort = 1;
1969 }
1970 /* Sending intermediate configs */
1971 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001972 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 msg._txOff = 0;
1974 msg.txFlush = 0;
1975 msg.txBreak = (p_priv->break_on);
1976 msg.rxOn = 0;
1977 msg.rxOff = 0;
1978 msg.rxFlush = 0;
1979 msg.rxForward = 0;
1980 msg.returnStatus = 0;
1981 msg.resetDataToggle = 0x0;
1982 msg.enablePort = 0;
1983 msg.disablePort = 0;
1984 }
1985
Alan Coxdeb91682008-07-22 11:13:08 +01001986 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 msg.setRts = 0xff;
1988 msg.rts = p_priv->rts_state;
1989
1990 msg.setDtr = 0xff;
1991 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001992
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994
Alan Coxdeb91682008-07-22 11:13:08 +01001995 /* if the device is a 49wg, we send control message on usb
1996 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07001997
1998 if (d_details->product_id == keyspan_usa49wg_product_id) {
1999 dr = (void *)(s_priv->ctrl_buf);
2000 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
2001 dr->bRequest = 0xB0; /* 49wg control message */;
2002 dr->wValue = 0;
2003 dr->wIndex = 0;
2004 dr->wLength = cpu_to_le16(sizeof(msg));
2005
Alan Coxdeb91682008-07-22 11:13:08 +01002006 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07002007
Alan Coxdeb91682008-07-22 11:13:08 +01002008 usb_fill_control_urb(this_urb, serial->dev,
2009 usb_sndctrlpipe(serial->dev, 0),
2010 (unsigned char *)dr, s_priv->glocont_buf,
2011 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002012
2013 } else {
2014 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01002015
Lucy McCoy0ca12682007-05-18 12:10:41 -07002016 /* send the data out the device on control endpoint */
2017 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002018 }
Alan Coxdeb91682008-07-22 11:13:08 +01002019 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2020 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002021 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022#if 0
2023 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002024 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__,
2025 outcont_urb, this_urb->transfer_buffer_length,
2026 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 }
2028#endif
2029
Alan Coxa5b6f602008-04-08 17:16:06 +01002030 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031}
2032
2033static int keyspan_usa90_send_setup(struct usb_serial *serial,
2034 struct usb_serial_port *port,
2035 int reset_port)
2036{
Alan Coxdeb91682008-07-22 11:13:08 +01002037 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 struct keyspan_serial_private *s_priv;
2039 struct keyspan_port_private *p_priv;
2040 const struct keyspan_device_details *d_details;
2041 struct urb *this_urb;
2042 int err;
2043 u8 prescaler;
2044
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 s_priv = usb_get_serial_data(serial);
2046 p_priv = usb_get_serial_port_data(port);
2047 d_details = s_priv->device_details;
2048
2049 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002050 this_urb = p_priv->outcont_urb;
2051 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002052 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 return -1;
2054 }
2055
2056 /* Save reset port val for resend.
2057 Don't overwrite resend for open/close condition. */
2058 if ((reset_port + 1) > p_priv->resend_cont)
2059 p_priv->resend_cont = reset_port + 1;
2060 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002061 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002063 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 }
2065
Alan Coxdeb91682008-07-22 11:13:08 +01002066 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067
Alan Coxdeb91682008-07-22 11:13:08 +01002068 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 if (p_priv->old_baud != p_priv->baud) {
2070 p_priv->old_baud = p_priv->baud;
2071 msg.setClocking = 0x01;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002072 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2073 &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2074 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2075 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 p_priv->baud = 9600;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002077 d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2079 }
2080 msg.setRxMode = 1;
2081 msg.setTxMode = 1;
2082 }
2083
2084 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002085 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 msg.rxMode = RXMODE_DMA;
2087 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002088 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 msg.rxMode = RXMODE_BYHAND;
2090 msg.txMode = TXMODE_BYHAND;
2091 }
2092
Ben Minerds2b982ab2012-07-12 00:10:16 +10002093 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 switch (p_priv->cflag & CSIZE) {
2095 case CS5:
2096 msg.lcr |= USA_DATABITS_5;
2097 break;
2098 case CS6:
2099 msg.lcr |= USA_DATABITS_6;
2100 break;
2101 case CS7:
2102 msg.lcr |= USA_DATABITS_7;
2103 break;
2104 case CS8:
2105 msg.lcr |= USA_DATABITS_8;
2106 break;
2107 }
2108 if (p_priv->cflag & PARENB) {
2109 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002110 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002111 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 }
2113 if (p_priv->old_cflag != p_priv->cflag) {
2114 p_priv->old_cflag = p_priv->cflag;
2115 msg.setLcr = 0x01;
2116 }
2117
2118 if (p_priv->flow_control == flow_cts)
2119 msg.txFlowControl = TXFLOW_CTS;
2120 msg.setTxFlowControl = 0x01;
2121 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002122
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002124 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 msg.txAckSetting = 0;
2126 msg.xonChar = 17;
2127 msg.xoffChar = 19;
2128
Alan Coxdeb91682008-07-22 11:13:08 +01002129 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 if (reset_port == 1) {
2131 msg.portEnabled = 1;
2132 msg.rxFlush = 1;
2133 msg.txBreak = (p_priv->break_on);
2134 }
2135 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002136 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 /* Sending intermediate configs */
2139 else {
Alan Stern1f871582010-02-17 10:05:47 -05002140 msg.portEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 msg.txBreak = (p_priv->break_on);
2142 }
2143
Alan Coxdeb91682008-07-22 11:13:08 +01002144 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 msg.setRts = 0x01;
2146 msg.rts = p_priv->rts_state;
2147
2148 msg.setDtr = 0x01;
2149 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002150
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002152 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2153
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 /* send the data out the device on control endpoint */
2155 this_urb->transfer_buffer_length = sizeof(msg);
2156
Alan Coxdeb91682008-07-22 11:13:08 +01002157 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2158 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002159 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002160 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161}
2162
Lucy McCoy0ca12682007-05-18 12:10:41 -07002163static int keyspan_usa67_send_setup(struct usb_serial *serial,
2164 struct usb_serial_port *port,
2165 int reset_port)
2166{
2167 struct keyspan_usa67_portControlMessage msg;
2168 struct keyspan_serial_private *s_priv;
2169 struct keyspan_port_private *p_priv;
2170 const struct keyspan_device_details *d_details;
2171 struct urb *this_urb;
2172 int err, device_port;
2173
Lucy McCoy0ca12682007-05-18 12:10:41 -07002174 s_priv = usb_get_serial_data(serial);
2175 p_priv = usb_get_serial_port_data(port);
2176 d_details = s_priv->device_details;
2177
2178 this_urb = s_priv->glocont_urb;
2179
2180 /* Work out which port within the device is being setup */
2181 device_port = port->number - port->serial->minor;
2182
2183 /* Make sure we have an urb then send the message */
2184 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002185 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002186 port->number);
2187 return -1;
2188 }
2189
2190 /* Save reset port val for resend.
2191 Don't overwrite resend for open/close condition. */
2192 if ((reset_port + 1) > p_priv->resend_cont)
2193 p_priv->resend_cont = reset_port + 1;
2194 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002195 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002196 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002197 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002198 }
2199
2200 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2201
2202 msg.port = device_port;
2203
2204 /* Only set baud rate if it's changed */
2205 if (p_priv->old_baud != p_priv->baud) {
2206 p_priv->old_baud = p_priv->baud;
2207 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002208 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2209 &msg.baudHi, &msg.baudLo, &msg.prescaler,
2210 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2211 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2212 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002213 msg.baudLo = 0;
2214 msg.baudHi = 125; /* Values for 9600 baud */
2215 msg.prescaler = 10;
2216 }
2217 msg.setPrescaler = 0xff;
2218 }
2219
2220 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2221 switch (p_priv->cflag & CSIZE) {
2222 case CS5:
2223 msg.lcr |= USA_DATABITS_5;
2224 break;
2225 case CS6:
2226 msg.lcr |= USA_DATABITS_6;
2227 break;
2228 case CS7:
2229 msg.lcr |= USA_DATABITS_7;
2230 break;
2231 case CS8:
2232 msg.lcr |= USA_DATABITS_8;
2233 break;
2234 }
2235 if (p_priv->cflag & PARENB) {
2236 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002237 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002238 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002239 }
2240 msg.setLcr = 0xff;
2241
2242 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2243 msg.xonFlowControl = 0;
2244 msg.setFlowControl = 0xff;
2245 msg.forwardingLength = 16;
2246 msg.xonChar = 17;
2247 msg.xoffChar = 19;
2248
2249 if (reset_port == 1) {
2250 /* Opening port */
2251 msg._txOn = 1;
2252 msg._txOff = 0;
2253 msg.txFlush = 0;
2254 msg.txBreak = 0;
2255 msg.rxOn = 1;
2256 msg.rxOff = 0;
2257 msg.rxFlush = 1;
2258 msg.rxForward = 0;
2259 msg.returnStatus = 0;
2260 msg.resetDataToggle = 0xff;
2261 } else if (reset_port == 2) {
2262 /* Closing port */
2263 msg._txOn = 0;
2264 msg._txOff = 1;
2265 msg.txFlush = 0;
2266 msg.txBreak = 0;
2267 msg.rxOn = 0;
2268 msg.rxOff = 1;
2269 msg.rxFlush = 1;
2270 msg.rxForward = 0;
2271 msg.returnStatus = 0;
2272 msg.resetDataToggle = 0;
2273 } else {
2274 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002275 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002276 msg._txOff = 0;
2277 msg.txFlush = 0;
2278 msg.txBreak = (p_priv->break_on);
2279 msg.rxOn = 0;
2280 msg.rxOff = 0;
2281 msg.rxFlush = 0;
2282 msg.rxForward = 0;
2283 msg.returnStatus = 0;
2284 msg.resetDataToggle = 0x0;
2285 }
2286
2287 /* Do handshaking outputs */
2288 msg.setTxTriState_setRts = 0xff;
2289 msg.txTriState_rts = p_priv->rts_state;
2290
2291 msg.setHskoa_setDtr = 0xff;
2292 msg.hskoa_dtr = p_priv->dtr_state;
2293
2294 p_priv->resend_cont = 0;
2295
2296 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2297
2298 /* send the data out the device on control endpoint */
2299 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002300
2301 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2302 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002303 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002304 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002305}
2306
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2308{
2309 struct usb_serial *serial = port->serial;
2310 struct keyspan_serial_private *s_priv;
2311 const struct keyspan_device_details *d_details;
2312
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 s_priv = usb_get_serial_data(serial);
2314 d_details = s_priv->device_details;
2315
2316 switch (d_details->msg_format) {
2317 case msg_usa26:
2318 keyspan_usa26_send_setup(serial, port, reset_port);
2319 break;
2320 case msg_usa28:
2321 keyspan_usa28_send_setup(serial, port, reset_port);
2322 break;
2323 case msg_usa49:
2324 keyspan_usa49_send_setup(serial, port, reset_port);
2325 break;
2326 case msg_usa90:
2327 keyspan_usa90_send_setup(serial, port, reset_port);
2328 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002329 case msg_usa67:
2330 keyspan_usa67_send_setup(serial, port, reset_port);
2331 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 }
2333}
2334
2335
2336/* Gets called by the "real" driver (ie once firmware is loaded
2337 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002338static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339{
2340 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 const struct keyspan_device_details *d_details;
2343
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002345 if (d_details->product_id ==
2346 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 break;
2348 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002349 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2350 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 return 1;
2352 }
2353
2354 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002355 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 if (!s_priv) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002357 dev_dbg(&serial->dev->dev, "%s - kmalloc for keyspan_serial_private failed.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 return -ENOMEM;
2359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
2361 s_priv->device_details = d_details;
2362 usb_set_serial_data(serial, s_priv);
2363
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 keyspan_setup_urbs(serial);
2365
Lucy McCoy0ca12682007-05-18 12:10:41 -07002366 if (s_priv->instat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002367 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2368 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002369 dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002370 }
2371 if (s_priv->indat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002372 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2373 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002374 dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 }
Alan Coxdeb91682008-07-22 11:13:08 +01002376
Alan Coxa5b6f602008-04-08 17:16:06 +01002377 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378}
2379
Alan Sternf9c99bb2009-06-02 11:53:55 -04002380static void keyspan_disconnect(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002382 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 s_priv = usb_get_serial_data(serial);
2385
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 stop_urb(s_priv->instat_urb);
2387 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002388 stop_urb(s_priv->indat_urb);
Alan Sternf9c99bb2009-06-02 11:53:55 -04002389}
2390
2391static void keyspan_release(struct usb_serial *serial)
2392{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002393 struct keyspan_serial_private *s_priv;
Alan Sternf9c99bb2009-06-02 11:53:55 -04002394
Alan Sternf9c99bb2009-06-02 11:53:55 -04002395 s_priv = usb_get_serial_data(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002397 usb_free_urb(s_priv->instat_urb);
2398 usb_free_urb(s_priv->indat_urb);
2399 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002401 kfree(s_priv);
2402}
2403
2404static int keyspan_port_probe(struct usb_serial_port *port)
2405{
2406 struct usb_serial *serial = port->serial;
Bjørn Morkf0e3e352012-11-10 10:13:42 +01002407 struct keyspan_serial_private *s_priv;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002408 struct keyspan_port_private *p_priv;
2409 const struct keyspan_device_details *d_details;
2410 struct callbacks *cback;
2411 int endp;
2412 int port_num;
2413 int i;
2414
2415 s_priv = usb_get_serial_data(serial);
2416 d_details = s_priv->device_details;
2417
2418 p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL);
2419 if (!p_priv)
2420 return -ENOMEM;
2421
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002422 p_priv->device_details = d_details;
2423
2424 /* Setup values for the various callback routines */
2425 cback = &keyspan_callbacks[d_details->msg_format];
2426
2427 port_num = port->number - port->serial->minor;
2428
2429 /* Do indat endpoints first, once for each flip */
2430 endp = d_details->indat_endpoints[port_num];
2431 for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
2432 p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
2433 USB_DIR_IN, port,
2434 p_priv->in_buffer[i], 64,
2435 cback->indat_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 }
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002437 /* outdat endpoints also have flip */
2438 endp = d_details->outdat_endpoints[port_num];
2439 for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
2440 p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
2441 USB_DIR_OUT, port,
2442 p_priv->out_buffer[i], 64,
2443 cback->outdat_callback);
2444 }
2445 /* inack endpoint */
2446 p_priv->inack_urb = keyspan_setup_urb(serial,
2447 d_details->inack_endpoints[port_num],
2448 USB_DIR_IN, port,
2449 p_priv->inack_buffer, 1,
2450 cback->inack_callback);
2451 /* outcont endpoint */
2452 p_priv->outcont_urb = keyspan_setup_urb(serial,
2453 d_details->outcont_endpoints[port_num],
2454 USB_DIR_OUT, port,
2455 p_priv->outcont_buffer, 64,
2456 cback->outcont_callback);
2457
2458 usb_set_serial_port_data(port, p_priv);
2459
2460 return 0;
2461}
2462
2463static int keyspan_port_remove(struct usb_serial_port *port)
2464{
2465 struct keyspan_port_private *p_priv;
2466 int i;
2467
2468 p_priv = usb_get_serial_port_data(port);
2469
2470 stop_urb(p_priv->inack_urb);
2471 stop_urb(p_priv->outcont_urb);
2472 for (i = 0; i < 2; i++) {
2473 stop_urb(p_priv->in_urbs[i]);
2474 stop_urb(p_priv->out_urbs[i]);
2475 }
2476
2477 usb_free_urb(p_priv->inack_urb);
2478 usb_free_urb(p_priv->outcont_urb);
2479 for (i = 0; i < 2; i++) {
2480 usb_free_urb(p_priv->in_urbs[i]);
2481 usb_free_urb(p_priv->out_urbs[i]);
2482 }
2483
2484 kfree(p_priv);
2485
2486 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487}
2488
Alan Coxdeb91682008-07-22 11:13:08 +01002489MODULE_AUTHOR(DRIVER_AUTHOR);
2490MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491MODULE_LICENSE("GPL");
2492
David Woodhouse2971c572008-05-30 14:04:03 +03002493MODULE_FIRMWARE("keyspan/usa28.fw");
2494MODULE_FIRMWARE("keyspan/usa28x.fw");
2495MODULE_FIRMWARE("keyspan/usa28xa.fw");
2496MODULE_FIRMWARE("keyspan/usa28xb.fw");
2497MODULE_FIRMWARE("keyspan/usa19.fw");
2498MODULE_FIRMWARE("keyspan/usa19qi.fw");
2499MODULE_FIRMWARE("keyspan/mpr.fw");
2500MODULE_FIRMWARE("keyspan/usa19qw.fw");
2501MODULE_FIRMWARE("keyspan/usa18x.fw");
2502MODULE_FIRMWARE("keyspan/usa19w.fw");
2503MODULE_FIRMWARE("keyspan/usa49w.fw");
2504MODULE_FIRMWARE("keyspan/usa49wlc.fw");