From patchwork Mon Oct 23 09:42:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Eckert X-Patchwork-Id: 737422 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7D2D8C004C0 for ; Mon, 23 Oct 2023 09:42:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229575AbjJWJme (ORCPT ); Mon, 23 Oct 2023 05:42:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35732 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229912AbjJWJm0 (ORCPT ); Mon, 23 Oct 2023 05:42:26 -0400 Received: from mxout70.expurgate.net (mxout70.expurgate.net [91.198.224.70]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 67066FC; Mon, 23 Oct 2023 02:42:22 -0700 (PDT) Received: from [127.0.0.1] (helo=localhost) by relay.expurgate.net with smtp (Exim 4.92) (envelope-from ) id 1qurRv-003Gso-6q; Mon, 23 Oct 2023 11:42:15 +0200 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 1qurRu-00FTm3-CF; Mon, 23 Oct 2023 11:42:14 +0200 Received: from securemail.tdt.de (localhost [127.0.0.1]) by securemail.tdt.de (Postfix) with ESMTP id F237E24004D; Mon, 23 Oct 2023 11:42:13 +0200 (CEST) Received: from mail.dev.tdt.de (unknown [10.2.4.42]) by securemail.tdt.de (Postfix) with ESMTP id 4DFDA240049; Mon, 23 Oct 2023 11:42:13 +0200 (CEST) Received: from localhost.localdomain (unknown [10.2.3.40]) by mail.dev.tdt.de (Postfix) with ESMTPSA id 04571217C3; Mon, 23 Oct 2023 11:42:13 +0200 (CEST) From: Florian Eckert To: Eckert.Florian@googlemail.com, gregkh@linuxfoundation.org, jirislaby@kernel.org, pavel@ucw.cz, lee@kernel.org, kabel@kernel.org, u.kleine-koenig@pengutronix.de, m.brock@vanmierlo.com Cc: linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v5 1/2] tty: add new helper function tty_get_tiocm Date: Mon, 23 Oct 2023 11:42:04 +0200 Message-ID: <20231023094205.2706812-2-fe@dev.tdt.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20231023094205.2706812-1-fe@dev.tdt.de> References: <20231023094205.2706812-1-fe@dev.tdt.de> MIME-Version: 1.0 X-purgate-ID: 151534::1698054135-FA0CB49D-6752218D/0/0 X-purgate: clean X-purgate-type: clean Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org 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. 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 3299a5d50727..a12f63854ac4 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2494,6 +2494,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 @@ -2506,14 +2524,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 f002d0f25db7..8e4d0b3b12b7 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -421,6 +421,7 @@ int 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 Oct 23 09:42:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Eckert X-Patchwork-Id: 737421 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E20A4CDB474 for ; Mon, 23 Oct 2023 09:42:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229996AbjJWJmg (ORCPT ); Mon, 23 Oct 2023 05:42:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50502 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229985AbjJWJm1 (ORCPT ); Mon, 23 Oct 2023 05:42:27 -0400 Received: from mxout70.expurgate.net (mxout70.expurgate.net [91.198.224.70]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 296D1DF; Mon, 23 Oct 2023 02:42:22 -0700 (PDT) Received: from [127.0.0.1] (helo=localhost) by relay.expurgate.net with smtp (Exim 4.92) (envelope-from ) id 1qurRv-003rZd-PJ; Mon, 23 Oct 2023 11:42:15 +0200 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 1qurRu-00Bw5F-Uz; Mon, 23 Oct 2023 11:42:15 +0200 Received: from securemail.tdt.de (localhost [127.0.0.1]) by securemail.tdt.de (Postfix) with ESMTP id 81FDB240049; Mon, 23 Oct 2023 11:42:14 +0200 (CEST) Received: from mail.dev.tdt.de (unknown [10.2.4.42]) by securemail.tdt.de (Postfix) with ESMTP id D4188240040; Mon, 23 Oct 2023 11:42:13 +0200 (CEST) Received: from localhost.localdomain (unknown [10.2.3.40]) by mail.dev.tdt.de (Postfix) with ESMTPSA id 4F3C5216D6; Mon, 23 Oct 2023 11:42:13 +0200 (CEST) From: Florian Eckert To: Eckert.Florian@googlemail.com, gregkh@linuxfoundation.org, jirislaby@kernel.org, pavel@ucw.cz, lee@kernel.org, kabel@kernel.org, u.kleine-koenig@pengutronix.de, m.brock@vanmierlo.com Cc: linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, linux-leds@vger.kernel.org Subject: [PATCH v5 2/2] leds: ledtrig-tty: add new line mode evaluation Date: Mon, 23 Oct 2023 11:42:05 +0200 Message-ID: <20231023094205.2706812-3-fe@dev.tdt.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20231023094205.2706812-1-fe@dev.tdt.de> References: <20231023094205.2706812-1-fe@dev.tdt.de> MIME-Version: 1.0 X-purgate-type: clean X-purgate-ID: 151534::1698054135-DDB7B1F7-5966E501/0/0 X-purgate: clean Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Until now, the LED blinks when data is sent via the tty (rx/tx). 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. - line_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. - line_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. - line_car: 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 CAR (DCD). If set to 1, the LED will evaluate CAR (DCD). - line_rng: DCE has detected an incoming ring signal on the telephone line (RI = Ring Indicator). If the line state is detected, the LED is switched on. If set to 0 (default), the LED will not evaluate RNG (RI). If set to 1, the LED will evaluate RNG (RI). Explanation: DCE = Data Communication Equipment (Modem) DTE = Data Terminal Equipment (Computer) In addition to the new line_* entries in sysfs, the indication for the direction of the transmitted data is independently controllable via the new rx and tx sysfs entrie now too. These are on by default. Thus the trigger behaves as before this change. - 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. Signed-off-by: Florian Eckert --- .../ABI/testing/sysfs-class-led-trigger-tty | 54 +++++ drivers/leds/trigger/ledtrig-tty.c | 187 ++++++++++++++++-- 2 files changed, 230 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..08127b1a4602 100644 --- a/Documentation/ABI/testing/sysfs-class-led-trigger-tty +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-tty @@ -4,3 +4,57 @@ 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: October 2023 +KernelVersion: 6.7 +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: October 2023 +KernelVersion: 6.7 +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. + +car rng +What: /sys/class/leds//line_cts +Date: October 2023 +KernelVersion: 6.7 +Description: + DCE is ready to accept data from the DTE (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. + +What: /sys/class/leds//line_dsr +Date: October 2023 +KernelVersion: 6.7 +Description: + DCE is ready to receive and send data (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. + +What: /sys/class/leds//line_car +Date: October 2023 +KernelVersion: 6.7 +Description: + DTE is receiving a carrier from the DCE (Data Carrier Detect). + 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//line_cts +Date: October 2023 +KernelVersion: 6.7 +Description: + DCE has detected an incoming ring signal on the telephone + line (Ring Indicator). If the line state is detected, the + LED is switched on. + If set to 0 (default), the LED will not evaluate RNG (RI). + If set to 1, the LED will evaluate RNG (RI). diff --git a/drivers/leds/trigger/ledtrig-tty.c b/drivers/leds/trigger/ledtrig-tty.c index 8ae0d2d284af..5c8aea1791cf 100644 --- a/drivers/leds/trigger/ledtrig-tty.c +++ b/drivers/leds/trigger/ledtrig-tty.c @@ -16,6 +16,28 @@ struct ledtrig_tty_data { const char *ttyname; struct tty_struct *tty; int rx, tx; + unsigned long ttytrigger; +}; + +/* Indicates which state the LED should now display */ +enum led_trigger_tty_state { + TTY_LED_BLINK, + TTY_LED_ENABLE, + TTY_LED_DISABLE, +}; + +/* This enum is used to read and write the ttytrigger selection via the + * sysfs entry and also to evaluate the TIOCM_* bits. + */ +enum led_trigger_tty_bits { + TRIGGER_TTY_RX = 0, + TRIGGER_TTY_TX, + TRIGGER_TTY_CTS, + TRIGGER_TTY_DSR, + TRIGGER_TTY_CAR, + TRIGGER_TTY_RNG, + /* Keep last */ + __TRIGGER_TTY_MAX, }; static void ledtrig_tty_restart(struct ledtrig_tty_data *trigger_data) @@ -78,13 +100,94 @@ 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_bits attr) +{ + struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev); + int trigger; + + switch (attr) { + case TRIGGER_TTY_RX: + case TRIGGER_TTY_TX: + case TRIGGER_TTY_CTS: + case TRIGGER_TTY_DSR: + case TRIGGER_TTY_CAR: + case TRIGGER_TTY_RNG: + trigger = attr; + break; + default: + return -EINVAL; + } + + return sysfs_emit(buf, "%u\n", test_bit(trigger, &trigger_data->ttytrigger)); +} + +static ssize_t ledtrig_tty_attr_store(struct device *dev, const char *buf, + size_t size, enum led_trigger_tty_bits attr) +{ + struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev); + bool enable; + int trigger; + int ret; + + ret = kstrtobool(buf, &enable); + if (ret) + return ret; + + switch (attr) { + case TRIGGER_TTY_RX: + case TRIGGER_TTY_TX: + case TRIGGER_TTY_CTS: + case TRIGGER_TTY_DSR: + case TRIGGER_TTY_CAR: + case TRIGGER_TTY_RNG: + trigger = attr; + break; + default: + return -EINVAL; + } + + if (enable) + set_bit(trigger, &trigger_data->ttytrigger); + else + clear_bit(trigger, &trigger_data->ttytrigger); + + 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); +DEFINE_TTY_TRIGGER(line_cts, TRIGGER_TTY_CTS); +DEFINE_TTY_TRIGGER(line_dsr, TRIGGER_TTY_DSR); +DEFINE_TTY_TRIGGER(line_car, TRIGGER_TTY_CAR); +DEFINE_TTY_TRIGGER(line_rng, TRIGGER_TTY_RNG); + 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 led_classdev *led_cdev = trigger_data->led_cdev; + unsigned long interval = LEDTRIG_TTY_INTERVAL; struct serial_icounter_struct icount; + enum led_trigger_tty_state state; + int current_brightness; + int status; int ret; + state = TTY_LED_DISABLE; mutex_lock(&trigger_data->mutex); if (!trigger_data->ttyname) { @@ -115,22 +218,74 @@ static void ledtrig_tty_work(struct work_struct *work) trigger_data->tty = tty; } - 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; + status = tty_get_tiocm(trigger_data->tty); + if (status > 0) { + if (test_bit(TRIGGER_TTY_CTS, &trigger_data->ttytrigger)) { + if (status & TIOCM_CTS) + state = TTY_LED_ENABLE; + } + + if (test_bit(TRIGGER_TTY_DSR, &trigger_data->ttytrigger)) { + if (status & TIOCM_DSR) + state = TTY_LED_ENABLE; + } + + if (test_bit(TRIGGER_TTY_CAR, &trigger_data->ttytrigger)) { + if (status & TIOCM_CAR) + state = TTY_LED_ENABLE; + } + + if (test_bit(TRIGGER_TTY_RNG, &trigger_data->ttytrigger)) { + if (status & TIOCM_RNG) + state = TTY_LED_ENABLE; + } + } + + /* The rx/tx handling must come after the evaluation of TIOCM_*, + * since the display for rx/tx has priority + */ + if (test_bit(TRIGGER_TTY_RX, &trigger_data->ttytrigger) || + test_bit(TRIGGER_TTY_TX, &trigger_data->ttytrigger)) { + 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 (test_bit(TRIGGER_TTY_RX, &trigger_data->ttytrigger) && + (icount.tx != trigger_data->tx)) { + trigger_data->tx = icount.tx; + state = TTY_LED_BLINK; + } + + if (test_bit(TRIGGER_TTY_TX, &trigger_data->ttytrigger) && + (icount.rx != trigger_data->rx)) { + trigger_data->rx = icount.rx; + state = TTY_LED_BLINK; + } } - if (icount.rx != trigger_data->rx || - icount.tx != trigger_data->tx) { - unsigned long interval = LEDTRIG_TTY_INTERVAL; + current_brightness = led_cdev->brightness; + if (current_brightness) + led_cdev->blink_brightness = current_brightness; + if (!led_cdev->blink_brightness) + led_cdev->blink_brightness = led_cdev->max_brightness; + + switch (state) { + case TTY_LED_BLINK: led_blink_set_oneshot(trigger_data->led_cdev, &interval, &interval, 0); - - trigger_data->rx = icount.rx; - trigger_data->tx = icount.tx; + break; + case TTY_LED_ENABLE: + led_set_brightness(led_cdev, led_cdev->blink_brightness); + break; + case TTY_LED_DISABLE: + fallthrough; + default: + led_set_brightness(led_cdev, LED_OFF); + break; } out: @@ -141,6 +296,12 @@ 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, + &dev_attr_line_cts.attr, + &dev_attr_line_dsr.attr, + &dev_attr_line_car.attr, + &dev_attr_line_rng.attr, NULL }; ATTRIBUTE_GROUPS(ledtrig_tty); @@ -153,6 +314,10 @@ static int ledtrig_tty_activate(struct led_classdev *led_cdev) if (!trigger_data) return -ENOMEM; + /* Enable default rx/tx LED blink */ + set_bit(TRIGGER_TTY_TX, &trigger_data->ttytrigger); + set_bit(TRIGGER_TTY_RX, &trigger_data->ttytrigger); + led_set_trigger_data(led_cdev, trigger_data); INIT_DELAYED_WORK(&trigger_data->dwork, ledtrig_tty_work);