1 /*
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>
36  *	Added support for the Belkin F5U109 DB9 adaptor
37  *
38  * 30-May-2001 Greg Kroah-Hartman
39  *	switched from using spinlock to a semaphore, which fixes lots of problems.
40  *
41  * 04-May-2001 Stelian Pop
42  *   - Set the maximum bulk output size for Sitecom U232-P25 model to 16 bytes
43  *     instead of the device reported 32 (using 32 bytes causes many data
44  *     loss, Windows driver uses 16 too).
45  *
46  * 02-May-2001 Stelian Pop
47  *   - Fixed the baud calculation for Sitecom U232-P25 model
48  *
49  * 08-Apr-2001 gb
50  *   - Identify version on module load.
51  *
52  * 06-Jan-2001 Cornel Ciocirlan
53  *   - Added support for Sitecom U232-P25 model (Product Id 0x0230)
54  *   - Added support for D-Link DU-H3SP USB BAY (Product Id 0x0200)
55  *
56  * 29-Nov-2000 Greg Kroah-Hartman
57  *   - Added device id table to fit with 2.4.0-test11 structure.
58  *   - took out DEAL_WITH_TWO_INT_IN_ENDPOINTS #define as it's not needed
59  *     (lots of things will change if/when the usb-serial core changes to
60  *     handle these issues.
61  *
62  * 27-Nov-2000 Wolfgang Grandegger
63  *   A version for kernel 2.4.0-test10 released to the Linux community
64  *   (via linux-usb-devel).
65  */
66 
67 #include <linux/config.h>
68 #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>
77 #include <asm/uaccess.h>
78 #include <linux/usb.h>
79 
80 #ifdef CONFIG_USB_SERIAL_DEBUG
81  	static int debug = 1;
82 #else
83  	static int debug;
84 #endif
85 
86 #include "usb-serial.h"
87 #include "mct_u232.h"
88 
89 /*
90  * Version Information
91  */
92 #define DRIVER_VERSION "z2.0"		/* Linux in-kernel version */
93 #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
94 #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
95 
96 /*
97  * Function prototypes
98  */
99 static int  mct_u232_startup	         (struct usb_serial *serial);
100 static void mct_u232_shutdown	         (struct usb_serial *serial);
101 static int  mct_u232_open	         (struct usb_serial_port *port,
102 					  struct file *filp);
103 static void mct_u232_close	         (struct usb_serial_port *port,
104 					  struct file *filp);
105 static void mct_u232_read_int_callback   (struct urb *urb);
106 static void mct_u232_set_termios         (struct usb_serial_port *port,
107 					  struct termios * old);
108 static int  mct_u232_ioctl	         (struct usb_serial_port *port,
109 					  struct file * file,
110 					  unsigned int cmd,
111 					  unsigned long arg);
112 static void mct_u232_break_ctl	         (struct usb_serial_port *port,
113 					  int break_state );
114 
115 /*
116  * All of the device info needed for the MCT USB-RS232 converter.
117  */
118 static struct usb_device_id id_table_combined [] = {
119 	{ USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
120 	{ USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
121 	{ USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
122 	{ USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) },
123 	{ }		/* Terminating entry */
124 };
125 
126 MODULE_DEVICE_TABLE (usb, id_table_combined);
127 
128 
129 static struct usb_serial_device_type mct_u232_device = {
130 	.owner =	     THIS_MODULE,
131 	.name =		     "MCT U232",
132 	.id_table =	     id_table_combined,
133 	.num_interrupt_in =  2,
134 	.num_bulk_in =	     0,
135 	.num_bulk_out =	     1,
136 	.num_ports =	     1,
137 	.open =		     mct_u232_open,
138 	.close =	     mct_u232_close,
139 	.read_int_callback = mct_u232_read_int_callback,
140 	.ioctl =	     mct_u232_ioctl,
141 	.set_termios =	     mct_u232_set_termios,
142 	.break_ctl =	     mct_u232_break_ctl,
143 	.startup =	     mct_u232_startup,
144 	.shutdown =	     mct_u232_shutdown,
145 };
146 
147 struct mct_u232_interval_kludge {
148 	int ecnt;			/* Error counter */
149 	int ibase;			/* Initial interval value */
150 };
151 
152 struct mct_u232_private {
153 	spinlock_t lock;
154 	struct mct_u232_interval_kludge ik[2];
155 	unsigned int	     control_state; /* Modem Line Setting (TIOCM) */
156 	unsigned char        last_lcr;      /* Line Control Register */
157 	unsigned char	     last_lsr;      /* Line Status Register */
158 	unsigned char	     last_msr;      /* Modem Status Register */
159 };
160 
161 /*
162  * Handle vendor specific USB requests
163  */
164 
165 #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
166 
167 /*
168  * Later day 2.6.0-test kernels have new baud rates like B230400 which
169  * we do not know how to support. We ignore them for the moment.
170  * XXX Rate-limit the error message, it's user triggerable.
171  */
mct_u232_calculate_baud_rate(struct usb_serial * serial,int value)172 static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value) {
173 	if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID
174 	  || serial->dev->descriptor.idProduct == MCT_U232_BELKIN_F5U109_PID) {
175 		switch (value) {
176 		case    B300: return 0x01;
177 		case    B600: return 0x02; /* this one not tested */
178 		case   B1200: return 0x03;
179 		case   B2400: return 0x04;
180 		case   B4800: return 0x06;
181 		case   B9600: return 0x08;
182 		case  B19200: return 0x09;
183 		case  B38400: return 0x0a;
184 		case  B57600: return 0x0b;
185 		case B115200: return 0x0c;
186 		default:
187 			err("MCT USB-RS232: unsupported baudrate request 0x%x,"
188 			    " using default of B9600", value);
189 			return 0x08;
190 		}
191 	} else {
192 		switch (value) {
193 		case    B300: value =     300; break;
194 		case    B600: value =     600; break;
195 		case   B1200: value =    1200; break;
196 		case   B2400: value =    2400; break;
197 		case   B4800: value =    4800; break;
198 		case   B9600: value =    9600; break;
199 		case  B19200: value =   19200; break;
200 		case  B38400: value =   38400; break;
201 		case  B57600: value =   57600; break;
202 		case B115200: value =  115200; break;
203 		default:
204 			err("MCT USB-RS232: unsupported baudrate request 0x%x,"
205 			    " using default of B9600", value);
206 			value = 9600;
207 		}
208 		return 115200/value;
209 	}
210 }
211 
mct_u232_set_baud_rate(struct usb_serial * serial,int value)212 static int mct_u232_set_baud_rate(struct usb_serial *serial, int value)
213 {
214 	unsigned int divisor;
215         int rc;
216         unsigned char zero_byte = 0;
217 
218 	divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value));
219 
220         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
221                              MCT_U232_SET_BAUD_RATE_REQUEST,
222 			     MCT_U232_SET_REQUEST_TYPE,
223                              0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
224 			     WDR_TIMEOUT);
225 	if (rc < 0)
226 		err("Set BAUD RATE %d failed (error = %d)", value, rc);
227 	dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor);
228 
229 	/* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
230 	   always sends two extra USB 'device request' messages after the
231 	   'baud rate change' message.  The actual functionality of the
232 	   request codes in these messages is not fully understood but these
233 	   particular codes are never seen in any operation besides a baud
234 	   rate change.  Both of these messages send a single byte of data
235 	   whose value is always zero.  The second of these two extra messages
236 	   is required in order for data to be properly written to an RS-232
237 	   device which does not assert the 'CTS' signal. */
238 
239 	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
240 			     MCT_U232_SET_UNKNOWN1_REQUEST,
241 			     MCT_U232_SET_REQUEST_TYPE,
242 			     0, 0, &zero_byte, MCT_U232_SET_UNKNOWN1_SIZE,
243 			     WDR_TIMEOUT);
244 	if (rc < 0)
245 		err("Sending USB device request code %d failed (error = %d)",
246 		    MCT_U232_SET_UNKNOWN1_REQUEST, rc);
247 
248 	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
249 			     MCT_U232_SET_UNKNOWN2_REQUEST,
250 			     MCT_U232_SET_REQUEST_TYPE,
251 			     0, 0, &zero_byte, MCT_U232_SET_UNKNOWN2_SIZE,
252 			     WDR_TIMEOUT);
253 	if (rc < 0)
254 		err("Sending USB device request code %d failed (error = %d)",
255 		    MCT_U232_SET_UNKNOWN2_REQUEST, rc);
256 
257         return rc;
258 } /* mct_u232_set_baud_rate */
259 
mct_u232_set_line_ctrl(struct usb_serial * serial,unsigned char lcr)260 static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr)
261 {
262         int rc;
263         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
264                              MCT_U232_SET_LINE_CTRL_REQUEST,
265 			     MCT_U232_SET_REQUEST_TYPE,
266                              0, 0, &lcr, MCT_U232_SET_LINE_CTRL_SIZE,
267 			     WDR_TIMEOUT);
268 	if (rc < 0)
269 		err("Set LINE CTRL 0x%x failed (error = %d)", lcr, rc);
270 	dbg("set_line_ctrl: 0x%x", lcr);
271         return rc;
272 } /* mct_u232_set_line_ctrl */
273 
mct_u232_set_modem_ctrl(struct usb_serial * serial,unsigned int control_state)274 static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
275 				   unsigned int control_state)
276 {
277         int rc;
278 	unsigned char mcr = MCT_U232_MCR_NONE;
279 
280 	if (control_state & TIOCM_DTR)
281 		mcr |= MCT_U232_MCR_DTR;
282 	if (control_state & TIOCM_RTS)
283 		mcr |= MCT_U232_MCR_RTS;
284 
285         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
286                              MCT_U232_SET_MODEM_CTRL_REQUEST,
287 			     MCT_U232_SET_REQUEST_TYPE,
288                              0, 0, &mcr, MCT_U232_SET_MODEM_CTRL_SIZE,
289 			     WDR_TIMEOUT);
290 	if (rc < 0)
291 		err("Set MODEM CTRL 0x%x failed (error = %d)", mcr, rc);
292 	dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr);
293 
294         return rc;
295 } /* mct_u232_set_modem_ctrl */
296 
mct_u232_get_modem_stat(struct usb_serial * serial,unsigned char * msr)297 static int mct_u232_get_modem_stat(struct usb_serial *serial, unsigned char *msr)
298 {
299         int rc;
300         rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
301                              MCT_U232_GET_MODEM_STAT_REQUEST,
302 			     MCT_U232_GET_REQUEST_TYPE,
303                              0, 0, msr, MCT_U232_GET_MODEM_STAT_SIZE,
304 			     WDR_TIMEOUT);
305 	if (rc < 0) {
306 		err("Get MODEM STATus failed (error = %d)", rc);
307 		*msr = 0;
308 	}
309 	dbg("get_modem_stat: 0x%x", *msr);
310         return rc;
311 } /* mct_u232_get_modem_stat */
312 
mct_u232_msr_to_state(unsigned int * control_state,unsigned char msr)313 static void mct_u232_msr_to_state(unsigned int *control_state, unsigned char msr)
314 {
315  	/* Translate Control Line states */
316 	if (msr & MCT_U232_MSR_DSR)
317 		*control_state |=  TIOCM_DSR;
318 	else
319 		*control_state &= ~TIOCM_DSR;
320 	if (msr & MCT_U232_MSR_CTS)
321 		*control_state |=  TIOCM_CTS;
322 	else
323 		*control_state &= ~TIOCM_CTS;
324 	if (msr & MCT_U232_MSR_RI)
325 		*control_state |=  TIOCM_RI;
326 	else
327 		*control_state &= ~TIOCM_RI;
328 	if (msr & MCT_U232_MSR_CD)
329 		*control_state |=  TIOCM_CD;
330 	else
331 		*control_state &= ~TIOCM_CD;
332  	dbg("msr_to_state: msr=0x%x ==> state=0x%x", msr, *control_state);
333 } /* mct_u232_msr_to_state */
334 
335 /*
336  * Driver's tty interface functions
337  */
338 
mct_u232_startup(struct usb_serial * serial)339 static int mct_u232_startup (struct usb_serial *serial)
340 {
341 	struct mct_u232_private *priv;
342 	struct usb_serial_port *port, *rport;
343 
344 	priv = kmalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
345 	if (!priv)
346 		return -ENOMEM;
347 	memset(priv, 0, sizeof(struct mct_u232_private));
348 	spin_lock_init(&priv->lock);
349 	serial->port->private = priv;
350 
351 	init_waitqueue_head(&serial->port->write_wait);
352 
353 	/* Puh, that's dirty */
354 	port = &serial->port[0];
355 	rport = &serial->port[1];
356 	if (port->read_urb) {
357 		/* No unlinking, it wasn't submitted yet. */
358 		usb_free_urb(port->read_urb);
359 	}
360 	port->read_urb = rport->interrupt_in_urb;
361 	rport->interrupt_in_urb = NULL;
362 	port->read_urb->context = port;
363 
364 	priv->ik[0].ibase = port->read_urb->interval;
365 	priv->ik[1].ibase = port->interrupt_in_urb->interval;
366 
367 	return (0);
368 } /* mct_u232_startup */
369 
370 
mct_u232_shutdown(struct usb_serial * serial)371 static void mct_u232_shutdown (struct usb_serial *serial)
372 {
373 	struct mct_u232_private *priv;
374 	int i;
375 
376 	dbg("%s", __FUNCTION__);
377 
378 	for (i=0; i < serial->num_ports; ++i) {
379 		/* My special items, the standard routines free my urbs */
380 		priv = serial->port[i].private;
381 		if (priv) {
382 			serial->port[i].private = NULL;
383 			kfree(priv);
384 		}
385 	}
386 } /* mct_u232_shutdown */
387 
mct_u232_open(struct usb_serial_port * port,struct file * filp)388 static int  mct_u232_open (struct usb_serial_port *port, struct file *filp)
389 {
390 	struct usb_serial *serial = port->serial;
391 	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
392 	int retval = 0;
393 	unsigned int control_state;
394 	unsigned long flags;
395 	unsigned char last_lcr;
396 	unsigned char last_msr;
397 
398 	dbg("%s port %d", __FUNCTION__, port->number);
399 
400 	/* Compensate for a hardware bug: although the Sitecom U232-P25
401 	 * device reports a maximum output packet size of 32 bytes,
402 	 * it seems to be able to accept only 16 bytes (and that's what
403 	 * SniffUSB says too...)
404 	 */
405 	if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID)
406 		port->bulk_out_size = 16;
407 
408 	/* Do a defined restart: the normal serial device seems to
409 	 * always turn on DTR and RTS here, so do the same. I'm not
410 	 * sure if this is really necessary. But it should not harm
411 	 * either.
412 	 */
413 	spin_lock_irqsave(&priv->lock, flags);
414 	if (port->tty->termios->c_cflag & CBAUD)
415 		priv->control_state = TIOCM_DTR | TIOCM_RTS;
416 	else
417 		priv->control_state = 0;
418 
419 	priv->last_lcr = (MCT_U232_DATA_BITS_8 |
420 			  MCT_U232_PARITY_NONE |
421 			  MCT_U232_STOP_BITS_1);
422 	control_state = priv->control_state;
423 	last_lcr = priv->last_lcr;
424 	spin_unlock_irqrestore(&priv->lock, flags);
425 	mct_u232_set_modem_ctrl(serial, control_state);
426 	mct_u232_set_line_ctrl(serial, last_lcr);
427 
428 	/* Read modem status and update control state */
429 	mct_u232_get_modem_stat(serial, &last_msr);
430 	spin_lock_irqsave(&priv->lock, flags);
431 	priv->last_msr = last_msr;
432 	mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
433 	spin_unlock_irqrestore(&priv->lock, flags);
434 
435 	port->read_urb->dev = port->serial->dev;
436 	port->read_urb->interval = priv->ik[0].ibase;
437 	retval = usb_submit_urb(port->read_urb);
438 	if (retval) {
439 		err("usb_submit_urb(read bulk) failed pipe 0x%x err %d",
440 		    port->read_urb->pipe, retval);
441 		goto exit;
442 	}
443 
444 	port->interrupt_in_urb->dev = port->serial->dev;
445 	port->interrupt_in_urb->interval = priv->ik[1].ibase;
446 	retval = usb_submit_urb(port->interrupt_in_urb);
447 	if (retval)
448 		err(" usb_submit_urb(read int) failed pipe 0x%x err %d",
449 		    port->interrupt_in_urb->pipe, retval);
450 
451 exit:
452 	return 0;
453 } /* mct_u232_open */
454 
455 
mct_u232_close(struct usb_serial_port * port,struct file * filp)456 static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
457 {
458 	dbg("%s port %d", __FUNCTION__, port->number);
459 
460 	if (port->serial->dev) {
461 		/* shutdown our urbs */
462 		usb_unlink_urb (port->write_urb);
463 		usb_unlink_urb (port->read_urb);
464 		usb_unlink_urb (port->interrupt_in_urb);
465 	}
466 } /* mct_u232_close */
467 
mct_u232_error_step(struct urb * urb,struct mct_u232_private * priv,int n)468 static void mct_u232_error_step (struct urb *urb,
469     struct mct_u232_private *priv, int n)
470 {
471 	struct mct_u232_interval_kludge *ikp = &priv->ik[n];
472 
473 	if (ikp->ecnt >= 2) {
474 		if (urb->interval)
475 			err("%s - too many errors: "
476 			    "status %d pipe 0x%x interval %d",
477 			    __FUNCTION__,
478 			    urb->status, urb->pipe, urb->interval);
479 		urb->interval = 0;
480 	} else {
481 		++ikp->ecnt;
482 	}
483 }
484 
mct_u232_read_int_callback(struct urb * urb)485 static void mct_u232_read_int_callback (struct urb *urb)
486 {
487 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
488 	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
489 	struct usb_serial *serial = port->serial;
490 	struct tty_struct *tty;
491 	unsigned char *data = urb->transfer_buffer;
492 	unsigned long flags;
493 
494 	/* The urb might have been killed. */
495         if (urb->status) {
496 		dbg("%s - nonzero status %d, pipe 0x%x flags 0x%x interval %d",
497 		    __FUNCTION__,
498 		    urb->status, urb->pipe, urb->transfer_flags, urb->interval);
499 		/*
500 		 * The bad stuff happens when a device is disconnected.
501 		 * This can cause us to spin while trying to resubmit.
502 		 * Unfortunately, in kernel 2.4 error codes are wildly
503 		 * different between controllers, so the status is useless.
504 		 * Instead we just refuse to spin too much.
505 		 */
506 		if (urb == port->read_urb)
507 			mct_u232_error_step(urb, priv, 0);
508 		if (urb == port->interrupt_in_urb)
509 			mct_u232_error_step(urb, priv, 1);
510                 return;
511         }
512 	if (!serial) {
513 		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
514 		return;
515 	}
516 
517         dbg("%s - port %d", __FUNCTION__, port->number);
518 	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
519 
520 	if (urb == port->read_urb)
521 		priv->ik[0].ecnt = 0;
522 	if (urb == port->interrupt_in_urb)
523 		priv->ik[1].ecnt = 0;
524 
525 	/*
526 	 * Work-a-round: handle the 'usual' bulk-in pipe here
527 	 */
528 	if (urb->transfer_buffer_length > 2) {
529 		int i;
530 		tty = port->tty;
531 		if (urb->actual_length) {
532 			for (i = 0; i < urb->actual_length ; ++i) {
533 				tty_insert_flip_char(tty, data[i], 0);
534 			}
535 			tty_flip_buffer_push(tty);
536 		}
537 		/* INT urbs are automatically re-submitted */
538 		return;
539 	}
540 
541 	/*
542 	 * The interrupt-in pipe signals exceptional conditions (modem line
543 	 * signal changes and errors). data[0] holds MSR, data[1] holds LSR.
544 	 */
545 	spin_lock_irqsave(&priv->lock, flags);
546 	priv->last_msr = data[MCT_U232_MSR_INDEX];
547 
548 	/* Record Control Line states */
549 	mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
550 
551 #if 0
552 	/* Not yet handled. See belin_sa.c for further information */
553 	/* Now to report any errors */
554 	priv->last_lsr = data[MCT_U232_LSR_INDEX];
555 	/*
556 	 * fill in the flip buffer here, but I do not know the relation
557 	 * to the current/next receive buffer or characters.  I need
558 	 * to look in to this before committing any code.
559 	 */
560 	if (priv->last_lsr & MCT_U232_LSR_ERR) {
561 		tty = port->tty;
562 		/* Overrun Error */
563 		if (priv->last_lsr & MCT_U232_LSR_OE) {
564 		}
565 		/* Parity Error */
566 		if (priv->last_lsr & MCT_U232_LSR_PE) {
567 		}
568 		/* Framing Error */
569 		if (priv->last_lsr & MCT_U232_LSR_FE) {
570 		}
571 		/* Break Indicator */
572 		if (priv->last_lsr & MCT_U232_LSR_BI) {
573 		}
574 	}
575 #endif
576 	spin_unlock_irqrestore(&priv->lock, flags);
577 
578 	/* INT urbs are automatically re-submitted */
579 } /* mct_u232_read_int_callback */
580 
mct_u232_set_termios(struct usb_serial_port * port,struct termios * old_termios)581 static void mct_u232_set_termios (struct usb_serial_port *port,
582 				  struct termios *old_termios)
583 {
584 	struct usb_serial *serial = port->serial;
585 	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
586 	unsigned int iflag = port->tty->termios->c_iflag;
587 	unsigned int cflag = port->tty->termios->c_cflag;
588 	unsigned int old_cflag = old_termios->c_cflag;
589 	unsigned long flags;
590 	unsigned int control_state, new_state;
591 	unsigned char last_lcr;
592 
593 	/* get a local copy of the current port settings */
594 	spin_lock_irqsave(&priv->lock, flags);
595 	control_state = priv->control_state;
596 	spin_unlock_irqrestore(&priv->lock, flags);
597 	last_lcr = 0;
598 
599 	/*
600 	 * Update baud rate.
601 	 * Do not attempt to cache old rates and skip settings,
602 	 * disconnects screw such tricks up completely.
603 	 * Premature optimization is the root of all evil.
604 	 */
605 
606         /* reassert DTR and (maybe) RTS on transition from B0 */
607 	if ((old_cflag & CBAUD) == B0) {
608 		dbg("%s: baud was B0", __FUNCTION__);
609 		control_state |= TIOCM_DTR;
610 		/* don't set RTS if using hardware flow control */
611 		if (!(old_cflag & CRTSCTS)) {
612 			control_state |= TIOCM_RTS;
613 		}
614 		mct_u232_set_modem_ctrl(serial, control_state);
615 	}
616 
617 	mct_u232_set_baud_rate(serial, cflag & CBAUD);
618 
619 	if ((cflag & CBAUD) == B0 ) {
620 		dbg("%s: baud is B0", __FUNCTION__);
621 		/* Drop RTS and DTR */
622 		control_state &= ~(TIOCM_DTR | TIOCM_RTS);
623        		mct_u232_set_modem_ctrl(serial, control_state);
624 	}
625 
626 	/*
627 	 * Update line control register (LCR)
628 	 */
629 
630 	/* set the parity */
631 	if (cflag & PARENB)
632 		last_lcr |= (cflag & PARODD) ?
633 			MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
634 	else
635 		last_lcr |= MCT_U232_PARITY_NONE;
636 
637 	/* set the number of data bits */
638 	switch (cflag & CSIZE) {
639 	case CS5:
640 		last_lcr |= MCT_U232_DATA_BITS_5; break;
641 	case CS6:
642 		last_lcr |= MCT_U232_DATA_BITS_6; break;
643 	case CS7:
644 		last_lcr |= MCT_U232_DATA_BITS_7; break;
645 	case CS8:
646 		last_lcr |= MCT_U232_DATA_BITS_8; break;
647 	default:
648 		err("CSIZE was not CS5-CS8, using default of 8");
649 		last_lcr |= MCT_U232_DATA_BITS_8;
650 		break;
651 	}
652 
653 	/* set the number of stop bits */
654 	last_lcr |= (cflag & CSTOPB) ?
655 		MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
656 
657 	mct_u232_set_line_ctrl(serial, last_lcr);
658 
659 	/*
660 	 * Set flow control: well, I do not really now how to handle DTR/RTS.
661 	 * Just do what we have seen with SniffUSB on Win98.
662 	 */
663 	/* Drop DTR/RTS if no flow control otherwise assert */
664 	new_state = control_state;
665 	if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
666 		new_state |= TIOCM_DTR | TIOCM_RTS;
667 	else
668 		new_state &= ~(TIOCM_DTR | TIOCM_RTS);
669 	if (new_state != control_state) {
670 		mct_u232_set_modem_ctrl(serial, new_state);
671 		control_state = new_state;
672 	}
673 
674 	/* save off the modified port settings */
675 	spin_lock_irqsave(&priv->lock, flags);
676 	priv->control_state = control_state;
677 	priv->last_lcr = last_lcr;
678 	spin_unlock_irqrestore(&priv->lock, flags);
679 } /* mct_u232_set_termios */
680 
mct_u232_break_ctl(struct usb_serial_port * port,int break_state)681 static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state )
682 {
683 	struct usb_serial *serial = port->serial;
684 	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
685 	unsigned char lcr;
686 	unsigned long flags;
687 
688 	dbg("%sstate=%d", __FUNCTION__, break_state);
689 
690 	spin_lock_irqsave(&priv->lock, flags);
691 	lcr = priv->last_lcr;
692 	spin_unlock_irqrestore(&priv->lock, flags);
693 
694 	if (break_state)
695 		lcr |= MCT_U232_SET_BREAK;
696 
697 	mct_u232_set_line_ctrl(serial, lcr);
698 } /* mct_u232_break_ctl */
699 
700 
mct_u232_tiocmget(struct usb_serial_port * port,struct file * file)701 static int mct_u232_tiocmget (struct usb_serial_port *port, struct file *file)
702 {
703 	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
704 	unsigned int control_state;
705 	unsigned long flags;
706 
707 	dbg("%s", __FUNCTION__);
708 
709 	spin_lock_irqsave(&priv->lock, flags);
710 	control_state = priv->control_state;
711 	spin_unlock_irqrestore(&priv->lock, flags);
712 
713 	return control_state;
714 }
715 
mct_u232_ioctl(struct usb_serial_port * port,struct file * file,unsigned int cmd,unsigned long arg)716 static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
717 			   unsigned int cmd, unsigned long arg)
718 {
719 	struct usb_serial *serial = port->serial;
720 	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
721 	int mask;
722 	unsigned long flags;
723 
724 	dbg("%scmd=0x%x", __FUNCTION__, cmd);
725 
726 	/* Based on code from acm.c and others */
727 	switch (cmd) {
728 	case TIOCMGET:
729 		mask = mct_u232_tiocmget(port, file);
730 		return put_user(mask, (unsigned long *) arg);
731 
732 	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
733 	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
734 	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
735 		if (get_user(mask, (unsigned long *) arg))
736 			return -EFAULT;
737 
738 		spin_lock_irqsave(&priv->lock, flags);
739 		if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
740 			/* RTS needs set */
741 			if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) ||
742 			    (cmd == TIOCMBIS) )
743 				priv->control_state |=  TIOCM_RTS;
744 			else
745 				priv->control_state &= ~TIOCM_RTS;
746 		}
747 
748 		if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
749 			/* DTR needs set */
750 			if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) ||
751 			    (cmd == TIOCMBIS) )
752 				priv->control_state |=  TIOCM_DTR;
753 			else
754 				priv->control_state &= ~TIOCM_DTR;
755 		}
756 		spin_unlock_irqrestore(&priv->lock, flags);
757 		mct_u232_set_modem_ctrl(serial, priv->control_state);
758 		break;
759 
760 	case TIOCMIWAIT:
761 		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
762 		/* TODO */
763 		return( 0 );
764 
765 	case TIOCGICOUNT:
766 		/* return count of modemline transitions */
767 		/* TODO */
768 		return 0;
769 
770 	default:
771 		dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd);
772 		return(-ENOIOCTLCMD);
773 		break;
774 	}
775 	return 0;
776 } /* mct_u232_ioctl */
777 
778 
mct_u232_init(void)779 static int __init mct_u232_init (void)
780 {
781 	usb_serial_register (&mct_u232_device);
782 	info(DRIVER_DESC " " DRIVER_VERSION);
783 	return 0;
784 }
785 
786 
mct_u232_exit(void)787 static void __exit mct_u232_exit (void)
788 {
789 	usb_serial_deregister (&mct_u232_device);
790 }
791 
792 
793 module_init (mct_u232_init);
794 module_exit(mct_u232_exit);
795 
796 MODULE_AUTHOR( DRIVER_AUTHOR );
797 MODULE_DESCRIPTION( DRIVER_DESC );
798 MODULE_LICENSE("GPL");
799 
800 MODULE_PARM(debug, "i");
801 MODULE_PARM_DESC(debug, "Debug enabled or not");
802