Commit 0ed12afa authored by Lino Sanfilippo's avatar Lino Sanfilippo Committed by Greg Kroah-Hartman
Browse files

serial: core: move RS485 configuration tasks from drivers into core



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.

Signed-off-by: default avatarLino Sanfilippo <LinoSanfilippo@gmx.de>
Link: https://lore.kernel.org/r/20220410104642.32195-2-LinoSanfilippo@gmx.de


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 368ab68b
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -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);
@@ -1296,8 +1301,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;