The rx trigger fires when data is pushed to the ldisc by the driver. This is a bit later than the actual receiving of data but has the nice benefit that it doesn't need adaption for each driver and isn't in the hot path. Similarly the tx trigger fires when data was copied from userspace and is given to the ldisc. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx> --- drivers/tty/Kconfig | 7 +++++++ drivers/tty/tty_buffer.c | 2 ++ drivers/tty/tty_io.c | 3 +++ drivers/tty/tty_port.c | 32 ++++++++++++++++++++++++++++++-- include/linux/tty.h | 22 ++++++++++++++++++++++ 5 files changed, 64 insertions(+), 2 deletions(-) diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 0840d27381ea..b119c0fa1f5a 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -41,6 +41,13 @@ config VT If unsure, say Y, or else you won't be able to do much with your new shiny Linux system :-) +config TTY_LEDS_TRIGGERS + bool "Enable support for TTY actions making LEDs blink" + depends on LEDS_TRIGGERS + ---help--- + This enable support for tty triggers. It provides two LED triggers + (rx and tx) for each TTY. + config CONSOLE_TRANSLATIONS depends on VT default y diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index c996b6859c5e..364080ce8e91 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -521,6 +521,8 @@ static void flush_to_ldisc(struct work_struct *work) continue; } + tty_led_trigger_rx(port); + count = receive_buf(port, head, count); if (!count) break; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 7c838b90a31d..8ef597dc0c3d 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -955,6 +955,9 @@ static inline ssize_t do_tty_write( ret = -EFAULT; if (copy_from_user(tty->write_buf, buf, size)) break; + + tty_led_trigger_tx(tty->port); + ret = write(tty, file, tty->write_buf, size); if (ret <= 0) break; diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 25d736880013..72dcde234a7d 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -37,6 +37,8 @@ static int tty_port_default_receive_buf(struct tty_port *port, ret = tty_ldisc_receive_buf(disc, p, (char *)f, count); + tty_led_trigger_rx(port); + tty_ldisc_deref(disc); return ret; @@ -163,8 +165,31 @@ struct device *tty_port_register_device_attr_serdev(struct tty_port *port, return dev; } - return tty_register_device_attr(driver, index, device, drvdata, - attr_grp); + if (IS_ENABLED(CONFIG_TTY_LEDS_TRIGGERS)) { + int ret; + + ret = led_trigger_register_format(&port->led_trigger_rx, + "%s%d-rx", driver->name, index); + if (ret < 0) + pr_warn("Failed to register rx trigger for %s%d (%d)\n", + driver->name, index, ret); + + ret = led_trigger_register_format(&port->led_trigger_tx, + "%s%d-tx", driver->name, index); + if (ret < 0) + pr_warn("Failed to register tx trigger for %s%d (%d)\n", + driver->name, index, ret); + } + + dev = tty_register_device_attr(driver, index, + device, drvdata, attr_grp); + + if (IS_ENABLED(CONFIG_TTY_LEDS_TRIGGERS) && IS_ERR(dev)) { + led_trigger_unregister_simple(port->led_trigger_tx); + led_trigger_unregister_simple(port->led_trigger_rx); + } + + return dev; } EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev); @@ -207,6 +232,9 @@ void tty_port_unregister_device(struct tty_port *port, return; tty_unregister_device(driver, index); + + led_trigger_unregister_simple(port->led_trigger_rx); + led_trigger_unregister_simple(port->led_trigger_tx); } EXPORT_SYMBOL_GPL(tty_port_unregister_device); diff --git a/include/linux/tty.h b/include/linux/tty.h index 1dd587ba6d88..75d4e9b6acf9 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -3,6 +3,7 @@ #define _LINUX_TTY_H #include <linux/fs.h> +#include <linux/leds.h> #include <linux/major.h> #include <linux/termios.h> #include <linux/workqueue.h> @@ -249,8 +250,29 @@ struct tty_port { set to size of fifo */ struct kref kref; /* Ref counter */ void *client_data; + + struct led_trigger *led_trigger_rx; + struct led_trigger *led_trigger_tx; }; +static inline void tty_led_trigger(struct led_trigger *trig) +{ + unsigned long delay_ms = 50; + + if (IS_ENABLED(CONFIG_TTY_LEDS_TRIGGERS)) + led_trigger_blink_oneshot(trig, &delay_ms, &delay_ms, 0); +} + +static inline void tty_led_trigger_rx(struct tty_port *port) +{ + tty_led_trigger(port->led_trigger_rx); +} + +static inline void tty_led_trigger_tx(struct tty_port *port) +{ + tty_led_trigger(port->led_trigger_tx); +} + /* tty_port::iflags bits -- use atomic bit ops */ #define TTY_PORT_INITIALIZED 0 /* device is initialized */ #define TTY_PORT_SUSPENDED 1 /* device is suspended */ -- 2.17.0 -- 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