aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/pl2303.c
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2013-12-29 13:22:53 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-03 15:31:46 -0500
commit623c8263376c0b8a4b0c220232e7313d762cd0cc (patch)
treeca59cfc957ff24d174401c32d12ece3701bf01d1 /drivers/usb/serial/pl2303.c
parent73ad0adcb69d6a895ff73855ab366a7ae0b2fb0b (diff)
USB: pl2303: fix data corruption on termios updates
Some PL2303 devices are known to lose bytes if you change serial settings even to the same values as before. Avoid this by comparing the encoded settings with the previsouly used ones before configuring the device. The common case was fixed by commit bf5e5834bffc6 ("pl2303: Fix mode switching regression"), but this problem was still possible to trigger, for instance, by using the TCSETS2-interface to repeatedly request 115201 baud, which gets mapped to 115200 and thus always triggers a settings update. Cc: Frank Schäfer <fschaefer.oss@googlemail.com> Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/serial/pl2303.c')
-rw-r--r--drivers/usb/serial/pl2303.c34
1 files changed, 25 insertions, 9 deletions
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 1e3318dfa1cb..beb8edce4ef2 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -142,6 +142,8 @@ struct pl2303_private {
142 spinlock_t lock; 142 spinlock_t lock;
143 u8 line_control; 143 u8 line_control;
144 u8 line_status; 144 u8 line_status;
145
146 u8 line_settings[7];
145}; 147};
146 148
147static int pl2303_vendor_read(__u16 value, __u16 index, 149static int pl2303_vendor_read(__u16 value, __u16 index,
@@ -339,11 +341,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
339 int i; 341 int i;
340 u8 control; 342 u8 control;
341 343
342 /*
343 * The PL2303 is reported to lose bytes if you change serial settings
344 * even to the same values as before. Thus we actually need to filter
345 * in this specific case.
346 */
347 if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) 344 if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
348 return; 345 return;
349 346
@@ -428,10 +425,29 @@ static void pl2303_set_termios(struct tty_struct *tty,
428 dev_dbg(&port->dev, "parity = none\n"); 425 dev_dbg(&port->dev, "parity = none\n");
429 } 426 }
430 427
431 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 428 /*
432 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 429 * Some PL2303 are known to lose bytes if you change serial settings
433 0, 0, buf, 7, 100); 430 * even to the same values as before. Thus we actually need to filter
434 dev_dbg(&port->dev, "0x21:0x20:0:0 %d\n", i); 431 * in this specific case.
432 *
433 * Note that the tty_termios_hw_change check above is not sufficient
434 * as a previously requested baud rate may differ from the one
435 * actually used (and stored in old_termios).
436 *
437 * NOTE: No additional locking needed for line_settings as it is
438 * only used in set_termios, which is serialised against itself.
439 */
440 if (!old_termios || memcmp(buf, priv->line_settings, 7)) {
441 i = usb_control_msg(serial->dev,
442 usb_sndctrlpipe(serial->dev, 0),
443 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
444 0, 0, buf, 7, 100);
445
446 dev_dbg(&port->dev, "0x21:0x20:0:0 %d\n", i);
447
448 if (i == 7)
449 memcpy(priv->line_settings, buf, 7);
450 }
435 451
436 /* change control lines if we are switching to or from B0 */ 452 /* change control lines if we are switching to or from B0 */
437 spin_lock_irqsave(&priv->lock, flags); 453 spin_lock_irqsave(&priv->lock, flags);