aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/mct_u232.c
diff options
context:
space:
mode:
authorDave Platt <dplatt@radagast.org>2007-05-08 14:00:12 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-12 19:29:48 -0400
commit45b844df5a4b17884b4e26e43bfc4802604e7cab (patch)
tree624c48e4fc481cac8f16a2d00dce56e22f06a541 /drivers/usb/serial/mct_u232.c
parent01cd08192040eab30f837f061ca07f43cf15f4a1 (diff)
USB: RTS/CTS handshaking support, DTR fixes for MCT U232 serial adapter
Improvements and fixes to the MCT U232 USB/serial interface driver. Implement RTS/CTS hardware flow control. Implement HUPCL. Bring handling of DTR and RTS into conformance with other Linux serial port drivers - assert both signals when opening device, even if "crtscts" is not currently selected. Signed-off-by: Dave Platt <dplatt@radagast.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/mct_u232.c')
-rw-r--r--drivers/usb/serial/mct_u232.c132
1 files changed, 98 insertions, 34 deletions
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 3db1adc25f84..204f0f928f6c 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -81,7 +81,7 @@
81/* 81/*
82 * Version Information 82 * Version Information
83 */ 83 */
84#define DRIVER_VERSION "z2.0" /* Linux in-kernel version */ 84#define DRIVER_VERSION "z2.1" /* Linux in-kernel version */
85#define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>" 85#define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
86#define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver" 86#define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
87 87
@@ -110,6 +110,10 @@ static int mct_u232_tiocmget (struct usb_serial_port *port,
110static int mct_u232_tiocmset (struct usb_serial_port *port, 110static int mct_u232_tiocmset (struct usb_serial_port *port,
111 struct file *file, unsigned int set, 111 struct file *file, unsigned int set,
112 unsigned int clear); 112 unsigned int clear);
113static void mct_u232_throttle (struct usb_serial_port *port);
114static void mct_u232_unthrottle (struct usb_serial_port *port);
115
116
113/* 117/*
114 * All of the device info needed for the MCT USB-RS232 converter. 118 * All of the device info needed for the MCT USB-RS232 converter.
115 */ 119 */
@@ -145,6 +149,8 @@ static struct usb_serial_driver mct_u232_device = {
145 .num_ports = 1, 149 .num_ports = 1,
146 .open = mct_u232_open, 150 .open = mct_u232_open,
147 .close = mct_u232_close, 151 .close = mct_u232_close,
152 .throttle = mct_u232_throttle,
153 .unthrottle = mct_u232_unthrottle,
148 .read_int_callback = mct_u232_read_int_callback, 154 .read_int_callback = mct_u232_read_int_callback,
149 .ioctl = mct_u232_ioctl, 155 .ioctl = mct_u232_ioctl,
150 .set_termios = mct_u232_set_termios, 156 .set_termios = mct_u232_set_termios,
@@ -162,8 +168,11 @@ struct mct_u232_private {
162 unsigned char last_lcr; /* Line Control Register */ 168 unsigned char last_lcr; /* Line Control Register */
163 unsigned char last_lsr; /* Line Status Register */ 169 unsigned char last_lsr; /* Line Status Register */
164 unsigned char last_msr; /* Modem Status Register */ 170 unsigned char last_msr; /* Modem Status Register */
171 unsigned int rx_flags; /* Throttling flags */
165}; 172};
166 173
174#define THROTTLED 0x01
175
167/* 176/*
168 * Handle vendor specific USB requests 177 * Handle vendor specific USB requests
169 */ 178 */
@@ -216,11 +225,13 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value)
216 } 225 }
217} 226}
218 227
219static int mct_u232_set_baud_rate(struct usb_serial *serial, int value) 228static int mct_u232_set_baud_rate(struct usb_serial *serial, struct usb_serial_port *port,
229 int value)
220{ 230{
221 __le32 divisor; 231 __le32 divisor;
222 int rc; 232 int rc;
223 unsigned char zero_byte = 0; 233 unsigned char zero_byte = 0;
234 unsigned char cts_enable_byte = 0;
224 235
225 divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value)); 236 divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value));
226 237
@@ -238,10 +249,17 @@ static int mct_u232_set_baud_rate(struct usb_serial *serial, int value)
238 'baud rate change' message. The actual functionality of the 249 'baud rate change' message. The actual functionality of the
239 request codes in these messages is not fully understood but these 250 request codes in these messages is not fully understood but these
240 particular codes are never seen in any operation besides a baud 251 particular codes are never seen in any operation besides a baud
241 rate change. Both of these messages send a single byte of data 252 rate change. Both of these messages send a single byte of data.
242 whose value is always zero. The second of these two extra messages 253 In the first message, the value of this byte is always zero.
243 is required in order for data to be properly written to an RS-232 254
244 device which does not assert the 'CTS' signal. */ 255 The second message has been determined experimentally to control
256 whether data will be transmitted to a device which is not asserting
257 the 'CTS' signal. If the second message's data byte is zero, data
258 will be transmitted even if 'CTS' is not asserted (i.e. no hardware
259 flow control). if the second message's data byte is nonzero (a value
260 of 1 is used by this driver), data will not be transmitted to a device
261 which is not asserting 'CTS'.
262 */
245 263
246 rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 264 rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
247 MCT_U232_SET_UNKNOWN1_REQUEST, 265 MCT_U232_SET_UNKNOWN1_REQUEST,
@@ -252,14 +270,19 @@ static int mct_u232_set_baud_rate(struct usb_serial *serial, int value)
252 err("Sending USB device request code %d failed (error = %d)", 270 err("Sending USB device request code %d failed (error = %d)",
253 MCT_U232_SET_UNKNOWN1_REQUEST, rc); 271 MCT_U232_SET_UNKNOWN1_REQUEST, rc);
254 272
273 if (port && C_CRTSCTS(port->tty)) {
274 cts_enable_byte = 1;
275 }
276
277 dbg("set_baud_rate: send second control message, data = %02X", cts_enable_byte);
255 rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 278 rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
256 MCT_U232_SET_UNKNOWN2_REQUEST, 279 MCT_U232_SET_CTS_REQUEST,
257 MCT_U232_SET_REQUEST_TYPE, 280 MCT_U232_SET_REQUEST_TYPE,
258 0, 0, &zero_byte, MCT_U232_SET_UNKNOWN2_SIZE, 281 0, 0, &cts_enable_byte, MCT_U232_SET_CTS_SIZE,
259 WDR_TIMEOUT); 282 WDR_TIMEOUT);
260 if (rc < 0) 283 if (rc < 0)
261 err("Sending USB device request code %d failed (error = %d)", 284 err("Sending USB device request code %d failed (error = %d)",
262 MCT_U232_SET_UNKNOWN2_REQUEST, rc); 285 MCT_U232_SET_CTS_REQUEST, rc);
263 286
264 return rc; 287 return rc;
265} /* mct_u232_set_baud_rate */ 288} /* mct_u232_set_baud_rate */
@@ -458,8 +481,25 @@ error:
458 481
459static void mct_u232_close (struct usb_serial_port *port, struct file *filp) 482static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
460{ 483{
484 unsigned int c_cflag;
485 unsigned long flags;
486 unsigned int control_state;
487 struct mct_u232_private *priv = usb_get_serial_port_data(port);
461 dbg("%s port %d", __FUNCTION__, port->number); 488 dbg("%s port %d", __FUNCTION__, port->number);
462 489
490 if (port->tty) {
491 c_cflag = port->tty->termios->c_cflag;
492 if (c_cflag & HUPCL) {
493 /* drop DTR and RTS */
494 spin_lock_irqsave(&priv->lock, flags);
495 priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
496 control_state = priv->control_state;
497 spin_unlock_irqrestore(&priv->lock, flags);
498 mct_u232_set_modem_ctrl(port->serial, control_state);
499 }
500 }
501
502
463 if (port->serial->dev) { 503 if (port->serial->dev) {
464 /* shutdown our urbs */ 504 /* shutdown our urbs */
465 usb_kill_urb(port->write_urb); 505 usb_kill_urb(port->write_urb);
@@ -565,11 +605,10 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
565{ 605{
566 struct usb_serial *serial = port->serial; 606 struct usb_serial *serial = port->serial;
567 struct mct_u232_private *priv = usb_get_serial_port_data(port); 607 struct mct_u232_private *priv = usb_get_serial_port_data(port);
568 unsigned int iflag = port->tty->termios->c_iflag;
569 unsigned int cflag = port->tty->termios->c_cflag; 608 unsigned int cflag = port->tty->termios->c_cflag;
570 unsigned int old_cflag = old_termios->c_cflag; 609 unsigned int old_cflag = old_termios->c_cflag;
571 unsigned long flags; 610 unsigned long flags;
572 unsigned int control_state, new_state; 611 unsigned int control_state;
573 unsigned char last_lcr; 612 unsigned char last_lcr;
574 613
575 /* get a local copy of the current port settings */ 614 /* get a local copy of the current port settings */
@@ -585,18 +624,14 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
585 * Premature optimization is the root of all evil. 624 * Premature optimization is the root of all evil.
586 */ 625 */
587 626
588 /* reassert DTR and (maybe) RTS on transition from B0 */ 627 /* reassert DTR and RTS on transition from B0 */
589 if ((old_cflag & CBAUD) == B0) { 628 if ((old_cflag & CBAUD) == B0) {
590 dbg("%s: baud was B0", __FUNCTION__); 629 dbg("%s: baud was B0", __FUNCTION__);
591 control_state |= TIOCM_DTR; 630 control_state |= TIOCM_DTR | TIOCM_RTS;
592 /* don't set RTS if using hardware flow control */
593 if (!(old_cflag & CRTSCTS)) {
594 control_state |= TIOCM_RTS;
595 }
596 mct_u232_set_modem_ctrl(serial, control_state); 631 mct_u232_set_modem_ctrl(serial, control_state);
597 } 632 }
598 633
599 mct_u232_set_baud_rate(serial, cflag & CBAUD); 634 mct_u232_set_baud_rate(serial, port, cflag & CBAUD);
600 635
601 if ((cflag & CBAUD) == B0 ) { 636 if ((cflag & CBAUD) == B0 ) {
602 dbg("%s: baud is B0", __FUNCTION__); 637 dbg("%s: baud is B0", __FUNCTION__);
@@ -638,21 +673,6 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
638 673
639 mct_u232_set_line_ctrl(serial, last_lcr); 674 mct_u232_set_line_ctrl(serial, last_lcr);
640 675
641 /*
642 * Set flow control: well, I do not really now how to handle DTR/RTS.
643 * Just do what we have seen with SniffUSB on Win98.
644 */
645 /* Drop DTR/RTS if no flow control otherwise assert */
646 new_state = control_state;
647 if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
648 new_state |= TIOCM_DTR | TIOCM_RTS;
649 else
650 new_state &= ~(TIOCM_DTR | TIOCM_RTS);
651 if (new_state != control_state) {
652 mct_u232_set_modem_ctrl(serial, new_state);
653 control_state = new_state;
654 }
655
656 /* save off the modified port settings */ 676 /* save off the modified port settings */
657 spin_lock_irqsave(&priv->lock, flags); 677 spin_lock_irqsave(&priv->lock, flags);
658 priv->control_state = control_state; 678 priv->control_state = control_state;
@@ -747,6 +767,50 @@ static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
747 return 0; 767 return 0;
748} /* mct_u232_ioctl */ 768} /* mct_u232_ioctl */
749 769
770static void mct_u232_throttle (struct usb_serial_port *port)
771{
772 struct mct_u232_private *priv = usb_get_serial_port_data(port);
773 unsigned long flags;
774 unsigned int control_state;
775 struct tty_struct *tty;
776
777 tty = port->tty;
778 dbg("%s - port %d", __FUNCTION__, port->number);
779
780 spin_lock_irqsave(&priv->lock, flags);
781 priv->rx_flags |= THROTTLED;
782 if (C_CRTSCTS(tty)) {
783 priv->control_state &= ~TIOCM_RTS;
784 control_state = priv->control_state;
785 spin_unlock_irqrestore(&priv->lock, flags);
786 (void) mct_u232_set_modem_ctrl(port->serial, control_state);
787 } else {
788 spin_unlock_irqrestore(&priv->lock, flags);
789 }
790}
791
792
793static void mct_u232_unthrottle (struct usb_serial_port *port)
794{
795 struct mct_u232_private *priv = usb_get_serial_port_data(port);
796 unsigned long flags;
797 unsigned int control_state;
798 struct tty_struct *tty;
799
800 dbg("%s - port %d", __FUNCTION__, port->number);
801
802 tty = port->tty;
803 spin_lock_irqsave(&priv->lock, flags);
804 if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
805 priv->rx_flags &= ~THROTTLED;
806 priv->control_state |= TIOCM_RTS;
807 control_state = priv->control_state;
808 spin_unlock_irqrestore(&priv->lock, flags);
809 (void) mct_u232_set_modem_ctrl(port->serial, control_state);
810 } else {
811 spin_unlock_irqrestore(&priv->lock, flags);
812 }
813}
750 814
751static int __init mct_u232_init (void) 815static int __init mct_u232_init (void)
752{ 816{