blob: d6960aebe246f24b623132c1c2eeca5f6484832e [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
Johan Hovoldbad41a52013-08-13 13:27:37 +020053#define IN_BUFLEN 64
54#define OUT_BUFLEN 64
55#define INACK_BUFLEN 1
56#define OUTCONT_BUFLEN 64
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58 /* Per device and per port private data */
59struct keyspan_serial_private {
60 const struct keyspan_device_details *device_details;
61
62 struct urb *instat_urb;
Johan Hovold2fcd1c92013-08-13 13:27:36 +020063 char *instat_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Alan Coxdeb91682008-07-22 11:13:08 +010065 /* added to support 49wg, where data from all 4 ports comes in
66 on 1 EP and high-speed supported */
Lucy McCoy0ca12682007-05-18 12:10:41 -070067 struct urb *indat_urb;
Johan Hovold2fcd1c92013-08-13 13:27:36 +020068 char *indat_buf;
Lucy McCoy0ca12682007-05-18 12:10:41 -070069
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 /* XXX this one probably will need a lock */
71 struct urb *glocont_urb;
Johan Hovold2fcd1c92013-08-13 13:27:36 +020072 char *glocont_buf;
73 char *ctrl_buf; /* for EP0 control message */
Linus Torvalds1da177e2005-04-16 15:20:36 -070074};
75
76struct keyspan_port_private {
77 /* Keep track of which input & output endpoints to use */
78 int in_flip;
79 int out_flip;
80
81 /* Keep duplicate of device details in each port
82 structure as well - simplifies some of the
83 callback functions etc. */
84 const struct keyspan_device_details *device_details;
85
86 /* Input endpoints and buffer for this port */
87 struct urb *in_urbs[2];
Johan Hovoldbad41a52013-08-13 13:27:37 +020088 char *in_buffer[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 /* Output endpoints and buffer for this port */
90 struct urb *out_urbs[2];
Johan Hovoldbad41a52013-08-13 13:27:37 +020091 char *out_buffer[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93 /* Input ack endpoint */
94 struct urb *inack_urb;
Johan Hovoldbad41a52013-08-13 13:27:37 +020095 char *inack_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97 /* Output control endpoint */
98 struct urb *outcont_urb;
Johan Hovoldbad41a52013-08-13 13:27:37 +020099 char *outcont_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
101 /* Settings for the port */
102 int baud;
103 int old_baud;
104 unsigned int cflag;
105 unsigned int old_cflag;
106 enum {flow_none, flow_cts, flow_xon} flow_control;
107 int rts_state; /* Handshaking pins (outputs) */
108 int dtr_state;
109 int cts_state; /* Handshaking pins (inputs) */
110 int dsr_state;
111 int dcd_state;
112 int ri_state;
113 int break_on;
114
115 unsigned long tx_start_time[2];
116 int resend_cont; /* need to resend control packet */
117};
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119/* Include Keyspan message headers. All current Keyspan Adapters
Lucy McCoy0ca12682007-05-18 12:10:41 -0700120 make use of one of five message formats which are referred
Alan Coxdeb91682008-07-22 11:13:08 +0100121 to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and
122 within this driver. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#include "keyspan_usa26msg.h"
124#include "keyspan_usa28msg.h"
125#include "keyspan_usa49msg.h"
126#include "keyspan_usa90msg.h"
Lucy McCoy0ca12682007-05-18 12:10:41 -0700127#include "keyspan_usa67msg.h"
Alan Coxdeb91682008-07-22 11:13:08 +0100128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -0700130module_usb_serial_driver(serial_drivers, keyspan_ids_combined);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
Alan Cox95da3102008-07-22 11:09:07 +0100132static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
Alan Cox95da3102008-07-22 11:09:07 +0100134 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 struct keyspan_port_private *p_priv;
136
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 p_priv = usb_get_serial_port_data(port);
138
139 if (break_state == -1)
140 p_priv->break_on = 1;
141 else
142 p_priv->break_on = 0;
143
144 keyspan_send_setup(port, 0);
145}
146
147
Alan Coxdeb91682008-07-22 11:13:08 +0100148static void keyspan_set_termios(struct tty_struct *tty,
Alan Cox95da3102008-07-22 11:09:07 +0100149 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150{
151 int baud_rate, device_port;
152 struct keyspan_port_private *p_priv;
153 const struct keyspan_device_details *d_details;
154 unsigned int cflag;
155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 p_priv = usb_get_serial_port_data(port);
157 d_details = p_priv->device_details;
Alan Coxadc8d742012-07-14 15:31:47 +0100158 cflag = tty->termios.c_cflag;
Greg Kroah-Hartman11438322013-06-06 10:32:00 -0700159 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161 /* Baud rate calculation takes baud rate as an integer
162 so other rates can be generated if desired. */
Alan Cox74240b02007-10-18 01:24:20 -0700163 baud_rate = tty_get_baud_rate(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100164 /* If no match or invalid, don't change */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700165 if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
167 /* FIXME - more to do here to ensure rate changes cleanly */
Alan Cox74240b02007-10-18 01:24:20 -0700168 /* FIXME - calcuate exact rate from divisor ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 p_priv->baud = baud_rate;
Alan Cox74240b02007-10-18 01:24:20 -0700170 } else
171 baud_rate = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
Alan Cox74240b02007-10-18 01:24:20 -0700173 tty_encode_baud_rate(tty, baud_rate, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 /* set CTS/RTS handshake etc. */
175 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +1000176 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
Alan Cox74240b02007-10-18 01:24:20 -0700178 /* Mark/Space not supported */
Alan Coxadc8d742012-07-14 15:31:47 +0100179 tty->termios.c_cflag &= ~CMSPAR;
Alan Cox74240b02007-10-18 01:24:20 -0700180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 keyspan_send_setup(port, 0);
182}
183
Alan Cox60b33c12011-02-14 16:26:14 +0000184static int keyspan_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
Alan Cox95da3102008-07-22 11:09:07 +0100186 struct usb_serial_port *port = tty->driver_data;
187 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 unsigned int value;
Alan Coxdeb91682008-07-22 11:13:08 +0100189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
191 ((p_priv->dtr_state) ? TIOCM_DTR : 0) |
192 ((p_priv->cts_state) ? TIOCM_CTS : 0) |
193 ((p_priv->dsr_state) ? TIOCM_DSR : 0) |
194 ((p_priv->dcd_state) ? TIOCM_CAR : 0) |
Alan Coxdeb91682008-07-22 11:13:08 +0100195 ((p_priv->ri_state) ? TIOCM_RNG : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
197 return value;
198}
199
Alan Cox20b9d172011-02-14 16:26:50 +0000200static int keyspan_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 unsigned int set, unsigned int clear)
202{
Alan Cox95da3102008-07-22 11:09:07 +0100203 struct usb_serial_port *port = tty->driver_data;
204 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100205
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 if (set & TIOCM_RTS)
207 p_priv->rts_state = 1;
208 if (set & TIOCM_DTR)
209 p_priv->dtr_state = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 if (clear & TIOCM_RTS)
211 p_priv->rts_state = 0;
212 if (clear & TIOCM_DTR)
213 p_priv->dtr_state = 0;
214 keyspan_send_setup(port, 0);
215 return 0;
216}
217
Alan Cox95da3102008-07-22 11:09:07 +0100218/* Write function is similar for the four protocols used
219 with only a minor change for usa90 (usa19hs) required */
220static int keyspan_write(struct tty_struct *tty,
221 struct usb_serial_port *port, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222{
223 struct keyspan_port_private *p_priv;
224 const struct keyspan_device_details *d_details;
225 int flip;
226 int left, todo;
227 struct urb *this_urb;
Alan Coxdeb91682008-07-22 11:13:08 +0100228 int err, maxDataLen, dataOffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
230 p_priv = usb_get_serial_port_data(port);
231 d_details = p_priv->device_details;
232
233 if (d_details->msg_format == msg_usa90) {
Alan Coxdeb91682008-07-22 11:13:08 +0100234 maxDataLen = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 dataOffset = 0;
236 } else {
237 maxDataLen = 63;
238 dataOffset = 1;
239 }
Alan Coxdeb91682008-07-22 11:13:08 +0100240
Greg Kroah-Hartman11438322013-06-06 10:32:00 -0700241 dev_dbg(&port->dev, "%s - %d chars, flip=%d\n", __func__, count,
242 p_priv->out_flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244 for (left = count; left > 0; left -= todo) {
245 todo = left;
246 if (todo > maxDataLen)
247 todo = maxDataLen;
248
249 flip = p_priv->out_flip;
Alan Coxdeb91682008-07-22 11:13:08 +0100250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 /* Check we have a valid urb/endpoint before we use it... */
Alan Coxdeb91682008-07-22 11:13:08 +0100252 this_urb = p_priv->out_urbs[flip];
253 if (this_urb == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 /* no bulk out, so return 0 bytes written */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700255 dev_dbg(&port->dev, "%s - no output urb :(\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 return count;
257 }
258
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700259 dev_dbg(&port->dev, "%s - endpoint %d flip %d\n",
Alan Coxdeb91682008-07-22 11:13:08 +0100260 __func__, usb_pipeendpoint(this_urb->pipe), flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +0100263 if (time_before(jiffies,
264 p_priv->tx_start_time[flip] + 10 * HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 usb_unlink_urb(this_urb);
267 break;
268 }
269
Alan Coxdeb91682008-07-22 11:13:08 +0100270 /* First byte in buffer is "last flag" (except for usa19hx)
271 - unused so for now so set to zero */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 ((char *)this_urb->transfer_buffer)[0] = 0;
273
Alan Coxdeb91682008-07-22 11:13:08 +0100274 memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 buf += todo;
276
277 /* send the data out the bulk port */
278 this_urb->transfer_buffer_length = todo + dataOffset;
279
Alan Coxdeb91682008-07-22 11:13:08 +0100280 err = usb_submit_urb(this_urb, GFP_ATOMIC);
281 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700282 dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 p_priv->tx_start_time[flip] = jiffies;
284
285 /* Flip for next time if usa26 or usa28 interface
286 (not used on usa49) */
287 p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
288 }
289
290 return count - left;
291}
292
David Howells7d12e782006-10-05 14:55:46 +0100293static void usa26_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
295 int i, err;
296 int endpoint;
297 struct usb_serial_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700299 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 endpoint = usb_pipeendpoint(urb->pipe);
302
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700303 if (status) {
Stefan Hubnera8ffa0b2012-12-13 22:45:00 +0100304 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700305 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 return;
307 }
308
Ming Leicdc97792008-02-24 18:41:47 +0800309 port = urb->context;
Jiri Slaby2e124b42013-01-03 15:53:06 +0100310 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 /* 0x80 bit is error flag */
312 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100313 /* no errors on individual bytes, only
314 possible overrun err */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100316 err = TTY_OVERRUN;
317 else
318 err = 0;
319 for (i = 1; i < urb->actual_length ; ++i)
Jiri Slaby92a19f92013-01-03 15:53:03 +0100320 tty_insert_flip_char(&port->port, data[i], err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 } else {
322 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700323 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 for (i = 0; i + 1 < urb->actual_length; i += 2) {
325 int stat = data[i], flag = 0;
326 if (stat & RXERROR_OVERRUN)
327 flag |= TTY_OVERRUN;
328 if (stat & RXERROR_FRAMING)
329 flag |= TTY_FRAME;
330 if (stat & RXERROR_PARITY)
331 flag |= TTY_PARITY;
332 /* XXX should handle break (0x10) */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100333 tty_insert_flip_char(&port->port, data[i+1],
334 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 }
336 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100337 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 }
Alan Coxdeb91682008-07-22 11:13:08 +0100339
340 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500341 err = usb_submit_urb(urb, GFP_ATOMIC);
342 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700343 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344}
345
Alan Coxdeb91682008-07-22 11:13:08 +0100346/* Outdat handling is common for all devices */
David Howells7d12e782006-10-05 14:55:46 +0100347static void usa2x_outdat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
349 struct usb_serial_port *port;
350 struct keyspan_port_private *p_priv;
351
Ming Leicdc97792008-02-24 18:41:47 +0800352 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 p_priv = usb_get_serial_port_data(port);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700354 dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
Alan Stern1f871582010-02-17 10:05:47 -0500356 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357}
358
David Howells7d12e782006-10-05 14:55:46 +0100359static void usa26_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361}
362
David Howells7d12e782006-10-05 14:55:46 +0100363static void usa26_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
365 struct usb_serial_port *port;
366 struct keyspan_port_private *p_priv;
367
Ming Leicdc97792008-02-24 18:41:47 +0800368 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 p_priv = usb_get_serial_port_data(port);
370
371 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700372 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100373 keyspan_usa26_send_setup(port->serial, port,
374 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 }
376}
377
David Howells7d12e782006-10-05 14:55:46 +0100378static void usa26_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
380 unsigned char *data = urb->transfer_buffer;
381 struct keyspan_usa26_portStatusMessage *msg;
382 struct usb_serial *serial;
383 struct usb_serial_port *port;
384 struct keyspan_port_private *p_priv;
385 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700386 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
Ming Leicdc97792008-02-24 18:41:47 +0800388 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700390 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700391 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 return;
393 }
394 if (urb->actual_length != 9) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700395 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 goto exit;
397 }
398
399 msg = (struct keyspan_usa26_portStatusMessage *)data;
400
401#if 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700402 dev_dbg(&urb->dev->dev,
403 "%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
404 __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr,
405 msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled,
406 msg->controlResponse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407#endif
408
409 /* Now do something useful with the data */
410
411
Alan Coxdeb91682008-07-22 11:13:08 +0100412 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700414 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 goto exit;
416 }
417 port = serial->port[msg->port];
418 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100419
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 /* Update handshaking pin state information */
421 old_dcd_state = p_priv->dcd_state;
422 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
423 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
424 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
425 p_priv->ri_state = ((msg->ri) ? 1 : 0);
426
Jiri Slabyaa27a092013-03-07 13:12:30 +0100427 if (old_dcd_state != p_priv->dcd_state)
428 tty_port_tty_hangup(&port->port, true);
Alan Coxdeb91682008-07-22 11:13:08 +0100429
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100431 err = usb_submit_urb(urb, GFP_ATOMIC);
432 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700433 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434exit: ;
435}
436
David Howells7d12e782006-10-05 14:55:46 +0100437static void usa26_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439}
440
441
David Howells7d12e782006-10-05 14:55:46 +0100442static void usa28_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
Alan Coxf035a8a2008-07-22 11:13:32 +0100444 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 struct usb_serial_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 unsigned char *data;
447 struct keyspan_port_private *p_priv;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700448 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
Ming Leicdc97792008-02-24 18:41:47 +0800450 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 p_priv = usb_get_serial_port_data(port);
452 data = urb->transfer_buffer;
453
454 if (urb != p_priv->in_urbs[p_priv->in_flip])
455 return;
456
457 do {
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700458 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700459 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
460 __func__, status, usb_pipeendpoint(urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 return;
462 }
463
Ming Leicdc97792008-02-24 18:41:47 +0800464 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 p_priv = usb_get_serial_port_data(port);
466 data = urb->transfer_buffer;
467
Jiri Slaby2e124b42013-01-03 15:53:06 +0100468 if (urb->actual_length) {
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100469 tty_insert_flip_string(&port->port, data,
470 urb->actual_length);
Jiri Slaby2e124b42013-01-03 15:53:06 +0100471 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 }
473
474 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500475 err = usb_submit_urb(urb, GFP_ATOMIC);
476 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700477 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
Alan Stern1f871582010-02-17 10:05:47 -0500478 __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 p_priv->in_flip ^= 1;
480
481 urb = p_priv->in_urbs[p_priv->in_flip];
482 } while (urb->status != -EINPROGRESS);
483}
484
David Howells7d12e782006-10-05 14:55:46 +0100485static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487}
488
David Howells7d12e782006-10-05 14:55:46 +0100489static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490{
491 struct usb_serial_port *port;
492 struct keyspan_port_private *p_priv;
493
Ming Leicdc97792008-02-24 18:41:47 +0800494 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 p_priv = usb_get_serial_port_data(port);
496
497 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700498 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100499 keyspan_usa28_send_setup(port->serial, port,
500 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 }
502}
503
David Howells7d12e782006-10-05 14:55:46 +0100504static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505{
506 int err;
507 unsigned char *data = urb->transfer_buffer;
508 struct keyspan_usa28_portStatusMessage *msg;
509 struct usb_serial *serial;
510 struct usb_serial_port *port;
511 struct keyspan_port_private *p_priv;
512 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700513 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Ming Leicdc97792008-02-24 18:41:47 +0800515 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700517 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700518 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 return;
520 }
521
522 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700523 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 goto exit;
525 }
526
Andy Shevchenko715cf922013-05-28 12:49:17 +0300527 /*dev_dbg(&urb->dev->dev, "%s %12ph", __func__, data);*/
Alan Coxdeb91682008-07-22 11:13:08 +0100528
529 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 msg = (struct keyspan_usa28_portStatusMessage *)data;
531
Alan Coxdeb91682008-07-22 11:13:08 +0100532 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700534 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 goto exit;
536 }
537 port = serial->port[msg->port];
538 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100539
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 /* Update handshaking pin state information */
541 old_dcd_state = p_priv->dcd_state;
542 p_priv->cts_state = ((msg->cts) ? 1 : 0);
543 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
544 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
545 p_priv->ri_state = ((msg->ri) ? 1 : 0);
546
Jiri Slabyaa27a092013-03-07 13:12:30 +0100547 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
548 tty_port_tty_hangup(&port->port, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
550 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100551 err = usb_submit_urb(urb, GFP_ATOMIC);
552 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700553 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554exit: ;
555}
556
David Howells7d12e782006-10-05 14:55:46 +0100557static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559}
560
561
David Howells7d12e782006-10-05 14:55:46 +0100562static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
564 struct usb_serial *serial;
565 struct usb_serial_port *port;
566 struct keyspan_port_private *p_priv;
567 int i;
568
Ming Leicdc97792008-02-24 18:41:47 +0800569 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 for (i = 0; i < serial->num_ports; ++i) {
571 port = serial->port[i];
572 p_priv = usb_get_serial_port_data(port);
573
574 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700575 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100576 keyspan_usa49_send_setup(serial, port,
577 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 break;
579 }
580 }
581}
582
583 /* This is actually called glostat in the Keyspan
584 doco */
David Howells7d12e782006-10-05 14:55:46 +0100585static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586{
587 int err;
588 unsigned char *data = urb->transfer_buffer;
589 struct keyspan_usa49_portStatusMessage *msg;
590 struct usb_serial *serial;
591 struct usb_serial_port *port;
592 struct keyspan_port_private *p_priv;
593 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700594 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Ming Leicdc97792008-02-24 18:41:47 +0800596 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700598 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700599 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 return;
601 }
602
Alan Coxdeb91682008-07-22 11:13:08 +0100603 if (urb->actual_length !=
604 sizeof(struct keyspan_usa49_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700605 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 goto exit;
607 }
608
Andy Shevchenko715cf922013-05-28 12:49:17 +0300609 /*dev_dbg(&urb->dev->dev, "%s: %11ph", __func__, data);*/
Alan Coxdeb91682008-07-22 11:13:08 +0100610
611 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 msg = (struct keyspan_usa49_portStatusMessage *)data;
613
Alan Coxdeb91682008-07-22 11:13:08 +0100614 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 if (msg->portNumber >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700616 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
617 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 goto exit;
619 }
620 port = serial->port[msg->portNumber];
621 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 /* Update handshaking pin state information */
624 old_dcd_state = p_priv->dcd_state;
625 p_priv->cts_state = ((msg->cts) ? 1 : 0);
626 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
627 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
628 p_priv->ri_state = ((msg->ri) ? 1 : 0);
629
Jiri Slabyaa27a092013-03-07 13:12:30 +0100630 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
631 tty_port_tty_hangup(&port->port, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
Alan Coxdeb91682008-07-22 11:13:08 +0100633 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100634 err = usb_submit_urb(urb, GFP_ATOMIC);
635 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700636 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637exit: ;
638}
639
David Howells7d12e782006-10-05 14:55:46 +0100640static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642}
643
David Howells7d12e782006-10-05 14:55:46 +0100644static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
646 int i, err;
647 int endpoint;
648 struct usb_serial_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700650 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 endpoint = usb_pipeendpoint(urb->pipe);
653
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700654 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700655 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
656 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 return;
658 }
659
Ming Leicdc97792008-02-24 18:41:47 +0800660 port = urb->context;
Jiri Slaby2e124b42013-01-03 15:53:06 +0100661 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 /* 0x80 bit is error flag */
663 if ((data[0] & 0x80) == 0) {
664 /* no error on any byte */
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100665 tty_insert_flip_string(&port->port, data + 1,
Alan Coxf035a8a2008-07-22 11:13:32 +0100666 urb->actual_length - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 } else {
668 /* some bytes had errors, every byte has status */
669 for (i = 0; i + 1 < urb->actual_length; i += 2) {
670 int stat = data[i], flag = 0;
671 if (stat & RXERROR_OVERRUN)
672 flag |= TTY_OVERRUN;
673 if (stat & RXERROR_FRAMING)
674 flag |= TTY_FRAME;
675 if (stat & RXERROR_PARITY)
676 flag |= TTY_PARITY;
677 /* XXX should handle break (0x10) */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100678 tty_insert_flip_char(&port->port, data[i+1],
679 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 }
681 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100682 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 }
Alan Coxdeb91682008-07-22 11:13:08 +0100684
685 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500686 err = usb_submit_urb(urb, GFP_ATOMIC);
687 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700688 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689}
690
Lucy McCoy0ca12682007-05-18 12:10:41 -0700691static void usa49wg_indat_callback(struct urb *urb)
692{
693 int i, len, x, err;
694 struct usb_serial *serial;
695 struct usb_serial_port *port;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700696 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700697 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700698
Lucy McCoy0ca12682007-05-18 12:10:41 -0700699 serial = urb->context;
700
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700701 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700702 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700703 return;
704 }
705
706 /* inbound data is in the form P#, len, status, data */
707 i = 0;
708 len = 0;
709
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300710 while (i < urb->actual_length) {
Lucy McCoy0ca12682007-05-18 12:10:41 -0700711
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300712 /* Check port number from message */
713 if (data[i] >= serial->num_ports) {
714 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
715 __func__, data[i]);
716 return;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700717 }
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300718 port = serial->port[data[i++]];
719 len = data[i++];
720
721 /* 0x80 bit is error flag */
722 if ((data[i] & 0x80) == 0) {
723 /* no error on any byte */
724 i++;
Dan Carpenter01a60e72013-04-05 08:43:20 +0300725 for (x = 1; x < len && i < urb->actual_length; ++x)
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300726 tty_insert_flip_char(&port->port,
727 data[i++], 0);
728 } else {
729 /*
730 * some bytes had errors, every byte has status
731 */
Dan Carpenter01a60e72013-04-05 08:43:20 +0300732 for (x = 0; x + 1 < len &&
733 i + 1 < urb->actual_length; x += 2) {
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300734 int stat = data[i], flag = 0;
735
736 if (stat & RXERROR_OVERRUN)
737 flag |= TTY_OVERRUN;
738 if (stat & RXERROR_FRAMING)
739 flag |= TTY_FRAME;
740 if (stat & RXERROR_PARITY)
741 flag |= TTY_PARITY;
742 /* XXX should handle break (0x10) */
743 tty_insert_flip_char(&port->port, data[i+1],
744 flag);
745 i += 2;
746 }
747 }
748 tty_flip_buffer_push(&port->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700749 }
750
751 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700752 err = usb_submit_urb(urb, GFP_ATOMIC);
753 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700754 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700755}
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700758static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760}
761
Lucy McCoy0ca12682007-05-18 12:10:41 -0700762static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
764 int i, err;
765 int endpoint;
766 struct usb_serial_port *port;
767 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700769 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 endpoint = usb_pipeendpoint(urb->pipe);
772
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700773 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700774 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800775 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 return;
777 }
778
Ming Leicdc97792008-02-24 18:41:47 +0800779 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 p_priv = usb_get_serial_port_data(port);
781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100784 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Alan Coxf035a8a2008-07-22 11:13:32 +0100786 if (p_priv->baud > 57600)
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100787 tty_insert_flip_string(&port->port, data,
788 urb->actual_length);
Alan Coxf035a8a2008-07-22 11:13:32 +0100789 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 /* 0x80 bit is error flag */
791 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100792 /* no errors on individual bytes, only
793 possible overrun err*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100795 err = TTY_OVERRUN;
796 else
797 err = 0;
798 for (i = 1; i < urb->actual_length ; ++i)
Jiri Slaby92a19f92013-01-03 15:53:03 +0100799 tty_insert_flip_char(&port->port,
800 data[i], err);
Alan Coxdeb91682008-07-22 11:13:08 +0100801 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700803 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 for (i = 0; i + 1 < urb->actual_length; i += 2) {
805 int stat = data[i], flag = 0;
806 if (stat & RXERROR_OVERRUN)
807 flag |= TTY_OVERRUN;
808 if (stat & RXERROR_FRAMING)
809 flag |= TTY_FRAME;
810 if (stat & RXERROR_PARITY)
811 flag |= TTY_PARITY;
812 /* XXX should handle break (0x10) */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100813 tty_insert_flip_char(&port->port,
814 data[i+1], flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 }
816 }
817 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100818 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 }
Alan Coxdeb91682008-07-22 11:13:08 +0100820
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500822 err = usb_submit_urb(urb, GFP_ATOMIC);
823 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700824 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825}
826
827
David Howells7d12e782006-10-05 14:55:46 +0100828static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829{
830 unsigned char *data = urb->transfer_buffer;
831 struct keyspan_usa90_portStatusMessage *msg;
832 struct usb_serial *serial;
833 struct usb_serial_port *port;
834 struct keyspan_port_private *p_priv;
835 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700836 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Ming Leicdc97792008-02-24 18:41:47 +0800838 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700840 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700841 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 return;
843 }
844 if (urb->actual_length < 14) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700845 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 goto exit;
847 }
848
849 msg = (struct keyspan_usa90_portStatusMessage *)data;
850
851 /* Now do something useful with the data */
852
853 port = serial->port[0];
854 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 /* Update handshaking pin state information */
857 old_dcd_state = p_priv->dcd_state;
858 p_priv->cts_state = ((msg->cts) ? 1 : 0);
859 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
860 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
861 p_priv->ri_state = ((msg->ri) ? 1 : 0);
862
Jiri Slabyaa27a092013-03-07 13:12:30 +0100863 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
864 tty_port_tty_hangup(&port->port, true);
Alan Coxdeb91682008-07-22 11:13:08 +0100865
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100867 err = usb_submit_urb(urb, GFP_ATOMIC);
868 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700869 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870exit:
871 ;
872}
873
David Howells7d12e782006-10-05 14:55:46 +0100874static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
876 struct usb_serial_port *port;
877 struct keyspan_port_private *p_priv;
878
Ming Leicdc97792008-02-24 18:41:47 +0800879 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 p_priv = usb_get_serial_port_data(port);
881
882 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700883 dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100884 keyspan_usa90_send_setup(port->serial, port,
885 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 }
887}
888
Lucy McCoy0ca12682007-05-18 12:10:41 -0700889/* Status messages from the 28xg */
890static void usa67_instat_callback(struct urb *urb)
891{
892 int err;
893 unsigned char *data = urb->transfer_buffer;
894 struct keyspan_usa67_portStatusMessage *msg;
895 struct usb_serial *serial;
896 struct usb_serial_port *port;
897 struct keyspan_port_private *p_priv;
898 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700899 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700900
Lucy McCoy0ca12682007-05-18 12:10:41 -0700901 serial = urb->context;
902
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700903 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700904 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700905 return;
906 }
907
Alan Coxdeb91682008-07-22 11:13:08 +0100908 if (urb->actual_length !=
909 sizeof(struct keyspan_usa67_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700910 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700911 return;
912 }
913
914
915 /* Now do something useful with the data */
916 msg = (struct keyspan_usa67_portStatusMessage *)data;
917
918 /* Check port number from message and retrieve private data */
919 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700920 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700921 return;
922 }
923
924 port = serial->port[msg->port];
925 p_priv = usb_get_serial_port_data(port);
926
927 /* Update handshaking pin state information */
928 old_dcd_state = p_priv->dcd_state;
929 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
930 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
931
Jiri Slabyaa27a092013-03-07 13:12:30 +0100932 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
933 tty_port_tty_hangup(&port->port, true);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700934
935 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700936 err = usb_submit_urb(urb, GFP_ATOMIC);
937 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700938 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700939}
940
941static void usa67_glocont_callback(struct urb *urb)
942{
943 struct usb_serial *serial;
944 struct usb_serial_port *port;
945 struct keyspan_port_private *p_priv;
946 int i;
947
Lucy McCoy0ca12682007-05-18 12:10:41 -0700948 serial = urb->context;
949 for (i = 0; i < serial->num_ports; ++i) {
950 port = serial->port[i];
951 p_priv = usb_get_serial_port_data(port);
952
953 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700954 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700955 keyspan_usa67_send_setup(serial, port,
956 p_priv->resend_cont - 1);
957 break;
958 }
959 }
960}
961
Alan Cox95da3102008-07-22 11:09:07 +0100962static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963{
Alan Cox95da3102008-07-22 11:09:07 +0100964 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 struct keyspan_port_private *p_priv;
966 const struct keyspan_device_details *d_details;
967 int flip;
968 int data_len;
969 struct urb *this_urb;
970
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 p_priv = usb_get_serial_port_data(port);
972 d_details = p_priv->device_details;
973
Alan Coxa5b6f602008-04-08 17:16:06 +0100974 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +0100976 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 else
978 data_len = 63;
979
980 flip = p_priv->out_flip;
981
982 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +0100983 this_urb = p_priv->out_urbs[flip];
984 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +0100986 return data_len;
987 flip = (flip + 1) & d_details->outdat_endp_flip;
988 this_urb = p_priv->out_urbs[flip];
989 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +0100991 return data_len;
992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 }
Alan Coxa5b6f602008-04-08 17:16:06 +0100994 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995}
996
997
Alan Coxa509a7e2009-09-19 13:13:26 -0700998static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001000 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 const struct keyspan_device_details *d_details;
1002 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001003 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001005 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 p_priv = usb_get_serial_port_data(port);
1008 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 /* Set some sane defaults */
1011 p_priv->rts_state = 1;
1012 p_priv->dtr_state = 1;
1013 p_priv->baud = 9600;
1014
1015 /* force baud and lcr to be set on open */
1016 p_priv->old_baud = 0;
1017 p_priv->old_cflag = 0;
1018
1019 p_priv->out_flip = 0;
1020 p_priv->in_flip = 0;
1021
1022 /* Reset low level data toggle and start reading from endpoints */
1023 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001024 urb = p_priv->in_urbs[i];
1025 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Alan Coxdeb91682008-07-22 11:13:08 +01001028 /* make sure endpoint data toggle is synchronized
1029 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001031 err = usb_submit_urb(urb, GFP_KERNEL);
1032 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001033 dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 }
1035
1036 /* Reset low level data toggle on out endpoints */
1037 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001038 urb = p_priv->out_urbs[i];
1039 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 continue;
Alan Coxdeb91682008-07-22 11:13:08 +01001041 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1042 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 }
1044
Andrew Mortonf78ba152007-11-28 16:21:54 -08001045 /* get the terminal config for the setup message now so we don't
1046 * need to send 2 of them */
1047
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001048 device_port = port->port_number;
Alan Cox95da3102008-07-22 11:09:07 +01001049 if (tty) {
Alan Coxadc8d742012-07-14 15:31:47 +01001050 cflag = tty->termios.c_cflag;
Alan Cox95da3102008-07-22 11:09:07 +01001051 /* Baud rate calculation takes baud rate as an integer
1052 so other rates can be generated if desired. */
1053 baud_rate = tty_get_baud_rate(tty);
1054 /* If no match or invalid, leave as default */
1055 if (baud_rate >= 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001056 && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Alan Cox95da3102008-07-22 11:09:07 +01001057 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1058 p_priv->baud = baud_rate;
1059 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001060 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001061 /* set CTS/RTS handshake etc. */
1062 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +10001063 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001064
1065 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001066 /* mdelay(100); */
1067 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001068
Alan Coxa5b6f602008-04-08 17:16:06 +01001069 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070}
1071
1072static inline void stop_urb(struct urb *urb)
1073{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001074 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076}
1077
Alan Cox335f8512009-06-11 12:26:29 +01001078static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1079{
1080 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1081
1082 p_priv->rts_state = on;
1083 p_priv->dtr_state = on;
1084 keyspan_send_setup(port, 0);
1085}
1086
1087static void keyspan_close(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088{
1089 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 struct keyspan_port_private *p_priv;
1091
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001093
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 p_priv->rts_state = 0;
1095 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001096
Johan Hovold80dfe0c2013-03-21 12:36:32 +01001097 keyspan_send_setup(port, 2);
1098 /* pilot-xfer seems to work best with this delay */
1099 mdelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101 p_priv->out_flip = 0;
1102 p_priv->in_flip = 0;
1103
Johan Hovold80dfe0c2013-03-21 12:36:32 +01001104 stop_urb(p_priv->inack_urb);
1105 for (i = 0; i < 2; i++) {
1106 stop_urb(p_priv->in_urbs[i]);
1107 stop_urb(p_priv->out_urbs[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109}
1110
Alan Coxdeb91682008-07-22 11:13:08 +01001111/* download the firmware to a pre-renumeration device */
1112static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113{
Rene Buergel8d733e22012-09-18 09:02:01 +02001114 char *fw_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001116 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
1117 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1118 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001119
1120 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1121 != 0x8000) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001122 dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n");
Alan Coxdeb91682008-07-22 11:13:08 +01001123 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 }
1125
1126 /* Select firmware image on the basis of idProduct */
1127 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1128 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001129 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 break;
1131
1132 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001133 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 break;
1135
1136 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001137 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 break;
1139
1140 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001141 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 break;
1143
1144 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001145 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001147
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001149 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001153 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 break;
1155
1156 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001157 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001161 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001163
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001165 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001169 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 break;
1171
1172 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001173 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 break;
1175
1176 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001177 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1178 le16_to_cpu(serial->dev->descriptor.idProduct));
1179 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 }
1181
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001182 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
Rene Buergel8d733e22012-09-18 09:02:01 +02001184 if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
1185 dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
1186 fw_name);
1187 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 }
1189
Rene Buergel8d733e22012-09-18 09:02:01 +02001190 /* after downloading firmware Renumeration will occur in a
1191 moment and the new device will bind to the real driver */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
1193 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001194 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195}
1196
1197/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001198static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1199 int endpoint)
1200{
1201 struct usb_host_interface *iface_desc;
1202 struct usb_endpoint_descriptor *ep;
1203 int i;
1204
1205 iface_desc = serial->interface->cur_altsetting;
1206 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1207 ep = &iface_desc->endpoint[i].desc;
1208 if (ep->bEndpointAddress == endpoint)
1209 return ep;
1210 }
1211 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1212 "endpoint %x\n", endpoint);
1213 return NULL;
1214}
1215
Alan Coxdeb91682008-07-22 11:13:08 +01001216static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001218 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219{
1220 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001221 struct usb_endpoint_descriptor const *ep_desc;
1222 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
1224 if (endpoint == -1)
1225 return NULL; /* endpoint not needed */
1226
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001227 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
1229 if (urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001230 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d failed.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 return NULL;
1232 }
1233
Lucy McCoy0ca12682007-05-18 12:10:41 -07001234 if (endpoint == 0) {
1235 /* control EP filled in when used */
1236 return urb;
1237 }
1238
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001239 ep_desc = find_ep(serial, endpoint);
1240 if (!ep_desc) {
1241 /* leak the urb, something's wrong and the callers don't care */
1242 return urb;
1243 }
1244 if (usb_endpoint_xfer_int(ep_desc)) {
1245 ep_type_name = "INT";
1246 usb_fill_int_urb(urb, serial->dev,
1247 usb_sndintpipe(serial->dev, endpoint) | dir,
1248 buf, len, callback, ctx,
1249 ep_desc->bInterval);
1250 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1251 ep_type_name = "BULK";
1252 usb_fill_bulk_urb(urb, serial->dev,
1253 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1254 buf, len, callback, ctx);
1255 } else {
1256 dev_warn(&serial->interface->dev,
1257 "unsupported endpoint type %x\n",
Julia Lawall2e0fe702008-12-29 11:22:14 +01001258 usb_endpoint_type(ep_desc));
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001259 usb_free_urb(urb);
1260 return NULL;
1261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001263 dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001264 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 return urb;
1266}
1267
1268static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001269 void (*instat_callback)(struct urb *);
1270 void (*glocont_callback)(struct urb *);
1271 void (*indat_callback)(struct urb *);
1272 void (*outdat_callback)(struct urb *);
1273 void (*inack_callback)(struct urb *);
1274 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275} keyspan_callbacks[] = {
1276 {
1277 /* msg_usa26 callbacks */
1278 .instat_callback = usa26_instat_callback,
1279 .glocont_callback = usa26_glocont_callback,
1280 .indat_callback = usa26_indat_callback,
1281 .outdat_callback = usa2x_outdat_callback,
1282 .inack_callback = usa26_inack_callback,
1283 .outcont_callback = usa26_outcont_callback,
1284 }, {
1285 /* msg_usa28 callbacks */
1286 .instat_callback = usa28_instat_callback,
1287 .glocont_callback = usa28_glocont_callback,
1288 .indat_callback = usa28_indat_callback,
1289 .outdat_callback = usa2x_outdat_callback,
1290 .inack_callback = usa28_inack_callback,
1291 .outcont_callback = usa28_outcont_callback,
1292 }, {
1293 /* msg_usa49 callbacks */
1294 .instat_callback = usa49_instat_callback,
1295 .glocont_callback = usa49_glocont_callback,
1296 .indat_callback = usa49_indat_callback,
1297 .outdat_callback = usa2x_outdat_callback,
1298 .inack_callback = usa49_inack_callback,
1299 .outcont_callback = usa49_outcont_callback,
1300 }, {
1301 /* msg_usa90 callbacks */
1302 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001303 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 .indat_callback = usa90_indat_callback,
1305 .outdat_callback = usa2x_outdat_callback,
1306 .inack_callback = usa28_inack_callback,
1307 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001308 }, {
1309 /* msg_usa67 callbacks */
1310 .instat_callback = usa67_instat_callback,
1311 .glocont_callback = usa67_glocont_callback,
1312 .indat_callback = usa26_indat_callback,
1313 .outdat_callback = usa2x_outdat_callback,
1314 .inack_callback = usa26_inack_callback,
1315 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 }
1317};
1318
1319 /* Generic setup urbs function that uses
1320 data in device_details */
1321static void keyspan_setup_urbs(struct usb_serial *serial)
1322{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 struct keyspan_serial_private *s_priv;
1324 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 struct callbacks *cback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 s_priv = usb_get_serial_data(serial);
1328 d_details = s_priv->device_details;
1329
Alan Coxdeb91682008-07-22 11:13:08 +01001330 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 cback = &keyspan_callbacks[d_details->msg_format];
1332
Alan Coxdeb91682008-07-22 11:13:08 +01001333 /* Allocate and set up urbs for each one that is in use,
1334 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 s_priv->instat_urb = keyspan_setup_urb
1336 (serial, d_details->instat_endpoint, USB_DIR_IN,
1337 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1338 cback->instat_callback);
1339
Lucy McCoy0ca12682007-05-18 12:10:41 -07001340 s_priv->indat_urb = keyspan_setup_urb
1341 (serial, d_details->indat_endpoint, USB_DIR_IN,
1342 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1343 usa49wg_indat_callback);
1344
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 s_priv->glocont_urb = keyspan_setup_urb
1346 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1347 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1348 cback->glocont_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349}
1350
1351/* usa19 function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001352static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1353 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 u8 *rate_low, u8 *prescaler, int portnum)
1355{
1356 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001357 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001360 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
Alan Coxdeb91682008-07-22 11:13:08 +01001362 /* prevent divide by zero... */
1363 b16 = baud_rate * 16L;
1364 if (b16 == 0)
1365 return KEYSPAN_INVALID_BAUD_RATE;
1366 /* Any "standard" rate over 57k6 is marginal on the USA-19
1367 as we run out of divisor resolution. */
1368 if (baud_rate > 57600)
1369 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Alan Coxdeb91682008-07-22 11:13:08 +01001371 /* calculate the divisor and the counter (its inverse) */
1372 div = baudclk / b16;
1373 if (div == 0)
1374 return KEYSPAN_INVALID_BAUD_RATE;
1375 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
Alan Coxdeb91682008-07-22 11:13:08 +01001378 if (div > 0xffff)
1379 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
Alan Coxdeb91682008-07-22 11:13:08 +01001381 /* return the counter values if non-null */
1382 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001384 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001386 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001387 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001388 __func__, baud_rate, *rate_hi, *rate_low);
1389 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390}
1391
1392/* usa19hs function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001393static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1394 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1395 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396{
1397 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001398 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001400 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
Alan Coxdeb91682008-07-22 11:13:08 +01001402 /* prevent divide by zero... */
1403 b16 = baud_rate * 16L;
1404 if (b16 == 0)
1405 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
Alan Coxdeb91682008-07-22 11:13:08 +01001407 /* calculate the divisor */
1408 div = baudclk / b16;
1409 if (div == 0)
1410 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Alan Coxdeb91682008-07-22 11:13:08 +01001412 if (div > 0xffff)
1413 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
Alan Coxdeb91682008-07-22 11:13:08 +01001415 /* return the counter values if non-null */
1416 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001418
1419 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001421
1422 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001423 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001424 __func__, baud_rate, *rate_hi, *rate_low);
1425
1426 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427}
1428
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001429static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1430 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 u8 *rate_low, u8 *prescaler, int portnum)
1432{
1433 u32 b16, /* baud rate times 16 (actual rate used internally) */
1434 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001435 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 res, /* resulting baud rate using 13/8 prescaler */
1437 diff, /* error using 13/8 prescaler */
1438 smallest_diff;
1439 u8 best_prescaler;
1440 int i;
1441
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001442 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
Alan Coxdeb91682008-07-22 11:13:08 +01001444 /* prevent divide by zero */
1445 b16 = baud_rate * 16L;
1446 if (b16 == 0)
1447 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
Alan Coxdeb91682008-07-22 11:13:08 +01001449 /* Calculate prescaler by trying them all and looking
1450 for best fit */
1451
1452 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 smallest_diff = 0xffffffff;
1454
1455 /* 0 is an invalid prescaler, used as a flag */
1456 best_prescaler = 0;
1457
Alan Coxdeb91682008-07-22 11:13:08 +01001458 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001460
1461 div = clk / b16;
1462 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
1465 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001466 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
Alan Coxdeb91682008-07-22 11:13:08 +01001468 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 best_prescaler = i;
1470 smallest_diff = diff;
1471 }
1472 }
1473
Alan Coxdeb91682008-07-22 11:13:08 +01001474 if (best_prescaler == 0)
1475 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
1477 clk = (baudclk * 8) / (u32) best_prescaler;
1478 div = clk / b16;
1479
Alan Coxdeb91682008-07-22 11:13:08 +01001480 /* return the divisor and prescaler if non-null */
1481 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001483 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 if (prescaler) {
1486 *prescaler = best_prescaler;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001487 /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 }
Alan Coxdeb91682008-07-22 11:13:08 +01001489 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490}
1491
1492 /* USA-28 supports different maximum baud rates on each port */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001493static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1494 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1495 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496{
1497 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001498 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 cnt; /* inverse of divisor (programmed into 8051) */
1500
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001501 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
1503 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001504 b16 = baud_rate * 16L;
1505 if (b16 == 0)
1506 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507
Alan Coxdeb91682008-07-22 11:13:08 +01001508 /* calculate the divisor and the counter (its inverse) */
1509 div = KEYSPAN_USA28_BAUDCLK / b16;
1510 if (div == 0)
1511 return KEYSPAN_INVALID_BAUD_RATE;
1512 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514
Alan Coxdeb91682008-07-22 11:13:08 +01001515 /* check for out of range, based on portnum,
1516 and return result */
1517 if (portnum == 0) {
1518 if (div > 0xffff)
1519 return KEYSPAN_INVALID_BAUD_RATE;
1520 } else {
1521 if (portnum == 1) {
1522 if (div > 0xff)
1523 return KEYSPAN_INVALID_BAUD_RATE;
1524 } else
1525 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 }
1527
1528 /* return the counter values if not NULL
1529 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001530 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001532 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001534 dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
Alan Coxdeb91682008-07-22 11:13:08 +01001535 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536}
1537
1538static int keyspan_usa26_send_setup(struct usb_serial *serial,
1539 struct usb_serial_port *port,
1540 int reset_port)
1541{
Alan Coxdeb91682008-07-22 11:13:08 +01001542 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 struct keyspan_serial_private *s_priv;
1544 struct keyspan_port_private *p_priv;
1545 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 struct urb *this_urb;
1547 int device_port, err;
1548
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001549 dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
1551 s_priv = usb_get_serial_data(serial);
1552 p_priv = usb_get_serial_port_data(port);
1553 d_details = s_priv->device_details;
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001554 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 this_urb = p_priv->outcont_urb;
1557
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001558 dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
1560 /* Make sure we have an urb then send the message */
1561 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001562 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 return -1;
1564 }
1565
1566 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001567 Don't overwrite resend for open/close condition. */
1568 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 p_priv->resend_cont = reset_port + 1;
1570 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001571 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001573 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 }
1575
Alan Coxdeb91682008-07-22 11:13:08 +01001576 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1577
1578 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 if (p_priv->old_baud != p_priv->baud) {
1580 p_priv->old_baud = p_priv->baud;
1581 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001582 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1583 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1584 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1585 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1586 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 msg.baudLo = 0;
1588 msg.baudHi = 125; /* Values for 9600 baud */
1589 msg.prescaler = 10;
1590 }
1591 msg.setPrescaler = 0xff;
1592 }
1593
Ben Minerds2b982ab2012-07-12 00:10:16 +10001594 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 switch (p_priv->cflag & CSIZE) {
1596 case CS5:
1597 msg.lcr |= USA_DATABITS_5;
1598 break;
1599 case CS6:
1600 msg.lcr |= USA_DATABITS_6;
1601 break;
1602 case CS7:
1603 msg.lcr |= USA_DATABITS_7;
1604 break;
1605 case CS8:
1606 msg.lcr |= USA_DATABITS_8;
1607 break;
1608 }
1609 if (p_priv->cflag & PARENB) {
1610 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001611 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001612 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 }
1614 msg.setLcr = 0xff;
1615
1616 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1617 msg.xonFlowControl = 0;
1618 msg.setFlowControl = 0xff;
1619 msg.forwardingLength = 16;
1620 msg.xonChar = 17;
1621 msg.xoffChar = 19;
1622
1623 /* Opening port */
1624 if (reset_port == 1) {
1625 msg._txOn = 1;
1626 msg._txOff = 0;
1627 msg.txFlush = 0;
1628 msg.txBreak = 0;
1629 msg.rxOn = 1;
1630 msg.rxOff = 0;
1631 msg.rxFlush = 1;
1632 msg.rxForward = 0;
1633 msg.returnStatus = 0;
1634 msg.resetDataToggle = 0xff;
1635 }
1636
1637 /* Closing port */
1638 else if (reset_port == 2) {
1639 msg._txOn = 0;
1640 msg._txOff = 1;
1641 msg.txFlush = 0;
1642 msg.txBreak = 0;
1643 msg.rxOn = 0;
1644 msg.rxOff = 1;
1645 msg.rxFlush = 1;
1646 msg.rxForward = 0;
1647 msg.returnStatus = 0;
1648 msg.resetDataToggle = 0;
1649 }
1650
1651 /* Sending intermediate configs */
1652 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001653 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 msg._txOff = 0;
1655 msg.txFlush = 0;
1656 msg.txBreak = (p_priv->break_on);
1657 msg.rxOn = 0;
1658 msg.rxOff = 0;
1659 msg.rxFlush = 0;
1660 msg.rxForward = 0;
1661 msg.returnStatus = 0;
1662 msg.resetDataToggle = 0x0;
1663 }
1664
Alan Coxdeb91682008-07-22 11:13:08 +01001665 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 msg.setTxTriState_setRts = 0xff;
1667 msg.txTriState_rts = p_priv->rts_state;
1668
1669 msg.setHskoa_setDtr = 0xff;
1670 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001671
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001673 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 /* send the data out the device on control endpoint */
1676 this_urb->transfer_buffer_length = sizeof(msg);
1677
Alan Coxdeb91682008-07-22 11:13:08 +01001678 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1679 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001680 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01001681 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682}
1683
1684static int keyspan_usa28_send_setup(struct usb_serial *serial,
1685 struct usb_serial_port *port,
1686 int reset_port)
1687{
Alan Coxdeb91682008-07-22 11:13:08 +01001688 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 struct keyspan_serial_private *s_priv;
1690 struct keyspan_port_private *p_priv;
1691 const struct keyspan_device_details *d_details;
1692 struct urb *this_urb;
1693 int device_port, err;
1694
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 s_priv = usb_get_serial_data(serial);
1696 p_priv = usb_get_serial_port_data(port);
1697 d_details = s_priv->device_details;
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001698 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
1700 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001701 this_urb = p_priv->outcont_urb;
1702 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001703 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 return -1;
1705 }
1706
1707 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001708 Don't overwrite resend for open/close condition. */
1709 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 p_priv->resend_cont = reset_port + 1;
1711 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001712 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001714 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 }
1716
Alan Coxdeb91682008-07-22 11:13:08 +01001717 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
1719 msg.setBaudRate = 1;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001720 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1721 &msg.baudHi, &msg.baudLo, NULL,
1722 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1723 dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001724 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 msg.baudLo = 0xff;
1726 msg.baudHi = 0xb2; /* Values for 9600 baud */
1727 }
1728
1729 /* If parity is enabled, we must calculate it ourselves. */
1730 msg.parity = 0; /* XXX for now */
1731
1732 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1733 msg.xonFlowControl = 0;
1734
Alan Coxdeb91682008-07-22 11:13:08 +01001735 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 msg.rts = p_priv->rts_state;
1737 msg.dtr = p_priv->dtr_state;
1738
1739 msg.forwardingLength = 16;
1740 msg.forwardMs = 10;
1741 msg.breakThreshold = 45;
1742 msg.xonChar = 17;
1743 msg.xoffChar = 19;
1744
1745 /*msg.returnStatus = 1;
1746 msg.resetDataToggle = 0xff;*/
1747 /* Opening port */
1748 if (reset_port == 1) {
1749 msg._txOn = 1;
1750 msg._txOff = 0;
1751 msg.txFlush = 0;
1752 msg.txForceXoff = 0;
1753 msg.txBreak = 0;
1754 msg.rxOn = 1;
1755 msg.rxOff = 0;
1756 msg.rxFlush = 1;
1757 msg.rxForward = 0;
1758 msg.returnStatus = 0;
1759 msg.resetDataToggle = 0xff;
1760 }
1761 /* Closing port */
1762 else if (reset_port == 2) {
1763 msg._txOn = 0;
1764 msg._txOff = 1;
1765 msg.txFlush = 0;
1766 msg.txForceXoff = 0;
1767 msg.txBreak = 0;
1768 msg.rxOn = 0;
1769 msg.rxOff = 1;
1770 msg.rxFlush = 1;
1771 msg.rxForward = 0;
1772 msg.returnStatus = 0;
1773 msg.resetDataToggle = 0;
1774 }
1775 /* Sending intermediate configs */
1776 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001777 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 msg._txOff = 0;
1779 msg.txFlush = 0;
1780 msg.txForceXoff = 0;
1781 msg.txBreak = (p_priv->break_on);
1782 msg.rxOn = 0;
1783 msg.rxOff = 0;
1784 msg.rxFlush = 0;
1785 msg.rxForward = 0;
1786 msg.returnStatus = 0;
1787 msg.resetDataToggle = 0x0;
1788 }
1789
1790 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001791 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
1793 /* send the data out the device on control endpoint */
1794 this_urb->transfer_buffer_length = sizeof(msg);
1795
Alan Coxdeb91682008-07-22 11:13:08 +01001796 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1797 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001798 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799#if 0
1800 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001801 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 this_urb->transfer_buffer_length);
1803 }
1804#endif
1805
Alan Coxa5b6f602008-04-08 17:16:06 +01001806 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807}
1808
1809static int keyspan_usa49_send_setup(struct usb_serial *serial,
1810 struct usb_serial_port *port,
1811 int reset_port)
1812{
Lucy McCoy0ca12682007-05-18 12:10:41 -07001813 struct keyspan_usa49_portControlMessage msg;
1814 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 struct keyspan_serial_private *s_priv;
1816 struct keyspan_port_private *p_priv;
1817 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 struct urb *this_urb;
1819 int err, device_port;
1820
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 s_priv = usb_get_serial_data(serial);
1822 p_priv = usb_get_serial_port_data(port);
1823 d_details = s_priv->device_details;
1824
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 this_urb = s_priv->glocont_urb;
1826
Lucy McCoy0ca12682007-05-18 12:10:41 -07001827 /* Work out which port within the device is being setup */
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001828 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301830 /* Make sure we have an urb then send the message */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 if (this_urb == NULL) {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001832 dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 return -1;
1834 }
1835
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001836 dev_dbg(&port->dev, "%s - endpoint %d (%d)\n",
1837 __func__, usb_pipeendpoint(this_urb->pipe), device_port);
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301838
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001840 Don't overwrite resend for open/close condition. */
1841 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001843
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001845 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001847 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 }
1849
Alan Coxdeb91682008-07-22 11:13:08 +01001850 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01001853
1854 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 if (p_priv->old_baud != p_priv->baud) {
1856 p_priv->old_baud = p_priv->baud;
1857 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001858 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1859 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1860 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1861 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1862 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 msg.baudLo = 0;
1864 msg.baudHi = 125; /* Values for 9600 baud */
1865 msg.prescaler = 10;
1866 }
Alan Coxdeb91682008-07-22 11:13:08 +01001867 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 }
1869
Ben Minerds2b982ab2012-07-12 00:10:16 +10001870 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 switch (p_priv->cflag & CSIZE) {
1872 case CS5:
1873 msg.lcr |= USA_DATABITS_5;
1874 break;
1875 case CS6:
1876 msg.lcr |= USA_DATABITS_6;
1877 break;
1878 case CS7:
1879 msg.lcr |= USA_DATABITS_7;
1880 break;
1881 case CS8:
1882 msg.lcr |= USA_DATABITS_8;
1883 break;
1884 }
1885 if (p_priv->cflag & PARENB) {
1886 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001887 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001888 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 }
1890 msg.setLcr = 0xff;
1891
1892 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1893 msg.xonFlowControl = 0;
1894 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01001895
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 msg.forwardingLength = 16;
1897 msg.xonChar = 17;
1898 msg.xoffChar = 19;
1899
Alan Coxdeb91682008-07-22 11:13:08 +01001900 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 if (reset_port == 1) {
1902 msg._txOn = 1;
1903 msg._txOff = 0;
1904 msg.txFlush = 0;
1905 msg.txBreak = 0;
1906 msg.rxOn = 1;
1907 msg.rxOff = 0;
1908 msg.rxFlush = 1;
1909 msg.rxForward = 0;
1910 msg.returnStatus = 0;
1911 msg.resetDataToggle = 0xff;
1912 msg.enablePort = 1;
1913 msg.disablePort = 0;
1914 }
1915 /* Closing port */
1916 else if (reset_port == 2) {
1917 msg._txOn = 0;
1918 msg._txOff = 1;
1919 msg.txFlush = 0;
1920 msg.txBreak = 0;
1921 msg.rxOn = 0;
1922 msg.rxOff = 1;
1923 msg.rxFlush = 1;
1924 msg.rxForward = 0;
1925 msg.returnStatus = 0;
1926 msg.resetDataToggle = 0;
1927 msg.enablePort = 0;
1928 msg.disablePort = 1;
1929 }
1930 /* Sending intermediate configs */
1931 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001932 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 msg._txOff = 0;
1934 msg.txFlush = 0;
1935 msg.txBreak = (p_priv->break_on);
1936 msg.rxOn = 0;
1937 msg.rxOff = 0;
1938 msg.rxFlush = 0;
1939 msg.rxForward = 0;
1940 msg.returnStatus = 0;
1941 msg.resetDataToggle = 0x0;
1942 msg.enablePort = 0;
1943 msg.disablePort = 0;
1944 }
1945
Alan Coxdeb91682008-07-22 11:13:08 +01001946 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 msg.setRts = 0xff;
1948 msg.rts = p_priv->rts_state;
1949
1950 msg.setDtr = 0xff;
1951 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001952
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954
Alan Coxdeb91682008-07-22 11:13:08 +01001955 /* if the device is a 49wg, we send control message on usb
1956 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07001957
1958 if (d_details->product_id == keyspan_usa49wg_product_id) {
1959 dr = (void *)(s_priv->ctrl_buf);
1960 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
1961 dr->bRequest = 0xB0; /* 49wg control message */;
1962 dr->wValue = 0;
1963 dr->wIndex = 0;
1964 dr->wLength = cpu_to_le16(sizeof(msg));
1965
Alan Coxdeb91682008-07-22 11:13:08 +01001966 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07001967
Alan Coxdeb91682008-07-22 11:13:08 +01001968 usb_fill_control_urb(this_urb, serial->dev,
1969 usb_sndctrlpipe(serial->dev, 0),
1970 (unsigned char *)dr, s_priv->glocont_buf,
1971 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001972
1973 } else {
1974 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01001975
Lucy McCoy0ca12682007-05-18 12:10:41 -07001976 /* send the data out the device on control endpoint */
1977 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001978 }
Alan Coxdeb91682008-07-22 11:13:08 +01001979 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1980 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001981 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982#if 0
1983 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001984 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__,
1985 outcont_urb, this_urb->transfer_buffer_length,
1986 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 }
1988#endif
1989
Alan Coxa5b6f602008-04-08 17:16:06 +01001990 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991}
1992
1993static int keyspan_usa90_send_setup(struct usb_serial *serial,
1994 struct usb_serial_port *port,
1995 int reset_port)
1996{
Alan Coxdeb91682008-07-22 11:13:08 +01001997 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 struct keyspan_serial_private *s_priv;
1999 struct keyspan_port_private *p_priv;
2000 const struct keyspan_device_details *d_details;
2001 struct urb *this_urb;
2002 int err;
2003 u8 prescaler;
2004
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 s_priv = usb_get_serial_data(serial);
2006 p_priv = usb_get_serial_port_data(port);
2007 d_details = s_priv->device_details;
2008
2009 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002010 this_urb = p_priv->outcont_urb;
2011 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002012 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 return -1;
2014 }
2015
2016 /* Save reset port val for resend.
2017 Don't overwrite resend for open/close condition. */
2018 if ((reset_port + 1) > p_priv->resend_cont)
2019 p_priv->resend_cont = reset_port + 1;
2020 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002021 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002023 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 }
2025
Alan Coxdeb91682008-07-22 11:13:08 +01002026 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
Alan Coxdeb91682008-07-22 11:13:08 +01002028 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 if (p_priv->old_baud != p_priv->baud) {
2030 p_priv->old_baud = p_priv->baud;
2031 msg.setClocking = 0x01;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002032 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2033 &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2034 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2035 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 p_priv->baud = 9600;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002037 d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2039 }
2040 msg.setRxMode = 1;
2041 msg.setTxMode = 1;
2042 }
2043
2044 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002045 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 msg.rxMode = RXMODE_DMA;
2047 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002048 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 msg.rxMode = RXMODE_BYHAND;
2050 msg.txMode = TXMODE_BYHAND;
2051 }
2052
Ben Minerds2b982ab2012-07-12 00:10:16 +10002053 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 switch (p_priv->cflag & CSIZE) {
2055 case CS5:
2056 msg.lcr |= USA_DATABITS_5;
2057 break;
2058 case CS6:
2059 msg.lcr |= USA_DATABITS_6;
2060 break;
2061 case CS7:
2062 msg.lcr |= USA_DATABITS_7;
2063 break;
2064 case CS8:
2065 msg.lcr |= USA_DATABITS_8;
2066 break;
2067 }
2068 if (p_priv->cflag & PARENB) {
2069 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002070 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002071 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 }
2073 if (p_priv->old_cflag != p_priv->cflag) {
2074 p_priv->old_cflag = p_priv->cflag;
2075 msg.setLcr = 0x01;
2076 }
2077
2078 if (p_priv->flow_control == flow_cts)
2079 msg.txFlowControl = TXFLOW_CTS;
2080 msg.setTxFlowControl = 0x01;
2081 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002082
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002084 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 msg.txAckSetting = 0;
2086 msg.xonChar = 17;
2087 msg.xoffChar = 19;
2088
Alan Coxdeb91682008-07-22 11:13:08 +01002089 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 if (reset_port == 1) {
2091 msg.portEnabled = 1;
2092 msg.rxFlush = 1;
2093 msg.txBreak = (p_priv->break_on);
2094 }
2095 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002096 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 /* Sending intermediate configs */
2099 else {
Alan Stern1f871582010-02-17 10:05:47 -05002100 msg.portEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 msg.txBreak = (p_priv->break_on);
2102 }
2103
Alan Coxdeb91682008-07-22 11:13:08 +01002104 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 msg.setRts = 0x01;
2106 msg.rts = p_priv->rts_state;
2107
2108 msg.setDtr = 0x01;
2109 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002110
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002112 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2113
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 /* send the data out the device on control endpoint */
2115 this_urb->transfer_buffer_length = sizeof(msg);
2116
Alan Coxdeb91682008-07-22 11:13:08 +01002117 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2118 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002119 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002120 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121}
2122
Lucy McCoy0ca12682007-05-18 12:10:41 -07002123static int keyspan_usa67_send_setup(struct usb_serial *serial,
2124 struct usb_serial_port *port,
2125 int reset_port)
2126{
2127 struct keyspan_usa67_portControlMessage msg;
2128 struct keyspan_serial_private *s_priv;
2129 struct keyspan_port_private *p_priv;
2130 const struct keyspan_device_details *d_details;
2131 struct urb *this_urb;
2132 int err, device_port;
2133
Lucy McCoy0ca12682007-05-18 12:10:41 -07002134 s_priv = usb_get_serial_data(serial);
2135 p_priv = usb_get_serial_port_data(port);
2136 d_details = s_priv->device_details;
2137
2138 this_urb = s_priv->glocont_urb;
2139
2140 /* Work out which port within the device is being setup */
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002141 device_port = port->port_number;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002142
2143 /* Make sure we have an urb then send the message */
2144 if (this_urb == NULL) {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002145 dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002146 return -1;
2147 }
2148
2149 /* Save reset port val for resend.
2150 Don't overwrite resend for open/close condition. */
2151 if ((reset_port + 1) > p_priv->resend_cont)
2152 p_priv->resend_cont = reset_port + 1;
2153 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002154 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002155 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002156 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002157 }
2158
2159 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2160
2161 msg.port = device_port;
2162
2163 /* Only set baud rate if it's changed */
2164 if (p_priv->old_baud != p_priv->baud) {
2165 p_priv->old_baud = p_priv->baud;
2166 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002167 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2168 &msg.baudHi, &msg.baudLo, &msg.prescaler,
2169 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2170 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2171 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002172 msg.baudLo = 0;
2173 msg.baudHi = 125; /* Values for 9600 baud */
2174 msg.prescaler = 10;
2175 }
2176 msg.setPrescaler = 0xff;
2177 }
2178
2179 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2180 switch (p_priv->cflag & CSIZE) {
2181 case CS5:
2182 msg.lcr |= USA_DATABITS_5;
2183 break;
2184 case CS6:
2185 msg.lcr |= USA_DATABITS_6;
2186 break;
2187 case CS7:
2188 msg.lcr |= USA_DATABITS_7;
2189 break;
2190 case CS8:
2191 msg.lcr |= USA_DATABITS_8;
2192 break;
2193 }
2194 if (p_priv->cflag & PARENB) {
2195 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002196 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002197 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002198 }
2199 msg.setLcr = 0xff;
2200
2201 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2202 msg.xonFlowControl = 0;
2203 msg.setFlowControl = 0xff;
2204 msg.forwardingLength = 16;
2205 msg.xonChar = 17;
2206 msg.xoffChar = 19;
2207
2208 if (reset_port == 1) {
2209 /* Opening port */
2210 msg._txOn = 1;
2211 msg._txOff = 0;
2212 msg.txFlush = 0;
2213 msg.txBreak = 0;
2214 msg.rxOn = 1;
2215 msg.rxOff = 0;
2216 msg.rxFlush = 1;
2217 msg.rxForward = 0;
2218 msg.returnStatus = 0;
2219 msg.resetDataToggle = 0xff;
2220 } else if (reset_port == 2) {
2221 /* Closing port */
2222 msg._txOn = 0;
2223 msg._txOff = 1;
2224 msg.txFlush = 0;
2225 msg.txBreak = 0;
2226 msg.rxOn = 0;
2227 msg.rxOff = 1;
2228 msg.rxFlush = 1;
2229 msg.rxForward = 0;
2230 msg.returnStatus = 0;
2231 msg.resetDataToggle = 0;
2232 } else {
2233 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002234 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002235 msg._txOff = 0;
2236 msg.txFlush = 0;
2237 msg.txBreak = (p_priv->break_on);
2238 msg.rxOn = 0;
2239 msg.rxOff = 0;
2240 msg.rxFlush = 0;
2241 msg.rxForward = 0;
2242 msg.returnStatus = 0;
2243 msg.resetDataToggle = 0x0;
2244 }
2245
2246 /* Do handshaking outputs */
2247 msg.setTxTriState_setRts = 0xff;
2248 msg.txTriState_rts = p_priv->rts_state;
2249
2250 msg.setHskoa_setDtr = 0xff;
2251 msg.hskoa_dtr = p_priv->dtr_state;
2252
2253 p_priv->resend_cont = 0;
2254
2255 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2256
2257 /* send the data out the device on control endpoint */
2258 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002259
2260 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2261 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002262 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002263 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002264}
2265
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2267{
2268 struct usb_serial *serial = port->serial;
2269 struct keyspan_serial_private *s_priv;
2270 const struct keyspan_device_details *d_details;
2271
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 s_priv = usb_get_serial_data(serial);
2273 d_details = s_priv->device_details;
2274
2275 switch (d_details->msg_format) {
2276 case msg_usa26:
2277 keyspan_usa26_send_setup(serial, port, reset_port);
2278 break;
2279 case msg_usa28:
2280 keyspan_usa28_send_setup(serial, port, reset_port);
2281 break;
2282 case msg_usa49:
2283 keyspan_usa49_send_setup(serial, port, reset_port);
2284 break;
2285 case msg_usa90:
2286 keyspan_usa90_send_setup(serial, port, reset_port);
2287 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002288 case msg_usa67:
2289 keyspan_usa67_send_setup(serial, port, reset_port);
2290 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 }
2292}
2293
2294
2295/* Gets called by the "real" driver (ie once firmware is loaded
2296 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002297static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298{
2299 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 const struct keyspan_device_details *d_details;
2302
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002304 if (d_details->product_id ==
2305 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 break;
2307 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002308 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2309 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Johan Hovoldff8a43c2013-08-13 13:27:35 +02002310 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 }
2312
2313 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002314 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 if (!s_priv) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002316 dev_dbg(&serial->dev->dev, "%s - kmalloc for keyspan_serial_private failed.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 return -ENOMEM;
2318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
Johan Hovold2fcd1c92013-08-13 13:27:36 +02002320 s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);
2321 if (!s_priv->instat_buf)
2322 goto err_instat_buf;
2323
2324 s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL);
2325 if (!s_priv->indat_buf)
2326 goto err_indat_buf;
2327
2328 s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL);
2329 if (!s_priv->glocont_buf)
2330 goto err_glocont_buf;
2331
2332 s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
2333 if (!s_priv->ctrl_buf)
2334 goto err_ctrl_buf;
2335
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 s_priv->device_details = d_details;
2337 usb_set_serial_data(serial, s_priv);
2338
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 keyspan_setup_urbs(serial);
2340
Lucy McCoy0ca12682007-05-18 12:10:41 -07002341 if (s_priv->instat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002342 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2343 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002344 dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002345 }
2346 if (s_priv->indat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002347 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2348 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002349 dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 }
Alan Coxdeb91682008-07-22 11:13:08 +01002351
Alan Coxa5b6f602008-04-08 17:16:06 +01002352 return 0;
Johan Hovold2fcd1c92013-08-13 13:27:36 +02002353
2354err_ctrl_buf:
2355 kfree(s_priv->glocont_buf);
2356err_glocont_buf:
2357 kfree(s_priv->indat_buf);
2358err_indat_buf:
2359 kfree(s_priv->instat_buf);
2360err_instat_buf:
2361 kfree(s_priv);
2362
2363 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364}
2365
Alan Sternf9c99bb2009-06-02 11:53:55 -04002366static void keyspan_disconnect(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002368 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 s_priv = usb_get_serial_data(serial);
2371
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 stop_urb(s_priv->instat_urb);
2373 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002374 stop_urb(s_priv->indat_urb);
Alan Sternf9c99bb2009-06-02 11:53:55 -04002375}
2376
2377static void keyspan_release(struct usb_serial *serial)
2378{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002379 struct keyspan_serial_private *s_priv;
Alan Sternf9c99bb2009-06-02 11:53:55 -04002380
Alan Sternf9c99bb2009-06-02 11:53:55 -04002381 s_priv = usb_get_serial_data(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002383 usb_free_urb(s_priv->instat_urb);
2384 usb_free_urb(s_priv->indat_urb);
2385 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
Johan Hovold2fcd1c92013-08-13 13:27:36 +02002387 kfree(s_priv->ctrl_buf);
2388 kfree(s_priv->glocont_buf);
2389 kfree(s_priv->indat_buf);
2390 kfree(s_priv->instat_buf);
2391
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002392 kfree(s_priv);
2393}
2394
2395static int keyspan_port_probe(struct usb_serial_port *port)
2396{
2397 struct usb_serial *serial = port->serial;
Bjørn Morkf0e3e352012-11-10 10:13:42 +01002398 struct keyspan_serial_private *s_priv;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002399 struct keyspan_port_private *p_priv;
2400 const struct keyspan_device_details *d_details;
2401 struct callbacks *cback;
2402 int endp;
2403 int port_num;
2404 int i;
2405
2406 s_priv = usb_get_serial_data(serial);
2407 d_details = s_priv->device_details;
2408
2409 p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL);
2410 if (!p_priv)
2411 return -ENOMEM;
2412
Johan Hovoldbad41a52013-08-13 13:27:37 +02002413 for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
2414 p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
2415 if (!p_priv->in_buffer[i])
2416 goto err_in_buffer;
2417 }
2418
2419 for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
2420 p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
2421 if (!p_priv->out_buffer[i])
2422 goto err_out_buffer;
2423 }
2424
2425 p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
2426 if (!p_priv->inack_buffer)
2427 goto err_inack_buffer;
2428
2429 p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
2430 if (!p_priv->outcont_buffer)
2431 goto err_outcont_buffer;
2432
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002433 p_priv->device_details = d_details;
2434
2435 /* Setup values for the various callback routines */
2436 cback = &keyspan_callbacks[d_details->msg_format];
2437
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002438 port_num = port->port_number;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002439
2440 /* Do indat endpoints first, once for each flip */
2441 endp = d_details->indat_endpoints[port_num];
2442 for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
2443 p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
2444 USB_DIR_IN, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002445 p_priv->in_buffer[i],
2446 IN_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002447 cback->indat_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 }
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002449 /* outdat endpoints also have flip */
2450 endp = d_details->outdat_endpoints[port_num];
2451 for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
2452 p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
2453 USB_DIR_OUT, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002454 p_priv->out_buffer[i],
2455 OUT_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002456 cback->outdat_callback);
2457 }
2458 /* inack endpoint */
2459 p_priv->inack_urb = keyspan_setup_urb(serial,
2460 d_details->inack_endpoints[port_num],
2461 USB_DIR_IN, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002462 p_priv->inack_buffer,
2463 INACK_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002464 cback->inack_callback);
2465 /* outcont endpoint */
2466 p_priv->outcont_urb = keyspan_setup_urb(serial,
2467 d_details->outcont_endpoints[port_num],
2468 USB_DIR_OUT, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002469 p_priv->outcont_buffer,
2470 OUTCONT_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002471 cback->outcont_callback);
2472
2473 usb_set_serial_port_data(port, p_priv);
2474
2475 return 0;
Johan Hovoldbad41a52013-08-13 13:27:37 +02002476
2477err_outcont_buffer:
2478 kfree(p_priv->inack_buffer);
2479err_inack_buffer:
2480 for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
2481 kfree(p_priv->out_buffer[i]);
2482err_out_buffer:
2483 for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
2484 kfree(p_priv->in_buffer[i]);
2485err_in_buffer:
2486 kfree(p_priv);
2487
2488 return -ENOMEM;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002489}
2490
2491static int keyspan_port_remove(struct usb_serial_port *port)
2492{
2493 struct keyspan_port_private *p_priv;
2494 int i;
2495
2496 p_priv = usb_get_serial_port_data(port);
2497
2498 stop_urb(p_priv->inack_urb);
2499 stop_urb(p_priv->outcont_urb);
2500 for (i = 0; i < 2; i++) {
2501 stop_urb(p_priv->in_urbs[i]);
2502 stop_urb(p_priv->out_urbs[i]);
2503 }
2504
2505 usb_free_urb(p_priv->inack_urb);
2506 usb_free_urb(p_priv->outcont_urb);
2507 for (i = 0; i < 2; i++) {
2508 usb_free_urb(p_priv->in_urbs[i]);
2509 usb_free_urb(p_priv->out_urbs[i]);
2510 }
2511
Johan Hovoldbad41a52013-08-13 13:27:37 +02002512 kfree(p_priv->outcont_buffer);
2513 kfree(p_priv->inack_buffer);
2514 for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
2515 kfree(p_priv->out_buffer[i]);
2516 for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
2517 kfree(p_priv->in_buffer[i]);
2518
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002519 kfree(p_priv);
2520
2521 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522}
2523
Alan Coxdeb91682008-07-22 11:13:08 +01002524MODULE_AUTHOR(DRIVER_AUTHOR);
2525MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526MODULE_LICENSE("GPL");
2527
David Woodhouse2971c572008-05-30 14:04:03 +03002528MODULE_FIRMWARE("keyspan/usa28.fw");
2529MODULE_FIRMWARE("keyspan/usa28x.fw");
2530MODULE_FIRMWARE("keyspan/usa28xa.fw");
2531MODULE_FIRMWARE("keyspan/usa28xb.fw");
2532MODULE_FIRMWARE("keyspan/usa19.fw");
2533MODULE_FIRMWARE("keyspan/usa19qi.fw");
2534MODULE_FIRMWARE("keyspan/mpr.fw");
2535MODULE_FIRMWARE("keyspan/usa19qw.fw");
2536MODULE_FIRMWARE("keyspan/usa18x.fw");
2537MODULE_FIRMWARE("keyspan/usa19w.fw");
2538MODULE_FIRMWARE("keyspan/usa49w.fw");
2539MODULE_FIRMWARE("keyspan/usa49wlc.fw");