@@ -203,7 +203,8 @@ void serial8250_rpm_put(struct uart_8250_port *p);
void serial8250_rpm_get_tx(struct uart_8250_port *p);
void serial8250_rpm_put_tx(struct uart_8250_port *p);
-int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485);
+int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485,
+ struct ktermios *termios);
void serial8250_em485_start_tx(struct uart_8250_port *p);
void serial8250_em485_stop_tx(struct uart_8250_port *p);
void serial8250_em485_destroy(struct uart_8250_port *p);
@@ -85,7 +85,8 @@ void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct
}
EXPORT_SYMBOL_GPL(dw8250_do_set_termios);
-static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485)
+static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485,
+ struct ktermios *termios)
{
u32 tcr;
@@ -112,7 +112,8 @@
struct exar8250;
struct exar8250_platform {
- int (*rs485_config)(struct uart_port *, struct serial_rs485 *);
+ int (*rs485_config)(struct uart_port *port, struct serial_rs485 *rs485,
+ struct ktermios *termios);
const struct serial_rs485 *rs485_supported;
int (*register_gpio)(struct pci_dev *, struct uart_8250_port *);
void (*unregister_gpio)(struct uart_8250_port *);
@@ -410,7 +411,7 @@ static void xr17v35x_unregister_gpio(struct uart_8250_port *port)
}
static int generic_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED);
u8 __iomem *p = port->membase;
@@ -442,7 +443,7 @@ static const struct exar8250_platform exar8250_default_platform = {
};
static int iot2040_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED);
u8 __iomem *p = port->membase;
@@ -471,7 +472,7 @@ static int iot2040_rs485_config(struct uart_port *port,
value |= mode;
writeb(value, p + UART_EXAR_MPIOLVL_7_0);
- return generic_rs485_config(port, rs485);
+ return generic_rs485_config(port, rs485, termios);
}
static const struct serial_rs485 iot2040_rs485_supported = {
@@ -192,7 +192,7 @@ static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min,
}
static int fintek_8250_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
uint8_t config = 0;
struct fintek_8250 *pdata = port->private_data;
@@ -33,7 +33,7 @@ struct lpc18xx_uart_data {
};
static int lpc18xx_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct uart_8250_port *up = up_to_u8250p(port);
u32 rs485_ctrl_reg = 0;
@@ -1554,7 +1554,7 @@ pci_brcm_trumanage_setup(struct serial_private *priv,
/* We should do proper H/W transceiver setting before change to RS485 mode */
static int pci_fintek_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct pci_dev *pci_dev = to_pci_dev(port->dev);
u8 setting;
@@ -664,7 +664,8 @@ EXPORT_SYMBOL_GPL(serial8250_em485_supported);
* if the uart is incapable of driving RTS as a Transmit Enable signal in
* hardware, relying on software emulation instead.
*/
-int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
+int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485,
+ struct ktermios *termios)
{
struct uart_8250_port *up = up_to_u8250p(port);
@@ -2198,7 +2198,7 @@ static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
}
static int pl011_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
@@ -581,7 +581,7 @@ static const struct uart_ops ar933x_uart_ops = {
};
static int ar933x_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485conf)
+ struct serial_rs485 *rs485conf, struct ktermios *termios)
{
struct ar933x_uart_port *up =
container_of(port, struct ar933x_uart_port, port);
@@ -286,7 +286,7 @@ static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port,
/* Enable or disable the rs485 support */
static int atmel_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485conf)
+ struct serial_rs485 *rs485conf, struct ktermios *termios)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int mode;
@@ -1356,7 +1356,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
}
static int lpuart_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
@@ -1386,7 +1386,7 @@ static int lpuart_config_rs485(struct uart_port *port,
}
static int lpuart32_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
@@ -1908,7 +1908,7 @@ static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c)
/* called with port.lock taken and irqs off or from .probe without locking */
static int imx_uart_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485conf)
+ struct serial_rs485 *rs485conf, struct ktermios *termios)
{
struct imx_port *sport = (struct imx_port *)port;
u32 ucr2;
@@ -1027,7 +1027,7 @@ static void max310x_rs_proc(struct work_struct *ws)
}
static int max310x_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct max310x_one *one = to_max310x_port(port);
@@ -431,7 +431,8 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
/****************************************************************************/
/* Enable or disable the RS485 support */
-static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
+static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485,
+ struct ktermios *termios)
{
unsigned char mr1, mr2;
@@ -1325,7 +1325,8 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up)
/* Enable or disable the rs485 support */
static int
-serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
+serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485,
+ struct ktermios *termios)
{
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned int mode;
@@ -1128,7 +1128,7 @@ static void sc16is7xx_set_termios(struct uart_port *port,
}
static int sc16is7xx_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
@@ -1359,7 +1359,8 @@ int uart_rs485_config(struct uart_port *port)
uart_sanitize_serial_rs485(port, rs485);
- ret = port->rs485_config(port, rs485);
+ ret = port->rs485_config(port, rs485, NULL);
+
if (ret)
memset(rs485, 0, sizeof(*rs485));
@@ -1383,7 +1384,7 @@ static int uart_get_rs485_config(struct uart_port *port,
return 0;
}
-static int uart_set_rs485_config(struct uart_port *port,
+static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port,
struct serial_rs485 __user *rs485_user)
{
struct serial_rs485 rs485;
@@ -1402,7 +1403,7 @@ static int uart_set_rs485_config(struct uart_port *port,
uart_sanitize_serial_rs485(port, &rs485);
spin_lock_irqsave(&port->lock, flags);
- ret = port->rs485_config(port, &rs485);
+ ret = port->rs485_config(port, &rs485, &tty->termios);
if (!ret)
port->rs485 = rs485;
spin_unlock_irqrestore(&port->lock, flags);
@@ -1511,6 +1512,10 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
if (ret != -ENOIOCTLCMD)
goto out;
+ /* rs485_config requires more locking than others */
+ if (cmd == TIOCGRS485)
+ down_write(&tty->termios_rwsem);
+
mutex_lock(&port->mutex);
uport = uart_port_check(state);
@@ -1534,7 +1539,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
break;
case TIOCSRS485:
- ret = uart_set_rs485_config(uport, uarg);
+ ret = uart_set_rs485_config(tty, uport, uarg);
break;
case TIOCSISO7816:
@@ -1551,6 +1556,8 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
}
out_up:
mutex_unlock(&port->mutex);
+ if (cmd == TIOCGRS485)
+ up_write(&tty->termios_rwsem);
out:
return ret;
}
@@ -98,7 +98,7 @@ static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
}
static int stm32_usart_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485conf)
+ struct serial_rs485 *rs485conf, struct ktermios *termios)
{
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
@@ -132,7 +132,8 @@ struct uart_port {
unsigned int old);
void (*handle_break)(struct uart_port *);
int (*rs485_config)(struct uart_port *,
- struct serial_rs485 *rs485);
+ struct serial_rs485 *rs485,
+ struct ktermios *termios);
int (*iso7816_config)(struct uart_port *,
struct serial_iso7816 *iso7816);
unsigned int irq; /* irq number */
To be able to alter ADDRB within .rs485_config(), take termios_rwsem before calling .rs485_config() and pass termios. Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> --- drivers/tty/serial/8250/8250.h | 3 ++- drivers/tty/serial/8250/8250_dwlib.c | 3 ++- drivers/tty/serial/8250/8250_exar.c | 9 +++++---- drivers/tty/serial/8250/8250_fintek.c | 2 +- drivers/tty/serial/8250/8250_lpc18xx.c | 2 +- drivers/tty/serial/8250/8250_pci.c | 2 +- drivers/tty/serial/8250/8250_port.c | 3 ++- drivers/tty/serial/amba-pl011.c | 2 +- drivers/tty/serial/ar933x_uart.c | 2 +- drivers/tty/serial/atmel_serial.c | 2 +- drivers/tty/serial/fsl_lpuart.c | 4 ++-- drivers/tty/serial/imx.c | 2 +- drivers/tty/serial/max310x.c | 2 +- drivers/tty/serial/mcf.c | 3 ++- drivers/tty/serial/omap-serial.c | 3 ++- drivers/tty/serial/sc16is7xx.c | 2 +- drivers/tty/serial/serial_core.c | 15 +++++++++++---- drivers/tty/serial/stm32-usart.c | 2 +- include/linux/serial_core.h | 3 ++- 19 files changed, 40 insertions(+), 26 deletions(-)