summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-04-17 16:23:14 (GMT)
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-11-04 11:25:56 (GMT)
commit9aba8d5b011193c8e01d565c5b585df5b94f1db2 (patch)
tree4f45580d7310ea7ea7dba87a237732f0580ecb36
parentdba05832cbe4f305dfd998fb26d7c685d91fbbd8 (diff)
downloadlinux-fsl-qoriq-9aba8d5b011193c8e01d565c5b585df5b94f1db2.tar.xz
SERIAL: core: add throttle/unthrottle callbacks for hardware assisted flow control
Add two callbacks for hardware assisted flow control; we need to know when the tty layers want us to stop and restart due to their buffer levels. Call a driver specific throttle/unthrottle function if and only if the driver indicates that it is using an enabled hardware assisted flow control method, otherwise fall back to the non-hardware assisted methods. Acked-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/tty/serial/serial_core.c31
-rw-r--r--include/linux/serial_core.h2
2 files changed, 29 insertions, 4 deletions
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 9d8796e..098bb99 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -610,27 +610,50 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
static void uart_throttle(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->uart_port;
+ uint32_t mask = 0;
if (I_IXOFF(tty))
+ mask |= UPF_SOFT_FLOW;
+ if (tty->termios.c_cflag & CRTSCTS)
+ mask |= UPF_HARD_FLOW;
+
+ if (port->flags & mask) {
+ port->ops->throttle(port);
+ mask &= ~port->flags;
+ }
+
+ if (mask & UPF_SOFT_FLOW)
uart_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios.c_cflag & CRTSCTS)
- uart_clear_mctrl(state->uart_port, TIOCM_RTS);
+ if (mask & UPF_HARD_FLOW)
+ uart_clear_mctrl(port, TIOCM_RTS);
}
static void uart_unthrottle(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
+ uint32_t mask = 0;
- if (I_IXOFF(tty)) {
+ if (I_IXOFF(tty))
+ mask |= UPF_SOFT_FLOW;
+ if (tty->termios.c_cflag & CRTSCTS)
+ mask |= UPF_HARD_FLOW;
+
+ if (port->flags & mask) {
+ port->ops->unthrottle(port);
+ mask &= ~port->flags;
+ }
+
+ if (mask & UPF_SOFT_FLOW) {
if (port->x_char)
port->x_char = 0;
else
uart_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS)
+ if (mask & UPF_HARD_FLOW)
uart_set_mctrl(port, TIOCM_RTS);
}
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index e2cda5d..c6690a2 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -46,6 +46,8 @@ struct uart_ops {
unsigned int (*get_mctrl)(struct uart_port *);
void (*stop_tx)(struct uart_port *);
void (*start_tx)(struct uart_port *);
+ void (*throttle)(struct uart_port *);
+ void (*unthrottle)(struct uart_port *);
void (*send_xchar)(struct uart_port *, char ch);
void (*stop_rx)(struct uart_port *);
void (*enable_ms)(struct uart_port *);