SERIAL: core: add throttle/unthrottle callbacks for hardware assisted flow control
authorRussell King <rmk+kernel@arm.linux.org.uk>
Tue, 17 Apr 2012 16:23:14 +0000 (17:23 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sun, 4 Nov 2012 11:25:56 +0000 (11:25 +0000)
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>
drivers/tty/serial/serial_core.c
include/linux/serial_core.h

index 9d8796e7718830cc6c1bc64b7db67171a0121692..098bb99c2b9f431440f6ca8ed7e555902d28a0f5 100644 (file)
@@ -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);
 }
 
index e2cda5d04e480452c28097f1e577d1c321f13f66..c6690a2a27fb48f7d10aad50ed2931add0abe3f4 100644 (file)
@@ -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 *);