mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-18 15:44:02 +08:00
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
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.
|
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
|
config LEDS_TRIGGER_IDE_DISK
|
||||||
bool "LED IDE Disk Trigger"
|
bool "LED IDE Disk Trigger"
|
||||||
depends on IDE_GD_ATA
|
depends on IDE_GD_ATA
|
||||||
|
@ -53,6 +53,7 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
|
|||||||
|
|
||||||
# LED Triggers
|
# LED Triggers
|
||||||
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
|
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_IDE_DISK) += ledtrig-ide-disk.o
|
||||||
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
|
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
|
||||||
obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.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 New Issue
Block a user