aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/tty/serial/8250/8250_omap.c7
-rw-r--r--drivers/tty/serial/omap-serial.c7
-rw-r--r--drivers/tty/serial/serial_core.c76
-rw-r--r--include/linux/serial_core.h21
4 files changed, 59 insertions, 52 deletions
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 9191d05cfaf0..6e4ff7148ead 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -421,8 +421,11 @@ static void omap_8250_set_termios(struct uart_port *port,
421 421
422 priv->efr = 0; 422 priv->efr = 0;
423 up->mcr &= ~(UART_MCR_RTS | UART_MCR_XONANY); 423 up->mcr &= ~(UART_MCR_RTS | UART_MCR_XONANY);
424 up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
425
424 if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) { 426 if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
425 /* Enable AUTORTS and AUTOCTS */ 427 /* Enable AUTORTS and AUTOCTS */
428 up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
426 priv->efr |= UART_EFR_CTS | UART_EFR_RTS; 429 priv->efr |= UART_EFR_CTS | UART_EFR_RTS;
427 } else if (up->port.flags & UPF_SOFT_FLOW) { 430 } else if (up->port.flags & UPF_SOFT_FLOW) {
428 /* 431 /*
@@ -438,8 +441,10 @@ static void omap_8250_set_termios(struct uart_port *port,
438 * Enable XON/XOFF flow control on output. 441 * Enable XON/XOFF flow control on output.
439 * Transmit XON1, XOFF1 442 * Transmit XON1, XOFF1
440 */ 443 */
441 if (termios->c_iflag & IXOFF) 444 if (termios->c_iflag & IXOFF) {
445 up->port.status |= UPSTAT_AUTOXOFF;
442 priv->efr |= OMAP_UART_SW_TX; 446 priv->efr |= OMAP_UART_SW_TX;
447 }
443 448
444 /* 449 /*
445 * IXANY Flag: 450 * IXANY Flag:
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index b1cf9a3b673a..6129fe515932 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1053,8 +1053,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
1053 1053
1054 serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); 1054 serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
1055 1055
1056 up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
1057
1056 if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) { 1058 if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
1057 /* Enable AUTORTS and AUTOCTS */ 1059 /* Enable AUTORTS and AUTOCTS */
1060 up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
1058 up->efr |= UART_EFR_CTS | UART_EFR_RTS; 1061 up->efr |= UART_EFR_CTS | UART_EFR_RTS;
1059 1062
1060 /* Ensure MCR RTS is asserted */ 1063 /* Ensure MCR RTS is asserted */
@@ -1081,8 +1084,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
1081 * Enable XON/XOFF flow control on output. 1084 * Enable XON/XOFF flow control on output.
1082 * Transmit XON1, XOFF1 1085 * Transmit XON1, XOFF1
1083 */ 1086 */
1084 if (termios->c_iflag & IXOFF) 1087 if (termios->c_iflag & IXOFF) {
1088 up->port.status |= UPSTAT_AUTOXOFF;
1085 up->efr |= OMAP_UART_SW_TX; 1089 up->efr |= OMAP_UART_SW_TX;
1090 }
1086 1091
1087 /* 1092 /*
1088 * IXANY Flag: 1093 * IXANY Flag:
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 2c67a077042a..6a1055ae3437 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -179,14 +179,6 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
179 if (tty->termios.c_cflag & CBAUD) 179 if (tty->termios.c_cflag & CBAUD)
180 uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); 180 uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
181 } 181 }
182
183 spin_lock_irq(&uport->lock);
184 if (uart_cts_enabled(uport) &&
185 !(uport->ops->get_mctrl(uport) & TIOCM_CTS))
186 uport->hw_stopped = 1;
187 else
188 uport->hw_stopped = 0;
189 spin_unlock_irq(&uport->lock);
190 } 182 }
191 183
192 /* 184 /*
@@ -442,6 +434,7 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
442{ 434{
443 struct uart_port *uport = state->uart_port; 435 struct uart_port *uport = state->uart_port;
444 struct ktermios *termios; 436 struct ktermios *termios;
437 int hw_stopped;
445 438
446 /* 439 /*
447 * If we have no tty, termios, or the port does not exist, 440 * If we have no tty, termios, or the port does not exist,
@@ -466,6 +459,18 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
466 uport->status &= ~UPSTAT_DCD_ENABLE; 459 uport->status &= ~UPSTAT_DCD_ENABLE;
467 else 460 else
468 uport->status |= UPSTAT_DCD_ENABLE; 461 uport->status |= UPSTAT_DCD_ENABLE;
462
463 /* reset sw-assisted CTS flow control based on (possibly) new mode */
464 hw_stopped = uport->hw_stopped;
465 uport->hw_stopped = uart_softcts_mode(uport) &&
466 !(uport->ops->get_mctrl(uport) & TIOCM_CTS);
467 if (uport->hw_stopped) {
468 if (!hw_stopped)
469 uport->ops->stop_tx(uport);
470 } else {
471 if (hw_stopped)
472 __uart_start(tty);
473 }
469 spin_unlock_irq(&uport->lock); 474 spin_unlock_irq(&uport->lock);
470} 475}
471 476
@@ -619,22 +624,22 @@ static void uart_throttle(struct tty_struct *tty)
619{ 624{
620 struct uart_state *state = tty->driver_data; 625 struct uart_state *state = tty->driver_data;
621 struct uart_port *port = state->uart_port; 626 struct uart_port *port = state->uart_port;
622 upf_t mask = 0; 627 upstat_t mask = 0;
623 628
624 if (I_IXOFF(tty)) 629 if (I_IXOFF(tty))
625 mask |= UPF_SOFT_FLOW; 630 mask |= UPSTAT_AUTOXOFF;
626 if (tty->termios.c_cflag & CRTSCTS) 631 if (tty->termios.c_cflag & CRTSCTS)
627 mask |= UPF_HARD_FLOW; 632 mask |= UPSTAT_AUTORTS;
628 633
629 if (port->flags & mask) { 634 if (port->status & mask) {
630 port->ops->throttle(port); 635 port->ops->throttle(port);
631 mask &= ~port->flags; 636 mask &= ~port->status;
632 } 637 }
633 638
634 if (mask & UPF_SOFT_FLOW) 639 if (mask & UPSTAT_AUTOXOFF)
635 uart_send_xchar(tty, STOP_CHAR(tty)); 640 uart_send_xchar(tty, STOP_CHAR(tty));
636 641
637 if (mask & UPF_HARD_FLOW) 642 if (mask & UPSTAT_AUTORTS)
638 uart_clear_mctrl(port, TIOCM_RTS); 643 uart_clear_mctrl(port, TIOCM_RTS);
639} 644}
640 645
@@ -642,22 +647,22 @@ static void uart_unthrottle(struct tty_struct *tty)
642{ 647{
643 struct uart_state *state = tty->driver_data; 648 struct uart_state *state = tty->driver_data;
644 struct uart_port *port = state->uart_port; 649 struct uart_port *port = state->uart_port;
645 upf_t mask = 0; 650 upstat_t mask = 0;
646 651
647 if (I_IXOFF(tty)) 652 if (I_IXOFF(tty))
648 mask |= UPF_SOFT_FLOW; 653 mask |= UPSTAT_AUTOXOFF;
649 if (tty->termios.c_cflag & CRTSCTS) 654 if (tty->termios.c_cflag & CRTSCTS)
650 mask |= UPF_HARD_FLOW; 655 mask |= UPSTAT_AUTORTS;
651 656
652 if (port->flags & mask) { 657 if (port->status & mask) {
653 port->ops->unthrottle(port); 658 port->ops->unthrottle(port);
654 mask &= ~port->flags; 659 mask &= ~port->status;
655 } 660 }
656 661
657 if (mask & UPF_SOFT_FLOW) 662 if (mask & UPSTAT_AUTOXOFF)
658 uart_send_xchar(tty, START_CHAR(tty)); 663 uart_send_xchar(tty, START_CHAR(tty));
659 664
660 if (mask & UPF_HARD_FLOW) 665 if (mask & UPSTAT_AUTORTS)
661 uart_set_mctrl(port, TIOCM_RTS); 666 uart_set_mctrl(port, TIOCM_RTS);
662} 667}
663 668
@@ -1351,30 +1356,6 @@ static void uart_set_termios(struct tty_struct *tty,
1351 mask |= TIOCM_RTS; 1356 mask |= TIOCM_RTS;
1352 uart_set_mctrl(uport, mask); 1357 uart_set_mctrl(uport, mask);
1353 } 1358 }
1354
1355 /*
1356 * If the port is doing h/w assisted flow control, do nothing.
1357 * We assume that port->hw_stopped has never been set.
1358 */
1359 if (uport->flags & UPF_HARD_FLOW)
1360 return;
1361
1362 /* Handle turning off CRTSCTS */
1363 if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
1364 spin_lock_irq(&uport->lock);
1365 uport->hw_stopped = 0;
1366 __uart_start(tty);
1367 spin_unlock_irq(&uport->lock);
1368 }
1369 /* Handle turning on CRTSCTS */
1370 else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
1371 spin_lock_irq(&uport->lock);
1372 if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) {
1373 uport->hw_stopped = 1;
1374 uport->ops->stop_tx(uport);
1375 }
1376 spin_unlock_irq(&uport->lock);
1377 }
1378} 1359}
1379 1360
1380/* 1361/*
@@ -2855,7 +2836,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
2855 2836
2856 uport->icount.cts++; 2837 uport->icount.cts++;
2857 2838
2858 if (uart_cts_enabled(uport)) { 2839 if (uart_softcts_mode(uport)) {
2859 if (uport->hw_stopped) { 2840 if (uport->hw_stopped) {
2860 if (status) { 2841 if (status) {
2861 uport->hw_stopped = 0; 2842 uport->hw_stopped = 0;
@@ -2868,6 +2849,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
2868 uport->ops->stop_tx(uport); 2849 uport->ops->stop_tx(uport);
2869 } 2850 }
2870 } 2851 }
2852
2871 } 2853 }
2872} 2854}
2873EXPORT_SYMBOL_GPL(uart_handle_cts_change); 2855EXPORT_SYMBOL_GPL(uart_handle_cts_change);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index a0c7033d5f91..baf3e1d08416 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -191,8 +191,10 @@ struct uart_port {
191#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15)) 191#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15))
192#define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ ) 192#define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ )
193 193
194/* Port has hardware-assisted h/w flow control (iow, auto-RTS *not* auto-CTS) */ 194/* Port has hardware-assisted h/w flow control */
195#define UPF_HARD_FLOW ((__force upf_t) (1 << 21)) 195#define UPF_AUTO_CTS ((__force upf_t) (1 << 20))
196#define UPF_AUTO_RTS ((__force upf_t) (1 << 21))
197#define UPF_HARD_FLOW ((__force upf_t) (UPF_AUTO_CTS | UPF_AUTO_RTS))
196/* Port has hardware-assisted s/w flow control */ 198/* Port has hardware-assisted s/w flow control */
197#define UPF_SOFT_FLOW ((__force upf_t) (1 << 22)) 199#define UPF_SOFT_FLOW ((__force upf_t) (1 << 22))
198#define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) 200#define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
@@ -214,11 +216,17 @@ struct uart_port {
214#error Change mask not equivalent to userspace-visible bit defines 216#error Change mask not equivalent to userspace-visible bit defines
215#endif 217#endif
216 218
217 /* status must be updated while holding port lock */ 219 /*
220 * Must hold termios_rwsem, port mutex and port lock to change;
221 * can hold any one lock to read.
222 */
218 upstat_t status; 223 upstat_t status;
219 224
220#define UPSTAT_CTS_ENABLE ((__force upstat_t) (1 << 0)) 225#define UPSTAT_CTS_ENABLE ((__force upstat_t) (1 << 0))
221#define UPSTAT_DCD_ENABLE ((__force upstat_t) (1 << 1)) 226#define UPSTAT_DCD_ENABLE ((__force upstat_t) (1 << 1))
227#define UPSTAT_AUTORTS ((__force upstat_t) (1 << 2))
228#define UPSTAT_AUTOCTS ((__force upstat_t) (1 << 3))
229#define UPSTAT_AUTOXOFF ((__force upstat_t) (1 << 4))
222 230
223 int hw_stopped; /* sw-assisted CTS flow state */ 231 int hw_stopped; /* sw-assisted CTS flow state */
224 unsigned int mctrl; /* current modem ctrl settings */ 232 unsigned int mctrl; /* current modem ctrl settings */
@@ -392,6 +400,13 @@ static inline bool uart_cts_enabled(struct uart_port *uport)
392 return !!(uport->status & UPSTAT_CTS_ENABLE); 400 return !!(uport->status & UPSTAT_CTS_ENABLE);
393} 401}
394 402
403static inline bool uart_softcts_mode(struct uart_port *uport)
404{
405 upstat_t mask = UPSTAT_CTS_ENABLE | UPSTAT_AUTOCTS;
406
407 return ((uport->status & mask) == UPSTAT_CTS_ENABLE);
408}
409
395/* 410/*
396 * The following are helper functions for the low level drivers. 411 * The following are helper functions for the low level drivers.
397 */ 412 */