serial: Fix IGNBRK handling
authorPeter Hurley <peter@hurleysoftware.com>
Mon, 16 Jun 2014 12:10:41 +0000 (08:10 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 9 Jul 2014 18:18:28 +0000 (11:18 -0700)
commit ef8b9ddcb45fa3b1e11acd72be2398001e807d14 upstream.

If IGNBRK is set without either BRKINT or PARMRK set, some uart
drivers send a 0x00 byte for BREAK without the TTYBREAK flag to the
line discipline, when it should send either nothing or the TTYBREAK flag
set. This happens because the read_status_mask masks out the BI
condition, which uart_insert_char() then interprets as a normal 0x00 byte.

SUS v3 is clear regarding the meaning of IGNBRK; Section 11.2.2, General
Terminal Interface - Input Modes, states:
  "If IGNBRK is set, a break condition detected on input shall be ignored;
   that is, not put on the input queue and therefore not read by any
   process."

Fix read_status_mask to include the BI bit if IGNBRK is set; the
lsr status retains the BI bit if a BREAK is recv'd, which is
subsequently ignored in uart_insert_char() when masked with the
ignore_status_mask.

Affected drivers:
8250 - all
serial_txx9
mfd
amba-pl010
amba-pl011
atmel_serial
bfin_uart
dz
ip22zilog
max310x
mxs-auart
netx-serial
pnx8xxx_uart
pxa
sb1250-duart
sccnxp
serial_ks8695
sirfsoc_uart
st-asc
vr41xx_siu
zs
sunzilog
fsl_lpuart
sunsab
ucc_uart
bcm63xx_uart
sunsu
efm32-uart
pmac_zilog
mpsc
msm_serial
m32r_sio

Unaffected drivers:
omap-serial
rp2
sa1100
imx
icom

Annotated for fixes:
altera_uart
mcf

Drivers without break detection:
21285
xilinx-uartps
altera_jtaguart
apbuart
arc-uart
clps711x
max3100
uartlite
msm_serial_hs
nwpserial
lantiq
vt8500_serial

Unknown:
samsung
mpc52xx_uart
bfin_sport_uart
cpm_uart/core

Fixes: Bugzilla #71651, '8250_core.c incorrectly handles IGNBRK flag'
Reported-by: Ivan <athlon_@mail.ru>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
34 files changed:
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/altera_uart.c
drivers/tty/serial/amba-pl010.c
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/bcm63xx_uart.c
drivers/tty/serial/bfin_uart.c
drivers/tty/serial/dz.c
drivers/tty/serial/efm32-uart.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/ip22zilog.c
drivers/tty/serial/m32r_sio.c
drivers/tty/serial/max310x.c
drivers/tty/serial/mcf.c
drivers/tty/serial/mfd.c
drivers/tty/serial/mpsc.c
drivers/tty/serial/msm_serial.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/netx-serial.c
drivers/tty/serial/pmac_zilog.c
drivers/tty/serial/pnx8xxx_uart.c
drivers/tty/serial/pxa.c
drivers/tty/serial/sb1250-duart.c
drivers/tty/serial/sccnxp.c
drivers/tty/serial/serial_ks8695.c
drivers/tty/serial/serial_txx9.c
drivers/tty/serial/sirfsoc_uart.c
drivers/tty/serial/st-asc.c
drivers/tty/serial/sunsab.c
drivers/tty/serial/sunsu.c
drivers/tty/serial/sunzilog.c
drivers/tty/serial/ucc_uart.c
drivers/tty/serial/vr41xx_siu.c
drivers/tty/serial/zs.c

index 29a7f63..612dfc7 100644 (file)
@@ -2356,7 +2356,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
        port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                port->read_status_mask |= UART_LSR_BI;
 
        /*
index 501667e..3233766 100644 (file)
@@ -185,6 +185,12 @@ static void altera_uart_set_termios(struct uart_port *port,
        uart_update_timeout(port, termios->c_cflag, baud);
        altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG);
        spin_unlock_irqrestore(&port->lock, flags);
+
+       /*
+        * FIXME: port->read_status_mask and port->ignore_status_mask
+        * need to be initialized based on termios settings for
+        * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT
+        */
 }
 
 static void altera_uart_rx_chars(struct altera_uart *pp)
index 01c9e72..971af1e 100644 (file)
@@ -420,7 +420,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,
        uap->port.read_status_mask = UART01x_RSR_OE;
        if (termios->c_iflag & INPCK)
                uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                uap->port.read_status_mask |= UART01x_RSR_BE;
 
        /*
index d58783d..b569011 100644 (file)
@@ -1744,7 +1744,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
        port->read_status_mask = UART011_DR_OE | 255;
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                port->read_status_mask |= UART011_DR_BE;
 
        /*
index a49f10d..ce352b8 100644 (file)
@@ -1811,7 +1811,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
        port->read_status_mask = ATMEL_US_OVRE;
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                port->read_status_mask |= ATMEL_US_RXBRK;
 
        if (atmel_use_pdc_rx(port))
index 78e82b0..e0b87d5 100644 (file)
@@ -565,7 +565,7 @@ static void bcm_uart_set_termios(struct uart_port *port,
                port->read_status_mask |= UART_FIFO_FRAMEERR_MASK;
                port->read_status_mask |= UART_FIFO_PARERR_MASK;
        }
-       if (new->c_iflag & (BRKINT))
+       if (new->c_iflag & (IGNBRK | BRKINT))
                port->read_status_mask |= UART_FIFO_BRKDET_MASK;
 
        port->ignore_status_mask = 0;
index 869ceba..ac86a20 100644 (file)
@@ -833,7 +833,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
        port->read_status_mask = OE;
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= (FE | PE);
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                port->read_status_mask |= BI;
 
        /*
index 2f2b2e5..cdbbc78 100644 (file)
@@ -625,7 +625,7 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
        dport->port.read_status_mask = DZ_OERR;
        if (termios->c_iflag & INPCK)
                dport->port.read_status_mask |= DZ_FERR | DZ_PERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                dport->port.read_status_mask |= DZ_BREAK;
 
        /* characters to ignore */
index 0eb5b56..948f17b 100644 (file)
@@ -407,7 +407,7 @@ static void efm32_uart_set_termios(struct uart_port *port,
        if (new->c_iflag & INPCK)
                port->read_status_mask |=
                        UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
-       if (new->c_iflag & (BRKINT | PARMRK))
+       if (new->c_iflag & (IGNBRK | BRKINT | PARMRK))
                port->read_status_mask |= SW_UARTn_RXDATAX_BERR;
 
        port->ignore_status_mask = 0;
index 8978dc9..175f123 100644 (file)
@@ -496,7 +496,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
        sport->port.read_status_mask = 0;
        if (termios->c_iflag & INPCK)
                sport->port.read_status_mask |= (UARTSR1_FE | UARTSR1_PE);
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                sport->port.read_status_mask |= UARTSR1_FE;
 
        /* characters to ignore */
index 1d94205..1efd4c3 100644 (file)
@@ -850,7 +850,7 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag,
        up->port.read_status_mask = Rx_OVR;
        if (iflag & INPCK)
                up->port.read_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & (BRKINT | PARMRK))
+       if (iflag & (IGNBRK | BRKINT | PARMRK))
                up->port.read_status_mask |= BRK_ABRT;
 
        up->port.ignore_status_mask = 0;
index 9cd9b4e..68f2c53 100644 (file)
@@ -737,7 +737,7 @@ static void m32r_sio_set_termios(struct uart_port *port,
        up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
        if (termios->c_iflag & INPCK)
                up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                up->port.read_status_mask |= UART_LSR_BI;
 
        /*
index 8d71e40..558af63 100644 (file)
@@ -842,7 +842,7 @@ static void max310x_set_termios(struct uart_port *port,
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= MAX310X_LSR_RXPAR_BIT |
                                          MAX310X_LSR_FRERR_BIT;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                port->read_status_mask |= MAX310X_LSR_RXBRK_BIT;
 
        /* Set status ignore mask */
index 0edfaf8..a6f0857 100644 (file)
@@ -248,6 +248,12 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
                mr1 |= MCFUART_MR1_PARITYNONE;
        }
 
+       /*
+        * FIXME: port->read_status_mask and port->ignore_status_mask
+        * need to be initialized based on termios settings for
+        * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT
+        */
+
        if (termios->c_cflag & CSTOPB)
                mr2 |= MCFUART_MR2_STOP2;
        else
index 52c930f..445799d 100644 (file)
@@ -977,7 +977,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
        up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
        if (termios->c_iflag & INPCK)
                up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                up->port.read_status_mask |= UART_LSR_BI;
 
        /* Characters to ignore */
index e30a3ca..759c6a6 100644 (file)
@@ -1458,7 +1458,7 @@ static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
                pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE
                        | SDMA_DESC_CMDSTAT_FR;
 
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR;
 
        /* Characters/events to ignore */
index b5d779c..c0f2b3e 100644 (file)
@@ -570,7 +570,7 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
        port->read_status_mask = 0;
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= UART_SR_PAR_FRAME_ERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                port->read_status_mask |= UART_SR_RX_BREAK;
 
        uart_update_timeout(port, termios->c_cflag, baud);
index aa97fd8..d98f1d4 100644 (file)
@@ -604,7 +604,7 @@ static void mxs_auart_settermios(struct uart_port *u,
 
        if (termios->c_iflag & INPCK)
                u->read_status_mask |= AUART_STAT_PERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                u->read_status_mask |= AUART_STAT_BERR;
 
        /*
index 0a4dd70..7a67456 100644 (file)
@@ -419,7 +419,7 @@ netx_set_termios(struct uart_port *port, struct ktermios *termios,
        }
 
        port->read_status_mask = 0;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                port->read_status_mask |= SR_BE;
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= SR_PE | SR_FE;
index e9d420f..8193635 100644 (file)
@@ -1092,7 +1092,7 @@ static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag,
        uap->port.read_status_mask = Rx_OVR;
        if (iflag & INPCK)
                uap->port.read_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & (BRKINT | PARMRK))
+       if (iflag & (IGNBRK | BRKINT | PARMRK))
                uap->port.read_status_mask |= BRK_ABRT;
 
        uap->port.ignore_status_mask = 0;
index de6c05c..2ba24a4 100644 (file)
@@ -477,7 +477,7 @@ pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios,
                sport->port.read_status_mask |=
                        FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
                        FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                sport->port.read_status_mask |=
                        ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
 
index f9f20f3..fc3f308 100644 (file)
@@ -492,7 +492,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
        up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
        if (termios->c_iflag & INPCK)
                up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                up->port.read_status_mask |= UART_LSR_BI;
 
        /*
index a7cdec2..771f361 100644 (file)
@@ -596,7 +596,7 @@ static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios,
        if (termios->c_iflag & INPCK)
                uport->read_status_mask |= M_DUART_FRM_ERR |
                                           M_DUART_PARITY_ERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                uport->read_status_mask |= M_DUART_RCVD_BRK;
 
        uport->ignore_status_mask = 0;
index a447f71..75ea832 100644 (file)
@@ -667,7 +667,7 @@ static void sccnxp_set_termios(struct uart_port *port,
        port->read_status_mask = SR_OVR;
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= SR_PE | SR_FE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                port->read_status_mask |= SR_BRK;
 
        /* Set status ignore mask */
index e1caa99..5c79bda 100644 (file)
@@ -437,7 +437,7 @@ static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *term
        port->read_status_mask = URLS_URROE;
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= (URLS_URFE | URLS_URPE);
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                port->read_status_mask |= URLS_URBI;
 
        /*
index 90a080b..cbf501d 100644 (file)
@@ -702,7 +702,7 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
                TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS;
        if (termios->c_iflag & INPCK)
                up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                up->port.read_status_mask |= TXX9_SIDISR_UBRK;
 
        /*
index b7bfe24..020fe22 100644 (file)
@@ -908,7 +908,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
                if (termios->c_iflag & INPCK)
                        port->read_status_mask |= uint_en->sirfsoc_frm_err_en;
        }
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                        port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en;
        if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
                if (termios->c_iflag & IGNPAR)
index 21e6e84..0ee3175 100644 (file)
@@ -547,7 +547,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
        ascport->port.read_status_mask = ASC_RXBUF_DUMMY_OE;
        if (termios->c_iflag & INPCK)
                ascport->port.read_status_mask |= ASC_RXBUF_FE | ASC_RXBUF_PE;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                ascport->port.read_status_mask |= ASC_RXBUF_DUMMY_BE;
 
        /*
index 5faa8e9..80a58ec 100644 (file)
@@ -719,7 +719,7 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla
        if (iflag & INPCK)
                up->port.read_status_mask |= (SAB82532_ISR0_PERR |
                                              SAB82532_ISR0_FERR);
-       if (iflag & (BRKINT | PARMRK))
+       if (iflag & (IGNBRK | BRKINT | PARMRK))
                up->port.read_status_mask |= (SAB82532_ISR1_BRK << 8);
 
        /*
index 9a0f24f..5326ae1 100644 (file)
@@ -834,7 +834,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
        up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
        if (iflag & INPCK)
                up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (iflag & (BRKINT | PARMRK))
+       if (iflag & (IGNBRK | BRKINT | PARMRK))
                up->port.read_status_mask |= UART_LSR_BI;
 
        /*
index a2c40ed..a85db8b 100644 (file)
@@ -915,7 +915,7 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
        up->port.read_status_mask = Rx_OVR;
        if (iflag & INPCK)
                up->port.read_status_mask |= CRC_ERR | PAR_ERR;
-       if (iflag & (BRKINT | PARMRK))
+       if (iflag & (IGNBRK | BRKINT | PARMRK))
                up->port.read_status_mask |= BRK_ABRT;
 
        up->port.ignore_status_mask = 0;
index d569ca5..1c52074 100644 (file)
@@ -936,7 +936,7 @@ static void qe_uart_set_termios(struct uart_port *port,
        port->read_status_mask = BD_SC_EMPTY | BD_SC_OV;
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= BD_SC_FR | BD_SC_PR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                port->read_status_mask |= BD_SC_BR;
 
        /*
index a63c14b..db0c8a4 100644 (file)
@@ -559,7 +559,7 @@ static void siu_set_termios(struct uart_port *port, struct ktermios *new,
        port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR;
        if (c_iflag & INPCK)
                port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (c_iflag & (BRKINT | PARMRK))
+       if (c_iflag & (IGNBRK | BRKINT | PARMRK))
                port->read_status_mask |= UART_LSR_BI;
 
        port->ignore_status_mask = 0;
index 6a16987..2b65bb7 100644 (file)
@@ -923,7 +923,7 @@ static void zs_set_termios(struct uart_port *uport, struct ktermios *termios,
        uport->read_status_mask = Rx_OVR;
        if (termios->c_iflag & INPCK)
                uport->read_status_mask |= FRM_ERR | PAR_ERR;
-       if (termios->c_iflag & (BRKINT | PARMRK))
+       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
                uport->read_status_mask |= Rx_BRK;
 
        uport->ignore_status_mask = 0;