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

leds: add oneshot trigger

Add oneshot trigger to blink a led with configurale parameters via
sysfs.

Signed-off-by: Fabio Baltieri <fabio.baltieri@gmail.com>
Cc: Shuah Khan <shuahkhan@gmail.com>
Signed-off-by: Bryan Wu <bryan.wu@canonical.com>

authored by

Fabio Baltieri and committed by
Bryan Wu
5e417281 43786482

+278
+59
Documentation/leds/ledtrig-oneshot.txt
··· 1 + One-shot LED Trigger 2 + ==================== 3 + 4 + This is a LED trigger useful for signaling the user of an event where there are 5 + no clear trap points to put standard led-on and led-off settings. Using this 6 + trigger, the application needs only to signal the trigger when an event has 7 + happened, than the trigger turns the LED on and than keeps it off for a 8 + specified amount of time. 9 + 10 + This trigger is meant to be usable both for sporadic and dense events. In the 11 + first case, the trigger produces a clear single controlled blink for each 12 + event, while in the latter it keeps blinking at constant rate, as to signal 13 + that the events are arriving continuously. 14 + 15 + A one-shot LED only stays in a constant state when there are no events. An 16 + additional "invert" property specifies if the LED has to stay off (normal) or 17 + on (inverted) when not rearmed. 18 + 19 + The trigger can be activated from user space on led class devices as shown 20 + below: 21 + 22 + echo oneshot > trigger 23 + 24 + This adds the following sysfs attributes to the LED: 25 + 26 + delay_on - specifies for how many milliseconds the LED has to stay at 27 + LED_FULL brightness after it has been armed. 28 + Default to 100 ms. 29 + 30 + delay_off - specifies for how many milliseconds the LED has to stay at 31 + LED_OFF brightness after it has been armed. 32 + Default to 100 ms. 33 + 34 + invert - reverse the blink logic. If set to 0 (default) blink on for delay_on 35 + ms, then blink off for delay_off ms, leaving the LED normally off. If 36 + set to 1, blink off for delay_off ms, then blink on for delay_on ms, 37 + leaving the LED normally on. 38 + Setting this value also immediately change the LED state. 39 + 40 + shot - write any non-empty string to signal an events, this starts a blink 41 + sequence if not already running. 42 + 43 + Example use-case: network devices, initialization: 44 + 45 + echo oneshot > trigger # set trigger for this led 46 + echo 33 > delay_on # blink at 1 / (33 + 33) Hz on continuous traffic 47 + echo 33 > delay_off 48 + 49 + interface goes up: 50 + 51 + echo 1 > invert # set led as normally-on, turn the led on 52 + 53 + packet received/transmitted: 54 + 55 + echo 1 > shot # led starts blinking, ignored if already blinking 56 + 57 + interface goes down 58 + 59 + echo 0 > invert # set led as normally-off, turn the led off
+14
drivers/leds/Kconfig
··· 443 443 444 444 If unsure, say Y. 445 445 446 + config LEDS_TRIGGER_ONESHOT 447 + tristate "LED One-shot Trigger" 448 + depends on LEDS_TRIGGERS 449 + help 450 + This allows LEDs to blink in one-shot pulses with parameters 451 + controlled via sysfs. It's useful to notify the user on 452 + sporadic events, when there are no clear begin and end trap points, 453 + or on dense events, where this blinks the LED at constant rate if 454 + rearmed continuously. 455 + 456 + It also shows how to use the led_blink_set_oneshot() function. 457 + 458 + If unsure, say Y. 459 + 446 460 config LEDS_TRIGGER_IDE_DISK 447 461 bool "LED IDE Disk Trigger" 448 462 depends on IDE_GD_ATA
+1
drivers/leds/Makefile
··· 53 53 54 54 # LED Triggers 55 55 obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o 56 + obj-$(CONFIG_LEDS_TRIGGER_ONESHOT) += ledtrig-oneshot.o 56 57 obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o 57 58 obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o 58 59 obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
+204
drivers/leds/ledtrig-oneshot.c
··· 1 + /* 2 + * One-shot LED Trigger 3 + * 4 + * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com> 5 + * 6 + * Based on ledtrig-timer.c by Richard Purdie <rpurdie@openedhand.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + */ 13 + 14 + #include <linux/module.h> 15 + #include <linux/kernel.h> 16 + #include <linux/init.h> 17 + #include <linux/device.h> 18 + #include <linux/ctype.h> 19 + #include <linux/slab.h> 20 + #include <linux/leds.h> 21 + #include "leds.h" 22 + 23 + #define DEFAULT_DELAY 100 24 + 25 + struct oneshot_trig_data { 26 + unsigned int invert; 27 + }; 28 + 29 + static ssize_t led_shot(struct device *dev, 30 + struct device_attribute *attr, const char *buf, size_t size) 31 + { 32 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 33 + struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data; 34 + 35 + led_blink_set_oneshot(led_cdev, 36 + &led_cdev->blink_delay_on, &led_cdev->blink_delay_off, 37 + oneshot_data->invert); 38 + 39 + /* content is ignored */ 40 + return size; 41 + } 42 + static ssize_t led_invert_show(struct device *dev, 43 + struct device_attribute *attr, char *buf) 44 + { 45 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 46 + struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data; 47 + 48 + return sprintf(buf, "%u\n", oneshot_data->invert); 49 + } 50 + 51 + static ssize_t led_invert_store(struct device *dev, 52 + struct device_attribute *attr, const char *buf, size_t size) 53 + { 54 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 55 + struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data; 56 + unsigned long state; 57 + int ret; 58 + 59 + ret = kstrtoul(buf, 0, &state); 60 + if (ret) 61 + return ret; 62 + 63 + oneshot_data->invert = !!state; 64 + 65 + if (oneshot_data->invert) 66 + led_set_brightness(led_cdev, LED_FULL); 67 + else 68 + led_set_brightness(led_cdev, LED_OFF); 69 + 70 + return size; 71 + } 72 + 73 + static ssize_t led_delay_on_show(struct device *dev, 74 + struct device_attribute *attr, char *buf) 75 + { 76 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 77 + 78 + return sprintf(buf, "%lu\n", led_cdev->blink_delay_on); 79 + } 80 + 81 + static ssize_t led_delay_on_store(struct device *dev, 82 + struct device_attribute *attr, const char *buf, size_t size) 83 + { 84 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 85 + unsigned long state; 86 + int ret; 87 + 88 + ret = kstrtoul(buf, 0, &state); 89 + if (ret) 90 + return ret; 91 + 92 + led_cdev->blink_delay_on = state; 93 + 94 + return size; 95 + } 96 + static ssize_t led_delay_off_show(struct device *dev, 97 + struct device_attribute *attr, char *buf) 98 + { 99 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 100 + 101 + return sprintf(buf, "%lu\n", led_cdev->blink_delay_off); 102 + } 103 + 104 + static ssize_t led_delay_off_store(struct device *dev, 105 + struct device_attribute *attr, const char *buf, size_t size) 106 + { 107 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 108 + unsigned long state; 109 + int ret; 110 + 111 + ret = kstrtoul(buf, 0, &state); 112 + if (ret) 113 + return ret; 114 + 115 + led_cdev->blink_delay_off = state; 116 + 117 + return size; 118 + } 119 + 120 + static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store); 121 + static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); 122 + static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store); 123 + static DEVICE_ATTR(shot, 0200, NULL, led_shot); 124 + 125 + static void oneshot_trig_activate(struct led_classdev *led_cdev) 126 + { 127 + struct oneshot_trig_data *oneshot_data; 128 + int rc; 129 + 130 + oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL); 131 + if (!oneshot_data) 132 + return; 133 + 134 + led_cdev->trigger_data = oneshot_data; 135 + 136 + rc = device_create_file(led_cdev->dev, &dev_attr_delay_on); 137 + if (rc) 138 + goto err_out_trig_data; 139 + rc = device_create_file(led_cdev->dev, &dev_attr_delay_off); 140 + if (rc) 141 + goto err_out_delayon; 142 + rc = device_create_file(led_cdev->dev, &dev_attr_invert); 143 + if (rc) 144 + goto err_out_delayoff; 145 + rc = device_create_file(led_cdev->dev, &dev_attr_shot); 146 + if (rc) 147 + goto err_out_invert; 148 + 149 + led_cdev->blink_delay_on = DEFAULT_DELAY; 150 + led_cdev->blink_delay_off = DEFAULT_DELAY; 151 + 152 + led_cdev->activated = true; 153 + 154 + return; 155 + 156 + err_out_invert: 157 + device_remove_file(led_cdev->dev, &dev_attr_invert); 158 + err_out_delayoff: 159 + device_remove_file(led_cdev->dev, &dev_attr_delay_off); 160 + err_out_delayon: 161 + device_remove_file(led_cdev->dev, &dev_attr_delay_on); 162 + err_out_trig_data: 163 + kfree(led_cdev->trigger_data); 164 + } 165 + 166 + static void oneshot_trig_deactivate(struct led_classdev *led_cdev) 167 + { 168 + struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data; 169 + 170 + if (led_cdev->activated) { 171 + device_remove_file(led_cdev->dev, &dev_attr_delay_on); 172 + device_remove_file(led_cdev->dev, &dev_attr_delay_off); 173 + device_remove_file(led_cdev->dev, &dev_attr_invert); 174 + device_remove_file(led_cdev->dev, &dev_attr_shot); 175 + kfree(oneshot_data); 176 + led_cdev->activated = false; 177 + } 178 + 179 + /* Stop blinking */ 180 + led_brightness_set(led_cdev, LED_OFF); 181 + } 182 + 183 + static struct led_trigger oneshot_led_trigger = { 184 + .name = "oneshot", 185 + .activate = oneshot_trig_activate, 186 + .deactivate = oneshot_trig_deactivate, 187 + }; 188 + 189 + static int __init oneshot_trig_init(void) 190 + { 191 + return led_trigger_register(&oneshot_led_trigger); 192 + } 193 + 194 + static void __exit oneshot_trig_exit(void) 195 + { 196 + led_trigger_unregister(&oneshot_led_trigger); 197 + } 198 + 199 + module_init(oneshot_trig_init); 200 + module_exit(oneshot_trig_exit); 201 + 202 + MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>"); 203 + MODULE_DESCRIPTION("One-shot LED trigger"); 204 + MODULE_LICENSE("GPL");