summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAlexander Shiyan <shc_work@mail.ru>2012-10-14 11:05:30 +0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-10-24 22:39:48 +0400
commitf27de95c2a2120526c8cb051d741b7eb09e78cc9 (patch)
treea77a16711ea877bdce3cdd8877e81902883194e0 /drivers
parentec335526b4bce21f6777d3917d6d67c16009ec63 (diff)
downloadlinux-f27de95c2a2120526c8cb051d741b7eb09e78cc9.tar.xz
serial: clps711x: Check for valid TTY in RX-interrupt
Signed-off-by: Alexander Shiyan <shc_work@mail.ru> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/tty/serial/clps711x.c59
1 files changed, 29 insertions, 30 deletions
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 73505c1edc7d..6039ebe349c0 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -55,8 +55,6 @@
#define TX_IRQ(port) ((port)->line ? IRQ_UTXINT2 : IRQ_UTXINT1)
#define RX_IRQ(port) ((port)->line ? IRQ_URXINT2 : IRQ_URXINT1)
-#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
-
struct clps711x_port {
struct uart_driver uart;
struct clk *uart_clk;
@@ -99,54 +97,55 @@ static void clps711xuart_enable_ms(struct uart_port *port)
static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
- struct tty_struct *tty = port->state->port.tty;
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
unsigned int status, ch, flg;
- status = clps_readl(SYSFLG(port));
- while (!(status & SYSFLG_URXFE)) {
- ch = clps_readl(UARTDR(port));
+ if (!tty)
+ return IRQ_HANDLED;
- port->icount.rx++;
+ for (;;) {
+ status = clps_readl(SYSFLG(port));
+ if (status & SYSFLG_URXFE)
+ break;
+ ch = clps_readw(UARTDR(port));
+ status = ch & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR);
+ ch &= 0xff;
+
+ port->icount.rx++;
flg = TTY_NORMAL;
- /*
- * Note that the error handling code is
- * out of the main execution path
- */
- if (unlikely(ch & UART_ANY_ERR)) {
- if (ch & UARTDR_PARERR)
+ if (unlikely(status)) {
+ if (status & UARTDR_PARERR)
port->icount.parity++;
- else if (ch & UARTDR_FRMERR)
+ else if (status & UARTDR_FRMERR)
port->icount.frame++;
- if (ch & UARTDR_OVERR)
+ else if (status & UARTDR_OVERR)
port->icount.overrun++;
- ch &= port->read_status_mask;
+ status &= port->read_status_mask;
- if (ch & UARTDR_PARERR)
+ if (status & UARTDR_PARERR)
flg = TTY_PARITY;
- else if (ch & UARTDR_FRMERR)
+ else if (status & UARTDR_FRMERR)
flg = TTY_FRAME;
-
-#ifdef SUPPORT_SYSRQ
- port->sysrq = 0;
-#endif
+ else if (status & UARTDR_OVERR)
+ flg = TTY_OVERRUN;
}
if (uart_handle_sysrq_char(port, ch))
- goto ignore_char;
+ continue;
- /*
- * CHECK: does overrun affect the current character?
- * ASSUMPTION: it does not.
- */
- uart_insert_char(port, ch, UARTDR_OVERR, ch, flg);
+ if (status & port->ignore_status_mask)
+ continue;
- ignore_char:
- status = clps_readl(SYSFLG(port));
+ uart_insert_char(port, status, UARTDR_OVERR, ch, flg);
}
+
tty_flip_buffer_push(tty);
+
+ tty_kref_put(tty);
+
return IRQ_HANDLED;
}