aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/serial/ftdi_sio.c24
1 files changed, 17 insertions, 7 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 33f1cca7eaa6..07b146d7033a 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -2483,6 +2483,7 @@ static int ftdi_process_packet(struct usb_serial_port *port,
struct ftdi_private *priv, unsigned char *buf, int len)
{
unsigned char status;
+ bool brkint = false;
int i;
char flag;
@@ -2534,13 +2535,17 @@ static int ftdi_process_packet(struct usb_serial_port *port,
*/
flag = TTY_NORMAL;
if (buf[1] & FTDI_RS_ERR_MASK) {
- /* Break takes precedence over parity, which takes precedence
- * over framing errors */
- if (buf[1] & FTDI_RS_BI) {
- flag = TTY_BREAK;
+ /*
+ * Break takes precedence over parity, which takes precedence
+ * over framing errors. Note that break is only associated
+ * with the last character in the buffer and only when it's a
+ * NUL.
+ */
+ if (buf[1] & FTDI_RS_BI && buf[len - 1] == '\0') {
port->icount.brk++;
- usb_serial_handle_break(port);
- } else if (buf[1] & FTDI_RS_PE) {
+ brkint = true;
+ }
+ if (buf[1] & FTDI_RS_PE) {
flag = TTY_PARITY;
port->icount.parity++;
} else if (buf[1] & FTDI_RS_FE) {
@@ -2556,8 +2561,13 @@ static int ftdi_process_packet(struct usb_serial_port *port,
port->icount.rx += len - 2;
- if (port->port.console && port->sysrq) {
+ if (brkint || (port->port.console && port->sysrq)) {
for (i = 2; i < len; i++) {
+ if (brkint && i == len - 1) {
+ if (usb_serial_handle_break(port))
+ return len - 3;
+ flag = TTY_BREAK;
+ }
if (usb_serial_handle_sysrq_char(port, buf[i]))
continue;
tty_insert_flip_char(&port->port, buf[i], flag);