Re: [PATCH] Add DCD line support to CP210x driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Mar 24, 2016 at 10:53:27AM +0300, Valentin Yakovenkov wrote:
> Sorry, I missed the branch.
> 
> Here it is.

Thanks for the patch. Please resubmit it on a format that can be applied
(i.e. without quoted text, etc). Remember to include a patch
revision in the Subject when resubmitting patches (this one should be
[PATCH v3] or so). Putting a changelog below the cut-off line (---) is
also recommended.

> This patch adds DCD line support to CP210x USB serial driver.
> 
> First it enables CP210x events embedding to incoming URB's by calling:
> cp210x_set_config_single(port, CP210X_EMBED_EVENTS, CP210X_ESCCHAR);
> 
> Then it parses incoming URB's via custom routine:
> cp210x_process_read_urb(...)
> searches for event sequences and handles all of DCD changes calling
> usb_serial_handle_dcd_change(...)
> 
> Signed-off-by: Valentin Yakovenkov <yakovenkov@xxxxxxxxx>
> ---
>  drivers/usb/serial/cp210x.c | 118 +++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 117 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
> index c740592..ef0e8b1 100644
> --- a/drivers/usb/serial/cp210x.c
> +++ b/drivers/usb/serial/cp210x.c
> @@ -47,6 +47,7 @@ static void cp210x_break_ctl(struct tty_struct *, int);
>  static int cp210x_port_probe(struct usb_serial_port *);
>  static int cp210x_port_remove(struct usb_serial_port *);
>  static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
> +static void cp210x_process_read_urb(struct urb *urb);
>  
>  static const struct usb_device_id id_table[] = {
>  	{ USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */
> @@ -199,9 +200,21 @@ static const struct usb_device_id id_table[] = {
>  
>  MODULE_DEVICE_TABLE(usb, id_table);
>  
> +#define CP210X_ESCCHAR		0x1e

Move this below the PURGE_ALL definition.

> +enum cp210x_rx_state {
> +	CP210X_STATE_IDLE = 0,
> +	CP210X_STATE_ESC,
> +	CP210X_STATE_LS0,
> +	CP210X_STATE_LS1,
> +	CP210X_STATE_LS,
> +	CP210X_STATE_MS
> +};
> +
> +
>  struct cp210x_port_private {
>  	__u8			bInterfaceNumber;
>  	bool			has_swapped_line_ctl;
> +	enum cp210x_rx_state	rx_state;

This shouldn't be needed (see below).

>  };
>  
>  static struct usb_serial_driver cp210x_device = {
> @@ -222,7 +235,8 @@ static struct usb_serial_driver cp210x_device = {
>  	.tiocmset		= cp210x_tiocmset,
>  	.port_probe		= cp210x_port_probe,
>  	.port_remove		= cp210x_port_remove,
> -	.dtr_rts		= cp210x_dtr_rts
> +	.dtr_rts		= cp210x_dtr_rts,
> +	.process_read_urb       = cp210x_process_read_urb
>  };
>  
>  static struct usb_serial_driver * const serial_drivers[] = {
> @@ -588,6 +602,11 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
>  {
>  	int result;
>  
> +	struct usb_serial *serial = port->serial;
> +	struct cp210x_port_private *spriv = usb_get_serial_data(serial);
> +
> +	spriv->rx_state = CP210X_STATE_IDLE;
> +
>  	result = cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_ENABLE);
>  	if (result) {
>  		dev_err(&port->dev, "%s - Unable to enable UART\n", __func__);
> @@ -601,6 +620,15 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
>  	if (tty)
>  		cp210x_change_speed(tty, port, NULL);
>  
> +	/* Enable events embedding to data stream */
> +	result = cp210x_write_u16_reg(port, CP210X_EMBED_EVENTS,
> +								CP210X_ESCCHAR);
> +	if (result) {
> +		dev_err(&port->dev, "%s - Unable to enable event embedding on UART\n",
> +				__func__);
> +		return result;
> +	}
> +
>  	return usb_serial_generic_open(tty, port);
>  }
>  
> @@ -659,6 +687,94 @@ static bool cp210x_tx_empty(struct usb_serial_port *port)
>  	return !count;
>  }
>  
> +static void cp210x_process_read_urb(struct urb *urb)
> +{
> +	struct usb_serial_port *port = urb->context;
> +	char *ch = (char *)urb->transfer_buffer;
> +	char *tbuf = (char *)urb->transfer_buffer;
> +	int i;
> +	int tcnt = 0;
> +	struct usb_serial *serial = port->serial;
> +	struct cp210x_port_private *spriv = usb_get_serial_data(serial);
> +
> +	if (!urb->actual_length)
> +		return;
> +
> +	/* Process escape chars */
> +	for (i = 0; i < urb->actual_length; i++) {
> +		char c = ch[i];
> +
> +		switch (spriv->rx_state) {
> +		case CP210X_STATE_IDLE:
> +			if (c == CP210X_ESCCHAR)
> +				spriv->rx_state = CP210X_STATE_ESC;
> +			else
> +				tbuf[tcnt++] = c;
> +			break;
> +
> +		case CP210X_STATE_ESC:
> +			if (c == 0x01)
> +				spriv->rx_state = CP210X_STATE_LS0;
> +			else if (c == 0x02)
> +				spriv->rx_state = CP210X_STATE_LS;
> +			else if (c == 0x03)
> +				spriv->rx_state = CP210X_STATE_MS;
> +			else {
> +				tbuf[tcnt++] = (c == 0x00) ? CP210X_ESCCHAR : c;
> +				spriv->rx_state = CP210X_STATE_IDLE;
> +			}
> +			break;
> +
> +		case CP210X_STATE_LS0:
> +			spriv->rx_state = CP210X_STATE_LS1;
> +			break;
> +
> +		case CP210X_STATE_LS1:
> +			tbuf[tcnt++] = c;
> +			spriv->rx_state = CP210X_STATE_IDLE;
> +			break;
> +
> +		case CP210X_STATE_LS:
> +			spriv->rx_state = CP210X_STATE_IDLE;
> +			break;
> +
> +		case CP210X_STATE_MS:
> +			if (c & 0x08) {
> +				/* DCD change event */
> +				struct tty_struct *tty;
> +
> +				port->icount.dcd++;
> +				tty = tty_port_tty_get(&port->port);
> +				if (tty)
> +					usb_serial_handle_dcd_change(port, tty,
> +							c & 0x80);
> +				tty_kref_put(tty);
> +
> +			}
> +			wake_up_interruptible(&port->port.delta_msr_wait);
> +			spriv->rx_state = CP210X_STATE_IDLE;
> +			break;
> +		}
> +	}

Instead of maintaining this state machine (which should not need to be
global, or can the events really be split over multiple bulk
transfers?), just scan the buffer for the escape character and if found,
process the symbols one by one for that buffer. If line errors were
detected, this should also be reported to user space (e.g. using
tty_insert_flip_char and a non TTY_NORMAL flag), etc.

Thanks,
Johan
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux