diff options
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 24 |
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); |