Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

leds: ledtrig-tty: Add additional line state evaluation

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/<leds>/' 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 <fe@dev.tdt.de>
Reviewed-by: Maarten Brock <m.brock@vanmierlo.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://lore.kernel.org/r/20231127110311.3583957-5-fe@dev.tdt.de
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Florian Eckert and committed by
Lee Jones
6dec6598 5b755ca6

+117 -1
+40
Documentation/ABI/testing/sysfs-class-led-trigger-tty
··· 20 20 Signal transmission (tx) of data on the named tty device. 21 21 If set to 0, the LED will not blink on transmission. 22 22 If set to 1 (default), the LED will blink on transmission. 23 + 24 + What: /sys/class/leds/<led>/cts 25 + Date: February 2024 26 + KernelVersion: 6.8 27 + Description: 28 + CTS = Clear To Send 29 + DCE is ready to accept data from the DTE. 30 + If the line state is detected, the LED is switched on. 31 + If set to 0 (default), the LED will not evaluate CTS. 32 + If set to 1, the LED will evaluate CTS. 33 + 34 + What: /sys/class/leds/<led>/dsr 35 + Date: February 2024 36 + KernelVersion: 6.8 37 + Description: 38 + DSR = Data Set Ready 39 + DCE is ready to receive and send data. 40 + If the line state is detected, the LED is switched on. 41 + If set to 0 (default), the LED will not evaluate DSR. 42 + If set to 1, the LED will evaluate DSR. 43 + 44 + What: /sys/class/leds/<led>/dcd 45 + Date: February 2024 46 + KernelVersion: 6.8 47 + Description: 48 + DCD = Data Carrier Detect 49 + DTE is receiving a carrier from the DCE. 50 + If the line state is detected, the LED is switched on. 51 + If set to 0 (default), the LED will not evaluate CAR (DCD). 52 + If set to 1, the LED will evaluate CAR (DCD). 53 + 54 + What: /sys/class/leds/<led>/rng 55 + Date: February 2024 56 + KernelVersion: 6.8 57 + Description: 58 + RNG = Ring Indicator 59 + DCE has detected an incoming ring signal on the telephone 60 + line. If the line state is detected, the LED is switched on. 61 + If set to 0 (default), the LED will not evaluate RNG. 62 + If set to 1, the LED will evaluate RNG.
+77 -1
drivers/leds/trigger/ledtrig-tty.c
··· 19 19 int rx, tx; 20 20 bool mode_rx; 21 21 bool mode_tx; 22 + bool mode_cts; 23 + bool mode_dsr; 24 + bool mode_dcd; 25 + bool mode_rng; 22 26 }; 23 27 24 28 /* Indicates which state the LED should now display */ 25 29 enum led_trigger_tty_state { 26 30 TTY_LED_BLINK, 31 + TTY_LED_ENABLE, 27 32 TTY_LED_DISABLE, 28 33 }; 29 34 30 35 enum led_trigger_tty_modes { 31 36 TRIGGER_TTY_RX = 0, 32 37 TRIGGER_TTY_TX, 38 + TRIGGER_TTY_CTS, 39 + TRIGGER_TTY_DSR, 40 + TRIGGER_TTY_DCD, 41 + TRIGGER_TTY_RNG, 33 42 }; 34 43 35 44 static int ledtrig_tty_wait_for_completion(struct device *dev) ··· 120 111 case TRIGGER_TTY_TX: 121 112 state = trigger_data->mode_tx; 122 113 break; 114 + case TRIGGER_TTY_CTS: 115 + state = trigger_data->mode_cts; 116 + break; 117 + case TRIGGER_TTY_DSR: 118 + state = trigger_data->mode_dsr; 119 + break; 120 + case TRIGGER_TTY_DCD: 121 + state = trigger_data->mode_dcd; 122 + break; 123 + case TRIGGER_TTY_RNG: 124 + state = trigger_data->mode_rng; 125 + break; 123 126 } 124 127 125 128 return sysfs_emit(buf, "%u\n", state); ··· 155 134 case TRIGGER_TTY_TX: 156 135 trigger_data->mode_tx = state; 157 136 break; 137 + case TRIGGER_TTY_CTS: 138 + trigger_data->mode_cts = state; 139 + break; 140 + case TRIGGER_TTY_DSR: 141 + trigger_data->mode_dsr = state; 142 + break; 143 + case TRIGGER_TTY_DCD: 144 + trigger_data->mode_dcd = state; 145 + break; 146 + case TRIGGER_TTY_RNG: 147 + trigger_data->mode_rng = state; 148 + break; 158 149 } 159 150 160 151 return size; ··· 187 154 188 155 DEFINE_TTY_TRIGGER(rx, TRIGGER_TTY_RX); 189 156 DEFINE_TTY_TRIGGER(tx, TRIGGER_TTY_TX); 157 + DEFINE_TTY_TRIGGER(cts, TRIGGER_TTY_CTS); 158 + DEFINE_TTY_TRIGGER(dsr, TRIGGER_TTY_DSR); 159 + DEFINE_TTY_TRIGGER(dcd, TRIGGER_TTY_DCD); 160 + DEFINE_TTY_TRIGGER(rng, TRIGGER_TTY_RNG); 190 161 191 162 static void ledtrig_tty_work(struct work_struct *work) 192 163 { ··· 198 161 container_of(work, struct ledtrig_tty_data, dwork.work); 199 162 enum led_trigger_tty_state state = TTY_LED_DISABLE; 200 163 unsigned long interval = LEDTRIG_TTY_INTERVAL; 164 + bool invert = false; 165 + int status; 201 166 int ret; 202 167 203 168 if (!trigger_data->ttyname) ··· 227 188 trigger_data->tty = tty; 228 189 } 229 190 191 + status = tty_get_tiocm(trigger_data->tty); 192 + if (status > 0) { 193 + if (trigger_data->mode_cts) { 194 + if (status & TIOCM_CTS) 195 + state = TTY_LED_ENABLE; 196 + } 197 + 198 + if (trigger_data->mode_dsr) { 199 + if (status & TIOCM_DSR) 200 + state = TTY_LED_ENABLE; 201 + } 202 + 203 + if (trigger_data->mode_dcd) { 204 + if (status & TIOCM_CAR) 205 + state = TTY_LED_ENABLE; 206 + } 207 + 208 + if (trigger_data->mode_rng) { 209 + if (status & TIOCM_RNG) 210 + state = TTY_LED_ENABLE; 211 + } 212 + } 213 + 214 + /* 215 + * The evaluation of rx/tx must be done after the evaluation 216 + * of TIOCM_*, because rx/tx has priority. 217 + */ 230 218 if (trigger_data->mode_rx || trigger_data->mode_tx) { 231 219 struct serial_icounter_struct icount; 232 220 ··· 263 197 264 198 if (trigger_data->mode_tx && (icount.tx != trigger_data->tx)) { 265 199 trigger_data->tx = icount.tx; 200 + invert = state == TTY_LED_ENABLE; 266 201 state = TTY_LED_BLINK; 267 202 } 268 203 269 204 if (trigger_data->mode_rx && (icount.rx != trigger_data->rx)) { 270 205 trigger_data->rx = icount.rx; 206 + invert = state == TTY_LED_ENABLE; 271 207 state = TTY_LED_BLINK; 272 208 } 273 209 } ··· 278 210 switch (state) { 279 211 case TTY_LED_BLINK: 280 212 led_blink_set_oneshot(trigger_data->led_cdev, &interval, 281 - &interval, 0); 213 + &interval, invert); 214 + break; 215 + case TTY_LED_ENABLE: 216 + led_set_brightness(trigger_data->led_cdev, 217 + trigger_data->led_cdev->blink_brightness); 282 218 break; 283 219 case TTY_LED_DISABLE: 284 220 fallthrough; ··· 300 228 &dev_attr_ttyname.attr, 301 229 &dev_attr_rx.attr, 302 230 &dev_attr_tx.attr, 231 + &dev_attr_cts.attr, 232 + &dev_attr_dsr.attr, 233 + &dev_attr_dcd.attr, 234 + &dev_attr_rng.attr, 303 235 NULL 304 236 }; 305 237 ATTRIBUTE_GROUPS(ledtrig_tty);