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

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

 



Sorry, I missed the branch.

Here it is.

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
+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;
 };
 
 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;
+		}
+	}
+
+	/*
+	 * The per character mucking around with sysrq path it too slow for
+	 * stuff like 3G modems, so shortcircuit it in the 99.9999999% of
+	 * cases where the USB serial is not a console anyway.
+	 */
+	if (!port->port.console || !port->sysrq) {
+		tty_insert_flip_string(&port->port, tbuf, tcnt);
+	} else {
+		ch = tbuf;
+		for (i = 0; i < tcnt; i++, ch++) {
+			if (!usb_serial_handle_sysrq_char(port, *ch))
+				tty_insert_flip_char(&port->port, *ch,
+						TTY_NORMAL);
+		}
+	}
+	tty_flip_buffer_push(&port->port);
+}
+
 /*
  * cp210x_get_termios
  * Reads the baud rate, data bits, parity, stop bits and flow control mode
-- 
2.5.0



23.03.2016 21:05, Konstantin Shkolnyy пишет:
>> -----Original Message-----
>> From: Valentin Yakovenkov [mailto:yakovenkov@xxxxxxxxx]
>> Sent: Wednesday, March 23, 2016 11:52
>> To: Konstantin Shkolnyy; linux-usb@xxxxxxxxxxxxxxx
>> Subject: Re: [PATCH] Add DCD line support to CP210x driver
>>
>> Here's regenerated patch against latest usb-serial tree.
> 
> [...]
> 
>> @@ -533,6 +547,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_set_config_single(port, CP210X_IFC_ENABLE,
> 
> This call to cp210x_set_config_single tells me that it's not against the proper branch. This function was replaced with cp210x_write_u16_reg just recently.
> 
> When I use these commands:
> git clone git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git
> cd usb-serial
> git checkout usb-next
> git log
> 
> I get:
> commit 7084fa868b509646fa30773d5d3ef4f26a62eb6f
> Author: Konstantin Shkolnyy <konstantin.shkolnyy@xxxxxxxxx>
> Date:   Sun Feb 28 15:51:56 2016 -0600
> 
>     USB: serial: cp210x: add new access functions for large registers
>     
>     cp210x_get_config and cp210x_set_config are cumbersome to use. This change
>     switches large register access to use new block functions. The old
>     functions are removed because now they become unused.
>     
>     Signed-off-by: Konstantin Shkolnyy <konstantin.shkolnyy@xxxxxxxxx>
>     [johan: minor style change ]
>     Signed-off-by: Johan Hovold <johan@xxxxxxxxxx>
> 
> 
> 
> 
> 
> 
--
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