blob: 3d92394aba3a28770d10abf7064a724cc87b4d69 [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
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300729 while (i < urb->actual_length) {
Lucy McCoy0ca12682007-05-18 12:10:41 -0700730
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300731 /* Check port number from message */
732 if (data[i] >= serial->num_ports) {
733 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
734 __func__, data[i]);
735 return;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700736 }
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300737 port = serial->port[data[i++]];
738 len = data[i++];
739
740 /* 0x80 bit is error flag */
741 if ((data[i] & 0x80) == 0) {
742 /* no error on any byte */
743 i++;
744 for (x = 1; x < len ; ++x)
745 tty_insert_flip_char(&port->port,
746 data[i++], 0);
747 } else {
748 /*
749 * some bytes had errors, every byte has status
750 */
751 for (x = 0; x + 1 < len; x += 2) {
752 int stat = data[i], flag = 0;
753
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) */
761 tty_insert_flip_char(&port->port, data[i+1],
762 flag);
763 i += 2;
764 }
765 }
766 tty_flip_buffer_push(&port->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700767 }
768
769 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700770 err = usb_submit_urb(urb, GFP_ATOMIC);
771 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700772 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700773}
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700776static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778}
779
Lucy McCoy0ca12682007-05-18 12:10:41 -0700780static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781{
782 int i, err;
783 int endpoint;
784 struct usb_serial_port *port;
785 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700787 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 endpoint = usb_pipeendpoint(urb->pipe);
790
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700791 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700792 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800793 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 return;
795 }
796
Ming Leicdc97792008-02-24 18:41:47 +0800797 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 p_priv = usb_get_serial_port_data(port);
799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100802 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
Alan Coxf035a8a2008-07-22 11:13:32 +0100804 if (p_priv->baud > 57600)
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100805 tty_insert_flip_string(&port->port, data,
806 urb->actual_length);
Alan Coxf035a8a2008-07-22 11:13:32 +0100807 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 /* 0x80 bit is error flag */
809 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100810 /* no errors on individual bytes, only
811 possible overrun err*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100813 err = TTY_OVERRUN;
814 else
815 err = 0;
816 for (i = 1; i < urb->actual_length ; ++i)
Jiri Slaby92a19f92013-01-03 15:53:03 +0100817 tty_insert_flip_char(&port->port,
818 data[i], err);
Alan Coxdeb91682008-07-22 11:13:08 +0100819 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700821 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 for (i = 0; i + 1 < urb->actual_length; i += 2) {
823 int stat = data[i], flag = 0;
824 if (stat & RXERROR_OVERRUN)
825 flag |= TTY_OVERRUN;
826 if (stat & RXERROR_FRAMING)
827 flag |= TTY_FRAME;
828 if (stat & RXERROR_PARITY)
829 flag |= TTY_PARITY;
830 /* XXX should handle break (0x10) */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100831 tty_insert_flip_char(&port->port,
832 data[i+1], flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
834 }
835 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100836 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 }
Alan Coxdeb91682008-07-22 11:13:08 +0100838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500840 err = usb_submit_urb(urb, GFP_ATOMIC);
841 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700842 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843}
844
845
David Howells7d12e782006-10-05 14:55:46 +0100846static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847{
848 unsigned char *data = urb->transfer_buffer;
849 struct keyspan_usa90_portStatusMessage *msg;
850 struct usb_serial *serial;
851 struct usb_serial_port *port;
852 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100853 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700855 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
Ming Leicdc97792008-02-24 18:41:47 +0800857 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700859 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700860 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 return;
862 }
863 if (urb->actual_length < 14) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700864 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 goto exit;
866 }
867
868 msg = (struct keyspan_usa90_portStatusMessage *)data;
869
870 /* Now do something useful with the data */
871
872 port = serial->port[0];
873 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 /* Update handshaking pin state information */
876 old_dcd_state = p_priv->dcd_state;
877 p_priv->cts_state = ((msg->cts) ? 1 : 0);
878 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
879 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
880 p_priv->ri_state = ((msg->ri) ? 1 : 0);
881
Alan Cox4a90f092008-10-13 10:39:46 +0100882 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
883 tty = tty_port_tty_get(&port->port);
884 if (tty && !C_CLOCAL(tty))
885 tty_hangup(tty);
886 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 }
Alan Coxdeb91682008-07-22 11:13:08 +0100888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100890 err = usb_submit_urb(urb, GFP_ATOMIC);
891 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700892 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893exit:
894 ;
895}
896
David Howells7d12e782006-10-05 14:55:46 +0100897static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898{
899 struct usb_serial_port *port;
900 struct keyspan_port_private *p_priv;
901
Ming Leicdc97792008-02-24 18:41:47 +0800902 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 p_priv = usb_get_serial_port_data(port);
904
905 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700906 dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100907 keyspan_usa90_send_setup(port->serial, port,
908 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 }
910}
911
Lucy McCoy0ca12682007-05-18 12:10:41 -0700912/* Status messages from the 28xg */
913static void usa67_instat_callback(struct urb *urb)
914{
915 int err;
916 unsigned char *data = urb->transfer_buffer;
917 struct keyspan_usa67_portStatusMessage *msg;
918 struct usb_serial *serial;
919 struct usb_serial_port *port;
920 struct keyspan_port_private *p_priv;
921 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700922 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700923
Lucy McCoy0ca12682007-05-18 12:10:41 -0700924 serial = urb->context;
925
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700926 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700927 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700928 return;
929 }
930
Alan Coxdeb91682008-07-22 11:13:08 +0100931 if (urb->actual_length !=
932 sizeof(struct keyspan_usa67_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700933 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700934 return;
935 }
936
937
938 /* Now do something useful with the data */
939 msg = (struct keyspan_usa67_portStatusMessage *)data;
940
941 /* Check port number from message and retrieve private data */
942 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700943 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700944 return;
945 }
946
947 port = serial->port[msg->port];
948 p_priv = usb_get_serial_port_data(port);
949
950 /* Update handshaking pin state information */
951 old_dcd_state = p_priv->dcd_state;
952 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
953 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
954
Alan Cox4a90f092008-10-13 10:39:46 +0100955 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
956 struct tty_struct *tty = tty_port_tty_get(&port->port);
957 if (tty && !C_CLOCAL(tty))
958 tty_hangup(tty);
959 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700960 }
961
962 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700963 err = usb_submit_urb(urb, GFP_ATOMIC);
964 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700965 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700966}
967
968static void usa67_glocont_callback(struct urb *urb)
969{
970 struct usb_serial *serial;
971 struct usb_serial_port *port;
972 struct keyspan_port_private *p_priv;
973 int i;
974
Lucy McCoy0ca12682007-05-18 12:10:41 -0700975 serial = urb->context;
976 for (i = 0; i < serial->num_ports; ++i) {
977 port = serial->port[i];
978 p_priv = usb_get_serial_port_data(port);
979
980 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700981 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700982 keyspan_usa67_send_setup(serial, port,
983 p_priv->resend_cont - 1);
984 break;
985 }
986 }
987}
988
Alan Cox95da3102008-07-22 11:09:07 +0100989static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990{
Alan Cox95da3102008-07-22 11:09:07 +0100991 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 struct keyspan_port_private *p_priv;
993 const struct keyspan_device_details *d_details;
994 int flip;
995 int data_len;
996 struct urb *this_urb;
997
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 p_priv = usb_get_serial_port_data(port);
999 d_details = p_priv->device_details;
1000
Alan Coxa5b6f602008-04-08 17:16:06 +01001001 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +01001003 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 else
1005 data_len = 63;
1006
1007 flip = p_priv->out_flip;
1008
1009 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +01001010 this_urb = p_priv->out_urbs[flip];
1011 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001013 return data_len;
1014 flip = (flip + 1) & d_details->outdat_endp_flip;
1015 this_urb = p_priv->out_urbs[flip];
1016 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001018 return data_len;
1019 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 }
Alan Coxa5b6f602008-04-08 17:16:06 +01001021 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022}
1023
1024
Alan Coxa509a7e2009-09-19 13:13:26 -07001025static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001027 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 const struct keyspan_device_details *d_details;
1029 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001030 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001032 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 p_priv = usb_get_serial_port_data(port);
1035 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001036
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 /* Set some sane defaults */
1038 p_priv->rts_state = 1;
1039 p_priv->dtr_state = 1;
1040 p_priv->baud = 9600;
1041
1042 /* force baud and lcr to be set on open */
1043 p_priv->old_baud = 0;
1044 p_priv->old_cflag = 0;
1045
1046 p_priv->out_flip = 0;
1047 p_priv->in_flip = 0;
1048
1049 /* Reset low level data toggle and start reading from endpoints */
1050 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001051 urb = p_priv->in_urbs[i];
1052 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054
Alan Coxdeb91682008-07-22 11:13:08 +01001055 /* make sure endpoint data toggle is synchronized
1056 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001058 err = usb_submit_urb(urb, GFP_KERNEL);
1059 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001060 dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 }
1062
1063 /* Reset low level data toggle on out endpoints */
1064 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001065 urb = p_priv->out_urbs[i];
1066 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 continue;
Alan Coxdeb91682008-07-22 11:13:08 +01001068 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1069 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 }
1071
Andrew Mortonf78ba152007-11-28 16:21:54 -08001072 /* get the terminal config for the setup message now so we don't
1073 * need to send 2 of them */
1074
Andrew Mortonf78ba152007-11-28 16:21:54 -08001075 device_port = port->number - port->serial->minor;
Alan Cox95da3102008-07-22 11:09:07 +01001076 if (tty) {
Alan Coxadc8d742012-07-14 15:31:47 +01001077 cflag = tty->termios.c_cflag;
Alan Cox95da3102008-07-22 11:09:07 +01001078 /* Baud rate calculation takes baud rate as an integer
1079 so other rates can be generated if desired. */
1080 baud_rate = tty_get_baud_rate(tty);
1081 /* If no match or invalid, leave as default */
1082 if (baud_rate >= 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001083 && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Alan Cox95da3102008-07-22 11:09:07 +01001084 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1085 p_priv->baud = baud_rate;
1086 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001087 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001088 /* set CTS/RTS handshake etc. */
1089 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +10001090 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001091
1092 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001093 /* mdelay(100); */
1094 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001095
Alan Coxa5b6f602008-04-08 17:16:06 +01001096 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097}
1098
1099static inline void stop_urb(struct urb *urb)
1100{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001101 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103}
1104
Alan Cox335f8512009-06-11 12:26:29 +01001105static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1106{
1107 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1108
1109 p_priv->rts_state = on;
1110 p_priv->dtr_state = on;
1111 keyspan_send_setup(port, 0);
1112}
1113
1114static void keyspan_close(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115{
1116 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 struct keyspan_port_private *p_priv;
1118
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 p_priv->rts_state = 0;
1122 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001123
Johan Hovold80dfe0c2013-03-21 12:36:32 +01001124 keyspan_send_setup(port, 2);
1125 /* pilot-xfer seems to work best with this delay */
1126 mdelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
1128 p_priv->out_flip = 0;
1129 p_priv->in_flip = 0;
1130
Johan Hovold80dfe0c2013-03-21 12:36:32 +01001131 stop_urb(p_priv->inack_urb);
1132 for (i = 0; i < 2; i++) {
1133 stop_urb(p_priv->in_urbs[i]);
1134 stop_urb(p_priv->out_urbs[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136}
1137
Alan Coxdeb91682008-07-22 11:13:08 +01001138/* download the firmware to a pre-renumeration device */
1139static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140{
Rene Buergel8d733e22012-09-18 09:02:01 +02001141 char *fw_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001143 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
1144 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1145 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001146
1147 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1148 != 0x8000) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001149 dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n");
Alan Coxdeb91682008-07-22 11:13:08 +01001150 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 }
1152
1153 /* Select firmware image on the basis of idProduct */
1154 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1155 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001156 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 break;
1158
1159 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001160 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 break;
1162
1163 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001164 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 break;
1166
1167 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001168 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 break;
1170
1171 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001172 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001176 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001178
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001180 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 break;
1182
1183 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001184 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001186
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001188 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001190
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001192 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001196 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 break;
1198
1199 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001200 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 break;
1202
1203 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001204 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1205 le16_to_cpu(serial->dev->descriptor.idProduct));
1206 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 }
1208
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001209 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
Rene Buergel8d733e22012-09-18 09:02:01 +02001211 if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
1212 dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
1213 fw_name);
1214 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 }
1216
Rene Buergel8d733e22012-09-18 09:02:01 +02001217 /* after downloading firmware Renumeration will occur in a
1218 moment and the new device will bind to the real driver */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
1220 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001221 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222}
1223
1224/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001225static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1226 int endpoint)
1227{
1228 struct usb_host_interface *iface_desc;
1229 struct usb_endpoint_descriptor *ep;
1230 int i;
1231
1232 iface_desc = serial->interface->cur_altsetting;
1233 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1234 ep = &iface_desc->endpoint[i].desc;
1235 if (ep->bEndpointAddress == endpoint)
1236 return ep;
1237 }
1238 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1239 "endpoint %x\n", endpoint);
1240 return NULL;
1241}
1242
Alan Coxdeb91682008-07-22 11:13:08 +01001243static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001245 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246{
1247 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001248 struct usb_endpoint_descriptor const *ep_desc;
1249 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
1251 if (endpoint == -1)
1252 return NULL; /* endpoint not needed */
1253
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001254 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
1256 if (urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001257 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d failed.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 return NULL;
1259 }
1260
Lucy McCoy0ca12682007-05-18 12:10:41 -07001261 if (endpoint == 0) {
1262 /* control EP filled in when used */
1263 return urb;
1264 }
1265
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001266 ep_desc = find_ep(serial, endpoint);
1267 if (!ep_desc) {
1268 /* leak the urb, something's wrong and the callers don't care */
1269 return urb;
1270 }
1271 if (usb_endpoint_xfer_int(ep_desc)) {
1272 ep_type_name = "INT";
1273 usb_fill_int_urb(urb, serial->dev,
1274 usb_sndintpipe(serial->dev, endpoint) | dir,
1275 buf, len, callback, ctx,
1276 ep_desc->bInterval);
1277 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1278 ep_type_name = "BULK";
1279 usb_fill_bulk_urb(urb, serial->dev,
1280 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1281 buf, len, callback, ctx);
1282 } else {
1283 dev_warn(&serial->interface->dev,
1284 "unsupported endpoint type %x\n",
Julia Lawall2e0fe702008-12-29 11:22:14 +01001285 usb_endpoint_type(ep_desc));
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001286 usb_free_urb(urb);
1287 return NULL;
1288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001290 dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001291 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 return urb;
1293}
1294
1295static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001296 void (*instat_callback)(struct urb *);
1297 void (*glocont_callback)(struct urb *);
1298 void (*indat_callback)(struct urb *);
1299 void (*outdat_callback)(struct urb *);
1300 void (*inack_callback)(struct urb *);
1301 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302} keyspan_callbacks[] = {
1303 {
1304 /* msg_usa26 callbacks */
1305 .instat_callback = usa26_instat_callback,
1306 .glocont_callback = usa26_glocont_callback,
1307 .indat_callback = usa26_indat_callback,
1308 .outdat_callback = usa2x_outdat_callback,
1309 .inack_callback = usa26_inack_callback,
1310 .outcont_callback = usa26_outcont_callback,
1311 }, {
1312 /* msg_usa28 callbacks */
1313 .instat_callback = usa28_instat_callback,
1314 .glocont_callback = usa28_glocont_callback,
1315 .indat_callback = usa28_indat_callback,
1316 .outdat_callback = usa2x_outdat_callback,
1317 .inack_callback = usa28_inack_callback,
1318 .outcont_callback = usa28_outcont_callback,
1319 }, {
1320 /* msg_usa49 callbacks */
1321 .instat_callback = usa49_instat_callback,
1322 .glocont_callback = usa49_glocont_callback,
1323 .indat_callback = usa49_indat_callback,
1324 .outdat_callback = usa2x_outdat_callback,
1325 .inack_callback = usa49_inack_callback,
1326 .outcont_callback = usa49_outcont_callback,
1327 }, {
1328 /* msg_usa90 callbacks */
1329 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001330 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 .indat_callback = usa90_indat_callback,
1332 .outdat_callback = usa2x_outdat_callback,
1333 .inack_callback = usa28_inack_callback,
1334 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001335 }, {
1336 /* msg_usa67 callbacks */
1337 .instat_callback = usa67_instat_callback,
1338 .glocont_callback = usa67_glocont_callback,
1339 .indat_callback = usa26_indat_callback,
1340 .outdat_callback = usa2x_outdat_callback,
1341 .inack_callback = usa26_inack_callback,
1342 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 }
1344};
1345
1346 /* Generic setup urbs function that uses
1347 data in device_details */
1348static void keyspan_setup_urbs(struct usb_serial *serial)
1349{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 struct keyspan_serial_private *s_priv;
1351 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 struct callbacks *cback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 s_priv = usb_get_serial_data(serial);
1355 d_details = s_priv->device_details;
1356
Alan Coxdeb91682008-07-22 11:13:08 +01001357 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 cback = &keyspan_callbacks[d_details->msg_format];
1359
Alan Coxdeb91682008-07-22 11:13:08 +01001360 /* Allocate and set up urbs for each one that is in use,
1361 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 s_priv->instat_urb = keyspan_setup_urb
1363 (serial, d_details->instat_endpoint, USB_DIR_IN,
1364 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1365 cback->instat_callback);
1366
Lucy McCoy0ca12682007-05-18 12:10:41 -07001367 s_priv->indat_urb = keyspan_setup_urb
1368 (serial, d_details->indat_endpoint, USB_DIR_IN,
1369 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1370 usa49wg_indat_callback);
1371
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 s_priv->glocont_urb = keyspan_setup_urb
1373 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1374 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1375 cback->glocont_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376}
1377
1378/* usa19 function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001379static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1380 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 u8 *rate_low, u8 *prescaler, int portnum)
1382{
1383 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001384 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001387 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
Alan Coxdeb91682008-07-22 11:13:08 +01001389 /* prevent divide by zero... */
1390 b16 = baud_rate * 16L;
1391 if (b16 == 0)
1392 return KEYSPAN_INVALID_BAUD_RATE;
1393 /* Any "standard" rate over 57k6 is marginal on the USA-19
1394 as we run out of divisor resolution. */
1395 if (baud_rate > 57600)
1396 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
Alan Coxdeb91682008-07-22 11:13:08 +01001398 /* calculate the divisor and the counter (its inverse) */
1399 div = baudclk / b16;
1400 if (div == 0)
1401 return KEYSPAN_INVALID_BAUD_RATE;
1402 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
Alan Coxdeb91682008-07-22 11:13:08 +01001405 if (div > 0xffff)
1406 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
Alan Coxdeb91682008-07-22 11:13:08 +01001408 /* return the counter values if non-null */
1409 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001411 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001413 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001414 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001415 __func__, baud_rate, *rate_hi, *rate_low);
1416 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417}
1418
1419/* usa19hs function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001420static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1421 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1422 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423{
1424 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001425 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001427 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428
Alan Coxdeb91682008-07-22 11:13:08 +01001429 /* prevent divide by zero... */
1430 b16 = baud_rate * 16L;
1431 if (b16 == 0)
1432 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433
Alan Coxdeb91682008-07-22 11:13:08 +01001434 /* calculate the divisor */
1435 div = baudclk / b16;
1436 if (div == 0)
1437 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
Alan Coxdeb91682008-07-22 11:13:08 +01001439 if (div > 0xffff)
1440 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
Alan Coxdeb91682008-07-22 11:13:08 +01001442 /* return the counter values if non-null */
1443 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001445
1446 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001448
1449 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001450 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001451 __func__, baud_rate, *rate_hi, *rate_low);
1452
1453 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454}
1455
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001456static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1457 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 u8 *rate_low, u8 *prescaler, int portnum)
1459{
1460 u32 b16, /* baud rate times 16 (actual rate used internally) */
1461 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001462 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 res, /* resulting baud rate using 13/8 prescaler */
1464 diff, /* error using 13/8 prescaler */
1465 smallest_diff;
1466 u8 best_prescaler;
1467 int i;
1468
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001469 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470
Alan Coxdeb91682008-07-22 11:13:08 +01001471 /* prevent divide by zero */
1472 b16 = baud_rate * 16L;
1473 if (b16 == 0)
1474 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
Alan Coxdeb91682008-07-22 11:13:08 +01001476 /* Calculate prescaler by trying them all and looking
1477 for best fit */
1478
1479 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 smallest_diff = 0xffffffff;
1481
1482 /* 0 is an invalid prescaler, used as a flag */
1483 best_prescaler = 0;
1484
Alan Coxdeb91682008-07-22 11:13:08 +01001485 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001487
1488 div = clk / b16;
1489 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
1492 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001493 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494
Alan Coxdeb91682008-07-22 11:13:08 +01001495 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 best_prescaler = i;
1497 smallest_diff = diff;
1498 }
1499 }
1500
Alan Coxdeb91682008-07-22 11:13:08 +01001501 if (best_prescaler == 0)
1502 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503
1504 clk = (baudclk * 8) / (u32) best_prescaler;
1505 div = clk / b16;
1506
Alan Coxdeb91682008-07-22 11:13:08 +01001507 /* return the divisor and prescaler if non-null */
1508 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001510 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 if (prescaler) {
1513 *prescaler = best_prescaler;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001514 /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 }
Alan Coxdeb91682008-07-22 11:13:08 +01001516 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517}
1518
1519 /* USA-28 supports different maximum baud rates on each port */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001520static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1521 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1522 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523{
1524 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001525 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 cnt; /* inverse of divisor (programmed into 8051) */
1527
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001528 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
1530 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001531 b16 = baud_rate * 16L;
1532 if (b16 == 0)
1533 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
Alan Coxdeb91682008-07-22 11:13:08 +01001535 /* calculate the divisor and the counter (its inverse) */
1536 div = KEYSPAN_USA28_BAUDCLK / b16;
1537 if (div == 0)
1538 return KEYSPAN_INVALID_BAUD_RATE;
1539 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
Alan Coxdeb91682008-07-22 11:13:08 +01001542 /* check for out of range, based on portnum,
1543 and return result */
1544 if (portnum == 0) {
1545 if (div > 0xffff)
1546 return KEYSPAN_INVALID_BAUD_RATE;
1547 } else {
1548 if (portnum == 1) {
1549 if (div > 0xff)
1550 return KEYSPAN_INVALID_BAUD_RATE;
1551 } else
1552 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 }
1554
1555 /* return the counter values if not NULL
1556 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001557 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001559 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001561 dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
Alan Coxdeb91682008-07-22 11:13:08 +01001562 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563}
1564
1565static int keyspan_usa26_send_setup(struct usb_serial *serial,
1566 struct usb_serial_port *port,
1567 int reset_port)
1568{
Alan Coxdeb91682008-07-22 11:13:08 +01001569 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 struct keyspan_serial_private *s_priv;
1571 struct keyspan_port_private *p_priv;
1572 const struct keyspan_device_details *d_details;
1573 int outcont_urb;
1574 struct urb *this_urb;
1575 int device_port, err;
1576
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001577 dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
1579 s_priv = usb_get_serial_data(serial);
1580 p_priv = usb_get_serial_port_data(port);
1581 d_details = s_priv->device_details;
1582 device_port = port->number - port->serial->minor;
1583
1584 outcont_urb = d_details->outcont_endpoints[port->number];
1585 this_urb = p_priv->outcont_urb;
1586
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001587 dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
1589 /* Make sure we have an urb then send the message */
1590 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001591 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 return -1;
1593 }
1594
1595 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001596 Don't overwrite resend for open/close condition. */
1597 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 p_priv->resend_cont = reset_port + 1;
1599 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001600 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001602 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 }
1604
Alan Coxdeb91682008-07-22 11:13:08 +01001605 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1606
1607 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 if (p_priv->old_baud != p_priv->baud) {
1609 p_priv->old_baud = p_priv->baud;
1610 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001611 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1612 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1613 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1614 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1615 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 msg.baudLo = 0;
1617 msg.baudHi = 125; /* Values for 9600 baud */
1618 msg.prescaler = 10;
1619 }
1620 msg.setPrescaler = 0xff;
1621 }
1622
Ben Minerds2b982ab2012-07-12 00:10:16 +10001623 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 switch (p_priv->cflag & CSIZE) {
1625 case CS5:
1626 msg.lcr |= USA_DATABITS_5;
1627 break;
1628 case CS6:
1629 msg.lcr |= USA_DATABITS_6;
1630 break;
1631 case CS7:
1632 msg.lcr |= USA_DATABITS_7;
1633 break;
1634 case CS8:
1635 msg.lcr |= USA_DATABITS_8;
1636 break;
1637 }
1638 if (p_priv->cflag & PARENB) {
1639 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001640 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001641 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 }
1643 msg.setLcr = 0xff;
1644
1645 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1646 msg.xonFlowControl = 0;
1647 msg.setFlowControl = 0xff;
1648 msg.forwardingLength = 16;
1649 msg.xonChar = 17;
1650 msg.xoffChar = 19;
1651
1652 /* Opening port */
1653 if (reset_port == 1) {
1654 msg._txOn = 1;
1655 msg._txOff = 0;
1656 msg.txFlush = 0;
1657 msg.txBreak = 0;
1658 msg.rxOn = 1;
1659 msg.rxOff = 0;
1660 msg.rxFlush = 1;
1661 msg.rxForward = 0;
1662 msg.returnStatus = 0;
1663 msg.resetDataToggle = 0xff;
1664 }
1665
1666 /* Closing port */
1667 else if (reset_port == 2) {
1668 msg._txOn = 0;
1669 msg._txOff = 1;
1670 msg.txFlush = 0;
1671 msg.txBreak = 0;
1672 msg.rxOn = 0;
1673 msg.rxOff = 1;
1674 msg.rxFlush = 1;
1675 msg.rxForward = 0;
1676 msg.returnStatus = 0;
1677 msg.resetDataToggle = 0;
1678 }
1679
1680 /* Sending intermediate configs */
1681 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001682 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 msg._txOff = 0;
1684 msg.txFlush = 0;
1685 msg.txBreak = (p_priv->break_on);
1686 msg.rxOn = 0;
1687 msg.rxOff = 0;
1688 msg.rxFlush = 0;
1689 msg.rxForward = 0;
1690 msg.returnStatus = 0;
1691 msg.resetDataToggle = 0x0;
1692 }
1693
Alan Coxdeb91682008-07-22 11:13:08 +01001694 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 msg.setTxTriState_setRts = 0xff;
1696 msg.txTriState_rts = p_priv->rts_state;
1697
1698 msg.setHskoa_setDtr = 0xff;
1699 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001700
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001702 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1703
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 /* send the data out the device on control endpoint */
1705 this_urb->transfer_buffer_length = sizeof(msg);
1706
Alan Coxdeb91682008-07-22 11:13:08 +01001707 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1708 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001709 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710#if 0
1711 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001712 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__
1713 outcont_urb, this_urb->transfer_buffer_length,
1714 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 }
1716#endif
1717
Alan Coxa5b6f602008-04-08 17:16:06 +01001718 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719}
1720
1721static int keyspan_usa28_send_setup(struct usb_serial *serial,
1722 struct usb_serial_port *port,
1723 int reset_port)
1724{
Alan Coxdeb91682008-07-22 11:13:08 +01001725 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 struct keyspan_serial_private *s_priv;
1727 struct keyspan_port_private *p_priv;
1728 const struct keyspan_device_details *d_details;
1729 struct urb *this_urb;
1730 int device_port, err;
1731
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 s_priv = usb_get_serial_data(serial);
1733 p_priv = usb_get_serial_port_data(port);
1734 d_details = s_priv->device_details;
1735 device_port = port->number - port->serial->minor;
1736
1737 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001738 this_urb = p_priv->outcont_urb;
1739 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001740 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 return -1;
1742 }
1743
1744 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001745 Don't overwrite resend for open/close condition. */
1746 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 p_priv->resend_cont = reset_port + 1;
1748 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001749 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001751 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 }
1753
Alan Coxdeb91682008-07-22 11:13:08 +01001754 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
1756 msg.setBaudRate = 1;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001757 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1758 &msg.baudHi, &msg.baudLo, NULL,
1759 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1760 dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001761 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 msg.baudLo = 0xff;
1763 msg.baudHi = 0xb2; /* Values for 9600 baud */
1764 }
1765
1766 /* If parity is enabled, we must calculate it ourselves. */
1767 msg.parity = 0; /* XXX for now */
1768
1769 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1770 msg.xonFlowControl = 0;
1771
Alan Coxdeb91682008-07-22 11:13:08 +01001772 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 msg.rts = p_priv->rts_state;
1774 msg.dtr = p_priv->dtr_state;
1775
1776 msg.forwardingLength = 16;
1777 msg.forwardMs = 10;
1778 msg.breakThreshold = 45;
1779 msg.xonChar = 17;
1780 msg.xoffChar = 19;
1781
1782 /*msg.returnStatus = 1;
1783 msg.resetDataToggle = 0xff;*/
1784 /* Opening port */
1785 if (reset_port == 1) {
1786 msg._txOn = 1;
1787 msg._txOff = 0;
1788 msg.txFlush = 0;
1789 msg.txForceXoff = 0;
1790 msg.txBreak = 0;
1791 msg.rxOn = 1;
1792 msg.rxOff = 0;
1793 msg.rxFlush = 1;
1794 msg.rxForward = 0;
1795 msg.returnStatus = 0;
1796 msg.resetDataToggle = 0xff;
1797 }
1798 /* Closing port */
1799 else if (reset_port == 2) {
1800 msg._txOn = 0;
1801 msg._txOff = 1;
1802 msg.txFlush = 0;
1803 msg.txForceXoff = 0;
1804 msg.txBreak = 0;
1805 msg.rxOn = 0;
1806 msg.rxOff = 1;
1807 msg.rxFlush = 1;
1808 msg.rxForward = 0;
1809 msg.returnStatus = 0;
1810 msg.resetDataToggle = 0;
1811 }
1812 /* Sending intermediate configs */
1813 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001814 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 msg._txOff = 0;
1816 msg.txFlush = 0;
1817 msg.txForceXoff = 0;
1818 msg.txBreak = (p_priv->break_on);
1819 msg.rxOn = 0;
1820 msg.rxOff = 0;
1821 msg.rxFlush = 0;
1822 msg.rxForward = 0;
1823 msg.returnStatus = 0;
1824 msg.resetDataToggle = 0x0;
1825 }
1826
1827 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001828 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
1830 /* send the data out the device on control endpoint */
1831 this_urb->transfer_buffer_length = sizeof(msg);
1832
Alan Coxdeb91682008-07-22 11:13:08 +01001833 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1834 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001835 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836#if 0
1837 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001838 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 this_urb->transfer_buffer_length);
1840 }
1841#endif
1842
Alan Coxa5b6f602008-04-08 17:16:06 +01001843 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844}
1845
1846static int keyspan_usa49_send_setup(struct usb_serial *serial,
1847 struct usb_serial_port *port,
1848 int reset_port)
1849{
Lucy McCoy0ca12682007-05-18 12:10:41 -07001850 struct keyspan_usa49_portControlMessage msg;
1851 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 struct keyspan_serial_private *s_priv;
1853 struct keyspan_port_private *p_priv;
1854 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 struct urb *this_urb;
1856 int err, device_port;
1857
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 s_priv = usb_get_serial_data(serial);
1859 p_priv = usb_get_serial_port_data(port);
1860 d_details = s_priv->device_details;
1861
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 this_urb = s_priv->glocont_urb;
1863
Lucy McCoy0ca12682007-05-18 12:10:41 -07001864 /* Work out which port within the device is being setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 device_port = port->number - port->serial->minor;
1866
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301867 /* Make sure we have an urb then send the message */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001869 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 return -1;
1871 }
1872
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001873 dev_dbg(&port->dev, "%s - endpoint %d port %d (%d)\n",
1874 __func__, usb_pipeendpoint(this_urb->pipe),
1875 port->number, device_port);
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301876
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001878 Don't overwrite resend for open/close condition. */
1879 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001881
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001883 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001885 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 }
1887
Alan Coxdeb91682008-07-22 11:13:08 +01001888 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
1890 /*msg.portNumber = port->number;*/
1891 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01001892
1893 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 if (p_priv->old_baud != p_priv->baud) {
1895 p_priv->old_baud = p_priv->baud;
1896 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001897 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1898 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1899 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1900 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1901 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 msg.baudLo = 0;
1903 msg.baudHi = 125; /* Values for 9600 baud */
1904 msg.prescaler = 10;
1905 }
Alan Coxdeb91682008-07-22 11:13:08 +01001906 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 }
1908
Ben Minerds2b982ab2012-07-12 00:10:16 +10001909 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 switch (p_priv->cflag & CSIZE) {
1911 case CS5:
1912 msg.lcr |= USA_DATABITS_5;
1913 break;
1914 case CS6:
1915 msg.lcr |= USA_DATABITS_6;
1916 break;
1917 case CS7:
1918 msg.lcr |= USA_DATABITS_7;
1919 break;
1920 case CS8:
1921 msg.lcr |= USA_DATABITS_8;
1922 break;
1923 }
1924 if (p_priv->cflag & PARENB) {
1925 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001926 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001927 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 }
1929 msg.setLcr = 0xff;
1930
1931 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1932 msg.xonFlowControl = 0;
1933 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01001934
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 msg.forwardingLength = 16;
1936 msg.xonChar = 17;
1937 msg.xoffChar = 19;
1938
Alan Coxdeb91682008-07-22 11:13:08 +01001939 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 if (reset_port == 1) {
1941 msg._txOn = 1;
1942 msg._txOff = 0;
1943 msg.txFlush = 0;
1944 msg.txBreak = 0;
1945 msg.rxOn = 1;
1946 msg.rxOff = 0;
1947 msg.rxFlush = 1;
1948 msg.rxForward = 0;
1949 msg.returnStatus = 0;
1950 msg.resetDataToggle = 0xff;
1951 msg.enablePort = 1;
1952 msg.disablePort = 0;
1953 }
1954 /* Closing port */
1955 else if (reset_port == 2) {
1956 msg._txOn = 0;
1957 msg._txOff = 1;
1958 msg.txFlush = 0;
1959 msg.txBreak = 0;
1960 msg.rxOn = 0;
1961 msg.rxOff = 1;
1962 msg.rxFlush = 1;
1963 msg.rxForward = 0;
1964 msg.returnStatus = 0;
1965 msg.resetDataToggle = 0;
1966 msg.enablePort = 0;
1967 msg.disablePort = 1;
1968 }
1969 /* Sending intermediate configs */
1970 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001971 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 msg._txOff = 0;
1973 msg.txFlush = 0;
1974 msg.txBreak = (p_priv->break_on);
1975 msg.rxOn = 0;
1976 msg.rxOff = 0;
1977 msg.rxFlush = 0;
1978 msg.rxForward = 0;
1979 msg.returnStatus = 0;
1980 msg.resetDataToggle = 0x0;
1981 msg.enablePort = 0;
1982 msg.disablePort = 0;
1983 }
1984
Alan Coxdeb91682008-07-22 11:13:08 +01001985 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 msg.setRts = 0xff;
1987 msg.rts = p_priv->rts_state;
1988
1989 msg.setDtr = 0xff;
1990 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001991
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
Alan Coxdeb91682008-07-22 11:13:08 +01001994 /* if the device is a 49wg, we send control message on usb
1995 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07001996
1997 if (d_details->product_id == keyspan_usa49wg_product_id) {
1998 dr = (void *)(s_priv->ctrl_buf);
1999 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
2000 dr->bRequest = 0xB0; /* 49wg control message */;
2001 dr->wValue = 0;
2002 dr->wIndex = 0;
2003 dr->wLength = cpu_to_le16(sizeof(msg));
2004
Alan Coxdeb91682008-07-22 11:13:08 +01002005 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07002006
Alan Coxdeb91682008-07-22 11:13:08 +01002007 usb_fill_control_urb(this_urb, serial->dev,
2008 usb_sndctrlpipe(serial->dev, 0),
2009 (unsigned char *)dr, s_priv->glocont_buf,
2010 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002011
2012 } else {
2013 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01002014
Lucy McCoy0ca12682007-05-18 12:10:41 -07002015 /* send the data out the device on control endpoint */
2016 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002017 }
Alan Coxdeb91682008-07-22 11:13:08 +01002018 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2019 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002020 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021#if 0
2022 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002023 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__,
2024 outcont_urb, this_urb->transfer_buffer_length,
2025 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 }
2027#endif
2028
Alan Coxa5b6f602008-04-08 17:16:06 +01002029 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030}
2031
2032static int keyspan_usa90_send_setup(struct usb_serial *serial,
2033 struct usb_serial_port *port,
2034 int reset_port)
2035{
Alan Coxdeb91682008-07-22 11:13:08 +01002036 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 struct keyspan_serial_private *s_priv;
2038 struct keyspan_port_private *p_priv;
2039 const struct keyspan_device_details *d_details;
2040 struct urb *this_urb;
2041 int err;
2042 u8 prescaler;
2043
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 s_priv = usb_get_serial_data(serial);
2045 p_priv = usb_get_serial_port_data(port);
2046 d_details = s_priv->device_details;
2047
2048 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002049 this_urb = p_priv->outcont_urb;
2050 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002051 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 return -1;
2053 }
2054
2055 /* Save reset port val for resend.
2056 Don't overwrite resend for open/close condition. */
2057 if ((reset_port + 1) > p_priv->resend_cont)
2058 p_priv->resend_cont = reset_port + 1;
2059 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002060 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002062 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 }
2064
Alan Coxdeb91682008-07-22 11:13:08 +01002065 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
Alan Coxdeb91682008-07-22 11:13:08 +01002067 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 if (p_priv->old_baud != p_priv->baud) {
2069 p_priv->old_baud = p_priv->baud;
2070 msg.setClocking = 0x01;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002071 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2072 &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2073 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2074 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 p_priv->baud = 9600;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002076 d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2078 }
2079 msg.setRxMode = 1;
2080 msg.setTxMode = 1;
2081 }
2082
2083 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002084 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 msg.rxMode = RXMODE_DMA;
2086 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002087 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 msg.rxMode = RXMODE_BYHAND;
2089 msg.txMode = TXMODE_BYHAND;
2090 }
2091
Ben Minerds2b982ab2012-07-12 00:10:16 +10002092 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 switch (p_priv->cflag & CSIZE) {
2094 case CS5:
2095 msg.lcr |= USA_DATABITS_5;
2096 break;
2097 case CS6:
2098 msg.lcr |= USA_DATABITS_6;
2099 break;
2100 case CS7:
2101 msg.lcr |= USA_DATABITS_7;
2102 break;
2103 case CS8:
2104 msg.lcr |= USA_DATABITS_8;
2105 break;
2106 }
2107 if (p_priv->cflag & PARENB) {
2108 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002109 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002110 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 }
2112 if (p_priv->old_cflag != p_priv->cflag) {
2113 p_priv->old_cflag = p_priv->cflag;
2114 msg.setLcr = 0x01;
2115 }
2116
2117 if (p_priv->flow_control == flow_cts)
2118 msg.txFlowControl = TXFLOW_CTS;
2119 msg.setTxFlowControl = 0x01;
2120 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002121
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002123 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 msg.txAckSetting = 0;
2125 msg.xonChar = 17;
2126 msg.xoffChar = 19;
2127
Alan Coxdeb91682008-07-22 11:13:08 +01002128 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 if (reset_port == 1) {
2130 msg.portEnabled = 1;
2131 msg.rxFlush = 1;
2132 msg.txBreak = (p_priv->break_on);
2133 }
2134 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002135 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 /* Sending intermediate configs */
2138 else {
Alan Stern1f871582010-02-17 10:05:47 -05002139 msg.portEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 msg.txBreak = (p_priv->break_on);
2141 }
2142
Alan Coxdeb91682008-07-22 11:13:08 +01002143 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 msg.setRts = 0x01;
2145 msg.rts = p_priv->rts_state;
2146
2147 msg.setDtr = 0x01;
2148 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002149
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002151 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2152
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 /* send the data out the device on control endpoint */
2154 this_urb->transfer_buffer_length = sizeof(msg);
2155
Alan Coxdeb91682008-07-22 11:13:08 +01002156 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2157 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002158 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002159 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160}
2161
Lucy McCoy0ca12682007-05-18 12:10:41 -07002162static int keyspan_usa67_send_setup(struct usb_serial *serial,
2163 struct usb_serial_port *port,
2164 int reset_port)
2165{
2166 struct keyspan_usa67_portControlMessage msg;
2167 struct keyspan_serial_private *s_priv;
2168 struct keyspan_port_private *p_priv;
2169 const struct keyspan_device_details *d_details;
2170 struct urb *this_urb;
2171 int err, device_port;
2172
Lucy McCoy0ca12682007-05-18 12:10:41 -07002173 s_priv = usb_get_serial_data(serial);
2174 p_priv = usb_get_serial_port_data(port);
2175 d_details = s_priv->device_details;
2176
2177 this_urb = s_priv->glocont_urb;
2178
2179 /* Work out which port within the device is being setup */
2180 device_port = port->number - port->serial->minor;
2181
2182 /* Make sure we have an urb then send the message */
2183 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002184 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002185 port->number);
2186 return -1;
2187 }
2188
2189 /* Save reset port val for resend.
2190 Don't overwrite resend for open/close condition. */
2191 if ((reset_port + 1) > p_priv->resend_cont)
2192 p_priv->resend_cont = reset_port + 1;
2193 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002194 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002195 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002196 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002197 }
2198
2199 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2200
2201 msg.port = device_port;
2202
2203 /* Only set baud rate if it's changed */
2204 if (p_priv->old_baud != p_priv->baud) {
2205 p_priv->old_baud = p_priv->baud;
2206 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002207 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2208 &msg.baudHi, &msg.baudLo, &msg.prescaler,
2209 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2210 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2211 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002212 msg.baudLo = 0;
2213 msg.baudHi = 125; /* Values for 9600 baud */
2214 msg.prescaler = 10;
2215 }
2216 msg.setPrescaler = 0xff;
2217 }
2218
2219 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2220 switch (p_priv->cflag & CSIZE) {
2221 case CS5:
2222 msg.lcr |= USA_DATABITS_5;
2223 break;
2224 case CS6:
2225 msg.lcr |= USA_DATABITS_6;
2226 break;
2227 case CS7:
2228 msg.lcr |= USA_DATABITS_7;
2229 break;
2230 case CS8:
2231 msg.lcr |= USA_DATABITS_8;
2232 break;
2233 }
2234 if (p_priv->cflag & PARENB) {
2235 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002236 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002237 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002238 }
2239 msg.setLcr = 0xff;
2240
2241 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2242 msg.xonFlowControl = 0;
2243 msg.setFlowControl = 0xff;
2244 msg.forwardingLength = 16;
2245 msg.xonChar = 17;
2246 msg.xoffChar = 19;
2247
2248 if (reset_port == 1) {
2249 /* Opening port */
2250 msg._txOn = 1;
2251 msg._txOff = 0;
2252 msg.txFlush = 0;
2253 msg.txBreak = 0;
2254 msg.rxOn = 1;
2255 msg.rxOff = 0;
2256 msg.rxFlush = 1;
2257 msg.rxForward = 0;
2258 msg.returnStatus = 0;
2259 msg.resetDataToggle = 0xff;
2260 } else if (reset_port == 2) {
2261 /* Closing port */
2262 msg._txOn = 0;
2263 msg._txOff = 1;
2264 msg.txFlush = 0;
2265 msg.txBreak = 0;
2266 msg.rxOn = 0;
2267 msg.rxOff = 1;
2268 msg.rxFlush = 1;
2269 msg.rxForward = 0;
2270 msg.returnStatus = 0;
2271 msg.resetDataToggle = 0;
2272 } else {
2273 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002274 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002275 msg._txOff = 0;
2276 msg.txFlush = 0;
2277 msg.txBreak = (p_priv->break_on);
2278 msg.rxOn = 0;
2279 msg.rxOff = 0;
2280 msg.rxFlush = 0;
2281 msg.rxForward = 0;
2282 msg.returnStatus = 0;
2283 msg.resetDataToggle = 0x0;
2284 }
2285
2286 /* Do handshaking outputs */
2287 msg.setTxTriState_setRts = 0xff;
2288 msg.txTriState_rts = p_priv->rts_state;
2289
2290 msg.setHskoa_setDtr = 0xff;
2291 msg.hskoa_dtr = p_priv->dtr_state;
2292
2293 p_priv->resend_cont = 0;
2294
2295 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2296
2297 /* send the data out the device on control endpoint */
2298 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002299
2300 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2301 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002302 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002303 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002304}
2305
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2307{
2308 struct usb_serial *serial = port->serial;
2309 struct keyspan_serial_private *s_priv;
2310 const struct keyspan_device_details *d_details;
2311
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 s_priv = usb_get_serial_data(serial);
2313 d_details = s_priv->device_details;
2314
2315 switch (d_details->msg_format) {
2316 case msg_usa26:
2317 keyspan_usa26_send_setup(serial, port, reset_port);
2318 break;
2319 case msg_usa28:
2320 keyspan_usa28_send_setup(serial, port, reset_port);
2321 break;
2322 case msg_usa49:
2323 keyspan_usa49_send_setup(serial, port, reset_port);
2324 break;
2325 case msg_usa90:
2326 keyspan_usa90_send_setup(serial, port, reset_port);
2327 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002328 case msg_usa67:
2329 keyspan_usa67_send_setup(serial, port, reset_port);
2330 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 }
2332}
2333
2334
2335/* Gets called by the "real" driver (ie once firmware is loaded
2336 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002337static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338{
2339 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 const struct keyspan_device_details *d_details;
2342
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002344 if (d_details->product_id ==
2345 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 break;
2347 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002348 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2349 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 return 1;
2351 }
2352
2353 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002354 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 if (!s_priv) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002356 dev_dbg(&serial->dev->dev, "%s - kmalloc for keyspan_serial_private failed.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 return -ENOMEM;
2358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359
2360 s_priv->device_details = d_details;
2361 usb_set_serial_data(serial, s_priv);
2362
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 keyspan_setup_urbs(serial);
2364
Lucy McCoy0ca12682007-05-18 12:10:41 -07002365 if (s_priv->instat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002366 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2367 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002368 dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002369 }
2370 if (s_priv->indat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002371 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2372 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002373 dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 }
Alan Coxdeb91682008-07-22 11:13:08 +01002375
Alan Coxa5b6f602008-04-08 17:16:06 +01002376 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377}
2378
Alan Sternf9c99bb2009-06-02 11:53:55 -04002379static void keyspan_disconnect(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002381 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 s_priv = usb_get_serial_data(serial);
2384
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 stop_urb(s_priv->instat_urb);
2386 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002387 stop_urb(s_priv->indat_urb);
Alan Sternf9c99bb2009-06-02 11:53:55 -04002388}
2389
2390static void keyspan_release(struct usb_serial *serial)
2391{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002392 struct keyspan_serial_private *s_priv;
Alan Sternf9c99bb2009-06-02 11:53:55 -04002393
Alan Sternf9c99bb2009-06-02 11:53:55 -04002394 s_priv = usb_get_serial_data(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002396 usb_free_urb(s_priv->instat_urb);
2397 usb_free_urb(s_priv->indat_urb);
2398 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002400 kfree(s_priv);
2401}
2402
2403static int keyspan_port_probe(struct usb_serial_port *port)
2404{
2405 struct usb_serial *serial = port->serial;
Bjørn Morkf0e3e352012-11-10 10:13:42 +01002406 struct keyspan_serial_private *s_priv;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002407 struct keyspan_port_private *p_priv;
2408 const struct keyspan_device_details *d_details;
2409 struct callbacks *cback;
2410 int endp;
2411 int port_num;
2412 int i;
2413
2414 s_priv = usb_get_serial_data(serial);
2415 d_details = s_priv->device_details;
2416
2417 p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL);
2418 if (!p_priv)
2419 return -ENOMEM;
2420
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002421 p_priv->device_details = d_details;
2422
2423 /* Setup values for the various callback routines */
2424 cback = &keyspan_callbacks[d_details->msg_format];
2425
2426 port_num = port->number - port->serial->minor;
2427
2428 /* Do indat endpoints first, once for each flip */
2429 endp = d_details->indat_endpoints[port_num];
2430 for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
2431 p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
2432 USB_DIR_IN, port,
2433 p_priv->in_buffer[i], 64,
2434 cback->indat_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 }
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002436 /* outdat endpoints also have flip */
2437 endp = d_details->outdat_endpoints[port_num];
2438 for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
2439 p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
2440 USB_DIR_OUT, port,
2441 p_priv->out_buffer[i], 64,
2442 cback->outdat_callback);
2443 }
2444 /* inack endpoint */
2445 p_priv->inack_urb = keyspan_setup_urb(serial,
2446 d_details->inack_endpoints[port_num],
2447 USB_DIR_IN, port,
2448 p_priv->inack_buffer, 1,
2449 cback->inack_callback);
2450 /* outcont endpoint */
2451 p_priv->outcont_urb = keyspan_setup_urb(serial,
2452 d_details->outcont_endpoints[port_num],
2453 USB_DIR_OUT, port,
2454 p_priv->outcont_buffer, 64,
2455 cback->outcont_callback);
2456
2457 usb_set_serial_port_data(port, p_priv);
2458
2459 return 0;
2460}
2461
2462static int keyspan_port_remove(struct usb_serial_port *port)
2463{
2464 struct keyspan_port_private *p_priv;
2465 int i;
2466
2467 p_priv = usb_get_serial_port_data(port);
2468
2469 stop_urb(p_priv->inack_urb);
2470 stop_urb(p_priv->outcont_urb);
2471 for (i = 0; i < 2; i++) {
2472 stop_urb(p_priv->in_urbs[i]);
2473 stop_urb(p_priv->out_urbs[i]);
2474 }
2475
2476 usb_free_urb(p_priv->inack_urb);
2477 usb_free_urb(p_priv->outcont_urb);
2478 for (i = 0; i < 2; i++) {
2479 usb_free_urb(p_priv->in_urbs[i]);
2480 usb_free_urb(p_priv->out_urbs[i]);
2481 }
2482
2483 kfree(p_priv);
2484
2485 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486}
2487
Alan Coxdeb91682008-07-22 11:13:08 +01002488MODULE_AUTHOR(DRIVER_AUTHOR);
2489MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490MODULE_LICENSE("GPL");
2491
David Woodhouse2971c572008-05-30 14:04:03 +03002492MODULE_FIRMWARE("keyspan/usa28.fw");
2493MODULE_FIRMWARE("keyspan/usa28x.fw");
2494MODULE_FIRMWARE("keyspan/usa28xa.fw");
2495MODULE_FIRMWARE("keyspan/usa28xb.fw");
2496MODULE_FIRMWARE("keyspan/usa19.fw");
2497MODULE_FIRMWARE("keyspan/usa19qi.fw");
2498MODULE_FIRMWARE("keyspan/mpr.fw");
2499MODULE_FIRMWARE("keyspan/usa19qw.fw");
2500MODULE_FIRMWARE("keyspan/usa18x.fw");
2501MODULE_FIRMWARE("keyspan/usa19w.fw");
2502MODULE_FIRMWARE("keyspan/usa49w.fw");
2503MODULE_FIRMWARE("keyspan/usa49wlc.fw");