Re: [RFC/RFT PATCH] pl2303: avoid data corruption with some chip types

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Am 01.11.2013 13:19, schrieb Mika Westerberg:
> On Fri, Nov 01, 2013 at 12:49:22PM +0100, Frank Schäfer wrote:
>> Some PL2303 chips are reported to lose bytes if the serial settings are set to
>> the same values as before.
>> At least HXD chips are affected, HX chips seem to be ok.
>> The current code tries to avoid this by calling tty_termios_hw_change(), but
>> this check isn't sufficient because different requested baud rates can result
>> in identic encoded baud rates.
>> The solution is to save and compare the encoded settings instead.
> I tried this on top of rc7 and I can still see data get corrupted (both
> 115200 and 460800 bps).
Ok... Ready for the next round ? ;)
Attached are two further experimental patches.

Regards,
Frank
>From 95a3f0e0751dad4ae39fdd7a915a2fa22997a540 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Frank=20Sch=C3=A4fer?= <fschaefer.oss@xxxxxxxxxxxxxx>
Date: Fri, 1 Nov 2013 13:56:53 +0100
Subject: [PATCH] EXPERIMENTAL PATCH 1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Frank Schäfer <fschaefer.oss@xxxxxxxxxxxxxx>
---
 drivers/usb/serial/pl2303.c |   30 ++++++++++++++++++------------
 1 Datei geändert, 18 Zeilen hinzugefügt(+), 12 Zeilen entfernt(-)

diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index bedf8e4..8496eef 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -496,20 +496,13 @@ static void pl2303_set_termios(struct tty_struct *tty,
 	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
 	struct pl2303_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
-	unsigned char *buf;
+	unsigned char *buf, *buf_old;
 	int i;
 	u8 control;
 
-	/*
-	 * The PL2303 is reported to lose bytes if you change serial settings
-	 * even to the same values as before. Thus we actually need to filter
-	 * in this specific case.
-	 */
-	if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
-		return;
-
 	buf = kzalloc(7, GFP_KERNEL);
-	if (!buf) {
+	buf_old = kzalloc(7, GFP_KERNEL);
+	if (!buf || buf_old) {
 		dev_err(&port->dev, "%s - out of memory.\n", __func__);
 		/* Report back no change occurred */
 		if (old_termios)
@@ -519,8 +512,8 @@ static void pl2303_set_termios(struct tty_struct *tty,
 
 	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
-			    0, 0, buf, 7, 100);
-	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf);
+			    0, 0, buf_old, 7, 100);
+	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf_old);
 
 	if (C_CSIZE(tty)) {
 		switch (C_CSIZE(tty)) {
@@ -591,6 +584,17 @@ static void pl2303_set_termios(struct tty_struct *tty,
 		dev_dbg(&port->dev, "parity = none\n");
 	}
 
+	/*
+	 * Some PL2303 chips are reported to lose bytes if you change the
+	 * serial settings even to the same values as before.
+	 * At least HXD chips are affected, HX chips seem to be ok.
+	 * Thus we actually need to filter in this specific case.
+	 * NOTE: a tty_termios_hw_change() check isn't sufficient, because
+	 * different baud rates can result in identic encoded values.
+	 */
+	if (!memcmp(buf, buf_old, 7))
+		goto out;
+
 	i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			    SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
 			    0, 0, buf, 7, 100);
@@ -626,7 +630,9 @@ static void pl2303_set_termios(struct tty_struct *tty,
 		pl2303_vendor_write(0x0, 0x0, serial);
 	}
 
+out:
 	kfree(buf);
+	kfree(buf_old);
 }
 
 static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
-- 
1.7.10.4

>From d303ff67ab1b817bf75b32eaa276369039ee4af2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Frank=20Sch=C3=A4fer?= <fschaefer.oss@xxxxxxxxxxxxxx>
Date: Fri, 1 Nov 2013 13:59:58 +0100
Subject: [PATCH] EXPERIMENTAL PATCH 2
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Frank Schäfer <fschaefer.oss@xxxxxxxxxxxxxx>
---
 drivers/usb/serial/pl2303.c |   29 ++++++++++++++++-------------
 1 Datei geändert, 16 Zeilen hinzugefügt(+), 13 Zeilen entfernt(-)

diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index bedf8e4..b0d3d66 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -155,6 +155,7 @@ struct pl2303_private {
 	spinlock_t lock;
 	u8 line_control;
 	u8 line_status;
+	u8 line_settings_enc[7]; /* baud rate, data bits, stop bits, parity */
 };
 
 static int pl2303_vendor_read(__u16 value, __u16 index,
@@ -500,14 +501,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
 	int i;
 	u8 control;
 
-	/*
-	 * The PL2303 is reported to lose bytes if you change serial settings
-	 * even to the same values as before. Thus we actually need to filter
-	 * in this specific case.
-	 */
-	if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
-		return;
-
 	buf = kzalloc(7, GFP_KERNEL);
 	if (!buf) {
 		dev_err(&port->dev, "%s - out of memory.\n", __func__);
@@ -517,11 +510,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
 		return;
 	}
 
-	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
-			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
-			    0, 0, buf, 7, 100);
-	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf);
-
 	if (C_CSIZE(tty)) {
 		switch (C_CSIZE(tty)) {
 		case CS5:
@@ -591,10 +579,25 @@ static void pl2303_set_termios(struct tty_struct *tty,
 		dev_dbg(&port->dev, "parity = none\n");
 	}
 
+	/*
+	 * Some PL2303 chips are reported to lose bytes if you change the
+	 * serial settings even to the same values as before.
+	 * At least HXD chips are affected, HX chips seem to be ok.
+	 * Thus we actually need to filter in this specific case.
+	 * NOTE: a tty_termios_hw_change() check isn't sufficient, because
+	 * different baud rates can result in identic encoded values.
+	 */
+	if (!memcmp(priv->line_settings_enc, buf, 7)) {
+		kfree(buf);
+		return;
+	}
+
 	i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			    SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
 			    0, 0, buf, 7, 100);
 	dev_dbg(&port->dev, "0x21:0x20:0:0  %d\n", i);
+	if (i == 7)
+		memcpy(buf, priv->line_settings_enc, 7);
 
 	/* change control lines if we are switching to or from B0 */
 	spin_lock_irqsave(&priv->lock, flags);
-- 
1.7.10.4


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux