blob: 1635f5062f002bcaa400e4446fdb1d29b30e6dea [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 Keyspan USB to Serial Converter driver
Alan Coxdeb91682008-07-22 11:13:08 +01003
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 (C) Copyright (C) 2000-2001 Hugh Blemings <hugh@blemings.org>
5 (C) Copyright (C) 2002 Greg Kroah-Hartman <greg@kroah.com>
Alan Coxdeb91682008-07-22 11:13:08 +01006
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
Justin P. Mattock631dd1a2010-10-18 11:03:14 +020012 See http://blemings.org/hugh/keyspan.html for more information.
Alan Coxdeb91682008-07-22 11:13:08 +010013
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 Code in this driver inspired by and in a number of places taken
15 from Brian Warner's original Keyspan-PDA driver.
16
17 This driver has been put together with the support of Innosys, Inc.
18 and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
19 Thanks Guys :)
Alan Coxdeb91682008-07-22 11:13:08 +010020
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 Thanks to Paulus for miscellaneous tidy ups, some largish chunks
22 of much nicer and/or completely new code and (perhaps most uniquely)
23 having the patience to sit down and explain why and where he'd changed
Alan Coxdeb91682008-07-22 11:13:08 +010024 stuff.
25
26 Tip 'o the hat to IBM (and previously Linuxcare :) for supporting
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 staff in their work on open source projects.
Linus Torvalds1da177e2005-04-16 15:20:36 -070028*/
29
30
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/kernel.h>
32#include <linux/jiffies.h>
33#include <linux/errno.h>
34#include <linux/init.h>
35#include <linux/slab.h>
36#include <linux/tty.h>
37#include <linux/tty_driver.h>
38#include <linux/tty_flip.h>
39#include <linux/module.h>
40#include <linux/spinlock.h>
David Woodhouse2971c572008-05-30 14:04:03 +030041#include <linux/firmware.h>
42#include <linux/ihex.h>
Alan Coxdeb91682008-07-22 11:13:08 +010043#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070045#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include "keyspan.h"
47
Rusty Russell90ab5ee2012-01-13 09:32:20 +103048static bool debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50/*
51 * Version Information
52 */
Lucy McCoy0ca12682007-05-18 12:10:41 -070053#define DRIVER_VERSION "v1.1.5"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
55#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
56
57#define INSTAT_BUFLEN 32
58#define GLOCONT_BUFLEN 64
Lucy McCoy0ca12682007-05-18 12:10:41 -070059#define INDAT49W_BUFLEN 512
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
61 /* Per device and per port private data */
62struct keyspan_serial_private {
63 const struct keyspan_device_details *device_details;
64
65 struct urb *instat_urb;
66 char instat_buf[INSTAT_BUFLEN];
67
Alan Coxdeb91682008-07-22 11:13:08 +010068 /* added to support 49wg, where data from all 4 ports comes in
69 on 1 EP and high-speed supported */
Lucy McCoy0ca12682007-05-18 12:10:41 -070070 struct urb *indat_urb;
71 char indat_buf[INDAT49W_BUFLEN];
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 /* XXX this one probably will need a lock */
74 struct urb *glocont_urb;
75 char glocont_buf[GLOCONT_BUFLEN];
Alan Coxdeb91682008-07-22 11:13:08 +010076 char ctrl_buf[8]; /* for EP0 control message */
Linus Torvalds1da177e2005-04-16 15:20:36 -070077};
78
79struct keyspan_port_private {
80 /* Keep track of which input & output endpoints to use */
81 int in_flip;
82 int out_flip;
83
84 /* Keep duplicate of device details in each port
85 structure as well - simplifies some of the
86 callback functions etc. */
87 const struct keyspan_device_details *device_details;
88
89 /* Input endpoints and buffer for this port */
90 struct urb *in_urbs[2];
91 char in_buffer[2][64];
92 /* Output endpoints and buffer for this port */
93 struct urb *out_urbs[2];
94 char out_buffer[2][64];
95
96 /* Input ack endpoint */
97 struct urb *inack_urb;
98 char inack_buffer[1];
99
100 /* Output control endpoint */
101 struct urb *outcont_urb;
102 char outcont_buffer[64];
103
104 /* Settings for the port */
105 int baud;
106 int old_baud;
107 unsigned int cflag;
108 unsigned int old_cflag;
109 enum {flow_none, flow_cts, flow_xon} flow_control;
110 int rts_state; /* Handshaking pins (outputs) */
111 int dtr_state;
112 int cts_state; /* Handshaking pins (inputs) */
113 int dsr_state;
114 int dcd_state;
115 int ri_state;
116 int break_on;
117
118 unsigned long tx_start_time[2];
119 int resend_cont; /* need to resend control packet */
120};
121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122/* Include Keyspan message headers. All current Keyspan Adapters
Lucy McCoy0ca12682007-05-18 12:10:41 -0700123 make use of one of five message formats which are referred
Alan Coxdeb91682008-07-22 11:13:08 +0100124 to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and
125 within this driver. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126#include "keyspan_usa26msg.h"
127#include "keyspan_usa28msg.h"
128#include "keyspan_usa49msg.h"
129#include "keyspan_usa90msg.h"
Lucy McCoy0ca12682007-05-18 12:10:41 -0700130#include "keyspan_usa67msg.h"
Alan Coxdeb91682008-07-22 11:13:08 +0100131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -0700133module_usb_serial_driver(serial_drivers, keyspan_ids_combined);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Alan Cox95da3102008-07-22 11:09:07 +0100135static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136{
Alan Cox95da3102008-07-22 11:09:07 +0100137 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 struct keyspan_port_private *p_priv;
139
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 p_priv = usb_get_serial_port_data(port);
141
142 if (break_state == -1)
143 p_priv->break_on = 1;
144 else
145 p_priv->break_on = 0;
146
147 keyspan_send_setup(port, 0);
148}
149
150
Alan Coxdeb91682008-07-22 11:13:08 +0100151static void keyspan_set_termios(struct tty_struct *tty,
Alan Cox95da3102008-07-22 11:09:07 +0100152 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153{
154 int baud_rate, device_port;
155 struct keyspan_port_private *p_priv;
156 const struct keyspan_device_details *d_details;
157 unsigned int cflag;
158
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 p_priv = usb_get_serial_port_data(port);
160 d_details = p_priv->device_details;
Alan Cox74240b02007-10-18 01:24:20 -0700161 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 device_port = port->number - port->serial->minor;
163
164 /* Baud rate calculation takes baud rate as an integer
165 so other rates can be generated if desired. */
Alan Cox74240b02007-10-18 01:24:20 -0700166 baud_rate = tty_get_baud_rate(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100167 /* If no match or invalid, don't change */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700168 if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
170 /* FIXME - more to do here to ensure rate changes cleanly */
Alan Cox74240b02007-10-18 01:24:20 -0700171 /* FIXME - calcuate exact rate from divisor ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 p_priv->baud = baud_rate;
Alan Cox74240b02007-10-18 01:24:20 -0700173 } else
174 baud_rate = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
Alan Cox74240b02007-10-18 01:24:20 -0700176 tty_encode_baud_rate(tty, baud_rate, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 /* set CTS/RTS handshake etc. */
178 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +1000179 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Alan Cox74240b02007-10-18 01:24:20 -0700181 /* Mark/Space not supported */
182 tty->termios->c_cflag &= ~CMSPAR;
183
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 keyspan_send_setup(port, 0);
185}
186
Alan Cox60b33c12011-02-14 16:26:14 +0000187static int keyspan_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188{
Alan Cox95da3102008-07-22 11:09:07 +0100189 struct usb_serial_port *port = tty->driver_data;
190 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 unsigned int value;
Alan Coxdeb91682008-07-22 11:13:08 +0100192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
194 ((p_priv->dtr_state) ? TIOCM_DTR : 0) |
195 ((p_priv->cts_state) ? TIOCM_CTS : 0) |
196 ((p_priv->dsr_state) ? TIOCM_DSR : 0) |
197 ((p_priv->dcd_state) ? TIOCM_CAR : 0) |
Alan Coxdeb91682008-07-22 11:13:08 +0100198 ((p_priv->ri_state) ? TIOCM_RNG : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200 return value;
201}
202
Alan Cox20b9d172011-02-14 16:26:50 +0000203static int keyspan_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 unsigned int set, unsigned int clear)
205{
Alan Cox95da3102008-07-22 11:09:07 +0100206 struct usb_serial_port *port = tty->driver_data;
207 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 if (set & TIOCM_RTS)
210 p_priv->rts_state = 1;
211 if (set & TIOCM_DTR)
212 p_priv->dtr_state = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 if (clear & TIOCM_RTS)
214 p_priv->rts_state = 0;
215 if (clear & TIOCM_DTR)
216 p_priv->dtr_state = 0;
217 keyspan_send_setup(port, 0);
218 return 0;
219}
220
Alan Cox95da3102008-07-22 11:09:07 +0100221/* Write function is similar for the four protocols used
222 with only a minor change for usa90 (usa19hs) required */
223static int keyspan_write(struct tty_struct *tty,
224 struct usb_serial_port *port, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225{
226 struct keyspan_port_private *p_priv;
227 const struct keyspan_device_details *d_details;
228 int flip;
229 int left, todo;
230 struct urb *this_urb;
Alan Coxdeb91682008-07-22 11:13:08 +0100231 int err, maxDataLen, dataOffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 p_priv = usb_get_serial_port_data(port);
234 d_details = p_priv->device_details;
235
236 if (d_details->msg_format == msg_usa90) {
Alan Coxdeb91682008-07-22 11:13:08 +0100237 maxDataLen = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 dataOffset = 0;
239 } else {
240 maxDataLen = 63;
241 dataOffset = 1;
242 }
Alan Coxdeb91682008-07-22 11:13:08 +0100243
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700244 dev_dbg(&port->dev, "%s - for port %d (%d chars), flip=%d\n",
245 __func__, port->number, count, p_priv->out_flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
247 for (left = count; left > 0; left -= todo) {
248 todo = left;
249 if (todo > maxDataLen)
250 todo = maxDataLen;
251
252 flip = p_priv->out_flip;
Alan Coxdeb91682008-07-22 11:13:08 +0100253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 /* Check we have a valid urb/endpoint before we use it... */
Alan Coxdeb91682008-07-22 11:13:08 +0100255 this_urb = p_priv->out_urbs[flip];
256 if (this_urb == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 /* no bulk out, so return 0 bytes written */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700258 dev_dbg(&port->dev, "%s - no output urb :(\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 return count;
260 }
261
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700262 dev_dbg(&port->dev, "%s - endpoint %d flip %d\n",
Alan Coxdeb91682008-07-22 11:13:08 +0100263 __func__, usb_pipeendpoint(this_urb->pipe), flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +0100266 if (time_before(jiffies,
267 p_priv->tx_start_time[flip] + 10 * HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 usb_unlink_urb(this_urb);
270 break;
271 }
272
Alan Coxdeb91682008-07-22 11:13:08 +0100273 /* First byte in buffer is "last flag" (except for usa19hx)
274 - unused so for now so set to zero */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 ((char *)this_urb->transfer_buffer)[0] = 0;
276
Alan Coxdeb91682008-07-22 11:13:08 +0100277 memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 buf += todo;
279
280 /* send the data out the bulk port */
281 this_urb->transfer_buffer_length = todo + dataOffset;
282
Alan Coxdeb91682008-07-22 11:13:08 +0100283 err = usb_submit_urb(this_urb, GFP_ATOMIC);
284 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700285 dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 p_priv->tx_start_time[flip] = jiffies;
287
288 /* Flip for next time if usa26 or usa28 interface
289 (not used on usa49) */
290 p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
291 }
292
293 return count - left;
294}
295
David Howells7d12e782006-10-05 14:55:46 +0100296static void usa26_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297{
298 int i, err;
299 int endpoint;
300 struct usb_serial_port *port;
301 struct tty_struct *tty;
302 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700303 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 endpoint = usb_pipeendpoint(urb->pipe);
306
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700307 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700308 dev_dbg(&urb->dev->dev,"%s - nonzero status: %x on endpoint %d.\n",
309 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 return;
311 }
312
Ming Leicdc97792008-02-24 18:41:47 +0800313 port = urb->context;
Alan Cox4a90f092008-10-13 10:39:46 +0100314 tty = tty_port_tty_get(&port->port);
Alan Coxa5569a52008-01-21 17:18:24 -0800315 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 /* 0x80 bit is error flag */
317 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100318 /* no errors on individual bytes, only
319 possible overrun err */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100321 err = TTY_OVERRUN;
322 else
323 err = 0;
324 for (i = 1; i < urb->actual_length ; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 tty_insert_flip_char(tty, data[i], err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 } else {
327 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700328 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 for (i = 0; i + 1 < urb->actual_length; i += 2) {
330 int stat = data[i], flag = 0;
331 if (stat & RXERROR_OVERRUN)
332 flag |= TTY_OVERRUN;
333 if (stat & RXERROR_FRAMING)
334 flag |= TTY_FRAME;
335 if (stat & RXERROR_PARITY)
336 flag |= TTY_PARITY;
337 /* XXX should handle break (0x10) */
338 tty_insert_flip_char(tty, data[i+1], flag);
339 }
340 }
341 tty_flip_buffer_push(tty);
342 }
Alan Cox4a90f092008-10-13 10:39:46 +0100343 tty_kref_put(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100344
345 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500346 err = usb_submit_urb(urb, GFP_ATOMIC);
347 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700348 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349}
350
Alan Coxdeb91682008-07-22 11:13:08 +0100351/* Outdat handling is common for all devices */
David Howells7d12e782006-10-05 14:55:46 +0100352static void usa2x_outdat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
354 struct usb_serial_port *port;
355 struct keyspan_port_private *p_priv;
356
Ming Leicdc97792008-02-24 18:41:47 +0800357 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 p_priv = usb_get_serial_port_data(port);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700359 dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Alan Stern1f871582010-02-17 10:05:47 -0500361 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
David Howells7d12e782006-10-05 14:55:46 +0100364static void usa26_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366}
367
David Howells7d12e782006-10-05 14:55:46 +0100368static void usa26_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
370 struct usb_serial_port *port;
371 struct keyspan_port_private *p_priv;
372
Ming Leicdc97792008-02-24 18:41:47 +0800373 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 p_priv = usb_get_serial_port_data(port);
375
376 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700377 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100378 keyspan_usa26_send_setup(port->serial, port,
379 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
381}
382
David Howells7d12e782006-10-05 14:55:46 +0100383static void usa26_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 unsigned char *data = urb->transfer_buffer;
386 struct keyspan_usa26_portStatusMessage *msg;
387 struct usb_serial *serial;
388 struct usb_serial_port *port;
389 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100390 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700392 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Ming Leicdc97792008-02-24 18:41:47 +0800394 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700396 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700397 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 return;
399 }
400 if (urb->actual_length != 9) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700401 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 goto exit;
403 }
404
405 msg = (struct keyspan_usa26_portStatusMessage *)data;
406
407#if 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700408 dev_dbg(&urb->dev->dev,
409 "%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
410 __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr,
411 msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled,
412 msg->controlResponse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413#endif
414
415 /* Now do something useful with the data */
416
417
Alan Coxdeb91682008-07-22 11:13:08 +0100418 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700420 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 goto exit;
422 }
423 port = serial->port[msg->port];
424 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100425
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 /* Update handshaking pin state information */
427 old_dcd_state = p_priv->dcd_state;
428 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
429 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
430 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
431 p_priv->ri_state = ((msg->ri) ? 1 : 0);
432
Alan Cox4a90f092008-10-13 10:39:46 +0100433 if (old_dcd_state != p_priv->dcd_state) {
434 tty = tty_port_tty_get(&port->port);
435 if (tty && !C_CLOCAL(tty))
436 tty_hangup(tty);
437 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 }
Alan Coxdeb91682008-07-22 11:13:08 +0100439
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100441 err = usb_submit_urb(urb, GFP_ATOMIC);
442 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700443 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444exit: ;
445}
446
David Howells7d12e782006-10-05 14:55:46 +0100447static void usa26_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449}
450
451
David Howells7d12e782006-10-05 14:55:46 +0100452static void usa28_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453{
Alan Coxf035a8a2008-07-22 11:13:32 +0100454 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 struct usb_serial_port *port;
456 struct tty_struct *tty;
457 unsigned char *data;
458 struct keyspan_port_private *p_priv;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700459 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Ming Leicdc97792008-02-24 18:41:47 +0800461 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 p_priv = usb_get_serial_port_data(port);
463 data = urb->transfer_buffer;
464
465 if (urb != p_priv->in_urbs[p_priv->in_flip])
466 return;
467
468 do {
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700469 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700470 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
471 __func__, status, usb_pipeendpoint(urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 return;
473 }
474
Ming Leicdc97792008-02-24 18:41:47 +0800475 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 p_priv = usb_get_serial_port_data(port);
477 data = urb->transfer_buffer;
478
Ben Minerds40adac82012-07-12 00:10:17 +1000479 tty = tty_port_tty_get(&port->port);
Alan Cox4a90f092008-10-13 10:39:46 +0100480 if (tty && urb->actual_length) {
Alan Coxf035a8a2008-07-22 11:13:32 +0100481 tty_insert_flip_string(tty, data, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 tty_flip_buffer_push(tty);
483 }
Alan Cox4a90f092008-10-13 10:39:46 +0100484 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500487 err = usb_submit_urb(urb, GFP_ATOMIC);
488 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700489 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
Alan Stern1f871582010-02-17 10:05:47 -0500490 __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 p_priv->in_flip ^= 1;
492
493 urb = p_priv->in_urbs[p_priv->in_flip];
494 } while (urb->status != -EINPROGRESS);
495}
496
David Howells7d12e782006-10-05 14:55:46 +0100497static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499}
500
David Howells7d12e782006-10-05 14:55:46 +0100501static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
503 struct usb_serial_port *port;
504 struct keyspan_port_private *p_priv;
505
Ming Leicdc97792008-02-24 18:41:47 +0800506 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 p_priv = usb_get_serial_port_data(port);
508
509 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700510 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100511 keyspan_usa28_send_setup(port->serial, port,
512 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 }
514}
515
David Howells7d12e782006-10-05 14:55:46 +0100516static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
518 int err;
519 unsigned char *data = urb->transfer_buffer;
520 struct keyspan_usa28_portStatusMessage *msg;
521 struct usb_serial *serial;
522 struct usb_serial_port *port;
523 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100524 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700526 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Ming Leicdc97792008-02-24 18:41:47 +0800528 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700530 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700531 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 return;
533 }
534
535 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700536 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 goto exit;
538 }
539
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700540 /*
541 dev_dbg(&urb->dev->dev,
542 "%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__,
543 data[0], data[1], data[2], data[3], data[4], data[5],
544 data[6], data[7], data[8], data[9], data[10], data[11]);
545 */
Alan Coxdeb91682008-07-22 11:13:08 +0100546
547 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 msg = (struct keyspan_usa28_portStatusMessage *)data;
549
Alan Coxdeb91682008-07-22 11:13:08 +0100550 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700552 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 goto exit;
554 }
555 port = serial->port[msg->port];
556 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100557
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 /* Update handshaking pin state information */
559 old_dcd_state = p_priv->dcd_state;
560 p_priv->cts_state = ((msg->cts) ? 1 : 0);
561 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
562 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
563 p_priv->ri_state = ((msg->ri) ? 1 : 0);
564
Ben Minerdsddc04ae2012-07-12 00:10:18 +1000565 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
Alan Cox4a90f092008-10-13 10:39:46 +0100566 tty = tty_port_tty_get(&port->port);
Ben Minerds878b5fd2012-07-12 00:10:19 +1000567 if (tty && !C_CLOCAL(tty))
Alan Cox4a90f092008-10-13 10:39:46 +0100568 tty_hangup(tty);
569 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 }
571
572 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100573 err = usb_submit_urb(urb, GFP_ATOMIC);
574 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700575 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576exit: ;
577}
578
David Howells7d12e782006-10-05 14:55:46 +0100579static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581}
582
583
David Howells7d12e782006-10-05 14:55:46 +0100584static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
586 struct usb_serial *serial;
587 struct usb_serial_port *port;
588 struct keyspan_port_private *p_priv;
589 int i;
590
Ming Leicdc97792008-02-24 18:41:47 +0800591 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 for (i = 0; i < serial->num_ports; ++i) {
593 port = serial->port[i];
594 p_priv = usb_get_serial_port_data(port);
595
596 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700597 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100598 keyspan_usa49_send_setup(serial, port,
599 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 break;
601 }
602 }
603}
604
605 /* This is actually called glostat in the Keyspan
606 doco */
David Howells7d12e782006-10-05 14:55:46 +0100607static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
609 int err;
610 unsigned char *data = urb->transfer_buffer;
611 struct keyspan_usa49_portStatusMessage *msg;
612 struct usb_serial *serial;
613 struct usb_serial_port *port;
614 struct keyspan_port_private *p_priv;
615 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700616 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Ming Leicdc97792008-02-24 18:41:47 +0800618 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700620 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700621 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 return;
623 }
624
Alan Coxdeb91682008-07-22 11:13:08 +0100625 if (urb->actual_length !=
626 sizeof(struct keyspan_usa49_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700627 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 goto exit;
629 }
630
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700631 /*
632 dev_dbg(&urb->dev->dev, "%s: %x %x %x %x %x %x %x %x %x %x %x",
633 __func__, data[0], data[1], data[2], data[3], data[4],
634 data[5], data[6], data[7], data[8], data[9], data[10]);
635 */
Alan Coxdeb91682008-07-22 11:13:08 +0100636
637 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 msg = (struct keyspan_usa49_portStatusMessage *)data;
639
Alan Coxdeb91682008-07-22 11:13:08 +0100640 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 if (msg->portNumber >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700642 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
643 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 goto exit;
645 }
646 port = serial->port[msg->portNumber];
647 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 /* Update handshaking pin state information */
650 old_dcd_state = p_priv->dcd_state;
651 p_priv->cts_state = ((msg->cts) ? 1 : 0);
652 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
653 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
654 p_priv->ri_state = ((msg->ri) ? 1 : 0);
655
Alan Cox4a90f092008-10-13 10:39:46 +0100656 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
657 struct tty_struct *tty = tty_port_tty_get(&port->port);
658 if (tty && !C_CLOCAL(tty))
659 tty_hangup(tty);
660 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 }
662
Alan Coxdeb91682008-07-22 11:13:08 +0100663 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100664 err = usb_submit_urb(urb, GFP_ATOMIC);
665 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700666 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667exit: ;
668}
669
David Howells7d12e782006-10-05 14:55:46 +0100670static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672}
673
David Howells7d12e782006-10-05 14:55:46 +0100674static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
676 int i, err;
677 int endpoint;
678 struct usb_serial_port *port;
679 struct tty_struct *tty;
680 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700681 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 endpoint = usb_pipeendpoint(urb->pipe);
684
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700685 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700686 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
687 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 return;
689 }
690
Ming Leicdc97792008-02-24 18:41:47 +0800691 port = urb->context;
Alan Cox4a90f092008-10-13 10:39:46 +0100692 tty = tty_port_tty_get(&port->port);
Alan Cox3004e532008-01-03 16:59:04 +0000693 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 /* 0x80 bit is error flag */
695 if ((data[0] & 0x80) == 0) {
696 /* no error on any byte */
Alan Coxf035a8a2008-07-22 11:13:32 +0100697 tty_insert_flip_string(tty, data + 1,
698 urb->actual_length - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 } else {
700 /* some bytes had errors, every byte has status */
701 for (i = 0; i + 1 < urb->actual_length; i += 2) {
702 int stat = data[i], flag = 0;
703 if (stat & RXERROR_OVERRUN)
704 flag |= TTY_OVERRUN;
705 if (stat & RXERROR_FRAMING)
706 flag |= TTY_FRAME;
707 if (stat & RXERROR_PARITY)
708 flag |= TTY_PARITY;
709 /* XXX should handle break (0x10) */
710 tty_insert_flip_char(tty, data[i+1], flag);
711 }
712 }
713 tty_flip_buffer_push(tty);
714 }
Alan Cox4a90f092008-10-13 10:39:46 +0100715 tty_kref_put(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100716
717 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500718 err = usb_submit_urb(urb, GFP_ATOMIC);
719 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700720 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721}
722
Lucy McCoy0ca12682007-05-18 12:10:41 -0700723static void usa49wg_indat_callback(struct urb *urb)
724{
725 int i, len, x, err;
726 struct usb_serial *serial;
727 struct usb_serial_port *port;
728 struct tty_struct *tty;
729 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700730 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700731
Lucy McCoy0ca12682007-05-18 12:10:41 -0700732 serial = urb->context;
733
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700734 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700735 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700736 return;
737 }
738
739 /* inbound data is in the form P#, len, status, data */
740 i = 0;
741 len = 0;
742
743 if (urb->actual_length) {
744 while (i < urb->actual_length) {
745
746 /* Check port number from message*/
747 if (data[i] >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700748 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800749 __func__, data[i]);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700750 return;
751 }
752 port = serial->port[data[i++]];
Alan Cox4a90f092008-10-13 10:39:46 +0100753 tty = tty_port_tty_get(&port->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700754 len = data[i++];
755
756 /* 0x80 bit is error flag */
757 if ((data[i] & 0x80) == 0) {
758 /* no error on any byte */
759 i++;
760 for (x = 1; x < len ; ++x)
Alan Stern1f871582010-02-17 10:05:47 -0500761 tty_insert_flip_char(tty, data[i++], 0);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700762 } else {
763 /*
764 * some bytes had errors, every byte has status
765 */
766 for (x = 0; x + 1 < len; x += 2) {
767 int stat = data[i], flag = 0;
768 if (stat & RXERROR_OVERRUN)
769 flag |= TTY_OVERRUN;
770 if (stat & RXERROR_FRAMING)
771 flag |= TTY_FRAME;
772 if (stat & RXERROR_PARITY)
773 flag |= TTY_PARITY;
774 /* XXX should handle break (0x10) */
Alan Stern1f871582010-02-17 10:05:47 -0500775 tty_insert_flip_char(tty,
Lucy McCoy0ca12682007-05-18 12:10:41 -0700776 data[i+1], flag);
777 i += 2;
778 }
779 }
Alan Stern1f871582010-02-17 10:05:47 -0500780 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100781 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700782 }
783 }
784
785 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700786 err = usb_submit_urb(urb, GFP_ATOMIC);
787 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700788 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700789}
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700792static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794}
795
Lucy McCoy0ca12682007-05-18 12:10:41 -0700796static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797{
798 int i, err;
799 int endpoint;
800 struct usb_serial_port *port;
801 struct keyspan_port_private *p_priv;
802 struct tty_struct *tty;
803 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700804 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 endpoint = usb_pipeendpoint(urb->pipe);
807
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700808 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700809 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800810 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 return;
812 }
813
Ming Leicdc97792008-02-24 18:41:47 +0800814 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 p_priv = usb_get_serial_port_data(port);
816
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 if (urb->actual_length) {
Alan Cox4a90f092008-10-13 10:39:46 +0100818 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100820 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
Alan Coxf035a8a2008-07-22 11:13:32 +0100822 if (p_priv->baud > 57600)
823 tty_insert_flip_string(tty, data, urb->actual_length);
824 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 /* 0x80 bit is error flag */
826 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100827 /* no errors on individual bytes, only
828 possible overrun err*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100830 err = TTY_OVERRUN;
831 else
832 err = 0;
833 for (i = 1; i < urb->actual_length ; ++i)
834 tty_insert_flip_char(tty, data[i],
835 err);
836 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700838 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 for (i = 0; i + 1 < urb->actual_length; i += 2) {
840 int stat = data[i], flag = 0;
841 if (stat & RXERROR_OVERRUN)
842 flag |= TTY_OVERRUN;
843 if (stat & RXERROR_FRAMING)
844 flag |= TTY_FRAME;
845 if (stat & RXERROR_PARITY)
846 flag |= TTY_PARITY;
847 /* XXX should handle break (0x10) */
Alan Coxdeb91682008-07-22 11:13:08 +0100848 tty_insert_flip_char(tty, data[i+1],
849 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 }
851 }
852 }
853 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100854 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 }
Alan Coxdeb91682008-07-22 11:13:08 +0100856
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500858 err = usb_submit_urb(urb, GFP_ATOMIC);
859 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700860 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861}
862
863
David Howells7d12e782006-10-05 14:55:46 +0100864static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865{
866 unsigned char *data = urb->transfer_buffer;
867 struct keyspan_usa90_portStatusMessage *msg;
868 struct usb_serial *serial;
869 struct usb_serial_port *port;
870 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100871 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700873 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Ming Leicdc97792008-02-24 18:41:47 +0800875 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700877 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700878 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 return;
880 }
881 if (urb->actual_length < 14) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700882 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 goto exit;
884 }
885
886 msg = (struct keyspan_usa90_portStatusMessage *)data;
887
888 /* Now do something useful with the data */
889
890 port = serial->port[0];
891 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 /* Update handshaking pin state information */
894 old_dcd_state = p_priv->dcd_state;
895 p_priv->cts_state = ((msg->cts) ? 1 : 0);
896 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
897 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
898 p_priv->ri_state = ((msg->ri) ? 1 : 0);
899
Alan Cox4a90f092008-10-13 10:39:46 +0100900 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
901 tty = tty_port_tty_get(&port->port);
902 if (tty && !C_CLOCAL(tty))
903 tty_hangup(tty);
904 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
Alan Coxdeb91682008-07-22 11:13:08 +0100906
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100908 err = usb_submit_urb(urb, GFP_ATOMIC);
909 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700910 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911exit:
912 ;
913}
914
David Howells7d12e782006-10-05 14:55:46 +0100915static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916{
917 struct usb_serial_port *port;
918 struct keyspan_port_private *p_priv;
919
Ming Leicdc97792008-02-24 18:41:47 +0800920 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 p_priv = usb_get_serial_port_data(port);
922
923 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700924 dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100925 keyspan_usa90_send_setup(port->serial, port,
926 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 }
928}
929
Lucy McCoy0ca12682007-05-18 12:10:41 -0700930/* Status messages from the 28xg */
931static void usa67_instat_callback(struct urb *urb)
932{
933 int err;
934 unsigned char *data = urb->transfer_buffer;
935 struct keyspan_usa67_portStatusMessage *msg;
936 struct usb_serial *serial;
937 struct usb_serial_port *port;
938 struct keyspan_port_private *p_priv;
939 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700940 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700941
Lucy McCoy0ca12682007-05-18 12:10:41 -0700942 serial = urb->context;
943
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700944 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700945 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700946 return;
947 }
948
Alan Coxdeb91682008-07-22 11:13:08 +0100949 if (urb->actual_length !=
950 sizeof(struct keyspan_usa67_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700951 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700952 return;
953 }
954
955
956 /* Now do something useful with the data */
957 msg = (struct keyspan_usa67_portStatusMessage *)data;
958
959 /* Check port number from message and retrieve private data */
960 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700961 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700962 return;
963 }
964
965 port = serial->port[msg->port];
966 p_priv = usb_get_serial_port_data(port);
967
968 /* Update handshaking pin state information */
969 old_dcd_state = p_priv->dcd_state;
970 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
971 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
972
Alan Cox4a90f092008-10-13 10:39:46 +0100973 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
974 struct tty_struct *tty = tty_port_tty_get(&port->port);
975 if (tty && !C_CLOCAL(tty))
976 tty_hangup(tty);
977 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700978 }
979
980 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700981 err = usb_submit_urb(urb, GFP_ATOMIC);
982 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700983 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700984}
985
986static void usa67_glocont_callback(struct urb *urb)
987{
988 struct usb_serial *serial;
989 struct usb_serial_port *port;
990 struct keyspan_port_private *p_priv;
991 int i;
992
Lucy McCoy0ca12682007-05-18 12:10:41 -0700993 serial = urb->context;
994 for (i = 0; i < serial->num_ports; ++i) {
995 port = serial->port[i];
996 p_priv = usb_get_serial_port_data(port);
997
998 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700999 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -07001000 keyspan_usa67_send_setup(serial, port,
1001 p_priv->resend_cont - 1);
1002 break;
1003 }
1004 }
1005}
1006
Alan Cox95da3102008-07-22 11:09:07 +01001007static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008{
Alan Cox95da3102008-07-22 11:09:07 +01001009 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 struct keyspan_port_private *p_priv;
1011 const struct keyspan_device_details *d_details;
1012 int flip;
1013 int data_len;
1014 struct urb *this_urb;
1015
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 p_priv = usb_get_serial_port_data(port);
1017 d_details = p_priv->device_details;
1018
Alan Coxa5b6f602008-04-08 17:16:06 +01001019 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +01001021 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 else
1023 data_len = 63;
1024
1025 flip = p_priv->out_flip;
1026
1027 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +01001028 this_urb = p_priv->out_urbs[flip];
1029 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001031 return data_len;
1032 flip = (flip + 1) & d_details->outdat_endp_flip;
1033 this_urb = p_priv->out_urbs[flip];
1034 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001036 return data_len;
1037 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 }
Alan Coxa5b6f602008-04-08 17:16:06 +01001039 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040}
1041
1042
Alan Coxa509a7e2009-09-19 13:13:26 -07001043static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001045 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 const struct keyspan_device_details *d_details;
1047 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001048 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001050 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 p_priv = usb_get_serial_port_data(port);
1053 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001054
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 /* Set some sane defaults */
1056 p_priv->rts_state = 1;
1057 p_priv->dtr_state = 1;
1058 p_priv->baud = 9600;
1059
1060 /* force baud and lcr to be set on open */
1061 p_priv->old_baud = 0;
1062 p_priv->old_cflag = 0;
1063
1064 p_priv->out_flip = 0;
1065 p_priv->in_flip = 0;
1066
1067 /* Reset low level data toggle and start reading from endpoints */
1068 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001069 urb = p_priv->in_urbs[i];
1070 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Alan Coxdeb91682008-07-22 11:13:08 +01001073 /* make sure endpoint data toggle is synchronized
1074 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001076 err = usb_submit_urb(urb, GFP_KERNEL);
1077 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001078 dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 }
1080
1081 /* Reset low level data toggle on out endpoints */
1082 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001083 urb = p_priv->out_urbs[i];
1084 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 continue;
Alan Coxdeb91682008-07-22 11:13:08 +01001086 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1087 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 }
1089
Andrew Mortonf78ba152007-11-28 16:21:54 -08001090 /* get the terminal config for the setup message now so we don't
1091 * need to send 2 of them */
1092
Andrew Mortonf78ba152007-11-28 16:21:54 -08001093 device_port = port->number - port->serial->minor;
Alan Cox95da3102008-07-22 11:09:07 +01001094 if (tty) {
1095 cflag = tty->termios->c_cflag;
1096 /* Baud rate calculation takes baud rate as an integer
1097 so other rates can be generated if desired. */
1098 baud_rate = tty_get_baud_rate(tty);
1099 /* If no match or invalid, leave as default */
1100 if (baud_rate >= 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001101 && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Alan Cox95da3102008-07-22 11:09:07 +01001102 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1103 p_priv->baud = baud_rate;
1104 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001105 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001106 /* set CTS/RTS handshake etc. */
1107 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +10001108 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001109
1110 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001111 /* mdelay(100); */
1112 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001113
Alan Coxa5b6f602008-04-08 17:16:06 +01001114 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115}
1116
1117static inline void stop_urb(struct urb *urb)
1118{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001119 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121}
1122
Alan Cox335f8512009-06-11 12:26:29 +01001123static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1124{
1125 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1126
1127 p_priv->rts_state = on;
1128 p_priv->dtr_state = on;
1129 keyspan_send_setup(port, 0);
1130}
1131
1132static void keyspan_close(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133{
1134 int i;
1135 struct usb_serial *serial = port->serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 struct keyspan_port_private *p_priv;
1137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001139
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 p_priv->rts_state = 0;
1141 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 if (serial->dev) {
1144 keyspan_send_setup(port, 2);
1145 /* pilot-xfer seems to work best with this delay */
1146 mdelay(100);
Alan Coxdeb91682008-07-22 11:13:08 +01001147 /* keyspan_set_termios(port, NULL); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149
1150 /*while (p_priv->outcont_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001151 dev_dbg(&port->dev, "%s - urb in progress\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }*/
1153
1154 p_priv->out_flip = 0;
1155 p_priv->in_flip = 0;
1156
1157 if (serial->dev) {
1158 /* Stop reading/writing urbs */
1159 stop_urb(p_priv->inack_urb);
1160 /* stop_urb(p_priv->outcont_urb); */
1161 for (i = 0; i < 2; i++) {
1162 stop_urb(p_priv->in_urbs[i]);
1163 stop_urb(p_priv->out_urbs[i]);
1164 }
1165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166}
1167
Alan Coxdeb91682008-07-22 11:13:08 +01001168/* download the firmware to a pre-renumeration device */
1169static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170{
1171 int response;
David Woodhouse2971c572008-05-30 14:04:03 +03001172 const struct ihex_binrec *record;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 char *fw_name;
David Woodhouse2971c572008-05-30 14:04:03 +03001174 const struct firmware *fw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001176 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
1177 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1178 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001179
1180 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1181 != 0x8000) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001182 dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n");
Alan Coxdeb91682008-07-22 11:13:08 +01001183 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 }
1185
1186 /* Select firmware image on the basis of idProduct */
1187 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1188 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001189 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 break;
1191
1192 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001193 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 break;
1195
1196 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001197 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 break;
1199
1200 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001201 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 break;
1203
1204 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001205 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001207
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001209 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001211
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001213 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 break;
1215
1216 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001217 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001219
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001221 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001223
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001225 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001229 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 break;
1231
1232 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001233 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 break;
1235
1236 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001237 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1238 le16_to_cpu(serial->dev->descriptor.idProduct));
1239 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 }
1241
David Woodhouse2971c572008-05-30 14:04:03 +03001242 if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 dev_err(&serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name);
Ben Minerdsf9943c22012-07-12 00:10:20 +10001244 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 }
1246
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001247 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
1249 /* download the firmware image */
Rene Buergel99495c72012-09-13 22:14:38 +02001250 response = ezusb_set_reset(serial->dev, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
David Woodhouse2971c572008-05-30 14:04:03 +03001252 record = (const struct ihex_binrec *)fw->data;
1253
1254 while (record) {
Rene Buergel99495c72012-09-13 22:14:38 +02001255 response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 (unsigned char *)record->data,
David Woodhouse2971c572008-05-30 14:04:03 +03001257 be16_to_cpu(record->len), 0xa0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 if (response < 0) {
Alan Coxdeb91682008-07-22 11:13:08 +01001259 dev_err(&serial->dev->dev, "ezusb_writememory failed for Keyspan firmware (%d %04X %p %d)\n",
David Woodhouse2971c572008-05-30 14:04:03 +03001260 response, be32_to_cpu(record->addr),
1261 record->data, be16_to_cpu(record->len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 break;
1263 }
David Woodhouse2971c572008-05-30 14:04:03 +03001264 record = ihex_next_binrec(record);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 }
David Woodhouse2971c572008-05-30 14:04:03 +03001266 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 /* bring device out of reset. Renumeration will occur in a
1268 moment and the new device will bind to the real driver */
Rene Buergel99495c72012-09-13 22:14:38 +02001269 response = ezusb_set_reset(serial->dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
1271 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001272 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273}
1274
1275/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001276static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1277 int endpoint)
1278{
1279 struct usb_host_interface *iface_desc;
1280 struct usb_endpoint_descriptor *ep;
1281 int i;
1282
1283 iface_desc = serial->interface->cur_altsetting;
1284 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1285 ep = &iface_desc->endpoint[i].desc;
1286 if (ep->bEndpointAddress == endpoint)
1287 return ep;
1288 }
1289 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1290 "endpoint %x\n", endpoint);
1291 return NULL;
1292}
1293
Alan Coxdeb91682008-07-22 11:13:08 +01001294static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001296 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297{
1298 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001299 struct usb_endpoint_descriptor const *ep_desc;
1300 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
1302 if (endpoint == -1)
1303 return NULL; /* endpoint not needed */
1304
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001305 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
1307 if (urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001308 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d failed.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 return NULL;
1310 }
1311
Lucy McCoy0ca12682007-05-18 12:10:41 -07001312 if (endpoint == 0) {
1313 /* control EP filled in when used */
1314 return urb;
1315 }
1316
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001317 ep_desc = find_ep(serial, endpoint);
1318 if (!ep_desc) {
1319 /* leak the urb, something's wrong and the callers don't care */
1320 return urb;
1321 }
1322 if (usb_endpoint_xfer_int(ep_desc)) {
1323 ep_type_name = "INT";
1324 usb_fill_int_urb(urb, serial->dev,
1325 usb_sndintpipe(serial->dev, endpoint) | dir,
1326 buf, len, callback, ctx,
1327 ep_desc->bInterval);
1328 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1329 ep_type_name = "BULK";
1330 usb_fill_bulk_urb(urb, serial->dev,
1331 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1332 buf, len, callback, ctx);
1333 } else {
1334 dev_warn(&serial->interface->dev,
1335 "unsupported endpoint type %x\n",
Julia Lawall2e0fe702008-12-29 11:22:14 +01001336 usb_endpoint_type(ep_desc));
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001337 usb_free_urb(urb);
1338 return NULL;
1339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001341 dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001342 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 return urb;
1344}
1345
1346static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001347 void (*instat_callback)(struct urb *);
1348 void (*glocont_callback)(struct urb *);
1349 void (*indat_callback)(struct urb *);
1350 void (*outdat_callback)(struct urb *);
1351 void (*inack_callback)(struct urb *);
1352 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353} keyspan_callbacks[] = {
1354 {
1355 /* msg_usa26 callbacks */
1356 .instat_callback = usa26_instat_callback,
1357 .glocont_callback = usa26_glocont_callback,
1358 .indat_callback = usa26_indat_callback,
1359 .outdat_callback = usa2x_outdat_callback,
1360 .inack_callback = usa26_inack_callback,
1361 .outcont_callback = usa26_outcont_callback,
1362 }, {
1363 /* msg_usa28 callbacks */
1364 .instat_callback = usa28_instat_callback,
1365 .glocont_callback = usa28_glocont_callback,
1366 .indat_callback = usa28_indat_callback,
1367 .outdat_callback = usa2x_outdat_callback,
1368 .inack_callback = usa28_inack_callback,
1369 .outcont_callback = usa28_outcont_callback,
1370 }, {
1371 /* msg_usa49 callbacks */
1372 .instat_callback = usa49_instat_callback,
1373 .glocont_callback = usa49_glocont_callback,
1374 .indat_callback = usa49_indat_callback,
1375 .outdat_callback = usa2x_outdat_callback,
1376 .inack_callback = usa49_inack_callback,
1377 .outcont_callback = usa49_outcont_callback,
1378 }, {
1379 /* msg_usa90 callbacks */
1380 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001381 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 .indat_callback = usa90_indat_callback,
1383 .outdat_callback = usa2x_outdat_callback,
1384 .inack_callback = usa28_inack_callback,
1385 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001386 }, {
1387 /* msg_usa67 callbacks */
1388 .instat_callback = usa67_instat_callback,
1389 .glocont_callback = usa67_glocont_callback,
1390 .indat_callback = usa26_indat_callback,
1391 .outdat_callback = usa2x_outdat_callback,
1392 .inack_callback = usa26_inack_callback,
1393 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 }
1395};
1396
1397 /* Generic setup urbs function that uses
1398 data in device_details */
1399static void keyspan_setup_urbs(struct usb_serial *serial)
1400{
1401 int i, j;
1402 struct keyspan_serial_private *s_priv;
1403 const struct keyspan_device_details *d_details;
1404 struct usb_serial_port *port;
1405 struct keyspan_port_private *p_priv;
1406 struct callbacks *cback;
1407 int endp;
1408
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 s_priv = usb_get_serial_data(serial);
1410 d_details = s_priv->device_details;
1411
Alan Coxdeb91682008-07-22 11:13:08 +01001412 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 cback = &keyspan_callbacks[d_details->msg_format];
1414
Alan Coxdeb91682008-07-22 11:13:08 +01001415 /* Allocate and set up urbs for each one that is in use,
1416 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 s_priv->instat_urb = keyspan_setup_urb
1418 (serial, d_details->instat_endpoint, USB_DIR_IN,
1419 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1420 cback->instat_callback);
1421
Lucy McCoy0ca12682007-05-18 12:10:41 -07001422 s_priv->indat_urb = keyspan_setup_urb
1423 (serial, d_details->indat_endpoint, USB_DIR_IN,
1424 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1425 usa49wg_indat_callback);
1426
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 s_priv->glocont_urb = keyspan_setup_urb
1428 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1429 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1430 cback->glocont_callback);
1431
Alan Coxdeb91682008-07-22 11:13:08 +01001432 /* Setup endpoints for each port specific thing */
1433 for (i = 0; i < d_details->num_ports; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 port = serial->port[i];
1435 p_priv = usb_get_serial_port_data(port);
1436
1437 /* Do indat endpoints first, once for each flip */
1438 endp = d_details->indat_endpoints[i];
1439 for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) {
1440 p_priv->in_urbs[j] = keyspan_setup_urb
1441 (serial, endp, USB_DIR_IN, port,
1442 p_priv->in_buffer[j], 64,
1443 cback->indat_callback);
1444 }
1445 for (; j < 2; ++j)
1446 p_priv->in_urbs[j] = NULL;
1447
1448 /* outdat endpoints also have flip */
1449 endp = d_details->outdat_endpoints[i];
1450 for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) {
1451 p_priv->out_urbs[j] = keyspan_setup_urb
1452 (serial, endp, USB_DIR_OUT, port,
1453 p_priv->out_buffer[j], 64,
1454 cback->outdat_callback);
1455 }
1456 for (; j < 2; ++j)
1457 p_priv->out_urbs[j] = NULL;
1458
1459 /* inack endpoint */
1460 p_priv->inack_urb = keyspan_setup_urb
1461 (serial, d_details->inack_endpoints[i], USB_DIR_IN,
1462 port, p_priv->inack_buffer, 1, cback->inack_callback);
1463
1464 /* outcont endpoint */
1465 p_priv->outcont_urb = keyspan_setup_urb
1466 (serial, d_details->outcont_endpoints[i], USB_DIR_OUT,
1467 port, p_priv->outcont_buffer, 64,
1468 cback->outcont_callback);
Alan Coxdeb91682008-07-22 11:13:08 +01001469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470}
1471
1472/* usa19 function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001473static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1474 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 u8 *rate_low, u8 *prescaler, int portnum)
1476{
1477 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001478 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001481 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482
Alan Coxdeb91682008-07-22 11:13:08 +01001483 /* prevent divide by zero... */
1484 b16 = baud_rate * 16L;
1485 if (b16 == 0)
1486 return KEYSPAN_INVALID_BAUD_RATE;
1487 /* Any "standard" rate over 57k6 is marginal on the USA-19
1488 as we run out of divisor resolution. */
1489 if (baud_rate > 57600)
1490 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
Alan Coxdeb91682008-07-22 11:13:08 +01001492 /* calculate the divisor and the counter (its inverse) */
1493 div = baudclk / b16;
1494 if (div == 0)
1495 return KEYSPAN_INVALID_BAUD_RATE;
1496 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
Alan Coxdeb91682008-07-22 11:13:08 +01001499 if (div > 0xffff)
1500 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
Alan Coxdeb91682008-07-22 11:13:08 +01001502 /* return the counter values if non-null */
1503 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001505 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001507 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001508 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001509 __func__, baud_rate, *rate_hi, *rate_low);
1510 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511}
1512
1513/* usa19hs function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001514static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1515 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1516 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517{
1518 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001519 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001521 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522
Alan Coxdeb91682008-07-22 11:13:08 +01001523 /* prevent divide by zero... */
1524 b16 = baud_rate * 16L;
1525 if (b16 == 0)
1526 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
Alan Coxdeb91682008-07-22 11:13:08 +01001528 /* calculate the divisor */
1529 div = baudclk / b16;
1530 if (div == 0)
1531 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532
Alan Coxdeb91682008-07-22 11:13:08 +01001533 if (div > 0xffff)
1534 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
Alan Coxdeb91682008-07-22 11:13:08 +01001536 /* return the counter values if non-null */
1537 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001539
1540 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001542
1543 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001544 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001545 __func__, baud_rate, *rate_hi, *rate_low);
1546
1547 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548}
1549
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001550static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1551 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 u8 *rate_low, u8 *prescaler, int portnum)
1553{
1554 u32 b16, /* baud rate times 16 (actual rate used internally) */
1555 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001556 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 res, /* resulting baud rate using 13/8 prescaler */
1558 diff, /* error using 13/8 prescaler */
1559 smallest_diff;
1560 u8 best_prescaler;
1561 int i;
1562
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001563 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
Alan Coxdeb91682008-07-22 11:13:08 +01001565 /* prevent divide by zero */
1566 b16 = baud_rate * 16L;
1567 if (b16 == 0)
1568 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569
Alan Coxdeb91682008-07-22 11:13:08 +01001570 /* Calculate prescaler by trying them all and looking
1571 for best fit */
1572
1573 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 smallest_diff = 0xffffffff;
1575
1576 /* 0 is an invalid prescaler, used as a flag */
1577 best_prescaler = 0;
1578
Alan Coxdeb91682008-07-22 11:13:08 +01001579 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001581
1582 div = clk / b16;
1583 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585
1586 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001587 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
Alan Coxdeb91682008-07-22 11:13:08 +01001589 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 best_prescaler = i;
1591 smallest_diff = diff;
1592 }
1593 }
1594
Alan Coxdeb91682008-07-22 11:13:08 +01001595 if (best_prescaler == 0)
1596 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
1598 clk = (baudclk * 8) / (u32) best_prescaler;
1599 div = clk / b16;
1600
Alan Coxdeb91682008-07-22 11:13:08 +01001601 /* return the divisor and prescaler if non-null */
1602 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001604 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 if (prescaler) {
1607 *prescaler = best_prescaler;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001608 /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 }
Alan Coxdeb91682008-07-22 11:13:08 +01001610 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611}
1612
1613 /* USA-28 supports different maximum baud rates on each port */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001614static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1615 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1616 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617{
1618 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001619 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 cnt; /* inverse of divisor (programmed into 8051) */
1621
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001622 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623
1624 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001625 b16 = baud_rate * 16L;
1626 if (b16 == 0)
1627 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
Alan Coxdeb91682008-07-22 11:13:08 +01001629 /* calculate the divisor and the counter (its inverse) */
1630 div = KEYSPAN_USA28_BAUDCLK / b16;
1631 if (div == 0)
1632 return KEYSPAN_INVALID_BAUD_RATE;
1633 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635
Alan Coxdeb91682008-07-22 11:13:08 +01001636 /* check for out of range, based on portnum,
1637 and return result */
1638 if (portnum == 0) {
1639 if (div > 0xffff)
1640 return KEYSPAN_INVALID_BAUD_RATE;
1641 } else {
1642 if (portnum == 1) {
1643 if (div > 0xff)
1644 return KEYSPAN_INVALID_BAUD_RATE;
1645 } else
1646 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 }
1648
1649 /* return the counter values if not NULL
1650 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001651 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001653 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001655 dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
Alan Coxdeb91682008-07-22 11:13:08 +01001656 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657}
1658
1659static int keyspan_usa26_send_setup(struct usb_serial *serial,
1660 struct usb_serial_port *port,
1661 int reset_port)
1662{
Alan Coxdeb91682008-07-22 11:13:08 +01001663 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 struct keyspan_serial_private *s_priv;
1665 struct keyspan_port_private *p_priv;
1666 const struct keyspan_device_details *d_details;
1667 int outcont_urb;
1668 struct urb *this_urb;
1669 int device_port, err;
1670
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001671 dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
1673 s_priv = usb_get_serial_data(serial);
1674 p_priv = usb_get_serial_port_data(port);
1675 d_details = s_priv->device_details;
1676 device_port = port->number - port->serial->minor;
1677
1678 outcont_urb = d_details->outcont_endpoints[port->number];
1679 this_urb = p_priv->outcont_urb;
1680
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001681 dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682
1683 /* Make sure we have an urb then send the message */
1684 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001685 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 return -1;
1687 }
1688
1689 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001690 Don't overwrite resend for open/close condition. */
1691 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 p_priv->resend_cont = reset_port + 1;
1693 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001694 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001696 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 }
1698
Alan Coxdeb91682008-07-22 11:13:08 +01001699 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1700
1701 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 if (p_priv->old_baud != p_priv->baud) {
1703 p_priv->old_baud = p_priv->baud;
1704 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001705 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1706 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1707 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1708 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1709 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 msg.baudLo = 0;
1711 msg.baudHi = 125; /* Values for 9600 baud */
1712 msg.prescaler = 10;
1713 }
1714 msg.setPrescaler = 0xff;
1715 }
1716
Ben Minerds2b982ab2012-07-12 00:10:16 +10001717 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 switch (p_priv->cflag & CSIZE) {
1719 case CS5:
1720 msg.lcr |= USA_DATABITS_5;
1721 break;
1722 case CS6:
1723 msg.lcr |= USA_DATABITS_6;
1724 break;
1725 case CS7:
1726 msg.lcr |= USA_DATABITS_7;
1727 break;
1728 case CS8:
1729 msg.lcr |= USA_DATABITS_8;
1730 break;
1731 }
1732 if (p_priv->cflag & PARENB) {
1733 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001734 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001735 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 }
1737 msg.setLcr = 0xff;
1738
1739 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1740 msg.xonFlowControl = 0;
1741 msg.setFlowControl = 0xff;
1742 msg.forwardingLength = 16;
1743 msg.xonChar = 17;
1744 msg.xoffChar = 19;
1745
1746 /* Opening port */
1747 if (reset_port == 1) {
1748 msg._txOn = 1;
1749 msg._txOff = 0;
1750 msg.txFlush = 0;
1751 msg.txBreak = 0;
1752 msg.rxOn = 1;
1753 msg.rxOff = 0;
1754 msg.rxFlush = 1;
1755 msg.rxForward = 0;
1756 msg.returnStatus = 0;
1757 msg.resetDataToggle = 0xff;
1758 }
1759
1760 /* Closing port */
1761 else if (reset_port == 2) {
1762 msg._txOn = 0;
1763 msg._txOff = 1;
1764 msg.txFlush = 0;
1765 msg.txBreak = 0;
1766 msg.rxOn = 0;
1767 msg.rxOff = 1;
1768 msg.rxFlush = 1;
1769 msg.rxForward = 0;
1770 msg.returnStatus = 0;
1771 msg.resetDataToggle = 0;
1772 }
1773
1774 /* Sending intermediate configs */
1775 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001776 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 msg._txOff = 0;
1778 msg.txFlush = 0;
1779 msg.txBreak = (p_priv->break_on);
1780 msg.rxOn = 0;
1781 msg.rxOff = 0;
1782 msg.rxFlush = 0;
1783 msg.rxForward = 0;
1784 msg.returnStatus = 0;
1785 msg.resetDataToggle = 0x0;
1786 }
1787
Alan Coxdeb91682008-07-22 11:13:08 +01001788 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 msg.setTxTriState_setRts = 0xff;
1790 msg.txTriState_rts = p_priv->rts_state;
1791
1792 msg.setHskoa_setDtr = 0xff;
1793 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001794
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001796 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1797
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 /* send the data out the device on control endpoint */
1799 this_urb->transfer_buffer_length = sizeof(msg);
1800
Alan Coxdeb91682008-07-22 11:13:08 +01001801 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1802 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001803 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804#if 0
1805 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001806 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__
1807 outcont_urb, this_urb->transfer_buffer_length,
1808 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 }
1810#endif
1811
Alan Coxa5b6f602008-04-08 17:16:06 +01001812 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813}
1814
1815static int keyspan_usa28_send_setup(struct usb_serial *serial,
1816 struct usb_serial_port *port,
1817 int reset_port)
1818{
Alan Coxdeb91682008-07-22 11:13:08 +01001819 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 struct keyspan_serial_private *s_priv;
1821 struct keyspan_port_private *p_priv;
1822 const struct keyspan_device_details *d_details;
1823 struct urb *this_urb;
1824 int device_port, err;
1825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 s_priv = usb_get_serial_data(serial);
1827 p_priv = usb_get_serial_port_data(port);
1828 d_details = s_priv->device_details;
1829 device_port = port->number - port->serial->minor;
1830
1831 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001832 this_urb = p_priv->outcont_urb;
1833 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001834 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 return -1;
1836 }
1837
1838 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001839 Don't overwrite resend for open/close condition. */
1840 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 p_priv->resend_cont = reset_port + 1;
1842 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001843 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001845 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 }
1847
Alan Coxdeb91682008-07-22 11:13:08 +01001848 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849
1850 msg.setBaudRate = 1;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001851 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1852 &msg.baudHi, &msg.baudLo, NULL,
1853 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1854 dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001855 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 msg.baudLo = 0xff;
1857 msg.baudHi = 0xb2; /* Values for 9600 baud */
1858 }
1859
1860 /* If parity is enabled, we must calculate it ourselves. */
1861 msg.parity = 0; /* XXX for now */
1862
1863 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1864 msg.xonFlowControl = 0;
1865
Alan Coxdeb91682008-07-22 11:13:08 +01001866 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 msg.rts = p_priv->rts_state;
1868 msg.dtr = p_priv->dtr_state;
1869
1870 msg.forwardingLength = 16;
1871 msg.forwardMs = 10;
1872 msg.breakThreshold = 45;
1873 msg.xonChar = 17;
1874 msg.xoffChar = 19;
1875
1876 /*msg.returnStatus = 1;
1877 msg.resetDataToggle = 0xff;*/
1878 /* Opening port */
1879 if (reset_port == 1) {
1880 msg._txOn = 1;
1881 msg._txOff = 0;
1882 msg.txFlush = 0;
1883 msg.txForceXoff = 0;
1884 msg.txBreak = 0;
1885 msg.rxOn = 1;
1886 msg.rxOff = 0;
1887 msg.rxFlush = 1;
1888 msg.rxForward = 0;
1889 msg.returnStatus = 0;
1890 msg.resetDataToggle = 0xff;
1891 }
1892 /* Closing port */
1893 else if (reset_port == 2) {
1894 msg._txOn = 0;
1895 msg._txOff = 1;
1896 msg.txFlush = 0;
1897 msg.txForceXoff = 0;
1898 msg.txBreak = 0;
1899 msg.rxOn = 0;
1900 msg.rxOff = 1;
1901 msg.rxFlush = 1;
1902 msg.rxForward = 0;
1903 msg.returnStatus = 0;
1904 msg.resetDataToggle = 0;
1905 }
1906 /* Sending intermediate configs */
1907 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001908 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 msg._txOff = 0;
1910 msg.txFlush = 0;
1911 msg.txForceXoff = 0;
1912 msg.txBreak = (p_priv->break_on);
1913 msg.rxOn = 0;
1914 msg.rxOff = 0;
1915 msg.rxFlush = 0;
1916 msg.rxForward = 0;
1917 msg.returnStatus = 0;
1918 msg.resetDataToggle = 0x0;
1919 }
1920
1921 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001922 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
1924 /* send the data out the device on control endpoint */
1925 this_urb->transfer_buffer_length = sizeof(msg);
1926
Alan Coxdeb91682008-07-22 11:13:08 +01001927 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1928 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001929 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930#if 0
1931 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001932 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 this_urb->transfer_buffer_length);
1934 }
1935#endif
1936
Alan Coxa5b6f602008-04-08 17:16:06 +01001937 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938}
1939
1940static int keyspan_usa49_send_setup(struct usb_serial *serial,
1941 struct usb_serial_port *port,
1942 int reset_port)
1943{
Lucy McCoy0ca12682007-05-18 12:10:41 -07001944 struct keyspan_usa49_portControlMessage msg;
1945 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 struct keyspan_serial_private *s_priv;
1947 struct keyspan_port_private *p_priv;
1948 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 struct urb *this_urb;
1950 int err, device_port;
1951
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 s_priv = usb_get_serial_data(serial);
1953 p_priv = usb_get_serial_port_data(port);
1954 d_details = s_priv->device_details;
1955
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 this_urb = s_priv->glocont_urb;
1957
Lucy McCoy0ca12682007-05-18 12:10:41 -07001958 /* Work out which port within the device is being setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 device_port = port->number - port->serial->minor;
1960
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301961 /* Make sure we have an urb then send the message */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001963 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 return -1;
1965 }
1966
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001967 dev_dbg(&port->dev, "%s - endpoint %d port %d (%d)\n",
1968 __func__, usb_pipeendpoint(this_urb->pipe),
1969 port->number, device_port);
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301970
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001972 Don't overwrite resend for open/close condition. */
1973 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001975
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001977 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001979 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 }
1981
Alan Coxdeb91682008-07-22 11:13:08 +01001982 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
1984 /*msg.portNumber = port->number;*/
1985 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01001986
1987 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 if (p_priv->old_baud != p_priv->baud) {
1989 p_priv->old_baud = p_priv->baud;
1990 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001991 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1992 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1993 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1994 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1995 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 msg.baudLo = 0;
1997 msg.baudHi = 125; /* Values for 9600 baud */
1998 msg.prescaler = 10;
1999 }
Alan Coxdeb91682008-07-22 11:13:08 +01002000 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 }
2002
Ben Minerds2b982ab2012-07-12 00:10:16 +10002003 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 switch (p_priv->cflag & CSIZE) {
2005 case CS5:
2006 msg.lcr |= USA_DATABITS_5;
2007 break;
2008 case CS6:
2009 msg.lcr |= USA_DATABITS_6;
2010 break;
2011 case CS7:
2012 msg.lcr |= USA_DATABITS_7;
2013 break;
2014 case CS8:
2015 msg.lcr |= USA_DATABITS_8;
2016 break;
2017 }
2018 if (p_priv->cflag & PARENB) {
2019 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002020 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002021 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 }
2023 msg.setLcr = 0xff;
2024
2025 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2026 msg.xonFlowControl = 0;
2027 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01002028
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 msg.forwardingLength = 16;
2030 msg.xonChar = 17;
2031 msg.xoffChar = 19;
2032
Alan Coxdeb91682008-07-22 11:13:08 +01002033 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 if (reset_port == 1) {
2035 msg._txOn = 1;
2036 msg._txOff = 0;
2037 msg.txFlush = 0;
2038 msg.txBreak = 0;
2039 msg.rxOn = 1;
2040 msg.rxOff = 0;
2041 msg.rxFlush = 1;
2042 msg.rxForward = 0;
2043 msg.returnStatus = 0;
2044 msg.resetDataToggle = 0xff;
2045 msg.enablePort = 1;
2046 msg.disablePort = 0;
2047 }
2048 /* Closing port */
2049 else if (reset_port == 2) {
2050 msg._txOn = 0;
2051 msg._txOff = 1;
2052 msg.txFlush = 0;
2053 msg.txBreak = 0;
2054 msg.rxOn = 0;
2055 msg.rxOff = 1;
2056 msg.rxFlush = 1;
2057 msg.rxForward = 0;
2058 msg.returnStatus = 0;
2059 msg.resetDataToggle = 0;
2060 msg.enablePort = 0;
2061 msg.disablePort = 1;
2062 }
2063 /* Sending intermediate configs */
2064 else {
Alan Coxdeb91682008-07-22 11:13:08 +01002065 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 msg._txOff = 0;
2067 msg.txFlush = 0;
2068 msg.txBreak = (p_priv->break_on);
2069 msg.rxOn = 0;
2070 msg.rxOff = 0;
2071 msg.rxFlush = 0;
2072 msg.rxForward = 0;
2073 msg.returnStatus = 0;
2074 msg.resetDataToggle = 0x0;
2075 msg.enablePort = 0;
2076 msg.disablePort = 0;
2077 }
2078
Alan Coxdeb91682008-07-22 11:13:08 +01002079 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 msg.setRts = 0xff;
2081 msg.rts = p_priv->rts_state;
2082
2083 msg.setDtr = 0xff;
2084 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002085
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087
Alan Coxdeb91682008-07-22 11:13:08 +01002088 /* if the device is a 49wg, we send control message on usb
2089 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002090
2091 if (d_details->product_id == keyspan_usa49wg_product_id) {
2092 dr = (void *)(s_priv->ctrl_buf);
2093 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
2094 dr->bRequest = 0xB0; /* 49wg control message */;
2095 dr->wValue = 0;
2096 dr->wIndex = 0;
2097 dr->wLength = cpu_to_le16(sizeof(msg));
2098
Alan Coxdeb91682008-07-22 11:13:08 +01002099 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07002100
Alan Coxdeb91682008-07-22 11:13:08 +01002101 usb_fill_control_urb(this_urb, serial->dev,
2102 usb_sndctrlpipe(serial->dev, 0),
2103 (unsigned char *)dr, s_priv->glocont_buf,
2104 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002105
2106 } else {
2107 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01002108
Lucy McCoy0ca12682007-05-18 12:10:41 -07002109 /* send the data out the device on control endpoint */
2110 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002111 }
Alan Coxdeb91682008-07-22 11:13:08 +01002112 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2113 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002114 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115#if 0
2116 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002117 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__,
2118 outcont_urb, this_urb->transfer_buffer_length,
2119 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 }
2121#endif
2122
Alan Coxa5b6f602008-04-08 17:16:06 +01002123 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124}
2125
2126static int keyspan_usa90_send_setup(struct usb_serial *serial,
2127 struct usb_serial_port *port,
2128 int reset_port)
2129{
Alan Coxdeb91682008-07-22 11:13:08 +01002130 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 struct keyspan_serial_private *s_priv;
2132 struct keyspan_port_private *p_priv;
2133 const struct keyspan_device_details *d_details;
2134 struct urb *this_urb;
2135 int err;
2136 u8 prescaler;
2137
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 s_priv = usb_get_serial_data(serial);
2139 p_priv = usb_get_serial_port_data(port);
2140 d_details = s_priv->device_details;
2141
2142 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002143 this_urb = p_priv->outcont_urb;
2144 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002145 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 return -1;
2147 }
2148
2149 /* Save reset port val for resend.
2150 Don't overwrite resend for open/close condition. */
2151 if ((reset_port + 1) > p_priv->resend_cont)
2152 p_priv->resend_cont = reset_port + 1;
2153 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002154 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002156 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 }
2158
Alan Coxdeb91682008-07-22 11:13:08 +01002159 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160
Alan Coxdeb91682008-07-22 11:13:08 +01002161 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 if (p_priv->old_baud != p_priv->baud) {
2163 p_priv->old_baud = p_priv->baud;
2164 msg.setClocking = 0x01;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002165 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2166 &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2167 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2168 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 p_priv->baud = 9600;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002170 d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2172 }
2173 msg.setRxMode = 1;
2174 msg.setTxMode = 1;
2175 }
2176
2177 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002178 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 msg.rxMode = RXMODE_DMA;
2180 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002181 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 msg.rxMode = RXMODE_BYHAND;
2183 msg.txMode = TXMODE_BYHAND;
2184 }
2185
Ben Minerds2b982ab2012-07-12 00:10:16 +10002186 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 switch (p_priv->cflag & CSIZE) {
2188 case CS5:
2189 msg.lcr |= USA_DATABITS_5;
2190 break;
2191 case CS6:
2192 msg.lcr |= USA_DATABITS_6;
2193 break;
2194 case CS7:
2195 msg.lcr |= USA_DATABITS_7;
2196 break;
2197 case CS8:
2198 msg.lcr |= USA_DATABITS_8;
2199 break;
2200 }
2201 if (p_priv->cflag & PARENB) {
2202 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002203 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002204 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 }
2206 if (p_priv->old_cflag != p_priv->cflag) {
2207 p_priv->old_cflag = p_priv->cflag;
2208 msg.setLcr = 0x01;
2209 }
2210
2211 if (p_priv->flow_control == flow_cts)
2212 msg.txFlowControl = TXFLOW_CTS;
2213 msg.setTxFlowControl = 0x01;
2214 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002215
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002217 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 msg.txAckSetting = 0;
2219 msg.xonChar = 17;
2220 msg.xoffChar = 19;
2221
Alan Coxdeb91682008-07-22 11:13:08 +01002222 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 if (reset_port == 1) {
2224 msg.portEnabled = 1;
2225 msg.rxFlush = 1;
2226 msg.txBreak = (p_priv->break_on);
2227 }
2228 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002229 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 /* Sending intermediate configs */
2232 else {
Alan Stern1f871582010-02-17 10:05:47 -05002233 msg.portEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 msg.txBreak = (p_priv->break_on);
2235 }
2236
Alan Coxdeb91682008-07-22 11:13:08 +01002237 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 msg.setRts = 0x01;
2239 msg.rts = p_priv->rts_state;
2240
2241 msg.setDtr = 0x01;
2242 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002243
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002245 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2246
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 /* send the data out the device on control endpoint */
2248 this_urb->transfer_buffer_length = sizeof(msg);
2249
Alan Coxdeb91682008-07-22 11:13:08 +01002250 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2251 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002252 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002253 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254}
2255
Lucy McCoy0ca12682007-05-18 12:10:41 -07002256static int keyspan_usa67_send_setup(struct usb_serial *serial,
2257 struct usb_serial_port *port,
2258 int reset_port)
2259{
2260 struct keyspan_usa67_portControlMessage msg;
2261 struct keyspan_serial_private *s_priv;
2262 struct keyspan_port_private *p_priv;
2263 const struct keyspan_device_details *d_details;
2264 struct urb *this_urb;
2265 int err, device_port;
2266
Lucy McCoy0ca12682007-05-18 12:10:41 -07002267 s_priv = usb_get_serial_data(serial);
2268 p_priv = usb_get_serial_port_data(port);
2269 d_details = s_priv->device_details;
2270
2271 this_urb = s_priv->glocont_urb;
2272
2273 /* Work out which port within the device is being setup */
2274 device_port = port->number - port->serial->minor;
2275
2276 /* Make sure we have an urb then send the message */
2277 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002278 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002279 port->number);
2280 return -1;
2281 }
2282
2283 /* Save reset port val for resend.
2284 Don't overwrite resend for open/close condition. */
2285 if ((reset_port + 1) > p_priv->resend_cont)
2286 p_priv->resend_cont = reset_port + 1;
2287 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002288 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002289 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002290 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002291 }
2292
2293 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2294
2295 msg.port = device_port;
2296
2297 /* Only set baud rate if it's changed */
2298 if (p_priv->old_baud != p_priv->baud) {
2299 p_priv->old_baud = p_priv->baud;
2300 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002301 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2302 &msg.baudHi, &msg.baudLo, &msg.prescaler,
2303 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2304 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2305 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002306 msg.baudLo = 0;
2307 msg.baudHi = 125; /* Values for 9600 baud */
2308 msg.prescaler = 10;
2309 }
2310 msg.setPrescaler = 0xff;
2311 }
2312
2313 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2314 switch (p_priv->cflag & CSIZE) {
2315 case CS5:
2316 msg.lcr |= USA_DATABITS_5;
2317 break;
2318 case CS6:
2319 msg.lcr |= USA_DATABITS_6;
2320 break;
2321 case CS7:
2322 msg.lcr |= USA_DATABITS_7;
2323 break;
2324 case CS8:
2325 msg.lcr |= USA_DATABITS_8;
2326 break;
2327 }
2328 if (p_priv->cflag & PARENB) {
2329 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002330 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002331 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002332 }
2333 msg.setLcr = 0xff;
2334
2335 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2336 msg.xonFlowControl = 0;
2337 msg.setFlowControl = 0xff;
2338 msg.forwardingLength = 16;
2339 msg.xonChar = 17;
2340 msg.xoffChar = 19;
2341
2342 if (reset_port == 1) {
2343 /* Opening port */
2344 msg._txOn = 1;
2345 msg._txOff = 0;
2346 msg.txFlush = 0;
2347 msg.txBreak = 0;
2348 msg.rxOn = 1;
2349 msg.rxOff = 0;
2350 msg.rxFlush = 1;
2351 msg.rxForward = 0;
2352 msg.returnStatus = 0;
2353 msg.resetDataToggle = 0xff;
2354 } else if (reset_port == 2) {
2355 /* Closing port */
2356 msg._txOn = 0;
2357 msg._txOff = 1;
2358 msg.txFlush = 0;
2359 msg.txBreak = 0;
2360 msg.rxOn = 0;
2361 msg.rxOff = 1;
2362 msg.rxFlush = 1;
2363 msg.rxForward = 0;
2364 msg.returnStatus = 0;
2365 msg.resetDataToggle = 0;
2366 } else {
2367 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002368 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002369 msg._txOff = 0;
2370 msg.txFlush = 0;
2371 msg.txBreak = (p_priv->break_on);
2372 msg.rxOn = 0;
2373 msg.rxOff = 0;
2374 msg.rxFlush = 0;
2375 msg.rxForward = 0;
2376 msg.returnStatus = 0;
2377 msg.resetDataToggle = 0x0;
2378 }
2379
2380 /* Do handshaking outputs */
2381 msg.setTxTriState_setRts = 0xff;
2382 msg.txTriState_rts = p_priv->rts_state;
2383
2384 msg.setHskoa_setDtr = 0xff;
2385 msg.hskoa_dtr = p_priv->dtr_state;
2386
2387 p_priv->resend_cont = 0;
2388
2389 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2390
2391 /* send the data out the device on control endpoint */
2392 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002393
2394 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2395 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002396 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002397 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002398}
2399
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2401{
2402 struct usb_serial *serial = port->serial;
2403 struct keyspan_serial_private *s_priv;
2404 const struct keyspan_device_details *d_details;
2405
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 s_priv = usb_get_serial_data(serial);
2407 d_details = s_priv->device_details;
2408
2409 switch (d_details->msg_format) {
2410 case msg_usa26:
2411 keyspan_usa26_send_setup(serial, port, reset_port);
2412 break;
2413 case msg_usa28:
2414 keyspan_usa28_send_setup(serial, port, reset_port);
2415 break;
2416 case msg_usa49:
2417 keyspan_usa49_send_setup(serial, port, reset_port);
2418 break;
2419 case msg_usa90:
2420 keyspan_usa90_send_setup(serial, port, reset_port);
2421 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002422 case msg_usa67:
2423 keyspan_usa67_send_setup(serial, port, reset_port);
2424 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 }
2426}
2427
2428
2429/* Gets called by the "real" driver (ie once firmware is loaded
2430 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002431static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432{
2433 int i, err;
2434 struct usb_serial_port *port;
2435 struct keyspan_serial_private *s_priv;
2436 struct keyspan_port_private *p_priv;
2437 const struct keyspan_device_details *d_details;
2438
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002440 if (d_details->product_id ==
2441 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 break;
2443 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002444 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2445 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 return 1;
2447 }
2448
2449 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002450 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 if (!s_priv) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002452 dev_dbg(&serial->dev->dev, "%s - kmalloc for keyspan_serial_private failed.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 return -ENOMEM;
2454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
2456 s_priv->device_details = d_details;
2457 usb_set_serial_data(serial, s_priv);
2458
2459 /* Now setup per port private data */
2460 for (i = 0; i < serial->num_ports; i++) {
2461 port = serial->port[i];
Alan Coxdeb91682008-07-22 11:13:08 +01002462 p_priv = kzalloc(sizeof(struct keyspan_port_private),
2463 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 if (!p_priv) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002465 dev_dbg(&port->dev, "%s - kmalloc for keyspan_port_private (%d) failed!.\n", __func__, i);
Alan Coxdeb91682008-07-22 11:13:08 +01002466 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 p_priv->device_details = d_details;
2469 usb_set_serial_port_data(port, p_priv);
2470 }
2471
2472 keyspan_setup_urbs(serial);
2473
Lucy McCoy0ca12682007-05-18 12:10:41 -07002474 if (s_priv->instat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002475 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2476 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002477 dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002478 }
2479 if (s_priv->indat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002480 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2481 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002482 dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 }
Alan Coxdeb91682008-07-22 11:13:08 +01002484
Alan Coxa5b6f602008-04-08 17:16:06 +01002485 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486}
2487
Alan Sternf9c99bb2009-06-02 11:53:55 -04002488static void keyspan_disconnect(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489{
2490 int i, j;
2491 struct usb_serial_port *port;
2492 struct keyspan_serial_private *s_priv;
2493 struct keyspan_port_private *p_priv;
2494
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 s_priv = usb_get_serial_data(serial);
2496
2497 /* Stop reading/writing urbs */
2498 stop_urb(s_priv->instat_urb);
2499 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002500 stop_urb(s_priv->indat_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 for (i = 0; i < serial->num_ports; ++i) {
2502 port = serial->port[i];
2503 p_priv = usb_get_serial_port_data(port);
2504 stop_urb(p_priv->inack_urb);
2505 stop_urb(p_priv->outcont_urb);
2506 for (j = 0; j < 2; j++) {
2507 stop_urb(p_priv->in_urbs[j]);
2508 stop_urb(p_priv->out_urbs[j]);
2509 }
2510 }
2511
2512 /* Now free them */
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002513 usb_free_urb(s_priv->instat_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002514 usb_free_urb(s_priv->indat_urb);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002515 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 for (i = 0; i < serial->num_ports; ++i) {
2517 port = serial->port[i];
2518 p_priv = usb_get_serial_port_data(port);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002519 usb_free_urb(p_priv->inack_urb);
2520 usb_free_urb(p_priv->outcont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 for (j = 0; j < 2; j++) {
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002522 usb_free_urb(p_priv->in_urbs[j]);
2523 usb_free_urb(p_priv->out_urbs[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 }
2525 }
Alan Sternf9c99bb2009-06-02 11:53:55 -04002526}
2527
2528static void keyspan_release(struct usb_serial *serial)
2529{
2530 int i;
2531 struct usb_serial_port *port;
2532 struct keyspan_serial_private *s_priv;
2533
Alan Sternf9c99bb2009-06-02 11:53:55 -04002534 s_priv = usb_get_serial_data(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 kfree(s_priv);
2537
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 /* Now free per port private data */
2539 for (i = 0; i < serial->num_ports; i++) {
2540 port = serial->port[i];
2541 kfree(usb_get_serial_port_data(port));
2542 }
2543}
2544
Alan Coxdeb91682008-07-22 11:13:08 +01002545MODULE_AUTHOR(DRIVER_AUTHOR);
2546MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547MODULE_LICENSE("GPL");
2548
David Woodhouse2971c572008-05-30 14:04:03 +03002549MODULE_FIRMWARE("keyspan/usa28.fw");
2550MODULE_FIRMWARE("keyspan/usa28x.fw");
2551MODULE_FIRMWARE("keyspan/usa28xa.fw");
2552MODULE_FIRMWARE("keyspan/usa28xb.fw");
2553MODULE_FIRMWARE("keyspan/usa19.fw");
2554MODULE_FIRMWARE("keyspan/usa19qi.fw");
2555MODULE_FIRMWARE("keyspan/mpr.fw");
2556MODULE_FIRMWARE("keyspan/usa19qw.fw");
2557MODULE_FIRMWARE("keyspan/usa18x.fw");
2558MODULE_FIRMWARE("keyspan/usa19w.fw");
2559MODULE_FIRMWARE("keyspan/usa49w.fw");
2560MODULE_FIRMWARE("keyspan/usa49wlc.fw");
2561
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562module_param(debug, bool, S_IRUGO | S_IWUSR);
2563MODULE_PARM_DESC(debug, "Debug enabled or not");
2564