blob: 873795548fc0a976a5bd129e3316933c9eda069b [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);
95static void mct_u232_shutdown(struct usb_serial *serial);
96static 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,
152 .shutdown = mct_u232_shutdown,
153};
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 Coxe19b2562008-07-22 11:14:30 +0100410static void mct_u232_shutdown(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]);
420 if (priv) {
421 usb_set_serial_port_data(serial->port[i], NULL);
422 kfree(priv);
423 }
424 }
425} /* mct_u232_shutdown */
426
Alan Coxe19b2562008-07-22 11:14:30 +0100427static int mct_u232_open(struct tty_struct *tty,
Alan Cox95da3102008-07-22 11:09:07 +0100428 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429{
430 struct usb_serial *serial = port->serial;
431 struct mct_u232_private *priv = usb_get_serial_port_data(port);
432 int retval = 0;
433 unsigned int control_state;
434 unsigned long flags;
435 unsigned char last_lcr;
436 unsigned char last_msr;
437
Harvey Harrison441b62c2008-03-03 16:08:34 -0800438 dbg("%s port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
440 /* Compensate for a hardware bug: although the Sitecom U232-P25
441 * device reports a maximum output packet size of 32 bytes,
442 * it seems to be able to accept only 16 bytes (and that's what
443 * SniffUSB says too...)
444 */
Alan Coxe19b2562008-07-22 11:14:30 +0100445 if (le16_to_cpu(serial->dev->descriptor.idProduct)
446 == MCT_U232_SITECOM_PID)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 port->bulk_out_size = 16;
448
Alan Coxe19b2562008-07-22 11:14:30 +0100449 /* Do a defined restart: the normal serial device seems to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 * always turn on DTR and RTS here, so do the same. I'm not
451 * sure if this is really necessary. But it should not harm
452 * either.
453 */
454 spin_lock_irqsave(&priv->lock, flags);
Alan Cox95da3102008-07-22 11:09:07 +0100455 if (tty && (tty->termios->c_cflag & CBAUD))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 priv->control_state = TIOCM_DTR | TIOCM_RTS;
457 else
458 priv->control_state = 0;
Alan Coxe19b2562008-07-22 11:14:30 +0100459
460 priv->last_lcr = (MCT_U232_DATA_BITS_8 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 MCT_U232_PARITY_NONE |
462 MCT_U232_STOP_BITS_1);
463 control_state = priv->control_state;
464 last_lcr = priv->last_lcr;
465 spin_unlock_irqrestore(&priv->lock, flags);
466 mct_u232_set_modem_ctrl(serial, control_state);
467 mct_u232_set_line_ctrl(serial, last_lcr);
468
469 /* Read modem status and update control state */
470 mct_u232_get_modem_stat(serial, &last_msr);
471 spin_lock_irqsave(&priv->lock, flags);
472 priv->last_msr = last_msr;
473 mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
474 spin_unlock_irqrestore(&priv->lock, flags);
475
476 port->read_urb->dev = port->serial->dev;
477 retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
478 if (retval) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700479 dev_err(&port->dev,
480 "usb_submit_urb(read bulk) failed pipe 0x%x err %d\n",
481 port->read_urb->pipe, retval);
Oliver Neukum2f007de2007-03-29 10:45:17 +0200482 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 }
484
485 port->interrupt_in_urb->dev = port->serial->dev;
486 retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Oliver Neukum2f007de2007-03-29 10:45:17 +0200487 if (retval) {
488 usb_kill_urb(port->read_urb);
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700489 dev_err(&port->dev,
490 "usb_submit_urb(read int) failed pipe 0x%x err %d",
491 port->interrupt_in_urb->pipe, retval);
Oliver Neukum2f007de2007-03-29 10:45:17 +0200492 goto error;
493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 return 0;
Oliver Neukum2f007de2007-03-29 10:45:17 +0200495
496error:
497 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498} /* mct_u232_open */
499
Alan Cox335f8512009-06-11 12:26:29 +0100500static void mct_u232_dtr_rts(struct usb_serial_port *port, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
Dave Platt45b844d2007-05-08 11:00:12 -0700502 unsigned int control_state;
503 struct mct_u232_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
Alan Cox335f8512009-06-11 12:26:29 +0100505 mutex_lock(&port->serial->disc_mutex);
506 if (!port->serial->disconnected) {
507 /* drop DTR and RTS */
508 spin_lock_irq(&priv->lock);
509 if (on)
510 priv->control_state |= TIOCM_DTR | TIOCM_RTS;
511 else
Oliver Neukume33fe4d2008-01-21 17:44:10 +0100512 priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
Alan Cox335f8512009-06-11 12:26:29 +0100513 control_state = priv->control_state;
514 spin_unlock_irq(&priv->lock);
515 mct_u232_set_modem_ctrl(port->serial, control_state);
Dave Platt45b844d2007-05-08 11:00:12 -0700516 }
Alan Cox335f8512009-06-11 12:26:29 +0100517 mutex_unlock(&port->serial->disc_mutex);
518}
Dave Platt45b844d2007-05-08 11:00:12 -0700519
Alan Cox335f8512009-06-11 12:26:29 +0100520static void mct_u232_close(struct usb_serial_port *port)
521{
522 dbg("%s port %d", __func__, port->number);
Dave Platt45b844d2007-05-08 11:00:12 -0700523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 if (port->serial->dev) {
525 /* shutdown our urbs */
526 usb_kill_urb(port->write_urb);
527 usb_kill_urb(port->read_urb);
528 usb_kill_urb(port->interrupt_in_urb);
529 }
530} /* mct_u232_close */
531
532
Alan Coxe19b2562008-07-22 11:14:30 +0100533static void mct_u232_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534{
Ming Leicdc97792008-02-24 18:41:47 +0800535 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 struct mct_u232_private *priv = usb_get_serial_port_data(port);
537 struct usb_serial *serial = port->serial;
538 struct tty_struct *tty;
539 unsigned char *data = urb->transfer_buffer;
Greg Kroah-Hartmane96da392007-06-15 15:44:13 -0700540 int retval;
541 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 unsigned long flags;
543
Greg Kroah-Hartmane96da392007-06-15 15:44:13 -0700544 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 case 0:
546 /* success */
547 break;
548 case -ECONNRESET:
549 case -ENOENT:
550 case -ESHUTDOWN:
551 /* this urb is terminated, clean up */
Greg Kroah-Hartmane96da392007-06-15 15:44:13 -0700552 dbg("%s - urb shutting down with status: %d",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800553 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 return;
555 default:
Greg Kroah-Hartmane96da392007-06-15 15:44:13 -0700556 dbg("%s - nonzero urb status received: %d",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800557 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 goto exit;
559 }
560
561 if (!serial) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800562 dbg("%s - bad serial pointer, exiting", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 return;
564 }
565
Alan Coxe19b2562008-07-22 11:14:30 +0100566 dbg("%s - port %d", __func__, port->number);
567 usb_serial_debug_data(debug, &port->dev, __func__,
568 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
570 /*
571 * Work-a-round: handle the 'usual' bulk-in pipe here
572 */
573 if (urb->transfer_buffer_length > 2) {
Alan Cox4a90f092008-10-13 10:39:46 +0100574 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 if (urb->actual_length) {
Alan Coxacc80752008-07-22 11:14:40 +0100576 tty_insert_flip_string(tty, data, urb->actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100578 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 }
580 goto exit;
581 }
Alan Coxe19b2562008-07-22 11:14:30 +0100582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 /*
584 * The interrupt-in pipe signals exceptional conditions (modem line
585 * signal changes and errors). data[0] holds MSR, data[1] holds LSR.
586 */
587 spin_lock_irqsave(&priv->lock, flags);
588 priv->last_msr = data[MCT_U232_MSR_INDEX];
Alan Coxe19b2562008-07-22 11:14:30 +0100589
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 /* Record Control Line states */
591 mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
592
593#if 0
Alan Coxe19b2562008-07-22 11:14:30 +0100594 /* Not yet handled. See belkin_sa.c for further information */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 /* Now to report any errors */
596 priv->last_lsr = data[MCT_U232_LSR_INDEX];
597 /*
598 * fill in the flip buffer here, but I do not know the relation
599 * to the current/next receive buffer or characters. I need
600 * to look in to this before committing any code.
601 */
602 if (priv->last_lsr & MCT_U232_LSR_ERR) {
Alan Cox4a90f092008-10-13 10:39:46 +0100603 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 /* Overrun Error */
605 if (priv->last_lsr & MCT_U232_LSR_OE) {
606 }
607 /* Parity Error */
608 if (priv->last_lsr & MCT_U232_LSR_PE) {
609 }
610 /* Framing Error */
611 if (priv->last_lsr & MCT_U232_LSR_FE) {
612 }
613 /* Break Indicator */
614 if (priv->last_lsr & MCT_U232_LSR_BI) {
615 }
Alan Cox4a90f092008-10-13 10:39:46 +0100616 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
618#endif
619 spin_unlock_irqrestore(&priv->lock, flags);
620exit:
Alan Coxe19b2562008-07-22 11:14:30 +0100621 retval = usb_submit_urb(urb, GFP_ATOMIC);
Greg Kroah-Hartmane96da392007-06-15 15:44:13 -0700622 if (retval)
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700623 dev_err(&port->dev,
624 "%s - usb_submit_urb failed with result %d\n",
625 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626} /* mct_u232_read_int_callback */
627
Alan Coxe19b2562008-07-22 11:14:30 +0100628static void mct_u232_set_termios(struct tty_struct *tty,
629 struct usb_serial_port *port,
630 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631{
632 struct usb_serial *serial = port->serial;
633 struct mct_u232_private *priv = usb_get_serial_port_data(port);
Alan Cox95da3102008-07-22 11:09:07 +0100634 struct ktermios *termios = tty->termios;
Alan Coxd0fab0d2007-12-13 16:15:29 -0800635 unsigned int cflag = termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 unsigned int old_cflag = old_termios->c_cflag;
637 unsigned long flags;
Dave Platt45b844d2007-05-08 11:00:12 -0700638 unsigned int control_state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 unsigned char last_lcr;
640
641 /* get a local copy of the current port settings */
642 spin_lock_irqsave(&priv->lock, flags);
643 control_state = priv->control_state;
644 spin_unlock_irqrestore(&priv->lock, flags);
645 last_lcr = 0;
646
647 /*
648 * Update baud rate.
649 * Do not attempt to cache old rates and skip settings,
650 * disconnects screw such tricks up completely.
651 * Premature optimization is the root of all evil.
652 */
653
Alan Coxe19b2562008-07-22 11:14:30 +0100654 /* reassert DTR and RTS on transition from B0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 if ((old_cflag & CBAUD) == B0) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800656 dbg("%s: baud was B0", __func__);
Dave Platt45b844d2007-05-08 11:00:12 -0700657 control_state |= TIOCM_DTR | TIOCM_RTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 mct_u232_set_modem_ctrl(serial, control_state);
659 }
660
Alan Cox95da3102008-07-22 11:09:07 +0100661 mct_u232_set_baud_rate(tty, serial, port, tty_get_baud_rate(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
Alan Coxe19b2562008-07-22 11:14:30 +0100663 if ((cflag & CBAUD) == B0) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800664 dbg("%s: baud is B0", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 /* Drop RTS and DTR */
666 control_state &= ~(TIOCM_DTR | TIOCM_RTS);
Alan Coxe19b2562008-07-22 11:14:30 +0100667 mct_u232_set_modem_ctrl(serial, control_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 }
669
670 /*
671 * Update line control register (LCR)
672 */
673
674 /* set the parity */
675 if (cflag & PARENB)
676 last_lcr |= (cflag & PARODD) ?
677 MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
678 else
679 last_lcr |= MCT_U232_PARITY_NONE;
680
681 /* set the number of data bits */
682 switch (cflag & CSIZE) {
683 case CS5:
684 last_lcr |= MCT_U232_DATA_BITS_5; break;
685 case CS6:
686 last_lcr |= MCT_U232_DATA_BITS_6; break;
687 case CS7:
688 last_lcr |= MCT_U232_DATA_BITS_7; break;
689 case CS8:
690 last_lcr |= MCT_U232_DATA_BITS_8; break;
691 default:
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700692 dev_err(&port->dev,
693 "CSIZE was not CS5-CS8, using default of 8\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 last_lcr |= MCT_U232_DATA_BITS_8;
695 break;
696 }
697
Alan Coxd0fab0d2007-12-13 16:15:29 -0800698 termios->c_cflag &= ~CMSPAR;
699
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 /* set the number of stop bits */
701 last_lcr |= (cflag & CSTOPB) ?
702 MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
703
704 mct_u232_set_line_ctrl(serial, last_lcr);
705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 /* save off the modified port settings */
707 spin_lock_irqsave(&priv->lock, flags);
708 priv->control_state = control_state;
709 priv->last_lcr = last_lcr;
710 spin_unlock_irqrestore(&priv->lock, flags);
711} /* mct_u232_set_termios */
712
Alan Cox95da3102008-07-22 11:09:07 +0100713static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
Alan Cox95da3102008-07-22 11:09:07 +0100715 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 struct usb_serial *serial = port->serial;
717 struct mct_u232_private *priv = usb_get_serial_port_data(port);
718 unsigned char lcr;
719 unsigned long flags;
720
Harvey Harrison441b62c2008-03-03 16:08:34 -0800721 dbg("%sstate=%d", __func__, break_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723 spin_lock_irqsave(&priv->lock, flags);
724 lcr = priv->last_lcr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 if (break_state)
727 lcr |= MCT_U232_SET_BREAK;
Alan Cox6b447f042009-01-02 13:48:56 +0000728 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
730 mct_u232_set_line_ctrl(serial, lcr);
731} /* mct_u232_break_ctl */
732
733
Alan Cox95da3102008-07-22 11:09:07 +0100734static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735{
Alan Cox95da3102008-07-22 11:09:07 +0100736 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 struct mct_u232_private *priv = usb_get_serial_port_data(port);
738 unsigned int control_state;
739 unsigned long flags;
Alan Coxe19b2562008-07-22 11:14:30 +0100740
Harvey Harrison441b62c2008-03-03 16:08:34 -0800741 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
743 spin_lock_irqsave(&priv->lock, flags);
744 control_state = priv->control_state;
745 spin_unlock_irqrestore(&priv->lock, flags);
746
747 return control_state;
748}
749
Alan Cox95da3102008-07-22 11:09:07 +0100750static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 unsigned int set, unsigned int clear)
752{
Alan Cox95da3102008-07-22 11:09:07 +0100753 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 struct usb_serial *serial = port->serial;
755 struct mct_u232_private *priv = usb_get_serial_port_data(port);
756 unsigned int control_state;
757 unsigned long flags;
Alan Coxe19b2562008-07-22 11:14:30 +0100758
Harvey Harrison441b62c2008-03-03 16:08:34 -0800759 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
761 spin_lock_irqsave(&priv->lock, flags);
762 control_state = priv->control_state;
763
764 if (set & TIOCM_RTS)
765 control_state |= TIOCM_RTS;
766 if (set & TIOCM_DTR)
767 control_state |= TIOCM_DTR;
768 if (clear & TIOCM_RTS)
769 control_state &= ~TIOCM_RTS;
770 if (clear & TIOCM_DTR)
771 control_state &= ~TIOCM_DTR;
772
773 priv->control_state = control_state;
774 spin_unlock_irqrestore(&priv->lock, flags);
775 return mct_u232_set_modem_ctrl(serial, control_state);
776}
777
Alan Cox95da3102008-07-22 11:09:07 +0100778static void mct_u232_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779{
Alan Cox95da3102008-07-22 11:09:07 +0100780 struct usb_serial_port *port = tty->driver_data;
Dave Platt45b844d2007-05-08 11:00:12 -0700781 struct mct_u232_private *priv = usb_get_serial_port_data(port);
782 unsigned long flags;
783 unsigned int control_state;
Dave Platt45b844d2007-05-08 11:00:12 -0700784
Harvey Harrison441b62c2008-03-03 16:08:34 -0800785 dbg("%s - port %d", __func__, port->number);
Dave Platt45b844d2007-05-08 11:00:12 -0700786
787 spin_lock_irqsave(&priv->lock, flags);
788 priv->rx_flags |= THROTTLED;
789 if (C_CRTSCTS(tty)) {
Alan Cox95da3102008-07-22 11:09:07 +0100790 priv->control_state &= ~TIOCM_RTS;
791 control_state = priv->control_state;
792 spin_unlock_irqrestore(&priv->lock, flags);
793 (void) mct_u232_set_modem_ctrl(port->serial, control_state);
Dave Platt45b844d2007-05-08 11:00:12 -0700794 } else {
Alan Cox95da3102008-07-22 11:09:07 +0100795 spin_unlock_irqrestore(&priv->lock, flags);
Dave Platt45b844d2007-05-08 11:00:12 -0700796 }
797}
798
799
Alan Cox95da3102008-07-22 11:09:07 +0100800static void mct_u232_unthrottle(struct tty_struct *tty)
Dave Platt45b844d2007-05-08 11:00:12 -0700801{
Alan Cox95da3102008-07-22 11:09:07 +0100802 struct usb_serial_port *port = tty->driver_data;
Dave Platt45b844d2007-05-08 11:00:12 -0700803 struct mct_u232_private *priv = usb_get_serial_port_data(port);
804 unsigned long flags;
805 unsigned int control_state;
Dave Platt45b844d2007-05-08 11:00:12 -0700806
Harvey Harrison441b62c2008-03-03 16:08:34 -0800807 dbg("%s - port %d", __func__, port->number);
Dave Platt45b844d2007-05-08 11:00:12 -0700808
Dave Platt45b844d2007-05-08 11:00:12 -0700809 spin_lock_irqsave(&priv->lock, flags);
810 if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
Alan Cox95da3102008-07-22 11:09:07 +0100811 priv->rx_flags &= ~THROTTLED;
812 priv->control_state |= TIOCM_RTS;
813 control_state = priv->control_state;
814 spin_unlock_irqrestore(&priv->lock, flags);
815 (void) mct_u232_set_modem_ctrl(port->serial, control_state);
Dave Platt45b844d2007-05-08 11:00:12 -0700816 } else {
Alan Cox95da3102008-07-22 11:09:07 +0100817 spin_unlock_irqrestore(&priv->lock, flags);
Dave Platt45b844d2007-05-08 11:00:12 -0700818 }
819}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Alan Coxe19b2562008-07-22 11:14:30 +0100821static int __init mct_u232_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822{
823 int retval;
824 retval = usb_serial_register(&mct_u232_device);
825 if (retval)
826 goto failed_usb_serial_register;
827 retval = usb_register(&mct_u232_driver);
828 if (retval)
829 goto failed_usb_register;
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -0700830 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
831 DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 return 0;
833failed_usb_register:
834 usb_serial_deregister(&mct_u232_device);
835failed_usb_serial_register:
836 return retval;
837}
838
839
Alan Coxe19b2562008-07-22 11:14:30 +0100840static void __exit mct_u232_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841{
Alan Coxe19b2562008-07-22 11:14:30 +0100842 usb_deregister(&mct_u232_driver);
843 usb_serial_deregister(&mct_u232_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844}
845
Alan Coxe19b2562008-07-22 11:14:30 +0100846module_init(mct_u232_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847module_exit(mct_u232_exit);
848
Alan Coxe19b2562008-07-22 11:14:30 +0100849MODULE_AUTHOR(DRIVER_AUTHOR);
850MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851MODULE_LICENSE("GPL");
852
853module_param(debug, bool, S_IRUGO | S_IWUSR);
854MODULE_PARM_DESC(debug, "Debug enabled or not");