blob: b6bd8e4a64865f9cda97549f24779ece4e967565 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/slab.h>
35#include <linux/tty.h>
36#include <linux/tty_driver.h>
37#include <linux/tty_flip.h>
38#include <linux/module.h>
39#include <linux/spinlock.h>
Alan Coxdeb91682008-07-22 11:13:08 +010040#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070042#include <linux/usb/serial.h>
Rene Buergelcc183e22012-09-18 09:00:41 +020043#include <linux/usb/ezusb.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include "keyspan.h"
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
47#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
48
49#define INSTAT_BUFLEN 32
50#define GLOCONT_BUFLEN 64
Lucy McCoy0ca12682007-05-18 12:10:41 -070051#define INDAT49W_BUFLEN 512
Johan Hovoldbad41a52013-08-13 13:27:37 +020052#define IN_BUFLEN 64
53#define OUT_BUFLEN 64
54#define INACK_BUFLEN 1
55#define OUTCONT_BUFLEN 64
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57 /* Per device and per port private data */
58struct keyspan_serial_private {
59 const struct keyspan_device_details *device_details;
60
61 struct urb *instat_urb;
Johan Hovold2fcd1c92013-08-13 13:27:36 +020062 char *instat_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Alan Coxdeb91682008-07-22 11:13:08 +010064 /* added to support 49wg, where data from all 4 ports comes in
65 on 1 EP and high-speed supported */
Lucy McCoy0ca12682007-05-18 12:10:41 -070066 struct urb *indat_urb;
Johan Hovold2fcd1c92013-08-13 13:27:36 +020067 char *indat_buf;
Lucy McCoy0ca12682007-05-18 12:10:41 -070068
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 /* XXX this one probably will need a lock */
70 struct urb *glocont_urb;
Johan Hovold2fcd1c92013-08-13 13:27:36 +020071 char *glocont_buf;
72 char *ctrl_buf; /* for EP0 control message */
Linus Torvalds1da177e2005-04-16 15:20:36 -070073};
74
75struct keyspan_port_private {
76 /* Keep track of which input & output endpoints to use */
77 int in_flip;
78 int out_flip;
79
80 /* Keep duplicate of device details in each port
81 structure as well - simplifies some of the
82 callback functions etc. */
83 const struct keyspan_device_details *device_details;
84
85 /* Input endpoints and buffer for this port */
86 struct urb *in_urbs[2];
Johan Hovoldbad41a52013-08-13 13:27:37 +020087 char *in_buffer[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 /* Output endpoints and buffer for this port */
89 struct urb *out_urbs[2];
Johan Hovoldbad41a52013-08-13 13:27:37 +020090 char *out_buffer[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92 /* Input ack endpoint */
93 struct urb *inack_urb;
Johan Hovoldbad41a52013-08-13 13:27:37 +020094 char *inack_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96 /* Output control endpoint */
97 struct urb *outcont_urb;
Johan Hovoldbad41a52013-08-13 13:27:37 +020098 char *outcont_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100 /* Settings for the port */
101 int baud;
102 int old_baud;
103 unsigned int cflag;
104 unsigned int old_cflag;
105 enum {flow_none, flow_cts, flow_xon} flow_control;
106 int rts_state; /* Handshaking pins (outputs) */
107 int dtr_state;
108 int cts_state; /* Handshaking pins (inputs) */
109 int dsr_state;
110 int dcd_state;
111 int ri_state;
112 int break_on;
113
114 unsigned long tx_start_time[2];
115 int resend_cont; /* need to resend control packet */
116};
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/* Include Keyspan message headers. All current Keyspan Adapters
Lucy McCoy0ca12682007-05-18 12:10:41 -0700119 make use of one of five message formats which are referred
Alan Coxdeb91682008-07-22 11:13:08 +0100120 to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and
121 within this driver. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122#include "keyspan_usa26msg.h"
123#include "keyspan_usa28msg.h"
124#include "keyspan_usa49msg.h"
125#include "keyspan_usa90msg.h"
Lucy McCoy0ca12682007-05-18 12:10:41 -0700126#include "keyspan_usa67msg.h"
Alan Coxdeb91682008-07-22 11:13:08 +0100127
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -0700129module_usb_serial_driver(serial_drivers, keyspan_ids_combined);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
Alan Cox95da3102008-07-22 11:09:07 +0100131static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132{
Alan Cox95da3102008-07-22 11:09:07 +0100133 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 struct keyspan_port_private *p_priv;
135
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 p_priv = usb_get_serial_port_data(port);
137
138 if (break_state == -1)
139 p_priv->break_on = 1;
140 else
141 p_priv->break_on = 0;
142
143 keyspan_send_setup(port, 0);
144}
145
146
Alan Coxdeb91682008-07-22 11:13:08 +0100147static void keyspan_set_termios(struct tty_struct *tty,
Alan Cox95da3102008-07-22 11:09:07 +0100148 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
150 int baud_rate, device_port;
151 struct keyspan_port_private *p_priv;
152 const struct keyspan_device_details *d_details;
153 unsigned int cflag;
154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 p_priv = usb_get_serial_port_data(port);
156 d_details = p_priv->device_details;
Alan Coxadc8d742012-07-14 15:31:47 +0100157 cflag = tty->termios.c_cflag;
Greg Kroah-Hartman11438322013-06-06 10:32:00 -0700158 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
160 /* Baud rate calculation takes baud rate as an integer
161 so other rates can be generated if desired. */
Alan Cox74240b02007-10-18 01:24:20 -0700162 baud_rate = tty_get_baud_rate(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100163 /* If no match or invalid, don't change */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700164 if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
166 /* FIXME - more to do here to ensure rate changes cleanly */
Rahul Bedarkarcd8c5052014-01-02 19:29:24 +0530167 /* FIXME - calculate exact rate from divisor ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 p_priv->baud = baud_rate;
Alan Cox74240b02007-10-18 01:24:20 -0700169 } else
170 baud_rate = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
Alan Cox74240b02007-10-18 01:24:20 -0700172 tty_encode_baud_rate(tty, baud_rate, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 /* set CTS/RTS handshake etc. */
174 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +1000175 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
Alan Cox74240b02007-10-18 01:24:20 -0700177 /* Mark/Space not supported */
Alan Coxadc8d742012-07-14 15:31:47 +0100178 tty->termios.c_cflag &= ~CMSPAR;
Alan Cox74240b02007-10-18 01:24:20 -0700179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 keyspan_send_setup(port, 0);
181}
182
Alan Cox60b33c12011-02-14 16:26:14 +0000183static int keyspan_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184{
Alan Cox95da3102008-07-22 11:09:07 +0100185 struct usb_serial_port *port = tty->driver_data;
186 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 unsigned int value;
Alan Coxdeb91682008-07-22 11:13:08 +0100188
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
190 ((p_priv->dtr_state) ? TIOCM_DTR : 0) |
191 ((p_priv->cts_state) ? TIOCM_CTS : 0) |
192 ((p_priv->dsr_state) ? TIOCM_DSR : 0) |
193 ((p_priv->dcd_state) ? TIOCM_CAR : 0) |
Alan Coxdeb91682008-07-22 11:13:08 +0100194 ((p_priv->ri_state) ? TIOCM_RNG : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196 return value;
197}
198
Alan Cox20b9d172011-02-14 16:26:50 +0000199static int keyspan_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 unsigned int set, unsigned int clear)
201{
Alan Cox95da3102008-07-22 11:09:07 +0100202 struct usb_serial_port *port = tty->driver_data;
203 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100204
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 if (set & TIOCM_RTS)
206 p_priv->rts_state = 1;
207 if (set & TIOCM_DTR)
208 p_priv->dtr_state = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 if (clear & TIOCM_RTS)
210 p_priv->rts_state = 0;
211 if (clear & TIOCM_DTR)
212 p_priv->dtr_state = 0;
213 keyspan_send_setup(port, 0);
214 return 0;
215}
216
Alan Cox95da3102008-07-22 11:09:07 +0100217/* Write function is similar for the four protocols used
218 with only a minor change for usa90 (usa19hs) required */
219static int keyspan_write(struct tty_struct *tty,
220 struct usb_serial_port *port, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221{
222 struct keyspan_port_private *p_priv;
223 const struct keyspan_device_details *d_details;
224 int flip;
225 int left, todo;
226 struct urb *this_urb;
Alan Coxdeb91682008-07-22 11:13:08 +0100227 int err, maxDataLen, dataOffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229 p_priv = usb_get_serial_port_data(port);
230 d_details = p_priv->device_details;
231
232 if (d_details->msg_format == msg_usa90) {
Alan Coxdeb91682008-07-22 11:13:08 +0100233 maxDataLen = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 dataOffset = 0;
235 } else {
236 maxDataLen = 63;
237 dataOffset = 1;
238 }
Alan Coxdeb91682008-07-22 11:13:08 +0100239
Greg Kroah-Hartman11438322013-06-06 10:32:00 -0700240 dev_dbg(&port->dev, "%s - %d chars, flip=%d\n", __func__, count,
241 p_priv->out_flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
243 for (left = count; left > 0; left -= todo) {
244 todo = left;
245 if (todo > maxDataLen)
246 todo = maxDataLen;
247
248 flip = p_priv->out_flip;
Alan Coxdeb91682008-07-22 11:13:08 +0100249
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 /* Check we have a valid urb/endpoint before we use it... */
Alan Coxdeb91682008-07-22 11:13:08 +0100251 this_urb = p_priv->out_urbs[flip];
252 if (this_urb == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 /* no bulk out, so return 0 bytes written */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700254 dev_dbg(&port->dev, "%s - no output urb :(\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 return count;
256 }
257
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700258 dev_dbg(&port->dev, "%s - endpoint %d flip %d\n",
Alan Coxdeb91682008-07-22 11:13:08 +0100259 __func__, usb_pipeendpoint(this_urb->pipe), flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
261 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +0100262 if (time_before(jiffies,
263 p_priv->tx_start_time[flip] + 10 * HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 usb_unlink_urb(this_urb);
266 break;
267 }
268
Alan Coxdeb91682008-07-22 11:13:08 +0100269 /* First byte in buffer is "last flag" (except for usa19hx)
270 - unused so for now so set to zero */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 ((char *)this_urb->transfer_buffer)[0] = 0;
272
Alan Coxdeb91682008-07-22 11:13:08 +0100273 memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 buf += todo;
275
276 /* send the data out the bulk port */
277 this_urb->transfer_buffer_length = todo + dataOffset;
278
Alan Coxdeb91682008-07-22 11:13:08 +0100279 err = usb_submit_urb(this_urb, GFP_ATOMIC);
280 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700281 dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 p_priv->tx_start_time[flip] = jiffies;
283
284 /* Flip for next time if usa26 or usa28 interface
285 (not used on usa49) */
286 p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
287 }
288
289 return count - left;
290}
291
David Howells7d12e782006-10-05 14:55:46 +0100292static void usa26_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
294 int i, err;
295 int endpoint;
296 struct usb_serial_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700298 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 endpoint = usb_pipeendpoint(urb->pipe);
301
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700302 if (status) {
Stefan Hubnera8ffa0b2012-12-13 22:45:00 +0100303 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700304 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 return;
306 }
307
Ming Leicdc97792008-02-24 18:41:47 +0800308 port = urb->context;
Jiri Slaby2e124b42013-01-03 15:53:06 +0100309 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 /* 0x80 bit is error flag */
311 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100312 /* no errors on individual bytes, only
313 possible overrun err */
Johan Hovold855515a2014-11-18 11:25:20 +0100314 if (data[0] & RXERROR_OVERRUN) {
315 tty_insert_flip_char(&port->port, 0,
316 TTY_OVERRUN);
317 }
Alan Coxdeb91682008-07-22 11:13:08 +0100318 for (i = 1; i < urb->actual_length ; ++i)
Johan Hovold855515a2014-11-18 11:25:20 +0100319 tty_insert_flip_char(&port->port, data[i],
320 TTY_NORMAL);
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) {
Johan Hovold5d1678a2014-11-18 11:25:19 +0100325 int stat = data[i];
326 int flag = TTY_NORMAL;
327
328 if (stat & RXERROR_OVERRUN) {
329 tty_insert_flip_char(&port->port, 0,
330 TTY_OVERRUN);
331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 /* XXX should handle break (0x10) */
Johan Hovold5d1678a2014-11-18 11:25:19 +0100333 if (stat & RXERROR_PARITY)
334 flag = TTY_PARITY;
335 else if (stat & RXERROR_FRAMING)
336 flag = TTY_FRAME;
337
Jiri Slaby92a19f92013-01-03 15:53:03 +0100338 tty_insert_flip_char(&port->port, data[i+1],
339 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 }
341 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100342 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 }
Alan Coxdeb91682008-07-22 11:13:08 +0100344
345 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500346 err = usb_submit_urb(urb, GFP_ATOMIC);
347 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700348 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349}
350
Alan Coxdeb91682008-07-22 11:13:08 +0100351/* Outdat handling is common for all devices */
David Howells7d12e782006-10-05 14:55:46 +0100352static void usa2x_outdat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
354 struct usb_serial_port *port;
355 struct keyspan_port_private *p_priv;
356
Ming Leicdc97792008-02-24 18:41:47 +0800357 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 p_priv = usb_get_serial_port_data(port);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700359 dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Alan Stern1f871582010-02-17 10:05:47 -0500361 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
David Howells7d12e782006-10-05 14:55:46 +0100364static void usa26_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366}
367
David Howells7d12e782006-10-05 14:55:46 +0100368static void usa26_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
370 struct usb_serial_port *port;
371 struct keyspan_port_private *p_priv;
372
Ming Leicdc97792008-02-24 18:41:47 +0800373 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 p_priv = usb_get_serial_port_data(port);
375
376 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700377 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100378 keyspan_usa26_send_setup(port->serial, port,
379 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
381}
382
David Howells7d12e782006-10-05 14:55:46 +0100383static void usa26_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 unsigned char *data = urb->transfer_buffer;
386 struct keyspan_usa26_portStatusMessage *msg;
387 struct usb_serial *serial;
388 struct usb_serial_port *port;
389 struct keyspan_port_private *p_priv;
390 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700391 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Ming Leicdc97792008-02-24 18:41:47 +0800393 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700395 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700396 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 return;
398 }
399 if (urb->actual_length != 9) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700400 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 goto exit;
402 }
403
404 msg = (struct keyspan_usa26_portStatusMessage *)data;
405
Alan Coxdeb91682008-07-22 11:13:08 +0100406 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700408 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 goto exit;
410 }
411 port = serial->port[msg->port];
412 p_priv = usb_get_serial_port_data(port);
Johan Hovoldb5122232014-12-22 18:39:39 +0100413 if (!p_priv)
414 goto resubmit;
Alan Coxdeb91682008-07-22 11:13:08 +0100415
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 /* Update handshaking pin state information */
417 old_dcd_state = p_priv->dcd_state;
418 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
419 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
420 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
421 p_priv->ri_state = ((msg->ri) ? 1 : 0);
422
Jiri Slabyaa27a092013-03-07 13:12:30 +0100423 if (old_dcd_state != p_priv->dcd_state)
424 tty_port_tty_hangup(&port->port, true);
Johan Hovoldb5122232014-12-22 18:39:39 +0100425resubmit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100427 err = usb_submit_urb(urb, GFP_ATOMIC);
428 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700429 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430exit: ;
431}
432
David Howells7d12e782006-10-05 14:55:46 +0100433static void usa26_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435}
436
437
David Howells7d12e782006-10-05 14:55:46 +0100438static void usa28_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
Alan Coxf035a8a2008-07-22 11:13:32 +0100440 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 struct usb_serial_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 unsigned char *data;
443 struct keyspan_port_private *p_priv;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700444 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Ming Leicdc97792008-02-24 18:41:47 +0800446 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 p_priv = usb_get_serial_port_data(port);
448 data = urb->transfer_buffer;
449
450 if (urb != p_priv->in_urbs[p_priv->in_flip])
451 return;
452
453 do {
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700454 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700455 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
456 __func__, status, usb_pipeendpoint(urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 return;
458 }
459
Ming Leicdc97792008-02-24 18:41:47 +0800460 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 p_priv = usb_get_serial_port_data(port);
462 data = urb->transfer_buffer;
463
Jiri Slaby2e124b42013-01-03 15:53:06 +0100464 if (urb->actual_length) {
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100465 tty_insert_flip_string(&port->port, data,
466 urb->actual_length);
Jiri Slaby2e124b42013-01-03 15:53:06 +0100467 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 }
469
470 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500471 err = usb_submit_urb(urb, GFP_ATOMIC);
472 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700473 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
Alan Stern1f871582010-02-17 10:05:47 -0500474 __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 p_priv->in_flip ^= 1;
476
477 urb = p_priv->in_urbs[p_priv->in_flip];
478 } while (urb->status != -EINPROGRESS);
479}
480
David Howells7d12e782006-10-05 14:55:46 +0100481static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483}
484
David Howells7d12e782006-10-05 14:55:46 +0100485static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
487 struct usb_serial_port *port;
488 struct keyspan_port_private *p_priv;
489
Ming Leicdc97792008-02-24 18:41:47 +0800490 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 p_priv = usb_get_serial_port_data(port);
492
493 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700494 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100495 keyspan_usa28_send_setup(port->serial, port,
496 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 }
498}
499
David Howells7d12e782006-10-05 14:55:46 +0100500static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
502 int err;
503 unsigned char *data = urb->transfer_buffer;
504 struct keyspan_usa28_portStatusMessage *msg;
505 struct usb_serial *serial;
506 struct usb_serial_port *port;
507 struct keyspan_port_private *p_priv;
508 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700509 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Ming Leicdc97792008-02-24 18:41:47 +0800511 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700513 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700514 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 return;
516 }
517
518 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700519 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 goto exit;
521 }
522
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 msg = (struct keyspan_usa28_portStatusMessage *)data;
524
Alan Coxdeb91682008-07-22 11:13:08 +0100525 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700527 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 goto exit;
529 }
530 port = serial->port[msg->port];
531 p_priv = usb_get_serial_port_data(port);
Johan Hovoldb5122232014-12-22 18:39:39 +0100532 if (!p_priv)
533 goto resubmit;
Alan Coxdeb91682008-07-22 11:13:08 +0100534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 /* Update handshaking pin state information */
536 old_dcd_state = p_priv->dcd_state;
537 p_priv->cts_state = ((msg->cts) ? 1 : 0);
538 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
539 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
540 p_priv->ri_state = ((msg->ri) ? 1 : 0);
541
Jiri Slabyaa27a092013-03-07 13:12:30 +0100542 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
543 tty_port_tty_hangup(&port->port, true);
Johan Hovoldb5122232014-12-22 18:39:39 +0100544resubmit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100546 err = usb_submit_urb(urb, GFP_ATOMIC);
547 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700548 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549exit: ;
550}
551
David Howells7d12e782006-10-05 14:55:46 +0100552static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554}
555
556
David Howells7d12e782006-10-05 14:55:46 +0100557static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558{
559 struct usb_serial *serial;
560 struct usb_serial_port *port;
561 struct keyspan_port_private *p_priv;
562 int i;
563
Ming Leicdc97792008-02-24 18:41:47 +0800564 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 for (i = 0; i < serial->num_ports; ++i) {
566 port = serial->port[i];
567 p_priv = usb_get_serial_port_data(port);
568
569 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700570 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100571 keyspan_usa49_send_setup(serial, port,
572 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 break;
574 }
575 }
576}
577
578 /* This is actually called glostat in the Keyspan
579 doco */
David Howells7d12e782006-10-05 14:55:46 +0100580static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
582 int err;
583 unsigned char *data = urb->transfer_buffer;
584 struct keyspan_usa49_portStatusMessage *msg;
585 struct usb_serial *serial;
586 struct usb_serial_port *port;
587 struct keyspan_port_private *p_priv;
588 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700589 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Ming Leicdc97792008-02-24 18:41:47 +0800591 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700593 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700594 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 return;
596 }
597
Alan Coxdeb91682008-07-22 11:13:08 +0100598 if (urb->actual_length !=
599 sizeof(struct keyspan_usa49_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700600 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 goto exit;
602 }
603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 msg = (struct keyspan_usa49_portStatusMessage *)data;
605
Alan Coxdeb91682008-07-22 11:13:08 +0100606 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 if (msg->portNumber >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700608 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
609 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 goto exit;
611 }
612 port = serial->port[msg->portNumber];
613 p_priv = usb_get_serial_port_data(port);
Johan Hovoldb5122232014-12-22 18:39:39 +0100614 if (!p_priv)
615 goto resubmit;
Alan Coxdeb91682008-07-22 11:13:08 +0100616
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 /* Update handshaking pin state information */
618 old_dcd_state = p_priv->dcd_state;
619 p_priv->cts_state = ((msg->cts) ? 1 : 0);
620 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
621 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
622 p_priv->ri_state = ((msg->ri) ? 1 : 0);
623
Jiri Slabyaa27a092013-03-07 13:12:30 +0100624 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
625 tty_port_tty_hangup(&port->port, true);
Johan Hovoldb5122232014-12-22 18:39:39 +0100626resubmit:
Alan Coxdeb91682008-07-22 11:13:08 +0100627 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100628 err = usb_submit_urb(urb, GFP_ATOMIC);
629 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700630 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631exit: ;
632}
633
David Howells7d12e782006-10-05 14:55:46 +0100634static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636}
637
David Howells7d12e782006-10-05 14:55:46 +0100638static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639{
640 int i, err;
641 int endpoint;
642 struct usb_serial_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700644 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 endpoint = usb_pipeendpoint(urb->pipe);
647
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700648 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700649 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
650 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 return;
652 }
653
Ming Leicdc97792008-02-24 18:41:47 +0800654 port = urb->context;
Jiri Slaby2e124b42013-01-03 15:53:06 +0100655 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 /* 0x80 bit is error flag */
657 if ((data[0] & 0x80) == 0) {
658 /* no error on any byte */
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100659 tty_insert_flip_string(&port->port, data + 1,
Alan Coxf035a8a2008-07-22 11:13:32 +0100660 urb->actual_length - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 } else {
662 /* some bytes had errors, every byte has status */
663 for (i = 0; i + 1 < urb->actual_length; i += 2) {
Johan Hovold5d1678a2014-11-18 11:25:19 +0100664 int stat = data[i];
665 int flag = TTY_NORMAL;
666
667 if (stat & RXERROR_OVERRUN) {
668 tty_insert_flip_char(&port->port, 0,
669 TTY_OVERRUN);
670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 /* XXX should handle break (0x10) */
Johan Hovold5d1678a2014-11-18 11:25:19 +0100672 if (stat & RXERROR_PARITY)
673 flag = TTY_PARITY;
674 else if (stat & RXERROR_FRAMING)
675 flag = TTY_FRAME;
676
Jiri Slaby92a19f92013-01-03 15:53:03 +0100677 tty_insert_flip_char(&port->port, data[i+1],
678 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 }
680 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100681 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 }
Alan Coxdeb91682008-07-22 11:13:08 +0100683
684 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500685 err = usb_submit_urb(urb, GFP_ATOMIC);
686 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700687 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688}
689
Lucy McCoy0ca12682007-05-18 12:10:41 -0700690static void usa49wg_indat_callback(struct urb *urb)
691{
692 int i, len, x, err;
693 struct usb_serial *serial;
694 struct usb_serial_port *port;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700695 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700696 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700697
Lucy McCoy0ca12682007-05-18 12:10:41 -0700698 serial = urb->context;
699
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700700 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700701 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700702 return;
703 }
704
705 /* inbound data is in the form P#, len, status, data */
706 i = 0;
707 len = 0;
708
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300709 while (i < urb->actual_length) {
Lucy McCoy0ca12682007-05-18 12:10:41 -0700710
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300711 /* Check port number from message */
712 if (data[i] >= serial->num_ports) {
713 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
714 __func__, data[i]);
715 return;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700716 }
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300717 port = serial->port[data[i++]];
718 len = data[i++];
719
720 /* 0x80 bit is error flag */
721 if ((data[i] & 0x80) == 0) {
722 /* no error on any byte */
723 i++;
Dan Carpenter01a60e72013-04-05 08:43:20 +0300724 for (x = 1; x < len && i < urb->actual_length; ++x)
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300725 tty_insert_flip_char(&port->port,
726 data[i++], 0);
727 } else {
728 /*
729 * some bytes had errors, every byte has status
730 */
Dan Carpenter01a60e72013-04-05 08:43:20 +0300731 for (x = 0; x + 1 < len &&
732 i + 1 < urb->actual_length; x += 2) {
Johan Hovold5d1678a2014-11-18 11:25:19 +0100733 int stat = data[i];
734 int flag = TTY_NORMAL;
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300735
Johan Hovold5d1678a2014-11-18 11:25:19 +0100736 if (stat & RXERROR_OVERRUN) {
737 tty_insert_flip_char(&port->port, 0,
738 TTY_OVERRUN);
739 }
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300740 /* XXX should handle break (0x10) */
Johan Hovold5d1678a2014-11-18 11:25:19 +0100741 if (stat & RXERROR_PARITY)
742 flag = TTY_PARITY;
743 else if (stat & RXERROR_FRAMING)
744 flag = TTY_FRAME;
745
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300746 tty_insert_flip_char(&port->port, data[i+1],
747 flag);
748 i += 2;
749 }
750 }
751 tty_flip_buffer_push(&port->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700752 }
753
754 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700755 err = usb_submit_urb(urb, GFP_ATOMIC);
756 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700757 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700758}
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700761static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763}
764
Lucy McCoy0ca12682007-05-18 12:10:41 -0700765static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
767 int i, err;
768 int endpoint;
769 struct usb_serial_port *port;
770 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700772 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 endpoint = usb_pipeendpoint(urb->pipe);
775
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700776 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700777 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800778 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 return;
780 }
781
Ming Leicdc97792008-02-24 18:41:47 +0800782 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 p_priv = usb_get_serial_port_data(port);
784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100787 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
Alan Coxf035a8a2008-07-22 11:13:32 +0100789 if (p_priv->baud > 57600)
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100790 tty_insert_flip_string(&port->port, data,
791 urb->actual_length);
Alan Coxf035a8a2008-07-22 11:13:32 +0100792 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 /* 0x80 bit is error flag */
794 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100795 /* no errors on individual bytes, only
796 possible overrun err*/
Johan Hovold855515a2014-11-18 11:25:20 +0100797 if (data[0] & RXERROR_OVERRUN) {
798 tty_insert_flip_char(&port->port, 0,
799 TTY_OVERRUN);
800 }
Alan Coxdeb91682008-07-22 11:13:08 +0100801 for (i = 1; i < urb->actual_length ; ++i)
Jiri Slaby92a19f92013-01-03 15:53:03 +0100802 tty_insert_flip_char(&port->port,
Johan Hovold855515a2014-11-18 11:25:20 +0100803 data[i], TTY_NORMAL);
Alan Coxdeb91682008-07-22 11:13:08 +0100804 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700806 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 for (i = 0; i + 1 < urb->actual_length; i += 2) {
Johan Hovold5d1678a2014-11-18 11:25:19 +0100808 int stat = data[i];
809 int flag = TTY_NORMAL;
810
811 if (stat & RXERROR_OVERRUN) {
812 tty_insert_flip_char(
813 &port->port, 0,
814 TTY_OVERRUN);
815 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 /* XXX should handle break (0x10) */
Johan Hovold5d1678a2014-11-18 11:25:19 +0100817 if (stat & RXERROR_PARITY)
818 flag = TTY_PARITY;
819 else if (stat & RXERROR_FRAMING)
820 flag = TTY_FRAME;
821
Jiri Slaby92a19f92013-01-03 15:53:03 +0100822 tty_insert_flip_char(&port->port,
823 data[i+1], flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 }
825 }
826 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100827 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
Alan Coxdeb91682008-07-22 11:13:08 +0100829
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500831 err = usb_submit_urb(urb, GFP_ATOMIC);
832 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700833 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834}
835
836
David Howells7d12e782006-10-05 14:55:46 +0100837static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838{
839 unsigned char *data = urb->transfer_buffer;
840 struct keyspan_usa90_portStatusMessage *msg;
841 struct usb_serial *serial;
842 struct usb_serial_port *port;
843 struct keyspan_port_private *p_priv;
844 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700845 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Ming Leicdc97792008-02-24 18:41:47 +0800847 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700849 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700850 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 return;
852 }
853 if (urb->actual_length < 14) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700854 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 goto exit;
856 }
857
858 msg = (struct keyspan_usa90_portStatusMessage *)data;
859
860 /* Now do something useful with the data */
861
862 port = serial->port[0];
863 p_priv = usb_get_serial_port_data(port);
Johan Hovoldb5122232014-12-22 18:39:39 +0100864 if (!p_priv)
865 goto resubmit;
Alan Coxdeb91682008-07-22 11:13:08 +0100866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 /* Update handshaking pin state information */
868 old_dcd_state = p_priv->dcd_state;
869 p_priv->cts_state = ((msg->cts) ? 1 : 0);
870 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
871 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
872 p_priv->ri_state = ((msg->ri) ? 1 : 0);
873
Jiri Slabyaa27a092013-03-07 13:12:30 +0100874 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
875 tty_port_tty_hangup(&port->port, true);
Johan Hovoldb5122232014-12-22 18:39:39 +0100876resubmit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100878 err = usb_submit_urb(urb, GFP_ATOMIC);
879 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700880 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881exit:
882 ;
883}
884
David Howells7d12e782006-10-05 14:55:46 +0100885static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886{
887 struct usb_serial_port *port;
888 struct keyspan_port_private *p_priv;
889
Ming Leicdc97792008-02-24 18:41:47 +0800890 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 p_priv = usb_get_serial_port_data(port);
892
893 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700894 dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100895 keyspan_usa90_send_setup(port->serial, port,
896 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 }
898}
899
Lucy McCoy0ca12682007-05-18 12:10:41 -0700900/* Status messages from the 28xg */
901static void usa67_instat_callback(struct urb *urb)
902{
903 int err;
904 unsigned char *data = urb->transfer_buffer;
905 struct keyspan_usa67_portStatusMessage *msg;
906 struct usb_serial *serial;
907 struct usb_serial_port *port;
908 struct keyspan_port_private *p_priv;
909 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700910 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700911
Lucy McCoy0ca12682007-05-18 12:10:41 -0700912 serial = urb->context;
913
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700914 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700915 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700916 return;
917 }
918
Alan Coxdeb91682008-07-22 11:13:08 +0100919 if (urb->actual_length !=
920 sizeof(struct keyspan_usa67_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700921 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700922 return;
923 }
924
925
926 /* Now do something useful with the data */
927 msg = (struct keyspan_usa67_portStatusMessage *)data;
928
929 /* Check port number from message and retrieve private data */
930 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700931 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700932 return;
933 }
934
935 port = serial->port[msg->port];
936 p_priv = usb_get_serial_port_data(port);
Johan Hovoldb5122232014-12-22 18:39:39 +0100937 if (!p_priv)
938 goto resubmit;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700939
940 /* Update handshaking pin state information */
941 old_dcd_state = p_priv->dcd_state;
942 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
943 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
944
Jiri Slabyaa27a092013-03-07 13:12:30 +0100945 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
946 tty_port_tty_hangup(&port->port, true);
Johan Hovoldb5122232014-12-22 18:39:39 +0100947resubmit:
Lucy McCoy0ca12682007-05-18 12:10:41 -0700948 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700949 err = usb_submit_urb(urb, GFP_ATOMIC);
950 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700951 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700952}
953
954static void usa67_glocont_callback(struct urb *urb)
955{
956 struct usb_serial *serial;
957 struct usb_serial_port *port;
958 struct keyspan_port_private *p_priv;
959 int i;
960
Lucy McCoy0ca12682007-05-18 12:10:41 -0700961 serial = urb->context;
962 for (i = 0; i < serial->num_ports; ++i) {
963 port = serial->port[i];
964 p_priv = usb_get_serial_port_data(port);
965
966 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700967 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700968 keyspan_usa67_send_setup(serial, port,
969 p_priv->resend_cont - 1);
970 break;
971 }
972 }
973}
974
Alan Cox95da3102008-07-22 11:09:07 +0100975static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976{
Alan Cox95da3102008-07-22 11:09:07 +0100977 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 struct keyspan_port_private *p_priv;
979 const struct keyspan_device_details *d_details;
980 int flip;
981 int data_len;
982 struct urb *this_urb;
983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 p_priv = usb_get_serial_port_data(port);
985 d_details = p_priv->device_details;
986
Alan Coxa5b6f602008-04-08 17:16:06 +0100987 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +0100989 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 else
991 data_len = 63;
992
993 flip = p_priv->out_flip;
994
995 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +0100996 this_urb = p_priv->out_urbs[flip];
997 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +0100999 return data_len;
1000 flip = (flip + 1) & d_details->outdat_endp_flip;
1001 this_urb = p_priv->out_urbs[flip];
1002 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001004 return data_len;
1005 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 }
Alan Coxa5b6f602008-04-08 17:16:06 +01001007 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008}
1009
1010
Alan Coxa509a7e2009-09-19 13:13:26 -07001011static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001013 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 const struct keyspan_device_details *d_details;
1015 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001016 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001018 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 p_priv = usb_get_serial_port_data(port);
1021 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 /* Set some sane defaults */
1024 p_priv->rts_state = 1;
1025 p_priv->dtr_state = 1;
1026 p_priv->baud = 9600;
1027
1028 /* force baud and lcr to be set on open */
1029 p_priv->old_baud = 0;
1030 p_priv->old_cflag = 0;
1031
1032 p_priv->out_flip = 0;
1033 p_priv->in_flip = 0;
1034
1035 /* Reset low level data toggle and start reading from endpoints */
1036 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001037 urb = p_priv->in_urbs[i];
1038 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Alan Coxdeb91682008-07-22 11:13:08 +01001041 /* make sure endpoint data toggle is synchronized
1042 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001044 err = usb_submit_urb(urb, GFP_KERNEL);
1045 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001046 dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 }
1048
1049 /* Reset low level data toggle on out endpoints */
1050 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001051 urb = p_priv->out_urbs[i];
1052 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 continue;
Alan Coxdeb91682008-07-22 11:13:08 +01001054 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1055 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 }
1057
Andrew Mortonf78ba152007-11-28 16:21:54 -08001058 /* get the terminal config for the setup message now so we don't
1059 * need to send 2 of them */
1060
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001061 device_port = port->port_number;
Alan Cox95da3102008-07-22 11:09:07 +01001062 if (tty) {
Alan Coxadc8d742012-07-14 15:31:47 +01001063 cflag = tty->termios.c_cflag;
Alan Cox95da3102008-07-22 11:09:07 +01001064 /* Baud rate calculation takes baud rate as an integer
1065 so other rates can be generated if desired. */
1066 baud_rate = tty_get_baud_rate(tty);
1067 /* If no match or invalid, leave as default */
1068 if (baud_rate >= 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001069 && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Alan Cox95da3102008-07-22 11:09:07 +01001070 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1071 p_priv->baud = baud_rate;
1072 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001073 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001074 /* set CTS/RTS handshake etc. */
1075 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +10001076 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001077
1078 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001079 /* mdelay(100); */
1080 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001081
Alan Coxa5b6f602008-04-08 17:16:06 +01001082 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083}
1084
1085static inline void stop_urb(struct urb *urb)
1086{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001087 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089}
1090
Alan Cox335f8512009-06-11 12:26:29 +01001091static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1092{
1093 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1094
1095 p_priv->rts_state = on;
1096 p_priv->dtr_state = on;
1097 keyspan_send_setup(port, 0);
1098}
1099
1100static void keyspan_close(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101{
1102 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 struct keyspan_port_private *p_priv;
1104
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 p_priv->rts_state = 0;
1108 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001109
Johan Hovold80dfe0c2013-03-21 12:36:32 +01001110 keyspan_send_setup(port, 2);
1111 /* pilot-xfer seems to work best with this delay */
1112 mdelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
1114 p_priv->out_flip = 0;
1115 p_priv->in_flip = 0;
1116
Johan Hovold80dfe0c2013-03-21 12:36:32 +01001117 stop_urb(p_priv->inack_urb);
1118 for (i = 0; i < 2; i++) {
1119 stop_urb(p_priv->in_urbs[i]);
1120 stop_urb(p_priv->out_urbs[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122}
1123
Alan Coxdeb91682008-07-22 11:13:08 +01001124/* download the firmware to a pre-renumeration device */
1125static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126{
Rene Buergel8d733e22012-09-18 09:02:01 +02001127 char *fw_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001129 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
1130 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1131 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001132
1133 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1134 != 0x8000) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001135 dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n");
Alan Coxdeb91682008-07-22 11:13:08 +01001136 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 }
1138
1139 /* Select firmware image on the basis of idProduct */
1140 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1141 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001142 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 break;
1144
1145 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001146 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 break;
1148
1149 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001150 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 break;
1152
1153 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001154 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 break;
1156
1157 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001158 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001162 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001166 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 break;
1168
1169 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001170 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001172
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001174 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001176
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001178 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001180
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001182 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 break;
1184
1185 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001186 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 break;
1188
1189 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001190 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1191 le16_to_cpu(serial->dev->descriptor.idProduct));
1192 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 }
1194
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001195 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
Rene Buergel8d733e22012-09-18 09:02:01 +02001197 if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
1198 dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
1199 fw_name);
1200 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 }
1202
Rene Buergel8d733e22012-09-18 09:02:01 +02001203 /* after downloading firmware Renumeration will occur in a
1204 moment and the new device will bind to the real driver */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205
1206 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001207 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208}
1209
1210/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001211static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1212 int endpoint)
1213{
1214 struct usb_host_interface *iface_desc;
1215 struct usb_endpoint_descriptor *ep;
1216 int i;
1217
1218 iface_desc = serial->interface->cur_altsetting;
1219 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1220 ep = &iface_desc->endpoint[i].desc;
1221 if (ep->bEndpointAddress == endpoint)
1222 return ep;
1223 }
1224 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1225 "endpoint %x\n", endpoint);
1226 return NULL;
1227}
1228
Alan Coxdeb91682008-07-22 11:13:08 +01001229static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001231 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232{
1233 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001234 struct usb_endpoint_descriptor const *ep_desc;
1235 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
1237 if (endpoint == -1)
1238 return NULL; /* endpoint not needed */
1239
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001240 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
Johan Hovold10c642d2013-12-29 19:22:56 +01001242 if (!urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Lucy McCoy0ca12682007-05-18 12:10:41 -07001245 if (endpoint == 0) {
1246 /* control EP filled in when used */
1247 return urb;
1248 }
1249
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001250 ep_desc = find_ep(serial, endpoint);
1251 if (!ep_desc) {
1252 /* leak the urb, something's wrong and the callers don't care */
1253 return urb;
1254 }
1255 if (usb_endpoint_xfer_int(ep_desc)) {
1256 ep_type_name = "INT";
1257 usb_fill_int_urb(urb, serial->dev,
1258 usb_sndintpipe(serial->dev, endpoint) | dir,
1259 buf, len, callback, ctx,
1260 ep_desc->bInterval);
1261 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1262 ep_type_name = "BULK";
1263 usb_fill_bulk_urb(urb, serial->dev,
1264 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1265 buf, len, callback, ctx);
1266 } else {
1267 dev_warn(&serial->interface->dev,
1268 "unsupported endpoint type %x\n",
Julia Lawall2e0fe702008-12-29 11:22:14 +01001269 usb_endpoint_type(ep_desc));
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001270 usb_free_urb(urb);
1271 return NULL;
1272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001274 dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001275 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 return urb;
1277}
1278
1279static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001280 void (*instat_callback)(struct urb *);
1281 void (*glocont_callback)(struct urb *);
1282 void (*indat_callback)(struct urb *);
1283 void (*outdat_callback)(struct urb *);
1284 void (*inack_callback)(struct urb *);
1285 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286} keyspan_callbacks[] = {
1287 {
1288 /* msg_usa26 callbacks */
1289 .instat_callback = usa26_instat_callback,
1290 .glocont_callback = usa26_glocont_callback,
1291 .indat_callback = usa26_indat_callback,
1292 .outdat_callback = usa2x_outdat_callback,
1293 .inack_callback = usa26_inack_callback,
1294 .outcont_callback = usa26_outcont_callback,
1295 }, {
1296 /* msg_usa28 callbacks */
1297 .instat_callback = usa28_instat_callback,
1298 .glocont_callback = usa28_glocont_callback,
1299 .indat_callback = usa28_indat_callback,
1300 .outdat_callback = usa2x_outdat_callback,
1301 .inack_callback = usa28_inack_callback,
1302 .outcont_callback = usa28_outcont_callback,
1303 }, {
1304 /* msg_usa49 callbacks */
1305 .instat_callback = usa49_instat_callback,
1306 .glocont_callback = usa49_glocont_callback,
1307 .indat_callback = usa49_indat_callback,
1308 .outdat_callback = usa2x_outdat_callback,
1309 .inack_callback = usa49_inack_callback,
1310 .outcont_callback = usa49_outcont_callback,
1311 }, {
1312 /* msg_usa90 callbacks */
1313 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001314 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 .indat_callback = usa90_indat_callback,
1316 .outdat_callback = usa2x_outdat_callback,
1317 .inack_callback = usa28_inack_callback,
1318 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001319 }, {
1320 /* msg_usa67 callbacks */
1321 .instat_callback = usa67_instat_callback,
1322 .glocont_callback = usa67_glocont_callback,
1323 .indat_callback = usa26_indat_callback,
1324 .outdat_callback = usa2x_outdat_callback,
1325 .inack_callback = usa26_inack_callback,
1326 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 }
1328};
1329
1330 /* Generic setup urbs function that uses
1331 data in device_details */
1332static void keyspan_setup_urbs(struct usb_serial *serial)
1333{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 struct keyspan_serial_private *s_priv;
1335 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 struct callbacks *cback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 s_priv = usb_get_serial_data(serial);
1339 d_details = s_priv->device_details;
1340
Alan Coxdeb91682008-07-22 11:13:08 +01001341 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 cback = &keyspan_callbacks[d_details->msg_format];
1343
Alan Coxdeb91682008-07-22 11:13:08 +01001344 /* Allocate and set up urbs for each one that is in use,
1345 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 s_priv->instat_urb = keyspan_setup_urb
1347 (serial, d_details->instat_endpoint, USB_DIR_IN,
1348 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1349 cback->instat_callback);
1350
Lucy McCoy0ca12682007-05-18 12:10:41 -07001351 s_priv->indat_urb = keyspan_setup_urb
1352 (serial, d_details->indat_endpoint, USB_DIR_IN,
1353 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1354 usa49wg_indat_callback);
1355
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 s_priv->glocont_urb = keyspan_setup_urb
1357 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1358 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1359 cback->glocont_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360}
1361
1362/* usa19 function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001363static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1364 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 u8 *rate_low, u8 *prescaler, int portnum)
1366{
1367 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001368 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001371 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Alan Coxdeb91682008-07-22 11:13:08 +01001373 /* prevent divide by zero... */
1374 b16 = baud_rate * 16L;
1375 if (b16 == 0)
1376 return KEYSPAN_INVALID_BAUD_RATE;
1377 /* Any "standard" rate over 57k6 is marginal on the USA-19
1378 as we run out of divisor resolution. */
1379 if (baud_rate > 57600)
1380 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
Alan Coxdeb91682008-07-22 11:13:08 +01001382 /* calculate the divisor and the counter (its inverse) */
1383 div = baudclk / b16;
1384 if (div == 0)
1385 return KEYSPAN_INVALID_BAUD_RATE;
1386 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
Alan Coxdeb91682008-07-22 11:13:08 +01001389 if (div > 0xffff)
1390 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
Alan Coxdeb91682008-07-22 11:13:08 +01001392 /* return the counter values if non-null */
1393 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001395 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001397 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001398 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001399 __func__, baud_rate, *rate_hi, *rate_low);
1400 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401}
1402
1403/* usa19hs function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001404static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1405 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1406 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407{
1408 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001409 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001411 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
Alan Coxdeb91682008-07-22 11:13:08 +01001413 /* prevent divide by zero... */
1414 b16 = baud_rate * 16L;
1415 if (b16 == 0)
1416 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
Alan Coxdeb91682008-07-22 11:13:08 +01001418 /* calculate the divisor */
1419 div = baudclk / b16;
1420 if (div == 0)
1421 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
Alan Coxdeb91682008-07-22 11:13:08 +01001423 if (div > 0xffff)
1424 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
Alan Coxdeb91682008-07-22 11:13:08 +01001426 /* return the counter values if non-null */
1427 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001429
1430 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001432
1433 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001434 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001435 __func__, baud_rate, *rate_hi, *rate_low);
1436
1437 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438}
1439
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001440static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1441 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 u8 *rate_low, u8 *prescaler, int portnum)
1443{
1444 u32 b16, /* baud rate times 16 (actual rate used internally) */
1445 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001446 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 res, /* resulting baud rate using 13/8 prescaler */
1448 diff, /* error using 13/8 prescaler */
1449 smallest_diff;
1450 u8 best_prescaler;
1451 int i;
1452
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001453 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
Alan Coxdeb91682008-07-22 11:13:08 +01001455 /* prevent divide by zero */
1456 b16 = baud_rate * 16L;
1457 if (b16 == 0)
1458 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459
Alan Coxdeb91682008-07-22 11:13:08 +01001460 /* Calculate prescaler by trying them all and looking
1461 for best fit */
1462
1463 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 smallest_diff = 0xffffffff;
1465
1466 /* 0 is an invalid prescaler, used as a flag */
1467 best_prescaler = 0;
1468
Alan Coxdeb91682008-07-22 11:13:08 +01001469 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001471
1472 div = clk / b16;
1473 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
1476 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001477 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
Alan Coxdeb91682008-07-22 11:13:08 +01001479 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 best_prescaler = i;
1481 smallest_diff = diff;
1482 }
1483 }
1484
Alan Coxdeb91682008-07-22 11:13:08 +01001485 if (best_prescaler == 0)
1486 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
1488 clk = (baudclk * 8) / (u32) best_prescaler;
1489 div = clk / b16;
1490
Alan Coxdeb91682008-07-22 11:13:08 +01001491 /* return the divisor and prescaler if non-null */
1492 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001494 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 if (prescaler) {
1497 *prescaler = best_prescaler;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001498 /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 }
Alan Coxdeb91682008-07-22 11:13:08 +01001500 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501}
1502
1503 /* USA-28 supports different maximum baud rates on each port */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001504static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1505 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1506 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507{
1508 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001509 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 cnt; /* inverse of divisor (programmed into 8051) */
1511
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001512 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513
1514 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001515 b16 = baud_rate * 16L;
1516 if (b16 == 0)
1517 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518
Alan Coxdeb91682008-07-22 11:13:08 +01001519 /* calculate the divisor and the counter (its inverse) */
1520 div = KEYSPAN_USA28_BAUDCLK / b16;
1521 if (div == 0)
1522 return KEYSPAN_INVALID_BAUD_RATE;
1523 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525
Alan Coxdeb91682008-07-22 11:13:08 +01001526 /* check for out of range, based on portnum,
1527 and return result */
1528 if (portnum == 0) {
1529 if (div > 0xffff)
1530 return KEYSPAN_INVALID_BAUD_RATE;
1531 } else {
1532 if (portnum == 1) {
1533 if (div > 0xff)
1534 return KEYSPAN_INVALID_BAUD_RATE;
1535 } else
1536 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 }
1538
1539 /* return the counter values if not NULL
1540 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001541 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001543 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001545 dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
Alan Coxdeb91682008-07-22 11:13:08 +01001546 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547}
1548
1549static int keyspan_usa26_send_setup(struct usb_serial *serial,
1550 struct usb_serial_port *port,
1551 int reset_port)
1552{
Alan Coxdeb91682008-07-22 11:13:08 +01001553 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 struct keyspan_serial_private *s_priv;
1555 struct keyspan_port_private *p_priv;
1556 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 struct urb *this_urb;
1558 int device_port, err;
1559
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001560 dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
1562 s_priv = usb_get_serial_data(serial);
1563 p_priv = usb_get_serial_port_data(port);
1564 d_details = s_priv->device_details;
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001565 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 this_urb = p_priv->outcont_urb;
1568
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 /* Make sure we have an urb then send the message */
1570 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001571 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 return -1;
1573 }
1574
Rickard Strandqvistd5afce82014-05-16 17:39:13 +02001575 dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
1576
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001578 Don't overwrite resend for open/close condition. */
1579 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 p_priv->resend_cont = reset_port + 1;
1581 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001582 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001584 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 }
1586
Alan Coxdeb91682008-07-22 11:13:08 +01001587 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1588
1589 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 if (p_priv->old_baud != p_priv->baud) {
1591 p_priv->old_baud = p_priv->baud;
1592 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001593 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1594 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1595 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1596 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1597 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 msg.baudLo = 0;
1599 msg.baudHi = 125; /* Values for 9600 baud */
1600 msg.prescaler = 10;
1601 }
1602 msg.setPrescaler = 0xff;
1603 }
1604
Ben Minerds2b982ab2012-07-12 00:10:16 +10001605 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 switch (p_priv->cflag & CSIZE) {
1607 case CS5:
1608 msg.lcr |= USA_DATABITS_5;
1609 break;
1610 case CS6:
1611 msg.lcr |= USA_DATABITS_6;
1612 break;
1613 case CS7:
1614 msg.lcr |= USA_DATABITS_7;
1615 break;
1616 case CS8:
1617 msg.lcr |= USA_DATABITS_8;
1618 break;
1619 }
1620 if (p_priv->cflag & PARENB) {
1621 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001622 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001623 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 }
1625 msg.setLcr = 0xff;
1626
1627 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1628 msg.xonFlowControl = 0;
1629 msg.setFlowControl = 0xff;
1630 msg.forwardingLength = 16;
1631 msg.xonChar = 17;
1632 msg.xoffChar = 19;
1633
1634 /* Opening port */
1635 if (reset_port == 1) {
1636 msg._txOn = 1;
1637 msg._txOff = 0;
1638 msg.txFlush = 0;
1639 msg.txBreak = 0;
1640 msg.rxOn = 1;
1641 msg.rxOff = 0;
1642 msg.rxFlush = 1;
1643 msg.rxForward = 0;
1644 msg.returnStatus = 0;
1645 msg.resetDataToggle = 0xff;
1646 }
1647
1648 /* Closing port */
1649 else if (reset_port == 2) {
1650 msg._txOn = 0;
1651 msg._txOff = 1;
1652 msg.txFlush = 0;
1653 msg.txBreak = 0;
1654 msg.rxOn = 0;
1655 msg.rxOff = 1;
1656 msg.rxFlush = 1;
1657 msg.rxForward = 0;
1658 msg.returnStatus = 0;
1659 msg.resetDataToggle = 0;
1660 }
1661
1662 /* Sending intermediate configs */
1663 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001664 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 msg._txOff = 0;
1666 msg.txFlush = 0;
1667 msg.txBreak = (p_priv->break_on);
1668 msg.rxOn = 0;
1669 msg.rxOff = 0;
1670 msg.rxFlush = 0;
1671 msg.rxForward = 0;
1672 msg.returnStatus = 0;
1673 msg.resetDataToggle = 0x0;
1674 }
1675
Alan Coxdeb91682008-07-22 11:13:08 +01001676 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 msg.setTxTriState_setRts = 0xff;
1678 msg.txTriState_rts = p_priv->rts_state;
1679
1680 msg.setHskoa_setDtr = 0xff;
1681 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001682
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001684 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 /* send the data out the device on control endpoint */
1687 this_urb->transfer_buffer_length = sizeof(msg);
1688
Alan Coxdeb91682008-07-22 11:13:08 +01001689 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1690 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001691 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01001692 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693}
1694
1695static int keyspan_usa28_send_setup(struct usb_serial *serial,
1696 struct usb_serial_port *port,
1697 int reset_port)
1698{
Alan Coxdeb91682008-07-22 11:13:08 +01001699 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 struct keyspan_serial_private *s_priv;
1701 struct keyspan_port_private *p_priv;
1702 const struct keyspan_device_details *d_details;
1703 struct urb *this_urb;
1704 int device_port, err;
1705
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 s_priv = usb_get_serial_data(serial);
1707 p_priv = usb_get_serial_port_data(port);
1708 d_details = s_priv->device_details;
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001709 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710
1711 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001712 this_urb = p_priv->outcont_urb;
1713 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001714 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 return -1;
1716 }
1717
1718 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001719 Don't overwrite resend for open/close condition. */
1720 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 p_priv->resend_cont = reset_port + 1;
1722 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001723 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001725 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 }
1727
Alan Coxdeb91682008-07-22 11:13:08 +01001728 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
1730 msg.setBaudRate = 1;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001731 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1732 &msg.baudHi, &msg.baudLo, NULL,
1733 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1734 dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001735 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 msg.baudLo = 0xff;
1737 msg.baudHi = 0xb2; /* Values for 9600 baud */
1738 }
1739
1740 /* If parity is enabled, we must calculate it ourselves. */
1741 msg.parity = 0; /* XXX for now */
1742
1743 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1744 msg.xonFlowControl = 0;
1745
Alan Coxdeb91682008-07-22 11:13:08 +01001746 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 msg.rts = p_priv->rts_state;
1748 msg.dtr = p_priv->dtr_state;
1749
1750 msg.forwardingLength = 16;
1751 msg.forwardMs = 10;
1752 msg.breakThreshold = 45;
1753 msg.xonChar = 17;
1754 msg.xoffChar = 19;
1755
1756 /*msg.returnStatus = 1;
1757 msg.resetDataToggle = 0xff;*/
1758 /* Opening port */
1759 if (reset_port == 1) {
1760 msg._txOn = 1;
1761 msg._txOff = 0;
1762 msg.txFlush = 0;
1763 msg.txForceXoff = 0;
1764 msg.txBreak = 0;
1765 msg.rxOn = 1;
1766 msg.rxOff = 0;
1767 msg.rxFlush = 1;
1768 msg.rxForward = 0;
1769 msg.returnStatus = 0;
1770 msg.resetDataToggle = 0xff;
1771 }
1772 /* Closing port */
1773 else if (reset_port == 2) {
1774 msg._txOn = 0;
1775 msg._txOff = 1;
1776 msg.txFlush = 0;
1777 msg.txForceXoff = 0;
1778 msg.txBreak = 0;
1779 msg.rxOn = 0;
1780 msg.rxOff = 1;
1781 msg.rxFlush = 1;
1782 msg.rxForward = 0;
1783 msg.returnStatus = 0;
1784 msg.resetDataToggle = 0;
1785 }
1786 /* Sending intermediate configs */
1787 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001788 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 msg._txOff = 0;
1790 msg.txFlush = 0;
1791 msg.txForceXoff = 0;
1792 msg.txBreak = (p_priv->break_on);
1793 msg.rxOn = 0;
1794 msg.rxOff = 0;
1795 msg.rxFlush = 0;
1796 msg.rxForward = 0;
1797 msg.returnStatus = 0;
1798 msg.resetDataToggle = 0x0;
1799 }
1800
1801 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001802 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
1804 /* send the data out the device on control endpoint */
1805 this_urb->transfer_buffer_length = sizeof(msg);
1806
Alan Coxdeb91682008-07-22 11:13:08 +01001807 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1808 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001809 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810
Alan Coxa5b6f602008-04-08 17:16:06 +01001811 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812}
1813
1814static int keyspan_usa49_send_setup(struct usb_serial *serial,
1815 struct usb_serial_port *port,
1816 int reset_port)
1817{
Lucy McCoy0ca12682007-05-18 12:10:41 -07001818 struct keyspan_usa49_portControlMessage msg;
1819 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 struct keyspan_serial_private *s_priv;
1821 struct keyspan_port_private *p_priv;
1822 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 struct urb *this_urb;
1824 int err, device_port;
1825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 s_priv = usb_get_serial_data(serial);
1827 p_priv = usb_get_serial_port_data(port);
1828 d_details = s_priv->device_details;
1829
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 this_urb = s_priv->glocont_urb;
1831
Lucy McCoy0ca12682007-05-18 12:10:41 -07001832 /* Work out which port within the device is being setup */
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001833 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301835 /* Make sure we have an urb then send the message */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 if (this_urb == NULL) {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001837 dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 return -1;
1839 }
1840
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001841 dev_dbg(&port->dev, "%s - endpoint %d (%d)\n",
1842 __func__, usb_pipeendpoint(this_urb->pipe), device_port);
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301843
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001845 Don't overwrite resend for open/close condition. */
1846 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001848
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001850 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001852 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 }
1854
Alan Coxdeb91682008-07-22 11:13:08 +01001855 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01001858
1859 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 if (p_priv->old_baud != p_priv->baud) {
1861 p_priv->old_baud = p_priv->baud;
1862 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001863 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1864 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1865 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1866 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1867 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 msg.baudLo = 0;
1869 msg.baudHi = 125; /* Values for 9600 baud */
1870 msg.prescaler = 10;
1871 }
Alan Coxdeb91682008-07-22 11:13:08 +01001872 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 }
1874
Ben Minerds2b982ab2012-07-12 00:10:16 +10001875 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 switch (p_priv->cflag & CSIZE) {
1877 case CS5:
1878 msg.lcr |= USA_DATABITS_5;
1879 break;
1880 case CS6:
1881 msg.lcr |= USA_DATABITS_6;
1882 break;
1883 case CS7:
1884 msg.lcr |= USA_DATABITS_7;
1885 break;
1886 case CS8:
1887 msg.lcr |= USA_DATABITS_8;
1888 break;
1889 }
1890 if (p_priv->cflag & PARENB) {
1891 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001892 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001893 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 }
1895 msg.setLcr = 0xff;
1896
1897 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1898 msg.xonFlowControl = 0;
1899 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01001900
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 msg.forwardingLength = 16;
1902 msg.xonChar = 17;
1903 msg.xoffChar = 19;
1904
Alan Coxdeb91682008-07-22 11:13:08 +01001905 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 if (reset_port == 1) {
1907 msg._txOn = 1;
1908 msg._txOff = 0;
1909 msg.txFlush = 0;
1910 msg.txBreak = 0;
1911 msg.rxOn = 1;
1912 msg.rxOff = 0;
1913 msg.rxFlush = 1;
1914 msg.rxForward = 0;
1915 msg.returnStatus = 0;
1916 msg.resetDataToggle = 0xff;
1917 msg.enablePort = 1;
1918 msg.disablePort = 0;
1919 }
1920 /* Closing port */
1921 else if (reset_port == 2) {
1922 msg._txOn = 0;
1923 msg._txOff = 1;
1924 msg.txFlush = 0;
1925 msg.txBreak = 0;
1926 msg.rxOn = 0;
1927 msg.rxOff = 1;
1928 msg.rxFlush = 1;
1929 msg.rxForward = 0;
1930 msg.returnStatus = 0;
1931 msg.resetDataToggle = 0;
1932 msg.enablePort = 0;
1933 msg.disablePort = 1;
1934 }
1935 /* Sending intermediate configs */
1936 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001937 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 msg._txOff = 0;
1939 msg.txFlush = 0;
1940 msg.txBreak = (p_priv->break_on);
1941 msg.rxOn = 0;
1942 msg.rxOff = 0;
1943 msg.rxFlush = 0;
1944 msg.rxForward = 0;
1945 msg.returnStatus = 0;
1946 msg.resetDataToggle = 0x0;
1947 msg.enablePort = 0;
1948 msg.disablePort = 0;
1949 }
1950
Alan Coxdeb91682008-07-22 11:13:08 +01001951 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 msg.setRts = 0xff;
1953 msg.rts = p_priv->rts_state;
1954
1955 msg.setDtr = 0xff;
1956 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001957
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959
Alan Coxdeb91682008-07-22 11:13:08 +01001960 /* if the device is a 49wg, we send control message on usb
1961 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07001962
1963 if (d_details->product_id == keyspan_usa49wg_product_id) {
1964 dr = (void *)(s_priv->ctrl_buf);
1965 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
Mathieu OTHACEHE64248392016-02-04 19:01:30 +01001966 dr->bRequest = 0xB0; /* 49wg control message */
Lucy McCoy0ca12682007-05-18 12:10:41 -07001967 dr->wValue = 0;
1968 dr->wIndex = 0;
1969 dr->wLength = cpu_to_le16(sizeof(msg));
1970
Alan Coxdeb91682008-07-22 11:13:08 +01001971 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07001972
Alan Coxdeb91682008-07-22 11:13:08 +01001973 usb_fill_control_urb(this_urb, serial->dev,
1974 usb_sndctrlpipe(serial->dev, 0),
1975 (unsigned char *)dr, s_priv->glocont_buf,
1976 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001977
1978 } else {
1979 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01001980
Lucy McCoy0ca12682007-05-18 12:10:41 -07001981 /* send the data out the device on control endpoint */
1982 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001983 }
Alan Coxdeb91682008-07-22 11:13:08 +01001984 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1985 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001986 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
Alan Coxa5b6f602008-04-08 17:16:06 +01001988 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989}
1990
1991static int keyspan_usa90_send_setup(struct usb_serial *serial,
1992 struct usb_serial_port *port,
1993 int reset_port)
1994{
Alan Coxdeb91682008-07-22 11:13:08 +01001995 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 struct keyspan_serial_private *s_priv;
1997 struct keyspan_port_private *p_priv;
1998 const struct keyspan_device_details *d_details;
1999 struct urb *this_urb;
2000 int err;
2001 u8 prescaler;
2002
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 s_priv = usb_get_serial_data(serial);
2004 p_priv = usb_get_serial_port_data(port);
2005 d_details = s_priv->device_details;
2006
2007 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002008 this_urb = p_priv->outcont_urb;
2009 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002010 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 return -1;
2012 }
2013
2014 /* Save reset port val for resend.
2015 Don't overwrite resend for open/close condition. */
2016 if ((reset_port + 1) > p_priv->resend_cont)
2017 p_priv->resend_cont = reset_port + 1;
2018 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002019 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002021 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 }
2023
Alan Coxdeb91682008-07-22 11:13:08 +01002024 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025
Alan Coxdeb91682008-07-22 11:13:08 +01002026 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 if (p_priv->old_baud != p_priv->baud) {
2028 p_priv->old_baud = p_priv->baud;
2029 msg.setClocking = 0x01;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002030 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2031 &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2032 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2033 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 p_priv->baud = 9600;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002035 d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2037 }
2038 msg.setRxMode = 1;
2039 msg.setTxMode = 1;
2040 }
2041
2042 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002043 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 msg.rxMode = RXMODE_DMA;
2045 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002046 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 msg.rxMode = RXMODE_BYHAND;
2048 msg.txMode = TXMODE_BYHAND;
2049 }
2050
Ben Minerds2b982ab2012-07-12 00:10:16 +10002051 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 switch (p_priv->cflag & CSIZE) {
2053 case CS5:
2054 msg.lcr |= USA_DATABITS_5;
2055 break;
2056 case CS6:
2057 msg.lcr |= USA_DATABITS_6;
2058 break;
2059 case CS7:
2060 msg.lcr |= USA_DATABITS_7;
2061 break;
2062 case CS8:
2063 msg.lcr |= USA_DATABITS_8;
2064 break;
2065 }
2066 if (p_priv->cflag & PARENB) {
2067 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002068 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002069 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 }
2071 if (p_priv->old_cflag != p_priv->cflag) {
2072 p_priv->old_cflag = p_priv->cflag;
2073 msg.setLcr = 0x01;
2074 }
2075
2076 if (p_priv->flow_control == flow_cts)
2077 msg.txFlowControl = TXFLOW_CTS;
2078 msg.setTxFlowControl = 0x01;
2079 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002080
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002082 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 msg.txAckSetting = 0;
2084 msg.xonChar = 17;
2085 msg.xoffChar = 19;
2086
Alan Coxdeb91682008-07-22 11:13:08 +01002087 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 if (reset_port == 1) {
2089 msg.portEnabled = 1;
2090 msg.rxFlush = 1;
2091 msg.txBreak = (p_priv->break_on);
2092 }
2093 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002094 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 /* Sending intermediate configs */
2097 else {
Alan Stern1f871582010-02-17 10:05:47 -05002098 msg.portEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 msg.txBreak = (p_priv->break_on);
2100 }
2101
Alan Coxdeb91682008-07-22 11:13:08 +01002102 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 msg.setRts = 0x01;
2104 msg.rts = p_priv->rts_state;
2105
2106 msg.setDtr = 0x01;
2107 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002108
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002110 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2111
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 /* send the data out the device on control endpoint */
2113 this_urb->transfer_buffer_length = sizeof(msg);
2114
Alan Coxdeb91682008-07-22 11:13:08 +01002115 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2116 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002117 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002118 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119}
2120
Lucy McCoy0ca12682007-05-18 12:10:41 -07002121static int keyspan_usa67_send_setup(struct usb_serial *serial,
2122 struct usb_serial_port *port,
2123 int reset_port)
2124{
2125 struct keyspan_usa67_portControlMessage msg;
2126 struct keyspan_serial_private *s_priv;
2127 struct keyspan_port_private *p_priv;
2128 const struct keyspan_device_details *d_details;
2129 struct urb *this_urb;
2130 int err, device_port;
2131
Lucy McCoy0ca12682007-05-18 12:10:41 -07002132 s_priv = usb_get_serial_data(serial);
2133 p_priv = usb_get_serial_port_data(port);
2134 d_details = s_priv->device_details;
2135
2136 this_urb = s_priv->glocont_urb;
2137
2138 /* Work out which port within the device is being setup */
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002139 device_port = port->port_number;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002140
2141 /* Make sure we have an urb then send the message */
2142 if (this_urb == NULL) {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002143 dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002144 return -1;
2145 }
2146
2147 /* Save reset port val for resend.
2148 Don't overwrite resend for open/close condition. */
2149 if ((reset_port + 1) > p_priv->resend_cont)
2150 p_priv->resend_cont = reset_port + 1;
2151 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002152 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002153 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002154 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002155 }
2156
2157 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2158
2159 msg.port = device_port;
2160
2161 /* Only set baud rate if it's changed */
2162 if (p_priv->old_baud != p_priv->baud) {
2163 p_priv->old_baud = p_priv->baud;
2164 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002165 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2166 &msg.baudHi, &msg.baudLo, &msg.prescaler,
2167 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2168 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2169 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002170 msg.baudLo = 0;
2171 msg.baudHi = 125; /* Values for 9600 baud */
2172 msg.prescaler = 10;
2173 }
2174 msg.setPrescaler = 0xff;
2175 }
2176
2177 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2178 switch (p_priv->cflag & CSIZE) {
2179 case CS5:
2180 msg.lcr |= USA_DATABITS_5;
2181 break;
2182 case CS6:
2183 msg.lcr |= USA_DATABITS_6;
2184 break;
2185 case CS7:
2186 msg.lcr |= USA_DATABITS_7;
2187 break;
2188 case CS8:
2189 msg.lcr |= USA_DATABITS_8;
2190 break;
2191 }
2192 if (p_priv->cflag & PARENB) {
2193 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002194 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002195 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002196 }
2197 msg.setLcr = 0xff;
2198
2199 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2200 msg.xonFlowControl = 0;
2201 msg.setFlowControl = 0xff;
2202 msg.forwardingLength = 16;
2203 msg.xonChar = 17;
2204 msg.xoffChar = 19;
2205
2206 if (reset_port == 1) {
2207 /* Opening port */
2208 msg._txOn = 1;
2209 msg._txOff = 0;
2210 msg.txFlush = 0;
2211 msg.txBreak = 0;
2212 msg.rxOn = 1;
2213 msg.rxOff = 0;
2214 msg.rxFlush = 1;
2215 msg.rxForward = 0;
2216 msg.returnStatus = 0;
2217 msg.resetDataToggle = 0xff;
2218 } else if (reset_port == 2) {
2219 /* Closing port */
2220 msg._txOn = 0;
2221 msg._txOff = 1;
2222 msg.txFlush = 0;
2223 msg.txBreak = 0;
2224 msg.rxOn = 0;
2225 msg.rxOff = 1;
2226 msg.rxFlush = 1;
2227 msg.rxForward = 0;
2228 msg.returnStatus = 0;
2229 msg.resetDataToggle = 0;
2230 } else {
2231 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002232 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002233 msg._txOff = 0;
2234 msg.txFlush = 0;
2235 msg.txBreak = (p_priv->break_on);
2236 msg.rxOn = 0;
2237 msg.rxOff = 0;
2238 msg.rxFlush = 0;
2239 msg.rxForward = 0;
2240 msg.returnStatus = 0;
2241 msg.resetDataToggle = 0x0;
2242 }
2243
2244 /* Do handshaking outputs */
2245 msg.setTxTriState_setRts = 0xff;
2246 msg.txTriState_rts = p_priv->rts_state;
2247
2248 msg.setHskoa_setDtr = 0xff;
2249 msg.hskoa_dtr = p_priv->dtr_state;
2250
2251 p_priv->resend_cont = 0;
2252
2253 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2254
2255 /* send the data out the device on control endpoint */
2256 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002257
2258 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2259 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002260 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002261 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002262}
2263
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2265{
2266 struct usb_serial *serial = port->serial;
2267 struct keyspan_serial_private *s_priv;
2268 const struct keyspan_device_details *d_details;
2269
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 s_priv = usb_get_serial_data(serial);
2271 d_details = s_priv->device_details;
2272
2273 switch (d_details->msg_format) {
2274 case msg_usa26:
2275 keyspan_usa26_send_setup(serial, port, reset_port);
2276 break;
2277 case msg_usa28:
2278 keyspan_usa28_send_setup(serial, port, reset_port);
2279 break;
2280 case msg_usa49:
2281 keyspan_usa49_send_setup(serial, port, reset_port);
2282 break;
2283 case msg_usa90:
2284 keyspan_usa90_send_setup(serial, port, reset_port);
2285 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002286 case msg_usa67:
2287 keyspan_usa67_send_setup(serial, port, reset_port);
2288 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 }
2290}
2291
2292
2293/* Gets called by the "real" driver (ie once firmware is loaded
2294 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002295static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296{
2297 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 const struct keyspan_device_details *d_details;
2300
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002302 if (d_details->product_id ==
2303 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 break;
2305 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002306 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2307 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Johan Hovoldff8a43c2013-08-13 13:27:35 +02002308 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 }
2310
2311 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002312 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Johan Hovold10c642d2013-12-29 19:22:56 +01002313 if (!s_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
Johan Hovold2fcd1c92013-08-13 13:27:36 +02002316 s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);
2317 if (!s_priv->instat_buf)
2318 goto err_instat_buf;
2319
2320 s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL);
2321 if (!s_priv->indat_buf)
2322 goto err_indat_buf;
2323
2324 s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL);
2325 if (!s_priv->glocont_buf)
2326 goto err_glocont_buf;
2327
2328 s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
2329 if (!s_priv->ctrl_buf)
2330 goto err_ctrl_buf;
2331
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 s_priv->device_details = d_details;
2333 usb_set_serial_data(serial, s_priv);
2334
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 keyspan_setup_urbs(serial);
2336
Lucy McCoy0ca12682007-05-18 12:10:41 -07002337 if (s_priv->instat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002338 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2339 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002340 dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002341 }
2342 if (s_priv->indat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002343 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2344 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002345 dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 }
Alan Coxdeb91682008-07-22 11:13:08 +01002347
Alan Coxa5b6f602008-04-08 17:16:06 +01002348 return 0;
Johan Hovold2fcd1c92013-08-13 13:27:36 +02002349
2350err_ctrl_buf:
2351 kfree(s_priv->glocont_buf);
2352err_glocont_buf:
2353 kfree(s_priv->indat_buf);
2354err_indat_buf:
2355 kfree(s_priv->instat_buf);
2356err_instat_buf:
2357 kfree(s_priv);
2358
2359 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360}
2361
Alan Sternf9c99bb2009-06-02 11:53:55 -04002362static void keyspan_disconnect(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002364 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 s_priv = usb_get_serial_data(serial);
2367
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 stop_urb(s_priv->instat_urb);
2369 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002370 stop_urb(s_priv->indat_urb);
Alan Sternf9c99bb2009-06-02 11:53:55 -04002371}
2372
2373static void keyspan_release(struct usb_serial *serial)
2374{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002375 struct keyspan_serial_private *s_priv;
Alan Sternf9c99bb2009-06-02 11:53:55 -04002376
Alan Sternf9c99bb2009-06-02 11:53:55 -04002377 s_priv = usb_get_serial_data(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002379 usb_free_urb(s_priv->instat_urb);
2380 usb_free_urb(s_priv->indat_urb);
2381 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
Johan Hovold2fcd1c92013-08-13 13:27:36 +02002383 kfree(s_priv->ctrl_buf);
2384 kfree(s_priv->glocont_buf);
2385 kfree(s_priv->indat_buf);
2386 kfree(s_priv->instat_buf);
2387
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002388 kfree(s_priv);
2389}
2390
2391static int keyspan_port_probe(struct usb_serial_port *port)
2392{
2393 struct usb_serial *serial = port->serial;
Bjørn Morkf0e3e352012-11-10 10:13:42 +01002394 struct keyspan_serial_private *s_priv;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002395 struct keyspan_port_private *p_priv;
2396 const struct keyspan_device_details *d_details;
2397 struct callbacks *cback;
2398 int endp;
2399 int port_num;
2400 int i;
2401
2402 s_priv = usb_get_serial_data(serial);
2403 d_details = s_priv->device_details;
2404
2405 p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL);
2406 if (!p_priv)
2407 return -ENOMEM;
2408
Johan Hovoldbad41a52013-08-13 13:27:37 +02002409 for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
2410 p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
2411 if (!p_priv->in_buffer[i])
2412 goto err_in_buffer;
2413 }
2414
2415 for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
2416 p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
2417 if (!p_priv->out_buffer[i])
2418 goto err_out_buffer;
2419 }
2420
2421 p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
2422 if (!p_priv->inack_buffer)
2423 goto err_inack_buffer;
2424
2425 p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
2426 if (!p_priv->outcont_buffer)
2427 goto err_outcont_buffer;
2428
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002429 p_priv->device_details = d_details;
2430
2431 /* Setup values for the various callback routines */
2432 cback = &keyspan_callbacks[d_details->msg_format];
2433
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002434 port_num = port->port_number;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002435
2436 /* Do indat endpoints first, once for each flip */
2437 endp = d_details->indat_endpoints[port_num];
2438 for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
2439 p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
2440 USB_DIR_IN, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002441 p_priv->in_buffer[i],
2442 IN_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002443 cback->indat_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 }
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002445 /* outdat endpoints also have flip */
2446 endp = d_details->outdat_endpoints[port_num];
2447 for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
2448 p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
2449 USB_DIR_OUT, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002450 p_priv->out_buffer[i],
2451 OUT_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002452 cback->outdat_callback);
2453 }
2454 /* inack endpoint */
2455 p_priv->inack_urb = keyspan_setup_urb(serial,
2456 d_details->inack_endpoints[port_num],
2457 USB_DIR_IN, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002458 p_priv->inack_buffer,
2459 INACK_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002460 cback->inack_callback);
2461 /* outcont endpoint */
2462 p_priv->outcont_urb = keyspan_setup_urb(serial,
2463 d_details->outcont_endpoints[port_num],
2464 USB_DIR_OUT, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002465 p_priv->outcont_buffer,
2466 OUTCONT_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002467 cback->outcont_callback);
2468
2469 usb_set_serial_port_data(port, p_priv);
2470
2471 return 0;
Johan Hovoldbad41a52013-08-13 13:27:37 +02002472
2473err_outcont_buffer:
2474 kfree(p_priv->inack_buffer);
2475err_inack_buffer:
2476 for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
2477 kfree(p_priv->out_buffer[i]);
2478err_out_buffer:
2479 for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
2480 kfree(p_priv->in_buffer[i]);
2481err_in_buffer:
2482 kfree(p_priv);
2483
2484 return -ENOMEM;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002485}
2486
2487static int keyspan_port_remove(struct usb_serial_port *port)
2488{
2489 struct keyspan_port_private *p_priv;
2490 int i;
2491
2492 p_priv = usb_get_serial_port_data(port);
2493
2494 stop_urb(p_priv->inack_urb);
2495 stop_urb(p_priv->outcont_urb);
2496 for (i = 0; i < 2; i++) {
2497 stop_urb(p_priv->in_urbs[i]);
2498 stop_urb(p_priv->out_urbs[i]);
2499 }
2500
2501 usb_free_urb(p_priv->inack_urb);
2502 usb_free_urb(p_priv->outcont_urb);
2503 for (i = 0; i < 2; i++) {
2504 usb_free_urb(p_priv->in_urbs[i]);
2505 usb_free_urb(p_priv->out_urbs[i]);
2506 }
2507
Johan Hovoldbad41a52013-08-13 13:27:37 +02002508 kfree(p_priv->outcont_buffer);
2509 kfree(p_priv->inack_buffer);
2510 for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
2511 kfree(p_priv->out_buffer[i]);
2512 for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
2513 kfree(p_priv->in_buffer[i]);
2514
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002515 kfree(p_priv);
2516
2517 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518}
2519
Alan Coxdeb91682008-07-22 11:13:08 +01002520MODULE_AUTHOR(DRIVER_AUTHOR);
2521MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522MODULE_LICENSE("GPL");
2523
David Woodhouse2971c572008-05-30 14:04:03 +03002524MODULE_FIRMWARE("keyspan/usa28.fw");
2525MODULE_FIRMWARE("keyspan/usa28x.fw");
2526MODULE_FIRMWARE("keyspan/usa28xa.fw");
2527MODULE_FIRMWARE("keyspan/usa28xb.fw");
2528MODULE_FIRMWARE("keyspan/usa19.fw");
2529MODULE_FIRMWARE("keyspan/usa19qi.fw");
2530MODULE_FIRMWARE("keyspan/mpr.fw");
2531MODULE_FIRMWARE("keyspan/usa19qw.fw");
2532MODULE_FIRMWARE("keyspan/usa18x.fw");
2533MODULE_FIRMWARE("keyspan/usa19w.fw");
2534MODULE_FIRMWARE("keyspan/usa49w.fw");
2535MODULE_FIRMWARE("keyspan/usa49wlc.fw");