Skip to content

Commit

Permalink
dz: handle special conditions on reception correctly
Browse files Browse the repository at this point in the history
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: Maciej W. Rozycki <[email protected]>
Cc: Jiri Slaby <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Maciej W. Rozycki authored and Linus Torvalds committed Feb 7, 2008
1 parent 43d46ab commit 54c0f37
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 38 deletions.
82 changes: 44 additions & 38 deletions drivers/serial/dz.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ static void dz_enable_ms(struct uart_port *port)
*/
static inline void dz_receive_chars(struct dz_port *dport_in)
{
struct uart_port *uport;
struct dz_port *dport;
struct tty_struct *tty = NULL;
struct uart_icount *icount;
Expand All @@ -176,57 +177,56 @@ static inline void dz_receive_chars(struct dz_port *dport_in)

while ((status = dz_in(dport_in, DZ_RBUF)) & DZ_DVAL) {
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 */
flag = TTY_NORMAL;

icount = &dport->port.icount;
icount = &uport->icount;
icount->rx++;

flag = TTY_NORMAL;
if (status & DZ_FERR) { /* frame error */
if (unlikely(status & (DZ_OERR | DZ_FERR | DZ_PERR))) {

/*
* There is no separate BREAK status bit, so
* treat framing errors as BREAKs for Magic SysRq
* and SAK; normally, otherwise.
* There is no separate BREAK status bit, so treat
* null characters with framing errors as BREAKs;
* normally, otherwise. For this move the Framing
* Error bit to a simulated BREAK bit.
*/
if (uart_handle_break(&dport->port))
continue;
if (dport->port.flags & UPF_SAK)
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;
} 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;
else
else if (status & DZ_FERR)
flag = TTY_FRAME;
} else if (status & DZ_OERR) /* overrun error */
flag = TTY_OVERRUN;
else if (status & DZ_PERR) /* parity error */
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;
else if (status & DZ_PERR)
flag = TTY_PARITY;

}

if (uart_handle_sysrq_char(&dport->port, ch))
if (uart_handle_sysrq_char(uport, ch))
continue;

if ((status & dport->port.ignore_status_mask) == 0) {
uart_insert_char(&dport->port,
status, DZ_OERR, ch, flag);
lines_rx[LINE(status)] = 1;
}
uart_insert_char(uport, status, DZ_OERR, ch, flag);
lines_rx[LINE(status)] = 1;
}
for (i = 0; i < DZ_NB_PORT; i++)
if (lines_rx[i])
Expand Down Expand Up @@ -556,11 +556,17 @@ 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))
dport->port.read_status_mask |= DZ_BREAK;

/* characters to ignore */
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)
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);
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/serial/dz.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
#define DZ_FERR 0x2000 /* Frame 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
from the input buffer */
#define UCHAR(x) ((unsigned char)(x & DZ_RBUF_MASK))
Expand Down

0 comments on commit 54c0f37

Please sign in to comment.