[PATCH] LEDS-One-Shot-Timer-Trigger-implementation

From: Shuah Khan
Date: Mon Mar 26 2012 - 19:34:42 EST



Signed-off-by: Shuah Khan <shuahkhan@xxxxxxxxx>
---
drivers/leds/led-class.c | 4 +-
drivers/leds/led-core.c | 26 +++++++++--
drivers/leds/ledtrig-timer.c | 101 +++++++++++++++++++++++++++++------------
3 files changed, 96 insertions(+), 35 deletions(-)

diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 5bff843..be7400a 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -107,7 +107,9 @@ static void led_timer_function(unsigned long data)

led_set_brightness(led_cdev, brightness);

- mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
+ if (delay != ULONG_MAX)
+ mod_timer(&led_cdev->blink_timer,
+ jiffies + msecs_to_jiffies(delay));
}

/**
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index d686004..40685f1 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -72,17 +72,35 @@ void led_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on,
unsigned long *delay_off)
{
+ unsigned long val_on;
+ unsigned long val_off;
+
del_timer_sync(&led_cdev->blink_timer);

- if (led_cdev->blink_set &&
+ if (delay_on && delay_off && led_cdev->blink_set &&
!led_cdev->blink_set(led_cdev, delay_on, delay_off))
return;

+ /* if delay_on is null, leave it on forever after delay_off period
+ if delay_off is null, leave it off forever after delay on period */
+ if (!delay_on)
+ val_on = ULONG_MAX;
+ else
+ val_on = *delay_on;
+
+ if (!delay_off)
+ val_off = ULONG_MAX;
+ else
+ val_off = *delay_off;
+
/* blink with 1 Hz as default if nothing specified */
- if (!*delay_on && !*delay_off)
- *delay_on = *delay_off = 500;
+ if (!val_on && !val_off) {
+ val_on = val_off = 500;
+ *delay_on = 500;
+ *delay_off = 500;
+ }

- led_set_software_blink(led_cdev, *delay_on, *delay_off);
+ led_set_software_blink(led_cdev, val_on, val_off);
}
EXPORT_SYMBOL(led_blink_set);

diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index 328c64c..bfda51c 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -24,6 +24,9 @@ static ssize_t led_delay_on_show(struct device *dev,
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);

+ if (led_cdev->blink_delay_on == ULONG_MAX)
+ return sprintf(buf, "%s\n", "forever");
+
return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
}

@@ -32,17 +35,25 @@ static ssize_t led_delay_on_store(struct device *dev,
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
int ret = -EINVAL;
- char *after;
- unsigned long state = simple_strtoul(buf, &after, 10);
- size_t count = after - buf;
-
- if (isspace(*after))
- count++;

- if (count == size) {
- led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off);
- led_cdev->blink_delay_on = state;
- ret = count;
+ if (strncmp(buf, "forever", 7) == 0) {
+ led_blink_set(led_cdev, NULL, &led_cdev->blink_delay_off);
+ led_cdev->blink_delay_on = ULONG_MAX;
+ ret = size;
+ } else {
+ char *after;
+ unsigned long state = simple_strtoul(buf, &after, 10);
+ size_t count = after - buf;
+
+ if (isspace(*after))
+ count++;
+
+ if (count == size) {
+ led_blink_set(led_cdev, &state,
+ &led_cdev->blink_delay_off);
+ led_cdev->blink_delay_on = state;
+ ret = count;
+ }
}

return ret;
@@ -53,6 +64,9 @@ static ssize_t led_delay_off_show(struct device *dev,
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);

+ if (led_cdev->blink_delay_off == ULONG_MAX)
+ return sprintf(buf, "%s\n", "forever");
+
return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
}

@@ -61,17 +75,24 @@ static ssize_t led_delay_off_store(struct device *dev,
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
int ret = -EINVAL;
- char *after;
- unsigned long state = simple_strtoul(buf, &after, 10);
- size_t count = after - buf;

- if (isspace(*after))
- count++;
-
- if (count == size) {
- led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state);
- led_cdev->blink_delay_off = state;
- ret = count;
+ if (strncmp(buf, "forever", 7) == 0) {
+ led_blink_set(led_cdev, &led_cdev->blink_delay_on, NULL);
+ led_cdev->blink_delay_off = ULONG_MAX;
+ } else {
+ char *after;
+ unsigned long state = simple_strtoul(buf, &after, 10);
+ size_t count = after - buf;
+
+ if (isspace(*after))
+ count++;
+
+ if (count == size) {
+ led_blink_set(led_cdev, &led_cdev->blink_delay_on,
+ &state);
+ led_cdev->blink_delay_off = state;
+ ret = count;
+ }
}

return ret;
@@ -80,7 +101,7 @@ static ssize_t led_delay_off_store(struct device *dev,
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 void timer_trig_activate(struct led_classdev *led_cdev)
+static void timer_trig_activate_common(struct led_classdev *led_cdev)
{
int rc;

@@ -91,17 +112,24 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
return;
rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
if (rc)
- goto err_out_delayon;
-
- led_blink_set(led_cdev, &led_cdev->blink_delay_on,
- &led_cdev->blink_delay_off);
+ device_remove_file(led_cdev->dev, &dev_attr_delay_on);

- led_cdev->trigger_data = (void *)1;
+ else
+ led_cdev->trigger_data = (void *)1;
+}

- return;
+static void timer_trig_activate_one_shot(struct led_classdev *led_cdev)
+{
+ timer_trig_activate_common(led_cdev);
+}

-err_out_delayon:
- device_remove_file(led_cdev->dev, &dev_attr_delay_on);
+static void timer_trig_activate(struct led_classdev *led_cdev)
+{
+ timer_trig_activate_common(led_cdev);
+ if (led_cdev->trigger_data) {
+ led_blink_set(led_cdev, &led_cdev->blink_delay_on,
+ &led_cdev->blink_delay_off);
+ }
}

static void timer_trig_deactivate(struct led_classdev *led_cdev)
@@ -121,14 +149,27 @@ static struct led_trigger timer_led_trigger = {
.deactivate = timer_trig_deactivate,
};

+static struct led_trigger one_shot_timer_led_trigger = {
+ .name = "one-shot-timer",
+ .activate = timer_trig_activate_one_shot,
+ .deactivate = timer_trig_deactivate,
+};
+
static int __init timer_trig_init(void)
{
- return led_trigger_register(&timer_led_trigger);
+ int rc = 0;
+
+ rc = led_trigger_register(&timer_led_trigger);
+ if (!rc)
+ rc = led_trigger_register(&one_shot_timer_led_trigger);
+
+ return rc;
}

static void __exit timer_trig_exit(void)
{
led_trigger_unregister(&timer_led_trigger);
+ led_trigger_unregister(&one_shot_timer_led_trigger);
}

module_init(timer_trig_init);
--
1.7.5.4



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/