--- drivers/usb/serial/cp210x.c | 62 ++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 11 deletions(-) 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, -- 2.34.1