aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2006-01-04 16:55:09 +0000
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-01-04 16:55:09 +0000
commit2af7cd68f1ed20e2e72c91988c3d4f457fa29ebc (patch)
treea242ce0d1ecd154ef6bfa7aaf910a003bed3abdd /drivers/serial
parentLinux v2.6.15 (diff)
downloadlinux-dev-2af7cd68f1ed20e2e72c91988c3d4f457fa29ebc.tar.xz
linux-dev-2af7cd68f1ed20e2e72c91988c3d4f457fa29ebc.zip
[Serial] Don't miss modem status changes
Reading the MSR register on 8250-compatible UARTs results in any modem status interrupts being cleared. To avoid missing any status changes, arrange for get_mctrl() to read the current status via check_modem_status(), which will process any pending state changes for us. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/8250.c33
1 files changed, 16 insertions, 17 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index d2bcd1f87cd6..076bf848e4d1 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1255,25 +1255,24 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up)
__stop_tx(up);
}
-static _INLINE_ void check_modem_status(struct uart_8250_port *up)
+static unsigned int check_modem_status(struct uart_8250_port *up)
{
- int status;
+ unsigned int status = serial_in(up, UART_MSR);
- status = serial_in(up, UART_MSR);
+ if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI) {
+ if (status & UART_MSR_TERI)
+ up->port.icount.rng++;
+ if (status & UART_MSR_DDSR)
+ up->port.icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+ if (status & UART_MSR_DCTS)
+ uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
- if ((status & UART_MSR_ANY_DELTA) == 0)
- return;
-
- if (status & UART_MSR_TERI)
- up->port.icount.rng++;
- if (status & UART_MSR_DDSR)
- up->port.icount.dsr++;
- if (status & UART_MSR_DDCD)
- uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
- if (status & UART_MSR_DCTS)
- uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+ wake_up_interruptible(&up->port.info->delta_msr_wait);
+ }
- wake_up_interruptible(&up->port.info->delta_msr_wait);
+ return status;
}
/*
@@ -1454,10 +1453,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
static unsigned int serial8250_get_mctrl(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
- unsigned char status;
+ unsigned int status;
unsigned int ret;
- status = serial_in(up, UART_MSR);
+ status = check_modem_status(up);
ret = 0;
if (status & UART_MSR_DCD)