From patchwork Mon Nov 27 11:03:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Eckert X-Patchwork-Id: 747911 Authentication-Results: smtp.subspace.kernel.org; dkim=none Received: from mxout70.expurgate.net (mxout70.expurgate.net [91.198.224.70]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F02D5135; Mon, 27 Nov 2023 03:03:24 -0800 (PST) Received: from [127.0.0.1] (helo=localhost) by relay.expurgate.net with smtp (Exim 4.92) (envelope-from ) id 1r7ZOY-006UlZ-Q9; Mon, 27 Nov 2023 12:03:18 +0100 Received: from [195.243.126.94] (helo=securemail.tdt.de) by relay.expurgate.net with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1r7ZOY-006Uko-2Y; Mon, 27 Nov 2023 12:03:18 +0100 Received: from securemail.tdt.de (localhost [127.0.0.1]) by securemail.tdt.de (Postfix) with ESMTP id B0B84240049; Mon, 27 Nov 2023 12:03:17 +0100 (CET) Received: from mail.dev.tdt.de (unknown [10.2.4.42]) by securemail.tdt.de (Postfix) with ESMTP id 24ED424004B; Mon, 27 Nov 2023 12:03:17 +0100 (CET) Received: from localhost.localdomain (unknown [10.2.3.40]) by mail.dev.tdt.de (Postfix) with ESMTPSA id 71FCB33D90; Mon, 27 Nov 2023 12:03:16 +0100 (CET) From: Florian Eckert To: Eckert.Florian@googlemail.com, pavel@ucw.cz, lee@kernel.org, kabel@kernel.org, gregkh@linuxfoundation.org, u.kleine-koenig@pengutronix.de Cc: linux-leds@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [Patch v9 1/4] tty: add new helper function tty_get_tiocm Date: Mon, 27 Nov 2023 12:03:08 +0100 Message-ID: <20231127110311.3583957-2-fe@dev.tdt.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20231127110311.3583957-1-fe@dev.tdt.de> References: <20231127110311.3583957-1-fe@dev.tdt.de> Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-purgate-ID: 151534::1701082998-FA0CB49D-132AF335/0/0 X-purgate-type: clean X-purgate: clean There is no in-kernel function to get the status register of a tty device like the TIOCMGET ioctl returns to userspace. Create a new function, tty_get_tiocm(), to obtain the status register that other portions of the kernel can call if they need this information, and move the existing internal tty_tiocmget() function to use this interface. Acked-by: Greg Kroah-Hartman Signed-off-by: Florian Eckert --- drivers/tty/tty_io.c | 28 ++++++++++++++++++++++------ include/linux/tty.h | 1 + 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 06414e43e0b5..e2e93404133e 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2498,6 +2498,24 @@ static int send_break(struct tty_struct *tty, unsigned int duration) return retval; } +/** + * tty_get_tiocm - get tiocm status register + * @tty: tty device + * + * Obtain the modem status bits from the tty driver if the feature + * is supported. + */ +int tty_get_tiocm(struct tty_struct *tty) +{ + int retval = -ENOTTY; + + if (tty->ops->tiocmget) + retval = tty->ops->tiocmget(tty); + + return retval; +} +EXPORT_SYMBOL_GPL(tty_get_tiocm); + /** * tty_tiocmget - get modem status * @tty: tty device @@ -2510,14 +2528,12 @@ static int send_break(struct tty_struct *tty, unsigned int duration) */ static int tty_tiocmget(struct tty_struct *tty, int __user *p) { - int retval = -ENOTTY; + int retval; - if (tty->ops->tiocmget) { - retval = tty->ops->tiocmget(tty); + retval = tty_get_tiocm(tty); + if (retval >= 0) + retval = put_user(retval, p); - if (retval >= 0) - retval = put_user(retval, p); - } return retval; } diff --git a/include/linux/tty.h b/include/linux/tty.h index 4b6340ac2af2..d219a11e3fe0 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -419,6 +419,7 @@ bool tty_unthrottle_safe(struct tty_struct *tty); int tty_do_resize(struct tty_struct *tty, struct winsize *ws); int tty_get_icount(struct tty_struct *tty, struct serial_icounter_struct *icount); +int tty_get_tiocm(struct tty_struct *tty); int is_current_pgrp_orphaned(void); void tty_hangup(struct tty_struct *tty); void tty_vhangup(struct tty_struct *tty); From patchwork Mon Nov 27 11:03:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Eckert X-Patchwork-Id: 747912 Authentication-Results: smtp.subspace.kernel.org; dkim=none Received: from mxout70.expurgate.net (mxout70.expurgate.net [91.198.224.70]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BEF2B113; Mon, 27 Nov 2023 03:03:24 -0800 (PST) Received: from [127.0.0.1] (helo=localhost) by relay.expurgate.net with smtp (Exim 4.92) (envelope-from ) id 1r7ZOZ-00HQdp-2E; Mon, 27 Nov 2023 12:03:19 +0100 Received: from [195.243.126.94] (helo=securemail.tdt.de) by relay.expurgate.net with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1r7ZOY-000Ydh-C2; Mon, 27 Nov 2023 12:03:18 +0100 Received: from securemail.tdt.de (localhost [127.0.0.1]) by securemail.tdt.de (Postfix) with ESMTP id 00E4724004D; Mon, 27 Nov 2023 12:03:18 +0100 (CET) Received: from mail.dev.tdt.de (unknown [10.2.4.42]) by securemail.tdt.de (Postfix) with ESMTP id 6BFFE240040; Mon, 27 Nov 2023 12:03:17 +0100 (CET) Received: from localhost.localdomain (unknown [10.2.3.40]) by mail.dev.tdt.de (Postfix) with ESMTPSA id 2512E33D8E; Mon, 27 Nov 2023 12:03:17 +0100 (CET) From: Florian Eckert To: Eckert.Florian@googlemail.com, pavel@ucw.cz, lee@kernel.org, kabel@kernel.org, gregkh@linuxfoundation.org, u.kleine-koenig@pengutronix.de Cc: linux-leds@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [Patch v9 2/4] leds: ledtrig-tty: replace mutex with completion Date: Mon, 27 Nov 2023 12:03:09 +0100 Message-ID: <20231127110311.3583957-3-fe@dev.tdt.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20231127110311.3583957-1-fe@dev.tdt.de> References: <20231127110311.3583957-1-fe@dev.tdt.de> Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-purgate: clean X-purgate-type: clean X-purgate-ID: 151534::1701082999-65079C7C-1C077096/0/0 With this commit, the mutex handling is replaced by the completion handling. When handling mutex, it must always be ensured that the held mutex is also released again. This is more error-prone should the number of code paths increase. This is a preparatory commit to make the trigger more configurable via additional sysfs parameters. With this change, the worker always runs and is no longer stopped if no ttyname is set. Signed-off-by: Florian Eckert --- drivers/leds/trigger/ledtrig-tty.c | 59 +++++++++++++++--------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-tty.c b/drivers/leds/trigger/ledtrig-tty.c index 8ae0d2d284af..0d73bec1529f 100644 --- a/drivers/leds/trigger/ledtrig-tty.c +++ b/drivers/leds/trigger/ledtrig-tty.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include #include #include @@ -12,15 +13,23 @@ struct ledtrig_tty_data { struct led_classdev *led_cdev; struct delayed_work dwork; - struct mutex mutex; + struct completion sysfs; const char *ttyname; struct tty_struct *tty; int rx, tx; }; -static void ledtrig_tty_restart(struct ledtrig_tty_data *trigger_data) +static int ledtrig_tty_wait_for_completion(struct device *dev) { - schedule_delayed_work(&trigger_data->dwork, 0); + struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev); + int ret; + + ret = wait_for_completion_timeout(&trigger_data->sysfs, + msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 20)); + if (ret == 0) + return -ETIMEDOUT; + + return ret; } static ssize_t ttyname_show(struct device *dev, @@ -28,14 +37,16 @@ static ssize_t ttyname_show(struct device *dev, { struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev); ssize_t len = 0; + int completion; - mutex_lock(&trigger_data->mutex); + reinit_completion(&trigger_data->sysfs); + completion = ledtrig_tty_wait_for_completion(dev); + if (completion < 0) + return completion; if (trigger_data->ttyname) len = sprintf(buf, "%s\n", trigger_data->ttyname); - mutex_unlock(&trigger_data->mutex); - return len; } @@ -46,7 +57,7 @@ static ssize_t ttyname_store(struct device *dev, struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev); char *ttyname; ssize_t ret = size; - bool running; + int completion; if (size > 0 && buf[size - 1] == '\n') size -= 1; @@ -59,9 +70,10 @@ static ssize_t ttyname_store(struct device *dev, ttyname = NULL; } - mutex_lock(&trigger_data->mutex); - - running = trigger_data->ttyname != NULL; + reinit_completion(&trigger_data->sysfs); + completion = ledtrig_tty_wait_for_completion(dev); + if (completion < 0) + return completion; kfree(trigger_data->ttyname); tty_kref_put(trigger_data->tty); @@ -69,11 +81,6 @@ static ssize_t ttyname_store(struct device *dev, trigger_data->ttyname = ttyname; - mutex_unlock(&trigger_data->mutex); - - if (ttyname && !running) - ledtrig_tty_restart(trigger_data); - return ret; } static DEVICE_ATTR_RW(ttyname); @@ -85,13 +92,8 @@ static void ledtrig_tty_work(struct work_struct *work) struct serial_icounter_struct icount; int ret; - mutex_lock(&trigger_data->mutex); - - if (!trigger_data->ttyname) { - /* exit without rescheduling */ - mutex_unlock(&trigger_data->mutex); - return; - } + if (!trigger_data->ttyname) + goto out; /* try to get the tty corresponding to $ttyname */ if (!trigger_data->tty) { @@ -116,11 +118,8 @@ static void ledtrig_tty_work(struct work_struct *work) } ret = tty_get_icount(trigger_data->tty, &icount); - if (ret) { - dev_info(trigger_data->tty->dev, "Failed to get icount, stopped polling\n"); - mutex_unlock(&trigger_data->mutex); - return; - } + if (ret) + goto out; if (icount.rx != trigger_data->rx || icount.tx != trigger_data->tx) { @@ -134,7 +133,7 @@ static void ledtrig_tty_work(struct work_struct *work) } out: - mutex_unlock(&trigger_data->mutex); + complete_all(&trigger_data->sysfs); schedule_delayed_work(&trigger_data->dwork, msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 2)); } @@ -157,7 +156,9 @@ static int ledtrig_tty_activate(struct led_classdev *led_cdev) INIT_DELAYED_WORK(&trigger_data->dwork, ledtrig_tty_work); trigger_data->led_cdev = led_cdev; - mutex_init(&trigger_data->mutex); + init_completion(&trigger_data->sysfs); + + schedule_delayed_work(&trigger_data->dwork, 0); return 0; } From patchwork Mon Nov 27 11:03:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Eckert X-Patchwork-Id: 747687 Authentication-Results: smtp.subspace.kernel.org; dkim=none Received: from mxout70.expurgate.net (mxout70.expurgate.net [91.198.224.70]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BEF8E12F; Mon, 27 Nov 2023 03:03:24 -0800 (PST) Received: from [127.0.0.1] (helo=localhost) by relay.expurgate.net with smtp (Exim 4.92) (envelope-from ) id 1r7ZOZ-006Um5-DO; Mon, 27 Nov 2023 12:03:19 +0100 Received: from [195.243.126.94] (helo=securemail.tdt.de) by relay.expurgate.net with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1r7ZOY-006UlJ-ND; Mon, 27 Nov 2023 12:03:18 +0100 Received: from securemail.tdt.de (localhost [127.0.0.1]) by securemail.tdt.de (Postfix) with ESMTP id 617F0240040; Mon, 27 Nov 2023 12:03:18 +0100 (CET) Received: from mail.dev.tdt.de (unknown [10.2.4.42]) by securemail.tdt.de (Postfix) with ESMTP id CC98D24004B; Mon, 27 Nov 2023 12:03:17 +0100 (CET) Received: from localhost.localdomain (unknown [10.2.3.40]) by mail.dev.tdt.de (Postfix) with ESMTPSA id 6E1B333D8E; Mon, 27 Nov 2023 12:03:17 +0100 (CET) From: Florian Eckert To: Eckert.Florian@googlemail.com, pavel@ucw.cz, lee@kernel.org, kabel@kernel.org, gregkh@linuxfoundation.org, u.kleine-koenig@pengutronix.de Cc: linux-leds@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [Patch v9 3/4] leds: ledtrig-tty: make rx tx activitate configurable Date: Mon, 27 Nov 2023 12:03:10 +0100 Message-ID: <20231127110311.3583957-4-fe@dev.tdt.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20231127110311.3583957-1-fe@dev.tdt.de> References: <20231127110311.3583957-1-fe@dev.tdt.de> Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-purgate-type: clean X-purgate: clean X-purgate-ID: 151534::1701082999-FA0CB49D-11F123A3/0/0 Until now, the LED blinks when data is sent via the tty (rx/tx). This is not configurable. This change adds the possibility to make the indication for the direction of the transmitted data independently controllable via the new rx and tx sysfs entries. - rx: Signal reception (rx) of data on the named tty device. If set to 0, the LED will not blink on reception. If set to 1 (default), the LED will blink on reception. - tx: Signal transmission (tx) of data on the named tty device. If set to 0, the LED will not blink on transmission. If set to 1 (default), the LED will blink on transmission. This new sysfs entry are on by default. Thus the trigger behaves as before this change. Signed-off-by: Florian Eckert --- .../ABI/testing/sysfs-class-led-trigger-tty | 16 +++ drivers/leds/trigger/ledtrig-tty.c | 114 ++++++++++++++++-- 2 files changed, 119 insertions(+), 11 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-tty b/Documentation/ABI/testing/sysfs-class-led-trigger-tty index 2bf6b24e781b..504dece151b8 100644 --- a/Documentation/ABI/testing/sysfs-class-led-trigger-tty +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-tty @@ -4,3 +4,19 @@ KernelVersion: 5.10 Contact: linux-leds@vger.kernel.org Description: Specifies the tty device name of the triggering tty + +What: /sys/class/leds//rx +Date: February 2024 +KernelVersion: 6.8 +Description: + Signal reception (rx) of data on the named tty device. + If set to 0, the LED will not blink on reception. + If set to 1 (default), the LED will blink on reception. + +What: /sys/class/leds//tx +Date: February 2024 +KernelVersion: 6.8 +Description: + Signal transmission (tx) of data on the named tty device. + If set to 0, the LED will not blink on transmission. + If set to 1 (default), the LED will blink on transmission. diff --git a/drivers/leds/trigger/ledtrig-tty.c b/drivers/leds/trigger/ledtrig-tty.c index 0d73bec1529f..ee6d01ecb309 100644 --- a/drivers/leds/trigger/ledtrig-tty.c +++ b/drivers/leds/trigger/ledtrig-tty.c @@ -17,6 +17,19 @@ struct ledtrig_tty_data { const char *ttyname; struct tty_struct *tty; int rx, tx; + bool mode_rx; + bool mode_tx; +}; + +/* Indicates which state the LED should now display */ +enum led_trigger_tty_state { + TTY_LED_BLINK, + TTY_LED_DISABLE, +}; + +enum led_trigger_tty_modes { + TRIGGER_TTY_RX = 0, + TRIGGER_TTY_TX, }; static int ledtrig_tty_wait_for_completion(struct device *dev) @@ -85,11 +98,69 @@ static ssize_t ttyname_store(struct device *dev, } static DEVICE_ATTR_RW(ttyname); +static ssize_t ledtrig_tty_attr_show(struct device *dev, char *buf, + enum led_trigger_tty_modes attr) +{ + struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev); + bool state; + + switch (attr) { + case TRIGGER_TTY_RX: + state = trigger_data->mode_rx; + break; + case TRIGGER_TTY_TX: + state = trigger_data->mode_tx; + break; + } + + return sysfs_emit(buf, "%u\n", state); +} + +static ssize_t ledtrig_tty_attr_store(struct device *dev, const char *buf, + size_t size, enum led_trigger_tty_modes attr) +{ + struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev); + bool state; + int ret; + + ret = kstrtobool(buf, &state); + if (ret) + return ret; + + switch (attr) { + case TRIGGER_TTY_RX: + trigger_data->mode_rx = state; + break; + case TRIGGER_TTY_TX: + trigger_data->mode_tx = state; + break; + } + + return size; +} + +#define DEFINE_TTY_TRIGGER(trigger_name, trigger) \ + static ssize_t trigger_name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ + { \ + return ledtrig_tty_attr_show(dev, buf, trigger); \ + } \ + static ssize_t trigger_name##_store(struct device *dev, \ + struct device_attribute *attr, const char *buf, size_t size) \ + { \ + return ledtrig_tty_attr_store(dev, buf, size, trigger); \ + } \ + static DEVICE_ATTR_RW(trigger_name) + +DEFINE_TTY_TRIGGER(rx, TRIGGER_TTY_RX); +DEFINE_TTY_TRIGGER(tx, TRIGGER_TTY_TX); + static void ledtrig_tty_work(struct work_struct *work) { struct ledtrig_tty_data *trigger_data = container_of(work, struct ledtrig_tty_data, dwork.work); - struct serial_icounter_struct icount; + enum led_trigger_tty_state state = TTY_LED_DISABLE; + unsigned long interval = LEDTRIG_TTY_INTERVAL; int ret; if (!trigger_data->ttyname) @@ -117,22 +188,37 @@ static void ledtrig_tty_work(struct work_struct *work) trigger_data->tty = tty; } - ret = tty_get_icount(trigger_data->tty, &icount); - if (ret) - goto out; + if (trigger_data->mode_rx || trigger_data->mode_tx) { + struct serial_icounter_struct icount; - if (icount.rx != trigger_data->rx || - icount.tx != trigger_data->tx) { - unsigned long interval = LEDTRIG_TTY_INTERVAL; + ret = tty_get_icount(trigger_data->tty, &icount); + if (ret) + goto out; - led_blink_set_oneshot(trigger_data->led_cdev, &interval, - &interval, 0); + if (trigger_data->mode_tx && (icount.tx != trigger_data->tx)) { + trigger_data->tx = icount.tx; + state = TTY_LED_BLINK; + } - trigger_data->rx = icount.rx; - trigger_data->tx = icount.tx; + if (trigger_data->mode_rx && (icount.rx != trigger_data->rx)) { + trigger_data->rx = icount.rx; + state = TTY_LED_BLINK; + } } out: + switch (state) { + case TTY_LED_BLINK: + led_blink_set_oneshot(trigger_data->led_cdev, &interval, + &interval, 0); + break; + case TTY_LED_DISABLE: + fallthrough; + default: + led_set_brightness(trigger_data->led_cdev, LED_OFF); + break; + } + complete_all(&trigger_data->sysfs); schedule_delayed_work(&trigger_data->dwork, msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 2)); @@ -140,6 +226,8 @@ static void ledtrig_tty_work(struct work_struct *work) static struct attribute *ledtrig_tty_attrs[] = { &dev_attr_ttyname.attr, + &dev_attr_rx.attr, + &dev_attr_tx.attr, NULL }; ATTRIBUTE_GROUPS(ledtrig_tty); @@ -152,6 +240,10 @@ static int ledtrig_tty_activate(struct led_classdev *led_cdev) if (!trigger_data) return -ENOMEM; + /* Enable default rx/tx mode */ + trigger_data->mode_rx = true; + trigger_data->mode_tx = true; + led_set_trigger_data(led_cdev, trigger_data); INIT_DELAYED_WORK(&trigger_data->dwork, ledtrig_tty_work); From patchwork Mon Nov 27 11:03:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Eckert X-Patchwork-Id: 747910 Authentication-Results: smtp.subspace.kernel.org; dkim=none Received: from mxout70.expurgate.net (mxout70.expurgate.net [194.37.255.70]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 99B7F136; Mon, 27 Nov 2023 03:03:25 -0800 (PST) Received: from [127.0.0.1] (helo=localhost) by relay.expurgate.net with smtp (Exim 4.92) (envelope-from ) id 1r7ZOa-002deE-CO; Mon, 27 Nov 2023 12:03:20 +0100 Received: from [195.243.126.94] (helo=securemail.tdt.de) by relay.expurgate.net with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1r7ZOZ-000aHz-Ie; Mon, 27 Nov 2023 12:03:19 +0100 Received: from securemail.tdt.de (localhost [127.0.0.1]) by securemail.tdt.de (Postfix) with ESMTP id 1F502240040; Mon, 27 Nov 2023 12:03:19 +0100 (CET) Received: from mail.dev.tdt.de (unknown [10.2.4.42]) by securemail.tdt.de (Postfix) with ESMTP id 7F7A8240049; Mon, 27 Nov 2023 12:03:18 +0100 (CET) Received: from localhost.localdomain (unknown [10.2.3.40]) by mail.dev.tdt.de (Postfix) with ESMTPSA id CD3AC33D90; Mon, 27 Nov 2023 12:03:17 +0100 (CET) From: Florian Eckert To: Eckert.Florian@googlemail.com, pavel@ucw.cz, lee@kernel.org, kabel@kernel.org, gregkh@linuxfoundation.org, u.kleine-koenig@pengutronix.de Cc: linux-leds@vger.kernel.org, linux-kernel@vger.kernel.org, Maarten Brock Subject: [Patch v9 4/4] leds: ledtrig-tty: add additional line state evaluation Date: Mon, 27 Nov 2023 12:03:11 +0100 Message-ID: <20231127110311.3583957-5-fe@dev.tdt.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20231127110311.3583957-1-fe@dev.tdt.de> References: <20231127110311.3583957-1-fe@dev.tdt.de> Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-purgate: clean X-purgate-ID: 151534::1701083000-57E4C018-8A688704/0/0 X-purgate-type: clean The serial tty interface also supports additional input signals, that can also be evaluated within this trigger. This change is adding the following additional input sources, which could be controlled via the '/sys/class//' sysfs interface. Explanation: DCE = Data Communication Equipment (Modem) DTE = Data Terminal Equipment (Computer) - cts: DCE is ready to accept data from the DTE (CTS = Clear To Send). If the line state is detected, the LED is switched on. If set to 0 (default), the LED will not evaluate CTS. If set to 1, the LED will evaluate CTS. - dsr: DCE is ready to receive and send data (DSR = Data Set Ready). If the line state is detected, the LED is switched on. If set to 0 (default), the LED will not evaluate DSR. If set to 1, the LED will evaluate DSR. - dcd: DTE is receiving a carrier from the DCE (DCD = Data Carrier Detect). If the line state is detected, the LED is switched on. If set to 0 (default), the LED will not evaluate DCD. If set to 1, the LED will evaluate DCD. - rng: DCE has detected an incoming ring signal on the telephone line (RNG = Ring Indicator). If the line state is detected, the LED is switched on. If set to 0 (default), the LED will not evaluate RNG. If set to 1, the LED will evaluate RNG. Also add an invert flag on LED blink, so that the LED blinks in the correct order. * If one off the new enabled input signals are evaluatet as 'enabled', and data are transmitted, then the LED should first blink 'off' and then 'on' (invert). * If all the new enabled input signals are evaluatet as 'disabled', and data are transmitted, then the LED should first blink 'on' and then 'off'. Signed-off-by: Florian Eckert Reviewed-by: Maarten Brock --- .../ABI/testing/sysfs-class-led-trigger-tty | 40 ++++++++++ drivers/leds/trigger/ledtrig-tty.c | 78 ++++++++++++++++++- 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-tty b/Documentation/ABI/testing/sysfs-class-led-trigger-tty index 504dece151b8..30cef9ac0f49 100644 --- a/Documentation/ABI/testing/sysfs-class-led-trigger-tty +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-tty @@ -20,3 +20,43 @@ Description: Signal transmission (tx) of data on the named tty device. If set to 0, the LED will not blink on transmission. If set to 1 (default), the LED will blink on transmission. + +What: /sys/class/leds//cts +Date: February 2024 +KernelVersion: 6.8 +Description: + CTS = Clear To Send + DCE is ready to accept data from the DTE. + If the line state is detected, the LED is switched on. + If set to 0 (default), the LED will not evaluate CTS. + If set to 1, the LED will evaluate CTS. + +What: /sys/class/leds//dsr +Date: February 2024 +KernelVersion: 6.8 +Description: + DSR = Data Set Ready + DCE is ready to receive and send data. + If the line state is detected, the LED is switched on. + If set to 0 (default), the LED will not evaluate DSR. + If set to 1, the LED will evaluate DSR. + +What: /sys/class/leds//dcd +Date: February 2024 +KernelVersion: 6.8 +Description: + DCD = Data Carrier Detect + DTE is receiving a carrier from the DCE. + If the line state is detected, the LED is switched on. + If set to 0 (default), the LED will not evaluate CAR (DCD). + If set to 1, the LED will evaluate CAR (DCD). + +What: /sys/class/leds//rng +Date: February 2024 +KernelVersion: 6.8 +Description: + RNG = Ring Indicator + DCE has detected an incoming ring signal on the telephone + line. If the line state is detected, the LED is switched on. + If set to 0 (default), the LED will not evaluate RNG. + If set to 1, the LED will evaluate RNG. diff --git a/drivers/leds/trigger/ledtrig-tty.c b/drivers/leds/trigger/ledtrig-tty.c index ee6d01ecb309..e30926424c48 100644 --- a/drivers/leds/trigger/ledtrig-tty.c +++ b/drivers/leds/trigger/ledtrig-tty.c @@ -19,17 +19,26 @@ struct ledtrig_tty_data { int rx, tx; bool mode_rx; bool mode_tx; + bool mode_cts; + bool mode_dsr; + bool mode_dcd; + bool mode_rng; }; /* Indicates which state the LED should now display */ enum led_trigger_tty_state { TTY_LED_BLINK, + TTY_LED_ENABLE, TTY_LED_DISABLE, }; enum led_trigger_tty_modes { TRIGGER_TTY_RX = 0, TRIGGER_TTY_TX, + TRIGGER_TTY_CTS, + TRIGGER_TTY_DSR, + TRIGGER_TTY_DCD, + TRIGGER_TTY_RNG, }; static int ledtrig_tty_wait_for_completion(struct device *dev) @@ -111,6 +120,18 @@ static ssize_t ledtrig_tty_attr_show(struct device *dev, char *buf, case TRIGGER_TTY_TX: state = trigger_data->mode_tx; break; + case TRIGGER_TTY_CTS: + state = trigger_data->mode_cts; + break; + case TRIGGER_TTY_DSR: + state = trigger_data->mode_dsr; + break; + case TRIGGER_TTY_DCD: + state = trigger_data->mode_dcd; + break; + case TRIGGER_TTY_RNG: + state = trigger_data->mode_rng; + break; } return sysfs_emit(buf, "%u\n", state); @@ -134,6 +155,18 @@ static ssize_t ledtrig_tty_attr_store(struct device *dev, const char *buf, case TRIGGER_TTY_TX: trigger_data->mode_tx = state; break; + case TRIGGER_TTY_CTS: + trigger_data->mode_cts = state; + break; + case TRIGGER_TTY_DSR: + trigger_data->mode_dsr = state; + break; + case TRIGGER_TTY_DCD: + trigger_data->mode_dcd = state; + break; + case TRIGGER_TTY_RNG: + trigger_data->mode_rng = state; + break; } return size; @@ -154,6 +187,10 @@ static ssize_t ledtrig_tty_attr_store(struct device *dev, const char *buf, DEFINE_TTY_TRIGGER(rx, TRIGGER_TTY_RX); DEFINE_TTY_TRIGGER(tx, TRIGGER_TTY_TX); +DEFINE_TTY_TRIGGER(cts, TRIGGER_TTY_CTS); +DEFINE_TTY_TRIGGER(dsr, TRIGGER_TTY_DSR); +DEFINE_TTY_TRIGGER(dcd, TRIGGER_TTY_DCD); +DEFINE_TTY_TRIGGER(rng, TRIGGER_TTY_RNG); static void ledtrig_tty_work(struct work_struct *work) { @@ -161,6 +198,8 @@ static void ledtrig_tty_work(struct work_struct *work) container_of(work, struct ledtrig_tty_data, dwork.work); enum led_trigger_tty_state state = TTY_LED_DISABLE; unsigned long interval = LEDTRIG_TTY_INTERVAL; + bool invert = false; + int status; int ret; if (!trigger_data->ttyname) @@ -188,6 +227,33 @@ static void ledtrig_tty_work(struct work_struct *work) trigger_data->tty = tty; } + status = tty_get_tiocm(trigger_data->tty); + if (status > 0) { + if (trigger_data->mode_cts) { + if (status & TIOCM_CTS) + state = TTY_LED_ENABLE; + } + + if (trigger_data->mode_dsr) { + if (status & TIOCM_DSR) + state = TTY_LED_ENABLE; + } + + if (trigger_data->mode_dcd) { + if (status & TIOCM_CAR) + state = TTY_LED_ENABLE; + } + + if (trigger_data->mode_rng) { + if (status & TIOCM_RNG) + state = TTY_LED_ENABLE; + } + } + + /* + * The evaluation of rx/tx must be done after the evaluation + * of TIOCM_*, because rx/tx has priority. + */ if (trigger_data->mode_rx || trigger_data->mode_tx) { struct serial_icounter_struct icount; @@ -197,11 +263,13 @@ static void ledtrig_tty_work(struct work_struct *work) if (trigger_data->mode_tx && (icount.tx != trigger_data->tx)) { trigger_data->tx = icount.tx; + invert = state == TTY_LED_ENABLE; state = TTY_LED_BLINK; } if (trigger_data->mode_rx && (icount.rx != trigger_data->rx)) { trigger_data->rx = icount.rx; + invert = state == TTY_LED_ENABLE; state = TTY_LED_BLINK; } } @@ -210,7 +278,11 @@ static void ledtrig_tty_work(struct work_struct *work) switch (state) { case TTY_LED_BLINK: led_blink_set_oneshot(trigger_data->led_cdev, &interval, - &interval, 0); + &interval, invert); + break; + case TTY_LED_ENABLE: + led_set_brightness(trigger_data->led_cdev, + trigger_data->led_cdev->blink_brightness); break; case TTY_LED_DISABLE: fallthrough; @@ -228,6 +300,10 @@ static struct attribute *ledtrig_tty_attrs[] = { &dev_attr_ttyname.attr, &dev_attr_rx.attr, &dev_attr_tx.attr, + &dev_attr_cts.attr, + &dev_attr_dsr.attr, + &dev_attr_dcd.attr, + &dev_attr_rng.attr, NULL }; ATTRIBUTE_GROUPS(ledtrig_tty);