[PATCH] Add DCD line support to CP210x driver

2016-03-22 Thread Valentin Yakovenkov
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 
---
 drivers/usb/serial/cp210x.c | 115 +++-
 1 file changed, 114 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 7a76fe4..d9cba4e 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -46,6 +46,7 @@ static void cp210x_break_ctl(struct tty_struct *, int);
 static int cp210x_startup(struct usb_serial *);
 static void cp210x_release(struct usb_serial *);
 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 */
@@ -201,8 +202,17 @@ static const struct usb_device_id id_table[] = {
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
+#define CP210X_ESCCHAR 0x1e
+#define CP210X_STATE_IDLE  0
+#define CP210X_STATE_ESC   1
+#define CP210X_STATE_LS0   2
+#define CP210X_STATE_LS1   3
+#define CP210X_STATE_LS4
+#define CP210X_STATE_MS5
+
 struct cp210x_serial_private {
__u8bInterfaceNumber;
+   int cp210x_tstate;
 };
 
 static struct usb_serial_driver cp210x_device = {
@@ -222,7 +232,8 @@ static struct usb_serial_driver cp210x_device = {
.tiocmset   = cp210x_tiocmset,
.attach = cp210x_startup,
.release= cp210x_release,
-   .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[] = {
@@ -460,6 +471,11 @@ static int cp210x_open(struct tty_struct *tty, struct 
usb_serial_port *port)
 {
int result;
 
+   struct usb_serial *serial = port->serial;
+   struct cp210x_serial_private *spriv = usb_get_serial_data(serial);
+
+   spriv->cp210x_tstate = CP210X_STATE_IDLE;
+
result = cp210x_set_config_single(port, CP210X_IFC_ENABLE,
UART_ENABLE);
if (result) {
@@ -474,6 +490,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_set_config_single(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);
 }
 
@@ -483,6 +508,94 @@ static void cp210x_close(struct usb_serial_port *port)
cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
 }
 
+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_serial_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->cp210x_tstate) {
+   case CP210X_STATE_IDLE:
+   if (c == CP210X_ESCCHAR)
+   spriv->cp210x_tstate = CP210X_STATE_ESC;
+   else
+   tbuf[tcnt++] = c;
+   break;
+
+   case CP210X_STATE_ESC:
+   if (c == 0x01)
+   spriv->cp210x_tstate = CP210X_STATE_LS0;
+   else if (c == 0x02)
+   spriv->cp210x_tstate = CP210X_STATE_LS;
+   else if (c == 0x03)
+   spriv->cp210x_tstate = CP210X_STATE_MS;
+   else {
+   tbuf[tcnt++] = (c == 0x00) ? CP210X_ESCCHAR : c;
+   spriv->cp210x_tstate = CP210X_STATE_IDLE;
+   }
+   break;
+
+   case CP210X_ST

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

2016-03-23 Thread Valentin Yakovenkov
This behavior is expected to be enabled by default, i think.
I'm using CP210x converter with GPS connected to it and DCD line is used
as PPS discipline to NTP daemon (this is standard behavior).

Moreover, it should be nice to add CTS/DSR handling same way.

Here is the patch against latest usb-serial tree.

23.03.2016 19:25, Konstantin Shkolnyy пишет:
>> -Original Message-
>> From: linux-usb-ow...@vger.kernel.org [mailto:linux-usb-
>> ow...@vger.kernel.org] On Behalf Of Valentin Yakovenkov
>> Sent: Tuesday, March 22, 2016 11:12
>> To: linux-usb@vger.kernel.org
>> Subject: [PATCH] Add DCD line support to CP210x driver
> [...]
>
>>   static struct usb_serial_driver * const serial_drivers[] = {
>> @@ -460,6 +471,11 @@ static int cp210x_open(struct tty_struct *tty, struct
>> usb_serial_port *port)
>>   {
>>  int result;
>>
>> +struct usb_serial *serial = port->serial;
>> +struct cp210x_serial_private *spriv = usb_get_serial_data(serial);
>> +
>> +spriv->cp210x_tstate = CP210X_STATE_IDLE;
>> +
>>  result = cp210x_set_config_single(port, CP210X_IFC_ENABLE,
>>
>>  UART_ENABLE);
>>  if (result) {
>> @@ -474,6 +490,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_set_config_single(port, CP210X_EMBED_EVENTS,
>> +
>>  CP210X_ESCCHAR);
>> +if (result) {
>> +dev_err(&port->dev, "%s - Unable to enable event
>> embedding on UART\n",
>> +__func__);
>> +return result;
>> +}
>> +
>
> This unconditionally enables the behavior every time the device is opened. 
> Instead it needs to be enabled by the application explicitly, otherwise it'll 
> hurt people who don't except it.
>
> [...]
>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

2016-03-23 Thread Valentin Yakovenkov
Here's regenerated patch against latest usb-serial tree.

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 
---
 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 987813b..9b7fbd1 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 {
__u8bInterfaceNumber;
boolhas_swapped_line_ctl;
+   enum cp210x_rx_staterx_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[] = {
@@ -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,
UART_ENABLE);
if (result) {
@@ -547,6 +566,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_set_config_single(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);
 }
 
@@ -608,6 +636,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;
+
+

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

2016-03-24 Thread Valentin Yakovenkov
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 
---
 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 {
__u8bInterfaceNumber;
boolhas_swapped_line_ctl;
+   enum cp210x_rx_staterx_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;
+
+