aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/mct_u232.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/mct_u232.c')
-rw-r--r--drivers/usb/serial/mct_u232.c149
1 files changed, 108 insertions, 41 deletions
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 3db1adc25f84..2a3fabcf5186 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);
@@ -476,10 +516,11 @@ static void mct_u232_read_int_callback (struct urb *urb)
476 struct usb_serial *serial = port->serial; 516 struct usb_serial *serial = port->serial;
477 struct tty_struct *tty; 517 struct tty_struct *tty;
478 unsigned char *data = urb->transfer_buffer; 518 unsigned char *data = urb->transfer_buffer;
479 int status; 519 int retval;
520 int status = urb->status;
480 unsigned long flags; 521 unsigned long flags;
481 522
482 switch (urb->status) { 523 switch (status) {
483 case 0: 524 case 0:
484 /* success */ 525 /* success */
485 break; 526 break;
@@ -487,10 +528,12 @@ static void mct_u232_read_int_callback (struct urb *urb)
487 case -ENOENT: 528 case -ENOENT:
488 case -ESHUTDOWN: 529 case -ESHUTDOWN:
489 /* this urb is terminated, clean up */ 530 /* this urb is terminated, clean up */
490 dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); 531 dbg("%s - urb shutting down with status: %d",
532 __FUNCTION__, status);
491 return; 533 return;
492 default: 534 default:
493 dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); 535 dbg("%s - nonzero urb status received: %d",
536 __FUNCTION__, status);
494 goto exit; 537 goto exit;
495 } 538 }
496 539
@@ -554,10 +597,10 @@ static void mct_u232_read_int_callback (struct urb *urb)
554#endif 597#endif
555 spin_unlock_irqrestore(&priv->lock, flags); 598 spin_unlock_irqrestore(&priv->lock, flags);
556exit: 599exit:
557 status = usb_submit_urb (urb, GFP_ATOMIC); 600 retval = usb_submit_urb (urb, GFP_ATOMIC);
558 if (status) 601 if (retval)
559 err ("%s - usb_submit_urb failed with result %d", 602 err ("%s - usb_submit_urb failed with result %d",
560 __FUNCTION__, status); 603 __FUNCTION__, retval);
561} /* mct_u232_read_int_callback */ 604} /* mct_u232_read_int_callback */
562 605
563static void mct_u232_set_termios (struct usb_serial_port *port, 606static void mct_u232_set_termios (struct usb_serial_port *port,
@@ -565,11 +608,10 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
565{ 608{
566 struct usb_serial *serial = port->serial; 609 struct usb_serial *serial = port->serial;
567 struct mct_u232_private *priv = usb_get_serial_port_data(port); 610 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; 611 unsigned int cflag = port->tty->termios->c_cflag;
570 unsigned int old_cflag = old_termios->c_cflag; 612 unsigned int old_cflag = old_termios->c_cflag;
571 unsigned long flags; 613 unsigned long flags;
572 unsigned int control_state, new_state; 614 unsigned int control_state;
573 unsigned char last_lcr; 615 unsigned char last_lcr;
574 616
575 /* get a local copy of the current port settings */ 617 /* get a local copy of the current port settings */
@@ -585,18 +627,14 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
585 * Premature optimization is the root of all evil. 627 * Premature optimization is the root of all evil.
586 */ 628 */
587 629
588 /* reassert DTR and (maybe) RTS on transition from B0 */ 630 /* reassert DTR and RTS on transition from B0 */
589 if ((old_cflag & CBAUD) == B0) { 631 if ((old_cflag & CBAUD) == B0) {
590 dbg("%s: baud was B0", __FUNCTION__); 632 dbg("%s: baud was B0", __FUNCTION__);
591 control_state |= TIOCM_DTR; 633 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); 634 mct_u232_set_modem_ctrl(serial, control_state);
597 } 635 }
598 636
599 mct_u232_set_baud_rate(serial, cflag & CBAUD); 637 mct_u232_set_baud_rate(serial, port, cflag & CBAUD);
600 638
601 if ((cflag & CBAUD) == B0 ) { 639 if ((cflag & CBAUD) == B0 ) {
602 dbg("%s: baud is B0", __FUNCTION__); 640 dbg("%s: baud is B0", __FUNCTION__);
@@ -638,21 +676,6 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
638 676
639 mct_u232_set_line_ctrl(serial, last_lcr); 677 mct_u232_set_line_ctrl(serial, last_lcr);
640 678
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 */ 679 /* save off the modified port settings */
657 spin_lock_irqsave(&priv->lock, flags); 680 spin_lock_irqsave(&priv->lock, flags);
658 priv->control_state = control_state; 681 priv->control_state = control_state;
@@ -747,6 +770,50 @@ static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
747 return 0; 770 return 0;
748} /* mct_u232_ioctl */ 771} /* mct_u232_ioctl */
749 772
773static void mct_u232_throttle (struct usb_serial_port *port)
774{
775 struct mct_u232_private *priv = usb_get_serial_port_data(port);
776 unsigned long flags;
777 unsigned int control_state;
778 struct tty_struct *tty;
779
780 tty = port->tty;
781 dbg("%s - port %d", __FUNCTION__, port->number);
782
783 spin_lock_irqsave(&priv->lock, flags);
784 priv->rx_flags |= THROTTLED;
785 if (C_CRTSCTS(tty)) {
786 priv->control_state &= ~TIOCM_RTS;
787 control_state = priv->control_state;
788 spin_unlock_irqrestore(&priv->lock, flags);
789 (void) mct_u232_set_modem_ctrl(port->serial, control_state);
790 } else {
791 spin_unlock_irqrestore(&priv->lock, flags);
792 }
793}
794
795
796static void mct_u232_unthrottle (struct usb_serial_port *port)
797{
798 struct mct_u232_private *priv = usb_get_serial_port_data(port);
799 unsigned long flags;
800 unsigned int control_state;
801 struct tty_struct *tty;
802
803 dbg("%s - port %d", __FUNCTION__, port->number);
804
805 tty = port->tty;
806 spin_lock_irqsave(&priv->lock, flags);
807 if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
808 priv->rx_flags &= ~THROTTLED;
809 priv->control_state |= TIOCM_RTS;
810 control_state = priv->control_state;
811 spin_unlock_irqrestore(&priv->lock, flags);
812 (void) mct_u232_set_modem_ctrl(port->serial, control_state);
813 } else {
814 spin_unlock_irqrestore(&priv->lock, flags);
815 }
816}
750 817
751static int __init mct_u232_init (void) 818static int __init mct_u232_init (void)
752{ 819{