aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabio Baltieri <fabio.baltieri@gmail.com>2012-06-06 18:11:05 -0400
committerBryan Wu <bryan.wu@canonical.com>2012-07-23 19:52:34 -0400
commit5e417281cde2ef56e9eb1a95d080d6254402e794 (patch)
tree142bdedb0e099b96276c0e094bf89a10251a7bc4
parent437864828d82b9dee50b5741106fbf5fa12b139a (diff)
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>
-rw-r--r--Documentation/leds/ledtrig-oneshot.txt59
-rw-r--r--drivers/leds/Kconfig14
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/ledtrig-oneshot.c204
4 files changed, 278 insertions, 0 deletions
diff --git a/Documentation/leds/ledtrig-oneshot.txt b/Documentation/leds/ledtrig-oneshot.txt
new file mode 100644
index 00000000000..07cd1fa41a3
--- /dev/null
+++ b/Documentation/leds/ledtrig-oneshot.txt
@@ -0,0 +1,59 @@
1One-shot LED Trigger
2====================
3
4This is a LED trigger useful for signaling the user of an event where there are
5no clear trap points to put standard led-on and led-off settings. Using this
6trigger, the application needs only to signal the trigger when an event has
7happened, than the trigger turns the LED on and than keeps it off for a
8specified amount of time.
9
10This trigger is meant to be usable both for sporadic and dense events. In the
11first case, the trigger produces a clear single controlled blink for each
12event, while in the latter it keeps blinking at constant rate, as to signal
13that the events are arriving continuously.
14
15A one-shot LED only stays in a constant state when there are no events. An
16additional "invert" property specifies if the LED has to stay off (normal) or
17on (inverted) when not rearmed.
18
19The trigger can be activated from user space on led class devices as shown
20below:
21
22 echo oneshot > trigger
23
24This 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
43Example 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
49interface goes up:
50
51 echo 1 > invert # set led as normally-on, turn the led on
52
53packet received/transmitted:
54
55 echo 1 > shot # led starts blinking, ignored if already blinking
56
57interface goes down
58
59 echo 0 > invert # set led as normally-off, turn the led off
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 12b2b55c519..54dd1a396fa 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -443,6 +443,20 @@ config LEDS_TRIGGER_TIMER
443 443
444 If unsure, say Y. 444 If unsure, say Y.
445 445
446config 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
446config LEDS_TRIGGER_IDE_DISK 460config LEDS_TRIGGER_IDE_DISK
447 bool "LED IDE Disk Trigger" 461 bool "LED IDE Disk Trigger"
448 depends on IDE_GD_ATA 462 depends on IDE_GD_ATA
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index f8958cd6cf6..9112d518f9d 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
53 53
54# LED Triggers 54# LED Triggers
55obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o 55obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
56obj-$(CONFIG_LEDS_TRIGGER_ONESHOT) += ledtrig-oneshot.o
56obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o 57obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
57obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o 58obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
58obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o 59obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
diff --git a/drivers/leds/ledtrig-oneshot.c b/drivers/leds/ledtrig-oneshot.c
new file mode 100644
index 00000000000..5c9edf7f489
--- /dev/null
+++ b/drivers/leds/ledtrig-oneshot.c
@@ -0,0 +1,204 @@
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
25struct oneshot_trig_data {
26 unsigned int invert;
27};
28
29static 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}
42static 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
51static 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
73static 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
81static 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}
96static 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
104static 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
120static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
121static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
122static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
123static DEVICE_ATTR(shot, 0200, NULL, led_shot);
124
125static 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
156err_out_invert:
157 device_remove_file(led_cdev->dev, &dev_attr_invert);
158err_out_delayoff:
159 device_remove_file(led_cdev->dev, &dev_attr_delay_off);
160err_out_delayon:
161 device_remove_file(led_cdev->dev, &dev_attr_delay_on);
162err_out_trig_data:
163 kfree(led_cdev->trigger_data);
164}
165
166static 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
183static struct led_trigger oneshot_led_trigger = {
184 .name = "oneshot",
185 .activate = oneshot_trig_activate,
186 .deactivate = oneshot_trig_deactivate,
187};
188
189static int __init oneshot_trig_init(void)
190{
191 return led_trigger_register(&oneshot_led_trigger);
192}
193
194static void __exit oneshot_trig_exit(void)
195{
196 led_trigger_unregister(&oneshot_led_trigger);
197}
198
199module_init(oneshot_trig_init);
200module_exit(oneshot_trig_exit);
201
202MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");
203MODULE_DESCRIPTION("One-shot LED trigger");
204MODULE_LICENSE("GPL");