
http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/?id=552f6bf1bb0eda0011c0525dd587aa9e7ba5b846


From 552f6bf1bb0eda0011c0525dd587aa9e7ba5b846 Mon Sep 17 00:00:00 2001
From: Andrew Worsley <amworsley@gmail.com>
Date: Fri, 18 Nov 2011 12:13:33 +0000
Subject: USB: Fix Corruption issue in USB ftdi driver ftdi_sio.c

commit b1ffb4c851f185e9051ba837c16d9b84ef688d26 upstream.

Fix for ftdi_set_termios() glitching output

ftdi_set_termios() is constantly setting the baud rate, data bits and parity
unnecessarily on every call, . When called while characters are being
transmitted can cause the FTDI chip to corrupt the serial port bit stream
output by stalling the output half a bit during the output of a character.
Simple fix by skipping this setting if the baud rate/data bits/parity are
unchanged.

Signed-off-by: Andrew Worsley <amworsley@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
--- linux-2.6.28/drivers/usb/serial/ftdi_sio.c
+++ linux-2.6.28/drivers/usb/serial/ftdi_sio.c
@@ -2197,13 +2197,19 @@
 
 	cflag = termios->c_cflag;
 
-	/* FIXME -For this cut I don't care if the line is really changing or
-	   not  - so just do the change regardless  - should be able to
-	   compare old_termios and tty->termios */
+	if (old_termios->c_cflag == termios->c_cflag
+		&& old_termios->c_ispeed == termios->c_ispeed
+		&& old_termios->c_ospeed == termios->c_ospeed)
+			goto no_c_cflag_changes;
+
 	/* NOTE These routines can get interrupted by
 	   ftdi_sio_read_bulk_callback  - need to examine what this means -
 	   don't see any problems yet */
 
+	if ((old_termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)) ==
+		(termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)))
+			goto no_data_parity_stop_changes;
+
 	/* Set number of data bits, parity, stop bits */
 
 	termios->c_cflag &= ~CMSPAR;
@@ -2240,6 +2246,7 @@
 	}
 
 	/* Now do the baudrate */
+no_data_parity_stop_changes:
 	if ((cflag & CBAUD) == B0) {
 		/* Disable flow control */
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@@ -2265,6 +2272,7 @@
 
 	/* Set flow control */
 	/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
+no_c_cflag_changes:
 	if (cflag & CRTSCTS) {
 		dbg("%s Setting to CRTSCTS flow control", __func__);
 		if (usb_control_msg(dev,
