blob: d8825e159aa5cfe9361b152489d79fe953f22889 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * MCT (Magic Control Technology Corp.) USB RS232 Converter Driver
3 *
4 * Copyright (C) 2000 Wolfgang Grandegger (wolfgang@ces.ch)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is largely derived from the Belkin USB Serial Adapter Driver
12 * (see belkin_sa.[ch]). All of the information about the device was acquired
13 * by using SniffUSB on Windows98. For technical details see mct_u232.h.
14 *
15 * William G. Greathouse and Greg Kroah-Hartman provided great help on how to
16 * do the reverse engineering and how to write a USB serial device driver.
17 *
18 * TO BE DONE, TO BE CHECKED:
19 * DTR/RTS signal handling may be incomplete or incorrect. I have mainly
20 * implemented what I have seen with SniffUSB or found in belkin_sa.c.
21 * For further TODOs check also belkin_sa.c.
22 *
23 * TEST STATUS:
24 * Basic tests have been performed with minicom/zmodem transfers and
25 * modem dialing under Linux 2.4.0-test10 (for me it works fine).
26 *
27 * 04-Nov-2003 Bill Marr <marr at flex dot com>
28 * - Mimic Windows driver by sending 2 USB 'device request' messages
29 * following normal 'baud rate change' message. This allows data to be
30 * transmitted to RS-232 devices which don't assert the 'CTS' signal.
31 *
32 * 10-Nov-2001 Wolfgang Grandegger
33 * - Fixed an endianess problem with the baudrate selection for PowerPC.
34 *
35 * 06-Dec-2001 Martin Hamilton <martinh@gnu.org>
Alan Coxe19b2562008-07-22 11:14:30 +010036 * - Added support for the Belkin F5U109 DB9 adaptor
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 *
38 * 30-May-2001 Greg Kroah-Hartman
Alan Coxe19b2562008-07-22 11:14:30 +010039 * - switched from using spinlock to a semaphore, which fixes lots of
40 * problems.
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 *
42 * 04-May-2001 Stelian Pop
43 * - Set the maximum bulk output size for Sitecom U232-P25 model to 16 bytes
44 * instead of the device reported 32 (using 32 bytes causes many data
45 * loss, Windows driver uses 16 too).
46 *
47 * 02-May-2001 Stelian Pop
48 * - Fixed the baud calculation for Sitecom U232-P25 model
49 *
50 * 08-Apr-2001 gb
51 * - Identify version on module load.
52 *
Alan Coxe19b2562008-07-22 11:14:30 +010053 * 06-Jan-2001 Cornel Ciocirlan
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 * - Added support for Sitecom U232-P25 model (Product Id 0x0230)
55 * - Added support for D-Link DU-H3SP USB BAY (Product Id 0x0200)
56 *
57 * 29-Nov-2000 Greg Kroah-Hartman
58 * - Added device id table to fit with 2.4.0-test11 structure.
59 * - took out DEAL_WITH_TWO_INT_IN_ENDPOINTS #define as it's not needed
60 * (lots of things will change if/when the usb-serial core changes to
61 * handle these issues.
62 *
Alan Coxe19b2562008-07-22 11:14:30 +010063 * 27-Nov-2000 Wolfgang Grandegge
64 * A version for kernel 2.4.0-test10 released to the Linux community
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 * (via linux-usb-devel).
66 */
67
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#include <linux/kernel.h>
69#include <linux/errno.h>
70#include <linux/init.h>
71#include <linux/slab.h>
72#include <linux/tty.h>
73#include <linux/tty_driver.h>
74#include <linux/tty_flip.h>
75#include <linux/module.h>
76#include <linux/spinlock.h>
Alan Coxe19b2562008-07-22 11:14:30 +010077#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070078#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070079#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#include "mct_u232.h"
81
82/*
83 * Version Information
84 */
Dave Platt45b844d2007-05-08 11:00:12 -070085#define DRIVER_VERSION "z2.1" /* Linux in-kernel version */
Linus Torvalds1da177e2005-04-16 15:20:36 -070086#define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
87#define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
88
89static int debug;
90
91/*
92 * Function prototypes
93 */
Alan Coxe19b2562008-07-22 11:14:30 +010094static int mct_u232_startup(struct usb_serial *serial);
Alan Sternf9c99bb2009-06-02 11:53:55 -040095static void mct_u232_release(struct usb_serial *serial);
Alan Coxe19b2562008-07-22 11:14:30 +010096static int mct_u232_open(struct tty_struct *tty,
97 struct usb_serial_port *port, struct file *filp);
Alan Cox335f8512009-06-11 12:26:29 +010098static void mct_u232_close(struct usb_serial_port *port);
99static void mct_u232_dtr_rts(struct usb_serial_port *port, int on);
Alan Coxe19b2562008-07-22 11:14:30 +0100100static void mct_u232_read_int_callback(struct urb *urb);
101static void mct_u232_set_termios(struct tty_struct *tty,
102 struct usb_serial_port *port, struct ktermios *old);
103static void mct_u232_break_ctl(struct tty_struct *tty, int break_state);
104static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file);
105static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file,
106 unsigned int set, unsigned int clear);
107static void mct_u232_throttle(struct tty_struct *tty);
108static void mct_u232_unthrottle(struct tty_struct *tty);
Dave Platt45b844d2007-05-08 11:00:12 -0700109
110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111/*
112 * All of the device info needed for the MCT USB-RS232 converter.
113 */
114static struct usb_device_id id_table_combined [] = {
115 { USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
116 { USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
117 { USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
118 { USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) },
119 { } /* Terminating entry */
120};
121
Alan Coxe19b2562008-07-22 11:14:30 +0100122MODULE_DEVICE_TABLE(usb, id_table_combined);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
124static struct usb_driver mct_u232_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 .name = "mct_u232",
126 .probe = usb_serial_probe,
127 .disconnect = usb_serial_disconnect,
128 .id_table = id_table_combined,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800129 .no_dynamic_id = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130};
131
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700132static struct usb_serial_driver mct_u232_device = {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700133 .driver = {
134 .owner = THIS_MODULE,
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -0700135 .name = "mct_u232",
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700136 },
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -0700137 .description = "MCT U232",
Johannes Hölzld9b1b782006-12-17 21:50:24 +0100138 .usb_driver = &mct_u232_driver,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 .id_table = id_table_combined,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 .num_ports = 1,
141 .open = mct_u232_open,
142 .close = mct_u232_close,
Alan Cox335f8512009-06-11 12:26:29 +0100143 .dtr_rts = mct_u232_dtr_rts,
Dave Platt45b844d2007-05-08 11:00:12 -0700144 .throttle = mct_u232_throttle,
145 .unthrottle = mct_u232_unthrottle,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 .read_int_callback = mct_u232_read_int_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 .set_termios = mct_u232_set_termios,
148 .break_ctl = mct_u232_break_ctl,
149 .tiocmget = mct_u232_tiocmget,
150 .tiocmset = mct_u232_tiocmset,
151 .attach = mct_u232_startup,
Alan Sternf9c99bb2009-06-02 11:53:55 -0400152 .release = mct_u232_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153};
154
155
156struct mct_u232_private {
157 spinlock_t lock;
158 unsigned int control_state; /* Modem Line Setting (TIOCM) */
159 unsigned char last_lcr; /* Line Control Register */
160 unsigned char last_lsr; /* Line Status Register */
161 unsigned char last_msr; /* Modem Status Register */
Dave Platt45b844d2007-05-08 11:00:12 -0700162 unsigned int rx_flags; /* Throttling flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163};
164
Dave Platt45b844d2007-05-08 11:00:12 -0700165#define THROTTLED 0x01
166
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167/*
168 * Handle vendor specific USB requests
169 */
170
171#define WDR_TIMEOUT 5000 /* default urb timeout */
172
173/*
174 * Later day 2.6.0-test kernels have new baud rates like B230400 which
175 * we do not know how to support. We ignore them for the moment.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 */
Alan Coxe19b2562008-07-22 11:14:30 +0100177static int mct_u232_calculate_baud_rate(struct usb_serial *serial,
178 speed_t value, speed_t *result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179{
Alan Coxd0fab0d2007-12-13 16:15:29 -0800180 *result = value;
181
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID
Alan Coxe19b2562008-07-22 11:14:30 +0100183 || le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 switch (value) {
Alan Coxe19b2562008-07-22 11:14:30 +0100185 case 300:
186 return 0x01;
187 case 600:
188 return 0x02; /* this one not tested */
189 case 1200:
190 return 0x03;
191 case 2400:
192 return 0x04;
193 case 4800:
194 return 0x06;
195 case 9600:
196 return 0x08;
197 case 19200:
198 return 0x09;
199 case 38400:
200 return 0x0a;
201 case 57600:
202 return 0x0b;
203 case 115200:
204 return 0x0c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 default:
Alan Coxd0fab0d2007-12-13 16:15:29 -0800206 *result = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 return 0x08;
208 }
209 } else {
Alan Coxd0fab0d2007-12-13 16:15:29 -0800210 /* FIXME: Can we use any divider - should we do
211 divider = 115200/value;
212 real baud = 115200/divider */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 switch (value) {
Andrew Mortonb3aceb22007-08-10 14:53:35 -0700214 case 300: break;
215 case 600: break;
216 case 1200: break;
217 case 2400: break;
218 case 4800: break;
219 case 9600: break;
220 case 19200: break;
221 case 38400: break;
222 case 57600: break;
223 case 115200: break;
224 default:
Andrew Mortonb3aceb22007-08-10 14:53:35 -0700225 value = 9600;
Alan Coxd0fab0d2007-12-13 16:15:29 -0800226 *result = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 }
228 return 115200/value;
229 }
230}
231
Alan Cox95da3102008-07-22 11:09:07 +0100232static int mct_u232_set_baud_rate(struct tty_struct *tty,
233 struct usb_serial *serial, struct usb_serial_port *port, speed_t value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234{
235 __le32 divisor;
Alan Coxe19b2562008-07-22 11:14:30 +0100236 int rc;
237 unsigned char zero_byte = 0;
238 unsigned char cts_enable_byte = 0;
239 speed_t speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
Alan Coxe19b2562008-07-22 11:14:30 +0100241 divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value,
242 &speed));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Alan Coxe19b2562008-07-22 11:14:30 +0100244 rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
245 MCT_U232_SET_BAUD_RATE_REQUEST,
246 MCT_U232_SET_REQUEST_TYPE,
247 0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
248 WDR_TIMEOUT);
Alan Coxd0fab0d2007-12-13 16:15:29 -0800249 if (rc < 0) /*FIXME: What value speed results */
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700250 dev_err(&port->dev, "Set BAUD RATE %d failed (error = %d)\n",
251 value, rc);
Alan Coxd0fab0d2007-12-13 16:15:29 -0800252 else
Alan Cox95da3102008-07-22 11:09:07 +0100253 tty_encode_baud_rate(tty, speed, speed);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor);
255
256 /* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
257 always sends two extra USB 'device request' messages after the
258 'baud rate change' message. The actual functionality of the
259 request codes in these messages is not fully understood but these
260 particular codes are never seen in any operation besides a baud
Dave Platt45b844d2007-05-08 11:00:12 -0700261 rate change. Both of these messages send a single byte of data.
262 In the first message, the value of this byte is always zero.
263
264 The second message has been determined experimentally to control
265 whether data will be transmitted to a device which is not asserting
266 the 'CTS' signal. If the second message's data byte is zero, data
267 will be transmitted even if 'CTS' is not asserted (i.e. no hardware
Alan Coxe19b2562008-07-22 11:14:30 +0100268 flow control). if the second message's data byte is nonzero (a
269 value of 1 is used by this driver), data will not be transmitted to
270 a device which is not asserting 'CTS'.
Dave Platt45b844d2007-05-08 11:00:12 -0700271 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
273 rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
Alan Coxe19b2562008-07-22 11:14:30 +0100274 MCT_U232_SET_UNKNOWN1_REQUEST,
275 MCT_U232_SET_REQUEST_TYPE,
276 0, 0, &zero_byte, MCT_U232_SET_UNKNOWN1_SIZE,
277 WDR_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 if (rc < 0)
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700279 dev_err(&port->dev, "Sending USB device request code %d "
280 "failed (error = %d)\n", MCT_U232_SET_UNKNOWN1_REQUEST,
281 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Alan Coxe19b2562008-07-22 11:14:30 +0100283 if (port && C_CRTSCTS(tty))
Dave Platt45b844d2007-05-08 11:00:12 -0700284 cts_enable_byte = 1;
Dave Platt45b844d2007-05-08 11:00:12 -0700285
Alan Coxe19b2562008-07-22 11:14:30 +0100286 dbg("set_baud_rate: send second control message, data = %02X",
287 cts_enable_byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
Alan Coxe19b2562008-07-22 11:14:30 +0100289 MCT_U232_SET_CTS_REQUEST,
290 MCT_U232_SET_REQUEST_TYPE,
291 0, 0, &cts_enable_byte, MCT_U232_SET_CTS_SIZE,
292 WDR_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 if (rc < 0)
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700294 dev_err(&port->dev, "Sending USB device request code %d "
295 "failed (error = %d)\n", MCT_U232_SET_CTS_REQUEST, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Alan Coxe19b2562008-07-22 11:14:30 +0100297 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298} /* mct_u232_set_baud_rate */
299
300static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr)
301{
Alan Coxe19b2562008-07-22 11:14:30 +0100302 int rc;
303 rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
304 MCT_U232_SET_LINE_CTRL_REQUEST,
305 MCT_U232_SET_REQUEST_TYPE,
306 0, 0, &lcr, MCT_U232_SET_LINE_CTRL_SIZE,
307 WDR_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 if (rc < 0)
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700309 dev_err(&serial->dev->dev,
310 "Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 dbg("set_line_ctrl: 0x%x", lcr);
Alan Coxe19b2562008-07-22 11:14:30 +0100312 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313} /* mct_u232_set_line_ctrl */
314
315static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
316 unsigned int control_state)
317{
Alan Coxe19b2562008-07-22 11:14:30 +0100318 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 unsigned char mcr = MCT_U232_MCR_NONE;
320
321 if (control_state & TIOCM_DTR)
322 mcr |= MCT_U232_MCR_DTR;
323 if (control_state & TIOCM_RTS)
324 mcr |= MCT_U232_MCR_RTS;
325
Alan Coxe19b2562008-07-22 11:14:30 +0100326 rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
327 MCT_U232_SET_MODEM_CTRL_REQUEST,
328 MCT_U232_SET_REQUEST_TYPE,
329 0, 0, &mcr, MCT_U232_SET_MODEM_CTRL_SIZE,
330 WDR_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 if (rc < 0)
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700332 dev_err(&serial->dev->dev,
333 "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr);
335
Alan Coxe19b2562008-07-22 11:14:30 +0100336 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337} /* mct_u232_set_modem_ctrl */
338
Alan Coxe19b2562008-07-22 11:14:30 +0100339static int mct_u232_get_modem_stat(struct usb_serial *serial,
340 unsigned char *msr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
Alan Coxe19b2562008-07-22 11:14:30 +0100342 int rc;
343 rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
344 MCT_U232_GET_MODEM_STAT_REQUEST,
345 MCT_U232_GET_REQUEST_TYPE,
346 0, 0, msr, MCT_U232_GET_MODEM_STAT_SIZE,
347 WDR_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 if (rc < 0) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700349 dev_err(&serial->dev->dev,
350 "Get MODEM STATus failed (error = %d)\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 *msr = 0;
352 }
353 dbg("get_modem_stat: 0x%x", *msr);
Alan Coxe19b2562008-07-22 11:14:30 +0100354 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355} /* mct_u232_get_modem_stat */
356
Alan Coxe19b2562008-07-22 11:14:30 +0100357static void mct_u232_msr_to_state(unsigned int *control_state,
358 unsigned char msr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359{
Alan Coxe19b2562008-07-22 11:14:30 +0100360 /* Translate Control Line states */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 if (msr & MCT_U232_MSR_DSR)
362 *control_state |= TIOCM_DSR;
363 else
364 *control_state &= ~TIOCM_DSR;
365 if (msr & MCT_U232_MSR_CTS)
366 *control_state |= TIOCM_CTS;
367 else
368 *control_state &= ~TIOCM_CTS;
369 if (msr & MCT_U232_MSR_RI)
370 *control_state |= TIOCM_RI;
371 else
372 *control_state &= ~TIOCM_RI;
373 if (msr & MCT_U232_MSR_CD)
374 *control_state |= TIOCM_CD;
375 else
376 *control_state &= ~TIOCM_CD;
Alan Coxe19b2562008-07-22 11:14:30 +0100377 dbg("msr_to_state: msr=0x%x ==> state=0x%x", msr, *control_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378} /* mct_u232_msr_to_state */
379
380/*
381 * Driver's tty interface functions
382 */
383
Alan Coxe19b2562008-07-22 11:14:30 +0100384static int mct_u232_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
386 struct mct_u232_private *priv;
387 struct usb_serial_port *port, *rport;
388
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100389 priv = kzalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 if (!priv)
391 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 spin_lock_init(&priv->lock);
393 usb_set_serial_port_data(serial->port[0], priv);
394
395 init_waitqueue_head(&serial->port[0]->write_wait);
396
397 /* Puh, that's dirty */
398 port = serial->port[0];
399 rport = serial->port[1];
Mariusz Kozlowski73135bb2006-11-08 15:36:42 +0100400 /* No unlinking, it wasn't submitted yet. */
401 usb_free_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 port->read_urb = rport->interrupt_in_urb;
403 rport->interrupt_in_urb = NULL;
404 port->read_urb->context = port;
405
Alan Coxe19b2562008-07-22 11:14:30 +0100406 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407} /* mct_u232_startup */
408
409
Alan Sternf9c99bb2009-06-02 11:53:55 -0400410static void mct_u232_release(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
412 struct mct_u232_private *priv;
413 int i;
Alan Coxe19b2562008-07-22 11:14:30 +0100414
Harvey Harrison441b62c2008-03-03 16:08:34 -0800415 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Alan Coxe19b2562008-07-22 11:14:30 +0100417 for (i = 0; i < serial->num_ports; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 /* My special items, the standard routines free my urbs */
419 priv = usb_get_serial_port_data(serial->port[i]);
Alan Sternf9c99bb2009-06-02 11:53:55 -0400420 kfree(priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 }
Alan Sternf9c99bb2009-06-02 11:53:55 -0400422} /* mct_u232_release */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Alan Coxe19b2562008-07-22 11:14:30 +0100424static int mct_u232_open(struct tty_struct *tty,
Alan Cox95da3102008-07-22 11:09:07 +0100425 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426{
427 struct usb_serial *serial = port->serial;
428 struct mct_u232_private *priv = usb_get_serial_port_data(port);
429 int retval = 0;
430 unsigned int control_state;
431 unsigned long flags;
432 unsigned char last_lcr;
433 unsigned char last_msr;
434
Harvey Harrison441b62c2008-03-03 16:08:34 -0800435 dbg("%s port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 /* Compensate for a hardware bug: although the Sitecom U232-P25
438 * device reports a maximum output packet size of 32 bytes,
439 * it seems to be able to accept only 16 bytes (and that's what
440 * SniffUSB says too...)
441 */
Alan Coxe19b2562008-07-22 11:14:30 +0100442 if (le16_to_cpu(serial->dev->descriptor.idProduct)
443 == MCT_U232_SITECOM_PID)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 port->bulk_out_size = 16;
445
Alan Coxe19b2562008-07-22 11:14:30 +0100446 /* Do a defined restart: the normal serial device seems to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 * always turn on DTR and RTS here, so do the same. I'm not
448 * sure if this is really necessary. But it should not harm
449 * either.
450 */
451 spin_lock_irqsave(&priv->lock, flags);
Alan Cox95da3102008-07-22 11:09:07 +0100452 if (tty && (tty->termios->c_cflag & CBAUD))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 priv->control_state = TIOCM_DTR | TIOCM_RTS;
454 else
455 priv->control_state = 0;
Alan Coxe19b2562008-07-22 11:14:30 +0100456
457 priv->last_lcr = (MCT_U232_DATA_BITS_8 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 MCT_U232_PARITY_NONE |
459 MCT_U232_STOP_BITS_1);
460 control_state = priv->control_state;
461 last_lcr = priv->last_lcr;
462 spin_unlock_irqrestore(&priv->lock, flags);
463 mct_u232_set_modem_ctrl(serial, control_state);
464 mct_u232_set_line_ctrl(serial, last_lcr);
465
466 /* Read modem status and update control state */
467 mct_u232_get_modem_stat(serial, &last_msr);
468 spin_lock_irqsave(&priv->lock, flags);
469 priv->last_msr = last_msr;
470 mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
471 spin_unlock_irqrestore(&priv->lock, flags);
472
473 port->read_urb->dev = port->serial->dev;
474 retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
475 if (retval) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700476 dev_err(&port->dev,
477 "usb_submit_urb(read bulk) failed pipe 0x%x err %d\n",
478 port->read_urb->pipe, retval);
Oliver Neukum2f007de2007-03-29 10:45:17 +0200479 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 }
481
482 port->interrupt_in_urb->dev = port->serial->dev;
483 retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Oliver Neukum2f007de2007-03-29 10:45:17 +0200484 if (retval) {
485 usb_kill_urb(port->read_urb);
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700486 dev_err(&port->dev,
487 "usb_submit_urb(read int) failed pipe 0x%x err %d",
488 port->interrupt_in_urb->pipe, retval);
Oliver Neukum2f007de2007-03-29 10:45:17 +0200489 goto error;
490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 return 0;
Oliver Neukum2f007de2007-03-29 10:45:17 +0200492
493error:
494 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495} /* mct_u232_open */
496
Alan Cox335f8512009-06-11 12:26:29 +0100497static void mct_u232_dtr_rts(struct usb_serial_port *port, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498{
Dave Platt45b844d2007-05-08 11:00:12 -0700499 unsigned int control_state;
500 struct mct_u232_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Alan Cox335f8512009-06-11 12:26:29 +0100502 mutex_lock(&port->serial->disc_mutex);
503 if (!port->serial->disconnected) {
504 /* drop DTR and RTS */
505 spin_lock_irq(&priv->lock);
506 if (on)
507 priv->control_state |= TIOCM_DTR | TIOCM_RTS;
508 else
Oliver Neukume33fe4d2008-01-21 17:44:10 +0100509 priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
Alan Cox335f8512009-06-11 12:26:29 +0100510 control_state = priv->control_state;
511 spin_unlock_irq(&priv->lock);
512 mct_u232_set_modem_ctrl(port->serial, control_state);
Dave Platt45b844d2007-05-08 11:00:12 -0700513 }
Alan Cox335f8512009-06-11 12:26:29 +0100514 mutex_unlock(&port->serial->disc_mutex);
515}
Dave Platt45b844d2007-05-08 11:00:12 -0700516
Alan Cox335f8512009-06-11 12:26:29 +0100517static void mct_u232_close(struct usb_serial_port *port)
518{
519 dbg("%s port %d", __func__, port->number);
Dave Platt45b844d2007-05-08 11:00:12 -0700520
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 if (port->serial->dev) {
522 /* shutdown our urbs */
523 usb_kill_urb(port->write_urb);
524 usb_kill_urb(port->read_urb);
525 usb_kill_urb(port->interrupt_in_urb);
526 }
527} /* mct_u232_close */
528
529
Alan Coxe19b2562008-07-22 11:14:30 +0100530static void mct_u232_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531{
Ming Leicdc97792008-02-24 18:41:47 +0800532 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 struct mct_u232_private *priv = usb_get_serial_port_data(port);
534 struct usb_serial *serial = port->serial;
535 struct tty_struct *tty;
536 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartmane96da392007-06-15 15:44:13 -0700537 int retval;
538 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 unsigned long flags;
540
Greg Kroah-Hartmane96da392007-06-15 15:44:13 -0700541 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 case 0:
543 /* success */
544 break;
545 case -ECONNRESET:
546 case -ENOENT:
547 case -ESHUTDOWN:
548 /* this urb is terminated, clean up */
Greg Kroah-Hartmane96da392007-06-15 15:44:13 -0700549 dbg("%s - urb shutting down with status: %d",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800550 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 return;
552 default:
Greg Kroah-Hartmane96da392007-06-15 15:44:13 -0700553 dbg("%s - nonzero urb status received: %d",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800554 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 goto exit;
556 }
557
558 if (!serial) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800559 dbg("%s - bad serial pointer, exiting", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 return;
561 }
562
Alan Coxe19b2562008-07-22 11:14:30 +0100563 dbg("%s - port %d", __func__, port->number);
564 usb_serial_debug_data(debug, &port->dev, __func__,
565 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
567 /*
568 * Work-a-round: handle the 'usual' bulk-in pipe here
569 */
570 if (urb->transfer_buffer_length > 2) {
Alan Cox4a90f092008-10-13 10:39:46 +0100571 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 if (urb->actual_length) {
Alan Coxacc80752008-07-22 11:14:40 +0100573 tty_insert_flip_string(tty, data, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100575 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 }
577 goto exit;
578 }
Alan Coxe19b2562008-07-22 11:14:30 +0100579
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 /*
581 * The interrupt-in pipe signals exceptional conditions (modem line
582 * signal changes and errors). data[0] holds MSR, data[1] holds LSR.
583 */
584 spin_lock_irqsave(&priv->lock, flags);
585 priv->last_msr = data[MCT_U232_MSR_INDEX];
Alan Coxe19b2562008-07-22 11:14:30 +0100586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 /* Record Control Line states */
588 mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
589
590#if 0
Alan Coxe19b2562008-07-22 11:14:30 +0100591 /* Not yet handled. See belkin_sa.c for further information */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 /* Now to report any errors */
593 priv->last_lsr = data[MCT_U232_LSR_INDEX];
594 /*
595 * fill in the flip buffer here, but I do not know the relation
596 * to the current/next receive buffer or characters. I need
597 * to look in to this before committing any code.
598 */
599 if (priv->last_lsr & MCT_U232_LSR_ERR) {
Alan Cox4a90f092008-10-13 10:39:46 +0100600 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 /* Overrun Error */
602 if (priv->last_lsr & MCT_U232_LSR_OE) {
603 }
604 /* Parity Error */
605 if (priv->last_lsr & MCT_U232_LSR_PE) {
606 }
607 /* Framing Error */
608 if (priv->last_lsr & MCT_U232_LSR_FE) {
609 }
610 /* Break Indicator */
611 if (priv->last_lsr & MCT_U232_LSR_BI) {
612 }
Alan Cox4a90f092008-10-13 10:39:46 +0100613 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 }
615#endif
616 spin_unlock_irqrestore(&priv->lock, flags);
617exit:
Alan Coxe19b2562008-07-22 11:14:30 +0100618 retval = usb_submit_urb(urb, GFP_ATOMIC);
Greg Kroah-Hartmane96da392007-06-15 15:44:13 -0700619 if (retval)
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700620 dev_err(&port->dev,
621 "%s - usb_submit_urb failed with result %d\n",
622 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623} /* mct_u232_read_int_callback */
624
Alan Coxe19b2562008-07-22 11:14:30 +0100625static void mct_u232_set_termios(struct tty_struct *tty,
626 struct usb_serial_port *port,
627 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
629 struct usb_serial *serial = port->serial;
630 struct mct_u232_private *priv = usb_get_serial_port_data(port);
Alan Cox95da3102008-07-22 11:09:07 +0100631 struct ktermios *termios = tty->termios;
Alan Coxd0fab0d2007-12-13 16:15:29 -0800632 unsigned int cflag = termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 unsigned int old_cflag = old_termios->c_cflag;
634 unsigned long flags;
Dave Platt45b844d2007-05-08 11:00:12 -0700635 unsigned int control_state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 unsigned char last_lcr;
637
638 /* get a local copy of the current port settings */
639 spin_lock_irqsave(&priv->lock, flags);
640 control_state = priv->control_state;
641 spin_unlock_irqrestore(&priv->lock, flags);
642 last_lcr = 0;
643
644 /*
645 * Update baud rate.
646 * Do not attempt to cache old rates and skip settings,
647 * disconnects screw such tricks up completely.
648 * Premature optimization is the root of all evil.
649 */
650
Alan Coxe19b2562008-07-22 11:14:30 +0100651 /* reassert DTR and RTS on transition from B0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 if ((old_cflag & CBAUD) == B0) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800653 dbg("%s: baud was B0", __func__);
Dave Platt45b844d2007-05-08 11:00:12 -0700654 control_state |= TIOCM_DTR | TIOCM_RTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 mct_u232_set_modem_ctrl(serial, control_state);
656 }
657
Alan Cox95da3102008-07-22 11:09:07 +0100658 mct_u232_set_baud_rate(tty, serial, port, tty_get_baud_rate(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Alan Coxe19b2562008-07-22 11:14:30 +0100660 if ((cflag & CBAUD) == B0) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800661 dbg("%s: baud is B0", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 /* Drop RTS and DTR */
663 control_state &= ~(TIOCM_DTR | TIOCM_RTS);
Alan Coxe19b2562008-07-22 11:14:30 +0100664 mct_u232_set_modem_ctrl(serial, control_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 }
666
667 /*
668 * Update line control register (LCR)
669 */
670
671 /* set the parity */
672 if (cflag & PARENB)
673 last_lcr |= (cflag & PARODD) ?
674 MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
675 else
676 last_lcr |= MCT_U232_PARITY_NONE;
677
678 /* set the number of data bits */
679 switch (cflag & CSIZE) {
680 case CS5:
681 last_lcr |= MCT_U232_DATA_BITS_5; break;
682 case CS6:
683 last_lcr |= MCT_U232_DATA_BITS_6; break;
684 case CS7:
685 last_lcr |= MCT_U232_DATA_BITS_7; break;
686 case CS8:
687 last_lcr |= MCT_U232_DATA_BITS_8; break;
688 default:
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700689 dev_err(&port->dev,
690 "CSIZE was not CS5-CS8, using default of 8\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 last_lcr |= MCT_U232_DATA_BITS_8;
692 break;
693 }
694
Alan Coxd0fab0d2007-12-13 16:15:29 -0800695 termios->c_cflag &= ~CMSPAR;
696
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 /* set the number of stop bits */
698 last_lcr |= (cflag & CSTOPB) ?
699 MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
700
701 mct_u232_set_line_ctrl(serial, last_lcr);
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 /* save off the modified port settings */
704 spin_lock_irqsave(&priv->lock, flags);
705 priv->control_state = control_state;
706 priv->last_lcr = last_lcr;
707 spin_unlock_irqrestore(&priv->lock, flags);
708} /* mct_u232_set_termios */
709
Alan Cox95da3102008-07-22 11:09:07 +0100710static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
Alan Cox95da3102008-07-22 11:09:07 +0100712 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 struct usb_serial *serial = port->serial;
714 struct mct_u232_private *priv = usb_get_serial_port_data(port);
715 unsigned char lcr;
716 unsigned long flags;
717
Harvey Harrison441b62c2008-03-03 16:08:34 -0800718 dbg("%sstate=%d", __func__, break_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 spin_lock_irqsave(&priv->lock, flags);
721 lcr = priv->last_lcr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723 if (break_state)
724 lcr |= MCT_U232_SET_BREAK;
Alan Cox6b447f042009-01-02 13:48:56 +0000725 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 mct_u232_set_line_ctrl(serial, lcr);
728} /* mct_u232_break_ctl */
729
730
Alan Cox95da3102008-07-22 11:09:07 +0100731static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732{
Alan Cox95da3102008-07-22 11:09:07 +0100733 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 struct mct_u232_private *priv = usb_get_serial_port_data(port);
735 unsigned int control_state;
736 unsigned long flags;
Alan Coxe19b2562008-07-22 11:14:30 +0100737
Harvey Harrison441b62c2008-03-03 16:08:34 -0800738 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
740 spin_lock_irqsave(&priv->lock, flags);
741 control_state = priv->control_state;
742 spin_unlock_irqrestore(&priv->lock, flags);
743
744 return control_state;
745}
746
Alan Cox95da3102008-07-22 11:09:07 +0100747static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 unsigned int set, unsigned int clear)
749{
Alan Cox95da3102008-07-22 11:09:07 +0100750 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 struct usb_serial *serial = port->serial;
752 struct mct_u232_private *priv = usb_get_serial_port_data(port);
753 unsigned int control_state;
754 unsigned long flags;
Alan Coxe19b2562008-07-22 11:14:30 +0100755
Harvey Harrison441b62c2008-03-03 16:08:34 -0800756 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
758 spin_lock_irqsave(&priv->lock, flags);
759 control_state = priv->control_state;
760
761 if (set & TIOCM_RTS)
762 control_state |= TIOCM_RTS;
763 if (set & TIOCM_DTR)
764 control_state |= TIOCM_DTR;
765 if (clear & TIOCM_RTS)
766 control_state &= ~TIOCM_RTS;
767 if (clear & TIOCM_DTR)
768 control_state &= ~TIOCM_DTR;
769
770 priv->control_state = control_state;
771 spin_unlock_irqrestore(&priv->lock, flags);
772 return mct_u232_set_modem_ctrl(serial, control_state);
773}
774
Alan Cox95da3102008-07-22 11:09:07 +0100775static void mct_u232_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776{
Alan Cox95da3102008-07-22 11:09:07 +0100777 struct usb_serial_port *port = tty->driver_data;
Dave Platt45b844d2007-05-08 11:00:12 -0700778 struct mct_u232_private *priv = usb_get_serial_port_data(port);
779 unsigned long flags;
780 unsigned int control_state;
Dave Platt45b844d2007-05-08 11:00:12 -0700781
Harvey Harrison441b62c2008-03-03 16:08:34 -0800782 dbg("%s - port %d", __func__, port->number);
Dave Platt45b844d2007-05-08 11:00:12 -0700783
784 spin_lock_irqsave(&priv->lock, flags);
785 priv->rx_flags |= THROTTLED;
786 if (C_CRTSCTS(tty)) {
Alan Cox95da3102008-07-22 11:09:07 +0100787 priv->control_state &= ~TIOCM_RTS;
788 control_state = priv->control_state;
789 spin_unlock_irqrestore(&priv->lock, flags);
790 (void) mct_u232_set_modem_ctrl(port->serial, control_state);
Dave Platt45b844d2007-05-08 11:00:12 -0700791 } else {
Alan Cox95da3102008-07-22 11:09:07 +0100792 spin_unlock_irqrestore(&priv->lock, flags);
Dave Platt45b844d2007-05-08 11:00:12 -0700793 }
794}
795
796
Alan Cox95da3102008-07-22 11:09:07 +0100797static void mct_u232_unthrottle(struct tty_struct *tty)
Dave Platt45b844d2007-05-08 11:00:12 -0700798{
Alan Cox95da3102008-07-22 11:09:07 +0100799 struct usb_serial_port *port = tty->driver_data;
Dave Platt45b844d2007-05-08 11:00:12 -0700800 struct mct_u232_private *priv = usb_get_serial_port_data(port);
801 unsigned long flags;
802 unsigned int control_state;
Dave Platt45b844d2007-05-08 11:00:12 -0700803
Harvey Harrison441b62c2008-03-03 16:08:34 -0800804 dbg("%s - port %d", __func__, port->number);
Dave Platt45b844d2007-05-08 11:00:12 -0700805
Dave Platt45b844d2007-05-08 11:00:12 -0700806 spin_lock_irqsave(&priv->lock, flags);
807 if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
Alan Cox95da3102008-07-22 11:09:07 +0100808 priv->rx_flags &= ~THROTTLED;
809 priv->control_state |= TIOCM_RTS;
810 control_state = priv->control_state;
811 spin_unlock_irqrestore(&priv->lock, flags);
812 (void) mct_u232_set_modem_ctrl(port->serial, control_state);
Dave Platt45b844d2007-05-08 11:00:12 -0700813 } else {
Alan Cox95da3102008-07-22 11:09:07 +0100814 spin_unlock_irqrestore(&priv->lock, flags);
Dave Platt45b844d2007-05-08 11:00:12 -0700815 }
816}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
Alan Coxe19b2562008-07-22 11:14:30 +0100818static int __init mct_u232_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819{
820 int retval;
821 retval = usb_serial_register(&mct_u232_device);
822 if (retval)
823 goto failed_usb_serial_register;
824 retval = usb_register(&mct_u232_driver);
825 if (retval)
826 goto failed_usb_register;
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -0700827 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
828 DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 return 0;
830failed_usb_register:
831 usb_serial_deregister(&mct_u232_device);
832failed_usb_serial_register:
833 return retval;
834}
835
836
Alan Coxe19b2562008-07-22 11:14:30 +0100837static void __exit mct_u232_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838{
Alan Coxe19b2562008-07-22 11:14:30 +0100839 usb_deregister(&mct_u232_driver);
840 usb_serial_deregister(&mct_u232_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841}
842
Alan Coxe19b2562008-07-22 11:14:30 +0100843module_init(mct_u232_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844module_exit(mct_u232_exit);
845
Alan Coxe19b2562008-07-22 11:14:30 +0100846MODULE_AUTHOR(DRIVER_AUTHOR);
847MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848MODULE_LICENSE("GPL");
849
850module_param(debug, bool, S_IRUGO | S_IWUSR);
851MODULE_PARM_DESC(debug, "Debug enabled or not");