diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2014-09-10 15:06:24 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-09-24 00:19:35 -0400 |
commit | 299245a145b2ad4cfb4c5432eb1264299f55e7e0 (patch) | |
tree | 53eb54bc7cf744f3813c34c79769529d0df6c223 /drivers/tty | |
parent | 4d90bb147ef6b91f529a21b498ff2b5fdc6785b4 (diff) |
serial: core: Privatize modem status enable flags
The serial core uses the tty port flags, ASYNC_CTS_FLOW and
ASYNC_CD_CHECK, to track whether CTS and DCD changes should be
ignored or handled. However, the tty port flags are not safe for
atomic bit operations and no lock provides serialized updates.
Introduce the struct uart_port status field to track CTS and DCD
enable states, and serialize access with uart port lock. Substitute
uart_cts_enabled() helper for tty_port_cts_enabled().
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/mxs-auart.c | 2 | ||||
-rw-r--r-- | drivers/tty/serial/serial_core.c | 29 |
2 files changed, 18 insertions, 13 deletions
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index b5c329248c81..10c29334fe2f 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c | |||
@@ -408,7 +408,7 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl) | |||
408 | 408 | ||
409 | ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS); | 409 | ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS); |
410 | if (mctrl & TIOCM_RTS) { | 410 | if (mctrl & TIOCM_RTS) { |
411 | if (tty_port_cts_enabled(&u->state->port)) | 411 | if (uart_cts_enabled(u)) |
412 | ctrl |= AUART_CTRL2_RTSEN; | 412 | ctrl |= AUART_CTRL2_RTSEN; |
413 | else | 413 | else |
414 | ctrl |= AUART_CTRL2_RTS; | 414 | ctrl |= AUART_CTRL2_RTS; |
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index f764de32b658..dd21ed900635 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c | |||
@@ -59,6 +59,11 @@ static void uart_change_pm(struct uart_state *state, | |||
59 | 59 | ||
60 | static void uart_port_shutdown(struct tty_port *port); | 60 | static void uart_port_shutdown(struct tty_port *port); |
61 | 61 | ||
62 | static int uart_dcd_enabled(struct uart_port *uport) | ||
63 | { | ||
64 | return uport->status & UPSTAT_DCD_ENABLE; | ||
65 | } | ||
66 | |||
62 | /* | 67 | /* |
63 | * This routine is used by the interrupt handler to schedule processing in | 68 | * This routine is used by the interrupt handler to schedule processing in |
64 | * the software interrupt portion of the driver. | 69 | * the software interrupt portion of the driver. |
@@ -130,7 +135,6 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, | |||
130 | int init_hw) | 135 | int init_hw) |
131 | { | 136 | { |
132 | struct uart_port *uport = state->uart_port; | 137 | struct uart_port *uport = state->uart_port; |
133 | struct tty_port *port = &state->port; | ||
134 | unsigned long page; | 138 | unsigned long page; |
135 | int retval = 0; | 139 | int retval = 0; |
136 | 140 | ||
@@ -176,12 +180,12 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, | |||
176 | uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); | 180 | uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); |
177 | } | 181 | } |
178 | 182 | ||
179 | if (tty_port_cts_enabled(port)) { | 183 | spin_lock_irq(&uport->lock); |
180 | spin_lock_irq(&uport->lock); | 184 | if (uart_cts_enabled(uport)) { |
181 | if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) | 185 | if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) |
182 | tty->hw_stopped = 1; | 186 | tty->hw_stopped = 1; |
183 | spin_unlock_irq(&uport->lock); | ||
184 | } | 187 | } |
188 | spin_unlock_irq(&uport->lock); | ||
185 | } | 189 | } |
186 | 190 | ||
187 | /* | 191 | /* |
@@ -435,7 +439,6 @@ EXPORT_SYMBOL(uart_get_divisor); | |||
435 | static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, | 439 | static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, |
436 | struct ktermios *old_termios) | 440 | struct ktermios *old_termios) |
437 | { | 441 | { |
438 | struct tty_port *port = &state->port; | ||
439 | struct uart_port *uport = state->uart_port; | 442 | struct uart_port *uport = state->uart_port; |
440 | struct ktermios *termios; | 443 | struct ktermios *termios; |
441 | 444 | ||
@@ -450,17 +453,19 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, | |||
450 | uport->ops->set_termios(uport, termios, old_termios); | 453 | uport->ops->set_termios(uport, termios, old_termios); |
451 | 454 | ||
452 | /* | 455 | /* |
453 | * Set flags based on termios cflag | 456 | * Set modem status enables based on termios cflag |
454 | */ | 457 | */ |
458 | spin_lock_irq(&uport->lock); | ||
455 | if (termios->c_cflag & CRTSCTS) | 459 | if (termios->c_cflag & CRTSCTS) |
456 | set_bit(ASYNCB_CTS_FLOW, &port->flags); | 460 | uport->status |= UPSTAT_CTS_ENABLE; |
457 | else | 461 | else |
458 | clear_bit(ASYNCB_CTS_FLOW, &port->flags); | 462 | uport->status &= ~UPSTAT_CTS_ENABLE; |
459 | 463 | ||
460 | if (termios->c_cflag & CLOCAL) | 464 | if (termios->c_cflag & CLOCAL) |
461 | clear_bit(ASYNCB_CHECK_CD, &port->flags); | 465 | uport->status &= ~UPSTAT_DCD_ENABLE; |
462 | else | 466 | else |
463 | set_bit(ASYNCB_CHECK_CD, &port->flags); | 467 | uport->status |= UPSTAT_DCD_ENABLE; |
468 | spin_unlock_irq(&uport->lock); | ||
464 | } | 469 | } |
465 | 470 | ||
466 | static inline int __uart_put_char(struct uart_port *port, | 471 | static inline int __uart_put_char(struct uart_port *port, |
@@ -2765,7 +2770,7 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status) | |||
2765 | 2770 | ||
2766 | uport->icount.dcd++; | 2771 | uport->icount.dcd++; |
2767 | 2772 | ||
2768 | if (port->flags & ASYNC_CHECK_CD) { | 2773 | if (uart_dcd_enabled(uport)) { |
2769 | if (status) | 2774 | if (status) |
2770 | wake_up_interruptible(&port->open_wait); | 2775 | wake_up_interruptible(&port->open_wait); |
2771 | else if (tty) | 2776 | else if (tty) |
@@ -2790,7 +2795,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status) | |||
2790 | 2795 | ||
2791 | uport->icount.cts++; | 2796 | uport->icount.cts++; |
2792 | 2797 | ||
2793 | if (tty_port_cts_enabled(port)) { | 2798 | if (uart_cts_enabled(uport)) { |
2794 | if (tty->hw_stopped) { | 2799 | if (tty->hw_stopped) { |
2795 | if (status) { | 2800 | if (status) { |
2796 | tty->hw_stopped = 0; | 2801 | tty->hw_stopped = 0; |