Commit 54c0f37e authored by Maciej W. Rozycki's avatar Maciej W. Rozycki Committed by Linus Torvalds

dz: handle special conditions on reception correctly

Handle the read and ignore status masks correctly.  Handle the BREAK condition
as expected: a framing error with a null character is a BREAK, any other
framing error is a framing error indeed.
Signed-off-by: default avatarMaciej W. Rozycki <macro@linux-mips.org>
Cc: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 43d46ab1
...@@ -166,6 +166,7 @@ static void dz_enable_ms(struct uart_port *port) ...@@ -166,6 +166,7 @@ static void dz_enable_ms(struct uart_port *port)
*/ */
static inline void dz_receive_chars(struct dz_port *dport_in) static inline void dz_receive_chars(struct dz_port *dport_in)
{ {
struct uart_port *uport;
struct dz_port *dport; struct dz_port *dport;
struct tty_struct *tty = NULL; struct tty_struct *tty = NULL;
struct uart_icount *icount; struct uart_icount *icount;
...@@ -176,58 +177,57 @@ static inline void dz_receive_chars(struct dz_port *dport_in) ...@@ -176,58 +177,57 @@ static inline void dz_receive_chars(struct dz_port *dport_in)
while ((status = dz_in(dport_in, DZ_RBUF)) & DZ_DVAL) { while ((status = dz_in(dport_in, DZ_RBUF)) & DZ_DVAL) {
dport = &dz_ports[LINE(status)]; dport = &dz_ports[LINE(status)];
tty = dport->port.info->tty; /* point to the proper dev */ uport = &dport->port;
tty = uport->info->tty; /* point to the proper dev */
ch = UCHAR(status); /* grab the char */ ch = UCHAR(status); /* grab the char */
flag = TTY_NORMAL;
icount = &dport->port.icount; icount = &uport->icount;
icount->rx++; icount->rx++;
flag = TTY_NORMAL; if (unlikely(status & (DZ_OERR | DZ_FERR | DZ_PERR))) {
if (status & DZ_FERR) { /* frame error */
/* /*
* There is no separate BREAK status bit, so * There is no separate BREAK status bit, so treat
* treat framing errors as BREAKs for Magic SysRq * null characters with framing errors as BREAKs;
* and SAK; normally, otherwise. * normally, otherwise. For this move the Framing
* Error bit to a simulated BREAK bit.
*/ */
if (uart_handle_break(&dport->port)) if (!ch) {
status |= (status & DZ_FERR) >>
(ffs(DZ_FERR) - ffs(DZ_BREAK));
status &= ~DZ_FERR;
}
/* Handle SysRq/SAK & keep track of the statistics. */
if (status & DZ_BREAK) {
icount->brk++;
if (uart_handle_break(uport))
continue; continue;
if (dport->port.flags & UPF_SAK) } else if (status & DZ_FERR)
icount->frame++;
else if (status & DZ_PERR)
icount->parity++;
if (status & DZ_OERR)
icount->overrun++;
status &= uport->read_status_mask;
if (status & DZ_BREAK)
flag = TTY_BREAK; flag = TTY_BREAK;
else else if (status & DZ_FERR)
flag = TTY_FRAME; flag = TTY_FRAME;
} else if (status & DZ_OERR) /* overrun error */ else if (status & DZ_PERR)
flag = TTY_OVERRUN;
else if (status & DZ_PERR) /* parity error */
flag = TTY_PARITY; flag = TTY_PARITY;
/* keep track of the statistics */
switch (flag) {
case TTY_FRAME:
icount->frame++;
break;
case TTY_PARITY:
icount->parity++;
break;
case TTY_OVERRUN:
icount->overrun++;
break;
case TTY_BREAK:
icount->brk++;
break;
default:
break;
} }
if (uart_handle_sysrq_char(&dport->port, ch)) if (uart_handle_sysrq_char(uport, ch))
continue; continue;
if ((status & dport->port.ignore_status_mask) == 0) { uart_insert_char(uport, status, DZ_OERR, ch, flag);
uart_insert_char(&dport->port,
status, DZ_OERR, ch, flag);
lines_rx[LINE(status)] = 1; lines_rx[LINE(status)] = 1;
} }
}
for (i = 0; i < DZ_NB_PORT; i++) for (i = 0; i < DZ_NB_PORT; i++)
if (lines_rx[i]) if (lines_rx[i])
tty_flip_buffer_push(dz_ports[i].port.info->tty); tty_flip_buffer_push(dz_ports[i].port.info->tty);
...@@ -556,11 +556,17 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, ...@@ -556,11 +556,17 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
dport->port.read_status_mask = DZ_OERR; dport->port.read_status_mask = DZ_OERR;
if (termios->c_iflag & INPCK) if (termios->c_iflag & INPCK)
dport->port.read_status_mask |= DZ_FERR | DZ_PERR; dport->port.read_status_mask |= DZ_FERR | DZ_PERR;
if (termios->c_iflag & (BRKINT | PARMRK))
dport->port.read_status_mask |= DZ_BREAK;
/* characters to ignore */ /* characters to ignore */
uport->ignore_status_mask = 0; uport->ignore_status_mask = 0;
if ((termios->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
dport->port.ignore_status_mask |= DZ_OERR;
if (termios->c_iflag & IGNPAR) if (termios->c_iflag & IGNPAR)
dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR; dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR;
if (termios->c_iflag & IGNBRK)
dport->port.ignore_status_mask |= DZ_BREAK;
spin_unlock_irqrestore(&dport->port.lock, flags); spin_unlock_irqrestore(&dport->port.lock, flags);
} }
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#define DZ_FERR 0x2000 /* Frame error indicator */ #define DZ_FERR 0x2000 /* Frame error indicator */
#define DZ_PERR 0x1000 /* Parity error indicator */ #define DZ_PERR 0x1000 /* Parity error indicator */
#define DZ_BREAK 0x0800 /* BREAK event software flag */
#define LINE(x) ((x & DZ_LINE_MASK) >> 8) /* Get the line number #define LINE(x) ((x & DZ_LINE_MASK) >> 8) /* Get the line number
from the input buffer */ from the input buffer */
#define UCHAR(x) ((unsigned char)(x & DZ_RBUF_MASK)) #define UCHAR(x) ((unsigned char)(x & DZ_RBUF_MASK))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment