linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] USB: serial: cp210x: modem-control fixes
@ 2021-01-25 13:48 Johan Hovold
  2021-01-25 13:48 ` [PATCH 1/7] USB: serial: cp210x: suppress modem-control errors Johan Hovold
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Johan Hovold @ 2021-01-25 13:48 UTC (permalink / raw)
  To: linux-usb; +Cc: Pho Tran, linux-kernel, Johan Hovold

This series fixes the modem-control handling and its interaction with
hardware flow control in the cp210x driver.

Johan

Johan Hovold (7):
  USB: serial: cp210x: suppress modem-control errors
  USB: serial: cp210x: fix modem-control handling
  USB: serial: cp210x: drop shift macros
  USB: serial: cp210x: clean up flow-control debug message
  USB: serial: cp210x: clean up printk zero padding
  USB: serial: cp210x: fix RTS handling
  USB: serial: cp210x: clean up auto-RTS handling

 drivers/usb/serial/cp210x.c | 113 ++++++++++++++++++++++++++++--------
 1 file changed, 89 insertions(+), 24 deletions(-)

-- 
2.26.2


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/7] USB: serial: cp210x: suppress modem-control errors
  2021-01-25 13:48 [PATCH 0/7] USB: serial: cp210x: modem-control fixes Johan Hovold
@ 2021-01-25 13:48 ` Johan Hovold
  2021-01-25 13:48 ` [PATCH 2/7] USB: serial: cp210x: fix modem-control handling Johan Hovold
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2021-01-25 13:48 UTC (permalink / raw)
  To: linux-usb; +Cc: Pho Tran, linux-kernel, Johan Hovold, Pho Tran

The CP210X_SET_MHS request cannot be used to control RTS when hardware
flow control (auto-RTS) is enabled and instead returns an error which is
currently logged as:

	cp210x ttyUSB0: failed set request 0x7 status: -32

when opening and closing a port (and on TIOCMSET requests).

Add a crtscts flag to keep track of the hardware flow-control setting
and use it to suppress any request to change RTS when auto-RTS is
enabled.

Note that RTS is still deasserted when disabling the UART as part of
close.

Reported-by: Pho Tran <pho.tran@silabs.com>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/usb/serial/cp210x.c | 33 ++++++++++++++++++++++++++++++---
 1 file changed, 30 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index d813a052738f..7e4a09b42c99 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -21,6 +21,7 @@
 #include <linux/usb/serial.h>
 #include <linux/gpio/driver.h>
 #include <linux/bitops.h>
+#include <linux/mutex.h>
 
 #define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver"
 
@@ -264,7 +265,10 @@ struct cp210x_port_private {
 	u8			bInterfaceNumber;
 	bool			event_mode;
 	enum cp210x_event_state event_state;
-	u8 lsr;
+	u8			lsr;
+
+	struct mutex		mutex;
+	bool			crtscts;
 };
 
 static struct usb_serial_driver cp210x_device = {
@@ -1117,6 +1121,7 @@ static bool cp210x_termios_change(const struct ktermios *a, const struct ktermio
 static void cp210x_set_flow_control(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios)
 {
+	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
 	struct cp210x_special_chars chars;
 	struct cp210x_flow_ctl flow_ctl;
 	u32 flow_repl;
@@ -1143,10 +1148,12 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
 			return;
 	}
 
+	mutex_lock(&port_priv->mutex);
+
 	ret = cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
 			sizeof(flow_ctl));
 	if (ret)
-		return;
+		goto out_unlock;
 
 	ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
 	flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);
@@ -1161,10 +1168,12 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
 		ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
 		flow_repl &= ~CP210X_SERIAL_RTS_MASK;
 		flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_FLOW_CTL);
+		port_priv->crtscts = true;
 	} else {
 		ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
 		flow_repl &= ~CP210X_SERIAL_RTS_MASK;
 		flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_ACTIVE);
+		port_priv->crtscts = false;
 	}
 
 	if (I_IXOFF(tty))
@@ -1188,6 +1197,8 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
 
 	cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl,
 			sizeof(flow_ctl));
+out_unlock:
+	mutex_unlock(&port_priv->mutex);
 }
 
 static void cp210x_set_termios(struct tty_struct *tty,
@@ -1272,7 +1283,9 @@ static int cp210x_tiocmset(struct tty_struct *tty,
 static int cp210x_tiocmset_port(struct usb_serial_port *port,
 		unsigned int set, unsigned int clear)
 {
+	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
 	u16 control = 0;
+	int ret;
 
 	if (set & TIOCM_RTS) {
 		control |= CONTROL_RTS;
@@ -1291,9 +1304,22 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port,
 		control |= CONTROL_WRITE_DTR;
 	}
 
+	mutex_lock(&port_priv->mutex);
+
+	/*
+	 * SET_MHS cannot be used to control RTS when auto-RTS is enabled.
+	 * Note that RTS is still deasserted when disabling the UART on close.
+	 */
+	if (port_priv->crtscts)
+		control &= ~CONTROL_WRITE_RTS;
+
 	dev_dbg(&port->dev, "%s - control = 0x%.4x\n", __func__, control);
 
-	return cp210x_write_u16_reg(port, CP210X_SET_MHS, control);
+	ret = cp210x_write_u16_reg(port, CP210X_SET_MHS, control);
+
+	mutex_unlock(&port_priv->mutex);
+
+	return ret;
 }
 
 static void cp210x_dtr_rts(struct usb_serial_port *port, int on)
@@ -1770,6 +1796,7 @@ static int cp210x_port_probe(struct usb_serial_port *port)
 		return -ENOMEM;
 
 	port_priv->bInterfaceNumber = cp210x_interface_num(serial);
+	mutex_init(&port_priv->mutex);
 
 	usb_set_serial_port_data(port, port_priv);
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/7] USB: serial: cp210x: fix modem-control handling
  2021-01-25 13:48 [PATCH 0/7] USB: serial: cp210x: modem-control fixes Johan Hovold
  2021-01-25 13:48 ` [PATCH 1/7] USB: serial: cp210x: suppress modem-control errors Johan Hovold
@ 2021-01-25 13:48 ` Johan Hovold
  2021-01-25 13:48 ` [PATCH 3/7] USB: serial: cp210x: drop shift macros Johan Hovold
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2021-01-25 13:48 UTC (permalink / raw)
  To: linux-usb; +Cc: Pho Tran, linux-kernel, Johan Hovold

The vendor request used to set the flow-control settings also sets the
state of the modem-control lines.

Add state variables to keep track of the modem-control lines to avoid
always asserting the lines whenever the flow-control settings are
updated.

This specifically also avoids asserting DTR/RTS when opening a port with
the line speed set to B0.

Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/usb/serial/cp210x.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 7e4a09b42c99..9378b4bba34b 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -269,6 +269,8 @@ struct cp210x_port_private {
 
 	struct mutex		mutex;
 	bool			crtscts;
+	bool			dtr;
+	bool			rts;
 };
 
 static struct usb_serial_driver cp210x_device = {
@@ -1162,7 +1164,10 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
 	ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE;
 	ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
 	ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
-	ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE);
+	if (port_priv->dtr)
+		ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE);
+	else
+		ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_INACTIVE);
 
 	if (C_CRTSCTS(tty)) {
 		ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
@@ -1172,7 +1177,10 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
 	} else {
 		ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
 		flow_repl &= ~CP210X_SERIAL_RTS_MASK;
-		flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_ACTIVE);
+		if (port_priv->rts)
+			flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_ACTIVE);
+		else
+			flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_INACTIVE);
 		port_priv->crtscts = false;
 	}
 
@@ -1287,25 +1295,29 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port,
 	u16 control = 0;
 	int ret;
 
+	mutex_lock(&port_priv->mutex);
+
 	if (set & TIOCM_RTS) {
+		port_priv->rts = true;
 		control |= CONTROL_RTS;
 		control |= CONTROL_WRITE_RTS;
 	}
 	if (set & TIOCM_DTR) {
+		port_priv->dtr = true;
 		control |= CONTROL_DTR;
 		control |= CONTROL_WRITE_DTR;
 	}
 	if (clear & TIOCM_RTS) {
+		port_priv->rts = false;
 		control &= ~CONTROL_RTS;
 		control |= CONTROL_WRITE_RTS;
 	}
 	if (clear & TIOCM_DTR) {
+		port_priv->dtr = false;
 		control &= ~CONTROL_DTR;
 		control |= CONTROL_WRITE_DTR;
 	}
 
-	mutex_lock(&port_priv->mutex);
-
 	/*
 	 * SET_MHS cannot be used to control RTS when auto-RTS is enabled.
 	 * Note that RTS is still deasserted when disabling the UART on close.
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/7] USB: serial: cp210x: drop shift macros
  2021-01-25 13:48 [PATCH 0/7] USB: serial: cp210x: modem-control fixes Johan Hovold
  2021-01-25 13:48 ` [PATCH 1/7] USB: serial: cp210x: suppress modem-control errors Johan Hovold
  2021-01-25 13:48 ` [PATCH 2/7] USB: serial: cp210x: fix modem-control handling Johan Hovold
@ 2021-01-25 13:48 ` Johan Hovold
  2021-01-25 13:48 ` [PATCH 4/7] USB: serial: cp210x: clean up flow-control debug message Johan Hovold
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2021-01-25 13:48 UTC (permalink / raw)
  To: linux-usb; +Cc: Pho Tran, linux-kernel, Johan Hovold

Drop the macros used to shift the flow-control settings to make the code
more readable for consistency with the other requests.

Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/usb/serial/cp210x.c | 28 +++++++++++-----------------
 1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 9378b4bba34b..aa874641374a 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -449,17 +449,14 @@ struct cp210x_flow_ctl {
 
 /* cp210x_flow_ctl::ulControlHandshake */
 #define CP210X_SERIAL_DTR_MASK		GENMASK(1, 0)
-#define CP210X_SERIAL_DTR_SHIFT(_mode)	(_mode)
+#define CP210X_SERIAL_DTR_INACTIVE	(0 << 0)
+#define CP210X_SERIAL_DTR_ACTIVE	(1 << 0)
+#define CP210X_SERIAL_DTR_FLOW_CTL	(2 << 0)
 #define CP210X_SERIAL_CTS_HANDSHAKE	BIT(3)
 #define CP210X_SERIAL_DSR_HANDSHAKE	BIT(4)
 #define CP210X_SERIAL_DCD_HANDSHAKE	BIT(5)
 #define CP210X_SERIAL_DSR_SENSITIVITY	BIT(6)
 
-/* values for cp210x_flow_ctl::ulControlHandshake::CP210X_SERIAL_DTR_MASK */
-#define CP210X_SERIAL_DTR_INACTIVE	0
-#define CP210X_SERIAL_DTR_ACTIVE	1
-#define CP210X_SERIAL_DTR_FLOW_CTL	2
-
 /* cp210x_flow_ctl::ulFlowReplace */
 #define CP210X_SERIAL_AUTO_TRANSMIT	BIT(0)
 #define CP210X_SERIAL_AUTO_RECEIVE	BIT(1)
@@ -467,14 +464,11 @@ struct cp210x_flow_ctl {
 #define CP210X_SERIAL_NULL_STRIPPING	BIT(3)
 #define CP210X_SERIAL_BREAK_CHAR	BIT(4)
 #define CP210X_SERIAL_RTS_MASK		GENMASK(7, 6)
-#define CP210X_SERIAL_RTS_SHIFT(_mode)	(_mode << 6)
+#define CP210X_SERIAL_RTS_INACTIVE	(0 << 6)
+#define CP210X_SERIAL_RTS_ACTIVE	(1 << 6)
+#define CP210X_SERIAL_RTS_FLOW_CTL	(2 << 6)
 #define CP210X_SERIAL_XOFF_CONTINUE	BIT(31)
 
-/* values for cp210x_flow_ctl::ulFlowReplace::CP210X_SERIAL_RTS_MASK */
-#define CP210X_SERIAL_RTS_INACTIVE	0
-#define CP210X_SERIAL_RTS_ACTIVE	1
-#define CP210X_SERIAL_RTS_FLOW_CTL	2
-
 /* CP210X_VENDOR_SPECIFIC, CP210X_GET_DEVICEMODE call reads these 0x2 bytes. */
 struct cp210x_pin_mode {
 	u8	eci;
@@ -1165,22 +1159,22 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
 	ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
 	ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
 	if (port_priv->dtr)
-		ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE);
+		ctl_hs |= CP210X_SERIAL_DTR_ACTIVE;
 	else
-		ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_INACTIVE);
+		ctl_hs |= CP210X_SERIAL_DTR_INACTIVE;
 
 	if (C_CRTSCTS(tty)) {
 		ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
 		flow_repl &= ~CP210X_SERIAL_RTS_MASK;
-		flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_FLOW_CTL);
+		flow_repl |= CP210X_SERIAL_RTS_FLOW_CTL;
 		port_priv->crtscts = true;
 	} else {
 		ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
 		flow_repl &= ~CP210X_SERIAL_RTS_MASK;
 		if (port_priv->rts)
-			flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_ACTIVE);
+			flow_repl |= CP210X_SERIAL_RTS_ACTIVE;
 		else
-			flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_INACTIVE);
+			flow_repl |= CP210X_SERIAL_RTS_INACTIVE;
 		port_priv->crtscts = false;
 	}
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/7] USB: serial: cp210x: clean up flow-control debug message
  2021-01-25 13:48 [PATCH 0/7] USB: serial: cp210x: modem-control fixes Johan Hovold
                   ` (2 preceding siblings ...)
  2021-01-25 13:48 ` [PATCH 3/7] USB: serial: cp210x: drop shift macros Johan Hovold
@ 2021-01-25 13:48 ` Johan Hovold
  2021-01-25 13:48 ` [PATCH 5/7] USB: serial: cp210x: clean up printk zero padding Johan Hovold
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2021-01-25 13:48 UTC (permalink / raw)
  To: linux-usb; +Cc: Pho Tran, linux-kernel, Johan Hovold

Shorten the flow-control debug message by abbreviating the field names
and reducing the value width to two characters. The latter improves
readability since all but the least significant byte will almost always
be zero anyway.

Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/usb/serial/cp210x.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index aa874641374a..36ae44818c13 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -1191,8 +1191,8 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
 	flow_ctl.ulXonLimit = cpu_to_le32(128);
 	flow_ctl.ulXoffLimit = cpu_to_le32(128);
 
-	dev_dbg(&port->dev, "%s - ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
-			__func__, ctl_hs, flow_repl);
+	dev_dbg(&port->dev, "%s - ctrl = 0x%02x, flow = 0x%02x\n", __func__,
+			ctl_hs, flow_repl);
 
 	flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs);
 	flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 5/7] USB: serial: cp210x: clean up printk zero padding
  2021-01-25 13:48 [PATCH 0/7] USB: serial: cp210x: modem-control fixes Johan Hovold
                   ` (3 preceding siblings ...)
  2021-01-25 13:48 ` [PATCH 4/7] USB: serial: cp210x: clean up flow-control debug message Johan Hovold
@ 2021-01-25 13:48 ` Johan Hovold
  2021-01-25 13:48 ` [PATCH 6/7] USB: serial: cp210x: fix RTS handling Johan Hovold
  2021-01-25 13:48 ` [PATCH 7/7] USB: serial: cp210x: clean up auto-RTS handling Johan Hovold
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2021-01-25 13:48 UTC (permalink / raw)
  To: linux-usb; +Cc: Pho Tran, linux-kernel, Johan Hovold

Use the 0-flag and a field width to specify zero-padding consistently in
printk messages.

Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/usb/serial/cp210x.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 36ae44818c13..4ba3fb096bf1 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -1319,7 +1319,7 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port,
 	if (port_priv->crtscts)
 		control &= ~CONTROL_WRITE_RTS;
 
-	dev_dbg(&port->dev, "%s - control = 0x%.4x\n", __func__, control);
+	dev_dbg(&port->dev, "%s - control = 0x%04x\n", __func__, control);
 
 	ret = cp210x_write_u16_reg(port, CP210X_SET_MHS, control);
 
@@ -1353,7 +1353,7 @@ static int cp210x_tiocmget(struct tty_struct *tty)
 		|((control & CONTROL_RING)? TIOCM_RI  : 0)
 		|((control & CONTROL_DCD) ? TIOCM_CD  : 0);
 
-	dev_dbg(&port->dev, "%s - control = 0x%.2x\n", __func__, control);
+	dev_dbg(&port->dev, "%s - control = 0x%02x\n", __func__, control);
 
 	return result;
 }
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 6/7] USB: serial: cp210x: fix RTS handling
  2021-01-25 13:48 [PATCH 0/7] USB: serial: cp210x: modem-control fixes Johan Hovold
                   ` (4 preceding siblings ...)
  2021-01-25 13:48 ` [PATCH 5/7] USB: serial: cp210x: clean up printk zero padding Johan Hovold
@ 2021-01-25 13:48 ` Johan Hovold
  2021-01-25 13:48 ` [PATCH 7/7] USB: serial: cp210x: clean up auto-RTS handling Johan Hovold
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2021-01-25 13:48 UTC (permalink / raw)
  To: linux-usb; +Cc: Pho Tran, linux-kernel, Johan Hovold

Clearing TIOCM_RTS should always deassert RTS and setting the same bit
should enable auto-RTS if hardware flow control is enabled.

This allows user space to throttle input directly at the source also
when hardware-assisted flow control is enabled and makes dtr_rts()
always deassert both lines during close (when HUPCL is set).

Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/usb/serial/cp210x.c | 47 +++++++++++++++++++++++++++++++------
 1 file changed, 40 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 4ba3fb096bf1..f00b736f3cd3 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -1166,7 +1166,10 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
 	if (C_CRTSCTS(tty)) {
 		ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
 		flow_repl &= ~CP210X_SERIAL_RTS_MASK;
-		flow_repl |= CP210X_SERIAL_RTS_FLOW_CTL;
+		if (port_priv->rts)
+			flow_repl |= CP210X_SERIAL_RTS_FLOW_CTL;
+		else
+			flow_repl |= CP210X_SERIAL_RTS_INACTIVE;
 		port_priv->crtscts = true;
 	} else {
 		ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
@@ -1286,6 +1289,8 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port,
 		unsigned int set, unsigned int clear)
 {
 	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
+	struct cp210x_flow_ctl flow_ctl;
+	u32 ctl_hs, flow_repl;
 	u16 control = 0;
 	int ret;
 
@@ -1313,16 +1318,44 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port,
 	}
 
 	/*
-	 * SET_MHS cannot be used to control RTS when auto-RTS is enabled.
-	 * Note that RTS is still deasserted when disabling the UART on close.
+	 * Use SET_FLOW to set DTR and enable/disable auto-RTS when hardware
+	 * flow control is enabled.
 	 */
-	if (port_priv->crtscts)
-		control &= ~CONTROL_WRITE_RTS;
+	if (port_priv->crtscts && control & CONTROL_WRITE_RTS) {
+		ret = cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
+				sizeof(flow_ctl));
+		if (ret)
+			goto out_unlock;
 
-	dev_dbg(&port->dev, "%s - control = 0x%04x\n", __func__, control);
+		ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
+		flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);
 
-	ret = cp210x_write_u16_reg(port, CP210X_SET_MHS, control);
+		ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
+		if (port_priv->dtr)
+			ctl_hs |= CP210X_SERIAL_DTR_ACTIVE;
+		else
+			ctl_hs |= CP210X_SERIAL_DTR_INACTIVE;
 
+		flow_repl &= ~CP210X_SERIAL_RTS_MASK;
+		if (port_priv->rts)
+			flow_repl |= CP210X_SERIAL_RTS_FLOW_CTL;
+		else
+			flow_repl |= CP210X_SERIAL_RTS_INACTIVE;
+
+		flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs);
+		flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
+
+		dev_dbg(&port->dev, "%s - ctrl = 0x%02x, flow = 0x%02x\n",
+				__func__, ctl_hs, flow_repl);
+
+		ret = cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl,
+				sizeof(flow_ctl));
+	} else {
+		dev_dbg(&port->dev, "%s - control = 0x%04x\n", __func__, control);
+
+		ret = cp210x_write_u16_reg(port, CP210X_SET_MHS, control);
+	}
+out_unlock:
 	mutex_unlock(&port_priv->mutex);
 
 	return ret;
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 7/7] USB: serial: cp210x: clean up auto-RTS handling
  2021-01-25 13:48 [PATCH 0/7] USB: serial: cp210x: modem-control fixes Johan Hovold
                   ` (5 preceding siblings ...)
  2021-01-25 13:48 ` [PATCH 6/7] USB: serial: cp210x: fix RTS handling Johan Hovold
@ 2021-01-25 13:48 ` Johan Hovold
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2021-01-25 13:48 UTC (permalink / raw)
  To: linux-usb; +Cc: Pho Tran, linux-kernel, Johan Hovold

Clear the RTS bits of the flow-control request before determining the
new value when updating the settings.

Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/usb/serial/cp210x.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index f00b736f3cd3..cc4f63a06f9e 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -1163,9 +1163,9 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
 	else
 		ctl_hs |= CP210X_SERIAL_DTR_INACTIVE;
 
+	flow_repl &= ~CP210X_SERIAL_RTS_MASK;
 	if (C_CRTSCTS(tty)) {
 		ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
-		flow_repl &= ~CP210X_SERIAL_RTS_MASK;
 		if (port_priv->rts)
 			flow_repl |= CP210X_SERIAL_RTS_FLOW_CTL;
 		else
@@ -1173,7 +1173,6 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
 		port_priv->crtscts = true;
 	} else {
 		ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
-		flow_repl &= ~CP210X_SERIAL_RTS_MASK;
 		if (port_priv->rts)
 			flow_repl |= CP210X_SERIAL_RTS_ACTIVE;
 		else
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-01-26 17:00 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-25 13:48 [PATCH 0/7] USB: serial: cp210x: modem-control fixes Johan Hovold
2021-01-25 13:48 ` [PATCH 1/7] USB: serial: cp210x: suppress modem-control errors Johan Hovold
2021-01-25 13:48 ` [PATCH 2/7] USB: serial: cp210x: fix modem-control handling Johan Hovold
2021-01-25 13:48 ` [PATCH 3/7] USB: serial: cp210x: drop shift macros Johan Hovold
2021-01-25 13:48 ` [PATCH 4/7] USB: serial: cp210x: clean up flow-control debug message Johan Hovold
2021-01-25 13:48 ` [PATCH 5/7] USB: serial: cp210x: clean up printk zero padding Johan Hovold
2021-01-25 13:48 ` [PATCH 6/7] USB: serial: cp210x: fix RTS handling Johan Hovold
2021-01-25 13:48 ` [PATCH 7/7] USB: serial: cp210x: clean up auto-RTS handling Johan Hovold

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).