forked from mirrors/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>
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