Complex triggers whilst available to all LEDs have LED specific
parameters and work on a per LED basis. The timer trigger is an example.
+The timer trigger will periodically change the LED brightness between
+LED_OFF and the current brightness setting. The "on" and "off" time can
+be specified via /sys/class/leds/<device>/delay_{on,off} in milliseconds.
+You can change the brightness value of a LED independently of the timer
+trigger. However, if you set the brightness value to LED_OFF it will
+also disable the timer trigger.
You can change triggers in a similar manner to the way an IO scheduler
is chosen (via /sys/class/leds/<device>/trigger). Trigger specific
this case the driver should give back the chosen value through delay_on
and delay_off parameters to the leds subsystem.
-Any call to the brightness_set() callback function should cancel the
-previously programmed hardware blinking function so setting the brightness
-to 0 can also cancel the blinking of the LED.
+Setting the brightness to zero with brightness_set() callback function
+should completely turn off the LED and cancel the previously programmed
+hardware blinking function, if any.
Known Issues
if (count == size) {
ret = count;
+
+ if (state == LED_OFF)
+ led_trigger_remove(led_cdev);
led_set_brightness(led_cdev, state);
}
trigger_name[len - 1] = '\0';
if (!strcmp(trigger_name, "none")) {
- down_write(&led_cdev->trigger_lock);
- led_trigger_set(led_cdev, NULL);
- up_write(&led_cdev->trigger_lock);
+ led_trigger_remove(led_cdev);
return count;
}
led_cdev->trigger = trigger;
}
+void led_trigger_remove(struct led_classdev *led_cdev)
+{
+ down_write(&led_cdev->trigger_lock);
+ led_trigger_set(led_cdev, NULL);
+ up_write(&led_cdev->trigger_lock);
+}
+
void led_trigger_set_default(struct led_classdev *led_cdev)
{
struct led_trigger *trig;
/* Used by LED Class */
EXPORT_SYMBOL_GPL(led_trigger_set);
+EXPORT_SYMBOL_GPL(led_trigger_remove);
EXPORT_SYMBOL_GPL(led_trigger_set_default);
EXPORT_SYMBOL_GPL(led_trigger_show);
EXPORT_SYMBOL_GPL(led_trigger_store);
led_cdev->brightness_set(led_cdev, value);
}
+static inline int led_get_brightness(struct led_classdev *led_cdev)
+{
+ return led_cdev->brightness;
+}
+
extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list;
void led_trigger_set_default(struct led_classdev *led_cdev);
void led_trigger_set(struct led_classdev *led_cdev,
struct led_trigger *trigger);
+void led_trigger_remove(struct led_classdev *led_cdev);
#else
#define led_trigger_set_default(x) do {} while(0)
#define led_trigger_set(x, y) do {} while(0)
+#define led_trigger_remove(x) do {} while(0)
#endif
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
#include "leds.h"
struct timer_trig_data {
+ int brightness_on; /* LED brightness during "on" period.
+ * (LED_OFF < brightness_on <= LED_FULL)
+ */
unsigned long delay_on; /* milliseconds on */
unsigned long delay_off; /* milliseconds off */
struct timer_list timer;
{
struct led_classdev *led_cdev = (struct led_classdev *) data;
struct timer_trig_data *timer_data = led_cdev->trigger_data;
- unsigned long brightness = LED_OFF;
- unsigned long delay = timer_data->delay_off;
+ unsigned long brightness;
+ unsigned long delay;
if (!timer_data->delay_on || !timer_data->delay_off) {
led_set_brightness(led_cdev, LED_OFF);
return;
}
- if (!led_cdev->brightness) {
- brightness = LED_FULL;
+ brightness = led_get_brightness(led_cdev);
+ if (!brightness) {
+ /* Time to switch the LED on. */
+ brightness = timer_data->brightness_on;
delay = timer_data->delay_on;
+ } else {
+ /* Store the current brightness value to be able
+ * to restore it when the delay_off period is over.
+ */
+ timer_data->brightness_on = brightness;
+ brightness = LED_OFF;
+ delay = timer_data->delay_off;
}
led_set_brightness(led_cdev, brightness);
if (!timer_data)
return;
+ timer_data->brightness_on = led_get_brightness(led_cdev);
+ if (timer_data->brightness_on == LED_OFF)
+ timer_data->brightness_on = LED_FULL;
led_cdev->trigger_data = timer_data;
init_timer(&timer_data->timer);