Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+44 −38
Original line number Original line Diff line number Diff line
@@ -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)


	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,
	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);
}
}
+2 −0
Original line number Original line Diff line number Diff line
@@ -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))