Blackfin serial driver: implement support for ignoring parity/break errors

properly setting up and respecting the read_status_mask / ignore_status_mask fields of the serial core

Signed-off-by: Mike Frysinger <michael.frysinger@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Mike Frysinger 2007-05-21 18:09:39 +08:00 committed by Linus Torvalds
parent 5c4e472b0a
commit 2ac5ee4738
1 changed files with 61 additions and 36 deletions

View File

@ -6,8 +6,6 @@
* Created: * Created:
* Description: Driver for blackfin 5xx serial ports * Description: Driver for blackfin 5xx serial ports
* *
* Rev: $Id: bfin_5xx.c,v 1.19 2006/09/24 02:33:53 aubrey Exp $
*
* Modified: * Modified:
* Copyright 2006 Analog Devices Inc. * Copyright 2006 Analog Devices Inc.
* *
@ -152,7 +150,7 @@ static void local_put_char(struct bfin_serial_port *uart, char ch)
static void bfin_serial_rx_chars(struct bfin_serial_port *uart) static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{ {
struct tty_struct *tty = uart->port.info?uart->port.info->tty:0; struct tty_struct *tty = uart->port.info->tty;
unsigned int status, ch, flg; unsigned int status, ch, flg;
#ifdef BF533_FAMILY #ifdef BF533_FAMILY
static int in_break = 0; static int in_break = 0;
@ -173,8 +171,10 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
if (ch != 0) { if (ch != 0) {
in_break = 0; in_break = 0;
ch = UART_GET_CHAR(uart); ch = UART_GET_CHAR(uart);
} if (bfin_revid() < 5)
return; return;
} else
return;
} }
#endif #endif
@ -185,27 +185,32 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
uart->port.icount.brk++; uart->port.icount.brk++;
if (uart_handle_break(&uart->port)) if (uart_handle_break(&uart->port))
goto ignore_char; goto ignore_char;
flg = TTY_BREAK; }
} else if (status & PE) { if (status & PE)
flg = TTY_PARITY;
uart->port.icount.parity++; uart->port.icount.parity++;
} else if (status & OE) { if (status & OE)
flg = TTY_OVERRUN;
uart->port.icount.overrun++; uart->port.icount.overrun++;
} else if (status & FE) { if (status & FE)
flg = TTY_FRAME;
uart->port.icount.frame++; uart->port.icount.frame++;
} else
status &= uart->port.read_status_mask;
if (status & BI)
flg = TTY_BREAK;
else if (status & PE)
flg = TTY_PARITY;
else if (status & FE)
flg = TTY_FRAME;
else
flg = TTY_NORMAL; flg = TTY_NORMAL;
if (uart_handle_sysrq_char(&uart->port, ch)) if (uart_handle_sysrq_char(&uart->port, ch))
goto ignore_char; goto ignore_char;
if (tty)
uart_insert_char(&uart->port, status, 2, ch, flg);
ignore_char: uart_insert_char(&uart->port, status, OE, ch, flg);
if (tty)
tty_flip_buffer_push(tty); ignore_char:
tty_flip_buffer_push(tty);
} }
static void bfin_serial_tx_chars(struct bfin_serial_port *uart) static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
@ -254,7 +259,6 @@ static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id) static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
{ {
struct bfin_serial_port *uart = dev_id; struct bfin_serial_port *uart = dev_id;
unsigned short status;
spin_lock(&uart->port.lock); spin_lock(&uart->port.lock);
while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_TX_READY) while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_TX_READY)
@ -325,7 +329,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
spin_unlock_irqrestore(&uart->port.lock, flags); spin_unlock_irqrestore(&uart->port.lock, flags);
} }
static void bfin_serial_dma_rx_chars(struct bfin_serial_port * uart) static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
{ {
struct tty_struct *tty = uart->port.info->tty; struct tty_struct *tty = uart->port.info->tty;
int i, flg, status; int i, flg, status;
@ -337,25 +341,32 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port * uart)
uart->port.icount.brk++; uart->port.icount.brk++;
if (uart_handle_break(&uart->port)) if (uart_handle_break(&uart->port))
goto dma_ignore_char; goto dma_ignore_char;
flg = TTY_BREAK; }
} else if (status & PE) { if (status & PE)
flg = TTY_PARITY;
uart->port.icount.parity++; uart->port.icount.parity++;
} else if (status & OE) { if (status & OE)
flg = TTY_OVERRUN;
uart->port.icount.overrun++; uart->port.icount.overrun++;
} else if (status & FE) { if (status & FE)
flg = TTY_FRAME;
uart->port.icount.frame++; uart->port.icount.frame++;
} else
status &= uart->port.read_status_mask;
if (status & BI)
flg = TTY_BREAK;
else if (status & PE)
flg = TTY_PARITY;
else if (status & FE)
flg = TTY_FRAME;
else
flg = TTY_NORMAL; flg = TTY_NORMAL;
for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) { for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) {
if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i])) if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
goto dma_ignore_char; goto dma_ignore_char;
uart_insert_char(&uart->port, status, 2, uart->rx_dma_buf.buf[i], flg); uart_insert_char(&uart->port, status, OE, uart->rx_dma_buf.buf[i], flg);
} }
dma_ignore_char:
dma_ignore_char:
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
} }
@ -620,13 +631,27 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
lcr |= EPS; lcr |= EPS;
} }
/* These controls are not implemented for this port */ port->read_status_mask = OE;
termios->c_iflag |= INPCK | BRKINT | PARMRK; if (termios->c_iflag & INPCK)
termios->c_iflag &= ~(IGNPAR | IGNBRK); port->read_status_mask |= (FE | PE);
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= BI;
/* These controls are not implemented for this port */ /*
termios->c_iflag |= INPCK | BRKINT | PARMRK; * Characters to ignore
termios->c_iflag &= ~(IGNPAR | IGNBRK); */
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= FE | PE;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= BI;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= OE;
}
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud); quot = uart_get_divisor(port, baud);