Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

serial: Fix IGNBRK handling

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>

authored by

Peter Hurley and committed by
Greg Kroah-Hartman
ef8b9ddc a859c8b2

+44 -32
+1 -1
drivers/tty/serial/8250/8250_core.c
··· 2357 2357 port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; 2358 2358 if (termios->c_iflag & INPCK) 2359 2359 port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; 2360 - if (termios->c_iflag & (BRKINT | PARMRK)) 2360 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 2361 2361 port->read_status_mask |= UART_LSR_BI; 2362 2362 2363 2363 /*
+6
drivers/tty/serial/altera_uart.c
··· 185 185 uart_update_timeout(port, termios->c_cflag, baud); 186 186 altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG); 187 187 spin_unlock_irqrestore(&port->lock, flags); 188 + 189 + /* 190 + * FIXME: port->read_status_mask and port->ignore_status_mask 191 + * need to be initialized based on termios settings for 192 + * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT 193 + */ 188 194 } 189 195 190 196 static void altera_uart_rx_chars(struct altera_uart *pp)
+1 -1
drivers/tty/serial/amba-pl010.c
··· 420 420 uap->port.read_status_mask = UART01x_RSR_OE; 421 421 if (termios->c_iflag & INPCK) 422 422 uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; 423 - if (termios->c_iflag & (BRKINT | PARMRK)) 423 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 424 424 uap->port.read_status_mask |= UART01x_RSR_BE; 425 425 426 426 /*
+1 -1
drivers/tty/serial/amba-pl011.c
··· 1744 1744 port->read_status_mask = UART011_DR_OE | 255; 1745 1745 if (termios->c_iflag & INPCK) 1746 1746 port->read_status_mask |= UART011_DR_FE | UART011_DR_PE; 1747 - if (termios->c_iflag & (BRKINT | PARMRK)) 1747 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 1748 1748 port->read_status_mask |= UART011_DR_BE; 1749 1749 1750 1750 /*
+1 -1
drivers/tty/serial/atmel_serial.c
··· 1932 1932 port->read_status_mask = ATMEL_US_OVRE; 1933 1933 if (termios->c_iflag & INPCK) 1934 1934 port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); 1935 - if (termios->c_iflag & (BRKINT | PARMRK)) 1935 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 1936 1936 port->read_status_mask |= ATMEL_US_RXBRK; 1937 1937 1938 1938 if (atmel_use_pdc_rx(port))
+1 -1
drivers/tty/serial/bcm63xx_uart.c
··· 567 567 port->read_status_mask |= UART_FIFO_FRAMEERR_MASK; 568 568 port->read_status_mask |= UART_FIFO_PARERR_MASK; 569 569 } 570 - if (new->c_iflag & (BRKINT)) 570 + if (new->c_iflag & (IGNBRK | BRKINT)) 571 571 port->read_status_mask |= UART_FIFO_BRKDET_MASK; 572 572 573 573 port->ignore_status_mask = 0;
+1 -1
drivers/tty/serial/bfin_uart.c
··· 833 833 port->read_status_mask = OE; 834 834 if (termios->c_iflag & INPCK) 835 835 port->read_status_mask |= (FE | PE); 836 - if (termios->c_iflag & (BRKINT | PARMRK)) 836 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 837 837 port->read_status_mask |= BI; 838 838 839 839 /*
+1 -1
drivers/tty/serial/dz.c
··· 625 625 dport->port.read_status_mask = DZ_OERR; 626 626 if (termios->c_iflag & INPCK) 627 627 dport->port.read_status_mask |= DZ_FERR | DZ_PERR; 628 - if (termios->c_iflag & (BRKINT | PARMRK)) 628 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 629 629 dport->port.read_status_mask |= DZ_BREAK; 630 630 631 631 /* characters to ignore */
+1 -1
drivers/tty/serial/efm32-uart.c
··· 407 407 if (new->c_iflag & INPCK) 408 408 port->read_status_mask |= 409 409 UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR; 410 - if (new->c_iflag & (BRKINT | PARMRK)) 410 + if (new->c_iflag & (IGNBRK | BRKINT | PARMRK)) 411 411 port->read_status_mask |= SW_UARTn_RXDATAX_BERR; 412 412 413 413 port->ignore_status_mask = 0;
+1 -1
drivers/tty/serial/fsl_lpuart.c
··· 902 902 sport->port.read_status_mask = 0; 903 903 if (termios->c_iflag & INPCK) 904 904 sport->port.read_status_mask |= (UARTSR1_FE | UARTSR1_PE); 905 - if (termios->c_iflag & (BRKINT | PARMRK)) 905 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 906 906 sport->port.read_status_mask |= UARTSR1_FE; 907 907 908 908 /* characters to ignore */
+1 -1
drivers/tty/serial/ip22zilog.c
··· 850 850 up->port.read_status_mask = Rx_OVR; 851 851 if (iflag & INPCK) 852 852 up->port.read_status_mask |= CRC_ERR | PAR_ERR; 853 - if (iflag & (BRKINT | PARMRK)) 853 + if (iflag & (IGNBRK | BRKINT | PARMRK)) 854 854 up->port.read_status_mask |= BRK_ABRT; 855 855 856 856 up->port.ignore_status_mask = 0;
+1 -1
drivers/tty/serial/m32r_sio.c
··· 737 737 up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; 738 738 if (termios->c_iflag & INPCK) 739 739 up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; 740 - if (termios->c_iflag & (BRKINT | PARMRK)) 740 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 741 741 up->port.read_status_mask |= UART_LSR_BI; 742 742 743 743 /*
+1 -1
drivers/tty/serial/max310x.c
··· 835 835 if (termios->c_iflag & INPCK) 836 836 port->read_status_mask |= MAX310X_LSR_RXPAR_BIT | 837 837 MAX310X_LSR_FRERR_BIT; 838 - if (termios->c_iflag & (BRKINT | PARMRK)) 838 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 839 839 port->read_status_mask |= MAX310X_LSR_RXBRK_BIT; 840 840 841 841 /* Set status ignore mask */
+6
drivers/tty/serial/mcf.c
··· 248 248 mr1 |= MCFUART_MR1_PARITYNONE; 249 249 } 250 250 251 + /* 252 + * FIXME: port->read_status_mask and port->ignore_status_mask 253 + * need to be initialized based on termios settings for 254 + * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT 255 + */ 256 + 251 257 if (termios->c_cflag & CSTOPB) 252 258 mr2 |= MCFUART_MR2_STOP2; 253 259 else
+1 -1
drivers/tty/serial/mfd.c
··· 977 977 up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; 978 978 if (termios->c_iflag & INPCK) 979 979 up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; 980 - if (termios->c_iflag & (BRKINT | PARMRK)) 980 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 981 981 up->port.read_status_mask |= UART_LSR_BI; 982 982 983 983 /* Characters to ignore */
+1 -1
drivers/tty/serial/mpsc.c
··· 1458 1458 pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE 1459 1459 | SDMA_DESC_CMDSTAT_FR; 1460 1460 1461 - if (termios->c_iflag & (BRKINT | PARMRK)) 1461 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 1462 1462 pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR; 1463 1463 1464 1464 /* Characters/events to ignore */
+1 -1
drivers/tty/serial/msm_serial.c
··· 582 582 port->read_status_mask = 0; 583 583 if (termios->c_iflag & INPCK) 584 584 port->read_status_mask |= UART_SR_PAR_FRAME_ERR; 585 - if (termios->c_iflag & (BRKINT | PARMRK)) 585 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 586 586 port->read_status_mask |= UART_SR_RX_BREAK; 587 587 588 588 uart_update_timeout(port, termios->c_cflag, baud);
+1 -1
drivers/tty/serial/mxs-auart.c
··· 604 604 605 605 if (termios->c_iflag & INPCK) 606 606 u->read_status_mask |= AUART_STAT_PERR; 607 - if (termios->c_iflag & (BRKINT | PARMRK)) 607 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 608 608 u->read_status_mask |= AUART_STAT_BERR; 609 609 610 610 /*
+1 -1
drivers/tty/serial/netx-serial.c
··· 419 419 } 420 420 421 421 port->read_status_mask = 0; 422 - if (termios->c_iflag & (BRKINT | PARMRK)) 422 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 423 423 port->read_status_mask |= SR_BE; 424 424 if (termios->c_iflag & INPCK) 425 425 port->read_status_mask |= SR_PE | SR_FE;
+1 -1
drivers/tty/serial/pmac_zilog.c
··· 1092 1092 uap->port.read_status_mask = Rx_OVR; 1093 1093 if (iflag & INPCK) 1094 1094 uap->port.read_status_mask |= CRC_ERR | PAR_ERR; 1095 - if (iflag & (BRKINT | PARMRK)) 1095 + if (iflag & (IGNBRK | BRKINT | PARMRK)) 1096 1096 uap->port.read_status_mask |= BRK_ABRT; 1097 1097 1098 1098 uap->port.ignore_status_mask = 0;
+1 -1
drivers/tty/serial/pnx8xxx_uart.c
··· 477 477 sport->port.read_status_mask |= 478 478 FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | 479 479 FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); 480 - if (termios->c_iflag & (BRKINT | PARMRK)) 480 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 481 481 sport->port.read_status_mask |= 482 482 ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); 483 483
+1 -1
drivers/tty/serial/pxa.c
··· 492 492 up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; 493 493 if (termios->c_iflag & INPCK) 494 494 up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; 495 - if (termios->c_iflag & (BRKINT | PARMRK)) 495 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 496 496 up->port.read_status_mask |= UART_LSR_BI; 497 497 498 498 /*
+1 -1
drivers/tty/serial/sb1250-duart.c
··· 596 596 if (termios->c_iflag & INPCK) 597 597 uport->read_status_mask |= M_DUART_FRM_ERR | 598 598 M_DUART_PARITY_ERR; 599 - if (termios->c_iflag & (BRKINT | PARMRK)) 599 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 600 600 uport->read_status_mask |= M_DUART_RCVD_BRK; 601 601 602 602 uport->ignore_status_mask = 0;
+1 -1
drivers/tty/serial/sccnxp.c
··· 665 665 port->read_status_mask = SR_OVR; 666 666 if (termios->c_iflag & INPCK) 667 667 port->read_status_mask |= SR_PE | SR_FE; 668 - if (termios->c_iflag & (BRKINT | PARMRK)) 668 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 669 669 port->read_status_mask |= SR_BRK; 670 670 671 671 /* Set status ignore mask */
+1 -1
drivers/tty/serial/serial_ks8695.c
··· 437 437 port->read_status_mask = URLS_URROE; 438 438 if (termios->c_iflag & INPCK) 439 439 port->read_status_mask |= (URLS_URFE | URLS_URPE); 440 - if (termios->c_iflag & (BRKINT | PARMRK)) 440 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 441 441 port->read_status_mask |= URLS_URBI; 442 442 443 443 /*
+1 -1
drivers/tty/serial/serial_txx9.c
··· 697 697 TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS; 698 698 if (termios->c_iflag & INPCK) 699 699 up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER; 700 - if (termios->c_iflag & (BRKINT | PARMRK)) 700 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 701 701 up->port.read_status_mask |= TXX9_SIDISR_UBRK; 702 702 703 703 /*
+1 -1
drivers/tty/serial/sirfsoc_uart.c
··· 896 896 if (termios->c_iflag & INPCK) 897 897 port->read_status_mask |= uint_en->sirfsoc_frm_err_en; 898 898 } 899 - if (termios->c_iflag & (BRKINT | PARMRK)) 899 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 900 900 port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en; 901 901 if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { 902 902 if (termios->c_iflag & IGNPAR)
+1 -1
drivers/tty/serial/st-asc.c
··· 547 547 ascport->port.read_status_mask = ASC_RXBUF_DUMMY_OE; 548 548 if (termios->c_iflag & INPCK) 549 549 ascport->port.read_status_mask |= ASC_RXBUF_FE | ASC_RXBUF_PE; 550 - if (termios->c_iflag & (BRKINT | PARMRK)) 550 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 551 551 ascport->port.read_status_mask |= ASC_RXBUF_DUMMY_BE; 552 552 553 553 /*
+1 -1
drivers/tty/serial/sunsab.c
··· 719 719 if (iflag & INPCK) 720 720 up->port.read_status_mask |= (SAB82532_ISR0_PERR | 721 721 SAB82532_ISR0_FERR); 722 - if (iflag & (BRKINT | PARMRK)) 722 + if (iflag & (IGNBRK | BRKINT | PARMRK)) 723 723 up->port.read_status_mask |= (SAB82532_ISR1_BRK << 8); 724 724 725 725 /*
+1 -1
drivers/tty/serial/sunsu.c
··· 834 834 up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; 835 835 if (iflag & INPCK) 836 836 up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; 837 - if (iflag & (BRKINT | PARMRK)) 837 + if (iflag & (IGNBRK | BRKINT | PARMRK)) 838 838 up->port.read_status_mask |= UART_LSR_BI; 839 839 840 840 /*
+1 -1
drivers/tty/serial/sunzilog.c
··· 915 915 up->port.read_status_mask = Rx_OVR; 916 916 if (iflag & INPCK) 917 917 up->port.read_status_mask |= CRC_ERR | PAR_ERR; 918 - if (iflag & (BRKINT | PARMRK)) 918 + if (iflag & (IGNBRK | BRKINT | PARMRK)) 919 919 up->port.read_status_mask |= BRK_ABRT; 920 920 921 921 up->port.ignore_status_mask = 0;
+1 -1
drivers/tty/serial/ucc_uart.c
··· 936 936 port->read_status_mask = BD_SC_EMPTY | BD_SC_OV; 937 937 if (termios->c_iflag & INPCK) 938 938 port->read_status_mask |= BD_SC_FR | BD_SC_PR; 939 - if (termios->c_iflag & (BRKINT | PARMRK)) 939 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 940 940 port->read_status_mask |= BD_SC_BR; 941 941 942 942 /*
+1 -1
drivers/tty/serial/vr41xx_siu.c
··· 559 559 port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR; 560 560 if (c_iflag & INPCK) 561 561 port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; 562 - if (c_iflag & (BRKINT | PARMRK)) 562 + if (c_iflag & (IGNBRK | BRKINT | PARMRK)) 563 563 port->read_status_mask |= UART_LSR_BI; 564 564 565 565 port->ignore_status_mask = 0;
+1 -1
drivers/tty/serial/zs.c
··· 923 923 uport->read_status_mask = Rx_OVR; 924 924 if (termios->c_iflag & INPCK) 925 925 uport->read_status_mask |= FRM_ERR | PAR_ERR; 926 - if (termios->c_iflag & (BRKINT | PARMRK)) 926 + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 927 927 uport->read_status_mask |= Rx_BRK; 928 928 929 929 uport->ignore_status_mask = 0;