* [PATCH 1/1] usbserial: cp210x - icount support for parity error checking
@ 2020-06-20 19:58 Jerry
2020-06-21 8:54 ` [PATCH v2] " Jerry
2020-06-21 8:58 ` [PATCH 1/1] " Greg Kroah-Hartman
0 siblings, 2 replies; 28+ messages in thread
From: Jerry @ 2020-06-20 19:58 UTC (permalink / raw)
To: Johan Hovold, Greg Kroah-Hartman, linux-usb
usbserial: add cp210x support for icount to detect parity error in received data
Motivation - current version of cp210x driver doesn't provide any way to detect
a parity error in received data from userspace. Some serial protocols like STM32
bootloader protect data only by even parity so application needs to detect
whether parity error happened to read again peripheral data.
I created a simple patch which adds support for icount (ioctl TIOCGICOUNT) which
sends GET_COMM_STATUS command to CP210X and according received flags increments
fields for parity error, frame error, break and overrun.
So application can detect an error condition after reading data from ttyUSB
and repeat operation. There is no impact for applications which don't
call ioctl TIOCGICOUNT.
This patch is also placed at http://yyy.jrr.cz/cp210x.patch (my first patch)
Signed-off-by: Jaromir Skorpil <Jerry@jrr.cz>
---
diff -up linux-5.8-rc1/drivers/usb/serial/cp210x.c j/drivers/usb/serial/cp210x.c
--- linux-5.8-rc1/drivers/usb/serial/cp210x.c 2020-06-14 21:45:04.000000000 +0200
+++ j/drivers/usb/serial/cp210x.c 2020-06-20 18:50:17.135843606 +0200
@@ -43,6 +43,8 @@ static int cp210x_tiocmget(struct tty_st
static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int);
static int cp210x_tiocmset_port(struct usb_serial_port *port,
unsigned int, unsigned int);
+static int cp210x_get_icount(struct tty_struct *tty,
+ struct serial_icounter_struct *icount);
static void cp210x_break_ctl(struct tty_struct *, int);
static int cp210x_attach(struct usb_serial *);
static void cp210x_disconnect(struct usb_serial *);
@@ -274,6 +276,7 @@ static struct usb_serial_driver cp210x_d
.tx_empty = cp210x_tx_empty,
.tiocmget = cp210x_tiocmget,
.tiocmset = cp210x_tiocmset,
+ .get_icount = cp210x_get_icount,
.attach = cp210x_attach,
.disconnect = cp210x_disconnect,
.release = cp210x_release,
@@ -393,6 +396,13 @@ struct cp210x_comm_status {
u8 bReserved;
} __packed;
+/* cp210x_comm_status::ulErrors */
+#define CP210X_SERIAL_ERR_BREAK BIT(0)
+#define CP210X_SERIAL_ERR_FRAME BIT(1)
+#define CP210X_SERIAL_ERR_HW_OVERRUN BIT(2)
+#define CP210X_SERIAL_ERR_QUEUE_OVERRUN BIT(3)
+#define CP210X_SERIAL_ERR_PARITY BIT(4)
+
/*
* CP210X_PURGE - 16 bits passed in wValue of USB request.
* SiLabs app note AN571 gives a strange description of the 4 bits:
@@ -836,10 +846,10 @@ static void cp210x_close(struct usb_seri
}
/*
- * Read how many bytes are waiting in the TX queue.
+ * Read how many bytes are waiting in the TX queue and update error counters.
*/
-static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port,
- u32 *count)
+static int cp210x_get_comm_status(struct usb_serial_port *port,
+ u32 *tx_count)
{
struct usb_serial *serial = port->serial;
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
@@ -855,7 +865,18 @@ static int cp210x_get_tx_queue_byte_coun
0, port_priv->bInterfaceNumber, sts, sizeof(*sts),
USB_CTRL_GET_TIMEOUT);
if (result == sizeof(*sts)) {
- *count = le32_to_cpu(sts->ulAmountInOutQueue);
+ if (tx_count)
+ *tx_count = le32_to_cpu(sts->ulAmountInOutQueue);
+ if (sts->ulErrors & CP210X_SERIAL_ERR_BREAK)
+ port->icount.brk++;
+ if (sts->ulErrors & CP210X_SERIAL_ERR_FRAME)
+ port->icount.frame++;
+ if (sts->ulErrors & CP210X_SERIAL_ERR_HW_OVERRUN)
+ port->icount.overrun++;
+ if (sts->ulErrors & CP210X_SERIAL_ERR_QUEUE_OVERRUN)
+ port->icount.buf_overrun++;
+ if (sts->ulErrors & CP210X_SERIAL_ERR_PARITY)
+ port->icount.parity++;
result = 0;
} else {
dev_err(&port->dev, "failed to get comm status: %d\n", result);
@@ -873,13 +894,26 @@ static bool cp210x_tx_empty(struct usb_s
int err;
u32 count;
- err = cp210x_get_tx_queue_byte_count(port, &count);
+ err = cp210x_get_comm_status(port, &count);
if (err)
return true;
return !count;
}
+static int cp210x_get_icount(struct tty_struct *tty,
+ struct serial_icounter_struct *icount)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ int result;
+
+ result = cp210x_get_comm_status(port, NULL);
+ if (result)
+ return result;
+
+ return usb_serial_generic_get_icount(tty, icount);
+}
+
/*
* cp210x_get_termios
* Reads the baud rate, data bits, parity, stop bits and flow control mode
^ permalink raw reply [flat|nested] 28+ messages in thread* [PATCH v2] usbserial: cp210x - icount support for parity error checking 2020-06-20 19:58 [PATCH 1/1] usbserial: cp210x - icount support for parity error checking Jerry @ 2020-06-21 8:54 ` Jerry 2020-06-21 8:58 ` [PATCH 1/1] " Greg Kroah-Hartman 1 sibling, 0 replies; 28+ messages in thread From: Jerry @ 2020-06-21 8:54 UTC (permalink / raw) To: linux-usb; +Cc: Johan Hovold, Greg Kroah-Hartman usbserial: add cp210x support for icount to detect parity error in received data Motivation - current version of cp210x driver doesn't provide any way to detect a parity error in received data from userspace. Some serial protocols like STM32 bootloader protect data only by even parity so application needs to detect whether parity error happened to read again peripheral data. This simple patch adds support for icount (ioctl TIOCGICOUNT) which sends GET_COMM_STATUS command to CP210X and according received flags increments fields for parity error, frame error, break and overrun. So application can detect an error condition after reading data from ttyUSB and repeat operation. There is no impact for applications which don't call ioctl TIOCGICOUNT. I slightly changed the patch because CP2102 sets flag "hardware overrun" for the first received byte after openning the port which was previously closed with some unreaded data in buffer. This is confusing and checking queue overrun seems be enough. This patch is also placed at http://yyy.jrr.cz/cp210x.patch Signed-off-by: Jaromir Skorpil <Jerry@jrr.cz> --- v2: Simplified counting - only queue overrun checked cp210x.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff -up linux-5.8-rc1/drivers/usb/serial/cp210x.c j/drivers/usb/serial/cp210x.c --- linux-5.8-rc1/drivers/usb/serial/cp210x.c +++ j/drivers/usb/serial/cp210x.c @@ -43,6 +43,8 @@ static int cp210x_tiocmget(struct tty_st static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int); static int cp210x_tiocmset_port(struct usb_serial_port *port, unsigned int, unsigned int); +static int cp210x_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount); static void cp210x_break_ctl(struct tty_struct *, int); static int cp210x_attach(struct usb_serial *); static void cp210x_disconnect(struct usb_serial *); @@ -274,6 +276,7 @@ static struct usb_serial_driver cp210x_d .tx_empty = cp210x_tx_empty, .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, + .get_icount = cp210x_get_icount, .attach = cp210x_attach, .disconnect = cp210x_disconnect, .release = cp210x_release, @@ -393,6 +396,13 @@ struct cp210x_comm_status { u8 bReserved; } __packed; +/* cp210x_comm_status::ulErrors */ +#define CP210X_SERIAL_ERR_BREAK BIT(0) +#define CP210X_SERIAL_ERR_FRAME BIT(1) +#define CP210X_SERIAL_ERR_HW_OVERRUN BIT(2) +#define CP210X_SERIAL_ERR_QUEUE_OVERRUN BIT(3) +#define CP210X_SERIAL_ERR_PARITY BIT(4) + /* * CP210X_PURGE - 16 bits passed in wValue of USB request. * SiLabs app note AN571 gives a strange description of the 4 bits: @@ -836,10 +846,10 @@ static void cp210x_close(struct usb_seri } /* - * Read how many bytes are waiting in the TX queue. + * Read how many bytes are waiting in the TX queue and update error counters. */ -static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port, - u32 *count) +static int cp210x_get_comm_status(struct usb_serial_port *port, + u32 *tx_count) { struct usb_serial *serial = port->serial; struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); @@ -855,7 +865,16 @@ static int cp210x_get_tx_queue_byte_coun 0, port_priv->bInterfaceNumber, sts, sizeof(*sts), USB_CTRL_GET_TIMEOUT); if (result == sizeof(*sts)) { - *count = le32_to_cpu(sts->ulAmountInOutQueue); + if (tx_count) + *tx_count = le32_to_cpu(sts->ulAmountInOutQueue); + if (sts->ulErrors & CP210X_SERIAL_ERR_BREAK) + port->icount.brk++; + if (sts->ulErrors & CP210X_SERIAL_ERR_FRAME) + port->icount.frame++; + if (sts->ulErrors & CP210X_SERIAL_ERR_QUEUE_OVERRUN) + port->icount.overrun++; + if (sts->ulErrors & CP210X_SERIAL_ERR_PARITY) + port->icount.parity++; result = 0; } else { dev_err(&port->dev, "failed to get comm status: %d\n", result); @@ -873,13 +892,26 @@ static bool cp210x_tx_empty(struct usb_s int err; u32 count; - err = cp210x_get_tx_queue_byte_count(port, &count); + err = cp210x_get_comm_status(port, &count); if (err) return true; return !count; } +static int cp210x_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct usb_serial_port *port = tty->driver_data; + int result; + + result = cp210x_get_comm_status(port, NULL); + if (result) + return result; + + return usb_serial_generic_get_icount(tty, icount); +} + /* * cp210x_get_termios * Reads the baud rate, data bits, parity, stop bits and flow control mode -- ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/1] usbserial: cp210x - icount support for parity error checking 2020-06-20 19:58 [PATCH 1/1] usbserial: cp210x - icount support for parity error checking Jerry 2020-06-21 8:54 ` [PATCH v2] " Jerry @ 2020-06-21 8:58 ` Greg Kroah-Hartman 2020-06-21 9:45 ` Jerry 1 sibling, 1 reply; 28+ messages in thread From: Greg Kroah-Hartman @ 2020-06-21 8:58 UTC (permalink / raw) To: Jerry; +Cc: Johan Hovold, linux-usb On Sat, Jun 20, 2020 at 09:58:40PM +0200, Jerry wrote: > usbserial: add cp210x support for icount to detect parity error in received data Why is this here? > Motivation - current version of cp210x driver doesn't provide any way to detect > a parity error in received data from userspace. Some serial protocols like STM32 > bootloader protect data only by even parity so application needs to detect > whether parity error happened to read again peripheral data. > > I created a simple patch which adds support for icount (ioctl TIOCGICOUNT) which > sends GET_COMM_STATUS command to CP210X and according received flags increments > fields for parity error, frame error, break and overrun. > So application can detect an error condition after reading data from ttyUSB > and repeat operation. There is no impact for applications which don't > call ioctl TIOCGICOUNT. > This patch is also placed at http://yyy.jrr.cz/cp210x.patch (my first patch) Please read the section entitled "The canonical patch format" in the kernel file, Documentation/SubmittingPatches for what is needed in order to properly describe the change. > Signed-off-by: Jaromir Skorpil <Jerry@jrr.cz> This does not match your From: line :( thanks, greg k-h ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/1] usbserial: cp210x - icount support for parity error checking 2020-06-21 8:58 ` [PATCH 1/1] " Greg Kroah-Hartman @ 2020-06-21 9:45 ` Jerry 2020-06-21 9:55 ` Greg Kroah-Hartman 0 siblings, 1 reply; 28+ messages in thread From: Jerry @ 2020-06-21 9:45 UTC (permalink / raw) To: Greg Kroah-Hartman; +Cc: Johan Hovold, linux-usb Greg Kroah-Hartman wrote on 6/21/20 10:58 AM: > On Sat, Jun 20, 2020 at 09:58:40PM +0200, Jerry wrote: >> usbserial: add cp210x support for icount to detect parity error in received data > Why is this here? > Because it seems be mandatory? https://www.kernel.org/doc/html/latest/process/5.Posting.html#patch-formatting-and-changelogs "A one-line description of what the patch does. This message should be enough for a reader who sees it with no other context to figure out the scope of the patch; it is the line that will show up in the “short form” changelogs. This message is usually formatted with the relevant subsystem name first, followed by the purpose of the patch. For example: gpio: fix build on CONFIG_GPIO_SYSFS=n" Did I misunderstand your rule or used wrong name of subsystem? Should I type? USB serial: add cp210x support for icount to detect parity error in received data >> Motivation - current version of cp210x driver doesn't provide any way to detect >> a parity error in received data from userspace. Some serial protocols like STM32 >> bootloader protect data only by even parity so application needs to detect >> whether parity error happened to read again peripheral data. >> >> I created a simple patch which adds support for icount (ioctl TIOCGICOUNT) which >> sends GET_COMM_STATUS command to CP210X and according received flags increments >> fields for parity error, frame error, break and overrun. >> So application can detect an error condition after reading data from ttyUSB >> and repeat operation. There is no impact for applications which don't >> call ioctl TIOCGICOUNT. >> This patch is also placed at http://yyy.jrr.cz/cp210x.patch (my first patch) > Please read the section entitled "The canonical patch format" in the > kernel file, Documentation/SubmittingPatches for what is needed in order > to properly describe the change. I read it, but still not sure what exactly was wrong? Yes, I wrapped lines of description to 80 colums and now I noticed that only 75 columns is allowed but I doubt that it is all? Sorry for my bad English, it is hard to guess whether you see a problem in function of patch, patch formatting, tab/spaces, description content, spelling, line wrapping, mail client identification, something else or all of them? >> Signed-off-by: Jaromir Skorpil <Jerry@jrr.cz> > This does not match your From: line :( I supposed that only mail address in From line matter? I understand that real name is mandatory only for Signed-off-by field? > > thanks, > > greg k-h Jerry ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/1] usbserial: cp210x - icount support for parity error checking 2020-06-21 9:45 ` Jerry @ 2020-06-21 9:55 ` Greg Kroah-Hartman 2020-06-21 10:34 ` Jerry 0 siblings, 1 reply; 28+ messages in thread From: Greg Kroah-Hartman @ 2020-06-21 9:55 UTC (permalink / raw) To: Jerry; +Cc: Johan Hovold, linux-usb On Sun, Jun 21, 2020 at 11:45:11AM +0200, Jerry wrote: > Greg Kroah-Hartman wrote on 6/21/20 10:58 AM: > > On Sat, Jun 20, 2020 at 09:58:40PM +0200, Jerry wrote: > > > usbserial: add cp210x support for icount to detect parity error in received data > > Why is this here? > > > Because it seems be mandatory? > https://www.kernel.org/doc/html/latest/process/5.Posting.html#patch-formatting-and-changelogs > > "A one-line description of what the patch does. This message should be > enough for a reader who sees it with no other context to figure out the > scope of the patch; it is the line that will show up in the “short form” > changelogs. This message is usually formatted with the relevant subsystem > name first, followed by the purpose of the patch. For example: > gpio: fix build on CONFIG_GPIO_SYSFS=n" Yes, that should have been the first line of the git commit, which ends up being the subject line for your email. > Did I misunderstand your rule or used wrong name of subsystem? Should I > type? > USB serial: add cp210x support for icount to detect parity error in received > data That would have been fine too, you can't do it twice, once as a subject and once as the first line in the email, otherwise that would look really odd, right? > > > Motivation - current version of cp210x driver doesn't provide any way to detect > > > a parity error in received data from userspace. Some serial protocols like STM32 > > > bootloader protect data only by even parity so application needs to detect > > > whether parity error happened to read again peripheral data. > > > > > > I created a simple patch which adds support for icount (ioctl TIOCGICOUNT) which > > > sends GET_COMM_STATUS command to CP210X and according received flags increments > > > fields for parity error, frame error, break and overrun. > > > So application can detect an error condition after reading data from ttyUSB > > > and repeat operation. There is no impact for applications which don't > > > call ioctl TIOCGICOUNT. > > > This patch is also placed at http://yyy.jrr.cz/cp210x.patch (my first patch) > > Please read the section entitled "The canonical patch format" in the > > kernel file, Documentation/SubmittingPatches for what is needed in order > > to properly describe the change. > I read it, but still not sure what exactly was wrong? Yes, I wrapped lines > of description to 80 colums and now I noticed that only 75 columns is > allowed but I doubt that it is all? That is one thing, but also the "This patch..." should not be in a changelog, right? Look at the other changes sent to the list for examples of how to do this. > > > Signed-off-by: Jaromir Skorpil <Jerry@jrr.cz> > > This does not match your From: line :( > I supposed that only mail address in From line matter? > I understand that real name is mandatory only for Signed-off-by field? It has to match the From: line of your email to ensure that this really is the same person. thanks, greg k-h ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/1] usbserial: cp210x - icount support for parity error checking 2020-06-21 9:55 ` Greg Kroah-Hartman @ 2020-06-21 10:34 ` Jerry 2020-06-21 13:58 ` Greg Kroah-Hartman 0 siblings, 1 reply; 28+ messages in thread From: Jerry @ 2020-06-21 10:34 UTC (permalink / raw) To: Greg Kroah-Hartman; +Cc: Johan Hovold, linux-usb Greg Kroah-Hartman wrote on 6/21/20 11:55 AM: >> I read it, but still not sure what exactly was wrong? Yes, I wrapped lines >> of description to 80 colums and now I noticed that only 75 columns is >> allowed but I doubt that it is all? > That is one thing, but also the "This patch..." should not be in a > changelog, right? Look at the other changes sent to the list for > examples of how to do this. Yes, I looked at another messages here and there are a lot of things which I don't understand. For example two dash -- marker at the end (bellow patch) with some strange number (2.7.4). I didn't find anything about that in documentation. And documentation request diff -up https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html#diff-up but patches here use another settings because diff -up never give me line like index 86638c1..f1b46b5 100644 before file names but put me file date and time next to filename. So what version of diff should I use? I have diff (GNU diffutils) 3.7 > >>>> Signed-off-by: Jaromir Skorpil <Jerry@jrr.cz> >>> This does not match your From: line :( >> I supposed that only mail address in From line matter? >> I understand that real name is mandatory only for Signed-off-by field? > It has to match the From: line of your email to ensure that this really > is the same person. Really? I looked at another message as you advised and it seems that even YOUR name often changes? https://marc.info/?l=linux-usb&m=159257306831535 https://marc.info/?l=linux-usb&m=159256948030250 Why is a name so important when you can't verify it? Typing the same text twice doesn't prove anything. In fact my real name can't be written in ascii because of diacritics marks and I doubt that it will work here correctly if I use unicode... > thanks, > > greg k-h Jerry ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/1] usbserial: cp210x - icount support for parity error checking 2020-06-21 10:34 ` Jerry @ 2020-06-21 13:58 ` Greg Kroah-Hartman 2020-06-21 20:21 ` [PATCH v3] " Jaromír Škorpil 2020-06-22 4:38 ` [PATCH 1/1] " Jerry 0 siblings, 2 replies; 28+ messages in thread From: Greg Kroah-Hartman @ 2020-06-21 13:58 UTC (permalink / raw) To: Jerry; +Cc: Johan Hovold, linux-usb On Sun, Jun 21, 2020 at 12:34:52PM +0200, Jerry wrote: > Greg Kroah-Hartman wrote on 6/21/20 11:55 AM: > > > I read it, but still not sure what exactly was wrong? Yes, I wrapped lines > > > of description to 80 colums and now I noticed that only 75 columns is > > > allowed but I doubt that it is all? > > That is one thing, but also the "This patch..." should not be in a > > changelog, right? Look at the other changes sent to the list for > > examples of how to do this. > Yes, I looked at another messages here and there are a lot of things which I > don't understand. For example two dash -- marker at the end (bellow patch) > with some strange number (2.7.4). I didn't find anything about that in > documentation. That is the git version number, and you can ignore it. > And documentation request diff -up > https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html#diff-up > but patches here use another settings because diff -up never give me line > like > index 86638c1..f1b46b5 100644 > before file names but put me file date and time next to filename. So what > version of diff should I use? I have diff (GNU diffutils) 3.7 git creates that, if you use it for creating a diff. If you want to use diff "by hand", you can do that too, I was not objecting to that at all. The only problems I found was in your changelog text, and your email header. > > > > > Signed-off-by: Jaromir Skorpil <Jerry@jrr.cz> > > > > This does not match your From: line :( > > > I supposed that only mail address in From line matter? > > > I understand that real name is mandatory only for Signed-off-by field? > > It has to match the From: line of your email to ensure that this really > > is the same person. > Really? > I looked at another message as you advised and it seems that even YOUR name > often changes? > https://marc.info/?l=linux-usb&m=159257306831535 > https://marc.info/?l=linux-usb&m=159256948030250 Short name vs. "real name" doesn't matter much when sending email text responses, but it does when sending patches, as you are making a legal agreement about that signed-off-by text. So it has to be the same, otherwise I can not take your patch. > Why is a name so important when you can't verify it? Typing the same text > twice doesn't prove anything. In fact my real name can't be written in ascii > because of diacritics marks and I doubt that it will work here correctly if > I use unicode... Please use unicode (well utf-8 if possible), I'm all for that, there is no requirement to use ascii only for your name in patches. I wish more people would do that when needed, as it's only fair to them to be able to properly represent their names and not have to change them somehow. thanks, greg k-h ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3] usbserial: cp210x - icount support for parity error checking 2020-06-21 13:58 ` Greg Kroah-Hartman @ 2020-06-21 20:21 ` Jaromír Škorpil 2020-06-22 5:31 ` Greg Kroah-Hartman 2020-06-22 4:38 ` [PATCH 1/1] " Jerry 1 sibling, 1 reply; 28+ messages in thread From: Jaromír Škorpil @ 2020-06-21 20:21 UTC (permalink / raw) To: Greg Kroah-Hartman, linux-usb; +Cc: Johan Hovold The current version of cp210x driver doesn't provide any way to detect a parity error in received data from userspace. Some serial protocols like STM32 bootloader protect data only by parity so application needs to know whether parity error happened to repeat peripheral data reading. Added support for icount (ioctl TIOCGICOUNT) which sends GET_COMM_STATUS command to CP210X and according received flags increments fields for parity error, frame error, break and overrun. An application can detect an error condition after reading data from ttyUSB and reacts adequately. There is no impact for applications which don't call ioctl TIOCGICOUNT. The flag "hardware overrun" is not examined because CP2102 sets this bit for the first received byte after openning of port which was previously closed with some unreaded data in buffer. This is confusing and checking "queue overrun" flag seems be enough. Signed-off-by: Jaromír Škorpil <Jerry@jrr.cz> --- v2: Simplified counting - only queue overrun checked v3: Changed description + UTF-8 name ;-) cp210x.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff -up linux-5.8-rc1/drivers/usb/serial/cp210x.c j/drivers/usb/serial/cp210x.c --- linux-5.8-rc1/drivers/usb/serial/cp210x.c +++ j/drivers/usb/serial/cp210x.c @@ -43,6 +43,8 @@ static int cp210x_tiocmget(struct tty_st static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int); static int cp210x_tiocmset_port(struct usb_serial_port *port, unsigned int, unsigned int); +static int cp210x_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount); static void cp210x_break_ctl(struct tty_struct *, int); static int cp210x_attach(struct usb_serial *); static void cp210x_disconnect(struct usb_serial *); @@ -274,6 +276,7 @@ static struct usb_serial_driver cp210x_d .tx_empty = cp210x_tx_empty, .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, + .get_icount = cp210x_get_icount, .attach = cp210x_attach, .disconnect = cp210x_disconnect, .release = cp210x_release, @@ -393,6 +396,13 @@ struct cp210x_comm_status { u8 bReserved; } __packed; +/* cp210x_comm_status::ulErrors */ +#define CP210X_SERIAL_ERR_BREAK BIT(0) +#define CP210X_SERIAL_ERR_FRAME BIT(1) +#define CP210X_SERIAL_ERR_HW_OVERRUN BIT(2) +#define CP210X_SERIAL_ERR_QUEUE_OVERRUN BIT(3) +#define CP210X_SERIAL_ERR_PARITY BIT(4) + /* * CP210X_PURGE - 16 bits passed in wValue of USB request. * SiLabs app note AN571 gives a strange description of the 4 bits: @@ -836,10 +846,10 @@ static void cp210x_close(struct usb_seri } /* - * Read how many bytes are waiting in the TX queue. + * Read how many bytes are waiting in the TX queue and update error counters. */ -static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port, - u32 *count) +static int cp210x_get_comm_status(struct usb_serial_port *port, + u32 *tx_count) { struct usb_serial *serial = port->serial; struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); @@ -855,7 +865,16 @@ static int cp210x_get_tx_queue_byte_coun 0, port_priv->bInterfaceNumber, sts, sizeof(*sts), USB_CTRL_GET_TIMEOUT); if (result == sizeof(*sts)) { - *count = le32_to_cpu(sts->ulAmountInOutQueue); + if (tx_count) + *tx_count = le32_to_cpu(sts->ulAmountInOutQueue); + if (sts->ulErrors & CP210X_SERIAL_ERR_BREAK) + port->icount.brk++; + if (sts->ulErrors & CP210X_SERIAL_ERR_FRAME) + port->icount.frame++; + if (sts->ulErrors & CP210X_SERIAL_ERR_QUEUE_OVERRUN) + port->icount.overrun++; + if (sts->ulErrors & CP210X_SERIAL_ERR_PARITY) + port->icount.parity++; result = 0; } else { dev_err(&port->dev, "failed to get comm status: %d\n", result); @@ -873,13 +892,26 @@ static bool cp210x_tx_empty(struct usb_s int err; u32 count; - err = cp210x_get_tx_queue_byte_count(port, &count); + err = cp210x_get_comm_status(port, &count); if (err) return true; return !count; } +static int cp210x_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct usb_serial_port *port = tty->driver_data; + int result; + + result = cp210x_get_comm_status(port, NULL); + if (result) + return result; + + return usb_serial_generic_get_icount(tty, icount); +} + /* * cp210x_get_termios * Reads the baud rate, data bits, parity, stop bits and flow control mode ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v3] usbserial: cp210x - icount support for parity error checking 2020-06-21 20:21 ` [PATCH v3] " Jaromír Škorpil @ 2020-06-22 5:31 ` Greg Kroah-Hartman 2020-06-22 15:13 ` [PATCH v4] " Jaromír Škorpil 0 siblings, 1 reply; 28+ messages in thread From: Greg Kroah-Hartman @ 2020-06-22 5:31 UTC (permalink / raw) To: Jaromír Škorpil; +Cc: linux-usb, Johan Hovold On Sun, Jun 21, 2020 at 10:21:11PM +0200, Jaromír Škorpil wrote: > The current version of cp210x driver doesn't provide any way to detect > a parity error in received data from userspace. Some serial protocols like > STM32 bootloader protect data only by parity so application needs to > know whether parity error happened to repeat peripheral data reading. > > Added support for icount (ioctl TIOCGICOUNT) which sends GET_COMM_STATUS > command to CP210X and according received flags increments fields for > parity error, frame error, break and overrun. An application can detect > an error condition after reading data from ttyUSB and reacts adequately. > There is no impact for applications which don't call ioctl TIOCGICOUNT. > > The flag "hardware overrun" is not examined because CP2102 sets this bit > for the first received byte after openning of port which was previously > closed with some unreaded data in buffer. This is confusing and checking > "queue overrun" flag seems be enough. > > Signed-off-by: Jaromír Škorpil <Jerry@jrr.cz> > --- > v2: Simplified counting - only queue overrun checked > v3: Changed description + UTF-8 name ;-) Much nicer, thanks for the changes! I'll let Johan comment on the actual patch itself, as he's the maintainer of this driver/subsystems. thanks, greg k-h ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-06-22 5:31 ` Greg Kroah-Hartman @ 2020-06-22 15:13 ` Jaromír Škorpil 2020-06-25 4:31 ` Jerry ` (2 more replies) 0 siblings, 3 replies; 28+ messages in thread From: Jaromír Škorpil @ 2020-06-22 15:13 UTC (permalink / raw) To: Greg Kroah-Hartman, Johan Hovold; +Cc: linux-usb The current version of cp210x driver doesn't provide any way to detect a parity error in received data from userspace. Some serial protocols like STM32 bootloader protect data only by parity so application needs to know whether parity error happened to repeat peripheral data reading. Added support for icount (ioctl TIOCGICOUNT) which sends GET_COMM_STATUS command to CP210X and according received flags increments fields for parity error, frame error, break and overrun. An application can detect an error condition after reading data from ttyUSB and reacts adequately. There is no impact for applications which don't call ioctl TIOCGICOUNT. The flag "hardware overrun" is not examined because CP2102 sets this bit for the first received byte after openning of port which was previously closed with some unreaded data in buffer. This is confusing and checking "queue overrun" flag seems be enough. Signed-off-by: Jaromír Škorpil <Jerry@jrr.cz> --- v2: Simplified counting - only queue overrun checked v3: Changed description + UTF8 name v4: Corrected endian cp210x.c | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff -up linux-5.8-rc1/drivers/usb/serial/cp210x.c j/drivers/usb/serial/cp210x.c --- linux-5.8-rc1/drivers/usb/serial/cp210x.c +++ j/drivers/usb/serial/cp210x.c @@ -43,6 +43,8 @@ static int cp210x_tiocmget(struct tty_st static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int); static int cp210x_tiocmset_port(struct usb_serial_port *port, unsigned int, unsigned int); +static int cp210x_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount); static void cp210x_break_ctl(struct tty_struct *, int); static int cp210x_attach(struct usb_serial *); static void cp210x_disconnect(struct usb_serial *); @@ -274,6 +276,7 @@ static struct usb_serial_driver cp210x_d .tx_empty = cp210x_tx_empty, .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, + .get_icount = cp210x_get_icount, .attach = cp210x_attach, .disconnect = cp210x_disconnect, .release = cp210x_release, @@ -393,6 +396,13 @@ struct cp210x_comm_status { u8 bReserved; } __packed; +/* cp210x_comm_status::ulErrors */ +#define CP210X_SERIAL_ERR_BREAK BIT(0) +#define CP210X_SERIAL_ERR_FRAME BIT(1) +#define CP210X_SERIAL_ERR_HW_OVERRUN BIT(2) +#define CP210X_SERIAL_ERR_QUEUE_OVERRUN BIT(3) +#define CP210X_SERIAL_ERR_PARITY BIT(4) + /* * CP210X_PURGE - 16 bits passed in wValue of USB request. * SiLabs app note AN571 gives a strange description of the 4 bits: @@ -836,10 +846,10 @@ static void cp210x_close(struct usb_seri } /* - * Read how many bytes are waiting in the TX queue. + * Read how many bytes are waiting in the TX queue and update error counters. */ -static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port, - u32 *count) +static int cp210x_get_comm_status(struct usb_serial_port *port, + u32 *tx_count) { struct usb_serial *serial = port->serial; struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); @@ -855,7 +865,17 @@ static int cp210x_get_tx_queue_byte_coun 0, port_priv->bInterfaceNumber, sts, sizeof(*sts), USB_CTRL_GET_TIMEOUT); if (result == sizeof(*sts)) { - *count = le32_to_cpu(sts->ulAmountInOutQueue); + u32 flags = le32_to_cpu(sts->ulErrors); + if (flags & CP210X_SERIAL_ERR_BREAK) + port->icount.brk++; + if (flags & CP210X_SERIAL_ERR_FRAME) + port->icount.frame++; + if (flags & CP210X_SERIAL_ERR_QUEUE_OVERRUN) + port->icount.overrun++; + if (flags & CP210X_SERIAL_ERR_PARITY) + port->icount.parity++; + if (tx_count) + *tx_count = le32_to_cpu(sts->ulAmountInOutQueue); result = 0; } else { dev_err(&port->dev, "failed to get comm status: %d\n", result); @@ -873,13 +893,26 @@ static bool cp210x_tx_empty(struct usb_s int err; u32 count; - err = cp210x_get_tx_queue_byte_count(port, &count); + err = cp210x_get_comm_status(port, &count); if (err) return true; return !count; } +static int cp210x_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct usb_serial_port *port = tty->driver_data; + int result; + + result = cp210x_get_comm_status(port, NULL); + if (result) + return result; + + return usb_serial_generic_get_icount(tty, icount); +} + /* * cp210x_get_termios * Reads the baud rate, data bits, parity, stop bits and flow control mode ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-06-22 15:13 ` [PATCH v4] " Jaromír Škorpil @ 2020-06-25 4:31 ` Jerry 2020-06-25 6:53 ` Johan Hovold 2020-07-01 15:42 ` Johan Hovold 2020-07-06 9:08 ` Johan Hovold 2 siblings, 1 reply; 28+ messages in thread From: Jerry @ 2020-06-25 4:31 UTC (permalink / raw) To: Greg Kroah-Hartman, Johan Hovold; +Cc: linux-usb Hello, can I do anything more for this patch? Jaromír Škorpil wrote on 6/22/20 5:13 PM: > The current version of cp210x driver doesn't provide any way to detect > a parity error in received data from userspace. Some serial protocols like > STM32 bootloader protect data only by parity so application needs to > know whether parity error happened to repeat peripheral data reading. > > Added support for icount (ioctl TIOCGICOUNT) which sends GET_COMM_STATUS > command to CP210X and according received flags increments fields for > parity error, frame error, break and overrun. An application can detect > an error condition after reading data from ttyUSB and reacts adequately. > There is no impact for applications which don't call ioctl TIOCGICOUNT. > > The flag "hardware overrun" is not examined because CP2102 sets this bit > for the first received byte after openning of port which was previously > closed with some unreaded data in buffer. This is confusing and checking > "queue overrun" flag seems be enough. > > Signed-off-by: Jaromír Škorpil <Jerry@jrr.cz> > --- > v2: Simplified counting - only queue overrun checked > v3: Changed description + UTF8 name > v4: Corrected endian > > cp210x.c | 43 ++++++++++++++++++++++++++++++++++++++----- > 1 file changed, 38 insertions(+), 5 deletions(-) > > diff -up linux-5.8-rc1/drivers/usb/serial/cp210x.c > j/drivers/usb/serial/cp210x.c > --- linux-5.8-rc1/drivers/usb/serial/cp210x.c > +++ j/drivers/usb/serial/cp210x.c > @@ -43,6 +43,8 @@ static int cp210x_tiocmget(struct tty_st > static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned > int); > static int cp210x_tiocmset_port(struct usb_serial_port *port, > unsigned int, unsigned int); > +static int cp210x_get_icount(struct tty_struct *tty, > + struct serial_icounter_struct *icount); > static void cp210x_break_ctl(struct tty_struct *, int); > static int cp210x_attach(struct usb_serial *); > static void cp210x_disconnect(struct usb_serial *); > @@ -274,6 +276,7 @@ static struct usb_serial_driver cp210x_d > .tx_empty = cp210x_tx_empty, > .tiocmget = cp210x_tiocmget, > .tiocmset = cp210x_tiocmset, > + .get_icount = cp210x_get_icount, > .attach = cp210x_attach, > .disconnect = cp210x_disconnect, > .release = cp210x_release, > @@ -393,6 +396,13 @@ struct cp210x_comm_status { > u8 bReserved; > } __packed; > > +/* cp210x_comm_status::ulErrors */ > +#define CP210X_SERIAL_ERR_BREAK BIT(0) > +#define CP210X_SERIAL_ERR_FRAME BIT(1) > +#define CP210X_SERIAL_ERR_HW_OVERRUN BIT(2) > +#define CP210X_SERIAL_ERR_QUEUE_OVERRUN BIT(3) > +#define CP210X_SERIAL_ERR_PARITY BIT(4) > + > /* > * CP210X_PURGE - 16 bits passed in wValue of USB request. > * SiLabs app note AN571 gives a strange description of the 4 bits: > @@ -836,10 +846,10 @@ static void cp210x_close(struct usb_seri > } > > /* > - * Read how many bytes are waiting in the TX queue. > + * Read how many bytes are waiting in the TX queue and update error > counters. > */ > -static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port, > - u32 *count) > +static int cp210x_get_comm_status(struct usb_serial_port *port, > + u32 *tx_count) > { > struct usb_serial *serial = port->serial; > struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); > @@ -855,7 +865,17 @@ static int cp210x_get_tx_queue_byte_coun > 0, port_priv->bInterfaceNumber, sts, sizeof(*sts), > USB_CTRL_GET_TIMEOUT); > if (result == sizeof(*sts)) { > - *count = le32_to_cpu(sts->ulAmountInOutQueue); > + u32 flags = le32_to_cpu(sts->ulErrors); > + if (flags & CP210X_SERIAL_ERR_BREAK) > + port->icount.brk++; > + if (flags & CP210X_SERIAL_ERR_FRAME) > + port->icount.frame++; > + if (flags & CP210X_SERIAL_ERR_QUEUE_OVERRUN) > + port->icount.overrun++; > + if (flags & CP210X_SERIAL_ERR_PARITY) > + port->icount.parity++; > + if (tx_count) > + *tx_count = le32_to_cpu(sts->ulAmountInOutQueue); > result = 0; > } else { > dev_err(&port->dev, "failed to get comm status: %d\n", result); > @@ -873,13 +893,26 @@ static bool cp210x_tx_empty(struct usb_s > int err; > u32 count; > > - err = cp210x_get_tx_queue_byte_count(port, &count); > + err = cp210x_get_comm_status(port, &count); > if (err) > return true; > > return !count; > } > > +static int cp210x_get_icount(struct tty_struct *tty, > + struct serial_icounter_struct *icount) > +{ > + struct usb_serial_port *port = tty->driver_data; > + int result; > + > + result = cp210x_get_comm_status(port, NULL); > + if (result) > + return result; > + > + return usb_serial_generic_get_icount(tty, icount); > +} > + > /* > * cp210x_get_termios > * Reads the baud rate, data bits, parity, stop bits and flow control mode > > > ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-06-25 4:31 ` Jerry @ 2020-06-25 6:53 ` Johan Hovold 0 siblings, 0 replies; 28+ messages in thread From: Johan Hovold @ 2020-06-25 6:53 UTC (permalink / raw) To: Jerry; +Cc: Greg Kroah-Hartman, Johan Hovold, linux-usb On Thu, Jun 25, 2020 at 06:31:09AM +0200, Jerry wrote: > Hello, can I do anything more for this patch? You posted the last update only this Monday. I'll try to review it next week. Johan ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-06-22 15:13 ` [PATCH v4] " Jaromír Škorpil 2020-06-25 4:31 ` Jerry @ 2020-07-01 15:42 ` Johan Hovold 2020-07-01 19:28 ` Jerry 2020-07-06 9:08 ` Johan Hovold 2 siblings, 1 reply; 28+ messages in thread From: Johan Hovold @ 2020-07-01 15:42 UTC (permalink / raw) To: Jaromír Škorpil; +Cc: Greg Kroah-Hartman, Johan Hovold, linux-usb On Mon, Jun 22, 2020 at 05:13:41PM +0200, Jaromír Škorpil wrote: > The current version of cp210x driver doesn't provide any way to detect > a parity error in received data from userspace. Some serial protocols like > STM32 bootloader protect data only by parity so application needs to > know whether parity error happened to repeat peripheral data reading. > > Added support for icount (ioctl TIOCGICOUNT) which sends GET_COMM_STATUS > command to CP210X and according received flags increments fields for > parity error, frame error, break and overrun. An application can detect > an error condition after reading data from ttyUSB and reacts adequately. > There is no impact for applications which don't call ioctl TIOCGICOUNT. > > The flag "hardware overrun" is not examined because CP2102 sets this bit > for the first received byte after openning of port which was previously > closed with some unreaded data in buffer. This is confusing and checking > "queue overrun" flag seems be enough. It would be better if could detect both types of overrun. Did you try moving the purge command at close to after disabling the uart? Or perhaps we can add a "dummy" comm-status command after disabling the uart? > Signed-off-by: Jaromír Škorpil <Jerry@jrr.cz> > --- > v2: Simplified counting - only queue overrun checked > v3: Changed description + UTF8 name > v4: Corrected endian > > cp210x.c | 43 ++++++++++++++++++++++++++++++++++++++----- > 1 file changed, 38 insertions(+), 5 deletions(-) > > diff -up linux-5.8-rc1/drivers/usb/serial/cp210x.c j/drivers/usb/serial/cp210x.c > --- linux-5.8-rc1/drivers/usb/serial/cp210x.c > +++ j/drivers/usb/serial/cp210x.c > @@ -43,6 +43,8 @@ static int cp210x_tiocmget(struct tty_st > static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int); > static int cp210x_tiocmset_port(struct usb_serial_port *port, > unsigned int, unsigned int); > +static int cp210x_get_icount(struct tty_struct *tty, > + struct serial_icounter_struct *icount); > static void cp210x_break_ctl(struct tty_struct *, int); > static int cp210x_attach(struct usb_serial *); > static void cp210x_disconnect(struct usb_serial *); > @@ -274,6 +276,7 @@ static struct usb_serial_driver cp210x_d > .tx_empty = cp210x_tx_empty, > .tiocmget = cp210x_tiocmget, > .tiocmset = cp210x_tiocmset, > + .get_icount = cp210x_get_icount, > .attach = cp210x_attach, > .disconnect = cp210x_disconnect, > .release = cp210x_release, > @@ -393,6 +396,13 @@ struct cp210x_comm_status { > u8 bReserved; > } __packed; > > +/* cp210x_comm_status::ulErrors */ > +#define CP210X_SERIAL_ERR_BREAK BIT(0) > +#define CP210X_SERIAL_ERR_FRAME BIT(1) > +#define CP210X_SERIAL_ERR_HW_OVERRUN BIT(2) > +#define CP210X_SERIAL_ERR_QUEUE_OVERRUN BIT(3) > +#define CP210X_SERIAL_ERR_PARITY BIT(4) > + > /* > * CP210X_PURGE - 16 bits passed in wValue of USB request. > * SiLabs app note AN571 gives a strange description of the 4 bits: > @@ -836,10 +846,10 @@ static void cp210x_close(struct usb_seri > } > > /* > - * Read how many bytes are waiting in the TX queue. > + * Read how many bytes are waiting in the TX queue and update error counters. > */ > -static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port, > - u32 *count) > +static int cp210x_get_comm_status(struct usb_serial_port *port, > + u32 *tx_count) > { > struct usb_serial *serial = port->serial; > struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); > @@ -855,7 +865,17 @@ static int cp210x_get_tx_queue_byte_coun > 0, port_priv->bInterfaceNumber, sts, sizeof(*sts), > USB_CTRL_GET_TIMEOUT); > if (result == sizeof(*sts)) { > - *count = le32_to_cpu(sts->ulAmountInOutQueue); > + u32 flags = le32_to_cpu(sts->ulErrors); > + if (flags & CP210X_SERIAL_ERR_BREAK) > + port->icount.brk++; > + if (flags & CP210X_SERIAL_ERR_FRAME) > + port->icount.frame++; > + if (flags & CP210X_SERIAL_ERR_QUEUE_OVERRUN) > + port->icount.overrun++; > + if (flags & CP210X_SERIAL_ERR_PARITY) > + port->icount.parity++; > + if (tx_count) > + *tx_count = le32_to_cpu(sts->ulAmountInOutQueue); > result = 0; > } else { > dev_err(&port->dev, "failed to get comm status: %d\n", result); > @@ -873,13 +893,26 @@ static bool cp210x_tx_empty(struct usb_s > int err; > u32 count; > > - err = cp210x_get_tx_queue_byte_count(port, &count); > + err = cp210x_get_comm_status(port, &count); > if (err) > return true; > > return !count; > } It seems a bit weird to be updating the error counters while polling for tx-empty during close. How about having cp210x_get_comm_status() take two u32 pointers for tx_count and errors and only pass in one or the other from cp210x_tx_empty() and cp210x_get_icount() respectively? > +static int cp210x_get_icount(struct tty_struct *tty, > + struct serial_icounter_struct *icount) > +{ > + struct usb_serial_port *port = tty->driver_data; > + int result; > + > + result = cp210x_get_comm_status(port, NULL); > + if (result) > + return result; And then you update the error counters here, preferably under the port lock. > + > + return usb_serial_generic_get_icount(tty, icount); > +} > + > /* > * cp210x_get_termios > * Reads the baud rate, data bits, parity, stop bits and flow control mode > > > Johan ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-07-01 15:42 ` Johan Hovold @ 2020-07-01 19:28 ` Jerry 2020-07-03 7:45 ` Johan Hovold 0 siblings, 1 reply; 28+ messages in thread From: Jerry @ 2020-07-01 19:28 UTC (permalink / raw) To: Johan Hovold; +Cc: Greg Kroah-Hartman, linux-usb Johan Hovold wrote on 7/1/20 5:42 PM: > It would be better if could detect both types of overrun. > > Did you try moving the purge command at close to after disabling the > uart? > > Or perhaps we can add a "dummy" comm-status command after disabling the > uart? Hello I try to describe more details about this overrun problem: 1) I tried only CP2102 because our company uses it, I have no idea whether the same apply for CP2104,2105... or not, I don't have another chip. 2) Maybe I should note I'm always using even parity (because of STM32 bootloader protocol). 3) I thought the problem is created by unreaded data when closing because overrun was reported after closing if GET_COMM_STATUS shown positive ulAmountInInQueue before closing. Later I discovered that if I close the port, wait, send some data from outside, then open it, I will also get HW_OVERRUN flag. 4) So currently I suppose that problem is usually created by any incoming data after disabling interface. If I remove UART_DISABLE from close method, no overrun ever reported. 5) Unfortunately this overrun is not reported immediately after port opening but later after receiving first byte. I didn't find any way how to purge nor dummy read this flag before transmitting data. 6) I didn't find this problem in a chip errata and nobody complaining about it. 7) I successfully reproduced the same problem in MS Windows 10. If some data arrived to closed port, then I open it, everything is OK but after sending request and receiving reply I often get overrun indication from Win32 API ClearCommError() 8) I removed HW_OVERRUN checking because I don't want to break anything but maybe Linux driver should work the same way as Windows and don't hide this problem? 9) I needed just to detect parity error from user space and things complicate. :-) >> >> /* >> - * Read how many bytes are waiting in the TX queue. >> + * Read how many bytes are waiting in the TX queue and update error counters. >> */ >> -static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port, >> - u32 *count) >> +static int cp210x_get_comm_status(struct usb_serial_port *port, >> + u32 *tx_count) >> { >> struct usb_serial *serial = port->serial; >> struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); >> @@ -855,7 +865,17 @@ static int cp210x_get_tx_queue_byte_coun >> 0, port_priv->bInterfaceNumber, sts, sizeof(*sts), >> USB_CTRL_GET_TIMEOUT); >> if (result == sizeof(*sts)) { >> - *count = le32_to_cpu(sts->ulAmountInOutQueue); >> + u32 flags = le32_to_cpu(sts->ulErrors); >> + if (flags & CP210X_SERIAL_ERR_BREAK) >> + port->icount.brk++; >> + if (flags & CP210X_SERIAL_ERR_FRAME) >> + port->icount.frame++; >> + if (flags & CP210X_SERIAL_ERR_QUEUE_OVERRUN) >> + port->icount.overrun++; >> + if (flags & CP210X_SERIAL_ERR_PARITY) >> + port->icount.parity++; >> + if (tx_count) >> + *tx_count = le32_to_cpu(sts->ulAmountInOutQueue); >> result = 0; >> } else { >> dev_err(&port->dev, "failed to get comm status: %d\n", result); >> @@ -873,13 +893,26 @@ static bool cp210x_tx_empty(struct usb_s >> int err; >> u32 count; >> >> - err = cp210x_get_tx_queue_byte_count(port, &count); >> + err = cp210x_get_comm_status(port, &count); >> if (err) >> return true; >> >> return !count; >> } > It seems a bit weird to be updating the error counters while polling > for tx-empty during close. How about having cp210x_get_comm_status() > take two u32 pointers for tx_count and errors and only pass in one or > the other from cp210x_tx_empty() and cp210x_get_icount() respectively? I suppose that GET_COMM_STATUS reads and CLEAR pending error flags (not explained in datasheet but behaves that way). So if some errors are reported during cp210x_tx_empty() it can be either counted immediately or lost. I'm not sure if cp210x_tx_empty() is called ONLY during close but seems be more consistent to count every detected error regardless who calls GET_COMM_STATUS. >> +static int cp210x_get_icount(struct tty_struct *tty, >> + struct serial_icounter_struct *icount) >> +{ >> + struct usb_serial_port *port = tty->driver_data; >> + int result; >> + >> + result = cp210x_get_comm_status(port, NULL); >> + if (result) >> + return result; > And then you update the error counters here, preferably under the port > lock. > I wasn't sure about port lock. I looked in several usb drivers (ftdi, pl2303) and it seems that port->icount.xxx increments are usually done out of lock. But if you wish I put increments into spin_lock_irqsave(&port->lock, flags), correct? > Johan Jerry ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-07-01 19:28 ` Jerry @ 2020-07-03 7:45 ` Johan Hovold 2020-07-03 15:01 ` Johan Hovold 2020-07-03 18:45 ` Jerry 0 siblings, 2 replies; 28+ messages in thread From: Johan Hovold @ 2020-07-03 7:45 UTC (permalink / raw) To: Jerry; +Cc: Johan Hovold, Greg Kroah-Hartman, linux-usb On Wed, Jul 01, 2020 at 09:28:25PM +0200, Jerry wrote: > Johan Hovold wrote on 7/1/20 5:42 PM: > > It would be better if could detect both types of overrun. > > > > Did you try moving the purge command at close to after disabling the > > uart? > > > > Or perhaps we can add a "dummy" comm-status command after disabling the > > uart? > I try to describe more details about this overrun problem: > 1) I tried only CP2102 because our company uses it, I have no idea whether > the same apply for CP2104,2105... or not, I don't have another chip. > 2) Maybe I should note I'm always using even parity (because of STM32 > bootloader protocol). > 3) I thought the problem is created by unreaded data when closing because > overrun was reported after closing if GET_COMM_STATUS shown positive > ulAmountInInQueue before closing. Later I discovered that if I close the > port, wait, send some data from outside, then open it, I will also get > HW_OVERRUN flag. > 4) So currently I suppose that problem is usually created by any incoming > data after disabling interface. If I remove UART_DISABLE from close method, > no overrun ever reported. > 5) Unfortunately this overrun is not reported immediately after port > opening but later after receiving first byte. I didn't find any way how to > purge nor dummy read this flag before transmitting data. > 6) I didn't find this problem in a chip errata and nobody complaining about it. > 7) I successfully reproduced the same problem in MS Windows 10. If some > data arrived to closed port, then I open it, everything is OK but after > sending request and receiving reply I often get overrun indication from > Win32 API ClearCommError() > 8) I removed HW_OVERRUN checking because I don't want to break anything but > maybe Linux driver should work the same way as Windows and don't hide this > problem? > 9) I needed just to detect parity error from user space and things > complicate. :-) Heh, yeah, it tends to be that way. :) But thanks for the great summary of your findings! I think it probably makes most sense to keep the error in as it's a quirk of the device rather than risk missing an actual overrun. The problem here is that we're sort of violating the API and turning TIOCGICOUNT into a polling interface instead of just returning our error and interrupt counters. This means will always undercount any errors for a start. The chip appears to have a mechanism for reporting errors in-band, but that would amount to processing every character received to look for the escape char, which adds overhead. I'm guessing that interface would also insert an overrun error when returning the first character. But perhaps that it was we should be using as it allows parity the errors to be reported using the normal in-band methods. If we only enable it when parity checking is enabled then the overhead seems justified. I did a quick test here and the event insertion appears to work well for parity errors. Didn't manage to get it to report break events yet, and modem-status changes are being buffered and not reported until the next character. But in theory we could expand the implementation to provide more features later. I'll see if I can cook something up quickly. > >> /* > >> - * Read how many bytes are waiting in the TX queue. > >> + * Read how many bytes are waiting in the TX queue and update error counters. > >> */ > >> -static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port, > >> - u32 *count) > >> +static int cp210x_get_comm_status(struct usb_serial_port *port, > >> + u32 *tx_count) > >> { > >> struct usb_serial *serial = port->serial; > >> struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); > >> @@ -855,7 +865,17 @@ static int cp210x_get_tx_queue_byte_coun > >> 0, port_priv->bInterfaceNumber, sts, sizeof(*sts), > >> USB_CTRL_GET_TIMEOUT); > >> if (result == sizeof(*sts)) { > >> - *count = le32_to_cpu(sts->ulAmountInOutQueue); > >> + u32 flags = le32_to_cpu(sts->ulErrors); > >> + if (flags & CP210X_SERIAL_ERR_BREAK) > >> + port->icount.brk++; > >> + if (flags & CP210X_SERIAL_ERR_FRAME) > >> + port->icount.frame++; > >> + if (flags & CP210X_SERIAL_ERR_QUEUE_OVERRUN) > >> + port->icount.overrun++; > >> + if (flags & CP210X_SERIAL_ERR_PARITY) > >> + port->icount.parity++; > >> + if (tx_count) > >> + *tx_count = le32_to_cpu(sts->ulAmountInOutQueue); > >> result = 0; > >> } else { > >> dev_err(&port->dev, "failed to get comm status: %d\n", result); > >> @@ -873,13 +893,26 @@ static bool cp210x_tx_empty(struct usb_s > >> int err; > >> u32 count; > >> > >> - err = cp210x_get_tx_queue_byte_count(port, &count); > >> + err = cp210x_get_comm_status(port, &count); > >> if (err) > >> return true; > >> > >> return !count; > >> } > > It seems a bit weird to be updating the error counters while polling > > for tx-empty during close. How about having cp210x_get_comm_status() > > take two u32 pointers for tx_count and errors and only pass in one or > > the other from cp210x_tx_empty() and cp210x_get_icount() respectively? > I suppose that GET_COMM_STATUS reads and CLEAR pending error flags (not > explained in datasheet but behaves that way). So if some errors are > reported during cp210x_tx_empty() it can be either counted immediately or > lost. I'm not sure if cp210x_tx_empty() is called ONLY during close but > seems be more consistent to count every detected error regardless who calls > GET_COMM_STATUS. tx_empty() is called when waiting for data to be drained for example during close but also on when changing terminal settings with TCSADRAIN or on tcdrain(). Since we wouldn't be counting errors during normal operation it seems arbitrary to be counting during these seemingly unrelated calls. Better to only poll from TIOCGICOUNT, if we decide to go with that approach at all. > >> +static int cp210x_get_icount(struct tty_struct *tty, > >> + struct serial_icounter_struct *icount) > >> +{ > >> + struct usb_serial_port *port = tty->driver_data; > >> + int result; > >> + > >> + result = cp210x_get_comm_status(port, NULL); > >> + if (result) > >> + return result; > > And then you update the error counters here, preferably under the port > > lock. > I wasn't sure about port lock. I looked in several usb drivers (ftdi, > pl2303) and it seems that port->icount.xxx increments are usually done out > of lock. But if you wish I put increments into > spin_lock_irqsave(&port->lock, flags), correct? Correct. It's quite possible that that's missing elsewhere, but at least those counters are updated in completion callbacks which do not run in parallel unlike ioctls(), which are not serialised. Johan ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-07-03 7:45 ` Johan Hovold @ 2020-07-03 15:01 ` Johan Hovold 2020-07-06 11:47 ` Jerry 2020-07-03 18:45 ` Jerry 1 sibling, 1 reply; 28+ messages in thread From: Johan Hovold @ 2020-07-03 15:01 UTC (permalink / raw) To: Jerry; +Cc: Johan Hovold, Greg Kroah-Hartman, linux-usb On Fri, Jul 03, 2020 at 09:45:39AM +0200, Johan Hovold wrote: > On Wed, Jul 01, 2020 at 09:28:25PM +0200, Jerry wrote: > > Johan Hovold wrote on 7/1/20 5:42 PM: > > > It would be better if could detect both types of overrun. > > > > > > Did you try moving the purge command at close to after disabling the > > > uart? > > > > > > Or perhaps we can add a "dummy" comm-status command after disabling the > > > uart? > > > I try to describe more details about this overrun problem: > > 1) I tried only CP2102 because our company uses it, I have no idea whether > > the same apply for CP2104,2105... or not, I don't have another chip. > > 2) Maybe I should note I'm always using even parity (because of STM32 > > bootloader protocol). > > 3) I thought the problem is created by unreaded data when closing because > > overrun was reported after closing if GET_COMM_STATUS shown positive > > ulAmountInInQueue before closing. Later I discovered that if I close the > > port, wait, send some data from outside, then open it, I will also get > > HW_OVERRUN flag. > > 4) So currently I suppose that problem is usually created by any incoming > > data after disabling interface. If I remove UART_DISABLE from close method, > > no overrun ever reported. > > 5) Unfortunately this overrun is not reported immediately after port > > opening but later after receiving first byte. I didn't find any way how to > > purge nor dummy read this flag before transmitting data. > > 6) I didn't find this problem in a chip errata and nobody complaining about it. > > 7) I successfully reproduced the same problem in MS Windows 10. If some > > data arrived to closed port, then I open it, everything is OK but after > > sending request and receiving reply I often get overrun indication from > > Win32 API ClearCommError() > > 8) I removed HW_OVERRUN checking because I don't want to break anything but > > maybe Linux driver should work the same way as Windows and don't hide this > > problem? > > 9) I needed just to detect parity error from user space and things > > complicate. :-) > > Heh, yeah, it tends to be that way. :) But thanks for the great summary > of your findings! > > I think it probably makes most sense to keep the error in as it's a > quirk of the device rather than risk missing an actual overrun. > > The problem here is that we're sort of violating the API and turning > TIOCGICOUNT into a polling interface instead of just returning our error > and interrupt counters. This means will always undercount any errors for > a start. > > The chip appears to have a mechanism for reporting errors in-band, but > that would amount to processing every character received to look for the > escape char, which adds overhead. I'm guessing that interface would also > insert an overrun error when returning the first character. > > But perhaps that it was we should be using as it allows parity the > errors to be reported using the normal in-band methods. If we only > enable it when parity checking is enabled then the overhead seems > justified. > > I did a quick test here and the event insertion appears to work well for > parity errors. Didn't manage to get it to report break events yet, and > modem-status changes are being buffered and not reported until the next > character. But in theory we could expand the implementation to provide > more features later. > > I'll see if I can cook something up quickly. Would you mind giving the below a try and see how that works in your setup? With this patch you'd be able to use PARMRK to be notified of any parity errors, but I also wired up TIOCGICOUNT if you prefer to use that. Also, could try and see if your device detects breaks properly? Mine just return a NUL char. Johan From 5fc7de670489a6651e023c325e674666d65cfe14 Mon Sep 17 00:00:00 2001 From: Johan Hovold <johan@kernel.org> Date: Fri, 3 Jul 2020 16:39:14 +0200 Subject: [PATCH] USB: serial: add support for line-status events Add support for line-status events that can be used to detect and report parity errors. Enable the device's event-insertion mode whenever input-parity checking is requested. This will insert line and modem status events into the data stream. Note that modem-status changes appear to be buffered until a character is received and is therefore left unimplemented. On at least one type of these chips, line breaks are also not detected properly and is just reported as a NUL character. I'm therefore not enabling event-insertion when !IGNBRK is requested. Also wire up TIOCGICOUNT to allow for reading out the line-status counters. Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/cp210x.c | 207 +++++++++++++++++++++++++++++++++++- 1 file changed, 204 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index f5143eedbc48..b5f8176ee7ab 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -50,6 +50,9 @@ static void cp210x_release(struct usb_serial *); 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 void cp210x_enable_event_mode(struct usb_serial_port *port); +static void cp210x_disable_event_mode(struct usb_serial_port *port); static const struct usb_device_id id_table[] = { { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */ @@ -253,9 +256,21 @@ struct cp210x_serial_private { bool use_actual_rate; }; +enum cp210x_event_state { + ES_DATA, + ES_ESCAPE, + ES_LSR, + ES_LSR_DATA_0, + ES_LSR_DATA_1, + ES_MSR +}; + struct cp210x_port_private { __u8 bInterfaceNumber; bool has_swapped_line_ctl; + bool event_mode; + enum cp210x_event_state event_state; + u8 lsr; }; static struct usb_serial_driver cp210x_device = { @@ -274,12 +289,14 @@ static struct usb_serial_driver cp210x_device = { .tx_empty = cp210x_tx_empty, .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, + .get_icount = usb_serial_generic_get_icount, .attach = cp210x_attach, .disconnect = cp210x_disconnect, .release = cp210x_release, .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[] = { @@ -401,6 +418,15 @@ struct cp210x_comm_status { */ #define PURGE_ALL 0x000f +/* CP210X_EMBED_EVENTS */ +#define CP210X_ESCCHAR 0xff + +#define CP210X_LSR_OVERRUN BIT(1) +#define CP210X_LSR_PARITY BIT(2) +#define CP210X_LSR_FRAME BIT(3) +#define CP210X_LSR_BREAK BIT(4) + + /* CP210X_GET_FLOW/CP210X_SET_FLOW read/write these 0x10 bytes */ struct cp210x_flow_ctl { __le32 ulControlHandshake; @@ -807,6 +833,7 @@ static int cp210x_get_line_ctl(struct usb_serial_port *port, u16 *ctl) static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) { + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); int result; result = cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_ENABLE); @@ -819,20 +846,151 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) cp210x_get_termios(tty, port); /* The baud rate must be initialised on cp2104 */ - if (tty) + if (tty) { cp210x_change_speed(tty, port, NULL); - return usb_serial_generic_open(tty, port); + /* FIXME: handle from set_termios() only */ + if (I_INPCK(tty)) + cp210x_enable_event_mode(port); + } + + result = usb_serial_generic_open(tty, port); + if (result) + goto err_disable; + + return 0; + +err_disable: + cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_DISABLE); + port_priv->event_mode = false; + + return result; } static void cp210x_close(struct usb_serial_port *port) { + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); + usb_serial_generic_close(port); /* Clear both queues; cp2108 needs this to avoid an occasional hang */ cp210x_write_u16_reg(port, CP210X_PURGE, PURGE_ALL); cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_DISABLE); + + /* Disabling the interface disables event-insertion mode. */ + port_priv->event_mode = false; +} + +static char cp210x_process_lsr(struct usb_serial_port *port, unsigned char lsr) +{ + char flag = TTY_NORMAL; + + if (lsr & CP210X_LSR_BREAK) { + flag = TTY_BREAK; + port->icount.brk++; + /* FIXME: no need to process sysrq chars without breaks... */ + usb_serial_handle_break(port); + } else if (lsr & CP210X_LSR_PARITY) { + flag = TTY_PARITY; + port->icount.parity++; + } else if (lsr & CP210X_LSR_FRAME) { + flag = TTY_FRAME; + port->icount.frame++; + } + + if (lsr & CP210X_LSR_OVERRUN) { + port->icount.overrun++; + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); + } + + return flag; +} + +static bool cp210x_process_event_char(struct usb_serial_port *port, unsigned char *ch, char *flag) +{ + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); + + switch(port_priv->event_state) { + case ES_DATA: + if (*ch == CP210X_ESCCHAR) { + port_priv->event_state = ES_ESCAPE; + break; + } + return false; + case ES_ESCAPE: + switch (*ch) { + case 0: + dev_dbg(&port->dev, "%s - escape char\n", __func__); + *ch = CP210X_ESCCHAR; + port_priv->event_state = ES_DATA; + return false; + case 1: + port_priv->event_state = ES_LSR_DATA_0; + break; + case 2: + port_priv->event_state = ES_LSR; + break; + case 3: + port_priv->event_state = ES_MSR; + break; + default: + dev_err(&port->dev, "malformed event 0x%02x\n", *ch); + port_priv->event_state = ES_DATA; + break; + } + break; + case ES_LSR_DATA_0: + port_priv->lsr = *ch; + port_priv->event_state = ES_LSR_DATA_1; + break; + case ES_LSR_DATA_1: + dev_dbg(&port->dev, "%s - lsr = 0x%02x, data = 0x%02x\n", + __func__, port_priv->lsr, *ch); + *flag = cp210x_process_lsr(port, port_priv->lsr); + port_priv->event_state = ES_DATA; + return false; + case ES_LSR: + dev_dbg(&port->dev, "%s - lsr = 0x%02x\n", __func__, *ch); + port_priv->lsr = *ch; + cp210x_process_lsr(port, port_priv->lsr); + port_priv->event_state = ES_DATA; + break; + case ES_MSR: + dev_dbg(&port->dev, "%s - msr = 0x%02x\n", __func__, *ch); + /* unimplemented */ + port_priv->event_state = ES_DATA; + break; + } + + return true; +} + +static void cp210x_process_read_urb(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); + unsigned char *ch = urb->transfer_buffer; + char flag; + int i; + + if (!urb->actual_length) + return; + + if (!port_priv->event_mode && !(port->port.console && port->sysrq)) { + tty_insert_flip_string(&port->port, ch, urb->actual_length); + } else { + for (i = 0; i < urb->actual_length; i++, ch++) { + flag = TTY_NORMAL; + + if (cp210x_process_event_char(port, ch, &flag)) + continue; + + if (!usb_serial_handle_sysrq_char(port, *ch)) + tty_insert_flip_char(&port->port, *ch, flag); + } + } + tty_flip_buffer_push(&port->port); } /* @@ -1148,6 +1306,41 @@ static void cp210x_change_speed(struct tty_struct *tty, tty_encode_baud_rate(tty, baud, baud); } +static void cp210x_enable_event_mode(struct usb_serial_port *port) +{ + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); + int ret; + + if (port_priv->event_mode) + return; + + port_priv->event_state = ES_DATA; + port_priv->event_mode = true; + + ret = cp210x_write_u16_reg(port, CP210X_EMBED_EVENTS, CP210X_ESCCHAR); + if (ret) { + dev_err(&port->dev, "failed to enable events: %d\n", ret); + port_priv->event_mode = false; + } +} + +static void cp210x_disable_event_mode(struct usb_serial_port *port) +{ + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); + int ret; + + if (!port_priv->event_mode) + return; + + ret = cp210x_write_u16_reg(port, CP210X_EMBED_EVENTS, 0); + if (ret) { + dev_err(&port->dev, "failed to disable events: %d\n", ret); + return; + } + + port_priv->event_mode = false; +} + static void cp210x_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { @@ -1270,6 +1463,14 @@ static void cp210x_set_termios(struct tty_struct *tty, sizeof(flow_ctl)); } + /* + * 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.26.2 ^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-07-03 15:01 ` Johan Hovold @ 2020-07-06 11:47 ` Jerry 2020-07-06 13:59 ` Johan Hovold 0 siblings, 1 reply; 28+ messages in thread From: Jerry @ 2020-07-06 11:47 UTC (permalink / raw) To: Johan Hovold; +Cc: Greg Kroah-Hartman, linux-usb Johan Hovold wrote on 7/3/20 5:01 PM: > On Fri, Jul 03, 2020 at 09:45:39AM +0200, Johan Hovold wrote: > Would you mind giving the below a try and see how that works in your > setup? > > With this patch you'd be able to use PARMRK to be notified of any parity > errors, but I also wired up TIOCGICOUNT if you prefer to use that. > > Also, could try and see if your device detects breaks properly? Mine > just return a NUL char. > > Johan > I tried your patch. It detects the parity error correctly for my application. Unfortunately I'm not able currently to verify a break reception due to holiday, I'll probably try it next week when back at work (I need to recompile the device firmware). An interesting thing that your patch don't report any overrun. I'm not able to create a real overrun (any idea?) but it doesn't report any fake overrun compared to GET_COMM_STATUS. The question could be a value of CP210X_ESCCHAR. You selected 0xFF and this value can be quite common in received data because an erased flash memory is full of 0xFF. When I read an empty memory it means double USB bandwidth so for example 0xFE seems be better... but I understand that it depend on application and it is hard to globally select this value. I'll do some more tests but your solution seems be fully acceptable for my needs. For me TIOCGICOUNT is enough (I just resend request when an error detected) but for other situation it would be very nice to know exactly which byte was malformed through PARMRK. Jerry ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-07-06 11:47 ` Jerry @ 2020-07-06 13:59 ` Johan Hovold 2020-07-08 21:05 ` Jerry 0 siblings, 1 reply; 28+ messages in thread From: Johan Hovold @ 2020-07-06 13:59 UTC (permalink / raw) To: Jerry; +Cc: Johan Hovold, Greg Kroah-Hartman, linux-usb On Mon, Jul 06, 2020 at 01:47:50PM +0200, Jerry wrote: > Johan Hovold wrote on 7/3/20 5:01 PM: > > On Fri, Jul 03, 2020 at 09:45:39AM +0200, Johan Hovold wrote: > > Would you mind giving the below a try and see how that works in your > > setup? > > > > With this patch you'd be able to use PARMRK to be notified of any parity > > errors, but I also wired up TIOCGICOUNT if you prefer to use that. > > > > Also, could try and see if your device detects breaks properly? Mine > > just return a NUL char. > I tried your patch. It detects the parity error correctly for my > application. Unfortunately I'm not able currently to verify a break > reception due to holiday, I'll probably try it next week when back at work > (I need to recompile the device firmware). Cool, thanks. I noticed that I can get comm-status to report a break condition when event-insertion mode is disabled, but it just results in a NUL char in event mode (the error flag isn't set then). Perhaps buggy firmware, unless there's some other command for masking events. Haven't quite understood how the EVENTMASK requests are supposed to be used. Replacing the break char (SET_CHAR) didn't help at least. > An interesting thing that your patch don't report any overrun. I'm not able > to create a real overrun (any idea?) but it doesn't report any fake overrun > compared to GET_COMM_STATUS. Yeah, I noticed that too, although I had a feeling the fake overrun didn't even always show up when sending while closed here either. Not sure how best to trigger an overrun since we rely on the read urb to report it. Perhaps pausing the read urbs, filling up the device fifo and then submitting the urbs again could work? Would need to patch the driver quite a bit for that though. > The question could be a value of CP210X_ESCCHAR. You selected 0xFF and this > value can be quite common in received data because an erased flash memory > is full of 0xFF. When I read an empty memory it means double USB bandwidth > so for example 0xFE seems be better... but I understand that it depend on > application and it is hard to globally select this value. Good point! I think we should definitely avoid 0xff. > I'll do some more tests but your solution seems be fully acceptable for my > needs. For me TIOCGICOUNT is enough (I just resend request when an error > detected) but for other situation it would be very nice to know exactly > which byte was malformed through PARMRK. That's good to hear. I'll respin the generic (event-based) solution then. Thanks, Johan ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-07-06 13:59 ` Johan Hovold @ 2020-07-08 21:05 ` Jerry 2020-07-13 10:54 ` Johan Hovold 0 siblings, 1 reply; 28+ messages in thread From: Jerry @ 2020-07-08 21:05 UTC (permalink / raw) To: Johan Hovold; +Cc: Greg Kroah-Hartman, linux-usb Johan Hovold wrote on 7/6/20 3:59 PM: > On Mon, Jul 06, 2020 at 01:47:50PM +0200, Jerry wrote: >> Johan Hovold wrote on 7/3/20 5:01 PM: >>> Also, could try and see if your device detects breaks properly? Mine >>> just return a NUL char. I've done some experiments with CP2102 receiving a break. It seems that chip always receives 0x00 for the start of break (with correct parity when even parity set, wrong for odd parity) and later (probably after 250 ms) it also sets break flag in GET_COMM_STATUS. I don't see any indication of the break event in data. I tried to change some things in your solution but without success. I also haven't ever seen Frame error (neither way). I tried several ways (different tx/rx baudrate, receive a parity data without parity enabled, generating shorter breaks) and I suppose that CP2102 can't indicate framing error. Luckily I haven't found any problem with parity checking. :-) > I noticed that I can get comm-status to report a break condition when > event-insertion mode is disabled, but it just results in a NUL char in > event mode (the error flag isn't set then). > > Perhaps buggy firmware, unless there's some other command for masking > events. Haven't quite understood how the EVENTMASK requests are supposed > to be used. Replacing the break char (SET_CHAR) didn't help at least. Neither I understand EVENTMASK in AN571 but I suppose that it is used for W32 API WaitCommEvent() because of very similar flag list https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-waitcommevent maybe somebody else can explain possible usage... >> An interesting thing that your patch don't report any overrun. I'm not able >> to create a real overrun (any idea?) but it doesn't report any fake overrun >> compared to GET_COMM_STATUS. > Yeah, I noticed that too, although I had a feeling the fake overrun > didn't even always show up when sending while closed here either. You are right, the fake HW overrun in GET_COMM_STATUS isn't reported always but very often. > > Thanks, > Johan Jerry ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-07-08 21:05 ` Jerry @ 2020-07-13 10:54 ` Johan Hovold 0 siblings, 0 replies; 28+ messages in thread From: Johan Hovold @ 2020-07-13 10:54 UTC (permalink / raw) To: Jerry; +Cc: Johan Hovold, Greg Kroah-Hartman, linux-usb On Wed, Jul 08, 2020 at 11:05:29PM +0200, Jerry wrote: > Johan Hovold wrote on 7/6/20 3:59 PM: > > On Mon, Jul 06, 2020 at 01:47:50PM +0200, Jerry wrote: > >> Johan Hovold wrote on 7/3/20 5:01 PM: > >>> Also, could try and see if your device detects breaks properly? Mine > >>> just return a NUL char. > I've done some experiments with CP2102 receiving a break. > It seems that chip always receives 0x00 for the start of break (with > correct parity when even parity set, wrong for odd parity) and later > (probably after 250 ms) it also sets break flag in GET_COMM_STATUS. > I don't see any indication of the break event in data. I tried to change > some things in your solution but without success. Ok, thanks for testing! The SERIAL_BREAK_CHAR in ulFlowReplace probably needs to be set for breaks to be reported in-band, but unfortunately that doesn't seem to have any effect on CP2102. > I also haven't ever seen Frame error (neither way). I tried several ways > (different tx/rx baudrate, receive a parity data without parity enabled, > generating shorter breaks) and I suppose that CP2102 can't indicate framing > error. > > Luckily I haven't found any problem with parity checking. :-) That's good. I've been giving this some more thought and decided that it's probably best not to extend TIOCGICOUNT with a COMM_STATUS request after all. TIOCGICOUNT is really only supposed to be used to retrieve the modem-status interrupts in concert with TIOCMIWAIT, but the ioctl was later amended with some error statistics as well. As I mentioned before, the ioctl is linux-specific and the statistics counter are mostly undocumented and the behaviour varies from driver to driver. And don't think adding another device-specific implementation which essentially polls for errors (rather than counts them) is a good idea. Since you confirmed that the event based implementation works for your use case I think we should stick to that as it's allows for the normal POSIX mechanisms for detecting parity errors. Johan ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-07-03 7:45 ` Johan Hovold 2020-07-03 15:01 ` Johan Hovold @ 2020-07-03 18:45 ` Jerry 2020-07-06 7:51 ` Johan Hovold 1 sibling, 1 reply; 28+ messages in thread From: Jerry @ 2020-07-03 18:45 UTC (permalink / raw) To: Johan Hovold; +Cc: Greg Kroah-Hartman, linux-usb Johan Hovold wrote on 7/3/20 9:45 AM: > Heh, yeah, it tends to be that way. :) But thanks for the great summary > of your findings! > > I think it probably makes most sense to keep the error in as it's a > quirk of the device rather than risk missing an actual overrun. OK > The problem here is that we're sort of violating the API and turning > TIOCGICOUNT into a polling interface instead of just returning our error > and interrupt counters. This means will always undercount any errors for > a start. > > The chip appears to have a mechanism for reporting errors in-band, but > that would amount to processing every character received to look for the > escape char, which adds overhead. I'm guessing that interface would also > insert an overrun error when returning the first character. Yes, it is posible to use EMBED_EVENTS and chip will insert event codes into stream of data bytes. But it will cost some processing power and if transmitted data contains ESC char it will be escaped so it will cost some additional bandwidth. In the worst case (all received data = ESC) it means double bandwidth. I have found such solution here: https://github.com/fortian/cp210x/blob/master/cp210x.c but it is quite complex and I expected argument that it costs too much (especially when using maximum baudrate) so I suggested simple way which doesn't have an impact until ioctl is called. > But perhaps that it was we should be using as it allows parity the > errors to be reported using the normal in-band methods. If we only > enable it when parity checking is enabled then the overhead seems > justified. > > I did a quick test here and the event insertion appears to work well for > parity errors. Didn't manage to get it to report break events yet, and > modem-status changes are being buffered and not reported until the next > character. But in theory we could expand the implementation to provide > more features later. > > I'll see if I can cook something up quickly. >> I suppose that GET_COMM_STATUS reads and CLEAR pending error flags (not >> explained in datasheet but behaves that way). So if some errors are >> reported during cp210x_tx_empty() it can be either counted immediately or >> lost. I'm not sure if cp210x_tx_empty() is called ONLY during close but >> seems be more consistent to count every detected error regardless who calls >> GET_COMM_STATUS. > tx_empty() is called when waiting for data to be drained for example > during close but also on when changing terminal settings with TCSADRAIN > or on tcdrain(). But losing an error during tcdrain() is definitely wrong. It is common to send (write) some request, then call tcdrain to be sure that whole request was transmitted and then receive response. Calling tcdrain is necessary in combination with GPIO manipulation but it can also be useful to measure correct timeout because I need to know that data was already transmitted to target (it can take long time for slow baudrate). There is no reason to discard error flags during such waiting. > Correct. > > It's quite possible that that's missing elsewhere, but at least those > counters are updated in completion callbacks which do not run in > parallel unlike ioctls(), which are not serialised. > > Johan Jerry ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-07-03 18:45 ` Jerry @ 2020-07-06 7:51 ` Johan Hovold 0 siblings, 0 replies; 28+ messages in thread From: Johan Hovold @ 2020-07-06 7:51 UTC (permalink / raw) To: Jerry; +Cc: Johan Hovold, Greg Kroah-Hartman, linux-usb On Fri, Jul 03, 2020 at 08:45:45PM +0200, Jerry wrote: > Johan Hovold wrote on 7/3/20 9:45 AM: > > The problem here is that we're sort of violating the API and turning > > TIOCGICOUNT into a polling interface instead of just returning our error > > and interrupt counters. This means will always undercount any errors for > > a start. > > > > The chip appears to have a mechanism for reporting errors in-band, but > > that would amount to processing every character received to look for the > > escape char, which adds overhead. I'm guessing that interface would also > > insert an overrun error when returning the first character. > Yes, it is posible to use EMBED_EVENTS and chip will insert event codes > into stream of data bytes. But it will cost some processing power and if > transmitted data contains ESC char it will be escaped so it will cost some > additional bandwidth. In the worst case (all received data = ESC) it means > double bandwidth. Yeah, but sending a stream of ESC chars isn't a particularly interesting application anyway. ;) > I have found such solution here: > https://github.com/fortian/cp210x/blob/master/cp210x.c > but it is quite complex and I expected argument that it costs too much > (especially when using maximum baudrate) so I suggested simple way which > doesn't have an impact until ioctl is called. It will definitely have some overhead, but since it allows for proper posix behaviour and things like break detection I think it's warranted (but only when those features are requested of course). It may be possible to get the best of both worlds here if we poll for changes only if input parity checking is disabled. You get the statistics and could still use the Linux-specific TIOCGICOUNT ioctl to check for errors indirectly. > > But perhaps that it was we should be using as it allows parity the > > errors to be reported using the normal in-band methods. If we only > > enable it when parity checking is enabled then the overhead seems > > justified. > > > > I did a quick test here and the event insertion appears to work well for > > parity errors. Didn't manage to get it to report break events yet, and > > modem-status changes are being buffered and not reported until the next > > character. But in theory we could expand the implementation to provide > > more features later. > > > > I'll see if I can cook something up quickly. > > >> I suppose that GET_COMM_STATUS reads and CLEAR pending error flags (not > >> explained in datasheet but behaves that way). So if some errors are > >> reported during cp210x_tx_empty() it can be either counted immediately or > >> lost. I'm not sure if cp210x_tx_empty() is called ONLY during close but > >> seems be more consistent to count every detected error regardless who calls > >> GET_COMM_STATUS. > > tx_empty() is called when waiting for data to be drained for example > > during close but also on when changing terminal settings with TCSADRAIN > > or on tcdrain(). > But losing an error during tcdrain() is definitely wrong. It is common to > send (write) some request, then call tcdrain to be sure that whole request > was transmitted and then receive response. Calling tcdrain is necessary in > combination with GPIO manipulation but it can also be useful to measure > correct timeout because I need to know that data was already transmitted to > target (it can take long time for slow baudrate). There is no reason to > discard error flags during such waiting. Yes, you're right of course. Since comm-status request clears the flags they need to be accounted for whenever it's used. Johan ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4] usbserial: cp210x - icount support for parity error checking 2020-06-22 15:13 ` [PATCH v4] " Jaromír Škorpil 2020-06-25 4:31 ` Jerry 2020-07-01 15:42 ` Johan Hovold @ 2020-07-06 9:08 ` Johan Hovold 2020-07-08 21:34 ` [PATCH v5] " Jaromir Skorpil 2020-07-08 22:21 ` Jaromir Skorpil 2 siblings, 2 replies; 28+ messages in thread From: Johan Hovold @ 2020-07-06 9:08 UTC (permalink / raw) To: Jaromír Škorpil; +Cc: Greg Kroah-Hartman, Johan Hovold, linux-usb On Mon, Jun 22, 2020 at 05:13:41PM +0200, Jaromír Škorpil wrote: > The current version of cp210x driver doesn't provide any way to detect > a parity error in received data from userspace. Some serial protocols like > STM32 bootloader protect data only by parity so application needs to > know whether parity error happened to repeat peripheral data reading. > > Added support for icount (ioctl TIOCGICOUNT) which sends GET_COMM_STATUS > command to CP210X and according received flags increments fields for > parity error, frame error, break and overrun. An application can detect > an error condition after reading data from ttyUSB and reacts adequately. > There is no impact for applications which don't call ioctl TIOCGICOUNT. > > The flag "hardware overrun" is not examined because CP2102 sets this bit > for the first received byte after openning of port which was previously > closed with some unreaded data in buffer. This is confusing and checking > "queue overrun" flag seems be enough. > > Signed-off-by: Jaromír Škorpil <Jerry@jrr.cz> > --- > v2: Simplified counting - only queue overrun checked > v3: Changed description + UTF8 name > v4: Corrected endian So let's go with this and then I can add support for in-band reporting on top. I was gonna apply it and the missing locking, but noticed that the patch is white-space damaged. At least some leading tabs have been converted. Try sending the patch yourself (e.g. using git-send-email) and make sure you can apply it using git-am. > cp210x.c | 43 ++++++++++++++++++++++++++++++++++++++----- > 1 file changed, 38 insertions(+), 5 deletions(-) > > diff -up linux-5.8-rc1/drivers/usb/serial/cp210x.c j/drivers/usb/serial/cp210x.c > --- linux-5.8-rc1/drivers/usb/serial/cp210x.c > +++ j/drivers/usb/serial/cp210x.c > @@ -43,6 +43,8 @@ static int cp210x_tiocmget(struct tty_st > static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int); > static int cp210x_tiocmset_port(struct usb_serial_port *port, > unsigned int, unsigned int); > +static int cp210x_get_icount(struct tty_struct *tty, > + struct serial_icounter_struct *icount); > static void cp210x_break_ctl(struct tty_struct *, int); > static int cp210x_attach(struct usb_serial *); > static void cp210x_disconnect(struct usb_serial *); > @@ -274,6 +276,7 @@ static struct usb_serial_driver cp210x_d > .tx_empty = cp210x_tx_empty, > .tiocmget = cp210x_tiocmget, > .tiocmset = cp210x_tiocmset, > + .get_icount = cp210x_get_icount, > .attach = cp210x_attach, > .disconnect = cp210x_disconnect, > .release = cp210x_release, > @@ -393,6 +396,13 @@ struct cp210x_comm_status { > u8 bReserved; > } __packed; > > +/* cp210x_comm_status::ulErrors */ > +#define CP210X_SERIAL_ERR_BREAK BIT(0) > +#define CP210X_SERIAL_ERR_FRAME BIT(1) > +#define CP210X_SERIAL_ERR_HW_OVERRUN BIT(2) > +#define CP210X_SERIAL_ERR_QUEUE_OVERRUN BIT(3) > +#define CP210X_SERIAL_ERR_PARITY BIT(4) Can you drop the SERIAL_ infix here? > + > /* > * CP210X_PURGE - 16 bits passed in wValue of USB request. > * SiLabs app note AN571 gives a strange description of the 4 bits: > @@ -836,10 +846,10 @@ static void cp210x_close(struct usb_seri > } > > /* > - * Read how many bytes are waiting in the TX queue. > + * Read how many bytes are waiting in the TX queue and update error counters. > */ > -static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port, > - u32 *count) > +static int cp210x_get_comm_status(struct usb_serial_port *port, > + u32 *tx_count) > { > struct usb_serial *serial = port->serial; > struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); > @@ -855,7 +865,17 @@ static int cp210x_get_tx_queue_byte_coun > 0, port_priv->bInterfaceNumber, sts, sizeof(*sts), > USB_CTRL_GET_TIMEOUT); > if (result == sizeof(*sts)) { > - *count = le32_to_cpu(sts->ulAmountInOutQueue); > + u32 flags = le32_to_cpu(sts->ulErrors); Here should be a newline. > + if (flags & CP210X_SERIAL_ERR_BREAK) > + port->icount.brk++; > + if (flags & CP210X_SERIAL_ERR_FRAME) > + port->icount.frame++; > + if (flags & CP210X_SERIAL_ERR_QUEUE_OVERRUN) > + port->icount.overrun++; > + if (flags & CP210X_SERIAL_ERR_PARITY) > + port->icount.parity++; And these icount increments should be done under the port->lock as TIOCGICOUNT can be called in parallel. > + if (tx_count) > + *tx_count = le32_to_cpu(sts->ulAmountInOutQueue); > result = 0; > } else { > dev_err(&port->dev, "failed to get comm status: %d\n", result); > @@ -873,13 +893,26 @@ static bool cp210x_tx_empty(struct usb_s > int err; > u32 count; > > - err = cp210x_get_tx_queue_byte_count(port, &count); > + err = cp210x_get_comm_status(port, &count); > if (err) > return true; > > return !count; > } > > +static int cp210x_get_icount(struct tty_struct *tty, > + struct serial_icounter_struct *icount) > +{ > + struct usb_serial_port *port = tty->driver_data; > + int result; > + > + result = cp210x_get_comm_status(port, NULL); > + if (result) > + return result; > + > + return usb_serial_generic_get_icount(tty, icount); > +} > + > /* > * cp210x_get_termios > * Reads the baud rate, data bits, parity, stop bits and flow control mode > > > Johan ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v5] usbserial: cp210x - icount support for parity error checking 2020-07-06 9:08 ` Johan Hovold @ 2020-07-08 21:34 ` Jaromir Skorpil 2020-07-08 22:21 ` Jaromir Skorpil 1 sibling, 0 replies; 28+ messages in thread From: Jaromir Skorpil @ 2020-07-08 21:34 UTC (permalink / raw) To: Johan Hovold; +Cc: Greg Kroah-Hartman, linux-usb The current version of cp210x driver doesn't provide any way to detect a parity error in received data from userspace. Some serial protocols like STM32 bootloader protect data only by parity so application needs to know whether parity error happened to repeat peripheral data reading. Added support for icount (ioctl TIOCGICOUNT) which sends GET_COMM_STATUS command to CP210X and according received flags increments fields for parity error, frame error, break and overrun. An application can detect an error condition after reading data from ttyUSB and reacts adequately. There is no impact for applications which don't call ioctl TIOCGICOUNT. The flag "hardware overrun" is sometimes set by CP2102 for the first received data after port opening when some data arrived to closed port. The same problem appears in MS Windows 10, so no reason to hide this fake overrun. Signed-off-by: Jaromir Skorpil <Jerry@jrr.cz> --- v2: Simplified counting - only queue overrun checked v3: Changed description + UTF8 name v4: Corrected endian v5: Port lock, hw+queue overrun, formatting cp210x.c | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff -up linux-5.8-rc1/drivers/usb/serial/cp210x.c j/drivers/usb/serial/cp210x.c --- linux-5.8-rc1/drivers/usb/serial/cp210x.c +++ j/drivers/usb/serial/cp210x.c @@ -43,6 +43,8 @@ static int cp210x_tiocmget(struct tty_st static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int); static int cp210x_tiocmset_port(struct usb_serial_port *port, unsigned int, unsigned int); +static int cp210x_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount); static void cp210x_break_ctl(struct tty_struct *, int); static int cp210x_attach(struct usb_serial *); static void cp210x_disconnect(struct usb_serial *); @@ -274,6 +276,7 @@ static struct usb_serial_driver cp210x_d .tx_empty = cp210x_tx_empty, .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, + .get_icount = cp210x_get_icount, .attach = cp210x_attach, .disconnect = cp210x_disconnect, .release = cp210x_release, @@ -393,6 +396,13 @@ struct cp210x_comm_status { u8 bReserved; } __packed; +/* cp210x_comm_status::ulErrors */ +#define CP210X_ERR_BREAK BIT(0) +#define CP210X_ERR_FRAME BIT(1) +#define CP210X_ERR_HW_OVERRUN BIT(2) +#define CP210X_ERR_QUEUE_OVERRUN BIT(3) +#define CP210X_ERR_PARITY BIT(4) + /* * CP210X_PURGE - 16 bits passed in wValue of USB request. * SiLabs app note AN571 gives a strange description of the 4 bits: @@ -836,10 +846,10 @@ static void cp210x_close(struct usb_seri } /* - * Read how many bytes are waiting in the TX queue. + * Read how many bytes are waiting in the TX queue and update error counters. */ -static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port, - u32 *count) +static int cp210x_get_comm_status(struct usb_serial_port *port, + u32 *tx_count) { struct usb_serial *serial = port->serial; struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); @@ -855,7 +865,22 @@ static int cp210x_get_tx_queue_byte_coun 0, port_priv->bInterfaceNumber, sts, sizeof(*sts), USB_CTRL_GET_TIMEOUT); if (result == sizeof(*sts)) { - *count = le32_to_cpu(sts->ulAmountInOutQueue); + unsigned long flags; + u32 err = le32_to_cpu(sts->ulErrors); + + spin_lock_irqsave(&port->lock, flags); + if (err & CP210X_ERR_BREAK) + port->icount.brk++; + if (err & CP210X_ERR_FRAME) + port->icount.frame++; + if (err & (CP210X_ERR_HW_OVERRUN | CP210X_ERR_QUEUE_OVERRUN)) + port->icount.overrun++; + if (err & CP210X_ERR_PARITY) + port->icount.parity++; + spin_unlock_irqrestore(&port->lock, flags); + + if (tx_count) + *tx_count = le32_to_cpu(sts->ulAmountInOutQueue); result = 0; } else { dev_err(&port->dev, "failed to get comm status: %d\n", result); @@ -873,13 +898,26 @@ static bool cp210x_tx_empty(struct usb_s int err; u32 count; - err = cp210x_get_tx_queue_byte_count(port, &count); + err = cp210x_get_comm_status(port, &count); if (err) return true; return !count; } +static int cp210x_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct usb_serial_port *port = tty->driver_data; + int result; + + result = cp210x_get_comm_status(port, NULL); + if (result) + return result; + + return usb_serial_generic_get_icount(tty, icount); +} + /* * cp210x_get_termios * Reads the baud rate, data bits, parity, stop bits and flow control mode ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v5] usbserial: cp210x - icount support for parity error checking 2020-07-06 9:08 ` Johan Hovold 2020-07-08 21:34 ` [PATCH v5] " Jaromir Skorpil @ 2020-07-08 22:21 ` Jaromir Skorpil 1 sibling, 0 replies; 28+ messages in thread From: Jaromir Skorpil @ 2020-07-08 22:21 UTC (permalink / raw) To: Johan Hovold; +Cc: Greg Kroah-Hartman, linux-usb The current version of cp210x driver doesn't provide any way to detect a parity error in received data from userspace. Some serial protocols like STM32 bootloader protect data only by parity so application needs to know whether parity error happened to repeat peripheral data reading. Added support for icount (ioctl TIOCGICOUNT) which sends GET_COMM_STATUS command to CP210X and according received flags increments fields for parity error, frame error, break and overrun. An application can detect an error condition after reading data from ttyUSB and reacts adequately. There is no impact for applications which don't call ioctl TIOCGICOUNT. The flag "hardware overrun" is sometimes set by CP2102 for the first received data after port opening when some data arrived to closed port. The same problem appears in MS Windows 10, so no reason to hide this fake overrun. Signed-off-by: Jaromir Skorpil <Jerry@jrr.cz> --- v2: Simplified counting - only queue overrun checked v3: Changed description + UTF8 name v4: Corrected endian v5: Port lock, hw+queue overrun, formatting (no flowed) cp210x.c | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff -up linux-5.8-rc1/drivers/usb/serial/cp210x.c j/drivers/usb/serial/cp210x.c --- linux-5.8-rc1/drivers/usb/serial/cp210x.c +++ j/drivers/usb/serial/cp210x.c @@ -43,6 +43,8 @@ static int cp210x_tiocmget(struct tty_st static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int); static int cp210x_tiocmset_port(struct usb_serial_port *port, unsigned int, unsigned int); +static int cp210x_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount); static void cp210x_break_ctl(struct tty_struct *, int); static int cp210x_attach(struct usb_serial *); static void cp210x_disconnect(struct usb_serial *); @@ -274,6 +276,7 @@ static struct usb_serial_driver cp210x_d .tx_empty = cp210x_tx_empty, .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, + .get_icount = cp210x_get_icount, .attach = cp210x_attach, .disconnect = cp210x_disconnect, .release = cp210x_release, @@ -393,6 +396,13 @@ struct cp210x_comm_status { u8 bReserved; } __packed; +/* cp210x_comm_status::ulErrors */ +#define CP210X_ERR_BREAK BIT(0) +#define CP210X_ERR_FRAME BIT(1) +#define CP210X_ERR_HW_OVERRUN BIT(2) +#define CP210X_ERR_QUEUE_OVERRUN BIT(3) +#define CP210X_ERR_PARITY BIT(4) + /* * CP210X_PURGE - 16 bits passed in wValue of USB request. * SiLabs app note AN571 gives a strange description of the 4 bits: @@ -836,10 +846,10 @@ static void cp210x_close(struct usb_seri } /* - * Read how many bytes are waiting in the TX queue. + * Read how many bytes are waiting in the TX queue and update error counters. */ -static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port, - u32 *count) +static int cp210x_get_comm_status(struct usb_serial_port *port, + u32 *tx_count) { struct usb_serial *serial = port->serial; struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); @@ -855,7 +865,22 @@ static int cp210x_get_tx_queue_byte_coun 0, port_priv->bInterfaceNumber, sts, sizeof(*sts), USB_CTRL_GET_TIMEOUT); if (result == sizeof(*sts)) { - *count = le32_to_cpu(sts->ulAmountInOutQueue); + unsigned long flags; + u32 err = le32_to_cpu(sts->ulErrors); + + spin_lock_irqsave(&port->lock, flags); + if (err & CP210X_ERR_BREAK) + port->icount.brk++; + if (err & CP210X_ERR_FRAME) + port->icount.frame++; + if (err & (CP210X_ERR_HW_OVERRUN | CP210X_ERR_QUEUE_OVERRUN)) + port->icount.overrun++; + if (err & CP210X_ERR_PARITY) + port->icount.parity++; + spin_unlock_irqrestore(&port->lock, flags); + + if (tx_count) + *tx_count = le32_to_cpu(sts->ulAmountInOutQueue); result = 0; } else { dev_err(&port->dev, "failed to get comm status: %d\n", result); @@ -873,13 +898,26 @@ static bool cp210x_tx_empty(struct usb_s int err; u32 count; - err = cp210x_get_tx_queue_byte_count(port, &count); + err = cp210x_get_comm_status(port, &count); if (err) return true; return !count; } +static int cp210x_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct usb_serial_port *port = tty->driver_data; + int result; + + result = cp210x_get_comm_status(port, NULL); + if (result) + return result; + + return usb_serial_generic_get_icount(tty, icount); +} + /* * cp210x_get_termios * Reads the baud rate, data bits, parity, stop bits and flow control mode ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/1] usbserial: cp210x - icount support for parity error checking 2020-06-21 13:58 ` Greg Kroah-Hartman 2020-06-21 20:21 ` [PATCH v3] " Jaromír Škorpil @ 2020-06-22 4:38 ` Jerry 2020-06-22 5:30 ` Greg Kroah-Hartman 1 sibling, 1 reply; 28+ messages in thread From: Jerry @ 2020-06-22 4:38 UTC (permalink / raw) To: Greg Kroah-Hartman; +Cc: Johan Hovold, linux-usb Greg Kroah-Hartman wrote on 6/21/20 3:58 PM: > Please use unicode (well utf-8 if possible), I'm all for that, there is > no requirement to use ascii only for your name in patches. I wish more > people would do that when needed, as it's only fair to them to be able > to properly represent their names and not have to change them somehow. I tried it and it seems that www.spinics.net understand UTF-8 but at marc.info it doesn't work correctly. https://marc.info/?l=linux-usb&m=159279589104617 It seems that this page don't send correct encoding to web browser so Firefox uses windows-1252 and insted of capital S with caron I can see A with ring. Similarily insted of I with acute accent the browser shows A with tilda... it looks horible. And even if I force UTF8 encoding for view, it corrects mail From but my name at Signed-off-by line stays damaged. So UTF-8 seems be a bad idea for kernel mailling list. Best regards Jerry / Jaromir Skorpil ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/1] usbserial: cp210x - icount support for parity error checking 2020-06-22 4:38 ` [PATCH 1/1] " Jerry @ 2020-06-22 5:30 ` Greg Kroah-Hartman 2020-06-22 16:50 ` Jerry 0 siblings, 1 reply; 28+ messages in thread From: Greg Kroah-Hartman @ 2020-06-22 5:30 UTC (permalink / raw) To: Jerry; +Cc: Johan Hovold, linux-usb On Mon, Jun 22, 2020 at 06:38:13AM +0200, Jerry wrote: > Greg Kroah-Hartman wrote on 6/21/20 3:58 PM: > > Please use unicode (well utf-8 if possible), I'm all for that, there is > > no requirement to use ascii only for your name in patches. I wish more > > people would do that when needed, as it's only fair to them to be able > > to properly represent their names and not have to change them somehow. > I tried it and it seems that www.spinics.net understand UTF-8 but at > marc.info it doesn't work correctly. > https://marc.info/?l=linux-usb&m=159279589104617 Why care about marc.info? We don't control that, nor do we use it. If lore.kernel.org does not work, please let us know, we can fix that. > It seems that this page don't send correct encoding to web browser so > Firefox uses windows-1252 and insted of capital S with caron I can see A > with ring. Similarily insted of I with acute accent the browser shows A with > tilda... it looks horible. And even if I force UTF8 encoding for view, it > corrects mail From but my name at Signed-off-by line stays damaged. > > So UTF-8 seems be a bad idea for kernel mailling list. It should not be, again, if lore.kernel.org does not work, please let us know. thanks, greg k-h ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/1] usbserial: cp210x - icount support for parity error checking 2020-06-22 5:30 ` Greg Kroah-Hartman @ 2020-06-22 16:50 ` Jerry 0 siblings, 0 replies; 28+ messages in thread From: Jerry @ 2020-06-22 16:50 UTC (permalink / raw) To: Greg Kroah-Hartman; +Cc: Johan Hovold, linux-usb Greg Kroah-Hartman wrote on 6/22/20 7:30 AM: >> I tried it and it seems that www.spinics.net understand UTF-8 but at >> marc.info it doesn't work correctly. >> https://marc.info/?l=linux-usb&m=159279589104617 > Why care about marc.info? We don't control that, nor do we use it. > > If lore.kernel.org does not work, please let us know, we can fix that. When I subscribed to linux-usb mailing list, I received an e-mail from Majordomo@vger.kernel.org. And in this mail, there were only two links for archives: http://marc.info/?l=linux-usb http://www.spinics.net/lists/linux-usb/ So I supposed that these servers are officially connected with Kernel.org. I didn't know about an existence of lore.kernel.org until now. If I post a message to somewhere I want to be correctly displayed to all users... >> It seems that this page don't send correct encoding to web browser so >> Firefox uses windows-1252 and insted of capital S with caron I can see A >> with ring. Similarily insted of I with acute accent the browser shows A with >> tilda... it looks horible. And even if I force UTF8 encoding for view, it >> corrects mail From but my name at Signed-off-by line stays damaged. >> >> So UTF-8 seems be a bad idea for kernel mailling list. > It should not be, again, if lore.kernel.org does not work, please let > us know. > > thanks, > > greg k-h Anyway, thanks a lot for your patience. Jerry ^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2020-07-13 10:54 UTC | newest] Thread overview: 28+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2020-06-20 19:58 [PATCH 1/1] usbserial: cp210x - icount support for parity error checking Jerry 2020-06-21 8:54 ` [PATCH v2] " Jerry 2020-06-21 8:58 ` [PATCH 1/1] " Greg Kroah-Hartman 2020-06-21 9:45 ` Jerry 2020-06-21 9:55 ` Greg Kroah-Hartman 2020-06-21 10:34 ` Jerry 2020-06-21 13:58 ` Greg Kroah-Hartman 2020-06-21 20:21 ` [PATCH v3] " Jaromír Škorpil 2020-06-22 5:31 ` Greg Kroah-Hartman 2020-06-22 15:13 ` [PATCH v4] " Jaromír Škorpil 2020-06-25 4:31 ` Jerry 2020-06-25 6:53 ` Johan Hovold 2020-07-01 15:42 ` Johan Hovold 2020-07-01 19:28 ` Jerry 2020-07-03 7:45 ` Johan Hovold 2020-07-03 15:01 ` Johan Hovold 2020-07-06 11:47 ` Jerry 2020-07-06 13:59 ` Johan Hovold 2020-07-08 21:05 ` Jerry 2020-07-13 10:54 ` Johan Hovold 2020-07-03 18:45 ` Jerry 2020-07-06 7:51 ` Johan Hovold 2020-07-06 9:08 ` Johan Hovold 2020-07-08 21:34 ` [PATCH v5] " Jaromir Skorpil 2020-07-08 22:21 ` Jaromir Skorpil 2020-06-22 4:38 ` [PATCH 1/1] " Jerry 2020-06-22 5:30 ` Greg Kroah-Hartman 2020-06-22 16:50 ` Jerry
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).