From: Lino Sanfilippo LinoSanfilippo@gmx.de
Several drivers that support setting the RS485 configuration via userspace implement one or more of the following tasks:
- in case of an invalid RTS configuration (both RTS after send and RTS on send set or both unset) fall back to enable RTS on send and disable RTS after send
- nullify the padding field of the returned serial_rs485 struct
- copy the configuration into the uart port struct
- limit RTS delays to 100 ms
Move these tasks into the serial core to make them generic and to provide a consistent behaviour among all drivers.
[ Upstream commit 0ed12afa5655512ee418047fb3546d229df20aa1 ] Link: https://lkml.kernel.org/r/20221017051737.51727-1-dominique.martinet@atmark-t... Signed-off-by: Lino Sanfilippo LinoSanfilippo@gmx.de Link: https://lore.kernel.org/r/20220410104642.32195-2-LinoSanfilippo@gmx.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Daisuke Mizobuchi mizo@atmark-techno.com Signed-off-by: Dominique Martinet dominique.martinet@atmark-techno.com ---
5.15 version of the 5.10 backport: https://lkml.kernel.org/r/20221017051737.51727-1-dominique.martinet@atmark-t... (only build tested)
drivers/tty/serial/serial_core.c | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 82ddbb92d07d..48dafd1e084b 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -42,6 +42,11 @@ static struct lock_class_key port_lock_key;
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+/* + * Max time with active RTS before/after data is sent. + */ +#define RS485_MAX_RTS_DELAY 100 /* msecs */ + static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); @@ -1299,8 +1304,36 @@ static int uart_set_rs485_config(struct uart_port *port, if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user))) return -EFAULT;
+ /* pick sane settings if the user hasn't */ + if (!(rs485.flags & SER_RS485_RTS_ON_SEND) == + !(rs485.flags & SER_RS485_RTS_AFTER_SEND)) { + dev_warn_ratelimited(port->dev, + "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n", + port->name, port->line); + rs485.flags |= SER_RS485_RTS_ON_SEND; + rs485.flags &= ~SER_RS485_RTS_AFTER_SEND; + } + + if (rs485.delay_rts_before_send > RS485_MAX_RTS_DELAY) { + rs485.delay_rts_before_send = RS485_MAX_RTS_DELAY; + dev_warn_ratelimited(port->dev, + "%s (%d): RTS delay before sending clamped to %u ms\n", + port->name, port->line, rs485.delay_rts_before_send); + } + + if (rs485.delay_rts_after_send > RS485_MAX_RTS_DELAY) { + rs485.delay_rts_after_send = RS485_MAX_RTS_DELAY; + dev_warn_ratelimited(port->dev, + "%s (%d): RTS delay after sending clamped to %u ms\n", + port->name, port->line, rs485.delay_rts_after_send); + } + /* Return clean padding area to userspace */ + memset(rs485.padding, 0, sizeof(rs485.padding)); + spin_lock_irqsave(&port->lock, flags); ret = port->rs485_config(port, &rs485); + if (!ret) + port->rs485 = rs485; spin_unlock_irqrestore(&port->lock, flags); if (ret) return ret;