diff mbox series

[1/2] Make cp210x respond to modem status changes (CTS, DSR, RI, DCD) by default.

Message ID 20231009023425.366783-2-brian@kloppenborg.net
State New
Headers show
Series [1/2] Make cp210x respond to modem status changes (CTS, DSR, RI, DCD) by default. | expand

Commit Message

Brian Kloppenborg Oct. 9, 2023, 2:34 a.m. UTC
---
 drivers/usb/serial/cp210x.c | 62 ++++++++++++++++++++++++++++++-------
 1 file changed, 51 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 1e61fe043171..af96d592456b 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -285,6 +285,7 @@  struct cp210x_port_private {
 	bool			event_mode;
 	enum cp210x_event_state event_state;
 	u8			lsr;
+	u8			msr;
 
 	struct mutex		mutex;
 	bool			crtscts;
@@ -459,6 +460,15 @@  struct cp210x_comm_status {
 #define CP210X_LSR_FRAME	BIT(3)
 #define CP210X_LSR_BREAK	BIT(4)
 
+/* Bits for Modem Status EMBED_EVENTS as described in AN571 */
+#define CP210X_MSR_DELTA_CTS_BIT 	BIT(0)
+#define CP210X_MSR_DELTA_DSR_BIT 	BIT(1)
+#define CP210X_MSR_DELTA_RI_BIT 	BIT(2)
+#define CP210X_MSR_DELTA_DCD_BIT 	BIT(3)
+#define CP210X_MSR_CTS_STATE_BIT 	BIT(4)
+#define CP210X_MSR_DSR_STATE_BIT 	BIT(5)
+#define CP210X_MSR_RI_STATE_BIT 	BIT(6)
+#define CP210X_MSR_DCD_STATE_BIT	BIT(7)
 
 /* CP210X_GET_FLOW/CP210X_SET_FLOW read/write these 0x10 bytes */
 struct cp210x_flow_ctl {
@@ -786,6 +796,8 @@  static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
 	if (result)
 		goto err_disable;
 
+	cp210x_enable_event_mode(port);
+
 	return 0;
 
 err_disable:
@@ -799,6 +811,8 @@  static void cp210x_close(struct usb_serial_port *port)
 {
 	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
 
+	cp210x_disable_event_mode(port);
+
 	usb_serial_generic_close(port);
 
 	/* Clear both queues; cp2108 needs this to avoid an occasional hang */
@@ -829,6 +843,41 @@  static void cp210x_process_lsr(struct usb_serial_port *port, unsigned char lsr,
 	}
 }
 
+static void cp210x_process_msr(struct usb_serial_port *port, unsigned char msr, char *flag)
+{
+	struct tty_struct *tty;
+
+	if(msr & CP210X_MSR_DELTA_CTS_BIT) {
+		port->icount.cts++;
+	}
+
+	if(msr & CP210X_MSR_DELTA_DSR_BIT) {
+		port->icount.dsr++;
+	}
+
+	if(msr & CP210X_MSR_DELTA_RI_BIT) {
+		port->icount.rng++;
+	}
+
+	if(msr & CP210X_MSR_DELTA_DCD_BIT) {
+		port->icount.dcd++;
+
+		tty = tty_port_tty_get(&port->port);
+		if (tty) {
+			usb_serial_handle_dcd_change(port, tty,
+				(msr) & CP210X_MSR_DCD_STATE_BIT);
+		}
+		tty_kref_put(tty);
+
+	}
+
+	if(msr & CP210X_MSR_CTS_STATE_BIT) {
+		port->icount.cts++;
+	}
+
+	wake_up_interruptible(&port->port.delta_msr_wait);
+}
+
 static bool cp210x_process_char(struct usb_serial_port *port, unsigned char *ch, char *flag)
 {
 	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
@@ -880,9 +929,9 @@  static bool cp210x_process_char(struct usb_serial_port *port, unsigned char *ch,
 		break;
 	case ES_MSR:
 		dev_dbg(&port->dev, "%s - msr = 0x%02x\n", __func__, *ch);
-		/* unimplemented */
+		port_priv->msr = *ch;
+		cp210x_process_msr(port, port_priv->msr, flag);
 		port_priv->event_state = ES_DATA;
-		break;
 	}
 
 	return true;
@@ -1310,15 +1359,6 @@  static void cp210x_set_termios(struct tty_struct *tty,
 		dev_err(&port->dev, "failed to set line control: %d\n", ret);
 
 	cp210x_set_flow_control(tty, port, old_termios);
-
-	/*
-	 * Enable event-insertion mode only if input parity checking is
-	 * enabled for now.
-	 */
-	if (I_INPCK(tty))
-		cp210x_enable_event_mode(port);
-	else
-		cp210x_disable_event_mode(port);
 }
 
 static int cp210x_tiocmset(struct tty_struct *tty,