blob: 265c6776b081747094a2b31f6e10994cf4ef247f [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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100315 err = TTY_OVERRUN;
316 else
317 err = 0;
318 for (i = 1; i < urb->actual_length ; ++i)
Jiri Slaby92a19f92013-01-03 15:53:03 +0100319 tty_insert_flip_char(&port->port, data[i], err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 } else {
321 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700322 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 for (i = 0; i + 1 < urb->actual_length; i += 2) {
324 int stat = data[i], flag = 0;
325 if (stat & RXERROR_OVERRUN)
326 flag |= TTY_OVERRUN;
327 if (stat & RXERROR_FRAMING)
328 flag |= TTY_FRAME;
329 if (stat & RXERROR_PARITY)
330 flag |= TTY_PARITY;
331 /* XXX should handle break (0x10) */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100332 tty_insert_flip_char(&port->port, data[i+1],
333 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 }
335 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100336 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 }
Alan Coxdeb91682008-07-22 11:13:08 +0100338
339 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500340 err = usb_submit_urb(urb, GFP_ATOMIC);
341 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700342 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343}
344
Alan Coxdeb91682008-07-22 11:13:08 +0100345/* Outdat handling is common for all devices */
David Howells7d12e782006-10-05 14:55:46 +0100346static void usa2x_outdat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
348 struct usb_serial_port *port;
349 struct keyspan_port_private *p_priv;
350
Ming Leicdc97792008-02-24 18:41:47 +0800351 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 p_priv = usb_get_serial_port_data(port);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700353 dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Alan Stern1f871582010-02-17 10:05:47 -0500355 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356}
357
David Howells7d12e782006-10-05 14:55:46 +0100358static void usa26_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
David Howells7d12e782006-10-05 14:55:46 +0100362static void usa26_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
364 struct usb_serial_port *port;
365 struct keyspan_port_private *p_priv;
366
Ming Leicdc97792008-02-24 18:41:47 +0800367 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 p_priv = usb_get_serial_port_data(port);
369
370 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700371 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100372 keyspan_usa26_send_setup(port->serial, port,
373 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 }
375}
376
David Howells7d12e782006-10-05 14:55:46 +0100377static void usa26_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378{
379 unsigned char *data = urb->transfer_buffer;
380 struct keyspan_usa26_portStatusMessage *msg;
381 struct usb_serial *serial;
382 struct usb_serial_port *port;
383 struct keyspan_port_private *p_priv;
384 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700385 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Ming Leicdc97792008-02-24 18:41:47 +0800387 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700389 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700390 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 return;
392 }
393 if (urb->actual_length != 9) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700394 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 goto exit;
396 }
397
398 msg = (struct keyspan_usa26_portStatusMessage *)data;
399
400#if 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700401 dev_dbg(&urb->dev->dev,
402 "%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
403 __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr,
404 msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled,
405 msg->controlResponse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406#endif
407
408 /* Now do something useful with the data */
409
410
Alan Coxdeb91682008-07-22 11:13:08 +0100411 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700413 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 goto exit;
415 }
416 port = serial->port[msg->port];
417 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100418
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 /* Update handshaking pin state information */
420 old_dcd_state = p_priv->dcd_state;
421 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
422 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
423 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
424 p_priv->ri_state = ((msg->ri) ? 1 : 0);
425
Jiri Slabyaa27a092013-03-07 13:12:30 +0100426 if (old_dcd_state != p_priv->dcd_state)
427 tty_port_tty_hangup(&port->port, true);
Alan Coxdeb91682008-07-22 11:13:08 +0100428
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100430 err = usb_submit_urb(urb, GFP_ATOMIC);
431 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700432 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433exit: ;
434}
435
David Howells7d12e782006-10-05 14:55:46 +0100436static void usa26_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438}
439
440
David Howells7d12e782006-10-05 14:55:46 +0100441static void usa28_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442{
Alan Coxf035a8a2008-07-22 11:13:32 +0100443 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 struct usb_serial_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 unsigned char *data;
446 struct keyspan_port_private *p_priv;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700447 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Ming Leicdc97792008-02-24 18:41:47 +0800449 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 p_priv = usb_get_serial_port_data(port);
451 data = urb->transfer_buffer;
452
453 if (urb != p_priv->in_urbs[p_priv->in_flip])
454 return;
455
456 do {
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700457 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700458 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
459 __func__, status, usb_pipeendpoint(urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 return;
461 }
462
Ming Leicdc97792008-02-24 18:41:47 +0800463 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 p_priv = usb_get_serial_port_data(port);
465 data = urb->transfer_buffer;
466
Jiri Slaby2e124b42013-01-03 15:53:06 +0100467 if (urb->actual_length) {
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100468 tty_insert_flip_string(&port->port, data,
469 urb->actual_length);
Jiri Slaby2e124b42013-01-03 15:53:06 +0100470 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 }
472
473 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500474 err = usb_submit_urb(urb, GFP_ATOMIC);
475 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700476 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
Alan Stern1f871582010-02-17 10:05:47 -0500477 __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 p_priv->in_flip ^= 1;
479
480 urb = p_priv->in_urbs[p_priv->in_flip];
481 } while (urb->status != -EINPROGRESS);
482}
483
David Howells7d12e782006-10-05 14:55:46 +0100484static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486}
487
David Howells7d12e782006-10-05 14:55:46 +0100488static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489{
490 struct usb_serial_port *port;
491 struct keyspan_port_private *p_priv;
492
Ming Leicdc97792008-02-24 18:41:47 +0800493 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 p_priv = usb_get_serial_port_data(port);
495
496 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700497 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100498 keyspan_usa28_send_setup(port->serial, port,
499 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
501}
502
David Howells7d12e782006-10-05 14:55:46 +0100503static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504{
505 int err;
506 unsigned char *data = urb->transfer_buffer;
507 struct keyspan_usa28_portStatusMessage *msg;
508 struct usb_serial *serial;
509 struct usb_serial_port *port;
510 struct keyspan_port_private *p_priv;
511 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700512 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
Ming Leicdc97792008-02-24 18:41:47 +0800514 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700516 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700517 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 return;
519 }
520
521 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700522 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 goto exit;
524 }
525
Andy Shevchenko715cf922013-05-28 12:49:17 +0300526 /*dev_dbg(&urb->dev->dev, "%s %12ph", __func__, data);*/
Alan Coxdeb91682008-07-22 11:13:08 +0100527
528 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 msg = (struct keyspan_usa28_portStatusMessage *)data;
530
Alan Coxdeb91682008-07-22 11:13:08 +0100531 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700533 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 goto exit;
535 }
536 port = serial->port[msg->port];
537 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 /* Update handshaking pin state information */
540 old_dcd_state = p_priv->dcd_state;
541 p_priv->cts_state = ((msg->cts) ? 1 : 0);
542 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
543 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
544 p_priv->ri_state = ((msg->ri) ? 1 : 0);
545
Jiri Slabyaa27a092013-03-07 13:12:30 +0100546 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
547 tty_port_tty_hangup(&port->port, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100550 err = usb_submit_urb(urb, GFP_ATOMIC);
551 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700552 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553exit: ;
554}
555
David Howells7d12e782006-10-05 14:55:46 +0100556static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558}
559
560
David Howells7d12e782006-10-05 14:55:46 +0100561static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562{
563 struct usb_serial *serial;
564 struct usb_serial_port *port;
565 struct keyspan_port_private *p_priv;
566 int i;
567
Ming Leicdc97792008-02-24 18:41:47 +0800568 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 for (i = 0; i < serial->num_ports; ++i) {
570 port = serial->port[i];
571 p_priv = usb_get_serial_port_data(port);
572
573 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700574 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100575 keyspan_usa49_send_setup(serial, port,
576 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 break;
578 }
579 }
580}
581
582 /* This is actually called glostat in the Keyspan
583 doco */
David Howells7d12e782006-10-05 14:55:46 +0100584static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
586 int err;
587 unsigned char *data = urb->transfer_buffer;
588 struct keyspan_usa49_portStatusMessage *msg;
589 struct usb_serial *serial;
590 struct usb_serial_port *port;
591 struct keyspan_port_private *p_priv;
592 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700593 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Ming Leicdc97792008-02-24 18:41:47 +0800595 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700597 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700598 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 return;
600 }
601
Alan Coxdeb91682008-07-22 11:13:08 +0100602 if (urb->actual_length !=
603 sizeof(struct keyspan_usa49_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700604 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 goto exit;
606 }
607
Andy Shevchenko715cf922013-05-28 12:49:17 +0300608 /*dev_dbg(&urb->dev->dev, "%s: %11ph", __func__, data);*/
Alan Coxdeb91682008-07-22 11:13:08 +0100609
610 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 msg = (struct keyspan_usa49_portStatusMessage *)data;
612
Alan Coxdeb91682008-07-22 11:13:08 +0100613 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 if (msg->portNumber >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700615 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
616 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 goto exit;
618 }
619 port = serial->port[msg->portNumber];
620 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100621
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 /* Update handshaking pin state information */
623 old_dcd_state = p_priv->dcd_state;
624 p_priv->cts_state = ((msg->cts) ? 1 : 0);
625 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
626 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
627 p_priv->ri_state = ((msg->ri) ? 1 : 0);
628
Jiri Slabyaa27a092013-03-07 13:12:30 +0100629 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
630 tty_port_tty_hangup(&port->port, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Alan Coxdeb91682008-07-22 11:13:08 +0100632 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100633 err = usb_submit_urb(urb, GFP_ATOMIC);
634 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700635 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636exit: ;
637}
638
David Howells7d12e782006-10-05 14:55:46 +0100639static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641}
642
David Howells7d12e782006-10-05 14:55:46 +0100643static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644{
645 int i, err;
646 int endpoint;
647 struct usb_serial_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700649 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 endpoint = usb_pipeendpoint(urb->pipe);
652
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700653 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700654 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
655 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 return;
657 }
658
Ming Leicdc97792008-02-24 18:41:47 +0800659 port = urb->context;
Jiri Slaby2e124b42013-01-03 15:53:06 +0100660 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 /* 0x80 bit is error flag */
662 if ((data[0] & 0x80) == 0) {
663 /* no error on any byte */
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100664 tty_insert_flip_string(&port->port, data + 1,
Alan Coxf035a8a2008-07-22 11:13:32 +0100665 urb->actual_length - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 } else {
667 /* some bytes had errors, every byte has status */
668 for (i = 0; i + 1 < urb->actual_length; i += 2) {
669 int stat = data[i], flag = 0;
670 if (stat & RXERROR_OVERRUN)
671 flag |= TTY_OVERRUN;
672 if (stat & RXERROR_FRAMING)
673 flag |= TTY_FRAME;
674 if (stat & RXERROR_PARITY)
675 flag |= TTY_PARITY;
676 /* XXX should handle break (0x10) */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100677 tty_insert_flip_char(&port->port, data[i+1],
678 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 }
680 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100681 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 }
Alan Coxdeb91682008-07-22 11:13:08 +0100683
684 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500685 err = usb_submit_urb(urb, GFP_ATOMIC);
686 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700687 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688}
689
Lucy McCoy0ca12682007-05-18 12:10:41 -0700690static void usa49wg_indat_callback(struct urb *urb)
691{
692 int i, len, x, err;
693 struct usb_serial *serial;
694 struct usb_serial_port *port;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700695 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700696 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700697
Lucy McCoy0ca12682007-05-18 12:10:41 -0700698 serial = urb->context;
699
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700700 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700701 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700702 return;
703 }
704
705 /* inbound data is in the form P#, len, status, data */
706 i = 0;
707 len = 0;
708
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300709 while (i < urb->actual_length) {
Lucy McCoy0ca12682007-05-18 12:10:41 -0700710
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300711 /* Check port number from message */
712 if (data[i] >= serial->num_ports) {
713 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
714 __func__, data[i]);
715 return;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700716 }
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300717 port = serial->port[data[i++]];
718 len = data[i++];
719
720 /* 0x80 bit is error flag */
721 if ((data[i] & 0x80) == 0) {
722 /* no error on any byte */
723 i++;
Dan Carpenter01a60e72013-04-05 08:43:20 +0300724 for (x = 1; x < len && i < urb->actual_length; ++x)
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300725 tty_insert_flip_char(&port->port,
726 data[i++], 0);
727 } else {
728 /*
729 * some bytes had errors, every byte has status
730 */
Dan Carpenter01a60e72013-04-05 08:43:20 +0300731 for (x = 0; x + 1 < len &&
732 i + 1 < urb->actual_length; x += 2) {
Dan Carpenter6a3ae842013-04-05 08:42:41 +0300733 int stat = data[i], flag = 0;
734
735 if (stat & RXERROR_OVERRUN)
736 flag |= TTY_OVERRUN;
737 if (stat & RXERROR_FRAMING)
738 flag |= TTY_FRAME;
739 if (stat & RXERROR_PARITY)
740 flag |= TTY_PARITY;
741 /* XXX should handle break (0x10) */
742 tty_insert_flip_char(&port->port, data[i+1],
743 flag);
744 i += 2;
745 }
746 }
747 tty_flip_buffer_push(&port->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700748 }
749
750 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700751 err = usb_submit_urb(urb, GFP_ATOMIC);
752 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700753 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700754}
755
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700757static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759}
760
Lucy McCoy0ca12682007-05-18 12:10:41 -0700761static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
763 int i, err;
764 int endpoint;
765 struct usb_serial_port *port;
766 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700768 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 endpoint = usb_pipeendpoint(urb->pipe);
771
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700772 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700773 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800774 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 return;
776 }
777
Ming Leicdc97792008-02-24 18:41:47 +0800778 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 p_priv = usb_get_serial_port_data(port);
780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 if (urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100783 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Alan Coxf035a8a2008-07-22 11:13:32 +0100785 if (p_priv->baud > 57600)
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100786 tty_insert_flip_string(&port->port, data,
787 urb->actual_length);
Alan Coxf035a8a2008-07-22 11:13:32 +0100788 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 /* 0x80 bit is error flag */
790 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100791 /* no errors on individual bytes, only
792 possible overrun err*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100794 err = TTY_OVERRUN;
795 else
796 err = 0;
797 for (i = 1; i < urb->actual_length ; ++i)
Jiri Slaby92a19f92013-01-03 15:53:03 +0100798 tty_insert_flip_char(&port->port,
799 data[i], err);
Alan Coxdeb91682008-07-22 11:13:08 +0100800 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700802 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 for (i = 0; i + 1 < urb->actual_length; i += 2) {
804 int stat = data[i], flag = 0;
805 if (stat & RXERROR_OVERRUN)
806 flag |= TTY_OVERRUN;
807 if (stat & RXERROR_FRAMING)
808 flag |= TTY_FRAME;
809 if (stat & RXERROR_PARITY)
810 flag |= TTY_PARITY;
811 /* XXX should handle break (0x10) */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100812 tty_insert_flip_char(&port->port,
813 data[i+1], flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 }
815 }
816 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100817 tty_flip_buffer_push(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
Alan Coxdeb91682008-07-22 11:13:08 +0100819
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500821 err = usb_submit_urb(urb, GFP_ATOMIC);
822 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700823 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824}
825
826
David Howells7d12e782006-10-05 14:55:46 +0100827static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828{
829 unsigned char *data = urb->transfer_buffer;
830 struct keyspan_usa90_portStatusMessage *msg;
831 struct usb_serial *serial;
832 struct usb_serial_port *port;
833 struct keyspan_port_private *p_priv;
834 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700835 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Ming Leicdc97792008-02-24 18:41:47 +0800837 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700839 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700840 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 return;
842 }
843 if (urb->actual_length < 14) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700844 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 goto exit;
846 }
847
848 msg = (struct keyspan_usa90_portStatusMessage *)data;
849
850 /* Now do something useful with the data */
851
852 port = serial->port[0];
853 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100854
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 /* Update handshaking pin state information */
856 old_dcd_state = p_priv->dcd_state;
857 p_priv->cts_state = ((msg->cts) ? 1 : 0);
858 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
859 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
860 p_priv->ri_state = ((msg->ri) ? 1 : 0);
861
Jiri Slabyaa27a092013-03-07 13:12:30 +0100862 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
863 tty_port_tty_hangup(&port->port, true);
Alan Coxdeb91682008-07-22 11:13:08 +0100864
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100866 err = usb_submit_urb(urb, GFP_ATOMIC);
867 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700868 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869exit:
870 ;
871}
872
David Howells7d12e782006-10-05 14:55:46 +0100873static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874{
875 struct usb_serial_port *port;
876 struct keyspan_port_private *p_priv;
877
Ming Leicdc97792008-02-24 18:41:47 +0800878 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 p_priv = usb_get_serial_port_data(port);
880
881 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700882 dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100883 keyspan_usa90_send_setup(port->serial, port,
884 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 }
886}
887
Lucy McCoy0ca12682007-05-18 12:10:41 -0700888/* Status messages from the 28xg */
889static void usa67_instat_callback(struct urb *urb)
890{
891 int err;
892 unsigned char *data = urb->transfer_buffer;
893 struct keyspan_usa67_portStatusMessage *msg;
894 struct usb_serial *serial;
895 struct usb_serial_port *port;
896 struct keyspan_port_private *p_priv;
897 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700898 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700899
Lucy McCoy0ca12682007-05-18 12:10:41 -0700900 serial = urb->context;
901
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700902 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700903 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700904 return;
905 }
906
Alan Coxdeb91682008-07-22 11:13:08 +0100907 if (urb->actual_length !=
908 sizeof(struct keyspan_usa67_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700909 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700910 return;
911 }
912
913
914 /* Now do something useful with the data */
915 msg = (struct keyspan_usa67_portStatusMessage *)data;
916
917 /* Check port number from message and retrieve private data */
918 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700919 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700920 return;
921 }
922
923 port = serial->port[msg->port];
924 p_priv = usb_get_serial_port_data(port);
925
926 /* Update handshaking pin state information */
927 old_dcd_state = p_priv->dcd_state;
928 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
929 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
930
Jiri Slabyaa27a092013-03-07 13:12:30 +0100931 if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
932 tty_port_tty_hangup(&port->port, true);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700933
934 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700935 err = usb_submit_urb(urb, GFP_ATOMIC);
936 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700937 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700938}
939
940static void usa67_glocont_callback(struct urb *urb)
941{
942 struct usb_serial *serial;
943 struct usb_serial_port *port;
944 struct keyspan_port_private *p_priv;
945 int i;
946
Lucy McCoy0ca12682007-05-18 12:10:41 -0700947 serial = urb->context;
948 for (i = 0; i < serial->num_ports; ++i) {
949 port = serial->port[i];
950 p_priv = usb_get_serial_port_data(port);
951
952 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700953 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700954 keyspan_usa67_send_setup(serial, port,
955 p_priv->resend_cont - 1);
956 break;
957 }
958 }
959}
960
Alan Cox95da3102008-07-22 11:09:07 +0100961static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
Alan Cox95da3102008-07-22 11:09:07 +0100963 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 struct keyspan_port_private *p_priv;
965 const struct keyspan_device_details *d_details;
966 int flip;
967 int data_len;
968 struct urb *this_urb;
969
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 p_priv = usb_get_serial_port_data(port);
971 d_details = p_priv->device_details;
972
Alan Coxa5b6f602008-04-08 17:16:06 +0100973 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +0100975 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 else
977 data_len = 63;
978
979 flip = p_priv->out_flip;
980
981 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +0100982 this_urb = p_priv->out_urbs[flip];
983 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +0100985 return data_len;
986 flip = (flip + 1) & d_details->outdat_endp_flip;
987 this_urb = p_priv->out_urbs[flip];
988 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +0100990 return data_len;
991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 }
Alan Coxa5b6f602008-04-08 17:16:06 +0100993 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994}
995
996
Alan Coxa509a7e2009-09-19 13:13:26 -0700997static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998{
Andrew Mortonf78ba152007-11-28 16:21:54 -0800999 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 const struct keyspan_device_details *d_details;
1001 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001002 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001004 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 p_priv = usb_get_serial_port_data(port);
1007 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001008
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 /* Set some sane defaults */
1010 p_priv->rts_state = 1;
1011 p_priv->dtr_state = 1;
1012 p_priv->baud = 9600;
1013
1014 /* force baud and lcr to be set on open */
1015 p_priv->old_baud = 0;
1016 p_priv->old_cflag = 0;
1017
1018 p_priv->out_flip = 0;
1019 p_priv->in_flip = 0;
1020
1021 /* Reset low level data toggle and start reading from endpoints */
1022 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001023 urb = p_priv->in_urbs[i];
1024 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
Alan Coxdeb91682008-07-22 11:13:08 +01001027 /* make sure endpoint data toggle is synchronized
1028 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001030 err = usb_submit_urb(urb, GFP_KERNEL);
1031 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001032 dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 }
1034
1035 /* Reset low level data toggle on out endpoints */
1036 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001037 urb = p_priv->out_urbs[i];
1038 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 continue;
Alan Coxdeb91682008-07-22 11:13:08 +01001040 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1041 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 }
1043
Andrew Mortonf78ba152007-11-28 16:21:54 -08001044 /* get the terminal config for the setup message now so we don't
1045 * need to send 2 of them */
1046
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001047 device_port = port->port_number;
Alan Cox95da3102008-07-22 11:09:07 +01001048 if (tty) {
Alan Coxadc8d742012-07-14 15:31:47 +01001049 cflag = tty->termios.c_cflag;
Alan Cox95da3102008-07-22 11:09:07 +01001050 /* Baud rate calculation takes baud rate as an integer
1051 so other rates can be generated if desired. */
1052 baud_rate = tty_get_baud_rate(tty);
1053 /* If no match or invalid, leave as default */
1054 if (baud_rate >= 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001055 && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Alan Cox95da3102008-07-22 11:09:07 +01001056 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1057 p_priv->baud = baud_rate;
1058 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001059 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001060 /* set CTS/RTS handshake etc. */
1061 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +10001062 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001063
1064 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001065 /* mdelay(100); */
1066 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001067
Alan Coxa5b6f602008-04-08 17:16:06 +01001068 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069}
1070
1071static inline void stop_urb(struct urb *urb)
1072{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001073 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075}
1076
Alan Cox335f8512009-06-11 12:26:29 +01001077static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1078{
1079 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1080
1081 p_priv->rts_state = on;
1082 p_priv->dtr_state = on;
1083 keyspan_send_setup(port, 0);
1084}
1085
1086static void keyspan_close(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087{
1088 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 struct keyspan_port_private *p_priv;
1090
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001092
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 p_priv->rts_state = 0;
1094 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001095
Johan Hovold80dfe0c2013-03-21 12:36:32 +01001096 keyspan_send_setup(port, 2);
1097 /* pilot-xfer seems to work best with this delay */
1098 mdelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
1100 p_priv->out_flip = 0;
1101 p_priv->in_flip = 0;
1102
Johan Hovold80dfe0c2013-03-21 12:36:32 +01001103 stop_urb(p_priv->inack_urb);
1104 for (i = 0; i < 2; i++) {
1105 stop_urb(p_priv->in_urbs[i]);
1106 stop_urb(p_priv->out_urbs[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108}
1109
Alan Coxdeb91682008-07-22 11:13:08 +01001110/* download the firmware to a pre-renumeration device */
1111static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112{
Rene Buergel8d733e22012-09-18 09:02:01 +02001113 char *fw_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001115 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
1116 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1117 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001118
1119 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1120 != 0x8000) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001121 dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n");
Alan Coxdeb91682008-07-22 11:13:08 +01001122 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 }
1124
1125 /* Select firmware image on the basis of idProduct */
1126 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1127 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001128 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 break;
1130
1131 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001132 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 break;
1134
1135 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001136 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 break;
1138
1139 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001140 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 break;
1142
1143 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001144 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001148 fw_name = "keyspan/usa19qi.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_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001152 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 break;
1154
1155 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001156 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001158
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001160 fw_name = "keyspan/usa18x.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_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001164 fw_name = "keyspan/usa19w.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_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001168 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 break;
1170
1171 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001172 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 break;
1174
1175 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001176 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1177 le16_to_cpu(serial->dev->descriptor.idProduct));
1178 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 }
1180
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001181 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182
Rene Buergel8d733e22012-09-18 09:02:01 +02001183 if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
1184 dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
1185 fw_name);
1186 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 }
1188
Rene Buergel8d733e22012-09-18 09:02:01 +02001189 /* after downloading firmware Renumeration will occur in a
1190 moment and the new device will bind to the real driver */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001193 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194}
1195
1196/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001197static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1198 int endpoint)
1199{
1200 struct usb_host_interface *iface_desc;
1201 struct usb_endpoint_descriptor *ep;
1202 int i;
1203
1204 iface_desc = serial->interface->cur_altsetting;
1205 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1206 ep = &iface_desc->endpoint[i].desc;
1207 if (ep->bEndpointAddress == endpoint)
1208 return ep;
1209 }
1210 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1211 "endpoint %x\n", endpoint);
1212 return NULL;
1213}
1214
Alan Coxdeb91682008-07-22 11:13:08 +01001215static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001217 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218{
1219 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001220 struct usb_endpoint_descriptor const *ep_desc;
1221 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
1223 if (endpoint == -1)
1224 return NULL; /* endpoint not needed */
1225
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001226 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
Johan Hovold10c642d2013-12-29 19:22:56 +01001228 if (!urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Lucy McCoy0ca12682007-05-18 12:10:41 -07001231 if (endpoint == 0) {
1232 /* control EP filled in when used */
1233 return urb;
1234 }
1235
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001236 ep_desc = find_ep(serial, endpoint);
1237 if (!ep_desc) {
1238 /* leak the urb, something's wrong and the callers don't care */
1239 return urb;
1240 }
1241 if (usb_endpoint_xfer_int(ep_desc)) {
1242 ep_type_name = "INT";
1243 usb_fill_int_urb(urb, serial->dev,
1244 usb_sndintpipe(serial->dev, endpoint) | dir,
1245 buf, len, callback, ctx,
1246 ep_desc->bInterval);
1247 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1248 ep_type_name = "BULK";
1249 usb_fill_bulk_urb(urb, serial->dev,
1250 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1251 buf, len, callback, ctx);
1252 } else {
1253 dev_warn(&serial->interface->dev,
1254 "unsupported endpoint type %x\n",
Julia Lawall2e0fe702008-12-29 11:22:14 +01001255 usb_endpoint_type(ep_desc));
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001256 usb_free_urb(urb);
1257 return NULL;
1258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001260 dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001261 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 return urb;
1263}
1264
1265static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001266 void (*instat_callback)(struct urb *);
1267 void (*glocont_callback)(struct urb *);
1268 void (*indat_callback)(struct urb *);
1269 void (*outdat_callback)(struct urb *);
1270 void (*inack_callback)(struct urb *);
1271 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272} keyspan_callbacks[] = {
1273 {
1274 /* msg_usa26 callbacks */
1275 .instat_callback = usa26_instat_callback,
1276 .glocont_callback = usa26_glocont_callback,
1277 .indat_callback = usa26_indat_callback,
1278 .outdat_callback = usa2x_outdat_callback,
1279 .inack_callback = usa26_inack_callback,
1280 .outcont_callback = usa26_outcont_callback,
1281 }, {
1282 /* msg_usa28 callbacks */
1283 .instat_callback = usa28_instat_callback,
1284 .glocont_callback = usa28_glocont_callback,
1285 .indat_callback = usa28_indat_callback,
1286 .outdat_callback = usa2x_outdat_callback,
1287 .inack_callback = usa28_inack_callback,
1288 .outcont_callback = usa28_outcont_callback,
1289 }, {
1290 /* msg_usa49 callbacks */
1291 .instat_callback = usa49_instat_callback,
1292 .glocont_callback = usa49_glocont_callback,
1293 .indat_callback = usa49_indat_callback,
1294 .outdat_callback = usa2x_outdat_callback,
1295 .inack_callback = usa49_inack_callback,
1296 .outcont_callback = usa49_outcont_callback,
1297 }, {
1298 /* msg_usa90 callbacks */
1299 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001300 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 .indat_callback = usa90_indat_callback,
1302 .outdat_callback = usa2x_outdat_callback,
1303 .inack_callback = usa28_inack_callback,
1304 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001305 }, {
1306 /* msg_usa67 callbacks */
1307 .instat_callback = usa67_instat_callback,
1308 .glocont_callback = usa67_glocont_callback,
1309 .indat_callback = usa26_indat_callback,
1310 .outdat_callback = usa2x_outdat_callback,
1311 .inack_callback = usa26_inack_callback,
1312 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 }
1314};
1315
1316 /* Generic setup urbs function that uses
1317 data in device_details */
1318static void keyspan_setup_urbs(struct usb_serial *serial)
1319{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 struct keyspan_serial_private *s_priv;
1321 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 struct callbacks *cback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 s_priv = usb_get_serial_data(serial);
1325 d_details = s_priv->device_details;
1326
Alan Coxdeb91682008-07-22 11:13:08 +01001327 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 cback = &keyspan_callbacks[d_details->msg_format];
1329
Alan Coxdeb91682008-07-22 11:13:08 +01001330 /* Allocate and set up urbs for each one that is in use,
1331 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 s_priv->instat_urb = keyspan_setup_urb
1333 (serial, d_details->instat_endpoint, USB_DIR_IN,
1334 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1335 cback->instat_callback);
1336
Lucy McCoy0ca12682007-05-18 12:10:41 -07001337 s_priv->indat_urb = keyspan_setup_urb
1338 (serial, d_details->indat_endpoint, USB_DIR_IN,
1339 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1340 usa49wg_indat_callback);
1341
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 s_priv->glocont_urb = keyspan_setup_urb
1343 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1344 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1345 cback->glocont_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346}
1347
1348/* usa19 function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001349static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1350 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 u8 *rate_low, u8 *prescaler, int portnum)
1352{
1353 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001354 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001357 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Alan Coxdeb91682008-07-22 11:13:08 +01001359 /* prevent divide by zero... */
1360 b16 = baud_rate * 16L;
1361 if (b16 == 0)
1362 return KEYSPAN_INVALID_BAUD_RATE;
1363 /* Any "standard" rate over 57k6 is marginal on the USA-19
1364 as we run out of divisor resolution. */
1365 if (baud_rate > 57600)
1366 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
Alan Coxdeb91682008-07-22 11:13:08 +01001368 /* calculate the divisor and the counter (its inverse) */
1369 div = baudclk / b16;
1370 if (div == 0)
1371 return KEYSPAN_INVALID_BAUD_RATE;
1372 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
Alan Coxdeb91682008-07-22 11:13:08 +01001375 if (div > 0xffff)
1376 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
Alan Coxdeb91682008-07-22 11:13:08 +01001378 /* return the counter values if non-null */
1379 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001381 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001383 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001384 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001385 __func__, baud_rate, *rate_hi, *rate_low);
1386 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387}
1388
1389/* usa19hs function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001390static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1391 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1392 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393{
1394 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001395 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001397 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Alan Coxdeb91682008-07-22 11:13:08 +01001399 /* prevent divide by zero... */
1400 b16 = baud_rate * 16L;
1401 if (b16 == 0)
1402 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
Alan Coxdeb91682008-07-22 11:13:08 +01001404 /* calculate the divisor */
1405 div = baudclk / b16;
1406 if (div == 0)
1407 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
Alan Coxdeb91682008-07-22 11:13:08 +01001409 if (div > 0xffff)
1410 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Alan Coxdeb91682008-07-22 11:13:08 +01001412 /* return the counter values if non-null */
1413 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001415
1416 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001418
1419 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001420 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001421 __func__, baud_rate, *rate_hi, *rate_low);
1422
1423 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424}
1425
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001426static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1427 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 u8 *rate_low, u8 *prescaler, int portnum)
1429{
1430 u32 b16, /* baud rate times 16 (actual rate used internally) */
1431 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001432 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 res, /* resulting baud rate using 13/8 prescaler */
1434 diff, /* error using 13/8 prescaler */
1435 smallest_diff;
1436 u8 best_prescaler;
1437 int i;
1438
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001439 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440
Alan Coxdeb91682008-07-22 11:13:08 +01001441 /* prevent divide by zero */
1442 b16 = baud_rate * 16L;
1443 if (b16 == 0)
1444 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
Alan Coxdeb91682008-07-22 11:13:08 +01001446 /* Calculate prescaler by trying them all and looking
1447 for best fit */
1448
1449 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 smallest_diff = 0xffffffff;
1451
1452 /* 0 is an invalid prescaler, used as a flag */
1453 best_prescaler = 0;
1454
Alan Coxdeb91682008-07-22 11:13:08 +01001455 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001457
1458 div = clk / b16;
1459 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
1462 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001463 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Alan Coxdeb91682008-07-22 11:13:08 +01001465 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 best_prescaler = i;
1467 smallest_diff = diff;
1468 }
1469 }
1470
Alan Coxdeb91682008-07-22 11:13:08 +01001471 if (best_prescaler == 0)
1472 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
1474 clk = (baudclk * 8) / (u32) best_prescaler;
1475 div = clk / b16;
1476
Alan Coxdeb91682008-07-22 11:13:08 +01001477 /* return the divisor and prescaler if non-null */
1478 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001480 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 if (prescaler) {
1483 *prescaler = best_prescaler;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001484 /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 }
Alan Coxdeb91682008-07-22 11:13:08 +01001486 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487}
1488
1489 /* USA-28 supports different maximum baud rates on each port */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001490static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1491 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1492 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
1494 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001495 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 cnt; /* inverse of divisor (programmed into 8051) */
1497
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001498 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499
1500 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001501 b16 = baud_rate * 16L;
1502 if (b16 == 0)
1503 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
Alan Coxdeb91682008-07-22 11:13:08 +01001505 /* calculate the divisor and the counter (its inverse) */
1506 div = KEYSPAN_USA28_BAUDCLK / b16;
1507 if (div == 0)
1508 return KEYSPAN_INVALID_BAUD_RATE;
1509 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
Alan Coxdeb91682008-07-22 11:13:08 +01001512 /* check for out of range, based on portnum,
1513 and return result */
1514 if (portnum == 0) {
1515 if (div > 0xffff)
1516 return KEYSPAN_INVALID_BAUD_RATE;
1517 } else {
1518 if (portnum == 1) {
1519 if (div > 0xff)
1520 return KEYSPAN_INVALID_BAUD_RATE;
1521 } else
1522 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 }
1524
1525 /* return the counter values if not NULL
1526 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001527 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001529 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001531 dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
Alan Coxdeb91682008-07-22 11:13:08 +01001532 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533}
1534
1535static int keyspan_usa26_send_setup(struct usb_serial *serial,
1536 struct usb_serial_port *port,
1537 int reset_port)
1538{
Alan Coxdeb91682008-07-22 11:13:08 +01001539 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 struct keyspan_serial_private *s_priv;
1541 struct keyspan_port_private *p_priv;
1542 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 struct urb *this_urb;
1544 int device_port, err;
1545
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001546 dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
1548 s_priv = usb_get_serial_data(serial);
1549 p_priv = usb_get_serial_port_data(port);
1550 d_details = s_priv->device_details;
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001551 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 this_urb = p_priv->outcont_urb;
1554
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001555 dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
1557 /* Make sure we have an urb then send the message */
1558 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001559 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 return -1;
1561 }
1562
1563 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001564 Don't overwrite resend for open/close condition. */
1565 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 p_priv->resend_cont = reset_port + 1;
1567 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001568 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001570 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 }
1572
Alan Coxdeb91682008-07-22 11:13:08 +01001573 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1574
1575 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 if (p_priv->old_baud != p_priv->baud) {
1577 p_priv->old_baud = p_priv->baud;
1578 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001579 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1580 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1581 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1582 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1583 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 msg.baudLo = 0;
1585 msg.baudHi = 125; /* Values for 9600 baud */
1586 msg.prescaler = 10;
1587 }
1588 msg.setPrescaler = 0xff;
1589 }
1590
Ben Minerds2b982ab2012-07-12 00:10:16 +10001591 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 switch (p_priv->cflag & CSIZE) {
1593 case CS5:
1594 msg.lcr |= USA_DATABITS_5;
1595 break;
1596 case CS6:
1597 msg.lcr |= USA_DATABITS_6;
1598 break;
1599 case CS7:
1600 msg.lcr |= USA_DATABITS_7;
1601 break;
1602 case CS8:
1603 msg.lcr |= USA_DATABITS_8;
1604 break;
1605 }
1606 if (p_priv->cflag & PARENB) {
1607 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001608 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001609 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 }
1611 msg.setLcr = 0xff;
1612
1613 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1614 msg.xonFlowControl = 0;
1615 msg.setFlowControl = 0xff;
1616 msg.forwardingLength = 16;
1617 msg.xonChar = 17;
1618 msg.xoffChar = 19;
1619
1620 /* Opening port */
1621 if (reset_port == 1) {
1622 msg._txOn = 1;
1623 msg._txOff = 0;
1624 msg.txFlush = 0;
1625 msg.txBreak = 0;
1626 msg.rxOn = 1;
1627 msg.rxOff = 0;
1628 msg.rxFlush = 1;
1629 msg.rxForward = 0;
1630 msg.returnStatus = 0;
1631 msg.resetDataToggle = 0xff;
1632 }
1633
1634 /* Closing port */
1635 else if (reset_port == 2) {
1636 msg._txOn = 0;
1637 msg._txOff = 1;
1638 msg.txFlush = 0;
1639 msg.txBreak = 0;
1640 msg.rxOn = 0;
1641 msg.rxOff = 1;
1642 msg.rxFlush = 1;
1643 msg.rxForward = 0;
1644 msg.returnStatus = 0;
1645 msg.resetDataToggle = 0;
1646 }
1647
1648 /* Sending intermediate configs */
1649 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001650 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 msg._txOff = 0;
1652 msg.txFlush = 0;
1653 msg.txBreak = (p_priv->break_on);
1654 msg.rxOn = 0;
1655 msg.rxOff = 0;
1656 msg.rxFlush = 0;
1657 msg.rxForward = 0;
1658 msg.returnStatus = 0;
1659 msg.resetDataToggle = 0x0;
1660 }
1661
Alan Coxdeb91682008-07-22 11:13:08 +01001662 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 msg.setTxTriState_setRts = 0xff;
1664 msg.txTriState_rts = p_priv->rts_state;
1665
1666 msg.setHskoa_setDtr = 0xff;
1667 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001668
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001670 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1671
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 /* send the data out the device on control endpoint */
1673 this_urb->transfer_buffer_length = sizeof(msg);
1674
Alan Coxdeb91682008-07-22 11:13:08 +01001675 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1676 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001677 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01001678 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679}
1680
1681static int keyspan_usa28_send_setup(struct usb_serial *serial,
1682 struct usb_serial_port *port,
1683 int reset_port)
1684{
Alan Coxdeb91682008-07-22 11:13:08 +01001685 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 struct keyspan_serial_private *s_priv;
1687 struct keyspan_port_private *p_priv;
1688 const struct keyspan_device_details *d_details;
1689 struct urb *this_urb;
1690 int device_port, err;
1691
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 s_priv = usb_get_serial_data(serial);
1693 p_priv = usb_get_serial_port_data(port);
1694 d_details = s_priv->device_details;
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001695 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001698 this_urb = p_priv->outcont_urb;
1699 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001700 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 return -1;
1702 }
1703
1704 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001705 Don't overwrite resend for open/close condition. */
1706 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 p_priv->resend_cont = reset_port + 1;
1708 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001709 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001711 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 }
1713
Alan Coxdeb91682008-07-22 11:13:08 +01001714 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715
1716 msg.setBaudRate = 1;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001717 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1718 &msg.baudHi, &msg.baudLo, NULL,
1719 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1720 dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001721 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 msg.baudLo = 0xff;
1723 msg.baudHi = 0xb2; /* Values for 9600 baud */
1724 }
1725
1726 /* If parity is enabled, we must calculate it ourselves. */
1727 msg.parity = 0; /* XXX for now */
1728
1729 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1730 msg.xonFlowControl = 0;
1731
Alan Coxdeb91682008-07-22 11:13:08 +01001732 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 msg.rts = p_priv->rts_state;
1734 msg.dtr = p_priv->dtr_state;
1735
1736 msg.forwardingLength = 16;
1737 msg.forwardMs = 10;
1738 msg.breakThreshold = 45;
1739 msg.xonChar = 17;
1740 msg.xoffChar = 19;
1741
1742 /*msg.returnStatus = 1;
1743 msg.resetDataToggle = 0xff;*/
1744 /* Opening port */
1745 if (reset_port == 1) {
1746 msg._txOn = 1;
1747 msg._txOff = 0;
1748 msg.txFlush = 0;
1749 msg.txForceXoff = 0;
1750 msg.txBreak = 0;
1751 msg.rxOn = 1;
1752 msg.rxOff = 0;
1753 msg.rxFlush = 1;
1754 msg.rxForward = 0;
1755 msg.returnStatus = 0;
1756 msg.resetDataToggle = 0xff;
1757 }
1758 /* Closing port */
1759 else if (reset_port == 2) {
1760 msg._txOn = 0;
1761 msg._txOff = 1;
1762 msg.txFlush = 0;
1763 msg.txForceXoff = 0;
1764 msg.txBreak = 0;
1765 msg.rxOn = 0;
1766 msg.rxOff = 1;
1767 msg.rxFlush = 1;
1768 msg.rxForward = 0;
1769 msg.returnStatus = 0;
1770 msg.resetDataToggle = 0;
1771 }
1772 /* Sending intermediate configs */
1773 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001774 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 msg._txOff = 0;
1776 msg.txFlush = 0;
1777 msg.txForceXoff = 0;
1778 msg.txBreak = (p_priv->break_on);
1779 msg.rxOn = 0;
1780 msg.rxOff = 0;
1781 msg.rxFlush = 0;
1782 msg.rxForward = 0;
1783 msg.returnStatus = 0;
1784 msg.resetDataToggle = 0x0;
1785 }
1786
1787 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001788 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789
1790 /* send the data out the device on control endpoint */
1791 this_urb->transfer_buffer_length = sizeof(msg);
1792
Alan Coxdeb91682008-07-22 11:13:08 +01001793 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1794 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001795 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796#if 0
1797 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001798 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 this_urb->transfer_buffer_length);
1800 }
1801#endif
1802
Alan Coxa5b6f602008-04-08 17:16:06 +01001803 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804}
1805
1806static int keyspan_usa49_send_setup(struct usb_serial *serial,
1807 struct usb_serial_port *port,
1808 int reset_port)
1809{
Lucy McCoy0ca12682007-05-18 12:10:41 -07001810 struct keyspan_usa49_portControlMessage msg;
1811 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 struct keyspan_serial_private *s_priv;
1813 struct keyspan_port_private *p_priv;
1814 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 struct urb *this_urb;
1816 int err, device_port;
1817
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 s_priv = usb_get_serial_data(serial);
1819 p_priv = usb_get_serial_port_data(port);
1820 d_details = s_priv->device_details;
1821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 this_urb = s_priv->glocont_urb;
1823
Lucy McCoy0ca12682007-05-18 12:10:41 -07001824 /* Work out which port within the device is being setup */
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001825 device_port = port->port_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301827 /* Make sure we have an urb then send the message */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 if (this_urb == NULL) {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001829 dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 return -1;
1831 }
1832
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001833 dev_dbg(&port->dev, "%s - endpoint %d (%d)\n",
1834 __func__, usb_pipeendpoint(this_urb->pipe), device_port);
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301835
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001837 Don't overwrite resend for open/close condition. */
1838 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001840
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001842 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001844 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 }
1846
Alan Coxdeb91682008-07-22 11:13:08 +01001847 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01001850
1851 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 if (p_priv->old_baud != p_priv->baud) {
1853 p_priv->old_baud = p_priv->baud;
1854 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001855 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1856 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1857 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1858 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1859 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 msg.baudLo = 0;
1861 msg.baudHi = 125; /* Values for 9600 baud */
1862 msg.prescaler = 10;
1863 }
Alan Coxdeb91682008-07-22 11:13:08 +01001864 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 }
1866
Ben Minerds2b982ab2012-07-12 00:10:16 +10001867 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 switch (p_priv->cflag & CSIZE) {
1869 case CS5:
1870 msg.lcr |= USA_DATABITS_5;
1871 break;
1872 case CS6:
1873 msg.lcr |= USA_DATABITS_6;
1874 break;
1875 case CS7:
1876 msg.lcr |= USA_DATABITS_7;
1877 break;
1878 case CS8:
1879 msg.lcr |= USA_DATABITS_8;
1880 break;
1881 }
1882 if (p_priv->cflag & PARENB) {
1883 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001884 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001885 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 }
1887 msg.setLcr = 0xff;
1888
1889 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1890 msg.xonFlowControl = 0;
1891 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01001892
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 msg.forwardingLength = 16;
1894 msg.xonChar = 17;
1895 msg.xoffChar = 19;
1896
Alan Coxdeb91682008-07-22 11:13:08 +01001897 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 if (reset_port == 1) {
1899 msg._txOn = 1;
1900 msg._txOff = 0;
1901 msg.txFlush = 0;
1902 msg.txBreak = 0;
1903 msg.rxOn = 1;
1904 msg.rxOff = 0;
1905 msg.rxFlush = 1;
1906 msg.rxForward = 0;
1907 msg.returnStatus = 0;
1908 msg.resetDataToggle = 0xff;
1909 msg.enablePort = 1;
1910 msg.disablePort = 0;
1911 }
1912 /* Closing port */
1913 else if (reset_port == 2) {
1914 msg._txOn = 0;
1915 msg._txOff = 1;
1916 msg.txFlush = 0;
1917 msg.txBreak = 0;
1918 msg.rxOn = 0;
1919 msg.rxOff = 1;
1920 msg.rxFlush = 1;
1921 msg.rxForward = 0;
1922 msg.returnStatus = 0;
1923 msg.resetDataToggle = 0;
1924 msg.enablePort = 0;
1925 msg.disablePort = 1;
1926 }
1927 /* Sending intermediate configs */
1928 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001929 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 msg._txOff = 0;
1931 msg.txFlush = 0;
1932 msg.txBreak = (p_priv->break_on);
1933 msg.rxOn = 0;
1934 msg.rxOff = 0;
1935 msg.rxFlush = 0;
1936 msg.rxForward = 0;
1937 msg.returnStatus = 0;
1938 msg.resetDataToggle = 0x0;
1939 msg.enablePort = 0;
1940 msg.disablePort = 0;
1941 }
1942
Alan Coxdeb91682008-07-22 11:13:08 +01001943 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 msg.setRts = 0xff;
1945 msg.rts = p_priv->rts_state;
1946
1947 msg.setDtr = 0xff;
1948 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001949
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951
Alan Coxdeb91682008-07-22 11:13:08 +01001952 /* if the device is a 49wg, we send control message on usb
1953 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07001954
1955 if (d_details->product_id == keyspan_usa49wg_product_id) {
1956 dr = (void *)(s_priv->ctrl_buf);
1957 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
1958 dr->bRequest = 0xB0; /* 49wg control message */;
1959 dr->wValue = 0;
1960 dr->wIndex = 0;
1961 dr->wLength = cpu_to_le16(sizeof(msg));
1962
Alan Coxdeb91682008-07-22 11:13:08 +01001963 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07001964
Alan Coxdeb91682008-07-22 11:13:08 +01001965 usb_fill_control_urb(this_urb, serial->dev,
1966 usb_sndctrlpipe(serial->dev, 0),
1967 (unsigned char *)dr, s_priv->glocont_buf,
1968 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001969
1970 } else {
1971 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01001972
Lucy McCoy0ca12682007-05-18 12:10:41 -07001973 /* send the data out the device on control endpoint */
1974 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001975 }
Alan Coxdeb91682008-07-22 11:13:08 +01001976 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1977 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001978 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979#if 0
1980 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001981 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__,
1982 outcont_urb, this_urb->transfer_buffer_length,
1983 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 }
1985#endif
1986
Alan Coxa5b6f602008-04-08 17:16:06 +01001987 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988}
1989
1990static int keyspan_usa90_send_setup(struct usb_serial *serial,
1991 struct usb_serial_port *port,
1992 int reset_port)
1993{
Alan Coxdeb91682008-07-22 11:13:08 +01001994 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 struct keyspan_serial_private *s_priv;
1996 struct keyspan_port_private *p_priv;
1997 const struct keyspan_device_details *d_details;
1998 struct urb *this_urb;
1999 int err;
2000 u8 prescaler;
2001
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 s_priv = usb_get_serial_data(serial);
2003 p_priv = usb_get_serial_port_data(port);
2004 d_details = s_priv->device_details;
2005
2006 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002007 this_urb = p_priv->outcont_urb;
2008 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002009 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 return -1;
2011 }
2012
2013 /* Save reset port val for resend.
2014 Don't overwrite resend for open/close condition. */
2015 if ((reset_port + 1) > p_priv->resend_cont)
2016 p_priv->resend_cont = reset_port + 1;
2017 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002018 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002020 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 }
2022
Alan Coxdeb91682008-07-22 11:13:08 +01002023 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024
Alan Coxdeb91682008-07-22 11:13:08 +01002025 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 if (p_priv->old_baud != p_priv->baud) {
2027 p_priv->old_baud = p_priv->baud;
2028 msg.setClocking = 0x01;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002029 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2030 &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2031 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2032 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 p_priv->baud = 9600;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002034 d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2036 }
2037 msg.setRxMode = 1;
2038 msg.setTxMode = 1;
2039 }
2040
2041 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002042 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 msg.rxMode = RXMODE_DMA;
2044 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002045 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 msg.rxMode = RXMODE_BYHAND;
2047 msg.txMode = TXMODE_BYHAND;
2048 }
2049
Ben Minerds2b982ab2012-07-12 00:10:16 +10002050 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 switch (p_priv->cflag & CSIZE) {
2052 case CS5:
2053 msg.lcr |= USA_DATABITS_5;
2054 break;
2055 case CS6:
2056 msg.lcr |= USA_DATABITS_6;
2057 break;
2058 case CS7:
2059 msg.lcr |= USA_DATABITS_7;
2060 break;
2061 case CS8:
2062 msg.lcr |= USA_DATABITS_8;
2063 break;
2064 }
2065 if (p_priv->cflag & PARENB) {
2066 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002067 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002068 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 }
2070 if (p_priv->old_cflag != p_priv->cflag) {
2071 p_priv->old_cflag = p_priv->cflag;
2072 msg.setLcr = 0x01;
2073 }
2074
2075 if (p_priv->flow_control == flow_cts)
2076 msg.txFlowControl = TXFLOW_CTS;
2077 msg.setTxFlowControl = 0x01;
2078 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002079
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002081 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 msg.txAckSetting = 0;
2083 msg.xonChar = 17;
2084 msg.xoffChar = 19;
2085
Alan Coxdeb91682008-07-22 11:13:08 +01002086 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 if (reset_port == 1) {
2088 msg.portEnabled = 1;
2089 msg.rxFlush = 1;
2090 msg.txBreak = (p_priv->break_on);
2091 }
2092 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002093 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 /* Sending intermediate configs */
2096 else {
Alan Stern1f871582010-02-17 10:05:47 -05002097 msg.portEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 msg.txBreak = (p_priv->break_on);
2099 }
2100
Alan Coxdeb91682008-07-22 11:13:08 +01002101 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 msg.setRts = 0x01;
2103 msg.rts = p_priv->rts_state;
2104
2105 msg.setDtr = 0x01;
2106 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002107
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002109 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2110
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 /* send the data out the device on control endpoint */
2112 this_urb->transfer_buffer_length = sizeof(msg);
2113
Alan Coxdeb91682008-07-22 11:13:08 +01002114 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2115 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002116 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002117 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118}
2119
Lucy McCoy0ca12682007-05-18 12:10:41 -07002120static int keyspan_usa67_send_setup(struct usb_serial *serial,
2121 struct usb_serial_port *port,
2122 int reset_port)
2123{
2124 struct keyspan_usa67_portControlMessage msg;
2125 struct keyspan_serial_private *s_priv;
2126 struct keyspan_port_private *p_priv;
2127 const struct keyspan_device_details *d_details;
2128 struct urb *this_urb;
2129 int err, device_port;
2130
Lucy McCoy0ca12682007-05-18 12:10:41 -07002131 s_priv = usb_get_serial_data(serial);
2132 p_priv = usb_get_serial_port_data(port);
2133 d_details = s_priv->device_details;
2134
2135 this_urb = s_priv->glocont_urb;
2136
2137 /* Work out which port within the device is being setup */
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002138 device_port = port->port_number;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002139
2140 /* Make sure we have an urb then send the message */
2141 if (this_urb == NULL) {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002142 dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002143 return -1;
2144 }
2145
2146 /* Save reset port val for resend.
2147 Don't overwrite resend for open/close condition. */
2148 if ((reset_port + 1) > p_priv->resend_cont)
2149 p_priv->resend_cont = reset_port + 1;
2150 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002151 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002152 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002153 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002154 }
2155
2156 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2157
2158 msg.port = device_port;
2159
2160 /* Only set baud rate if it's changed */
2161 if (p_priv->old_baud != p_priv->baud) {
2162 p_priv->old_baud = p_priv->baud;
2163 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002164 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2165 &msg.baudHi, &msg.baudLo, &msg.prescaler,
2166 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2167 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2168 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002169 msg.baudLo = 0;
2170 msg.baudHi = 125; /* Values for 9600 baud */
2171 msg.prescaler = 10;
2172 }
2173 msg.setPrescaler = 0xff;
2174 }
2175
2176 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2177 switch (p_priv->cflag & CSIZE) {
2178 case CS5:
2179 msg.lcr |= USA_DATABITS_5;
2180 break;
2181 case CS6:
2182 msg.lcr |= USA_DATABITS_6;
2183 break;
2184 case CS7:
2185 msg.lcr |= USA_DATABITS_7;
2186 break;
2187 case CS8:
2188 msg.lcr |= USA_DATABITS_8;
2189 break;
2190 }
2191 if (p_priv->cflag & PARENB) {
2192 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002193 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002194 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002195 }
2196 msg.setLcr = 0xff;
2197
2198 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2199 msg.xonFlowControl = 0;
2200 msg.setFlowControl = 0xff;
2201 msg.forwardingLength = 16;
2202 msg.xonChar = 17;
2203 msg.xoffChar = 19;
2204
2205 if (reset_port == 1) {
2206 /* Opening port */
2207 msg._txOn = 1;
2208 msg._txOff = 0;
2209 msg.txFlush = 0;
2210 msg.txBreak = 0;
2211 msg.rxOn = 1;
2212 msg.rxOff = 0;
2213 msg.rxFlush = 1;
2214 msg.rxForward = 0;
2215 msg.returnStatus = 0;
2216 msg.resetDataToggle = 0xff;
2217 } else if (reset_port == 2) {
2218 /* Closing port */
2219 msg._txOn = 0;
2220 msg._txOff = 1;
2221 msg.txFlush = 0;
2222 msg.txBreak = 0;
2223 msg.rxOn = 0;
2224 msg.rxOff = 1;
2225 msg.rxFlush = 1;
2226 msg.rxForward = 0;
2227 msg.returnStatus = 0;
2228 msg.resetDataToggle = 0;
2229 } else {
2230 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002231 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002232 msg._txOff = 0;
2233 msg.txFlush = 0;
2234 msg.txBreak = (p_priv->break_on);
2235 msg.rxOn = 0;
2236 msg.rxOff = 0;
2237 msg.rxFlush = 0;
2238 msg.rxForward = 0;
2239 msg.returnStatus = 0;
2240 msg.resetDataToggle = 0x0;
2241 }
2242
2243 /* Do handshaking outputs */
2244 msg.setTxTriState_setRts = 0xff;
2245 msg.txTriState_rts = p_priv->rts_state;
2246
2247 msg.setHskoa_setDtr = 0xff;
2248 msg.hskoa_dtr = p_priv->dtr_state;
2249
2250 p_priv->resend_cont = 0;
2251
2252 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2253
2254 /* send the data out the device on control endpoint */
2255 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002256
2257 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2258 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002259 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002260 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002261}
2262
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2264{
2265 struct usb_serial *serial = port->serial;
2266 struct keyspan_serial_private *s_priv;
2267 const struct keyspan_device_details *d_details;
2268
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 s_priv = usb_get_serial_data(serial);
2270 d_details = s_priv->device_details;
2271
2272 switch (d_details->msg_format) {
2273 case msg_usa26:
2274 keyspan_usa26_send_setup(serial, port, reset_port);
2275 break;
2276 case msg_usa28:
2277 keyspan_usa28_send_setup(serial, port, reset_port);
2278 break;
2279 case msg_usa49:
2280 keyspan_usa49_send_setup(serial, port, reset_port);
2281 break;
2282 case msg_usa90:
2283 keyspan_usa90_send_setup(serial, port, reset_port);
2284 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002285 case msg_usa67:
2286 keyspan_usa67_send_setup(serial, port, reset_port);
2287 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 }
2289}
2290
2291
2292/* Gets called by the "real" driver (ie once firmware is loaded
2293 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002294static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295{
2296 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 const struct keyspan_device_details *d_details;
2299
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002301 if (d_details->product_id ==
2302 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 break;
2304 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002305 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2306 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Johan Hovoldff8a43c2013-08-13 13:27:35 +02002307 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 }
2309
2310 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002311 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Johan Hovold10c642d2013-12-29 19:22:56 +01002312 if (!s_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
Johan Hovold2fcd1c92013-08-13 13:27:36 +02002315 s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);
2316 if (!s_priv->instat_buf)
2317 goto err_instat_buf;
2318
2319 s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL);
2320 if (!s_priv->indat_buf)
2321 goto err_indat_buf;
2322
2323 s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL);
2324 if (!s_priv->glocont_buf)
2325 goto err_glocont_buf;
2326
2327 s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
2328 if (!s_priv->ctrl_buf)
2329 goto err_ctrl_buf;
2330
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 s_priv->device_details = d_details;
2332 usb_set_serial_data(serial, s_priv);
2333
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 keyspan_setup_urbs(serial);
2335
Lucy McCoy0ca12682007-05-18 12:10:41 -07002336 if (s_priv->instat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002337 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2338 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002339 dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002340 }
2341 if (s_priv->indat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002342 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2343 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002344 dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 }
Alan Coxdeb91682008-07-22 11:13:08 +01002346
Alan Coxa5b6f602008-04-08 17:16:06 +01002347 return 0;
Johan Hovold2fcd1c92013-08-13 13:27:36 +02002348
2349err_ctrl_buf:
2350 kfree(s_priv->glocont_buf);
2351err_glocont_buf:
2352 kfree(s_priv->indat_buf);
2353err_indat_buf:
2354 kfree(s_priv->instat_buf);
2355err_instat_buf:
2356 kfree(s_priv);
2357
2358 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359}
2360
Alan Sternf9c99bb2009-06-02 11:53:55 -04002361static void keyspan_disconnect(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002363 struct keyspan_serial_private *s_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 s_priv = usb_get_serial_data(serial);
2366
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 stop_urb(s_priv->instat_urb);
2368 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002369 stop_urb(s_priv->indat_urb);
Alan Sternf9c99bb2009-06-02 11:53:55 -04002370}
2371
2372static void keyspan_release(struct usb_serial *serial)
2373{
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002374 struct keyspan_serial_private *s_priv;
Alan Sternf9c99bb2009-06-02 11:53:55 -04002375
Alan Sternf9c99bb2009-06-02 11:53:55 -04002376 s_priv = usb_get_serial_data(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002378 usb_free_urb(s_priv->instat_urb);
2379 usb_free_urb(s_priv->indat_urb);
2380 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381
Johan Hovold2fcd1c92013-08-13 13:27:36 +02002382 kfree(s_priv->ctrl_buf);
2383 kfree(s_priv->glocont_buf);
2384 kfree(s_priv->indat_buf);
2385 kfree(s_priv->instat_buf);
2386
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002387 kfree(s_priv);
2388}
2389
2390static int keyspan_port_probe(struct usb_serial_port *port)
2391{
2392 struct usb_serial *serial = port->serial;
Bjørn Morkf0e3e352012-11-10 10:13:42 +01002393 struct keyspan_serial_private *s_priv;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002394 struct keyspan_port_private *p_priv;
2395 const struct keyspan_device_details *d_details;
2396 struct callbacks *cback;
2397 int endp;
2398 int port_num;
2399 int i;
2400
2401 s_priv = usb_get_serial_data(serial);
2402 d_details = s_priv->device_details;
2403
2404 p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL);
2405 if (!p_priv)
2406 return -ENOMEM;
2407
Johan Hovoldbad41a52013-08-13 13:27:37 +02002408 for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
2409 p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
2410 if (!p_priv->in_buffer[i])
2411 goto err_in_buffer;
2412 }
2413
2414 for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
2415 p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
2416 if (!p_priv->out_buffer[i])
2417 goto err_out_buffer;
2418 }
2419
2420 p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
2421 if (!p_priv->inack_buffer)
2422 goto err_inack_buffer;
2423
2424 p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
2425 if (!p_priv->outcont_buffer)
2426 goto err_outcont_buffer;
2427
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002428 p_priv->device_details = d_details;
2429
2430 /* Setup values for the various callback routines */
2431 cback = &keyspan_callbacks[d_details->msg_format];
2432
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002433 port_num = port->port_number;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002434
2435 /* Do indat endpoints first, once for each flip */
2436 endp = d_details->indat_endpoints[port_num];
2437 for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
2438 p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
2439 USB_DIR_IN, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002440 p_priv->in_buffer[i],
2441 IN_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002442 cback->indat_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 }
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002444 /* outdat endpoints also have flip */
2445 endp = d_details->outdat_endpoints[port_num];
2446 for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
2447 p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
2448 USB_DIR_OUT, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002449 p_priv->out_buffer[i],
2450 OUT_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002451 cback->outdat_callback);
2452 }
2453 /* inack endpoint */
2454 p_priv->inack_urb = keyspan_setup_urb(serial,
2455 d_details->inack_endpoints[port_num],
2456 USB_DIR_IN, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002457 p_priv->inack_buffer,
2458 INACK_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002459 cback->inack_callback);
2460 /* outcont endpoint */
2461 p_priv->outcont_urb = keyspan_setup_urb(serial,
2462 d_details->outcont_endpoints[port_num],
2463 USB_DIR_OUT, port,
Johan Hovoldbad41a52013-08-13 13:27:37 +02002464 p_priv->outcont_buffer,
2465 OUTCONT_BUFLEN,
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002466 cback->outcont_callback);
2467
2468 usb_set_serial_port_data(port, p_priv);
2469
2470 return 0;
Johan Hovoldbad41a52013-08-13 13:27:37 +02002471
2472err_outcont_buffer:
2473 kfree(p_priv->inack_buffer);
2474err_inack_buffer:
2475 for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
2476 kfree(p_priv->out_buffer[i]);
2477err_out_buffer:
2478 for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
2479 kfree(p_priv->in_buffer[i]);
2480err_in_buffer:
2481 kfree(p_priv);
2482
2483 return -ENOMEM;
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002484}
2485
2486static int keyspan_port_remove(struct usb_serial_port *port)
2487{
2488 struct keyspan_port_private *p_priv;
2489 int i;
2490
2491 p_priv = usb_get_serial_port_data(port);
2492
2493 stop_urb(p_priv->inack_urb);
2494 stop_urb(p_priv->outcont_urb);
2495 for (i = 0; i < 2; i++) {
2496 stop_urb(p_priv->in_urbs[i]);
2497 stop_urb(p_priv->out_urbs[i]);
2498 }
2499
2500 usb_free_urb(p_priv->inack_urb);
2501 usb_free_urb(p_priv->outcont_urb);
2502 for (i = 0; i < 2; i++) {
2503 usb_free_urb(p_priv->in_urbs[i]);
2504 usb_free_urb(p_priv->out_urbs[i]);
2505 }
2506
Johan Hovoldbad41a52013-08-13 13:27:37 +02002507 kfree(p_priv->outcont_buffer);
2508 kfree(p_priv->inack_buffer);
2509 for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
2510 kfree(p_priv->out_buffer[i]);
2511 for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
2512 kfree(p_priv->in_buffer[i]);
2513
Johan Hovoldf79b2d02012-10-25 10:29:15 +02002514 kfree(p_priv);
2515
2516 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517}
2518
Alan Coxdeb91682008-07-22 11:13:08 +01002519MODULE_AUTHOR(DRIVER_AUTHOR);
2520MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521MODULE_LICENSE("GPL");
2522
David Woodhouse2971c572008-05-30 14:04:03 +03002523MODULE_FIRMWARE("keyspan/usa28.fw");
2524MODULE_FIRMWARE("keyspan/usa28x.fw");
2525MODULE_FIRMWARE("keyspan/usa28xa.fw");
2526MODULE_FIRMWARE("keyspan/usa28xb.fw");
2527MODULE_FIRMWARE("keyspan/usa19.fw");
2528MODULE_FIRMWARE("keyspan/usa19qi.fw");
2529MODULE_FIRMWARE("keyspan/mpr.fw");
2530MODULE_FIRMWARE("keyspan/usa19qw.fw");
2531MODULE_FIRMWARE("keyspan/usa18x.fw");
2532MODULE_FIRMWARE("keyspan/usa19w.fw");
2533MODULE_FIRMWARE("keyspan/usa49w.fw");
2534MODULE_FIRMWARE("keyspan/usa49wlc.fw");