From a5f276f10ff70da89b349df445e944c8cd87956c Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Thu, 6 Nov 2014 22:46:13 +0100 Subject: [PATCH] serial_core: Handle TIOC[GS]RS485 ioctls. The following drivers: 8250_core, atmel_serial, max310x, mcf, omap-serial and sci16is7xx implement code to handle RS485 ioctls. In order to avoid code duplication, we implement a simple ioctl handler on the serial_core layer. This handler can be used by all the other drivers instead of duplicating code. Until this is the only RS485 ioctl handler, it will try first the rs485_config callback and if it is not present it will call the driver specific ioctl. Reviewed-by: Alan Cox Cc: Greg Kroah-Hartman Cc: Jiri Slaby Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 45 ++++++++++++++++++++++++++++++++ include/linux/serial_core.h | 3 +++ 2 files changed, 48 insertions(+) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index c5fb08cfbdb1..ab4db1dcc474 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1152,6 +1152,39 @@ static int uart_get_icount(struct tty_struct *tty, return 0; } +static int uart_get_rs485_config(struct uart_port *port, + struct serial_rs485 __user *rs485) +{ + if (!port->rs485_config) + return -ENOIOCTLCMD; + + if (copy_to_user(rs485, &port->rs485, sizeof(port->rs485))) + return -EFAULT; + return 0; +} + +static int uart_set_rs485_config(struct uart_port *port, + struct serial_rs485 __user *rs485_user) +{ + struct serial_rs485 rs485; + int ret; + + if (!port->rs485_config) + return -ENOIOCTLCMD; + + if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user))) + return -EFAULT; + + ret = port->rs485_config(port, &rs485); + if (ret) + return ret; + + if (copy_to_user(rs485_user, &port->rs485, sizeof(port->rs485))) + return -EFAULT; + + return 0; +} + /* * Called via sys_ioctl. We can use spin_lock_irq() here. */ @@ -1223,6 +1256,18 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, * protected against the tty being hung up. */ switch (cmd) { + case TIOCGRS485: + ret = uart_get_rs485_config(state->uart_port, uarg); + break; + + case TIOCSRS485: + ret = uart_set_rs485_config(state->uart_port, uarg); + break; + } + if (ret != -ENOIOCTLCMD) + goto out; + + switch (cmd) { case TIOCSERGETLSR: /* Get line status register */ ret = uart_get_lsr_info(tty, state, uarg); break; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 40b4cc4f8e1d..3231a43f6acf 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -131,6 +131,8 @@ struct uart_port { void (*pm)(struct uart_port *, unsigned int state, unsigned int old); void (*handle_break)(struct uart_port *); + int (*rs485_config)(struct uart_port *, + struct serial_rs485 *rs485); unsigned int irq; /* irq number */ unsigned long irqflags; /* irq flags */ unsigned int uartclk; /* base uart clock */ @@ -231,6 +233,7 @@ struct uart_port { unsigned char unused[2]; struct attribute_group *attr_group; /* port specific attributes */ const struct attribute_group **tty_groups; /* all attributes (serial core use only) */ + struct serial_rs485 rs485; void *private_data; /* generic platform data pointer */ }; -- 2.20.1