[PATCH] dz: Handle special conditions on reception correctly

From: Maciej W. Rozycki
Date: Fri Oct 19 2007 - 16:51:29 EST


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 <macro@xxxxxxxxxxxxxx>
---
Tested with checkpatch.pl and at the run-time -- MIPS/Linux on a
DECstation 5000/200.

Please apply,

Maciej

patch-mips-2.6.23-rc5-20070904-dz-receive-8
diff -up --recursive --new-file linux-mips-2.6.23-rc5-20070904.macro/drivers/serial/dz.c linux-mips-2.6.23-rc5-20070904/drivers/serial/dz.c
--- linux-mips-2.6.23-rc5-20070904.macro/drivers/serial/dz.c 2007-05-02 04:56:10.000000000 +0000
+++ linux-mips-2.6.23-rc5-20070904/drivers/serial/dz.c 2007-10-13 22:24:40.000000000 +0000
@@ -172,6 +172,7 @@ static void dz_enable_ms(struct uart_por
*/
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;
@@ -182,57 +183,56 @@ static inline void dz_receive_chars(stru

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])
@@ -552,11 +552,17 @@ static void dz_set_termios(struct uart_p
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);
}
diff -up --recursive --new-file linux-mips-2.6.23-rc5-20070904.macro/drivers/serial/dz.h linux-mips-2.6.23-rc5-20070904/drivers/serial/dz.h
--- linux-mips-2.6.23-rc5-20070904.macro/drivers/serial/dz.h 2007-02-05 16:38:50.000000000 +0000
+++ linux-mips-2.6.23-rc5-20070904/drivers/serial/dz.h 2007-09-08 12:20:40.000000000 +0000
@@ -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))
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/