blob: 077c714f1285171ee3b9e4c418e0df42f60cd42c [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);
Alan Coxdeb91682008-07-22 11:13:08 +0100413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 /* Update handshaking pin state information */
415 old_dcd_state = p_priv->dcd_state;
416 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
417 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
418 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
419 p_priv->ri_state = ((msg->ri) ? 1 : 0);
420
Jiri Slabyaa27a092013-03-07 13:12:30 +0100421 if (old_dcd_state != p_priv->dcd_state)
422 tty_port_tty_hangup(&port->port, true);
Alan Coxdeb91682008-07-22 11:13:08 +0100423
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100425 err = usb_submit_urb(urb, GFP_ATOMIC);
426 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700427 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428exit: ;
429}
430
David Howells7d12e782006-10-05 14:55:46 +0100431static void usa26_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433}
434
435
David Howells7d12e782006-10-05 14:55:46 +0100436static void usa28_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
Alan Coxf035a8a2008-07-22 11:13:32 +0100438 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 struct usb_serial_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 unsigned char *data;
441 struct keyspan_port_private *p_priv;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700442 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
Ming Leicdc97792008-02-24 18:41:47 +0800444 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 p_priv = usb_get_serial_port_data(port);
446 data = urb->transfer_buffer;
447
448 if (urb != p_priv->in_urbs[p_priv->in_flip])
449 return;
450
451 do {
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700452 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700453 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
454 __func__, status, usb_pipeendpoint(urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 return;
456 }
457
Ming Leicdc97792008-02-24 18:41:47 +0800458 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 p_priv = usb_get_serial_port_data(port);
460 data = urb->transfer_buffer;
461
Jiri Slaby2e124b42013-01-03 15:53:06 +0100462 if (urb->actual_length) {
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100463 tty_insert_flip_string(&port->port, data,
464 urb->actual_length);
Jiri Slaby2e124b42013-01-03 15:53:06 +0100465 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 }
467
468 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500469 err = usb_submit_urb(urb, GFP_ATOMIC);
470 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700471 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
Alan Stern1f871582010-02-17 10:05:47 -0500472 __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 p_priv->in_flip ^= 1;
474
475 urb = p_priv->in_urbs[p_priv->in_flip];
476 } while (urb->status != -EINPROGRESS);
477}
478
David Howells7d12e782006-10-05 14:55:46 +0100479static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481}
482
David Howells7d12e782006-10-05 14:55:46 +0100483static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
485 struct usb_serial_port *port;
486 struct keyspan_port_private *p_priv;
487
Ming Leicdc97792008-02-24 18:41:47 +0800488 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 p_priv = usb_get_serial_port_data(port);
490
491 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700492 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100493 keyspan_usa28_send_setup(port->serial, port,
494 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 }
496}
497
David Howells7d12e782006-10-05 14:55:46 +0100498static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
500 int err;
501 unsigned char *data = urb->transfer_buffer;
502 struct keyspan_usa28_portStatusMessage *msg;
503 struct usb_serial *serial;
504 struct usb_serial_port *port;
505 struct keyspan_port_private *p_priv;
506 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700507 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Ming Leicdc97792008-02-24 18:41:47 +0800509 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700511 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700512 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 return;
514 }
515
516 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700517 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 goto exit;
519 }
520
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 msg = (struct keyspan_usa28_portStatusMessage *)data;
522
Alan Coxdeb91682008-07-22 11:13:08 +0100523 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700525 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 goto exit;
527 }
528 port = serial->port[msg->port];
529 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100530
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 /* Update handshaking pin state information */
532 old_dcd_state = p_priv->dcd_state;
533 p_priv->cts_state = ((msg->cts) ? 1 : 0);
534 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
535 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
536 p_priv->ri_state = ((msg->ri) ? 1 : 0);
537
Jiri Slabyaa27a092013-03-07 13:12:30 +0100538 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
539 tty_port_tty_hangup(&port->port, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
541 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100542 err = usb_submit_urb(urb, GFP_ATOMIC);
543 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700544 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545exit: ;
546}
547
David Howells7d12e782006-10-05 14:55:46 +0100548static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550}
551
552
David Howells7d12e782006-10-05 14:55:46 +0100553static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
555 struct usb_serial *serial;
556 struct usb_serial_port *port;
557 struct keyspan_port_private *p_priv;
558 int i;
559
Ming Leicdc97792008-02-24 18:41:47 +0800560 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 for (i = 0; i < serial->num_ports; ++i) {
562 port = serial->port[i];
563 p_priv = usb_get_serial_port_data(port);
564
565 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700566 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100567 keyspan_usa49_send_setup(serial, port,
568 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 break;
570 }
571 }
572}
573
574 /* This is actually called glostat in the Keyspan
575 doco */
David Howells7d12e782006-10-05 14:55:46 +0100576static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
578 int err;
579 unsigned char *data = urb->transfer_buffer;
580 struct keyspan_usa49_portStatusMessage *msg;
581 struct usb_serial *serial;
582 struct usb_serial_port *port;
583 struct keyspan_port_private *p_priv;
584 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700585 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Ming Leicdc97792008-02-24 18:41:47 +0800587 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700589 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700590 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 return;
592 }
593
Alan Coxdeb91682008-07-22 11:13:08 +0100594 if (urb->actual_length !=
595 sizeof(struct keyspan_usa49_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700596 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 goto exit;
598 }
599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 msg = (struct keyspan_usa49_portStatusMessage *)data;
601
Alan Coxdeb91682008-07-22 11:13:08 +0100602 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 if (msg->portNumber >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700604 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
605 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 goto exit;
607 }
608 port = serial->port[msg->portNumber];
609 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 /* Update handshaking pin state information */
612 old_dcd_state = p_priv->dcd_state;
613 p_priv->cts_state = ((msg->cts) ? 1 : 0);
614 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
615 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
616 p_priv->ri_state = ((msg->ri) ? 1 : 0);
617
Jiri Slabyaa27a092013-03-07 13:12:30 +0100618 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
619 tty_port_tty_hangup(&port->port, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
Alan Coxdeb91682008-07-22 11:13:08 +0100621 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100622 err = usb_submit_urb(urb, GFP_ATOMIC);
623 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700624 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625exit: ;
626}
627
David Howells7d12e782006-10-05 14:55:46 +0100628static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630}
631
David Howells7d12e782006-10-05 14:55:46 +0100632static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
634 int i, err;
635 int endpoint;
636 struct usb_serial_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700638 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 endpoint = usb_pipeendpoint(urb->pipe);
641
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700642 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700643 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
644 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 return;
646 }
647
Ming Leicdc97792008-02-24 18:41:47 +0800648 port = urb->context;
Jiri Slaby2e124b42013-01-03 15:53:06 +0100649 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 /* 0x80 bit is error flag */
651 if ((data[0] & 0x80) == 0) {
652 /* no error on any byte */
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100653 tty_insert_flip_string(&port->port, data + 1,
Alan Coxf035a8a2008-07-22 11:13:32 +0100654 urb->actual_length - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 } else {
656 /* some bytes had errors, every byte has status */
657 for (i = 0; i + 1 < urb->actual_length; i += 2) {
Johan Hovold5d1678a2014-11-18 11:25:19 +0100658 int stat = data[i];
659 int flag = TTY_NORMAL;
660
661 if (stat & RXERROR_OVERRUN) {
662 tty_insert_flip_char(&port->port, 0,
663 TTY_OVERRUN);
664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 /* XXX should handle break (0x10) */
Johan Hovold5d1678a2014-11-18 11:25:19 +0100666 if (stat & RXERROR_PARITY)
667 flag = TTY_PARITY;
668 else if (stat & RXERROR_FRAMING)
669 flag = TTY_FRAME;
670
Jiri Slaby92a19f92013-01-03 15:53:03 +0100671 tty_insert_flip_char(&port->port, data[i+1],
672 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 }
674 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100675 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 }
Alan Coxdeb91682008-07-22 11:13:08 +0100677
678 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500679 err = usb_submit_urb(urb, GFP_ATOMIC);
680 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700681 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682}
683
Lucy McCoy0ca12682007-05-18 12:10:41 -0700684static void usa49wg_indat_callback(struct urb *urb)
685{
686 int i, len, x, err;
687 struct usb_serial *serial;
688 struct usb_serial_port *port;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700689 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700690 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700691
Lucy McCoy0ca12682007-05-18 12:10:41 -0700692 serial = urb->context;
693
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700694 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700695 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700696 return;
697 }
698
699 /* inbound data is in the form P#, len, status, data */
700 i = 0;
701 len = 0;
702
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300703 while (i < urb->actual_length) {
Lucy McCoy0ca12682007-05-18 12:10:41 -0700704
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300705 /* Check port number from message */
706 if (data[i] >= serial->num_ports) {
707 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
708 __func__, data[i]);
709 return;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700710 }
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300711 port = serial->port[data[i++]];
712 len = data[i++];
713
714 /* 0x80 bit is error flag */
715 if ((data[i] & 0x80) == 0) {
716 /* no error on any byte */
717 i++;
Dan Carpenter01a60e72013-04-05 08:43:20 +0300718 for (x = 1; x < len && i < urb->actual_length; ++x)
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300719 tty_insert_flip_char(&port->port,
720 data[i++], 0);
721 } else {
722 /*
723 * some bytes had errors, every byte has status
724 */
Dan Carpenter01a60e72013-04-05 08:43:20 +0300725 for (x = 0; x + 1 < len &&
726 i + 1 < urb->actual_length; x += 2) {
Johan Hovold5d1678a2014-11-18 11:25:19 +0100727 int stat = data[i];
728 int flag = TTY_NORMAL;
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300729
Johan Hovold5d1678a2014-11-18 11:25:19 +0100730 if (stat & RXERROR_OVERRUN) {
731 tty_insert_flip_char(&port->port, 0,
732 TTY_OVERRUN);
733 }
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300734 /* XXX should handle break (0x10) */
Johan Hovold5d1678a2014-11-18 11:25:19 +0100735 if (stat & RXERROR_PARITY)
736 flag = TTY_PARITY;
737 else if (stat & RXERROR_FRAMING)
738 flag = TTY_FRAME;
739
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300740 tty_insert_flip_char(&port->port, data[i+1],
741 flag);
742 i += 2;
743 }
744 }
745 tty_flip_buffer_push(&port->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700746 }
747
748 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700749 err = usb_submit_urb(urb, GFP_ATOMIC);
750 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700751 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700752}
753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700755static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757}
758
Lucy McCoy0ca12682007-05-18 12:10:41 -0700759static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
761 int i, err;
762 int endpoint;
763 struct usb_serial_port *port;
764 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700766 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 endpoint = usb_pipeendpoint(urb->pipe);
769
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700770 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700771 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800772 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 return;
774 }
775
Ming Leicdc97792008-02-24 18:41:47 +0800776 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 p_priv = usb_get_serial_port_data(port);
778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100781 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Alan Coxf035a8a2008-07-22 11:13:32 +0100783 if (p_priv->baud > 57600)
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100784 tty_insert_flip_string(&port->port, data,
785 urb->actual_length);
Alan Coxf035a8a2008-07-22 11:13:32 +0100786 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 /* 0x80 bit is error flag */
788 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100789 /* no errors on individual bytes, only
790 possible overrun err*/
Johan Hovold855515a2014-11-18 11:25:20 +0100791 if (data[0] & RXERROR_OVERRUN) {
792 tty_insert_flip_char(&port->port, 0,
793 TTY_OVERRUN);
794 }
Alan Coxdeb91682008-07-22 11:13:08 +0100795 for (i = 1; i < urb->actual_length ; ++i)
Jiri Slaby92a19f92013-01-03 15:53:03 +0100796 tty_insert_flip_char(&port->port,
Johan Hovold855515a2014-11-18 11:25:20 +0100797 data[i], TTY_NORMAL);
Alan Coxdeb91682008-07-22 11:13:08 +0100798 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700800 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 for (i = 0; i + 1 < urb->actual_length; i += 2) {
Johan Hovold5d1678a2014-11-18 11:25:19 +0100802 int stat = data[i];
803 int flag = TTY_NORMAL;
804
805 if (stat & RXERROR_OVERRUN) {
806 tty_insert_flip_char(
807 &port->port, 0,
808 TTY_OVERRUN);
809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 /* XXX should handle break (0x10) */
Johan Hovold5d1678a2014-11-18 11:25:19 +0100811 if (stat & RXERROR_PARITY)
812 flag = TTY_PARITY;
813 else if (stat & RXERROR_FRAMING)
814 flag = TTY_FRAME;
815
Jiri Slaby92a19f92013-01-03 15:53:03 +0100816 tty_insert_flip_char(&port->port,
817 data[i+1], flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
819 }
820 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100821 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
Alan Coxdeb91682008-07-22 11:13:08 +0100823
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500825 err = usb_submit_urb(urb, GFP_ATOMIC);
826 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700827 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828}
829
830
David Howells7d12e782006-10-05 14:55:46 +0100831static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832{
833 unsigned char *data = urb->transfer_buffer;
834 struct keyspan_usa90_portStatusMessage *msg;
835 struct usb_serial *serial;
836 struct usb_serial_port *port;
837 struct keyspan_port_private *p_priv;
838 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700839 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Ming Leicdc97792008-02-24 18:41:47 +0800841 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700843 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700844 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 return;
846 }
847 if (urb->actual_length < 14) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700848 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 goto exit;
850 }
851
852 msg = (struct keyspan_usa90_portStatusMessage *)data;
853
854 /* Now do something useful with the data */
855
856 port = serial->port[0];
857 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100858
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 /* Update handshaking pin state information */
860 old_dcd_state = p_priv->dcd_state;
861 p_priv->cts_state = ((msg->cts) ? 1 : 0);
862 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
863 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
864 p_priv->ri_state = ((msg->ri) ? 1 : 0);
865
Jiri Slabyaa27a092013-03-07 13:12:30 +0100866 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
867 tty_port_tty_hangup(&port->port, true);
Alan Coxdeb91682008-07-22 11:13:08 +0100868
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100870 err = usb_submit_urb(urb, GFP_ATOMIC);
871 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700872 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873exit:
874 ;
875}
876
David Howells7d12e782006-10-05 14:55:46 +0100877static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878{
879 struct usb_serial_port *port;
880 struct keyspan_port_private *p_priv;
881
Ming Leicdc97792008-02-24 18:41:47 +0800882 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 p_priv = usb_get_serial_port_data(port);
884
885 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700886 dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100887 keyspan_usa90_send_setup(port->serial, port,
888 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 }
890}
891
Lucy McCoy0ca12682007-05-18 12:10:41 -0700892/* Status messages from the 28xg */
893static void usa67_instat_callback(struct urb *urb)
894{
895 int err;
896 unsigned char *data = urb->transfer_buffer;
897 struct keyspan_usa67_portStatusMessage *msg;
898 struct usb_serial *serial;
899 struct usb_serial_port *port;
900 struct keyspan_port_private *p_priv;
901 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700902 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700903
Lucy McCoy0ca12682007-05-18 12:10:41 -0700904 serial = urb->context;
905
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700906 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700907 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700908 return;
909 }
910
Alan Coxdeb91682008-07-22 11:13:08 +0100911 if (urb->actual_length !=
912 sizeof(struct keyspan_usa67_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700913 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700914 return;
915 }
916
917
918 /* Now do something useful with the data */
919 msg = (struct keyspan_usa67_portStatusMessage *)data;
920
921 /* Check port number from message and retrieve private data */
922 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700923 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700924 return;
925 }
926
927 port = serial->port[msg->port];
928 p_priv = usb_get_serial_port_data(port);
929
930 /* Update handshaking pin state information */
931 old_dcd_state = p_priv->dcd_state;
932 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
933 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
934
Jiri Slabyaa27a092013-03-07 13:12:30 +0100935 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
936 tty_port_tty_hangup(&port->port, true);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700937
938 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700939 err = usb_submit_urb(urb, GFP_ATOMIC);
940 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700941 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700942}
943
944static void usa67_glocont_callback(struct urb *urb)
945{
946 struct usb_serial *serial;
947 struct usb_serial_port *port;
948 struct keyspan_port_private *p_priv;
949 int i;
950
Lucy McCoy0ca12682007-05-18 12:10:41 -0700951 serial = urb->context;
952 for (i = 0; i < serial->num_ports; ++i) {
953 port = serial->port[i];
954 p_priv = usb_get_serial_port_data(port);
955
956 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700957 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700958 keyspan_usa67_send_setup(serial, port,
959 p_priv->resend_cont - 1);
960 break;
961 }
962 }
963}
964
Alan Cox95da3102008-07-22 11:09:07 +0100965static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966{
Alan Cox95da3102008-07-22 11:09:07 +0100967 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 struct keyspan_port_private *p_priv;
969 const struct keyspan_device_details *d_details;
970 int flip;
971 int data_len;
972 struct urb *this_urb;
973
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 p_priv = usb_get_serial_port_data(port);
975 d_details = p_priv->device_details;
976
Alan Coxa5b6f602008-04-08 17:16:06 +0100977 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +0100979 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 else
981 data_len = 63;
982
983 flip = p_priv->out_flip;
984
985 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +0100986 this_urb = p_priv->out_urbs[flip];
987 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +0100989 return data_len;
990 flip = (flip + 1) & d_details->outdat_endp_flip;
991 this_urb = p_priv->out_urbs[flip];
992 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +0100994 return data_len;
995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 }
Alan Coxa5b6f602008-04-08 17:16:06 +0100997 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998}
999
1000
Alan Coxa509a7e2009-09-19 13:13:26 -07001001static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001003 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 const struct keyspan_device_details *d_details;
1005 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001006 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001008 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 p_priv = usb_get_serial_port_data(port);
1011 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001012
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 /* Set some sane defaults */
1014 p_priv->rts_state = 1;
1015 p_priv->dtr_state = 1;
1016 p_priv->baud = 9600;
1017
1018 /* force baud and lcr to be set on open */
1019 p_priv->old_baud = 0;
1020 p_priv->old_cflag = 0;
1021
1022 p_priv->out_flip = 0;
1023 p_priv->in_flip = 0;
1024
1025 /* Reset low level data toggle and start reading from endpoints */
1026 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001027 urb = p_priv->in_urbs[i];
1028 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
Alan Coxdeb91682008-07-22 11:13:08 +01001031 /* make sure endpoint data toggle is synchronized
1032 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001034 err = usb_submit_urb(urb, GFP_KERNEL);
1035 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001036 dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 }
1038
1039 /* Reset low level data toggle on out endpoints */
1040 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001041 urb = p_priv->out_urbs[i];
1042 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 continue;
Alan Coxdeb91682008-07-22 11:13:08 +01001044 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1045 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 }
1047
Andrew Mortonf78ba152007-11-28 16:21:54 -08001048 /* get the terminal config for the setup message now so we don't
1049 * need to send 2 of them */
1050
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001051 device_port = port->port_number;
Alan Cox95da3102008-07-22 11:09:07 +01001052 if (tty) {
Alan Coxadc8d742012-07-14 15:31:47 +01001053 cflag = tty->termios.c_cflag;
Alan Cox95da3102008-07-22 11:09:07 +01001054 /* Baud rate calculation takes baud rate as an integer
1055 so other rates can be generated if desired. */
1056 baud_rate = tty_get_baud_rate(tty);
1057 /* If no match or invalid, leave as default */
1058 if (baud_rate >= 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001059 && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Alan Cox95da3102008-07-22 11:09:07 +01001060 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1061 p_priv->baud = baud_rate;
1062 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001063 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001064 /* set CTS/RTS handshake etc. */
1065 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +10001066 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001067
1068 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001069 /* mdelay(100); */
1070 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001071
Alan Coxa5b6f602008-04-08 17:16:06 +01001072 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073}
1074
1075static inline void stop_urb(struct urb *urb)
1076{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001077 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079}
1080
Alan Cox335f8512009-06-11 12:26:29 +01001081static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1082{
1083 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1084
1085 p_priv->rts_state = on;
1086 p_priv->dtr_state = on;
1087 keyspan_send_setup(port, 0);
1088}
1089
1090static void keyspan_close(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091{
1092 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 struct keyspan_port_private *p_priv;
1094
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001096
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 p_priv->rts_state = 0;
1098 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001099
Johan Hovold80dfe0c2013-03-21 12:36:32 +01001100 keyspan_send_setup(port, 2);
1101 /* pilot-xfer seems to work best with this delay */
1102 mdelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104 p_priv->out_flip = 0;
1105 p_priv->in_flip = 0;
1106
Johan Hovold80dfe0c2013-03-21 12:36:32 +01001107 stop_urb(p_priv->inack_urb);
1108 for (i = 0; i < 2; i++) {
1109 stop_urb(p_priv->in_urbs[i]);
1110 stop_urb(p_priv->out_urbs[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112}
1113
Alan Coxdeb91682008-07-22 11:13:08 +01001114/* download the firmware to a pre-renumeration device */
1115static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116{
Rene Buergel8d733e22012-09-18 09:02:01 +02001117 char *fw_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001119 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
1120 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1121 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001122
1123 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1124 != 0x8000) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001125 dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n");
Alan Coxdeb91682008-07-22 11:13:08 +01001126 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 }
1128
1129 /* Select firmware image on the basis of idProduct */
1130 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1131 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001132 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 break;
1134
1135 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001136 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 break;
1138
1139 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001140 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 break;
1142
1143 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001144 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 break;
1146
1147 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001148 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001152 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001154
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001156 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 break;
1158
1159 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001160 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001162
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001164 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001166
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001168 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001170
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001172 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 break;
1174
1175 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001176 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 break;
1178
1179 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001180 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1181 le16_to_cpu(serial->dev->descriptor.idProduct));
1182 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 }
1184
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001185 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
Rene Buergel8d733e22012-09-18 09:02:01 +02001187 if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
1188 dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
1189 fw_name);
1190 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 }
1192
Rene Buergel8d733e22012-09-18 09:02:01 +02001193 /* after downloading firmware Renumeration will occur in a
1194 moment and the new device will bind to the real driver */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195
1196 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001197 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198}
1199
1200/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001201static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1202 int endpoint)
1203{
1204 struct usb_host_interface *iface_desc;
1205 struct usb_endpoint_descriptor *ep;
1206 int i;
1207
1208 iface_desc = serial->interface->cur_altsetting;
1209 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1210 ep = &iface_desc->endpoint[i].desc;
1211 if (ep->bEndpointAddress == endpoint)
1212 return ep;
1213 }
1214 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1215 "endpoint %x\n", endpoint);
1216 return NULL;
1217}
1218
Alan Coxdeb91682008-07-22 11:13:08 +01001219static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001221 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222{
1223 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001224 struct usb_endpoint_descriptor const *ep_desc;
1225 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227 if (endpoint == -1)
1228 return NULL; /* endpoint not needed */
1229
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001230 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
Johan Hovold10c642d2013-12-29 19:22:56 +01001232 if (!urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Lucy McCoy0ca12682007-05-18 12:10:41 -07001235 if (endpoint == 0) {
1236 /* control EP filled in when used */
1237 return urb;
1238 }
1239
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001240 ep_desc = find_ep(serial, endpoint);
1241 if (!ep_desc) {
1242 /* leak the urb, something's wrong and the callers don't care */
1243 return urb;
1244 }
1245 if (usb_endpoint_xfer_int(ep_desc)) {
1246 ep_type_name = "INT";
1247 usb_fill_int_urb(urb, serial->dev,
1248 usb_sndintpipe(serial->dev, endpoint) | dir,
1249 buf, len, callback, ctx,
1250 ep_desc->bInterval);
1251 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1252 ep_type_name = "BULK";
1253 usb_fill_bulk_urb(urb, serial->dev,
1254 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1255 buf, len, callback, ctx);
1256 } else {
1257 dev_warn(&serial->interface->dev,
1258 "unsupported endpoint type %x\n",
Julia Lawall2e0fe702008-12-29 11:22:14 +01001259 usb_endpoint_type(ep_desc));
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001260 usb_free_urb(urb);
1261 return NULL;
1262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001264 dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001265 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 return urb;
1267}
1268
1269static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001270 void (*instat_callback)(struct urb *);
1271 void (*glocont_callback)(struct urb *);
1272 void (*indat_callback)(struct urb *);
1273 void (*outdat_callback)(struct urb *);
1274 void (*inack_callback)(struct urb *);
1275 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276} keyspan_callbacks[] = {
1277 {
1278 /* msg_usa26 callbacks */
1279 .instat_callback = usa26_instat_callback,
1280 .glocont_callback = usa26_glocont_callback,
1281 .indat_callback = usa26_indat_callback,
1282 .outdat_callback = usa2x_outdat_callback,
1283 .inack_callback = usa26_inack_callback,
1284 .outcont_callback = usa26_outcont_callback,
1285 }, {
1286 /* msg_usa28 callbacks */
1287 .instat_callback = usa28_instat_callback,
1288 .glocont_callback = usa28_glocont_callback,
1289 .indat_callback = usa28_indat_callback,
1290 .outdat_callback = usa2x_outdat_callback,
1291 .inack_callback = usa28_inack_callback,
1292 .outcont_callback = usa28_outcont_callback,
1293 }, {
1294 /* msg_usa49 callbacks */
1295 .instat_callback = usa49_instat_callback,
1296 .glocont_callback = usa49_glocont_callback,
1297 .indat_callback = usa49_indat_callback,
1298 .outdat_callback = usa2x_outdat_callback,
1299 .inack_callback = usa49_inack_callback,
1300 .outcont_callback = usa49_outcont_callback,
1301 }, {
1302 /* msg_usa90 callbacks */
1303 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001304 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 .indat_callback = usa90_indat_callback,
1306 .outdat_callback = usa2x_outdat_callback,
1307 .inack_callback = usa28_inack_callback,
1308 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001309 }, {
1310 /* msg_usa67 callbacks */
1311 .instat_callback = usa67_instat_callback,
1312 .glocont_callback = usa67_glocont_callback,
1313 .indat_callback = usa26_indat_callback,
1314 .outdat_callback = usa2x_outdat_callback,
1315 .inack_callback = usa26_inack_callback,
1316 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 }
1318};
1319
1320 /* Generic setup urbs function that uses
1321 data in device_details */
1322static void keyspan_setup_urbs(struct usb_serial *serial)
1323{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 struct keyspan_serial_private *s_priv;
1325 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 struct callbacks *cback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 s_priv = usb_get_serial_data(serial);
1329 d_details = s_priv->device_details;
1330
Alan Coxdeb91682008-07-22 11:13:08 +01001331 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 cback = &keyspan_callbacks[d_details->msg_format];
1333
Alan Coxdeb91682008-07-22 11:13:08 +01001334 /* Allocate and set up urbs for each one that is in use,
1335 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 s_priv->instat_urb = keyspan_setup_urb
1337 (serial, d_details->instat_endpoint, USB_DIR_IN,
1338 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1339 cback->instat_callback);
1340
Lucy McCoy0ca12682007-05-18 12:10:41 -07001341 s_priv->indat_urb = keyspan_setup_urb
1342 (serial, d_details->indat_endpoint, USB_DIR_IN,
1343 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1344 usa49wg_indat_callback);
1345
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 s_priv->glocont_urb = keyspan_setup_urb
1347 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1348 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1349 cback->glocont_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350}
1351
1352/* usa19 function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001353static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1354 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 u8 *rate_low, u8 *prescaler, int portnum)
1356{
1357 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001358 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001361 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
Alan Coxdeb91682008-07-22 11:13:08 +01001363 /* prevent divide by zero... */
1364 b16 = baud_rate * 16L;
1365 if (b16 == 0)
1366 return KEYSPAN_INVALID_BAUD_RATE;
1367 /* Any "standard" rate over 57k6 is marginal on the USA-19
1368 as we run out of divisor resolution. */
1369 if (baud_rate > 57600)
1370 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Alan Coxdeb91682008-07-22 11:13:08 +01001372 /* calculate the divisor and the counter (its inverse) */
1373 div = baudclk / b16;
1374 if (div == 0)
1375 return KEYSPAN_INVALID_BAUD_RATE;
1376 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
Alan Coxdeb91682008-07-22 11:13:08 +01001379 if (div > 0xffff)
1380 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
Alan Coxdeb91682008-07-22 11:13:08 +01001382 /* return the counter values if non-null */
1383 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001385 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001387 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001388 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001389 __func__, baud_rate, *rate_hi, *rate_low);
1390 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391}
1392
1393/* usa19hs function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001394static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1395 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1396 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397{
1398 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001399 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001401 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Alan Coxdeb91682008-07-22 11:13:08 +01001403 /* prevent divide by zero... */
1404 b16 = baud_rate * 16L;
1405 if (b16 == 0)
1406 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
Alan Coxdeb91682008-07-22 11:13:08 +01001408 /* calculate the divisor */
1409 div = baudclk / b16;
1410 if (div == 0)
1411 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
Alan Coxdeb91682008-07-22 11:13:08 +01001413 if (div > 0xffff)
1414 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
Alan Coxdeb91682008-07-22 11:13:08 +01001416 /* return the counter values if non-null */
1417 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001419
1420 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001422
1423 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001424 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001425 __func__, baud_rate, *rate_hi, *rate_low);
1426
1427 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428}
1429
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001430static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1431 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 u8 *rate_low, u8 *prescaler, int portnum)
1433{
1434 u32 b16, /* baud rate times 16 (actual rate used internally) */
1435 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001436 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 res, /* resulting baud rate using 13/8 prescaler */
1438 diff, /* error using 13/8 prescaler */
1439 smallest_diff;
1440 u8 best_prescaler;
1441 int i;
1442
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001443 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
Alan Coxdeb91682008-07-22 11:13:08 +01001445 /* prevent divide by zero */
1446 b16 = baud_rate * 16L;
1447 if (b16 == 0)
1448 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449
Alan Coxdeb91682008-07-22 11:13:08 +01001450 /* Calculate prescaler by trying them all and looking
1451 for best fit */
1452
1453 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 smallest_diff = 0xffffffff;
1455
1456 /* 0 is an invalid prescaler, used as a flag */
1457 best_prescaler = 0;
1458
Alan Coxdeb91682008-07-22 11:13:08 +01001459 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001461
1462 div = clk / b16;
1463 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
1466 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001467 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
Alan Coxdeb91682008-07-22 11:13:08 +01001469 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 best_prescaler = i;
1471 smallest_diff = diff;
1472 }
1473 }
1474
Alan Coxdeb91682008-07-22 11:13:08 +01001475 if (best_prescaler == 0)
1476 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
1478 clk = (baudclk * 8) / (u32) best_prescaler;
1479 div = clk / b16;
1480
Alan Coxdeb91682008-07-22 11:13:08 +01001481 /* return the divisor and prescaler if non-null */
1482 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001484 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 if (prescaler) {
1487 *prescaler = best_prescaler;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001488 /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 }
Alan Coxdeb91682008-07-22 11:13:08 +01001490 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491}
1492
1493 /* USA-28 supports different maximum baud rates on each port */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001494static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1495 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1496 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497{
1498 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001499 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 cnt; /* inverse of divisor (programmed into 8051) */
1501
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001502 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503
1504 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001505 b16 = baud_rate * 16L;
1506 if (b16 == 0)
1507 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
Alan Coxdeb91682008-07-22 11:13:08 +01001509 /* calculate the divisor and the counter (its inverse) */
1510 div = KEYSPAN_USA28_BAUDCLK / b16;
1511 if (div == 0)
1512 return KEYSPAN_INVALID_BAUD_RATE;
1513 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
Alan Coxdeb91682008-07-22 11:13:08 +01001516 /* check for out of range, based on portnum,
1517 and return result */
1518 if (portnum == 0) {
1519 if (div > 0xffff)
1520 return KEYSPAN_INVALID_BAUD_RATE;
1521 } else {
1522 if (portnum == 1) {
1523 if (div > 0xff)
1524 return KEYSPAN_INVALID_BAUD_RATE;
1525 } else
1526 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 }
1528
1529 /* return the counter values if not NULL
1530 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001531 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001533 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001535 dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
Alan Coxdeb91682008-07-22 11:13:08 +01001536 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537}
1538
1539static int keyspan_usa26_send_setup(struct usb_serial *serial,
1540 struct usb_serial_port *port,
1541 int reset_port)
1542{
Alan Coxdeb91682008-07-22 11:13:08 +01001543 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 struct keyspan_serial_private *s_priv;
1545 struct keyspan_port_private *p_priv;
1546 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 struct urb *this_urb;
1548 int device_port, err;
1549
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001550 dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551
1552 s_priv = usb_get_serial_data(serial);
1553 p_priv = usb_get_serial_port_data(port);
1554 d_details = s_priv->device_details;
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001555 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 this_urb = p_priv->outcont_urb;
1558
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 /* Make sure we have an urb then send the message */
1560 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001561 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 return -1;
1563 }
1564
Rickard Strandqvistd5afce82014-05-16 17:39:13 +02001565 dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
1566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001568 Don't overwrite resend for open/close condition. */
1569 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 p_priv->resend_cont = reset_port + 1;
1571 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001572 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001574 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 }
1576
Alan Coxdeb91682008-07-22 11:13:08 +01001577 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1578
1579 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 if (p_priv->old_baud != p_priv->baud) {
1581 p_priv->old_baud = p_priv->baud;
1582 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001583 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1584 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1585 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1586 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1587 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 msg.baudLo = 0;
1589 msg.baudHi = 125; /* Values for 9600 baud */
1590 msg.prescaler = 10;
1591 }
1592 msg.setPrescaler = 0xff;
1593 }
1594
Ben Minerds2b982ab2012-07-12 00:10:16 +10001595 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 switch (p_priv->cflag & CSIZE) {
1597 case CS5:
1598 msg.lcr |= USA_DATABITS_5;
1599 break;
1600 case CS6:
1601 msg.lcr |= USA_DATABITS_6;
1602 break;
1603 case CS7:
1604 msg.lcr |= USA_DATABITS_7;
1605 break;
1606 case CS8:
1607 msg.lcr |= USA_DATABITS_8;
1608 break;
1609 }
1610 if (p_priv->cflag & PARENB) {
1611 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001612 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001613 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 }
1615 msg.setLcr = 0xff;
1616
1617 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1618 msg.xonFlowControl = 0;
1619 msg.setFlowControl = 0xff;
1620 msg.forwardingLength = 16;
1621 msg.xonChar = 17;
1622 msg.xoffChar = 19;
1623
1624 /* Opening port */
1625 if (reset_port == 1) {
1626 msg._txOn = 1;
1627 msg._txOff = 0;
1628 msg.txFlush = 0;
1629 msg.txBreak = 0;
1630 msg.rxOn = 1;
1631 msg.rxOff = 0;
1632 msg.rxFlush = 1;
1633 msg.rxForward = 0;
1634 msg.returnStatus = 0;
1635 msg.resetDataToggle = 0xff;
1636 }
1637
1638 /* Closing port */
1639 else if (reset_port == 2) {
1640 msg._txOn = 0;
1641 msg._txOff = 1;
1642 msg.txFlush = 0;
1643 msg.txBreak = 0;
1644 msg.rxOn = 0;
1645 msg.rxOff = 1;
1646 msg.rxFlush = 1;
1647 msg.rxForward = 0;
1648 msg.returnStatus = 0;
1649 msg.resetDataToggle = 0;
1650 }
1651
1652 /* Sending intermediate configs */
1653 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001654 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 msg._txOff = 0;
1656 msg.txFlush = 0;
1657 msg.txBreak = (p_priv->break_on);
1658 msg.rxOn = 0;
1659 msg.rxOff = 0;
1660 msg.rxFlush = 0;
1661 msg.rxForward = 0;
1662 msg.returnStatus = 0;
1663 msg.resetDataToggle = 0x0;
1664 }
1665
Alan Coxdeb91682008-07-22 11:13:08 +01001666 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 msg.setTxTriState_setRts = 0xff;
1668 msg.txTriState_rts = p_priv->rts_state;
1669
1670 msg.setHskoa_setDtr = 0xff;
1671 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001672
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001674 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1675
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 /* send the data out the device on control endpoint */
1677 this_urb->transfer_buffer_length = sizeof(msg);
1678
Alan Coxdeb91682008-07-22 11:13:08 +01001679 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1680 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001681 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01001682 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683}
1684
1685static int keyspan_usa28_send_setup(struct usb_serial *serial,
1686 struct usb_serial_port *port,
1687 int reset_port)
1688{
Alan Coxdeb91682008-07-22 11:13:08 +01001689 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 struct keyspan_serial_private *s_priv;
1691 struct keyspan_port_private *p_priv;
1692 const struct keyspan_device_details *d_details;
1693 struct urb *this_urb;
1694 int device_port, err;
1695
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 s_priv = usb_get_serial_data(serial);
1697 p_priv = usb_get_serial_port_data(port);
1698 d_details = s_priv->device_details;
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001699 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
1701 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001702 this_urb = p_priv->outcont_urb;
1703 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001704 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 return -1;
1706 }
1707
1708 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001709 Don't overwrite resend for open/close condition. */
1710 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 p_priv->resend_cont = reset_port + 1;
1712 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001713 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001715 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 }
1717
Alan Coxdeb91682008-07-22 11:13:08 +01001718 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719
1720 msg.setBaudRate = 1;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001721 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1722 &msg.baudHi, &msg.baudLo, NULL,
1723 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1724 dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001725 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 msg.baudLo = 0xff;
1727 msg.baudHi = 0xb2; /* Values for 9600 baud */
1728 }
1729
1730 /* If parity is enabled, we must calculate it ourselves. */
1731 msg.parity = 0; /* XXX for now */
1732
1733 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1734 msg.xonFlowControl = 0;
1735
Alan Coxdeb91682008-07-22 11:13:08 +01001736 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 msg.rts = p_priv->rts_state;
1738 msg.dtr = p_priv->dtr_state;
1739
1740 msg.forwardingLength = 16;
1741 msg.forwardMs = 10;
1742 msg.breakThreshold = 45;
1743 msg.xonChar = 17;
1744 msg.xoffChar = 19;
1745
1746 /*msg.returnStatus = 1;
1747 msg.resetDataToggle = 0xff;*/
1748 /* Opening port */
1749 if (reset_port == 1) {
1750 msg._txOn = 1;
1751 msg._txOff = 0;
1752 msg.txFlush = 0;
1753 msg.txForceXoff = 0;
1754 msg.txBreak = 0;
1755 msg.rxOn = 1;
1756 msg.rxOff = 0;
1757 msg.rxFlush = 1;
1758 msg.rxForward = 0;
1759 msg.returnStatus = 0;
1760 msg.resetDataToggle = 0xff;
1761 }
1762 /* Closing port */
1763 else if (reset_port == 2) {
1764 msg._txOn = 0;
1765 msg._txOff = 1;
1766 msg.txFlush = 0;
1767 msg.txForceXoff = 0;
1768 msg.txBreak = 0;
1769 msg.rxOn = 0;
1770 msg.rxOff = 1;
1771 msg.rxFlush = 1;
1772 msg.rxForward = 0;
1773 msg.returnStatus = 0;
1774 msg.resetDataToggle = 0;
1775 }
1776 /* Sending intermediate configs */
1777 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001778 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 msg._txOff = 0;
1780 msg.txFlush = 0;
1781 msg.txForceXoff = 0;
1782 msg.txBreak = (p_priv->break_on);
1783 msg.rxOn = 0;
1784 msg.rxOff = 0;
1785 msg.rxFlush = 0;
1786 msg.rxForward = 0;
1787 msg.returnStatus = 0;
1788 msg.resetDataToggle = 0x0;
1789 }
1790
1791 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001792 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
1794 /* send the data out the device on control endpoint */
1795 this_urb->transfer_buffer_length = sizeof(msg);
1796
Alan Coxdeb91682008-07-22 11:13:08 +01001797 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1798 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001799 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Alan Coxa5b6f602008-04-08 17:16:06 +01001801 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802}
1803
1804static int keyspan_usa49_send_setup(struct usb_serial *serial,
1805 struct usb_serial_port *port,
1806 int reset_port)
1807{
Lucy McCoy0ca12682007-05-18 12:10:41 -07001808 struct keyspan_usa49_portControlMessage msg;
1809 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 struct keyspan_serial_private *s_priv;
1811 struct keyspan_port_private *p_priv;
1812 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 struct urb *this_urb;
1814 int err, device_port;
1815
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 s_priv = usb_get_serial_data(serial);
1817 p_priv = usb_get_serial_port_data(port);
1818 d_details = s_priv->device_details;
1819
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 this_urb = s_priv->glocont_urb;
1821
Lucy McCoy0ca12682007-05-18 12:10:41 -07001822 /* Work out which port within the device is being setup */
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001823 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301825 /* Make sure we have an urb then send the message */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 if (this_urb == NULL) {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001827 dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 return -1;
1829 }
1830
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001831 dev_dbg(&port->dev, "%s - endpoint %d (%d)\n",
1832 __func__, usb_pipeendpoint(this_urb->pipe), device_port);
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301833
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001835 Don't overwrite resend for open/close condition. */
1836 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001838
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001840 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001842 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 }
1844
Alan Coxdeb91682008-07-22 11:13:08 +01001845 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01001848
1849 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 if (p_priv->old_baud != p_priv->baud) {
1851 p_priv->old_baud = p_priv->baud;
1852 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001853 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1854 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1855 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1856 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1857 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 msg.baudLo = 0;
1859 msg.baudHi = 125; /* Values for 9600 baud */
1860 msg.prescaler = 10;
1861 }
Alan Coxdeb91682008-07-22 11:13:08 +01001862 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 }
1864
Ben Minerds2b982ab2012-07-12 00:10:16 +10001865 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 switch (p_priv->cflag & CSIZE) {
1867 case CS5:
1868 msg.lcr |= USA_DATABITS_5;
1869 break;
1870 case CS6:
1871 msg.lcr |= USA_DATABITS_6;
1872 break;
1873 case CS7:
1874 msg.lcr |= USA_DATABITS_7;
1875 break;
1876 case CS8:
1877 msg.lcr |= USA_DATABITS_8;
1878 break;
1879 }
1880 if (p_priv->cflag & PARENB) {
1881 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001882 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001883 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 }
1885 msg.setLcr = 0xff;
1886
1887 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1888 msg.xonFlowControl = 0;
1889 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01001890
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 msg.forwardingLength = 16;
1892 msg.xonChar = 17;
1893 msg.xoffChar = 19;
1894
Alan Coxdeb91682008-07-22 11:13:08 +01001895 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 if (reset_port == 1) {
1897 msg._txOn = 1;
1898 msg._txOff = 0;
1899 msg.txFlush = 0;
1900 msg.txBreak = 0;
1901 msg.rxOn = 1;
1902 msg.rxOff = 0;
1903 msg.rxFlush = 1;
1904 msg.rxForward = 0;
1905 msg.returnStatus = 0;
1906 msg.resetDataToggle = 0xff;
1907 msg.enablePort = 1;
1908 msg.disablePort = 0;
1909 }
1910 /* Closing port */
1911 else if (reset_port == 2) {
1912 msg._txOn = 0;
1913 msg._txOff = 1;
1914 msg.txFlush = 0;
1915 msg.txBreak = 0;
1916 msg.rxOn = 0;
1917 msg.rxOff = 1;
1918 msg.rxFlush = 1;
1919 msg.rxForward = 0;
1920 msg.returnStatus = 0;
1921 msg.resetDataToggle = 0;
1922 msg.enablePort = 0;
1923 msg.disablePort = 1;
1924 }
1925 /* Sending intermediate configs */
1926 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001927 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 msg._txOff = 0;
1929 msg.txFlush = 0;
1930 msg.txBreak = (p_priv->break_on);
1931 msg.rxOn = 0;
1932 msg.rxOff = 0;
1933 msg.rxFlush = 0;
1934 msg.rxForward = 0;
1935 msg.returnStatus = 0;
1936 msg.resetDataToggle = 0x0;
1937 msg.enablePort = 0;
1938 msg.disablePort = 0;
1939 }
1940
Alan Coxdeb91682008-07-22 11:13:08 +01001941 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 msg.setRts = 0xff;
1943 msg.rts = p_priv->rts_state;
1944
1945 msg.setDtr = 0xff;
1946 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001947
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949
Alan Coxdeb91682008-07-22 11:13:08 +01001950 /* if the device is a 49wg, we send control message on usb
1951 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07001952
1953 if (d_details->product_id == keyspan_usa49wg_product_id) {
1954 dr = (void *)(s_priv->ctrl_buf);
1955 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
1956 dr->bRequest = 0xB0; /* 49wg control message */;
1957 dr->wValue = 0;
1958 dr->wIndex = 0;
1959 dr->wLength = cpu_to_le16(sizeof(msg));
1960
Alan Coxdeb91682008-07-22 11:13:08 +01001961 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07001962
Alan Coxdeb91682008-07-22 11:13:08 +01001963 usb_fill_control_urb(this_urb, serial->dev,
1964 usb_sndctrlpipe(serial->dev, 0),
1965 (unsigned char *)dr, s_priv->glocont_buf,
1966 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001967
1968 } else {
1969 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01001970
Lucy McCoy0ca12682007-05-18 12:10:41 -07001971 /* send the data out the device on control endpoint */
1972 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001973 }
Alan Coxdeb91682008-07-22 11:13:08 +01001974 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1975 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001976 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977
Alan Coxa5b6f602008-04-08 17:16:06 +01001978 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979}
1980
1981static int keyspan_usa90_send_setup(struct usb_serial *serial,
1982 struct usb_serial_port *port,
1983 int reset_port)
1984{
Alan Coxdeb91682008-07-22 11:13:08 +01001985 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 struct keyspan_serial_private *s_priv;
1987 struct keyspan_port_private *p_priv;
1988 const struct keyspan_device_details *d_details;
1989 struct urb *this_urb;
1990 int err;
1991 u8 prescaler;
1992
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 s_priv = usb_get_serial_data(serial);
1994 p_priv = usb_get_serial_port_data(port);
1995 d_details = s_priv->device_details;
1996
1997 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001998 this_urb = p_priv->outcont_urb;
1999 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002000 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 return -1;
2002 }
2003
2004 /* Save reset port val for resend.
2005 Don't overwrite resend for open/close condition. */
2006 if ((reset_port + 1) > p_priv->resend_cont)
2007 p_priv->resend_cont = reset_port + 1;
2008 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002009 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002011 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 }
2013
Alan Coxdeb91682008-07-22 11:13:08 +01002014 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
Alan Coxdeb91682008-07-22 11:13:08 +01002016 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 if (p_priv->old_baud != p_priv->baud) {
2018 p_priv->old_baud = p_priv->baud;
2019 msg.setClocking = 0x01;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002020 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2021 &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2022 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2023 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 p_priv->baud = 9600;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002025 d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2027 }
2028 msg.setRxMode = 1;
2029 msg.setTxMode = 1;
2030 }
2031
2032 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002033 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 msg.rxMode = RXMODE_DMA;
2035 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002036 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 msg.rxMode = RXMODE_BYHAND;
2038 msg.txMode = TXMODE_BYHAND;
2039 }
2040
Ben Minerds2b982ab2012-07-12 00:10:16 +10002041 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 switch (p_priv->cflag & CSIZE) {
2043 case CS5:
2044 msg.lcr |= USA_DATABITS_5;
2045 break;
2046 case CS6:
2047 msg.lcr |= USA_DATABITS_6;
2048 break;
2049 case CS7:
2050 msg.lcr |= USA_DATABITS_7;
2051 break;
2052 case CS8:
2053 msg.lcr |= USA_DATABITS_8;
2054 break;
2055 }
2056 if (p_priv->cflag & PARENB) {
2057 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002058 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002059 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 }
2061 if (p_priv->old_cflag != p_priv->cflag) {
2062 p_priv->old_cflag = p_priv->cflag;
2063 msg.setLcr = 0x01;
2064 }
2065
2066 if (p_priv->flow_control == flow_cts)
2067 msg.txFlowControl = TXFLOW_CTS;
2068 msg.setTxFlowControl = 0x01;
2069 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002070
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002072 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 msg.txAckSetting = 0;
2074 msg.xonChar = 17;
2075 msg.xoffChar = 19;
2076
Alan Coxdeb91682008-07-22 11:13:08 +01002077 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 if (reset_port == 1) {
2079 msg.portEnabled = 1;
2080 msg.rxFlush = 1;
2081 msg.txBreak = (p_priv->break_on);
2082 }
2083 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002084 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 /* Sending intermediate configs */
2087 else {
Alan Stern1f871582010-02-17 10:05:47 -05002088 msg.portEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 msg.txBreak = (p_priv->break_on);
2090 }
2091
Alan Coxdeb91682008-07-22 11:13:08 +01002092 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 msg.setRts = 0x01;
2094 msg.rts = p_priv->rts_state;
2095
2096 msg.setDtr = 0x01;
2097 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002098
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002100 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2101
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 /* send the data out the device on control endpoint */
2103 this_urb->transfer_buffer_length = sizeof(msg);
2104
Alan Coxdeb91682008-07-22 11:13:08 +01002105 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2106 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002107 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002108 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109}
2110
Lucy McCoy0ca12682007-05-18 12:10:41 -07002111static int keyspan_usa67_send_setup(struct usb_serial *serial,
2112 struct usb_serial_port *port,
2113 int reset_port)
2114{
2115 struct keyspan_usa67_portControlMessage msg;
2116 struct keyspan_serial_private *s_priv;
2117 struct keyspan_port_private *p_priv;
2118 const struct keyspan_device_details *d_details;
2119 struct urb *this_urb;
2120 int err, device_port;
2121
Lucy McCoy0ca12682007-05-18 12:10:41 -07002122 s_priv = usb_get_serial_data(serial);
2123 p_priv = usb_get_serial_port_data(port);
2124 d_details = s_priv->device_details;
2125
2126 this_urb = s_priv->glocont_urb;
2127
2128 /* Work out which port within the device is being setup */
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002129 device_port = port->port_number;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002130
2131 /* Make sure we have an urb then send the message */
2132 if (this_urb == NULL) {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002133 dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002134 return -1;
2135 }
2136
2137 /* Save reset port val for resend.
2138 Don't overwrite resend for open/close condition. */
2139 if ((reset_port + 1) > p_priv->resend_cont)
2140 p_priv->resend_cont = reset_port + 1;
2141 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002142 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002143 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002144 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002145 }
2146
2147 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2148
2149 msg.port = device_port;
2150
2151 /* Only set baud rate if it's changed */
2152 if (p_priv->old_baud != p_priv->baud) {
2153 p_priv->old_baud = p_priv->baud;
2154 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002155 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2156 &msg.baudHi, &msg.baudLo, &msg.prescaler,
2157 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2158 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2159 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002160 msg.baudLo = 0;
2161 msg.baudHi = 125; /* Values for 9600 baud */
2162 msg.prescaler = 10;
2163 }
2164 msg.setPrescaler = 0xff;
2165 }
2166
2167 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2168 switch (p_priv->cflag & CSIZE) {
2169 case CS5:
2170 msg.lcr |= USA_DATABITS_5;
2171 break;
2172 case CS6:
2173 msg.lcr |= USA_DATABITS_6;
2174 break;
2175 case CS7:
2176 msg.lcr |= USA_DATABITS_7;
2177 break;
2178 case CS8:
2179 msg.lcr |= USA_DATABITS_8;
2180 break;
2181 }
2182 if (p_priv->cflag & PARENB) {
2183 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002184 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002185 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002186 }
2187 msg.setLcr = 0xff;
2188
2189 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2190 msg.xonFlowControl = 0;
2191 msg.setFlowControl = 0xff;
2192 msg.forwardingLength = 16;
2193 msg.xonChar = 17;
2194 msg.xoffChar = 19;
2195
2196 if (reset_port == 1) {
2197 /* Opening port */
2198 msg._txOn = 1;
2199 msg._txOff = 0;
2200 msg.txFlush = 0;
2201 msg.txBreak = 0;
2202 msg.rxOn = 1;
2203 msg.rxOff = 0;
2204 msg.rxFlush = 1;
2205 msg.rxForward = 0;
2206 msg.returnStatus = 0;
2207 msg.resetDataToggle = 0xff;
2208 } else if (reset_port == 2) {
2209 /* Closing port */
2210 msg._txOn = 0;
2211 msg._txOff = 1;
2212 msg.txFlush = 0;
2213 msg.txBreak = 0;
2214 msg.rxOn = 0;
2215 msg.rxOff = 1;
2216 msg.rxFlush = 1;
2217 msg.rxForward = 0;
2218 msg.returnStatus = 0;
2219 msg.resetDataToggle = 0;
2220 } else {
2221 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002222 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002223 msg._txOff = 0;
2224 msg.txFlush = 0;
2225 msg.txBreak = (p_priv->break_on);
2226 msg.rxOn = 0;
2227 msg.rxOff = 0;
2228 msg.rxFlush = 0;
2229 msg.rxForward = 0;
2230 msg.returnStatus = 0;
2231 msg.resetDataToggle = 0x0;
2232 }
2233
2234 /* Do handshaking outputs */
2235 msg.setTxTriState_setRts = 0xff;
2236 msg.txTriState_rts = p_priv->rts_state;
2237
2238 msg.setHskoa_setDtr = 0xff;
2239 msg.hskoa_dtr = p_priv->dtr_state;
2240
2241 p_priv->resend_cont = 0;
2242
2243 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2244
2245 /* send the data out the device on control endpoint */
2246 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002247
2248 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2249 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002250 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002251 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002252}
2253
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2255{
2256 struct usb_serial *serial = port->serial;
2257 struct keyspan_serial_private *s_priv;
2258 const struct keyspan_device_details *d_details;
2259
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 s_priv = usb_get_serial_data(serial);
2261 d_details = s_priv->device_details;
2262
2263 switch (d_details->msg_format) {
2264 case msg_usa26:
2265 keyspan_usa26_send_setup(serial, port, reset_port);
2266 break;
2267 case msg_usa28:
2268 keyspan_usa28_send_setup(serial, port, reset_port);
2269 break;
2270 case msg_usa49:
2271 keyspan_usa49_send_setup(serial, port, reset_port);
2272 break;
2273 case msg_usa90:
2274 keyspan_usa90_send_setup(serial, port, reset_port);
2275 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002276 case msg_usa67:
2277 keyspan_usa67_send_setup(serial, port, reset_port);
2278 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 }
2280}
2281
2282
2283/* Gets called by the "real" driver (ie once firmware is loaded
2284 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002285static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286{
2287 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 const struct keyspan_device_details *d_details;
2290
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002292 if (d_details->product_id ==
2293 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 break;
2295 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002296 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2297 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Johan Hovoldff8a43c2013-08-13 13:27:35 +02002298 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 }
2300
2301 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002302 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Johan Hovold10c642d2013-12-29 19:22:56 +01002303 if (!s_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305
Johan Hovold2fcd1c92013-08-13 13:27:36 +02002306 s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);
2307 if (!s_priv->instat_buf)
2308 goto err_instat_buf;
2309
2310 s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL);
2311 if (!s_priv->indat_buf)
2312 goto err_indat_buf;
2313
2314 s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL);
2315 if (!s_priv->glocont_buf)
2316 goto err_glocont_buf;
2317
2318 s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
2319 if (!s_priv->ctrl_buf)
2320 goto err_ctrl_buf;
2321
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 s_priv->device_details = d_details;
2323 usb_set_serial_data(serial, s_priv);
2324
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 keyspan_setup_urbs(serial);
2326
Lucy McCoy0ca12682007-05-18 12:10:41 -07002327 if (s_priv->instat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002328 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2329 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002330 dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002331 }
2332 if (s_priv->indat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002333 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2334 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002335 dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 }
Alan Coxdeb91682008-07-22 11:13:08 +01002337
Alan Coxa5b6f602008-04-08 17:16:06 +01002338 return 0;
Johan Hovold2fcd1c92013-08-13 13:27:36 +02002339
2340err_ctrl_buf:
2341 kfree(s_priv->glocont_buf);
2342err_glocont_buf:
2343 kfree(s_priv->indat_buf);
2344err_indat_buf:
2345 kfree(s_priv->instat_buf);
2346err_instat_buf:
2347 kfree(s_priv);
2348
2349 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350}
2351
Alan Sternf9c99bb2009-06-02 11:53:55 -04002352static void keyspan_disconnect(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002354 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 s_priv = usb_get_serial_data(serial);
2357
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 stop_urb(s_priv->instat_urb);
2359 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002360 stop_urb(s_priv->indat_urb);
Alan Sternf9c99bb2009-06-02 11:53:55 -04002361}
2362
2363static void keyspan_release(struct usb_serial *serial)
2364{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002365 struct keyspan_serial_private *s_priv;
Alan Sternf9c99bb2009-06-02 11:53:55 -04002366
Alan Sternf9c99bb2009-06-02 11:53:55 -04002367 s_priv = usb_get_serial_data(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002369 usb_free_urb(s_priv->instat_urb);
2370 usb_free_urb(s_priv->indat_urb);
2371 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372
Johan Hovold2fcd1c92013-08-13 13:27:36 +02002373 kfree(s_priv->ctrl_buf);
2374 kfree(s_priv->glocont_buf);
2375 kfree(s_priv->indat_buf);
2376 kfree(s_priv->instat_buf);
2377
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002378 kfree(s_priv);
2379}
2380
2381static int keyspan_port_probe(struct usb_serial_port *port)
2382{
2383 struct usb_serial *serial = port->serial;
Bjørn Morkf0e3e352012-11-10 10:13:42 +01002384 struct keyspan_serial_private *s_priv;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002385 struct keyspan_port_private *p_priv;
2386 const struct keyspan_device_details *d_details;
2387 struct callbacks *cback;
2388 int endp;
2389 int port_num;
2390 int i;
2391
2392 s_priv = usb_get_serial_data(serial);
2393 d_details = s_priv->device_details;
2394
2395 p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL);
2396 if (!p_priv)
2397 return -ENOMEM;
2398
Johan Hovoldbad41a52013-08-13 13:27:37 +02002399 for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
2400 p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
2401 if (!p_priv->in_buffer[i])
2402 goto err_in_buffer;
2403 }
2404
2405 for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
2406 p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
2407 if (!p_priv->out_buffer[i])
2408 goto err_out_buffer;
2409 }
2410
2411 p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
2412 if (!p_priv->inack_buffer)
2413 goto err_inack_buffer;
2414
2415 p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
2416 if (!p_priv->outcont_buffer)
2417 goto err_outcont_buffer;
2418
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002419 p_priv->device_details = d_details;
2420
2421 /* Setup values for the various callback routines */
2422 cback = &keyspan_callbacks[d_details->msg_format];
2423
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002424 port_num = port->port_number;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002425
2426 /* Do indat endpoints first, once for each flip */
2427 endp = d_details->indat_endpoints[port_num];
2428 for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
2429 p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
2430 USB_DIR_IN, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002431 p_priv->in_buffer[i],
2432 IN_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002433 cback->indat_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 }
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002435 /* outdat endpoints also have flip */
2436 endp = d_details->outdat_endpoints[port_num];
2437 for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
2438 p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
2439 USB_DIR_OUT, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002440 p_priv->out_buffer[i],
2441 OUT_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002442 cback->outdat_callback);
2443 }
2444 /* inack endpoint */
2445 p_priv->inack_urb = keyspan_setup_urb(serial,
2446 d_details->inack_endpoints[port_num],
2447 USB_DIR_IN, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002448 p_priv->inack_buffer,
2449 INACK_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002450 cback->inack_callback);
2451 /* outcont endpoint */
2452 p_priv->outcont_urb = keyspan_setup_urb(serial,
2453 d_details->outcont_endpoints[port_num],
2454 USB_DIR_OUT, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002455 p_priv->outcont_buffer,
2456 OUTCONT_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002457 cback->outcont_callback);
2458
2459 usb_set_serial_port_data(port, p_priv);
2460
2461 return 0;
Johan Hovoldbad41a52013-08-13 13:27:37 +02002462
2463err_outcont_buffer:
2464 kfree(p_priv->inack_buffer);
2465err_inack_buffer:
2466 for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
2467 kfree(p_priv->out_buffer[i]);
2468err_out_buffer:
2469 for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
2470 kfree(p_priv->in_buffer[i]);
2471err_in_buffer:
2472 kfree(p_priv);
2473
2474 return -ENOMEM;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002475}
2476
2477static int keyspan_port_remove(struct usb_serial_port *port)
2478{
2479 struct keyspan_port_private *p_priv;
2480 int i;
2481
2482 p_priv = usb_get_serial_port_data(port);
2483
2484 stop_urb(p_priv->inack_urb);
2485 stop_urb(p_priv->outcont_urb);
2486 for (i = 0; i < 2; i++) {
2487 stop_urb(p_priv->in_urbs[i]);
2488 stop_urb(p_priv->out_urbs[i]);
2489 }
2490
2491 usb_free_urb(p_priv->inack_urb);
2492 usb_free_urb(p_priv->outcont_urb);
2493 for (i = 0; i < 2; i++) {
2494 usb_free_urb(p_priv->in_urbs[i]);
2495 usb_free_urb(p_priv->out_urbs[i]);
2496 }
2497
Johan Hovoldbad41a52013-08-13 13:27:37 +02002498 kfree(p_priv->outcont_buffer);
2499 kfree(p_priv->inack_buffer);
2500 for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
2501 kfree(p_priv->out_buffer[i]);
2502 for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
2503 kfree(p_priv->in_buffer[i]);
2504
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002505 kfree(p_priv);
2506
2507 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508}
2509
Alan Coxdeb91682008-07-22 11:13:08 +01002510MODULE_AUTHOR(DRIVER_AUTHOR);
2511MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512MODULE_LICENSE("GPL");
2513
David Woodhouse2971c572008-05-30 14:04:03 +03002514MODULE_FIRMWARE("keyspan/usa28.fw");
2515MODULE_FIRMWARE("keyspan/usa28x.fw");
2516MODULE_FIRMWARE("keyspan/usa28xa.fw");
2517MODULE_FIRMWARE("keyspan/usa28xb.fw");
2518MODULE_FIRMWARE("keyspan/usa19.fw");
2519MODULE_FIRMWARE("keyspan/usa19qi.fw");
2520MODULE_FIRMWARE("keyspan/mpr.fw");
2521MODULE_FIRMWARE("keyspan/usa19qw.fw");
2522MODULE_FIRMWARE("keyspan/usa18x.fw");
2523MODULE_FIRMWARE("keyspan/usa19w.fw");
2524MODULE_FIRMWARE("keyspan/usa49w.fw");
2525MODULE_FIRMWARE("keyspan/usa49wlc.fw");