Add initial LED trigger support for serial ports by providing a simple API for registering/unregistering RX/TX/RXTX LED triggers for a serial port as well as actually triggering LEDs. UART drivers simply need to call uart_led_event() in their respective receive and transmit routines to support the LED triggers. Signed-off-by: Tobias Doerffel <tobias.doerffel@xxxxxxxxxxxxxx> --- MAINTAINERS | 2 ++ drivers/tty/serial/Kconfig | 12 +++++++ drivers/tty/serial/Makefile | 1 + drivers/tty/serial/serial_leds.c | 67 ++++++++++++++++++++++++++++++++++++++++ include/linux/serial_core.h | 13 ++++++++ include/linux/serial_leds.h | 41 ++++++++++++++++++++++++ 6 files changed, 136 insertions(+) create mode 100644 drivers/tty/serial/serial_leds.c create mode 100644 include/linux/serial_leds.h diff --git a/MAINTAINERS b/MAINTAINERS index ab65bbe..e36d69c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10905,7 +10905,9 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git F: Documentation/serial/ F: drivers/tty/ F: drivers/tty/serial/serial_core.c +F: drivers/tty/serial/serial_leds.c F: include/linux/serial_core.h +F: include/linux/serial_leds.h F: include/linux/serial.h F: include/linux/tty.h F: include/uapi/linux/serial_core.h diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index f38beb2..b178ac8 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -787,6 +787,18 @@ config SERIAL_CORE config SERIAL_CORE_CONSOLE bool +config SERIAL_LEDS + bool "Enable LED triggers for serial ports" + depends on LEDS_CLASS + select LEDS_TRIGGERS + ---help--- + This option adds LED triggers for receiving and transmitting data + from/to serial ports. Please note that not all drivers take + advantage of this feature yet. + + Say Y here if you are working on a system with led-class supported + LEDs and you want to use them as serial port activity indicators. + config CONSOLE_POLL bool diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 5ab4111..e85b473 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_SERIAL_CORE) += serial_core.o +obj-$(CONFIG_SERIAL_LEDS) += serial_leds.o obj-$(CONFIG_SERIAL_21285) += 21285.o obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o diff --git a/drivers/tty/serial/serial_leds.c b/drivers/tty/serial/serial_leds.c new file mode 100644 index 0000000..84c8d9c --- /dev/null +++ b/drivers/tty/serial/serial_leds.c @@ -0,0 +1,67 @@ +/* + * Copyright 2016, Tobias Doerffel <tobias.doerffel@xxxxxxxxxxxxxx> + * + * This program is free software; you uart redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/leds.h> +#include <linux/serial_leds.h> + +static unsigned long led_delay = 50; +module_param(led_delay, ulong, 0644); +MODULE_PARM_DESC(led_delay, + "blink delay time for activity leds (msecs, default: 50)."); + +/* Trigger a LED event in response to a UART device event */ +void uart_led_event(struct uart_port *port, enum uart_led_event event) +{ + switch (event) { + case UART_LED_EVENT_TX: + if (led_delay) { + led_trigger_blink_oneshot(port->tx_led_trig, + &led_delay, &led_delay, 1); + led_trigger_blink_oneshot(port->rxtx_led_trig, + &led_delay, &led_delay, 1); + } + break; + case UART_LED_EVENT_RX: + if (led_delay) { + led_trigger_blink_oneshot(port->rx_led_trig, + &led_delay, &led_delay, 1); + led_trigger_blink_oneshot(port->rxtx_led_trig, + &led_delay, &led_delay, 1); + } + break; + } +} +EXPORT_SYMBOL_GPL(uart_led_event); + +void uart_led_register(struct uart_driver *drv, struct uart_port *port) +{ + snprintf(port->tx_led_trig_name, sizeof(port->tx_led_trig_name), + "%s%d-tx", drv->dev_name, drv->tty_driver->name_base + + port->line); + snprintf(port->rx_led_trig_name, sizeof(port->rx_led_trig_name), + "%s%d-rx", drv->dev_name, drv->tty_driver->name_base + + port->line); + snprintf(port->rxtx_led_trig_name, sizeof(port->rxtx_led_trig_name), + "%s%d-rxtx", drv->dev_name, drv->tty_driver->name_base + + port->line); + + led_trigger_register_simple(port->tx_led_trig_name, &port->tx_led_trig); + led_trigger_register_simple(port->rx_led_trig_name, &port->rx_led_trig); + led_trigger_register_simple(port->rxtx_led_trig_name, + &port->rxtx_led_trig); +} +EXPORT_SYMBOL_GPL(uart_led_register); + +void uart_led_unregister(struct uart_port *port) +{ + led_trigger_unregister_simple(port->tx_led_trig); + led_trigger_unregister_simple(port->rx_led_trig); + led_trigger_unregister_simple(port->rxtx_led_trig); +} +EXPORT_SYMBOL_GPL(uart_led_unregister); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 297d4fa..ace19f8 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -38,6 +38,11 @@ #define uart_console(port) ({ (void)port; 0; }) #endif +#define UART_DEV_NAME_LEN 32 +/* keep space for device name + "-tx"/"-rx"/"-rxtx" suffix and null terminator + */ +#define UART_LED_NAME_SZ (UART_DEV_NAME_LEN + 6) + struct uart_port; struct serial_struct; struct device; @@ -246,6 +251,14 @@ struct uart_port { struct attribute_group *attr_group; /* port specific attributes */ const struct attribute_group **tty_groups; /* all attributes (serial core use only) */ struct serial_rs485 rs485; +#ifdef CONFIG_SERIAL_LEDS + struct led_trigger *tx_led_trig; + char tx_led_trig_name[UART_LED_NAME_SZ]; + struct led_trigger *rx_led_trig; + char rx_led_trig_name[UART_LED_NAME_SZ]; + struct led_trigger *rxtx_led_trig; + char rxtx_led_trig_name[UART_LED_NAME_SZ]; +#endif void *private_data; /* generic platform data pointer */ }; diff --git a/include/linux/serial_leds.h b/include/linux/serial_leds.h new file mode 100644 index 0000000..be953f5 --- /dev/null +++ b/include/linux/serial_leds.h @@ -0,0 +1,41 @@ +/* + * Copyright 2016, Tobias Doerffel <tobias.doerffel@xxxxxxxxxxxxxx> + * + * This program is free software; you uart redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _SERIAL_LEDS_H +#define _SERIAL_LEDS_H + +#include <linux/serial_core.h> +#include <linux/leds.h> + +enum uart_led_event { + UART_LED_EVENT_TX, + UART_LED_EVENT_RX, +}; + +#ifdef CONFIG_SERIAL_LEDS + +void uart_led_event(struct uart_port *port, enum uart_led_event event); +void uart_led_register(struct uart_driver *drv, struct uart_port *port); +void uart_led_unregister(struct uart_port *port); + +#else + +static inline void uart_led_event(struct uart_port *port, + enum uart_led_event event) +{ +} +static inline void uart_led_register(struct uart_port *port) +{ +} +static inline void uart_led_unregister(struct uart_port *port) +{ +} + +#endif + +#endif /* !_SERIAL_LEDS_H */ -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html