@@ -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,