Blame view

drivers/usb/serial/mct_u232.c 26 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
   * MCT (Magic Control Technology Corp.) USB RS232 Converter Driver
   *
   *   Copyright (C) 2000 Wolfgang Grandegger (wolfgang@ces.ch)
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   * This program is largely derived from the Belkin USB Serial Adapter Driver
   * (see belkin_sa.[ch]). All of the information about the device was acquired
   * by using SniffUSB on Windows98. For technical details see mct_u232.h.
   *
   * William G. Greathouse and Greg Kroah-Hartman provided great help on how to
   * do the reverse engineering and how to write a USB serial device driver.
   *
   * TO BE DONE, TO BE CHECKED:
   *   DTR/RTS signal handling may be incomplete or incorrect. I have mainly
   *   implemented what I have seen with SniffUSB or found in belkin_sa.c.
   *   For further TODOs check also belkin_sa.c.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
29
30
31
  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/tty.h>
  #include <linux/tty_driver.h>
  #include <linux/tty_flip.h>
  #include <linux/module.h>
  #include <linux/spinlock.h>
e19b2560b   Alan Cox   tty-usb-mct-u232:...
32
  #include <linux/uaccess.h>
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
33
  #include <asm/unaligned.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include <linux/usb.h>
a969888ce   Greg Kroah-Hartman   [PATCH] USB: move...
35
  #include <linux/usb/serial.h>
7af75af24   Vadim Tsozik   USB: serial: mct_...
36
37
  #include <linux/serial.h>
  #include <linux/ioctl.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
  #include "mct_u232.h"
  
  /*
   * Version Information
   */
45b844df5   Dave Platt   USB: RTS/CTS hand...
43
  #define DRIVER_VERSION "z2.1"		/* Linux in-kernel version */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
  #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
  #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
90ab5ee94   Rusty Russell   module_param: mak...
46
  static bool debug;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
  
  /*
   * Function prototypes
   */
e19b2560b   Alan Cox   tty-usb-mct-u232:...
51
  static int  mct_u232_startup(struct usb_serial *serial);
f9c99bb8b   Alan Stern   USB: usb-serial: ...
52
  static void mct_u232_release(struct usb_serial *serial);
a509a7e47   Alan Cox   tty: USB does not...
53
  static int  mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port);
335f8514f   Alan Cox   tty: Bring the us...
54
55
  static void mct_u232_close(struct usb_serial_port *port);
  static void mct_u232_dtr_rts(struct usb_serial_port *port, int on);
e19b2560b   Alan Cox   tty-usb-mct-u232:...
56
57
58
59
  static void mct_u232_read_int_callback(struct urb *urb);
  static void mct_u232_set_termios(struct tty_struct *tty,
  			struct usb_serial_port *port, struct ktermios *old);
  static void mct_u232_break_ctl(struct tty_struct *tty, int break_state);
60b33c133   Alan Cox   tiocmget: kill of...
60
  static int  mct_u232_tiocmget(struct tty_struct *tty);
20b9d1771   Alan Cox   tiocmset: kill th...
61
  static int  mct_u232_tiocmset(struct tty_struct *tty,
e19b2560b   Alan Cox   tty-usb-mct-u232:...
62
  			unsigned int set, unsigned int clear);
4acfaf829   Randy Dunlap   usb/serial: fix f...
63
  static int  mct_u232_ioctl(struct tty_struct *tty,
7af75af24   Vadim Tsozik   USB: serial: mct_...
64
65
66
  			unsigned int cmd, unsigned long arg);
  static int  mct_u232_get_icount(struct tty_struct *tty,
  			struct serial_icounter_struct *icount);
e19b2560b   Alan Cox   tty-usb-mct-u232:...
67
68
  static void mct_u232_throttle(struct tty_struct *tty);
  static void mct_u232_unthrottle(struct tty_struct *tty);
45b844df5   Dave Platt   USB: RTS/CTS hand...
69

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
  /*
   * All of the device info needed for the MCT USB-RS232 converter.
   */
7d40d7e85   Németh Márton   USB serial: make ...
73
  static const struct usb_device_id id_table_combined[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
77
78
79
  	{ USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
  	{ USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
  	{ USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
  	{ USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) },
  	{ }		/* Terminating entry */
  };
e19b2560b   Alan Cox   tty-usb-mct-u232:...
80
  MODULE_DEVICE_TABLE(usb, id_table_combined);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
  
  static struct usb_driver mct_u232_driver = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
  	.name =		"mct_u232",
  	.probe =	usb_serial_probe,
  	.disconnect =	usb_serial_disconnect,
  	.id_table =	id_table_combined,
ba9dc657a   Greg Kroah-Hartman   [PATCH] USB: allo...
87
  	.no_dynamic_id = 	1,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
  };
ea65370d0   Greg Kroah-Hartman   [PATCH] USB Seria...
89
  static struct usb_serial_driver mct_u232_device = {
18fcac353   Greg Kroah-Hartman   [PATCH] USB Seria...
90
91
  	.driver = {
  		.owner =	THIS_MODULE,
269bda1c1   Greg Kroah-Hartman   [PATCH] USB Seria...
92
  		.name =		"mct_u232",
18fcac353   Greg Kroah-Hartman   [PATCH] USB Seria...
93
  	},
269bda1c1   Greg Kroah-Hartman   [PATCH] USB Seria...
94
  	.description =	     "MCT U232",
d9b1b7877   Johannes Hölzl   USB serial: add d...
95
  	.usb_driver = 	     &mct_u232_driver,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  	.id_table =	     id_table_combined,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
  	.num_ports =	     1,
  	.open =		     mct_u232_open,
  	.close =	     mct_u232_close,
335f8514f   Alan Cox   tty: Bring the us...
100
  	.dtr_rts =	     mct_u232_dtr_rts,
45b844df5   Dave Platt   USB: RTS/CTS hand...
101
102
  	.throttle =	     mct_u232_throttle,
  	.unthrottle =	     mct_u232_unthrottle,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  	.read_int_callback = mct_u232_read_int_callback,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
108
  	.set_termios =	     mct_u232_set_termios,
  	.break_ctl =	     mct_u232_break_ctl,
  	.tiocmget =	     mct_u232_tiocmget,
  	.tiocmset =	     mct_u232_tiocmset,
  	.attach =	     mct_u232_startup,
f9c99bb8b   Alan Stern   USB: usb-serial: ...
109
  	.release =	     mct_u232_release,
7af75af24   Vadim Tsozik   USB: serial: mct_...
110
111
  	.ioctl =             mct_u232_ioctl,
  	.get_icount =        mct_u232_get_icount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
116
117
118
  struct mct_u232_private {
  	spinlock_t lock;
  	unsigned int	     control_state; /* Modem Line Setting (TIOCM) */
  	unsigned char        last_lcr;      /* Line Control Register */
  	unsigned char	     last_lsr;      /* Line Status Register */
  	unsigned char	     last_msr;      /* Modem Status Register */
45b844df5   Dave Platt   USB: RTS/CTS hand...
119
  	unsigned int	     rx_flags;      /* Throttling flags */
7af75af24   Vadim Tsozik   USB: serial: mct_...
120
121
122
  	struct async_icount  icount;
  	wait_queue_head_t    msr_wait;	/* for handling sleeping while waiting
  						for msr change to happen */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  };
45b844df5   Dave Platt   USB: RTS/CTS hand...
124
  #define THROTTLED		0x01
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
128
129
130
131
132
133
  /*
   * Handle vendor specific USB requests
   */
  
  #define WDR_TIMEOUT 5000 /* default urb timeout */
  
  /*
   * Later day 2.6.0-test kernels have new baud rates like B230400 which
   * we do not know how to support. We ignore them for the moment.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
   */
e19b2560b   Alan Cox   tty-usb-mct-u232:...
135
136
  static int mct_u232_calculate_baud_rate(struct usb_serial *serial,
  					speed_t value, speed_t *result)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  {
d0fab0ddf   Alan Cox   USB: mct232: spee...
138
  	*result = value;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  	if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID
e19b2560b   Alan Cox   tty-usb-mct-u232:...
140
  		|| le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  		switch (value) {
e19b2560b   Alan Cox   tty-usb-mct-u232:...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  		case 300:
  			return 0x01;
  		case 600:
  			return 0x02; /* this one not tested */
  		case 1200:
  			return 0x03;
  		case 2400:
  			return 0x04;
  		case 4800:
  			return 0x06;
  		case 9600:
  			return 0x08;
  		case 19200:
  			return 0x09;
  		case 38400:
  			return 0x0a;
  		case 57600:
  			return 0x0b;
  		case 115200:
  			return 0x0c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  		default:
d0fab0ddf   Alan Cox   USB: mct232: spee...
163
  			*result = 9600;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
  			return 0x08;
  		}
  	} else {
d0fab0ddf   Alan Cox   USB: mct232: spee...
167
168
169
  		/* FIXME: Can we use any divider - should we do
  		   divider = 115200/value;
  		   real baud = 115200/divider */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  		switch (value) {
b3aceb2ba   Andrew Morton   USB: mct_u232-con...
171
172
173
174
175
176
177
178
179
180
181
  		case 300: break;
  		case 600: break;
  		case 1200: break;
  		case 2400: break;
  		case 4800: break;
  		case 9600: break;
  		case 19200: break;
  		case 38400: break;
  		case 57600: break;
  		case 115200: break;
  		default:
b3aceb2ba   Andrew Morton   USB: mct_u232-con...
182
  			value = 9600;
d0fab0ddf   Alan Cox   USB: mct232: spee...
183
  			*result = 9600;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
  		}
  		return 115200/value;
  	}
  }
95da310e6   Alan Cox   usb_serial: API a...
188
189
  static int mct_u232_set_baud_rate(struct tty_struct *tty,
  	struct usb_serial *serial, struct usb_serial_port *port, speed_t value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
  {
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
191
  	unsigned int divisor;
e19b2560b   Alan Cox   tty-usb-mct-u232:...
192
  	int rc;
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
193
  	unsigned char *buf;
e19b2560b   Alan Cox   tty-usb-mct-u232:...
194
195
  	unsigned char cts_enable_byte = 0;
  	speed_t speed;
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
196
197
198
  	buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
  	if (buf == NULL)
  		return -ENOMEM;
e19b2560b   Alan Cox   tty-usb-mct-u232:...
199

af2ac1a09   Pete Zaitcev   USB: serial mct_u...
200
201
  	divisor = mct_u232_calculate_baud_rate(serial, value, &speed);
  	put_unaligned_le32(cpu_to_le32(divisor), buf);
e19b2560b   Alan Cox   tty-usb-mct-u232:...
202
203
204
  	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
  				MCT_U232_SET_BAUD_RATE_REQUEST,
  				MCT_U232_SET_REQUEST_TYPE,
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
205
  				0, 0, buf, MCT_U232_SET_BAUD_RATE_SIZE,
e19b2560b   Alan Cox   tty-usb-mct-u232:...
206
  				WDR_TIMEOUT);
d0fab0ddf   Alan Cox   USB: mct232: spee...
207
  	if (rc < 0)	/*FIXME: What value speed results */
194343d93   Greg Kroah-Hartman   USB: remove use o...
208
209
210
  		dev_err(&port->dev, "Set BAUD RATE %d failed (error = %d)
  ",
  			value, rc);
d0fab0ddf   Alan Cox   USB: mct232: spee...
211
  	else
95da310e6   Alan Cox   usb_serial: API a...
212
  		tty_encode_baud_rate(tty, speed, speed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
216
217
218
219
  	dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor);
  
  	/* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
  	   always sends two extra USB 'device request' messages after the
  	   'baud rate change' message.  The actual functionality of the
  	   request codes in these messages is not fully understood but these
  	   particular codes are never seen in any operation besides a baud
45b844df5   Dave Platt   USB: RTS/CTS hand...
220
221
222
223
224
225
226
  	   rate change.  Both of these messages send a single byte of data.
  	   In the first message, the value of this byte is always zero.
  
  	   The second message has been determined experimentally to control
  	   whether data will be transmitted to a device which is not asserting
  	   the 'CTS' signal.  If the second message's data byte is zero, data
  	   will be transmitted even if 'CTS' is not asserted (i.e. no hardware
e19b2560b   Alan Cox   tty-usb-mct-u232:...
227
228
229
  	   flow control).  if the second message's data byte is nonzero (a
  	   value of 1 is used by this driver), data will not be transmitted to
  	   a device which is not asserting 'CTS'.
45b844df5   Dave Platt   USB: RTS/CTS hand...
230
  	*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231

af2ac1a09   Pete Zaitcev   USB: serial mct_u...
232
  	buf[0] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
e19b2560b   Alan Cox   tty-usb-mct-u232:...
234
235
  				MCT_U232_SET_UNKNOWN1_REQUEST,
  				MCT_U232_SET_REQUEST_TYPE,
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
236
  				0, 0, buf, MCT_U232_SET_UNKNOWN1_SIZE,
e19b2560b   Alan Cox   tty-usb-mct-u232:...
237
  				WDR_TIMEOUT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  	if (rc < 0)
194343d93   Greg Kroah-Hartman   USB: remove use o...
239
240
241
242
  		dev_err(&port->dev, "Sending USB device request code %d "
  			"failed (error = %d)
  ", MCT_U232_SET_UNKNOWN1_REQUEST,
  			rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243

e19b2560b   Alan Cox   tty-usb-mct-u232:...
244
  	if (port && C_CRTSCTS(tty))
45b844df5   Dave Platt   USB: RTS/CTS hand...
245
  	   cts_enable_byte = 1;
45b844df5   Dave Platt   USB: RTS/CTS hand...
246

e19b2560b   Alan Cox   tty-usb-mct-u232:...
247
248
  	dbg("set_baud_rate: send second control message, data = %02X",
  							cts_enable_byte);
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
249
  	buf[0] = cts_enable_byte;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
e19b2560b   Alan Cox   tty-usb-mct-u232:...
251
252
  			MCT_U232_SET_CTS_REQUEST,
  			MCT_U232_SET_REQUEST_TYPE,
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
253
  			0, 0, buf, MCT_U232_SET_CTS_SIZE,
e19b2560b   Alan Cox   tty-usb-mct-u232:...
254
  			WDR_TIMEOUT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  	if (rc < 0)
194343d93   Greg Kroah-Hartman   USB: remove use o...
256
257
258
  		dev_err(&port->dev, "Sending USB device request code %d "
  			"failed (error = %d)
  ", MCT_U232_SET_CTS_REQUEST, rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259

af2ac1a09   Pete Zaitcev   USB: serial mct_u...
260
  	kfree(buf);
e19b2560b   Alan Cox   tty-usb-mct-u232:...
261
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
  } /* mct_u232_set_baud_rate */
  
  static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr)
  {
e19b2560b   Alan Cox   tty-usb-mct-u232:...
266
  	int rc;
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
267
268
269
270
271
272
273
  	unsigned char *buf;
  
  	buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
  	if (buf == NULL)
  		return -ENOMEM;
  
  	buf[0] = lcr;
e19b2560b   Alan Cox   tty-usb-mct-u232:...
274
275
276
  	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
  			MCT_U232_SET_LINE_CTRL_REQUEST,
  			MCT_U232_SET_REQUEST_TYPE,
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
277
  			0, 0, buf, MCT_U232_SET_LINE_CTRL_SIZE,
e19b2560b   Alan Cox   tty-usb-mct-u232:...
278
  			WDR_TIMEOUT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  	if (rc < 0)
194343d93   Greg Kroah-Hartman   USB: remove use o...
280
281
282
  		dev_err(&serial->dev->dev,
  			"Set LINE CTRL 0x%x failed (error = %d)
  ", lcr, rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  	dbg("set_line_ctrl: 0x%x", lcr);
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
284
  	kfree(buf);
e19b2560b   Alan Cox   tty-usb-mct-u232:...
285
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
290
  } /* mct_u232_set_line_ctrl */
  
  static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
  				   unsigned int control_state)
  {
e19b2560b   Alan Cox   tty-usb-mct-u232:...
291
  	int rc;
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
292
293
294
295
296
297
  	unsigned char mcr;
  	unsigned char *buf;
  
  	buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
  	if (buf == NULL)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298

af2ac1a09   Pete Zaitcev   USB: serial mct_u...
299
  	mcr = MCT_U232_MCR_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
302
303
  	if (control_state & TIOCM_DTR)
  		mcr |= MCT_U232_MCR_DTR;
  	if (control_state & TIOCM_RTS)
  		mcr |= MCT_U232_MCR_RTS;
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
304
  	buf[0] = mcr;
e19b2560b   Alan Cox   tty-usb-mct-u232:...
305
306
307
  	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
  			MCT_U232_SET_MODEM_CTRL_REQUEST,
  			MCT_U232_SET_REQUEST_TYPE,
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
308
  			0, 0, buf, MCT_U232_SET_MODEM_CTRL_SIZE,
e19b2560b   Alan Cox   tty-usb-mct-u232:...
309
  			WDR_TIMEOUT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  	if (rc < 0)
194343d93   Greg Kroah-Hartman   USB: remove use o...
311
312
313
  		dev_err(&serial->dev->dev,
  			"Set MODEM CTRL 0x%x failed (error = %d)
  ", mcr, rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  	dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr);
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
315
  	kfree(buf);
e19b2560b   Alan Cox   tty-usb-mct-u232:...
316
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  } /* mct_u232_set_modem_ctrl */
e19b2560b   Alan Cox   tty-usb-mct-u232:...
318
319
  static int mct_u232_get_modem_stat(struct usb_serial *serial,
  						unsigned char *msr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
  {
e19b2560b   Alan Cox   tty-usb-mct-u232:...
321
  	int rc;
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
322
323
324
325
326
327
328
  	unsigned char *buf;
  
  	buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
  	if (buf == NULL) {
  		*msr = 0;
  		return -ENOMEM;
  	}
e19b2560b   Alan Cox   tty-usb-mct-u232:...
329
330
331
  	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
  			MCT_U232_GET_MODEM_STAT_REQUEST,
  			MCT_U232_GET_REQUEST_TYPE,
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
332
  			0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE,
e19b2560b   Alan Cox   tty-usb-mct-u232:...
333
  			WDR_TIMEOUT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
  	if (rc < 0) {
194343d93   Greg Kroah-Hartman   USB: remove use o...
335
336
337
  		dev_err(&serial->dev->dev,
  			"Get MODEM STATus failed (error = %d)
  ", rc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
  		*msr = 0;
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
339
340
  	} else {
  		*msr = buf[0];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
  	}
  	dbg("get_modem_stat: 0x%x", *msr);
af2ac1a09   Pete Zaitcev   USB: serial mct_u...
343
  	kfree(buf);
e19b2560b   Alan Cox   tty-usb-mct-u232:...
344
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  } /* mct_u232_get_modem_stat */
7af75af24   Vadim Tsozik   USB: serial: mct_...
346
347
348
349
350
351
352
353
354
355
356
357
358
  static void mct_u232_msr_to_icount(struct async_icount *icount,
  						unsigned char msr)
  {
  	/* Translate Control Line states */
  	if (msr & MCT_U232_MSR_DDSR)
  		icount->dsr++;
  	if (msr & MCT_U232_MSR_DCTS)
  		icount->cts++;
  	if (msr & MCT_U232_MSR_DRI)
  		icount->rng++;
  	if (msr & MCT_U232_MSR_DCD)
  		icount->dcd++;
  } /* mct_u232_msr_to_icount */
e19b2560b   Alan Cox   tty-usb-mct-u232:...
359
360
  static void mct_u232_msr_to_state(unsigned int *control_state,
  						unsigned char msr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
  {
e19b2560b   Alan Cox   tty-usb-mct-u232:...
362
  	/* Translate Control Line states */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  	if (msr & MCT_U232_MSR_DSR)
  		*control_state |=  TIOCM_DSR;
  	else
  		*control_state &= ~TIOCM_DSR;
  	if (msr & MCT_U232_MSR_CTS)
  		*control_state |=  TIOCM_CTS;
  	else
  		*control_state &= ~TIOCM_CTS;
  	if (msr & MCT_U232_MSR_RI)
  		*control_state |=  TIOCM_RI;
  	else
  		*control_state &= ~TIOCM_RI;
  	if (msr & MCT_U232_MSR_CD)
  		*control_state |=  TIOCM_CD;
  	else
  		*control_state &= ~TIOCM_CD;
e19b2560b   Alan Cox   tty-usb-mct-u232:...
379
  	dbg("msr_to_state: msr=0x%x ==> state=0x%x", msr, *control_state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
384
  } /* mct_u232_msr_to_state */
  
  /*
   * Driver's tty interface functions
   */
e19b2560b   Alan Cox   tty-usb-mct-u232:...
385
  static int mct_u232_startup(struct usb_serial *serial)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
388
  {
  	struct mct_u232_private *priv;
  	struct usb_serial_port *port, *rport;
80b6ca483   Eric Sesterhenn   [PATCH] USB: kzal...
389
  	priv = kzalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
  	if (!priv)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  	spin_lock_init(&priv->lock);
7af75af24   Vadim Tsozik   USB: serial: mct_...
393
  	init_waitqueue_head(&priv->msr_wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
397
398
399
400
  	usb_set_serial_port_data(serial->port[0], priv);
  
  	init_waitqueue_head(&serial->port[0]->write_wait);
  
  	/* Puh, that's dirty */
  	port = serial->port[0];
  	rport = serial->port[1];
73135bb91   Mariusz Kozlowski   usb: mct_u232 fre...
401
402
  	/* No unlinking, it wasn't submitted yet. */
  	usb_free_urb(port->read_urb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
  	port->read_urb = rport->interrupt_in_urb;
  	rport->interrupt_in_urb = NULL;
  	port->read_urb->context = port;
e19b2560b   Alan Cox   tty-usb-mct-u232:...
406
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  } /* mct_u232_startup */
f9c99bb8b   Alan Stern   USB: usb-serial: ...
408
  static void mct_u232_release(struct usb_serial *serial)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
  {
  	struct mct_u232_private *priv;
  	int i;
e19b2560b   Alan Cox   tty-usb-mct-u232:...
412

441b62c1e   Harvey Harrison   USB: replace rema...
413
  	dbg("%s", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414

e19b2560b   Alan Cox   tty-usb-mct-u232:...
415
  	for (i = 0; i < serial->num_ports; ++i) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
  		/* My special items, the standard routines free my urbs */
  		priv = usb_get_serial_port_data(serial->port[i]);
f9c99bb8b   Alan Stern   USB: usb-serial: ...
418
  		kfree(priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
  	}
f9c99bb8b   Alan Stern   USB: usb-serial: ...
420
  } /* mct_u232_release */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421

a509a7e47   Alan Cox   tty: USB does not...
422
  static int  mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
427
428
429
430
  {
  	struct usb_serial *serial = port->serial;
  	struct mct_u232_private *priv = usb_get_serial_port_data(port);
  	int retval = 0;
  	unsigned int control_state;
  	unsigned long flags;
  	unsigned char last_lcr;
  	unsigned char last_msr;
441b62c1e   Harvey Harrison   USB: replace rema...
431
  	dbg("%s port %d", __func__, port->number);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
434
435
436
437
  
  	/* Compensate for a hardware bug: although the Sitecom U232-P25
  	 * device reports a maximum output packet size of 32 bytes,
  	 * it seems to be able to accept only 16 bytes (and that's what
  	 * SniffUSB says too...)
  	 */
e19b2560b   Alan Cox   tty-usb-mct-u232:...
438
439
  	if (le16_to_cpu(serial->dev->descriptor.idProduct)
  						== MCT_U232_SITECOM_PID)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  		port->bulk_out_size = 16;
e19b2560b   Alan Cox   tty-usb-mct-u232:...
441
  	/* Do a defined restart: the normal serial device seems to
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
446
  	 * always turn on DTR and RTS here, so do the same. I'm not
  	 * sure if this is really necessary. But it should not harm
  	 * either.
  	 */
  	spin_lock_irqsave(&priv->lock, flags);
95da310e6   Alan Cox   usb_serial: API a...
447
  	if (tty && (tty->termios->c_cflag & CBAUD))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
  		priv->control_state = TIOCM_DTR | TIOCM_RTS;
  	else
  		priv->control_state = 0;
e19b2560b   Alan Cox   tty-usb-mct-u232:...
451
452
  
  	priv->last_lcr = (MCT_U232_DATA_BITS_8 |
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
456
457
458
459
460
461
462
463
464
465
466
  			  MCT_U232_PARITY_NONE |
  			  MCT_U232_STOP_BITS_1);
  	control_state = priv->control_state;
  	last_lcr = priv->last_lcr;
  	spin_unlock_irqrestore(&priv->lock, flags);
  	mct_u232_set_modem_ctrl(serial, control_state);
  	mct_u232_set_line_ctrl(serial, last_lcr);
  
  	/* Read modem status and update control state */
  	mct_u232_get_modem_stat(serial, &last_msr);
  	spin_lock_irqsave(&priv->lock, flags);
  	priv->last_msr = last_msr;
  	mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
  	spin_unlock_irqrestore(&priv->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
  	retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
  	if (retval) {
194343d93   Greg Kroah-Hartman   USB: remove use o...
469
470
471
472
  		dev_err(&port->dev,
  			"usb_submit_urb(read bulk) failed pipe 0x%x err %d
  ",
  			port->read_urb->pipe, retval);
2f007de2f   Oliver Neukum   USB: fix error ha...
473
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
  	retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
2f007de2f   Oliver Neukum   USB: fix error ha...
476
477
  	if (retval) {
  		usb_kill_urb(port->read_urb);
194343d93   Greg Kroah-Hartman   USB: remove use o...
478
479
480
  		dev_err(&port->dev,
  			"usb_submit_urb(read int) failed pipe 0x%x err %d",
  			port->interrupt_in_urb->pipe, retval);
2f007de2f   Oliver Neukum   USB: fix error ha...
481
482
  		goto error;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
  	return 0;
2f007de2f   Oliver Neukum   USB: fix error ha...
484
485
486
  
  error:
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  } /* mct_u232_open */
335f8514f   Alan Cox   tty: Bring the us...
488
  static void mct_u232_dtr_rts(struct usb_serial_port *port, int on)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  {
45b844df5   Dave Platt   USB: RTS/CTS hand...
490
491
  	unsigned int control_state;
  	struct mct_u232_private *priv = usb_get_serial_port_data(port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492

335f8514f   Alan Cox   tty: Bring the us...
493
494
495
496
497
498
499
  	mutex_lock(&port->serial->disc_mutex);
  	if (!port->serial->disconnected) {
  		/* drop DTR and RTS */
  		spin_lock_irq(&priv->lock);
  		if (on)
  			priv->control_state |= TIOCM_DTR | TIOCM_RTS;
  		else
e33fe4d86   Oliver Neukum   USB: make sure us...
500
  			priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
335f8514f   Alan Cox   tty: Bring the us...
501
502
503
  		control_state = priv->control_state;
  		spin_unlock_irq(&priv->lock);
  		mct_u232_set_modem_ctrl(port->serial, control_state);
45b844df5   Dave Platt   USB: RTS/CTS hand...
504
  	}
335f8514f   Alan Cox   tty: Bring the us...
505
506
  	mutex_unlock(&port->serial->disc_mutex);
  }
45b844df5   Dave Platt   USB: RTS/CTS hand...
507

335f8514f   Alan Cox   tty: Bring the us...
508
509
510
  static void mct_u232_close(struct usb_serial_port *port)
  {
  	dbg("%s port %d", __func__, port->number);
45b844df5   Dave Platt   USB: RTS/CTS hand...
511

92ca0dc5e   Johan Hovold   USB: mct_u232: fi...
512
513
514
515
  	if (port->serial->dev) {
  		/* shutdown our urbs */
  		usb_kill_urb(port->write_urb);
  		usb_kill_urb(port->read_urb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
  		usb_kill_urb(port->interrupt_in_urb);
92ca0dc5e   Johan Hovold   USB: mct_u232: fi...
517
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
  } /* mct_u232_close */
e19b2560b   Alan Cox   tty-usb-mct-u232:...
519
  static void mct_u232_read_int_callback(struct urb *urb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  {
cdc977922   Ming Lei   USB: remove unnec...
521
  	struct usb_serial_port *port = urb->context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
524
525
  	struct mct_u232_private *priv = usb_get_serial_port_data(port);
  	struct usb_serial *serial = port->serial;
  	struct tty_struct *tty;
  	unsigned char *data = urb->transfer_buffer;
e96da398c   Greg Kroah-Hartman   USB: serial: mct_...
526
527
  	int retval;
  	int status = urb->status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
  	unsigned long flags;
e96da398c   Greg Kroah-Hartman   USB: serial: mct_...
529
  	switch (status) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
532
533
534
535
536
  	case 0:
  		/* success */
  		break;
  	case -ECONNRESET:
  	case -ENOENT:
  	case -ESHUTDOWN:
  		/* this urb is terminated, clean up */
e96da398c   Greg Kroah-Hartman   USB: serial: mct_...
537
  		dbg("%s - urb shutting down with status: %d",
441b62c1e   Harvey Harrison   USB: replace rema...
538
  		    __func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
  		return;
  	default:
e96da398c   Greg Kroah-Hartman   USB: serial: mct_...
541
  		dbg("%s - nonzero urb status received: %d",
441b62c1e   Harvey Harrison   USB: replace rema...
542
  		    __func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
545
546
  		goto exit;
  	}
  
  	if (!serial) {
441b62c1e   Harvey Harrison   USB: replace rema...
547
  		dbg("%s - bad serial pointer, exiting", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
  		return;
  	}
e19b2560b   Alan Cox   tty-usb-mct-u232:...
550
551
552
  	dbg("%s - port %d", __func__, port->number);
  	usb_serial_debug_data(debug, &port->dev, __func__,
  					urb->actual_length, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
554
555
556
557
  
  	/*
  	 * Work-a-round: handle the 'usual' bulk-in pipe here
  	 */
  	if (urb->transfer_buffer_length > 2) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  		if (urb->actual_length) {
054f2346c   Jiri Slaby   tty: USB: serial/...
559
560
561
562
563
564
  			tty = tty_port_tty_get(&port->port);
  			if (tty) {
  				tty_insert_flip_string(tty, data,
  						urb->actual_length);
  				tty_flip_buffer_push(tty);
  			}
4a90f09b2   Alan Cox   tty: usb-serial k...
565
  			tty_kref_put(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
  		}
  		goto exit;
  	}
e19b2560b   Alan Cox   tty-usb-mct-u232:...
569

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
573
574
575
  	/*
  	 * The interrupt-in pipe signals exceptional conditions (modem line
  	 * signal changes and errors). data[0] holds MSR, data[1] holds LSR.
  	 */
  	spin_lock_irqsave(&priv->lock, flags);
  	priv->last_msr = data[MCT_U232_MSR_INDEX];
e19b2560b   Alan Cox   tty-usb-mct-u232:...
576

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
  	/* Record Control Line states */
  	mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
7af75af24   Vadim Tsozik   USB: serial: mct_...
579
  	mct_u232_msr_to_icount(&priv->icount, priv->last_msr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  #if 0
e19b2560b   Alan Cox   tty-usb-mct-u232:...
581
  	/* Not yet handled. See belkin_sa.c for further information */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
585
586
587
588
589
  	/* Now to report any errors */
  	priv->last_lsr = data[MCT_U232_LSR_INDEX];
  	/*
  	 * fill in the flip buffer here, but I do not know the relation
  	 * to the current/next receive buffer or characters.  I need
  	 * to look in to this before committing any code.
  	 */
  	if (priv->last_lsr & MCT_U232_LSR_ERR) {
4a90f09b2   Alan Cox   tty: usb-serial k...
590
  		tty = tty_port_tty_get(&port->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
593
594
595
596
597
598
599
600
601
602
  		/* Overrun Error */
  		if (priv->last_lsr & MCT_U232_LSR_OE) {
  		}
  		/* Parity Error */
  		if (priv->last_lsr & MCT_U232_LSR_PE) {
  		}
  		/* Framing Error */
  		if (priv->last_lsr & MCT_U232_LSR_FE) {
  		}
  		/* Break Indicator */
  		if (priv->last_lsr & MCT_U232_LSR_BI) {
  		}
4a90f09b2   Alan Cox   tty: usb-serial k...
603
  		tty_kref_put(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
605
  	}
  #endif
7af75af24   Vadim Tsozik   USB: serial: mct_...
606
  	wake_up_interruptible(&priv->msr_wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
  	spin_unlock_irqrestore(&priv->lock, flags);
  exit:
e19b2560b   Alan Cox   tty-usb-mct-u232:...
609
  	retval = usb_submit_urb(urb, GFP_ATOMIC);
e96da398c   Greg Kroah-Hartman   USB: serial: mct_...
610
  	if (retval)
194343d93   Greg Kroah-Hartman   USB: remove use o...
611
612
613
614
  		dev_err(&port->dev,
  			"%s - usb_submit_urb failed with result %d
  ",
  			__func__, retval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
  } /* mct_u232_read_int_callback */
e19b2560b   Alan Cox   tty-usb-mct-u232:...
616
617
618
  static void mct_u232_set_termios(struct tty_struct *tty,
  				 struct usb_serial_port *port,
  				 struct ktermios *old_termios)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
620
621
  {
  	struct usb_serial *serial = port->serial;
  	struct mct_u232_private *priv = usb_get_serial_port_data(port);
95da310e6   Alan Cox   usb_serial: API a...
622
  	struct ktermios *termios = tty->termios;
d0fab0ddf   Alan Cox   USB: mct232: spee...
623
  	unsigned int cflag = termios->c_cflag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
  	unsigned int old_cflag = old_termios->c_cflag;
  	unsigned long flags;
45b844df5   Dave Platt   USB: RTS/CTS hand...
626
  	unsigned int control_state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
630
631
632
633
634
635
636
637
638
639
640
  	unsigned char last_lcr;
  
  	/* get a local copy of the current port settings */
  	spin_lock_irqsave(&priv->lock, flags);
  	control_state = priv->control_state;
  	spin_unlock_irqrestore(&priv->lock, flags);
  	last_lcr = 0;
  
  	/*
  	 * Update baud rate.
  	 * Do not attempt to cache old rates and skip settings,
  	 * disconnects screw such tricks up completely.
  	 * Premature optimization is the root of all evil.
  	 */
e19b2560b   Alan Cox   tty-usb-mct-u232:...
641
  	/* reassert DTR and RTS on transition from B0 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
  	if ((old_cflag & CBAUD) == B0) {
441b62c1e   Harvey Harrison   USB: replace rema...
643
  		dbg("%s: baud was B0", __func__);
45b844df5   Dave Platt   USB: RTS/CTS hand...
644
  		control_state |= TIOCM_DTR | TIOCM_RTS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
  		mct_u232_set_modem_ctrl(serial, control_state);
  	}
95da310e6   Alan Cox   usb_serial: API a...
647
  	mct_u232_set_baud_rate(tty, serial, port, tty_get_baud_rate(tty));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648

e19b2560b   Alan Cox   tty-usb-mct-u232:...
649
  	if ((cflag & CBAUD) == B0) {
441b62c1e   Harvey Harrison   USB: replace rema...
650
  		dbg("%s: baud is B0", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
  		/* Drop RTS and DTR */
  		control_state &= ~(TIOCM_DTR | TIOCM_RTS);
e19b2560b   Alan Cox   tty-usb-mct-u232:...
653
  		mct_u232_set_modem_ctrl(serial, control_state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
  	}
  
  	/*
  	 * Update line control register (LCR)
  	 */
  
  	/* set the parity */
  	if (cflag & PARENB)
  		last_lcr |= (cflag & PARODD) ?
  			MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
  	else
  		last_lcr |= MCT_U232_PARITY_NONE;
  
  	/* set the number of data bits */
  	switch (cflag & CSIZE) {
  	case CS5:
  		last_lcr |= MCT_U232_DATA_BITS_5; break;
  	case CS6:
  		last_lcr |= MCT_U232_DATA_BITS_6; break;
  	case CS7:
  		last_lcr |= MCT_U232_DATA_BITS_7; break;
  	case CS8:
  		last_lcr |= MCT_U232_DATA_BITS_8; break;
  	default:
194343d93   Greg Kroah-Hartman   USB: remove use o...
678
679
680
  		dev_err(&port->dev,
  			"CSIZE was not CS5-CS8, using default of 8
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
  		last_lcr |= MCT_U232_DATA_BITS_8;
  		break;
  	}
d0fab0ddf   Alan Cox   USB: mct232: spee...
684
  	termios->c_cflag &= ~CMSPAR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
688
689
  	/* set the number of stop bits */
  	last_lcr |= (cflag & CSTOPB) ?
  		MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
  
  	mct_u232_set_line_ctrl(serial, last_lcr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
691
692
693
694
695
  	/* save off the modified port settings */
  	spin_lock_irqsave(&priv->lock, flags);
  	priv->control_state = control_state;
  	priv->last_lcr = last_lcr;
  	spin_unlock_irqrestore(&priv->lock, flags);
  } /* mct_u232_set_termios */
95da310e6   Alan Cox   usb_serial: API a...
696
  static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  {
95da310e6   Alan Cox   usb_serial: API a...
698
  	struct usb_serial_port *port = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
702
  	struct usb_serial *serial = port->serial;
  	struct mct_u232_private *priv = usb_get_serial_port_data(port);
  	unsigned char lcr;
  	unsigned long flags;
441b62c1e   Harvey Harrison   USB: replace rema...
703
  	dbg("%sstate=%d", __func__, break_state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
  
  	spin_lock_irqsave(&priv->lock, flags);
  	lcr = priv->last_lcr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
  
  	if (break_state)
  		lcr |= MCT_U232_SET_BREAK;
6b447f04a   Alan Cox   tty: Drop the loc...
710
  	spin_unlock_irqrestore(&priv->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
713
  
  	mct_u232_set_line_ctrl(serial, lcr);
  } /* mct_u232_break_ctl */
60b33c133   Alan Cox   tiocmget: kill of...
714
  static int mct_u232_tiocmget(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
  {
95da310e6   Alan Cox   usb_serial: API a...
716
  	struct usb_serial_port *port = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
718
719
  	struct mct_u232_private *priv = usb_get_serial_port_data(port);
  	unsigned int control_state;
  	unsigned long flags;
e19b2560b   Alan Cox   tty-usb-mct-u232:...
720

441b62c1e   Harvey Harrison   USB: replace rema...
721
  	dbg("%s", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
725
726
727
728
  
  	spin_lock_irqsave(&priv->lock, flags);
  	control_state = priv->control_state;
  	spin_unlock_irqrestore(&priv->lock, flags);
  
  	return control_state;
  }
20b9d1771   Alan Cox   tiocmset: kill th...
729
  static int mct_u232_tiocmset(struct tty_struct *tty,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
  			      unsigned int set, unsigned int clear)
  {
95da310e6   Alan Cox   usb_serial: API a...
732
  	struct usb_serial_port *port = tty->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
735
736
  	struct usb_serial *serial = port->serial;
  	struct mct_u232_private *priv = usb_get_serial_port_data(port);
  	unsigned int control_state;
  	unsigned long flags;
e19b2560b   Alan Cox   tty-usb-mct-u232:...
737

441b62c1e   Harvey Harrison   USB: replace rema...
738
  	dbg("%s", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
  
  	spin_lock_irqsave(&priv->lock, flags);
  	control_state = priv->control_state;
  
  	if (set & TIOCM_RTS)
  		control_state |= TIOCM_RTS;
  	if (set & TIOCM_DTR)
  		control_state |= TIOCM_DTR;
  	if (clear & TIOCM_RTS)
  		control_state &= ~TIOCM_RTS;
  	if (clear & TIOCM_DTR)
  		control_state &= ~TIOCM_DTR;
  
  	priv->control_state = control_state;
  	spin_unlock_irqrestore(&priv->lock, flags);
  	return mct_u232_set_modem_ctrl(serial, control_state);
  }
95da310e6   Alan Cox   usb_serial: API a...
756
  static void mct_u232_throttle(struct tty_struct *tty)
45b844df5   Dave Platt   USB: RTS/CTS hand...
757
  {
95da310e6   Alan Cox   usb_serial: API a...
758
  	struct usb_serial_port *port = tty->driver_data;
45b844df5   Dave Platt   USB: RTS/CTS hand...
759
  	struct mct_u232_private *priv = usb_get_serial_port_data(port);
45b844df5   Dave Platt   USB: RTS/CTS hand...
760
  	unsigned int control_state;
45b844df5   Dave Platt   USB: RTS/CTS hand...
761

441b62c1e   Harvey Harrison   USB: replace rema...
762
  	dbg("%s - port %d", __func__, port->number);
45b844df5   Dave Platt   USB: RTS/CTS hand...
763

638325154   Oliver Neukum   USB: serial: fix ...
764
  	spin_lock_irq(&priv->lock);
45b844df5   Dave Platt   USB: RTS/CTS hand...
765
766
  	priv->rx_flags |= THROTTLED;
  	if (C_CRTSCTS(tty)) {
95da310e6   Alan Cox   usb_serial: API a...
767
768
  		priv->control_state &= ~TIOCM_RTS;
  		control_state = priv->control_state;
638325154   Oliver Neukum   USB: serial: fix ...
769
  		spin_unlock_irq(&priv->lock);
95da310e6   Alan Cox   usb_serial: API a...
770
  		(void) mct_u232_set_modem_ctrl(port->serial, control_state);
45b844df5   Dave Platt   USB: RTS/CTS hand...
771
  	} else {
638325154   Oliver Neukum   USB: serial: fix ...
772
  		spin_unlock_irq(&priv->lock);
45b844df5   Dave Platt   USB: RTS/CTS hand...
773
774
  	}
  }
95da310e6   Alan Cox   usb_serial: API a...
775
  static void mct_u232_unthrottle(struct tty_struct *tty)
45b844df5   Dave Platt   USB: RTS/CTS hand...
776
  {
95da310e6   Alan Cox   usb_serial: API a...
777
  	struct usb_serial_port *port = tty->driver_data;
45b844df5   Dave Platt   USB: RTS/CTS hand...
778
  	struct mct_u232_private *priv = usb_get_serial_port_data(port);
45b844df5   Dave Platt   USB: RTS/CTS hand...
779
  	unsigned int control_state;
45b844df5   Dave Platt   USB: RTS/CTS hand...
780

441b62c1e   Harvey Harrison   USB: replace rema...
781
  	dbg("%s - port %d", __func__, port->number);
45b844df5   Dave Platt   USB: RTS/CTS hand...
782

638325154   Oliver Neukum   USB: serial: fix ...
783
  	spin_lock_irq(&priv->lock);
45b844df5   Dave Platt   USB: RTS/CTS hand...
784
  	if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
95da310e6   Alan Cox   usb_serial: API a...
785
786
787
  		priv->rx_flags &= ~THROTTLED;
  		priv->control_state |= TIOCM_RTS;
  		control_state = priv->control_state;
638325154   Oliver Neukum   USB: serial: fix ...
788
  		spin_unlock_irq(&priv->lock);
95da310e6   Alan Cox   usb_serial: API a...
789
  		(void) mct_u232_set_modem_ctrl(port->serial, control_state);
45b844df5   Dave Platt   USB: RTS/CTS hand...
790
  	} else {
638325154   Oliver Neukum   USB: serial: fix ...
791
  		spin_unlock_irq(&priv->lock);
45b844df5   Dave Platt   USB: RTS/CTS hand...
792
793
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794

4acfaf829   Randy Dunlap   usb/serial: fix f...
795
  static int  mct_u232_ioctl(struct tty_struct *tty,
7af75af24   Vadim Tsozik   USB: serial: mct_...
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
  			unsigned int cmd, unsigned long arg)
  {
  	DEFINE_WAIT(wait);
  	struct usb_serial_port *port = tty->driver_data;
  	struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
  	struct async_icount cnow, cprev;
  	unsigned long flags;
  
  	dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
  
  	switch (cmd) {
  
  	case TIOCMIWAIT:
  
  		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
  
  		spin_lock_irqsave(&mct_u232_port->lock, flags);
  		cprev = mct_u232_port->icount;
  		spin_unlock_irqrestore(&mct_u232_port->lock, flags);
  		for ( ; ; ) {
  			prepare_to_wait(&mct_u232_port->msr_wait,
  					&wait, TASK_INTERRUPTIBLE);
  			schedule();
  			finish_wait(&mct_u232_port->msr_wait, &wait);
  			/* see if a signal did it */
  			if (signal_pending(current))
  				return -ERESTARTSYS;
  			spin_lock_irqsave(&mct_u232_port->lock, flags);
  			cnow = mct_u232_port->icount;
  			spin_unlock_irqrestore(&mct_u232_port->lock, flags);
  			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
  			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
  				return -EIO; /* no change => error */
  			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
  			    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
  			    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
  			    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
  				return 0;
  			}
  			cprev = cnow;
  		}
  
  	}
  	return -ENOIOCTLCMD;
  }
  
  static int  mct_u232_get_icount(struct tty_struct *tty,
  			struct serial_icounter_struct *icount)
  {
  	struct usb_serial_port *port = tty->driver_data;
  	struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
  	struct async_icount *ic = &mct_u232_port->icount;
  	unsigned long flags;
  
  	spin_lock_irqsave(&mct_u232_port->lock, flags);
  
  	icount->cts = ic->cts;
  	icount->dsr = ic->dsr;
  	icount->rng = ic->rng;
  	icount->dcd = ic->dcd;
  	icount->rx = ic->rx;
  	icount->tx = ic->tx;
  	icount->frame = ic->frame;
  	icount->overrun = ic->overrun;
  	icount->parity = ic->parity;
  	icount->brk = ic->brk;
  	icount->buf_overrun = ic->buf_overrun;
  
  	spin_unlock_irqrestore(&mct_u232_port->lock, flags);
  
  	dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d",
  		__func__,  port->number, icount->rx, icount->tx);
  	return 0;
  }
e19b2560b   Alan Cox   tty-usb-mct-u232:...
870
  static int __init mct_u232_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
873
874
875
876
877
878
  {
  	int retval;
  	retval = usb_serial_register(&mct_u232_device);
  	if (retval)
  		goto failed_usb_serial_register;
  	retval = usb_register(&mct_u232_driver);
  	if (retval)
  		goto failed_usb_register;
c197a8db5   Greg Kroah-Hartman   USB: remove info(...
879
880
881
  	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
  	       DRIVER_DESC "
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
884
885
886
887
  	return 0;
  failed_usb_register:
  	usb_serial_deregister(&mct_u232_device);
  failed_usb_serial_register:
  	return retval;
  }
e19b2560b   Alan Cox   tty-usb-mct-u232:...
888
  static void __exit mct_u232_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
  {
e19b2560b   Alan Cox   tty-usb-mct-u232:...
890
891
  	usb_deregister(&mct_u232_driver);
  	usb_serial_deregister(&mct_u232_device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  }
e19b2560b   Alan Cox   tty-usb-mct-u232:...
893
  module_init(mct_u232_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
  module_exit(mct_u232_exit);
e19b2560b   Alan Cox   tty-usb-mct-u232:...
895
896
  MODULE_AUTHOR(DRIVER_AUTHOR);
  MODULE_DESCRIPTION(DRIVER_DESC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
898
899
900
  MODULE_LICENSE("GPL");
  
  module_param(debug, bool, S_IRUGO | S_IWUSR);
  MODULE_PARM_DESC(debug, "Debug enabled or not");