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>
This commit is contained in:
parent
437864828d
commit
5e417281cd
4 changed files with 278 additions and 0 deletions
59
Documentation/leds/ledtrig-oneshot.txt
Normal file
59
Documentation/leds/ledtrig-oneshot.txt
Normal file
|
@ -0,0 +1,59 @@
|
|||
One-shot LED Trigger
|
||||
====================
|
||||
|
||||
This is a LED trigger useful for signaling the user of an event where there are
|
||||
no clear trap points to put standard led-on and led-off settings. Using this
|
||||
trigger, the application needs only to signal the trigger when an event has
|
||||
happened, than the trigger turns the LED on and than keeps it off for a
|
||||
specified amount of time.
|
||||
|
||||
This trigger is meant to be usable both for sporadic and dense events. In the
|
||||
first case, the trigger produces a clear single controlled blink for each
|
||||
event, while in the latter it keeps blinking at constant rate, as to signal
|
||||
that the events are arriving continuously.
|
||||
|
||||
A one-shot LED only stays in a constant state when there are no events. An
|
||||
additional "invert" property specifies if the LED has to stay off (normal) or
|
||||
on (inverted) when not rearmed.
|
||||
|
||||
The trigger can be activated from user space on led class devices as shown
|
||||
below:
|
||||
|
||||
echo oneshot > trigger
|
||||
|
||||
This adds the following sysfs attributes to the LED:
|
||||
|
||||
delay_on - specifies for how many milliseconds the LED has to stay at
|
||||
LED_FULL brightness after it has been armed.
|
||||
Default to 100 ms.
|
||||
|
||||
delay_off - specifies for how many milliseconds the LED has to stay at
|
||||
LED_OFF brightness after it has been armed.
|
||||
Default to 100 ms.
|
||||
|
||||
invert - reverse the blink logic. If set to 0 (default) blink on for delay_on
|
||||
ms, then blink off for delay_off ms, leaving the LED normally off. If
|
||||
set to 1, blink off for delay_off ms, then blink on for delay_on ms,
|
||||
leaving the LED normally on.
|
||||
Setting this value also immediately change the LED state.
|
||||
|
||||
shot - write any non-empty string to signal an events, this starts a blink
|
||||
sequence if not already running.
|
||||
|
||||
Example use-case: network devices, initialization:
|
||||
|
||||
echo oneshot > trigger # set trigger for this led
|
||||
echo 33 > delay_on # blink at 1 / (33 + 33) Hz on continuous traffic
|
||||
echo 33 > delay_off
|
||||
|
||||
interface goes up:
|
||||
|
||||
echo 1 > invert # set led as normally-on, turn the led on
|
||||
|
||||
packet received/transmitted:
|
||||
|
||||
echo 1 > shot # led starts blinking, ignored if already blinking
|
||||
|
||||
interface goes down
|
||||
|
||||
echo 0 > invert # set led as normally-off, turn the led off
|
|
@ -443,6 +443,20 @@ config LEDS_TRIGGER_TIMER
|
|||
|
||||
If unsure, say Y.
|
||||
|
||||
config LEDS_TRIGGER_ONESHOT
|
||||
tristate "LED One-shot Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows LEDs to blink in one-shot pulses with parameters
|
||||
controlled via sysfs. It's useful to notify the user on
|
||||
sporadic events, when there are no clear begin and end trap points,
|
||||
or on dense events, where this blinks the LED at constant rate if
|
||||
rearmed continuously.
|
||||
|
||||
It also shows how to use the led_blink_set_oneshot() function.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config LEDS_TRIGGER_IDE_DISK
|
||||
bool "LED IDE Disk Trigger"
|
||||
depends on IDE_GD_ATA
|
||||
|
|
|
@ -53,6 +53,7 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
|
|||
|
||||
# LED Triggers
|
||||
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_ONESHOT) += ledtrig-oneshot.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
|
||||
|
|
204
drivers/leds/ledtrig-oneshot.c
Normal file
204
drivers/leds/ledtrig-oneshot.c
Normal file
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* One-shot LED Trigger
|
||||
*
|
||||
* Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
|
||||
*
|
||||
* Based on ledtrig-timer.c by Richard Purdie <rpurdie@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/leds.h>
|
||||
#include "leds.h"
|
||||
|
||||
#define DEFAULT_DELAY 100
|
||||
|
||||
struct oneshot_trig_data {
|
||||
unsigned int invert;
|
||||
};
|
||||
|
||||
static ssize_t led_shot(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
|
||||
|
||||
led_blink_set_oneshot(led_cdev,
|
||||
&led_cdev->blink_delay_on, &led_cdev->blink_delay_off,
|
||||
oneshot_data->invert);
|
||||
|
||||
/* content is ignored */
|
||||
return size;
|
||||
}
|
||||
static ssize_t led_invert_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
|
||||
|
||||
return sprintf(buf, "%u\n", oneshot_data->invert);
|
||||
}
|
||||
|
||||
static ssize_t led_invert_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
|
||||
unsigned long state;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul(buf, 0, &state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
oneshot_data->invert = !!state;
|
||||
|
||||
if (oneshot_data->invert)
|
||||
led_set_brightness(led_cdev, LED_FULL);
|
||||
else
|
||||
led_set_brightness(led_cdev, LED_OFF);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t led_delay_on_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
|
||||
}
|
||||
|
||||
static ssize_t led_delay_on_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
unsigned long state;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul(buf, 0, &state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
led_cdev->blink_delay_on = state;
|
||||
|
||||
return size;
|
||||
}
|
||||
static ssize_t led_delay_off_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
|
||||
}
|
||||
|
||||
static ssize_t led_delay_off_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
unsigned long state;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul(buf, 0, &state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
led_cdev->blink_delay_off = state;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
|
||||
static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
|
||||
static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
|
||||
static DEVICE_ATTR(shot, 0200, NULL, led_shot);
|
||||
|
||||
static void oneshot_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct oneshot_trig_data *oneshot_data;
|
||||
int rc;
|
||||
|
||||
oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL);
|
||||
if (!oneshot_data)
|
||||
return;
|
||||
|
||||
led_cdev->trigger_data = oneshot_data;
|
||||
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
|
||||
if (rc)
|
||||
goto err_out_trig_data;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
|
||||
if (rc)
|
||||
goto err_out_delayon;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_invert);
|
||||
if (rc)
|
||||
goto err_out_delayoff;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_shot);
|
||||
if (rc)
|
||||
goto err_out_invert;
|
||||
|
||||
led_cdev->blink_delay_on = DEFAULT_DELAY;
|
||||
led_cdev->blink_delay_off = DEFAULT_DELAY;
|
||||
|
||||
led_cdev->activated = true;
|
||||
|
||||
return;
|
||||
|
||||
err_out_invert:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_invert);
|
||||
err_out_delayoff:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_off);
|
||||
err_out_delayon:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
|
||||
err_out_trig_data:
|
||||
kfree(led_cdev->trigger_data);
|
||||
}
|
||||
|
||||
static void oneshot_trig_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
|
||||
|
||||
if (led_cdev->activated) {
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_off);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_invert);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_shot);
|
||||
kfree(oneshot_data);
|
||||
led_cdev->activated = false;
|
||||
}
|
||||
|
||||
/* Stop blinking */
|
||||
led_brightness_set(led_cdev, LED_OFF);
|
||||
}
|
||||
|
||||
static struct led_trigger oneshot_led_trigger = {
|
||||
.name = "oneshot",
|
||||
.activate = oneshot_trig_activate,
|
||||
.deactivate = oneshot_trig_deactivate,
|
||||
};
|
||||
|
||||
static int __init oneshot_trig_init(void)
|
||||
{
|
||||
return led_trigger_register(&oneshot_led_trigger);
|
||||
}
|
||||
|
||||
static void __exit oneshot_trig_exit(void)
|
||||
{
|
||||
led_trigger_unregister(&oneshot_led_trigger);
|
||||
}
|
||||
|
||||
module_init(oneshot_trig_init);
|
||||
module_exit(oneshot_trig_exit);
|
||||
|
||||
MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");
|
||||
MODULE_DESCRIPTION("One-shot LED trigger");
|
||||
MODULE_LICENSE("GPL");
|
Loading…
Reference in a new issue