serial: core: Consider rs485 settings to drive RTS

Previously the rs485 settings weren't considered when setting the RTS
line, so e.g. closing and reopening a port made serial_core to drive
the line as if rs485 was disabled.

This patch fixes those issues.

Signed-off-by: Rafael Gago Castano <rgc@hms.se>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Rafael Gago 2017-07-31 10:46:42 +02:00 committed by Greg Kroah-Hartman
parent d77dc47fce
commit a6845e1e1b

View File

@ -165,6 +165,27 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) #define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0)
#define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear) #define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear)
static void uart_port_dtr_rts(struct uart_port *uport, int raise)
{
int rs485_on = uport->rs485_config &&
(uport->rs485.flags & SER_RS485_ENABLED);
int RTS_after_send = !!(uport->rs485.flags & SER_RS485_RTS_AFTER_SEND);
if (raise) {
if (rs485_on && !RTS_after_send) {
uart_set_mctrl(uport, TIOCM_DTR);
uart_clear_mctrl(uport, TIOCM_RTS);
} else {
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
}
} else {
unsigned int clear = TIOCM_DTR;
clear |= (!rs485_on || !RTS_after_send) ? TIOCM_RTS : 0;
uart_clear_mctrl(uport, clear);
}
}
/* /*
* Startup the port. This will be called once per open. All calls * Startup the port. This will be called once per open. All calls
* will be serialised by the per-port mutex. * will be serialised by the per-port mutex.
@ -214,7 +235,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
* port is open and ready to respond. * port is open and ready to respond.
*/ */
if (init_hw && C_BAUD(tty)) if (init_hw && C_BAUD(tty))
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); uart_port_dtr_rts(uport, 1);
} }
/* /*
@ -272,7 +293,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
uport->cons->cflag = tty->termios.c_cflag; uport->cons->cflag = tty->termios.c_cflag;
if (!tty || C_HUPCL(tty)) if (!tty || C_HUPCL(tty))
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); uart_port_dtr_rts(uport, 0);
uart_port_shutdown(port); uart_port_shutdown(port);
} }
@ -1658,7 +1679,7 @@ static int uart_carrier_raised(struct tty_port *port)
return 0; return 0;
} }
static void uart_dtr_rts(struct tty_port *port, int onoff) static void uart_dtr_rts(struct tty_port *port, int raise)
{ {
struct uart_state *state = container_of(port, struct uart_state, port); struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport; struct uart_port *uport;
@ -1666,12 +1687,7 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
uport = uart_port_ref(state); uport = uart_port_ref(state);
if (!uport) if (!uport)
return; return;
uart_port_dtr_rts(uport, raise);
if (onoff)
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
else
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
uart_port_deref(uport); uart_port_deref(uport);
} }