Skip to contentSkip to conversation

USB: serial: ch341: fix initial modem-control state

PATCH New Johan Hovold 1 participant 5 messages Jan 6, 2017 1 message not in the archive

Subsystems (3)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

Johan Hovold

author maintainer
#1 lore raw

PATCH v2 1/14 USB: serial: ch341: fix initial modem-control state

DTR and RTS will be asserted by the tty-layer when the port is opened and deasserted on close (if HUPCL is set). Make sure the initial state is not-asserted before the port is first opened as well.

Fixes 664d5df92e88 ("USB: usb-serial ch341: support for DTR/RTS/CTS")
Cc stable <[email protected]>
---
 drivers/usb/serial/ch341.c | 1 -
 1 file changed, 1 deletion(-)
drivers/usb/serial/ch341.c +0 -1
index 2597b83a8ae2..d133e72fe888 100644
@@ -258,7 +258,6 @@ static int ch341_port_probe(struct usb_serial_port *port)
 
 	spin_lock_init(&priv->lock);
 	priv->baud_rate = DEFAULT_BAUD_RATE;
-	priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
 
 	r = ch341_configure(port->serial->dev, priv);
 	if (r < 0)
Signature · 1 line
2.10.2
author maintainer
#2 lore raw

PATCH v2 2/14 USB: serial: ch341: fix open and resume after B0

In reply to a message not in the archive

The private baud_rate variable is used to configure the port at open and reset-resume and must never be set to (and left at) zero or reset-resume and all further open attempts will fail.

Fixes aa91def41a7b ("USB: ch341: set tty baud speed according to tty

struct")

Fixes 664d5df92e88 ("USB: usb-serial ch341: support for DTR/RTS/CTS")
Cc stable <[email protected]>
---
 drivers/usb/serial/ch341.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/usb/serial/ch341.c +3 -1
index d133e72fe888..6279df905c14 100644
@@ -355,7 +355,6 @@ static void ch341_set_termios(struct tty_struct *tty,
 
 	baud_rate = tty_get_baud_rate(tty);
 
-	priv->baud_rate = baud_rate;
 	ctrl = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX;
 
 	switch (C_CSIZE(tty)) {
@@ -388,6 +387,9 @@ static void ch341_set_termios(struct tty_struct *tty,
 		spin_lock_irqsave(&priv->lock, flags);
 		priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
 		spin_unlock_irqrestore(&priv->lock, flags);
+
+		priv->baud_rate = baud_rate;
+
 		r = ch341_init_set_baudrate(port->serial->dev, priv, ctrl);
 		if (r < 0 && old_termios) {
 			priv->baud_rate = tty_termios_baud_rate(old_termios);
Signature · 1 line
2.10.2
author maintainer
#3 lore raw

PATCH v2 3/14 USB: serial: ch341: fix modem-control and B0 handling

In reply to a message not in the archive

The modem-control signals are managed by the tty-layer during open and should not be asserted prematurely when set_termios is called from driver open.

Also make sure that the signals are asserted only when changing speed from B0.

Fixes 664d5df92e88 ("USB: usb-serial ch341: support for DTR/RTS/CTS")
Cc stable <[email protected]>
---
 drivers/usb/serial/ch341.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)
drivers/usb/serial/ch341.c +7 -9
index 6279df905c14..0cc5056b304d 100644
@@ -384,10 +384,6 @@ static void ch341_set_termios(struct tty_struct *tty,
 		ctrl |= CH341_LCR_STOP_BITS_2;
 
 	if (baud_rate) {
-		spin_lock_irqsave(&priv->lock, flags);
-		priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
-		spin_unlock_irqrestore(&priv->lock, flags);
-
 		priv->baud_rate = baud_rate;
 
 		r = ch341_init_set_baudrate(port->serial->dev, priv, ctrl);
@@ -395,14 +391,16 @@ static void ch341_set_termios(struct tty_struct *tty,
 			priv->baud_rate = tty_termios_baud_rate(old_termios);
 			tty_termios_copy_hw(&tty->termios, old_termios);
 		}
-	} else {
-		spin_lock_irqsave(&priv->lock, flags);
-		priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
-		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 
-	ch341_set_handshake(port->serial->dev, priv->line_control);
+	spin_lock_irqsave(&priv->lock, flags);
+	if (C_BAUD(tty) == B0)
+		priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
+	else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
+		priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
+	spin_unlock_irqrestore(&priv->lock, flags);
 
+	ch341_set_handshake(port->serial->dev, priv->line_control);
 }
 
 static void ch341_break_ctl(struct tty_struct *tty, int break_state)
Signature · 1 line
2.10.2
author maintainer
#4 lore raw

PATCH v2 4/14 USB: serial: ch341: fix open error handling

In reply to a message not in the archive

Make sure to stop the interrupt URB before returning on errors during open.

Fixes 664d5df92e88 ("USB: usb-serial ch341: support for DTR/RTS/CTS")
Cc stable <[email protected]>
---
 drivers/usb/serial/ch341.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/usb/serial/ch341.c +10 -3
index 0cc5056b304d..8f41d4385f1c 100644
@@ -319,7 +319,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
 
 	r = ch341_configure(serial->dev, priv);
 	if (r)
-		goto out;
+		return r;
 
 	if (tty)
 		ch341_set_termios(tty, port, NULL);
@@ -329,12 +329,19 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
 	if (r) {
 		dev_err(&port->dev, "%s - failed to submit interrupt urb: %d\n",
 			__func__, r);
-		goto out;
+		return r;
 	}
 
 	r = usb_serial_generic_open(tty, port);
+	if (r)
+		goto err_kill_interrupt_urb;
+
+	return 0;
+
+err_kill_interrupt_urb:
+	usb_kill_urb(port->interrupt_in_urb);
 
-out:	return r;
+	return r;
 }
 
 /* Old_termios contains the original termios settings and
Signature · 1 line
2.10.2
author maintainer
#5 lore raw

PATCH v2 5/14 USB: serial: ch341: fix resume after reset

In reply to a message not in the archive

Fix reset-resume handling which failed to resubmit the read and interrupt URBs, thereby leaving a port that was open before suspend in a broken state until closed and reopened.

Fixes 1ded7ea47b88 ("USB: ch341 serial: fix port number changed after

resume")

Fixes 2bfd1c96a9fb ("USB: serial: ch341: remove reset_resume callback")
Cc stable <[email protected]>
---
 drivers/usb/serial/ch341.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)
drivers/usb/serial/ch341.c +13 -4
index 8f41d4385f1c..5343d65f3b52 100644
@@ -582,14 +582,23 @@ static int ch341_tiocmget(struct tty_struct *tty)
 
 static int ch341_reset_resume(struct usb_serial *serial)
 {
-	struct ch341_private *priv;
-
-	priv = usb_get_serial_port_data(serial->port[0]);
+	struct usb_serial_port *port = serial->port[0];
+	struct ch341_private *priv = usb_get_serial_port_data(port);
+	int ret;
 
 	/* reconfigure ch341 serial port after bus-reset */
 	ch341_configure(serial->dev, priv);
 
-	return 0;
+	if (tty_port_initialized(&port->port)) {
+		ret = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
+		if (ret) {
+			dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	return usb_serial_generic_resume(serial);
 }
 
 static struct usb_serial_driver ch341_device = {
Signature · 1 line
2.10.2