blob: 0acb07131f6e82199586d7bbe2c4fb6dabf737dc [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 Keyspan USB to Serial Converter driver
Alan Coxdeb91682008-07-22 11:13:08 +01003
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 (C) Copyright (C) 2000-2001 Hugh Blemings <hugh@blemings.org>
5 (C) Copyright (C) 2002 Greg Kroah-Hartman <greg@kroah.com>
Alan Coxdeb91682008-07-22 11:13:08 +01006
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
Justin P. Mattock631dd1a2010-10-18 11:03:14 +020012 See http://blemings.org/hugh/keyspan.html for more information.
Alan Coxdeb91682008-07-22 11:13:08 +010013
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 Code in this driver inspired by and in a number of places taken
15 from Brian Warner's original Keyspan-PDA driver.
16
17 This driver has been put together with the support of Innosys, Inc.
18 and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
19 Thanks Guys :)
Alan Coxdeb91682008-07-22 11:13:08 +010020
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 Thanks to Paulus for miscellaneous tidy ups, some largish chunks
22 of much nicer and/or completely new code and (perhaps most uniquely)
23 having the patience to sit down and explain why and where he'd changed
Alan Coxdeb91682008-07-22 11:13:08 +010024 stuff.
25
26 Tip 'o the hat to IBM (and previously Linuxcare :) for supporting
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 staff in their work on open source projects.
Linus Torvalds1da177e2005-04-16 15:20:36 -070028*/
29
30
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/kernel.h>
32#include <linux/jiffies.h>
33#include <linux/errno.h>
34#include <linux/init.h>
35#include <linux/slab.h>
36#include <linux/tty.h>
37#include <linux/tty_driver.h>
38#include <linux/tty_flip.h>
39#include <linux/module.h>
40#include <linux/spinlock.h>
Alan Coxdeb91682008-07-22 11:13:08 +010041#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070043#include <linux/usb/serial.h>
Rene Buergelcc183e22012-09-18 09:00:41 +020044#include <linux/usb/ezusb.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include "keyspan.h"
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047/*
48 * Version Information
49 */
Lucy McCoy0ca12682007-05-18 12:10:41 -070050#define DRIVER_VERSION "v1.1.5"
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
52#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
53
54#define INSTAT_BUFLEN 32
55#define GLOCONT_BUFLEN 64
Lucy McCoy0ca12682007-05-18 12:10:41 -070056#define INDAT49W_BUFLEN 512
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58 /* Per device and per port private data */
59struct keyspan_serial_private {
60 const struct keyspan_device_details *device_details;
61
62 struct urb *instat_urb;
63 char instat_buf[INSTAT_BUFLEN];
64
Alan Coxdeb91682008-07-22 11:13:08 +010065 /* added to support 49wg, where data from all 4 ports comes in
66 on 1 EP and high-speed supported */
Lucy McCoy0ca12682007-05-18 12:10:41 -070067 struct urb *indat_urb;
68 char indat_buf[INDAT49W_BUFLEN];
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 /* XXX this one probably will need a lock */
71 struct urb *glocont_urb;
72 char glocont_buf[GLOCONT_BUFLEN];
Alan Coxdeb91682008-07-22 11:13:08 +010073 char ctrl_buf[8]; /* for EP0 control message */
Linus Torvalds1da177e2005-04-16 15:20:36 -070074};
75
76struct keyspan_port_private {
77 /* Keep track of which input & output endpoints to use */
78 int in_flip;
79 int out_flip;
80
81 /* Keep duplicate of device details in each port
82 structure as well - simplifies some of the
83 callback functions etc. */
84 const struct keyspan_device_details *device_details;
85
86 /* Input endpoints and buffer for this port */
87 struct urb *in_urbs[2];
88 char in_buffer[2][64];
89 /* Output endpoints and buffer for this port */
90 struct urb *out_urbs[2];
91 char out_buffer[2][64];
92
93 /* Input ack endpoint */
94 struct urb *inack_urb;
95 char inack_buffer[1];
96
97 /* Output control endpoint */
98 struct urb *outcont_urb;
99 char outcont_buffer[64];
100
101 /* Settings for the port */
102 int baud;
103 int old_baud;
104 unsigned int cflag;
105 unsigned int old_cflag;
106 enum {flow_none, flow_cts, flow_xon} flow_control;
107 int rts_state; /* Handshaking pins (outputs) */
108 int dtr_state;
109 int cts_state; /* Handshaking pins (inputs) */
110 int dsr_state;
111 int dcd_state;
112 int ri_state;
113 int break_on;
114
115 unsigned long tx_start_time[2];
116 int resend_cont; /* need to resend control packet */
117};
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119/* Include Keyspan message headers. All current Keyspan Adapters
Lucy McCoy0ca12682007-05-18 12:10:41 -0700120 make use of one of five message formats which are referred
Alan Coxdeb91682008-07-22 11:13:08 +0100121 to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and
122 within this driver. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#include "keyspan_usa26msg.h"
124#include "keyspan_usa28msg.h"
125#include "keyspan_usa49msg.h"
126#include "keyspan_usa90msg.h"
Lucy McCoy0ca12682007-05-18 12:10:41 -0700127#include "keyspan_usa67msg.h"
Alan Coxdeb91682008-07-22 11:13:08 +0100128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -0700130module_usb_serial_driver(serial_drivers, keyspan_ids_combined);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
Alan Cox95da3102008-07-22 11:09:07 +0100132static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
Alan Cox95da3102008-07-22 11:09:07 +0100134 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 struct keyspan_port_private *p_priv;
136
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 p_priv = usb_get_serial_port_data(port);
138
139 if (break_state == -1)
140 p_priv->break_on = 1;
141 else
142 p_priv->break_on = 0;
143
144 keyspan_send_setup(port, 0);
145}
146
147
Alan Coxdeb91682008-07-22 11:13:08 +0100148static void keyspan_set_termios(struct tty_struct *tty,
Alan Cox95da3102008-07-22 11:09:07 +0100149 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150{
151 int baud_rate, device_port;
152 struct keyspan_port_private *p_priv;
153 const struct keyspan_device_details *d_details;
154 unsigned int cflag;
155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 p_priv = usb_get_serial_port_data(port);
157 d_details = p_priv->device_details;
Alan Cox74240b02007-10-18 01:24:20 -0700158 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 device_port = port->number - port->serial->minor;
160
161 /* Baud rate calculation takes baud rate as an integer
162 so other rates can be generated if desired. */
Alan Cox74240b02007-10-18 01:24:20 -0700163 baud_rate = tty_get_baud_rate(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100164 /* If no match or invalid, don't change */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700165 if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
167 /* FIXME - more to do here to ensure rate changes cleanly */
Alan Cox74240b02007-10-18 01:24:20 -0700168 /* FIXME - calcuate exact rate from divisor ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 p_priv->baud = baud_rate;
Alan Cox74240b02007-10-18 01:24:20 -0700170 } else
171 baud_rate = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
Alan Cox74240b02007-10-18 01:24:20 -0700173 tty_encode_baud_rate(tty, baud_rate, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 /* set CTS/RTS handshake etc. */
175 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +1000176 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
Alan Cox74240b02007-10-18 01:24:20 -0700178 /* Mark/Space not supported */
179 tty->termios->c_cflag &= ~CMSPAR;
180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 keyspan_send_setup(port, 0);
182}
183
Alan Cox60b33c12011-02-14 16:26:14 +0000184static int keyspan_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
Alan Cox95da3102008-07-22 11:09:07 +0100186 struct usb_serial_port *port = tty->driver_data;
187 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 unsigned int value;
Alan Coxdeb91682008-07-22 11:13:08 +0100189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
191 ((p_priv->dtr_state) ? TIOCM_DTR : 0) |
192 ((p_priv->cts_state) ? TIOCM_CTS : 0) |
193 ((p_priv->dsr_state) ? TIOCM_DSR : 0) |
194 ((p_priv->dcd_state) ? TIOCM_CAR : 0) |
Alan Coxdeb91682008-07-22 11:13:08 +0100195 ((p_priv->ri_state) ? TIOCM_RNG : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
197 return value;
198}
199
Alan Cox20b9d172011-02-14 16:26:50 +0000200static int keyspan_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 unsigned int set, unsigned int clear)
202{
Alan Cox95da3102008-07-22 11:09:07 +0100203 struct usb_serial_port *port = tty->driver_data;
204 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100205
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 if (set & TIOCM_RTS)
207 p_priv->rts_state = 1;
208 if (set & TIOCM_DTR)
209 p_priv->dtr_state = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 if (clear & TIOCM_RTS)
211 p_priv->rts_state = 0;
212 if (clear & TIOCM_DTR)
213 p_priv->dtr_state = 0;
214 keyspan_send_setup(port, 0);
215 return 0;
216}
217
Alan Cox95da3102008-07-22 11:09:07 +0100218/* Write function is similar for the four protocols used
219 with only a minor change for usa90 (usa19hs) required */
220static int keyspan_write(struct tty_struct *tty,
221 struct usb_serial_port *port, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222{
223 struct keyspan_port_private *p_priv;
224 const struct keyspan_device_details *d_details;
225 int flip;
226 int left, todo;
227 struct urb *this_urb;
Alan Coxdeb91682008-07-22 11:13:08 +0100228 int err, maxDataLen, dataOffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
230 p_priv = usb_get_serial_port_data(port);
231 d_details = p_priv->device_details;
232
233 if (d_details->msg_format == msg_usa90) {
Alan Coxdeb91682008-07-22 11:13:08 +0100234 maxDataLen = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 dataOffset = 0;
236 } else {
237 maxDataLen = 63;
238 dataOffset = 1;
239 }
Alan Coxdeb91682008-07-22 11:13:08 +0100240
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700241 dev_dbg(&port->dev, "%s - for port %d (%d chars), flip=%d\n",
242 __func__, port->number, count, p_priv->out_flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244 for (left = count; left > 0; left -= todo) {
245 todo = left;
246 if (todo > maxDataLen)
247 todo = maxDataLen;
248
249 flip = p_priv->out_flip;
Alan Coxdeb91682008-07-22 11:13:08 +0100250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 /* Check we have a valid urb/endpoint before we use it... */
Alan Coxdeb91682008-07-22 11:13:08 +0100252 this_urb = p_priv->out_urbs[flip];
253 if (this_urb == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 /* no bulk out, so return 0 bytes written */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700255 dev_dbg(&port->dev, "%s - no output urb :(\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 return count;
257 }
258
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700259 dev_dbg(&port->dev, "%s - endpoint %d flip %d\n",
Alan Coxdeb91682008-07-22 11:13:08 +0100260 __func__, usb_pipeendpoint(this_urb->pipe), flip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262 if (this_urb->status == -EINPROGRESS) {
Alan Coxdeb91682008-07-22 11:13:08 +0100263 if (time_before(jiffies,
264 p_priv->tx_start_time[flip] + 10 * HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 usb_unlink_urb(this_urb);
267 break;
268 }
269
Alan Coxdeb91682008-07-22 11:13:08 +0100270 /* First byte in buffer is "last flag" (except for usa19hx)
271 - unused so for now so set to zero */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 ((char *)this_urb->transfer_buffer)[0] = 0;
273
Alan Coxdeb91682008-07-22 11:13:08 +0100274 memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 buf += todo;
276
277 /* send the data out the bulk port */
278 this_urb->transfer_buffer_length = todo + dataOffset;
279
Alan Coxdeb91682008-07-22 11:13:08 +0100280 err = usb_submit_urb(this_urb, GFP_ATOMIC);
281 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700282 dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 p_priv->tx_start_time[flip] = jiffies;
284
285 /* Flip for next time if usa26 or usa28 interface
286 (not used on usa49) */
287 p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
288 }
289
290 return count - left;
291}
292
David Howells7d12e782006-10-05 14:55:46 +0100293static void usa26_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
295 int i, err;
296 int endpoint;
297 struct usb_serial_port *port;
298 struct tty_struct *tty;
299 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700300 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 endpoint = usb_pipeendpoint(urb->pipe);
303
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700304 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700305 dev_dbg(&urb->dev->dev,"%s - nonzero status: %x on endpoint %d.\n",
306 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 return;
308 }
309
Ming Leicdc97792008-02-24 18:41:47 +0800310 port = urb->context;
Alan Cox4a90f092008-10-13 10:39:46 +0100311 tty = tty_port_tty_get(&port->port);
Alan Coxa5569a52008-01-21 17:18:24 -0800312 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 /* 0x80 bit is error flag */
314 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100315 /* no errors on individual bytes, only
316 possible overrun err */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100318 err = TTY_OVERRUN;
319 else
320 err = 0;
321 for (i = 1; i < urb->actual_length ; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 tty_insert_flip_char(tty, data[i], err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 } else {
324 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700325 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 for (i = 0; i + 1 < urb->actual_length; i += 2) {
327 int stat = data[i], flag = 0;
328 if (stat & RXERROR_OVERRUN)
329 flag |= TTY_OVERRUN;
330 if (stat & RXERROR_FRAMING)
331 flag |= TTY_FRAME;
332 if (stat & RXERROR_PARITY)
333 flag |= TTY_PARITY;
334 /* XXX should handle break (0x10) */
335 tty_insert_flip_char(tty, data[i+1], flag);
336 }
337 }
338 tty_flip_buffer_push(tty);
339 }
Alan Cox4a90f092008-10-13 10:39:46 +0100340 tty_kref_put(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100341
342 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500343 err = usb_submit_urb(urb, GFP_ATOMIC);
344 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700345 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346}
347
Alan Coxdeb91682008-07-22 11:13:08 +0100348/* Outdat handling is common for all devices */
David Howells7d12e782006-10-05 14:55:46 +0100349static void usa2x_outdat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
351 struct usb_serial_port *port;
352 struct keyspan_port_private *p_priv;
353
Ming Leicdc97792008-02-24 18:41:47 +0800354 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 p_priv = usb_get_serial_port_data(port);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700356 dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Alan Stern1f871582010-02-17 10:05:47 -0500358 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
360
David Howells7d12e782006-10-05 14:55:46 +0100361static void usa26_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363}
364
David Howells7d12e782006-10-05 14:55:46 +0100365static void usa26_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
367 struct usb_serial_port *port;
368 struct keyspan_port_private *p_priv;
369
Ming Leicdc97792008-02-24 18:41:47 +0800370 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 p_priv = usb_get_serial_port_data(port);
372
373 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700374 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100375 keyspan_usa26_send_setup(port->serial, port,
376 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 }
378}
379
David Howells7d12e782006-10-05 14:55:46 +0100380static void usa26_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{
382 unsigned char *data = urb->transfer_buffer;
383 struct keyspan_usa26_portStatusMessage *msg;
384 struct usb_serial *serial;
385 struct usb_serial_port *port;
386 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100387 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700389 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Ming Leicdc97792008-02-24 18:41:47 +0800391 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700393 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700394 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 return;
396 }
397 if (urb->actual_length != 9) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700398 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 goto exit;
400 }
401
402 msg = (struct keyspan_usa26_portStatusMessage *)data;
403
404#if 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700405 dev_dbg(&urb->dev->dev,
406 "%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
407 __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr,
408 msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled,
409 msg->controlResponse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410#endif
411
412 /* Now do something useful with the data */
413
414
Alan Coxdeb91682008-07-22 11:13:08 +0100415 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700417 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 goto exit;
419 }
420 port = serial->port[msg->port];
421 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 /* Update handshaking pin state information */
424 old_dcd_state = p_priv->dcd_state;
425 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
426 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
427 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
428 p_priv->ri_state = ((msg->ri) ? 1 : 0);
429
Alan Cox4a90f092008-10-13 10:39:46 +0100430 if (old_dcd_state != p_priv->dcd_state) {
431 tty = tty_port_tty_get(&port->port);
432 if (tty && !C_CLOCAL(tty))
433 tty_hangup(tty);
434 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 }
Alan Coxdeb91682008-07-22 11:13:08 +0100436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100438 err = usb_submit_urb(urb, GFP_ATOMIC);
439 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700440 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441exit: ;
442}
443
David Howells7d12e782006-10-05 14:55:46 +0100444static void usa26_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446}
447
448
David Howells7d12e782006-10-05 14:55:46 +0100449static void usa28_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
Alan Coxf035a8a2008-07-22 11:13:32 +0100451 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 struct usb_serial_port *port;
453 struct tty_struct *tty;
454 unsigned char *data;
455 struct keyspan_port_private *p_priv;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700456 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
Ming Leicdc97792008-02-24 18:41:47 +0800458 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 p_priv = usb_get_serial_port_data(port);
460 data = urb->transfer_buffer;
461
462 if (urb != p_priv->in_urbs[p_priv->in_flip])
463 return;
464
465 do {
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700466 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700467 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
468 __func__, status, usb_pipeendpoint(urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 return;
470 }
471
Ming Leicdc97792008-02-24 18:41:47 +0800472 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 p_priv = usb_get_serial_port_data(port);
474 data = urb->transfer_buffer;
475
Ben Minerds40adac82012-07-12 00:10:17 +1000476 tty = tty_port_tty_get(&port->port);
Alan Cox4a90f092008-10-13 10:39:46 +0100477 if (tty && urb->actual_length) {
Alan Coxf035a8a2008-07-22 11:13:32 +0100478 tty_insert_flip_string(tty, data, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 tty_flip_buffer_push(tty);
480 }
Alan Cox4a90f092008-10-13 10:39:46 +0100481 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500484 err = usb_submit_urb(urb, GFP_ATOMIC);
485 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700486 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
Alan Stern1f871582010-02-17 10:05:47 -0500487 __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 p_priv->in_flip ^= 1;
489
490 urb = p_priv->in_urbs[p_priv->in_flip];
491 } while (urb->status != -EINPROGRESS);
492}
493
David Howells7d12e782006-10-05 14:55:46 +0100494static void usa28_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496}
497
David Howells7d12e782006-10-05 14:55:46 +0100498static void usa28_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
500 struct usb_serial_port *port;
501 struct keyspan_port_private *p_priv;
502
Ming Leicdc97792008-02-24 18:41:47 +0800503 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 p_priv = usb_get_serial_port_data(port);
505
506 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700507 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100508 keyspan_usa28_send_setup(port->serial, port,
509 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 }
511}
512
David Howells7d12e782006-10-05 14:55:46 +0100513static void usa28_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514{
515 int err;
516 unsigned char *data = urb->transfer_buffer;
517 struct keyspan_usa28_portStatusMessage *msg;
518 struct usb_serial *serial;
519 struct usb_serial_port *port;
520 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100521 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700523 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Ming Leicdc97792008-02-24 18:41:47 +0800525 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700527 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700528 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 return;
530 }
531
532 if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700533 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 goto exit;
535 }
536
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700537 /*
538 dev_dbg(&urb->dev->dev,
539 "%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__,
540 data[0], data[1], data[2], data[3], data[4], data[5],
541 data[6], data[7], data[8], data[9], data[10], data[11]);
542 */
Alan Coxdeb91682008-07-22 11:13:08 +0100543
544 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 msg = (struct keyspan_usa28_portStatusMessage *)data;
546
Alan Coxdeb91682008-07-22 11:13:08 +0100547 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700549 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 goto exit;
551 }
552 port = serial->port[msg->port];
553 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100554
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 /* Update handshaking pin state information */
556 old_dcd_state = p_priv->dcd_state;
557 p_priv->cts_state = ((msg->cts) ? 1 : 0);
558 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
559 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
560 p_priv->ri_state = ((msg->ri) ? 1 : 0);
561
Ben Minerdsddc04ae2012-07-12 00:10:18 +1000562 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
Alan Cox4a90f092008-10-13 10:39:46 +0100563 tty = tty_port_tty_get(&port->port);
Ben Minerds878b5fd2012-07-12 00:10:19 +1000564 if (tty && !C_CLOCAL(tty))
Alan Cox4a90f092008-10-13 10:39:46 +0100565 tty_hangup(tty);
566 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 }
568
569 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100570 err = usb_submit_urb(urb, GFP_ATOMIC);
571 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700572 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573exit: ;
574}
575
David Howells7d12e782006-10-05 14:55:46 +0100576static void usa28_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578}
579
580
David Howells7d12e782006-10-05 14:55:46 +0100581static void usa49_glocont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582{
583 struct usb_serial *serial;
584 struct usb_serial_port *port;
585 struct keyspan_port_private *p_priv;
586 int i;
587
Ming Leicdc97792008-02-24 18:41:47 +0800588 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 for (i = 0; i < serial->num_ports; ++i) {
590 port = serial->port[i];
591 p_priv = usb_get_serial_port_data(port);
592
593 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700594 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100595 keyspan_usa49_send_setup(serial, port,
596 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 break;
598 }
599 }
600}
601
602 /* This is actually called glostat in the Keyspan
603 doco */
David Howells7d12e782006-10-05 14:55:46 +0100604static void usa49_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605{
606 int err;
607 unsigned char *data = urb->transfer_buffer;
608 struct keyspan_usa49_portStatusMessage *msg;
609 struct usb_serial *serial;
610 struct usb_serial_port *port;
611 struct keyspan_port_private *p_priv;
612 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700613 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
Ming Leicdc97792008-02-24 18:41:47 +0800615 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700617 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700618 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 return;
620 }
621
Alan Coxdeb91682008-07-22 11:13:08 +0100622 if (urb->actual_length !=
623 sizeof(struct keyspan_usa49_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700624 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 goto exit;
626 }
627
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700628 /*
629 dev_dbg(&urb->dev->dev, "%s: %x %x %x %x %x %x %x %x %x %x %x",
630 __func__, data[0], data[1], data[2], data[3], data[4],
631 data[5], data[6], data[7], data[8], data[9], data[10]);
632 */
Alan Coxdeb91682008-07-22 11:13:08 +0100633
634 /* Now do something useful with the data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 msg = (struct keyspan_usa49_portStatusMessage *)data;
636
Alan Coxdeb91682008-07-22 11:13:08 +0100637 /* Check port number from message and retrieve private data */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 if (msg->portNumber >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700639 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
640 __func__, msg->portNumber);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 goto exit;
642 }
643 port = serial->port[msg->portNumber];
644 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 /* Update handshaking pin state information */
647 old_dcd_state = p_priv->dcd_state;
648 p_priv->cts_state = ((msg->cts) ? 1 : 0);
649 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
650 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
651 p_priv->ri_state = ((msg->ri) ? 1 : 0);
652
Alan Cox4a90f092008-10-13 10:39:46 +0100653 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
654 struct tty_struct *tty = tty_port_tty_get(&port->port);
655 if (tty && !C_CLOCAL(tty))
656 tty_hangup(tty);
657 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 }
659
Alan Coxdeb91682008-07-22 11:13:08 +0100660 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100661 err = usb_submit_urb(urb, GFP_ATOMIC);
662 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700663 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664exit: ;
665}
666
David Howells7d12e782006-10-05 14:55:46 +0100667static void usa49_inack_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669}
670
David Howells7d12e782006-10-05 14:55:46 +0100671static void usa49_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672{
673 int i, err;
674 int endpoint;
675 struct usb_serial_port *port;
676 struct tty_struct *tty;
677 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700678 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 endpoint = usb_pipeendpoint(urb->pipe);
681
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700682 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700683 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
684 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 return;
686 }
687
Ming Leicdc97792008-02-24 18:41:47 +0800688 port = urb->context;
Alan Cox4a90f092008-10-13 10:39:46 +0100689 tty = tty_port_tty_get(&port->port);
Alan Cox3004e532008-01-03 16:59:04 +0000690 if (tty && urb->actual_length) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 /* 0x80 bit is error flag */
692 if ((data[0] & 0x80) == 0) {
693 /* no error on any byte */
Alan Coxf035a8a2008-07-22 11:13:32 +0100694 tty_insert_flip_string(tty, data + 1,
695 urb->actual_length - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 } else {
697 /* some bytes had errors, every byte has status */
698 for (i = 0; i + 1 < urb->actual_length; i += 2) {
699 int stat = data[i], flag = 0;
700 if (stat & RXERROR_OVERRUN)
701 flag |= TTY_OVERRUN;
702 if (stat & RXERROR_FRAMING)
703 flag |= TTY_FRAME;
704 if (stat & RXERROR_PARITY)
705 flag |= TTY_PARITY;
706 /* XXX should handle break (0x10) */
707 tty_insert_flip_char(tty, data[i+1], flag);
708 }
709 }
710 tty_flip_buffer_push(tty);
711 }
Alan Cox4a90f092008-10-13 10:39:46 +0100712 tty_kref_put(tty);
Alan Coxdeb91682008-07-22 11:13:08 +0100713
714 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500715 err = usb_submit_urb(urb, GFP_ATOMIC);
716 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700717 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718}
719
Lucy McCoy0ca12682007-05-18 12:10:41 -0700720static void usa49wg_indat_callback(struct urb *urb)
721{
722 int i, len, x, err;
723 struct usb_serial *serial;
724 struct usb_serial_port *port;
725 struct tty_struct *tty;
726 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700727 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700728
Lucy McCoy0ca12682007-05-18 12:10:41 -0700729 serial = urb->context;
730
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700731 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700732 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700733 return;
734 }
735
736 /* inbound data is in the form P#, len, status, data */
737 i = 0;
738 len = 0;
739
740 if (urb->actual_length) {
741 while (i < urb->actual_length) {
742
743 /* Check port number from message*/
744 if (data[i] >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700745 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800746 __func__, data[i]);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700747 return;
748 }
749 port = serial->port[data[i++]];
Alan Cox4a90f092008-10-13 10:39:46 +0100750 tty = tty_port_tty_get(&port->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700751 len = data[i++];
752
753 /* 0x80 bit is error flag */
754 if ((data[i] & 0x80) == 0) {
755 /* no error on any byte */
756 i++;
757 for (x = 1; x < len ; ++x)
Alan Stern1f871582010-02-17 10:05:47 -0500758 tty_insert_flip_char(tty, data[i++], 0);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700759 } else {
760 /*
761 * some bytes had errors, every byte has status
762 */
763 for (x = 0; x + 1 < len; x += 2) {
764 int stat = data[i], flag = 0;
765 if (stat & RXERROR_OVERRUN)
766 flag |= TTY_OVERRUN;
767 if (stat & RXERROR_FRAMING)
768 flag |= TTY_FRAME;
769 if (stat & RXERROR_PARITY)
770 flag |= TTY_PARITY;
771 /* XXX should handle break (0x10) */
Alan Stern1f871582010-02-17 10:05:47 -0500772 tty_insert_flip_char(tty,
Lucy McCoy0ca12682007-05-18 12:10:41 -0700773 data[i+1], flag);
774 i += 2;
775 }
776 }
Alan Stern1f871582010-02-17 10:05:47 -0500777 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100778 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700779 }
780 }
781
782 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700783 err = usb_submit_urb(urb, GFP_ATOMIC);
784 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700785 dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700786}
787
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788/* not used, usa-49 doesn't have per-port control endpoints */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700789static void usa49_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791}
792
Lucy McCoy0ca12682007-05-18 12:10:41 -0700793static void usa90_indat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{
795 int i, err;
796 int endpoint;
797 struct usb_serial_port *port;
798 struct keyspan_port_private *p_priv;
799 struct tty_struct *tty;
800 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700801 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 endpoint = usb_pipeendpoint(urb->pipe);
804
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700805 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700806 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800807 __func__, status, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 return;
809 }
810
Ming Leicdc97792008-02-24 18:41:47 +0800811 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 p_priv = usb_get_serial_port_data(port);
813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 if (urb->actual_length) {
Alan Cox4a90f092008-10-13 10:39:46 +0100815 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 /* if current mode is DMA, looks like usa28 format
Alan Coxdeb91682008-07-22 11:13:08 +0100817 otherwise looks like usa26 data format */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
Alan Coxf035a8a2008-07-22 11:13:32 +0100819 if (p_priv->baud > 57600)
820 tty_insert_flip_string(tty, data, urb->actual_length);
821 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 /* 0x80 bit is error flag */
823 if ((data[0] & 0x80) == 0) {
Alan Coxdeb91682008-07-22 11:13:08 +0100824 /* no errors on individual bytes, only
825 possible overrun err*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (data[0] & RXERROR_OVERRUN)
Alan Coxdeb91682008-07-22 11:13:08 +0100827 err = TTY_OVERRUN;
828 else
829 err = 0;
830 for (i = 1; i < urb->actual_length ; ++i)
831 tty_insert_flip_char(tty, data[i],
832 err);
833 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 /* some bytes had errors, every byte has status */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700835 dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 for (i = 0; i + 1 < urb->actual_length; i += 2) {
837 int stat = data[i], flag = 0;
838 if (stat & RXERROR_OVERRUN)
839 flag |= TTY_OVERRUN;
840 if (stat & RXERROR_FRAMING)
841 flag |= TTY_FRAME;
842 if (stat & RXERROR_PARITY)
843 flag |= TTY_PARITY;
844 /* XXX should handle break (0x10) */
Alan Coxdeb91682008-07-22 11:13:08 +0100845 tty_insert_flip_char(tty, data[i+1],
846 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848 }
849 }
850 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100851 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 }
Alan Coxdeb91682008-07-22 11:13:08 +0100853
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 /* Resubmit urb so we continue receiving */
Alan Stern1f871582010-02-17 10:05:47 -0500855 err = usb_submit_urb(urb, GFP_ATOMIC);
856 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700857 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858}
859
860
David Howells7d12e782006-10-05 14:55:46 +0100861static void usa90_instat_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862{
863 unsigned char *data = urb->transfer_buffer;
864 struct keyspan_usa90_portStatusMessage *msg;
865 struct usb_serial *serial;
866 struct usb_serial_port *port;
867 struct keyspan_port_private *p_priv;
Alan Cox4a90f092008-10-13 10:39:46 +0100868 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 int old_dcd_state, err;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700870 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
Ming Leicdc97792008-02-24 18:41:47 +0800872 serial = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700874 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700875 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 return;
877 }
878 if (urb->actual_length < 14) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700879 dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 goto exit;
881 }
882
883 msg = (struct keyspan_usa90_portStatusMessage *)data;
884
885 /* Now do something useful with the data */
886
887 port = serial->port[0];
888 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +0100889
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 /* Update handshaking pin state information */
891 old_dcd_state = p_priv->dcd_state;
892 p_priv->cts_state = ((msg->cts) ? 1 : 0);
893 p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
894 p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
895 p_priv->ri_state = ((msg->ri) ? 1 : 0);
896
Alan Cox4a90f092008-10-13 10:39:46 +0100897 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
898 tty = tty_port_tty_get(&port->port);
899 if (tty && !C_CLOCAL(tty))
900 tty_hangup(tty);
901 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 }
Alan Coxdeb91682008-07-22 11:13:08 +0100903
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 /* Resubmit urb so we continue receiving */
Alan Coxdeb91682008-07-22 11:13:08 +0100905 err = usb_submit_urb(urb, GFP_ATOMIC);
906 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700907 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908exit:
909 ;
910}
911
David Howells7d12e782006-10-05 14:55:46 +0100912static void usa90_outcont_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913{
914 struct usb_serial_port *port;
915 struct keyspan_port_private *p_priv;
916
Ming Leicdc97792008-02-24 18:41:47 +0800917 port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 p_priv = usb_get_serial_port_data(port);
919
920 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700921 dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
Alan Coxdeb91682008-07-22 11:13:08 +0100922 keyspan_usa90_send_setup(port->serial, port,
923 p_priv->resend_cont - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 }
925}
926
Lucy McCoy0ca12682007-05-18 12:10:41 -0700927/* Status messages from the 28xg */
928static void usa67_instat_callback(struct urb *urb)
929{
930 int err;
931 unsigned char *data = urb->transfer_buffer;
932 struct keyspan_usa67_portStatusMessage *msg;
933 struct usb_serial *serial;
934 struct usb_serial_port *port;
935 struct keyspan_port_private *p_priv;
936 int old_dcd_state;
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700937 int status = urb->status;
Lucy McCoy0ca12682007-05-18 12:10:41 -0700938
Lucy McCoy0ca12682007-05-18 12:10:41 -0700939 serial = urb->context;
940
Greg Kroah-Hartman95b93452007-06-15 15:44:13 -0700941 if (status) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700942 dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700943 return;
944 }
945
Alan Coxdeb91682008-07-22 11:13:08 +0100946 if (urb->actual_length !=
947 sizeof(struct keyspan_usa67_portStatusMessage)) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700948 dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700949 return;
950 }
951
952
953 /* Now do something useful with the data */
954 msg = (struct keyspan_usa67_portStatusMessage *)data;
955
956 /* Check port number from message and retrieve private data */
957 if (msg->port >= serial->num_ports) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700958 dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700959 return;
960 }
961
962 port = serial->port[msg->port];
963 p_priv = usb_get_serial_port_data(port);
964
965 /* Update handshaking pin state information */
966 old_dcd_state = p_priv->dcd_state;
967 p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
968 p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
969
Alan Cox4a90f092008-10-13 10:39:46 +0100970 if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
971 struct tty_struct *tty = tty_port_tty_get(&port->port);
972 if (tty && !C_CLOCAL(tty))
973 tty_hangup(tty);
974 tty_kref_put(tty);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700975 }
976
977 /* Resubmit urb so we continue receiving */
Lucy McCoy0ca12682007-05-18 12:10:41 -0700978 err = usb_submit_urb(urb, GFP_ATOMIC);
979 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700980 dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700981}
982
983static void usa67_glocont_callback(struct urb *urb)
984{
985 struct usb_serial *serial;
986 struct usb_serial_port *port;
987 struct keyspan_port_private *p_priv;
988 int i;
989
Lucy McCoy0ca12682007-05-18 12:10:41 -0700990 serial = urb->context;
991 for (i = 0; i < serial->num_ports; ++i) {
992 port = serial->port[i];
993 p_priv = usb_get_serial_port_data(port);
994
995 if (p_priv->resend_cont) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -0700996 dev_dbg(&port->dev, "%s - sending setup\n", __func__);
Lucy McCoy0ca12682007-05-18 12:10:41 -0700997 keyspan_usa67_send_setup(serial, port,
998 p_priv->resend_cont - 1);
999 break;
1000 }
1001 }
1002}
1003
Alan Cox95da3102008-07-22 11:09:07 +01001004static int keyspan_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005{
Alan Cox95da3102008-07-22 11:09:07 +01001006 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 struct keyspan_port_private *p_priv;
1008 const struct keyspan_device_details *d_details;
1009 int flip;
1010 int data_len;
1011 struct urb *this_urb;
1012
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 p_priv = usb_get_serial_port_data(port);
1014 d_details = p_priv->device_details;
1015
Alan Coxa5b6f602008-04-08 17:16:06 +01001016 /* FIXME: locking */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (d_details->msg_format == msg_usa90)
Alan Coxdeb91682008-07-22 11:13:08 +01001018 data_len = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 else
1020 data_len = 63;
1021
1022 flip = p_priv->out_flip;
1023
1024 /* Check both endpoints to see if any are available. */
Alan Coxdeb91682008-07-22 11:13:08 +01001025 this_urb = p_priv->out_urbs[flip];
1026 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001028 return data_len;
1029 flip = (flip + 1) & d_details->outdat_endp_flip;
1030 this_urb = p_priv->out_urbs[flip];
1031 if (this_urb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 if (this_urb->status != -EINPROGRESS)
Alan Coxdeb91682008-07-22 11:13:08 +01001033 return data_len;
1034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 }
Alan Coxa5b6f602008-04-08 17:16:06 +01001036 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037}
1038
1039
Alan Coxa509a7e2009-09-19 13:13:26 -07001040static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041{
Andrew Mortonf78ba152007-11-28 16:21:54 -08001042 struct keyspan_port_private *p_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 const struct keyspan_device_details *d_details;
1044 int i, err;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001045 int baud_rate, device_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 struct urb *urb;
Alan Cox95da3102008-07-22 11:09:07 +01001047 unsigned int cflag = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 p_priv = usb_get_serial_port_data(port);
1050 d_details = p_priv->device_details;
Borislav Petkov7eea4362007-11-14 17:00:39 -08001051
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 /* Set some sane defaults */
1053 p_priv->rts_state = 1;
1054 p_priv->dtr_state = 1;
1055 p_priv->baud = 9600;
1056
1057 /* force baud and lcr to be set on open */
1058 p_priv->old_baud = 0;
1059 p_priv->old_cflag = 0;
1060
1061 p_priv->out_flip = 0;
1062 p_priv->in_flip = 0;
1063
1064 /* Reset low level data toggle and start reading from endpoints */
1065 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001066 urb = p_priv->in_urbs[i];
1067 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
Alan Coxdeb91682008-07-22 11:13:08 +01001070 /* make sure endpoint data toggle is synchronized
1071 with the device */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 usb_clear_halt(urb->dev, urb->pipe);
Alan Coxdeb91682008-07-22 11:13:08 +01001073 err = usb_submit_urb(urb, GFP_KERNEL);
1074 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001075 dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 }
1077
1078 /* Reset low level data toggle on out endpoints */
1079 for (i = 0; i < 2; i++) {
Alan Coxdeb91682008-07-22 11:13:08 +01001080 urb = p_priv->out_urbs[i];
1081 if (urb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 continue;
Alan Coxdeb91682008-07-22 11:13:08 +01001083 /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
1084 usb_pipeout(urb->pipe), 0); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 }
1086
Andrew Mortonf78ba152007-11-28 16:21:54 -08001087 /* get the terminal config for the setup message now so we don't
1088 * need to send 2 of them */
1089
Andrew Mortonf78ba152007-11-28 16:21:54 -08001090 device_port = port->number - port->serial->minor;
Alan Cox95da3102008-07-22 11:09:07 +01001091 if (tty) {
1092 cflag = tty->termios->c_cflag;
1093 /* Baud rate calculation takes baud rate as an integer
1094 so other rates can be generated if desired. */
1095 baud_rate = tty_get_baud_rate(tty);
1096 /* If no match or invalid, leave as default */
1097 if (baud_rate >= 0
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001098 && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
Alan Cox95da3102008-07-22 11:09:07 +01001099 NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
1100 p_priv->baud = baud_rate;
1101 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001102 }
Andrew Mortonf78ba152007-11-28 16:21:54 -08001103 /* set CTS/RTS handshake etc. */
1104 p_priv->cflag = cflag;
Ben Minerds2b982ab2012-07-12 00:10:16 +10001105 p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
Andrew Mortonf78ba152007-11-28 16:21:54 -08001106
1107 keyspan_send_setup(port, 1);
Alan Coxdeb91682008-07-22 11:13:08 +01001108 /* mdelay(100); */
1109 /* keyspan_set_termios(port, NULL); */
Andrew Mortonf78ba152007-11-28 16:21:54 -08001110
Alan Coxa5b6f602008-04-08 17:16:06 +01001111 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112}
1113
1114static inline void stop_urb(struct urb *urb)
1115{
Greg Kroah-Hartman242cf672005-07-29 16:11:07 -04001116 if (urb && urb->status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 usb_kill_urb(urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118}
1119
Alan Cox335f8512009-06-11 12:26:29 +01001120static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
1121{
1122 struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
1123
1124 p_priv->rts_state = on;
1125 p_priv->dtr_state = on;
1126 keyspan_send_setup(port, 0);
1127}
1128
1129static void keyspan_close(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130{
1131 int i;
1132 struct usb_serial *serial = port->serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 struct keyspan_port_private *p_priv;
1134
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 p_priv = usb_get_serial_port_data(port);
Alan Coxdeb91682008-07-22 11:13:08 +01001136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 p_priv->rts_state = 0;
1138 p_priv->dtr_state = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001139
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 if (serial->dev) {
1141 keyspan_send_setup(port, 2);
1142 /* pilot-xfer seems to work best with this delay */
1143 mdelay(100);
Alan Coxdeb91682008-07-22 11:13:08 +01001144 /* keyspan_set_termios(port, NULL); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 }
1146
1147 /*while (p_priv->outcont_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001148 dev_dbg(&port->dev, "%s - urb in progress\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 }*/
1150
1151 p_priv->out_flip = 0;
1152 p_priv->in_flip = 0;
1153
1154 if (serial->dev) {
1155 /* Stop reading/writing urbs */
1156 stop_urb(p_priv->inack_urb);
1157 /* stop_urb(p_priv->outcont_urb); */
1158 for (i = 0; i < 2; i++) {
1159 stop_urb(p_priv->in_urbs[i]);
1160 stop_urb(p_priv->out_urbs[i]);
1161 }
1162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163}
1164
Alan Coxdeb91682008-07-22 11:13:08 +01001165/* download the firmware to a pre-renumeration device */
1166static int keyspan_fake_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167{
Rene Buergel8d733e22012-09-18 09:02:01 +02001168 char *fw_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001170 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
1171 le16_to_cpu(serial->dev->descriptor.bcdDevice),
1172 le16_to_cpu(serial->dev->descriptor.idProduct));
Alan Coxdeb91682008-07-22 11:13:08 +01001173
1174 if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
1175 != 0x8000) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001176 dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n");
Alan Coxdeb91682008-07-22 11:13:08 +01001177 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 }
1179
1180 /* Select firmware image on the basis of idProduct */
1181 switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
1182 case keyspan_usa28_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001183 fw_name = "keyspan/usa28.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 break;
1185
1186 case keyspan_usa28x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001187 fw_name = "keyspan/usa28x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 break;
1189
1190 case keyspan_usa28xa_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001191 fw_name = "keyspan/usa28xa.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 break;
1193
1194 case keyspan_usa28xb_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001195 fw_name = "keyspan/usa28xb.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 break;
1197
1198 case keyspan_usa19_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001199 fw_name = "keyspan/usa19.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001201
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 case keyspan_usa19qi_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001203 fw_name = "keyspan/usa19qi.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001205
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 case keyspan_mpr_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001207 fw_name = "keyspan/mpr.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 break;
1209
1210 case keyspan_usa19qw_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001211 fw_name = "keyspan/usa19qw.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 case keyspan_usa18x_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001215 fw_name = "keyspan/usa18x.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001217
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 case keyspan_usa19w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001219 fw_name = "keyspan/usa19w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 break;
Alan Coxdeb91682008-07-22 11:13:08 +01001221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 case keyspan_usa49w_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001223 fw_name = "keyspan/usa49w.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 break;
1225
1226 case keyspan_usa49wlc_pre_product_id:
David Woodhouse2971c572008-05-30 14:04:03 +03001227 fw_name = "keyspan/usa49wlc.fw";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 break;
1229
1230 default:
David Woodhouse2971c572008-05-30 14:04:03 +03001231 dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
1232 le16_to_cpu(serial->dev->descriptor.idProduct));
1233 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 }
1235
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001236 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
Rene Buergel8d733e22012-09-18 09:02:01 +02001238 if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
1239 dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
1240 fw_name);
1241 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
Rene Buergel8d733e22012-09-18 09:02:01 +02001243
1244 /* after downloading firmware Renumeration will occur in a
1245 moment and the new device will bind to the real driver */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247 /* we don't want this device to have a driver assigned to it. */
Alan Coxdeb91682008-07-22 11:13:08 +01001248 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249}
1250
1251/* Helper functions used by keyspan_setup_urbs */
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001252static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1253 int endpoint)
1254{
1255 struct usb_host_interface *iface_desc;
1256 struct usb_endpoint_descriptor *ep;
1257 int i;
1258
1259 iface_desc = serial->interface->cur_altsetting;
1260 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1261 ep = &iface_desc->endpoint[i].desc;
1262 if (ep->bEndpointAddress == endpoint)
1263 return ep;
1264 }
1265 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1266 "endpoint %x\n", endpoint);
1267 return NULL;
1268}
1269
Alan Coxdeb91682008-07-22 11:13:08 +01001270static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 int dir, void *ctx, char *buf, int len,
David Howells7d12e782006-10-05 14:55:46 +01001272 void (*callback)(struct urb *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273{
1274 struct urb *urb;
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001275 struct usb_endpoint_descriptor const *ep_desc;
1276 char const *ep_type_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
1278 if (endpoint == -1)
1279 return NULL; /* endpoint not needed */
1280
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001281 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
1283 if (urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001284 dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d failed.\n", __func__, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 return NULL;
1286 }
1287
Lucy McCoy0ca12682007-05-18 12:10:41 -07001288 if (endpoint == 0) {
1289 /* control EP filled in when used */
1290 return urb;
1291 }
1292
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001293 ep_desc = find_ep(serial, endpoint);
1294 if (!ep_desc) {
1295 /* leak the urb, something's wrong and the callers don't care */
1296 return urb;
1297 }
1298 if (usb_endpoint_xfer_int(ep_desc)) {
1299 ep_type_name = "INT";
1300 usb_fill_int_urb(urb, serial->dev,
1301 usb_sndintpipe(serial->dev, endpoint) | dir,
1302 buf, len, callback, ctx,
1303 ep_desc->bInterval);
1304 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1305 ep_type_name = "BULK";
1306 usb_fill_bulk_urb(urb, serial->dev,
1307 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1308 buf, len, callback, ctx);
1309 } else {
1310 dev_warn(&serial->interface->dev,
1311 "unsupported endpoint type %x\n",
Julia Lawall2e0fe702008-12-29 11:22:14 +01001312 usb_endpoint_type(ep_desc));
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001313 usb_free_urb(urb);
1314 return NULL;
1315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001317 dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
Rainer Weikusatfdcba532007-01-03 15:36:25 +01001318 __func__, urb, ep_type_name, endpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 return urb;
1320}
1321
1322static struct callbacks {
David Howells7d12e782006-10-05 14:55:46 +01001323 void (*instat_callback)(struct urb *);
1324 void (*glocont_callback)(struct urb *);
1325 void (*indat_callback)(struct urb *);
1326 void (*outdat_callback)(struct urb *);
1327 void (*inack_callback)(struct urb *);
1328 void (*outcont_callback)(struct urb *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329} keyspan_callbacks[] = {
1330 {
1331 /* msg_usa26 callbacks */
1332 .instat_callback = usa26_instat_callback,
1333 .glocont_callback = usa26_glocont_callback,
1334 .indat_callback = usa26_indat_callback,
1335 .outdat_callback = usa2x_outdat_callback,
1336 .inack_callback = usa26_inack_callback,
1337 .outcont_callback = usa26_outcont_callback,
1338 }, {
1339 /* msg_usa28 callbacks */
1340 .instat_callback = usa28_instat_callback,
1341 .glocont_callback = usa28_glocont_callback,
1342 .indat_callback = usa28_indat_callback,
1343 .outdat_callback = usa2x_outdat_callback,
1344 .inack_callback = usa28_inack_callback,
1345 .outcont_callback = usa28_outcont_callback,
1346 }, {
1347 /* msg_usa49 callbacks */
1348 .instat_callback = usa49_instat_callback,
1349 .glocont_callback = usa49_glocont_callback,
1350 .indat_callback = usa49_indat_callback,
1351 .outdat_callback = usa2x_outdat_callback,
1352 .inack_callback = usa49_inack_callback,
1353 .outcont_callback = usa49_outcont_callback,
1354 }, {
1355 /* msg_usa90 callbacks */
1356 .instat_callback = usa90_instat_callback,
Alan Coxdeb91682008-07-22 11:13:08 +01001357 .glocont_callback = usa28_glocont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 .indat_callback = usa90_indat_callback,
1359 .outdat_callback = usa2x_outdat_callback,
1360 .inack_callback = usa28_inack_callback,
1361 .outcont_callback = usa90_outcont_callback,
Lucy McCoy0ca12682007-05-18 12:10:41 -07001362 }, {
1363 /* msg_usa67 callbacks */
1364 .instat_callback = usa67_instat_callback,
1365 .glocont_callback = usa67_glocont_callback,
1366 .indat_callback = usa26_indat_callback,
1367 .outdat_callback = usa2x_outdat_callback,
1368 .inack_callback = usa26_inack_callback,
1369 .outcont_callback = usa26_outcont_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 }
1371};
1372
1373 /* Generic setup urbs function that uses
1374 data in device_details */
1375static void keyspan_setup_urbs(struct usb_serial *serial)
1376{
1377 int i, j;
1378 struct keyspan_serial_private *s_priv;
1379 const struct keyspan_device_details *d_details;
1380 struct usb_serial_port *port;
1381 struct keyspan_port_private *p_priv;
1382 struct callbacks *cback;
1383 int endp;
1384
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 s_priv = usb_get_serial_data(serial);
1386 d_details = s_priv->device_details;
1387
Alan Coxdeb91682008-07-22 11:13:08 +01001388 /* Setup values for the various callback routines */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 cback = &keyspan_callbacks[d_details->msg_format];
1390
Alan Coxdeb91682008-07-22 11:13:08 +01001391 /* Allocate and set up urbs for each one that is in use,
1392 starting with instat endpoints */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 s_priv->instat_urb = keyspan_setup_urb
1394 (serial, d_details->instat_endpoint, USB_DIR_IN,
1395 serial, s_priv->instat_buf, INSTAT_BUFLEN,
1396 cback->instat_callback);
1397
Lucy McCoy0ca12682007-05-18 12:10:41 -07001398 s_priv->indat_urb = keyspan_setup_urb
1399 (serial, d_details->indat_endpoint, USB_DIR_IN,
1400 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
1401 usa49wg_indat_callback);
1402
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 s_priv->glocont_urb = keyspan_setup_urb
1404 (serial, d_details->glocont_endpoint, USB_DIR_OUT,
1405 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
1406 cback->glocont_callback);
1407
Alan Coxdeb91682008-07-22 11:13:08 +01001408 /* Setup endpoints for each port specific thing */
1409 for (i = 0; i < d_details->num_ports; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 port = serial->port[i];
1411 p_priv = usb_get_serial_port_data(port);
1412
1413 /* Do indat endpoints first, once for each flip */
1414 endp = d_details->indat_endpoints[i];
1415 for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) {
1416 p_priv->in_urbs[j] = keyspan_setup_urb
1417 (serial, endp, USB_DIR_IN, port,
1418 p_priv->in_buffer[j], 64,
1419 cback->indat_callback);
1420 }
1421 for (; j < 2; ++j)
1422 p_priv->in_urbs[j] = NULL;
1423
1424 /* outdat endpoints also have flip */
1425 endp = d_details->outdat_endpoints[i];
1426 for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) {
1427 p_priv->out_urbs[j] = keyspan_setup_urb
1428 (serial, endp, USB_DIR_OUT, port,
1429 p_priv->out_buffer[j], 64,
1430 cback->outdat_callback);
1431 }
1432 for (; j < 2; ++j)
1433 p_priv->out_urbs[j] = NULL;
1434
1435 /* inack endpoint */
1436 p_priv->inack_urb = keyspan_setup_urb
1437 (serial, d_details->inack_endpoints[i], USB_DIR_IN,
1438 port, p_priv->inack_buffer, 1, cback->inack_callback);
1439
1440 /* outcont endpoint */
1441 p_priv->outcont_urb = keyspan_setup_urb
1442 (serial, d_details->outcont_endpoints[i], USB_DIR_OUT,
1443 port, p_priv->outcont_buffer, 64,
1444 cback->outcont_callback);
Alan Coxdeb91682008-07-22 11:13:08 +01001445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446}
1447
1448/* usa19 function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001449static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
1450 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 u8 *rate_low, u8 *prescaler, int portnum)
1452{
1453 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001454 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 cnt; /* inverse of divisor (programmed into 8051) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001457 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
Alan Coxdeb91682008-07-22 11:13:08 +01001459 /* prevent divide by zero... */
1460 b16 = baud_rate * 16L;
1461 if (b16 == 0)
1462 return KEYSPAN_INVALID_BAUD_RATE;
1463 /* Any "standard" rate over 57k6 is marginal on the USA-19
1464 as we run out of divisor resolution. */
1465 if (baud_rate > 57600)
1466 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
Alan Coxdeb91682008-07-22 11:13:08 +01001468 /* calculate the divisor and the counter (its inverse) */
1469 div = baudclk / b16;
1470 if (div == 0)
1471 return KEYSPAN_INVALID_BAUD_RATE;
1472 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
Alan Coxdeb91682008-07-22 11:13:08 +01001475 if (div > 0xffff)
1476 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
Alan Coxdeb91682008-07-22 11:13:08 +01001478 /* return the counter values if non-null */
1479 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001481 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001483 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001484 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001485 __func__, baud_rate, *rate_hi, *rate_low);
1486 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487}
1488
1489/* usa19hs function doesn't require prescaler */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001490static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
1491 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1492 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
1494 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001495 div; /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001497 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
Alan Coxdeb91682008-07-22 11:13:08 +01001499 /* prevent divide by zero... */
1500 b16 = baud_rate * 16L;
1501 if (b16 == 0)
1502 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503
Alan Coxdeb91682008-07-22 11:13:08 +01001504 /* calculate the divisor */
1505 div = baudclk / b16;
1506 if (div == 0)
1507 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
Alan Coxdeb91682008-07-22 11:13:08 +01001509 if (div > 0xffff)
1510 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
Alan Coxdeb91682008-07-22 11:13:08 +01001512 /* return the counter values if non-null */
1513 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001515
1516 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 *rate_hi = (u8) ((div >> 8) & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001518
1519 if (rate_low && rate_hi)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001520 dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001521 __func__, baud_rate, *rate_hi, *rate_low);
1522
1523 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524}
1525
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001526static int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
1527 u32 baud_rate, u32 baudclk, u8 *rate_hi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 u8 *rate_low, u8 *prescaler, int portnum)
1529{
1530 u32 b16, /* baud rate times 16 (actual rate used internally) */
1531 clk, /* clock with 13/8 prescaler */
Alan Coxdeb91682008-07-22 11:13:08 +01001532 div, /* divisor using 13/8 prescaler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 res, /* resulting baud rate using 13/8 prescaler */
1534 diff, /* error using 13/8 prescaler */
1535 smallest_diff;
1536 u8 best_prescaler;
1537 int i;
1538
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001539 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
Alan Coxdeb91682008-07-22 11:13:08 +01001541 /* prevent divide by zero */
1542 b16 = baud_rate * 16L;
1543 if (b16 == 0)
1544 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545
Alan Coxdeb91682008-07-22 11:13:08 +01001546 /* Calculate prescaler by trying them all and looking
1547 for best fit */
1548
1549 /* start with largest possible difference */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 smallest_diff = 0xffffffff;
1551
1552 /* 0 is an invalid prescaler, used as a flag */
1553 best_prescaler = 0;
1554
Alan Coxdeb91682008-07-22 11:13:08 +01001555 for (i = 8; i <= 0xff; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 clk = (baudclk * 8) / (u32) i;
Alan Coxdeb91682008-07-22 11:13:08 +01001557
1558 div = clk / b16;
1559 if (div == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
1562 res = clk / div;
Alan Coxdeb91682008-07-22 11:13:08 +01001563 diff = (res > b16) ? (res-b16) : (b16-res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
Alan Coxdeb91682008-07-22 11:13:08 +01001565 if (diff < smallest_diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 best_prescaler = i;
1567 smallest_diff = diff;
1568 }
1569 }
1570
Alan Coxdeb91682008-07-22 11:13:08 +01001571 if (best_prescaler == 0)
1572 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573
1574 clk = (baudclk * 8) / (u32) best_prescaler;
1575 div = clk / b16;
1576
Alan Coxdeb91682008-07-22 11:13:08 +01001577 /* return the divisor and prescaler if non-null */
1578 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 *rate_low = (u8) (div & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001580 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 *rate_hi = (u8) ((div >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 if (prescaler) {
1583 *prescaler = best_prescaler;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001584 /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 }
Alan Coxdeb91682008-07-22 11:13:08 +01001586 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587}
1588
1589 /* USA-28 supports different maximum baud rates on each port */
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001590static int keyspan_usa28_calc_baud(struct usb_serial_port *port,
1591 u32 baud_rate, u32 baudclk, u8 *rate_hi,
1592 u8 *rate_low, u8 *prescaler, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593{
1594 u32 b16, /* baud rate times 16 (actual rate used internally) */
Alan Coxdeb91682008-07-22 11:13:08 +01001595 div, /* divisor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 cnt; /* inverse of divisor (programmed into 8051) */
1597
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001598 dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599
1600 /* prevent divide by zero */
Alan Coxdeb91682008-07-22 11:13:08 +01001601 b16 = baud_rate * 16L;
1602 if (b16 == 0)
1603 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
Alan Coxdeb91682008-07-22 11:13:08 +01001605 /* calculate the divisor and the counter (its inverse) */
1606 div = KEYSPAN_USA28_BAUDCLK / b16;
1607 if (div == 0)
1608 return KEYSPAN_INVALID_BAUD_RATE;
1609 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 cnt = 0 - div;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
Alan Coxdeb91682008-07-22 11:13:08 +01001612 /* check for out of range, based on portnum,
1613 and return result */
1614 if (portnum == 0) {
1615 if (div > 0xffff)
1616 return KEYSPAN_INVALID_BAUD_RATE;
1617 } else {
1618 if (portnum == 1) {
1619 if (div > 0xff)
1620 return KEYSPAN_INVALID_BAUD_RATE;
1621 } else
1622 return KEYSPAN_INVALID_BAUD_RATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 }
1624
1625 /* return the counter values if not NULL
1626 (port 1 will ignore retHi) */
Alan Coxdeb91682008-07-22 11:13:08 +01001627 if (rate_low)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 *rate_low = (u8) (cnt & 0xff);
Alan Coxdeb91682008-07-22 11:13:08 +01001629 if (rate_hi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 *rate_hi = (u8) ((cnt >> 8) & 0xff);
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001631 dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
Alan Coxdeb91682008-07-22 11:13:08 +01001632 return KEYSPAN_BAUD_RATE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633}
1634
1635static int keyspan_usa26_send_setup(struct usb_serial *serial,
1636 struct usb_serial_port *port,
1637 int reset_port)
1638{
Alan Coxdeb91682008-07-22 11:13:08 +01001639 struct keyspan_usa26_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 struct keyspan_serial_private *s_priv;
1641 struct keyspan_port_private *p_priv;
1642 const struct keyspan_device_details *d_details;
1643 int outcont_urb;
1644 struct urb *this_urb;
1645 int device_port, err;
1646
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001647 dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
1649 s_priv = usb_get_serial_data(serial);
1650 p_priv = usb_get_serial_port_data(port);
1651 d_details = s_priv->device_details;
1652 device_port = port->number - port->serial->minor;
1653
1654 outcont_urb = d_details->outcont_endpoints[port->number];
1655 this_urb = p_priv->outcont_urb;
1656
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001657 dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
1659 /* Make sure we have an urb then send the message */
1660 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001661 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 return -1;
1663 }
1664
1665 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001666 Don't overwrite resend for open/close condition. */
1667 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 p_priv->resend_cont = reset_port + 1;
1669 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001670 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001672 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 }
1674
Alan Coxdeb91682008-07-22 11:13:08 +01001675 memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
1676
1677 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 if (p_priv->old_baud != p_priv->baud) {
1679 p_priv->old_baud = p_priv->baud;
1680 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001681 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1682 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1683 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1684 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1685 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 msg.baudLo = 0;
1687 msg.baudHi = 125; /* Values for 9600 baud */
1688 msg.prescaler = 10;
1689 }
1690 msg.setPrescaler = 0xff;
1691 }
1692
Ben Minerds2b982ab2012-07-12 00:10:16 +10001693 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 switch (p_priv->cflag & CSIZE) {
1695 case CS5:
1696 msg.lcr |= USA_DATABITS_5;
1697 break;
1698 case CS6:
1699 msg.lcr |= USA_DATABITS_6;
1700 break;
1701 case CS7:
1702 msg.lcr |= USA_DATABITS_7;
1703 break;
1704 case CS8:
1705 msg.lcr |= USA_DATABITS_8;
1706 break;
1707 }
1708 if (p_priv->cflag & PARENB) {
1709 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001710 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001711 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 }
1713 msg.setLcr = 0xff;
1714
1715 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1716 msg.xonFlowControl = 0;
1717 msg.setFlowControl = 0xff;
1718 msg.forwardingLength = 16;
1719 msg.xonChar = 17;
1720 msg.xoffChar = 19;
1721
1722 /* Opening port */
1723 if (reset_port == 1) {
1724 msg._txOn = 1;
1725 msg._txOff = 0;
1726 msg.txFlush = 0;
1727 msg.txBreak = 0;
1728 msg.rxOn = 1;
1729 msg.rxOff = 0;
1730 msg.rxFlush = 1;
1731 msg.rxForward = 0;
1732 msg.returnStatus = 0;
1733 msg.resetDataToggle = 0xff;
1734 }
1735
1736 /* Closing port */
1737 else if (reset_port == 2) {
1738 msg._txOn = 0;
1739 msg._txOff = 1;
1740 msg.txFlush = 0;
1741 msg.txBreak = 0;
1742 msg.rxOn = 0;
1743 msg.rxOff = 1;
1744 msg.rxFlush = 1;
1745 msg.rxForward = 0;
1746 msg.returnStatus = 0;
1747 msg.resetDataToggle = 0;
1748 }
1749
1750 /* Sending intermediate configs */
1751 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001752 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 msg._txOff = 0;
1754 msg.txFlush = 0;
1755 msg.txBreak = (p_priv->break_on);
1756 msg.rxOn = 0;
1757 msg.rxOff = 0;
1758 msg.rxFlush = 0;
1759 msg.rxForward = 0;
1760 msg.returnStatus = 0;
1761 msg.resetDataToggle = 0x0;
1762 }
1763
Alan Coxdeb91682008-07-22 11:13:08 +01001764 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 msg.setTxTriState_setRts = 0xff;
1766 msg.txTriState_rts = p_priv->rts_state;
1767
1768 msg.setHskoa_setDtr = 0xff;
1769 msg.hskoa_dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01001770
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001772 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
1773
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 /* send the data out the device on control endpoint */
1775 this_urb->transfer_buffer_length = sizeof(msg);
1776
Alan Coxdeb91682008-07-22 11:13:08 +01001777 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1778 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001779 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780#if 0
1781 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001782 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__
1783 outcont_urb, this_urb->transfer_buffer_length,
1784 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 }
1786#endif
1787
Alan Coxa5b6f602008-04-08 17:16:06 +01001788 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789}
1790
1791static int keyspan_usa28_send_setup(struct usb_serial *serial,
1792 struct usb_serial_port *port,
1793 int reset_port)
1794{
Alan Coxdeb91682008-07-22 11:13:08 +01001795 struct keyspan_usa28_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 struct keyspan_serial_private *s_priv;
1797 struct keyspan_port_private *p_priv;
1798 const struct keyspan_device_details *d_details;
1799 struct urb *this_urb;
1800 int device_port, err;
1801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 s_priv = usb_get_serial_data(serial);
1803 p_priv = usb_get_serial_port_data(port);
1804 d_details = s_priv->device_details;
1805 device_port = port->number - port->serial->minor;
1806
1807 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01001808 this_urb = p_priv->outcont_urb;
1809 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001810 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 return -1;
1812 }
1813
1814 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001815 Don't overwrite resend for open/close condition. */
1816 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 p_priv->resend_cont = reset_port + 1;
1818 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001819 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001821 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 }
1823
Alan Coxdeb91682008-07-22 11:13:08 +01001824 memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
1826 msg.setBaudRate = 1;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001827 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1828 &msg.baudHi, &msg.baudLo, NULL,
1829 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1830 dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
Alan Coxdeb91682008-07-22 11:13:08 +01001831 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 msg.baudLo = 0xff;
1833 msg.baudHi = 0xb2; /* Values for 9600 baud */
1834 }
1835
1836 /* If parity is enabled, we must calculate it ourselves. */
1837 msg.parity = 0; /* XXX for now */
1838
1839 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
1840 msg.xonFlowControl = 0;
1841
Alan Coxdeb91682008-07-22 11:13:08 +01001842 /* Do handshaking outputs, DTR is inverted relative to RTS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 msg.rts = p_priv->rts_state;
1844 msg.dtr = p_priv->dtr_state;
1845
1846 msg.forwardingLength = 16;
1847 msg.forwardMs = 10;
1848 msg.breakThreshold = 45;
1849 msg.xonChar = 17;
1850 msg.xoffChar = 19;
1851
1852 /*msg.returnStatus = 1;
1853 msg.resetDataToggle = 0xff;*/
1854 /* Opening port */
1855 if (reset_port == 1) {
1856 msg._txOn = 1;
1857 msg._txOff = 0;
1858 msg.txFlush = 0;
1859 msg.txForceXoff = 0;
1860 msg.txBreak = 0;
1861 msg.rxOn = 1;
1862 msg.rxOff = 0;
1863 msg.rxFlush = 1;
1864 msg.rxForward = 0;
1865 msg.returnStatus = 0;
1866 msg.resetDataToggle = 0xff;
1867 }
1868 /* Closing port */
1869 else if (reset_port == 2) {
1870 msg._txOn = 0;
1871 msg._txOff = 1;
1872 msg.txFlush = 0;
1873 msg.txForceXoff = 0;
1874 msg.txBreak = 0;
1875 msg.rxOn = 0;
1876 msg.rxOff = 1;
1877 msg.rxFlush = 1;
1878 msg.rxForward = 0;
1879 msg.returnStatus = 0;
1880 msg.resetDataToggle = 0;
1881 }
1882 /* Sending intermediate configs */
1883 else {
Alan Coxdeb91682008-07-22 11:13:08 +01001884 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 msg._txOff = 0;
1886 msg.txFlush = 0;
1887 msg.txForceXoff = 0;
1888 msg.txBreak = (p_priv->break_on);
1889 msg.rxOn = 0;
1890 msg.rxOff = 0;
1891 msg.rxFlush = 0;
1892 msg.rxForward = 0;
1893 msg.returnStatus = 0;
1894 msg.resetDataToggle = 0x0;
1895 }
1896
1897 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01001898 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900 /* send the data out the device on control endpoint */
1901 this_urb->transfer_buffer_length = sizeof(msg);
1902
Alan Coxdeb91682008-07-22 11:13:08 +01001903 err = usb_submit_urb(this_urb, GFP_ATOMIC);
1904 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001905 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906#if 0
1907 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001908 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 this_urb->transfer_buffer_length);
1910 }
1911#endif
1912
Alan Coxa5b6f602008-04-08 17:16:06 +01001913 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914}
1915
1916static int keyspan_usa49_send_setup(struct usb_serial *serial,
1917 struct usb_serial_port *port,
1918 int reset_port)
1919{
Lucy McCoy0ca12682007-05-18 12:10:41 -07001920 struct keyspan_usa49_portControlMessage msg;
1921 struct usb_ctrlrequest *dr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 struct keyspan_serial_private *s_priv;
1923 struct keyspan_port_private *p_priv;
1924 const struct keyspan_device_details *d_details;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 struct urb *this_urb;
1926 int err, device_port;
1927
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 s_priv = usb_get_serial_data(serial);
1929 p_priv = usb_get_serial_port_data(port);
1930 d_details = s_priv->device_details;
1931
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 this_urb = s_priv->glocont_urb;
1933
Lucy McCoy0ca12682007-05-18 12:10:41 -07001934 /* Work out which port within the device is being setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 device_port = port->number - port->serial->minor;
1936
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301937 /* Make sure we have an urb then send the message */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001939 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 return -1;
1941 }
1942
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001943 dev_dbg(&port->dev, "%s - endpoint %d port %d (%d)\n",
1944 __func__, usb_pipeendpoint(this_urb->pipe),
1945 port->number, device_port);
Huzaifa Sidhpurwalad8661502011-02-21 12:58:44 +05301946
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 /* Save reset port val for resend.
Lucy McCoy0ca12682007-05-18 12:10:41 -07001948 Don't overwrite resend for open/close condition. */
1949 if ((reset_port + 1) > p_priv->resend_cont)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 p_priv->resend_cont = reset_port + 1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07001951
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001953 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01001955 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 }
1957
Alan Coxdeb91682008-07-22 11:13:08 +01001958 memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959
1960 /*msg.portNumber = port->number;*/
1961 msg.portNumber = device_port;
Alan Coxdeb91682008-07-22 11:13:08 +01001962
1963 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 if (p_priv->old_baud != p_priv->baud) {
1965 p_priv->old_baud = p_priv->baud;
1966 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07001967 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
1968 &msg.baudHi, &msg.baudLo, &msg.prescaler,
1969 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
1970 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
1971 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 msg.baudLo = 0;
1973 msg.baudHi = 125; /* Values for 9600 baud */
1974 msg.prescaler = 10;
1975 }
Alan Coxdeb91682008-07-22 11:13:08 +01001976 /* msg.setPrescaler = 0xff; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 }
1978
Ben Minerds2b982ab2012-07-12 00:10:16 +10001979 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 switch (p_priv->cflag & CSIZE) {
1981 case CS5:
1982 msg.lcr |= USA_DATABITS_5;
1983 break;
1984 case CS6:
1985 msg.lcr |= USA_DATABITS_6;
1986 break;
1987 case CS7:
1988 msg.lcr |= USA_DATABITS_7;
1989 break;
1990 case CS8:
1991 msg.lcr |= USA_DATABITS_8;
1992 break;
1993 }
1994 if (p_priv->cflag & PARENB) {
1995 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10001996 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01001997 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 }
1999 msg.setLcr = 0xff;
2000
2001 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2002 msg.xonFlowControl = 0;
2003 msg.setFlowControl = 0xff;
Alan Coxdeb91682008-07-22 11:13:08 +01002004
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 msg.forwardingLength = 16;
2006 msg.xonChar = 17;
2007 msg.xoffChar = 19;
2008
Alan Coxdeb91682008-07-22 11:13:08 +01002009 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 if (reset_port == 1) {
2011 msg._txOn = 1;
2012 msg._txOff = 0;
2013 msg.txFlush = 0;
2014 msg.txBreak = 0;
2015 msg.rxOn = 1;
2016 msg.rxOff = 0;
2017 msg.rxFlush = 1;
2018 msg.rxForward = 0;
2019 msg.returnStatus = 0;
2020 msg.resetDataToggle = 0xff;
2021 msg.enablePort = 1;
2022 msg.disablePort = 0;
2023 }
2024 /* Closing port */
2025 else if (reset_port == 2) {
2026 msg._txOn = 0;
2027 msg._txOff = 1;
2028 msg.txFlush = 0;
2029 msg.txBreak = 0;
2030 msg.rxOn = 0;
2031 msg.rxOff = 1;
2032 msg.rxFlush = 1;
2033 msg.rxForward = 0;
2034 msg.returnStatus = 0;
2035 msg.resetDataToggle = 0;
2036 msg.enablePort = 0;
2037 msg.disablePort = 1;
2038 }
2039 /* Sending intermediate configs */
2040 else {
Alan Coxdeb91682008-07-22 11:13:08 +01002041 msg._txOn = (!p_priv->break_on);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 msg._txOff = 0;
2043 msg.txFlush = 0;
2044 msg.txBreak = (p_priv->break_on);
2045 msg.rxOn = 0;
2046 msg.rxOff = 0;
2047 msg.rxFlush = 0;
2048 msg.rxForward = 0;
2049 msg.returnStatus = 0;
2050 msg.resetDataToggle = 0x0;
2051 msg.enablePort = 0;
2052 msg.disablePort = 0;
2053 }
2054
Alan Coxdeb91682008-07-22 11:13:08 +01002055 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 msg.setRts = 0xff;
2057 msg.rts = p_priv->rts_state;
2058
2059 msg.setDtr = 0xff;
2060 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002061
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 p_priv->resend_cont = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063
Alan Coxdeb91682008-07-22 11:13:08 +01002064 /* if the device is a 49wg, we send control message on usb
2065 control EP 0 */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002066
2067 if (d_details->product_id == keyspan_usa49wg_product_id) {
2068 dr = (void *)(s_priv->ctrl_buf);
2069 dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
2070 dr->bRequest = 0xB0; /* 49wg control message */;
2071 dr->wValue = 0;
2072 dr->wIndex = 0;
2073 dr->wLength = cpu_to_le16(sizeof(msg));
2074
Alan Coxdeb91682008-07-22 11:13:08 +01002075 memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
Lucy McCoy0ca12682007-05-18 12:10:41 -07002076
Alan Coxdeb91682008-07-22 11:13:08 +01002077 usb_fill_control_urb(this_urb, serial->dev,
2078 usb_sndctrlpipe(serial->dev, 0),
2079 (unsigned char *)dr, s_priv->glocont_buf,
2080 sizeof(msg), usa49_glocont_callback, serial);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002081
2082 } else {
2083 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
Alan Coxdeb91682008-07-22 11:13:08 +01002084
Lucy McCoy0ca12682007-05-18 12:10:41 -07002085 /* send the data out the device on control endpoint */
2086 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002087 }
Alan Coxdeb91682008-07-22 11:13:08 +01002088 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2089 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002090 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091#if 0
2092 else {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002093 dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__,
2094 outcont_urb, this_urb->transfer_buffer_length,
2095 usb_pipeendpoint(this_urb->pipe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 }
2097#endif
2098
Alan Coxa5b6f602008-04-08 17:16:06 +01002099 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100}
2101
2102static int keyspan_usa90_send_setup(struct usb_serial *serial,
2103 struct usb_serial_port *port,
2104 int reset_port)
2105{
Alan Coxdeb91682008-07-22 11:13:08 +01002106 struct keyspan_usa90_portControlMessage msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 struct keyspan_serial_private *s_priv;
2108 struct keyspan_port_private *p_priv;
2109 const struct keyspan_device_details *d_details;
2110 struct urb *this_urb;
2111 int err;
2112 u8 prescaler;
2113
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 s_priv = usb_get_serial_data(serial);
2115 p_priv = usb_get_serial_port_data(port);
2116 d_details = s_priv->device_details;
2117
2118 /* only do something if we have a bulk out endpoint */
Alan Coxdeb91682008-07-22 11:13:08 +01002119 this_urb = p_priv->outcont_urb;
2120 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002121 dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 return -1;
2123 }
2124
2125 /* Save reset port val for resend.
2126 Don't overwrite resend for open/close condition. */
2127 if ((reset_port + 1) > p_priv->resend_cont)
2128 p_priv->resend_cont = reset_port + 1;
2129 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002130 dev_dbg(&port->dev, "%s already writing\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002132 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 }
2134
Alan Coxdeb91682008-07-22 11:13:08 +01002135 memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136
Alan Coxdeb91682008-07-22 11:13:08 +01002137 /* Only set baud rate if it's changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 if (p_priv->old_baud != p_priv->baud) {
2139 p_priv->old_baud = p_priv->baud;
2140 msg.setClocking = 0x01;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002141 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2142 &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
2143 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2144 __func__, p_priv->baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 p_priv->baud = 9600;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002146 d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 &msg.baudHi, &msg.baudLo, &prescaler, 0);
2148 }
2149 msg.setRxMode = 1;
2150 msg.setTxMode = 1;
2151 }
2152
2153 /* modes must always be correctly specified */
Alan Coxdeb91682008-07-22 11:13:08 +01002154 if (p_priv->baud > 57600) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 msg.rxMode = RXMODE_DMA;
2156 msg.txMode = TXMODE_DMA;
Alan Coxdeb91682008-07-22 11:13:08 +01002157 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 msg.rxMode = RXMODE_BYHAND;
2159 msg.txMode = TXMODE_BYHAND;
2160 }
2161
Ben Minerds2b982ab2012-07-12 00:10:16 +10002162 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 switch (p_priv->cflag & CSIZE) {
2164 case CS5:
2165 msg.lcr |= USA_DATABITS_5;
2166 break;
2167 case CS6:
2168 msg.lcr |= USA_DATABITS_6;
2169 break;
2170 case CS7:
2171 msg.lcr |= USA_DATABITS_7;
2172 break;
2173 case CS8:
2174 msg.lcr |= USA_DATABITS_8;
2175 break;
2176 }
2177 if (p_priv->cflag & PARENB) {
2178 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002179 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002180 USA_PARITY_ODD : USA_PARITY_EVEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 }
2182 if (p_priv->old_cflag != p_priv->cflag) {
2183 p_priv->old_cflag = p_priv->cflag;
2184 msg.setLcr = 0x01;
2185 }
2186
2187 if (p_priv->flow_control == flow_cts)
2188 msg.txFlowControl = TXFLOW_CTS;
2189 msg.setTxFlowControl = 0x01;
2190 msg.setRxFlowControl = 0x01;
Alan Coxdeb91682008-07-22 11:13:08 +01002191
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 msg.rxForwardingLength = 16;
Alan Coxdeb91682008-07-22 11:13:08 +01002193 msg.rxForwardingTimeout = 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 msg.txAckSetting = 0;
2195 msg.xonChar = 17;
2196 msg.xoffChar = 19;
2197
Alan Coxdeb91682008-07-22 11:13:08 +01002198 /* Opening port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 if (reset_port == 1) {
2200 msg.portEnabled = 1;
2201 msg.rxFlush = 1;
2202 msg.txBreak = (p_priv->break_on);
2203 }
2204 /* Closing port */
Alan Coxdeb91682008-07-22 11:13:08 +01002205 else if (reset_port == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 msg.portEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 /* Sending intermediate configs */
2208 else {
Alan Stern1f871582010-02-17 10:05:47 -05002209 msg.portEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 msg.txBreak = (p_priv->break_on);
2211 }
2212
Alan Coxdeb91682008-07-22 11:13:08 +01002213 /* Do handshaking outputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 msg.setRts = 0x01;
2215 msg.rts = p_priv->rts_state;
2216
2217 msg.setDtr = 0x01;
2218 msg.dtr = p_priv->dtr_state;
Alan Coxdeb91682008-07-22 11:13:08 +01002219
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 p_priv->resend_cont = 0;
Alan Coxdeb91682008-07-22 11:13:08 +01002221 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2222
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 /* send the data out the device on control endpoint */
2224 this_urb->transfer_buffer_length = sizeof(msg);
2225
Alan Coxdeb91682008-07-22 11:13:08 +01002226 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2227 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002228 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002229 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230}
2231
Lucy McCoy0ca12682007-05-18 12:10:41 -07002232static int keyspan_usa67_send_setup(struct usb_serial *serial,
2233 struct usb_serial_port *port,
2234 int reset_port)
2235{
2236 struct keyspan_usa67_portControlMessage msg;
2237 struct keyspan_serial_private *s_priv;
2238 struct keyspan_port_private *p_priv;
2239 const struct keyspan_device_details *d_details;
2240 struct urb *this_urb;
2241 int err, device_port;
2242
Lucy McCoy0ca12682007-05-18 12:10:41 -07002243 s_priv = usb_get_serial_data(serial);
2244 p_priv = usb_get_serial_port_data(port);
2245 d_details = s_priv->device_details;
2246
2247 this_urb = s_priv->glocont_urb;
2248
2249 /* Work out which port within the device is being setup */
2250 device_port = port->number - port->serial->minor;
2251
2252 /* Make sure we have an urb then send the message */
2253 if (this_urb == NULL) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002254 dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__,
Lucy McCoy0ca12682007-05-18 12:10:41 -07002255 port->number);
2256 return -1;
2257 }
2258
2259 /* Save reset port val for resend.
2260 Don't overwrite resend for open/close condition. */
2261 if ((reset_port + 1) > p_priv->resend_cont)
2262 p_priv->resend_cont = reset_port + 1;
2263 if (this_urb->status == -EINPROGRESS) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002264 /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */
Lucy McCoy0ca12682007-05-18 12:10:41 -07002265 mdelay(5);
Alan Coxdeb91682008-07-22 11:13:08 +01002266 return -1;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002267 }
2268
2269 memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
2270
2271 msg.port = device_port;
2272
2273 /* Only set baud rate if it's changed */
2274 if (p_priv->old_baud != p_priv->baud) {
2275 p_priv->old_baud = p_priv->baud;
2276 msg.setClocking = 0xff;
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002277 if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
2278 &msg.baudHi, &msg.baudLo, &msg.prescaler,
2279 device_port) == KEYSPAN_INVALID_BAUD_RATE) {
2280 dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
2281 __func__, p_priv->baud);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002282 msg.baudLo = 0;
2283 msg.baudHi = 125; /* Values for 9600 baud */
2284 msg.prescaler = 10;
2285 }
2286 msg.setPrescaler = 0xff;
2287 }
2288
2289 msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
2290 switch (p_priv->cflag & CSIZE) {
2291 case CS5:
2292 msg.lcr |= USA_DATABITS_5;
2293 break;
2294 case CS6:
2295 msg.lcr |= USA_DATABITS_6;
2296 break;
2297 case CS7:
2298 msg.lcr |= USA_DATABITS_7;
2299 break;
2300 case CS8:
2301 msg.lcr |= USA_DATABITS_8;
2302 break;
2303 }
2304 if (p_priv->cflag & PARENB) {
2305 /* note USA_PARITY_NONE == 0 */
Ben Minerds2b982ab2012-07-12 00:10:16 +10002306 msg.lcr |= (p_priv->cflag & PARODD) ?
Alan Coxdeb91682008-07-22 11:13:08 +01002307 USA_PARITY_ODD : USA_PARITY_EVEN;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002308 }
2309 msg.setLcr = 0xff;
2310
2311 msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
2312 msg.xonFlowControl = 0;
2313 msg.setFlowControl = 0xff;
2314 msg.forwardingLength = 16;
2315 msg.xonChar = 17;
2316 msg.xoffChar = 19;
2317
2318 if (reset_port == 1) {
2319 /* Opening port */
2320 msg._txOn = 1;
2321 msg._txOff = 0;
2322 msg.txFlush = 0;
2323 msg.txBreak = 0;
2324 msg.rxOn = 1;
2325 msg.rxOff = 0;
2326 msg.rxFlush = 1;
2327 msg.rxForward = 0;
2328 msg.returnStatus = 0;
2329 msg.resetDataToggle = 0xff;
2330 } else if (reset_port == 2) {
2331 /* Closing port */
2332 msg._txOn = 0;
2333 msg._txOff = 1;
2334 msg.txFlush = 0;
2335 msg.txBreak = 0;
2336 msg.rxOn = 0;
2337 msg.rxOff = 1;
2338 msg.rxFlush = 1;
2339 msg.rxForward = 0;
2340 msg.returnStatus = 0;
2341 msg.resetDataToggle = 0;
2342 } else {
2343 /* Sending intermediate configs */
Alan Coxdeb91682008-07-22 11:13:08 +01002344 msg._txOn = (!p_priv->break_on);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002345 msg._txOff = 0;
2346 msg.txFlush = 0;
2347 msg.txBreak = (p_priv->break_on);
2348 msg.rxOn = 0;
2349 msg.rxOff = 0;
2350 msg.rxFlush = 0;
2351 msg.rxForward = 0;
2352 msg.returnStatus = 0;
2353 msg.resetDataToggle = 0x0;
2354 }
2355
2356 /* Do handshaking outputs */
2357 msg.setTxTriState_setRts = 0xff;
2358 msg.txTriState_rts = p_priv->rts_state;
2359
2360 msg.setHskoa_setDtr = 0xff;
2361 msg.hskoa_dtr = p_priv->dtr_state;
2362
2363 p_priv->resend_cont = 0;
2364
2365 memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
2366
2367 /* send the data out the device on control endpoint */
2368 this_urb->transfer_buffer_length = sizeof(msg);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002369
2370 err = usb_submit_urb(this_urb, GFP_ATOMIC);
2371 if (err != 0)
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002372 dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
Alan Coxa5b6f602008-04-08 17:16:06 +01002373 return 0;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002374}
2375
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
2377{
2378 struct usb_serial *serial = port->serial;
2379 struct keyspan_serial_private *s_priv;
2380 const struct keyspan_device_details *d_details;
2381
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 s_priv = usb_get_serial_data(serial);
2383 d_details = s_priv->device_details;
2384
2385 switch (d_details->msg_format) {
2386 case msg_usa26:
2387 keyspan_usa26_send_setup(serial, port, reset_port);
2388 break;
2389 case msg_usa28:
2390 keyspan_usa28_send_setup(serial, port, reset_port);
2391 break;
2392 case msg_usa49:
2393 keyspan_usa49_send_setup(serial, port, reset_port);
2394 break;
2395 case msg_usa90:
2396 keyspan_usa90_send_setup(serial, port, reset_port);
2397 break;
Lucy McCoy0ca12682007-05-18 12:10:41 -07002398 case msg_usa67:
2399 keyspan_usa67_send_setup(serial, port, reset_port);
2400 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 }
2402}
2403
2404
2405/* Gets called by the "real" driver (ie once firmware is loaded
2406 and renumeration has taken place. */
Alan Coxdeb91682008-07-22 11:13:08 +01002407static int keyspan_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408{
2409 int i, err;
2410 struct usb_serial_port *port;
2411 struct keyspan_serial_private *s_priv;
2412 struct keyspan_port_private *p_priv;
2413 const struct keyspan_device_details *d_details;
2414
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
Alan Coxdeb91682008-07-22 11:13:08 +01002416 if (d_details->product_id ==
2417 le16_to_cpu(serial->dev->descriptor.idProduct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 break;
2419 if (d_details == NULL) {
Alan Coxdeb91682008-07-22 11:13:08 +01002420 dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
2421 __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 return 1;
2423 }
2424
2425 /* Setup private data for serial driver */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01002426 s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 if (!s_priv) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002428 dev_dbg(&serial->dev->dev, "%s - kmalloc for keyspan_serial_private failed.\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 return -ENOMEM;
2430 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431
2432 s_priv->device_details = d_details;
2433 usb_set_serial_data(serial, s_priv);
2434
2435 /* Now setup per port private data */
2436 for (i = 0; i < serial->num_ports; i++) {
2437 port = serial->port[i];
Alan Coxdeb91682008-07-22 11:13:08 +01002438 p_priv = kzalloc(sizeof(struct keyspan_port_private),
2439 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 if (!p_priv) {
Greg Kroah-Hartman049c6b42012-09-14 16:30:23 -07002441 dev_dbg(&port->dev, "%s - kmalloc for keyspan_port_private (%d) failed!.\n", __func__, i);
Alan Coxdeb91682008-07-22 11:13:08 +01002442 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 p_priv->device_details = d_details;
2445 usb_set_serial_port_data(port, p_priv);
2446 }
2447
2448 keyspan_setup_urbs(serial);
2449
Lucy McCoy0ca12682007-05-18 12:10:41 -07002450 if (s_priv->instat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002451 err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
2452 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002453 dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002454 }
2455 if (s_priv->indat_urb != NULL) {
Lucy McCoy0ca12682007-05-18 12:10:41 -07002456 err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
2457 if (err != 0)
Greg Kroah-Hartman7ebcb332012-09-14 16:34:21 -07002458 dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 }
Alan Coxdeb91682008-07-22 11:13:08 +01002460
Alan Coxa5b6f602008-04-08 17:16:06 +01002461 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462}
2463
Alan Sternf9c99bb2009-06-02 11:53:55 -04002464static void keyspan_disconnect(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465{
2466 int i, j;
2467 struct usb_serial_port *port;
2468 struct keyspan_serial_private *s_priv;
2469 struct keyspan_port_private *p_priv;
2470
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 s_priv = usb_get_serial_data(serial);
2472
2473 /* Stop reading/writing urbs */
2474 stop_urb(s_priv->instat_urb);
2475 stop_urb(s_priv->glocont_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002476 stop_urb(s_priv->indat_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 for (i = 0; i < serial->num_ports; ++i) {
2478 port = serial->port[i];
2479 p_priv = usb_get_serial_port_data(port);
2480 stop_urb(p_priv->inack_urb);
2481 stop_urb(p_priv->outcont_urb);
2482 for (j = 0; j < 2; j++) {
2483 stop_urb(p_priv->in_urbs[j]);
2484 stop_urb(p_priv->out_urbs[j]);
2485 }
2486 }
2487
2488 /* Now free them */
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002489 usb_free_urb(s_priv->instat_urb);
Lucy McCoy0ca12682007-05-18 12:10:41 -07002490 usb_free_urb(s_priv->indat_urb);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002491 usb_free_urb(s_priv->glocont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 for (i = 0; i < serial->num_ports; ++i) {
2493 port = serial->port[i];
2494 p_priv = usb_get_serial_port_data(port);
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002495 usb_free_urb(p_priv->inack_urb);
2496 usb_free_urb(p_priv->outcont_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 for (j = 0; j < 2; j++) {
Mariusz Kozlowski1cadc132006-11-08 15:36:34 +01002498 usb_free_urb(p_priv->in_urbs[j]);
2499 usb_free_urb(p_priv->out_urbs[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 }
2501 }
Alan Sternf9c99bb2009-06-02 11:53:55 -04002502}
2503
2504static void keyspan_release(struct usb_serial *serial)
2505{
2506 int i;
2507 struct usb_serial_port *port;
2508 struct keyspan_serial_private *s_priv;
2509
Alan Sternf9c99bb2009-06-02 11:53:55 -04002510 s_priv = usb_get_serial_data(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 kfree(s_priv);
2513
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 /* Now free per port private data */
2515 for (i = 0; i < serial->num_ports; i++) {
2516 port = serial->port[i];
2517 kfree(usb_get_serial_port_data(port));
2518 }
2519}
2520
Alan Coxdeb91682008-07-22 11:13:08 +01002521MODULE_AUTHOR(DRIVER_AUTHOR);
2522MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523MODULE_LICENSE("GPL");
2524
David Woodhouse2971c572008-05-30 14:04:03 +03002525MODULE_FIRMWARE("keyspan/usa28.fw");
2526MODULE_FIRMWARE("keyspan/usa28x.fw");
2527MODULE_FIRMWARE("keyspan/usa28xa.fw");
2528MODULE_FIRMWARE("keyspan/usa28xb.fw");
2529MODULE_FIRMWARE("keyspan/usa19.fw");
2530MODULE_FIRMWARE("keyspan/usa19qi.fw");
2531MODULE_FIRMWARE("keyspan/mpr.fw");
2532MODULE_FIRMWARE("keyspan/usa19qw.fw");
2533MODULE_FIRMWARE("keyspan/usa18x.fw");
2534MODULE_FIRMWARE("keyspan/usa19w.fw");
2535MODULE_FIRMWARE("keyspan/usa49w.fw");
2536MODULE_FIRMWARE("keyspan/usa49wlc.fw");