To:Richard-san
CC:all
I wrote LED Blink Trigger. Pleas apply if there is no problem.
This allows LEDs to be controlled by a programmable timer.
"blink" blinks LED at a constant cycle.
"bitshift" turns LED or Buzzer on and off by the value of pattern.
Kernel version: linux-2.6.21-rc4
Signed-off-by: kogiidena <[email protected]>
---
diff -urpN OLD/drivers/leds/Kconfig NEW/drivers/leds/Kconfig
--- OLD/drivers/leds/Kconfig 2007-03-27 18:30:44.000000000 +0900
+++ NEW/drivers/leds/Kconfig 2007-03-27 18:52:42.000000000 +0900
@@ -134,5 +134,14 @@ config LEDS_TRIGGER_HEARTBEAT
load average.
If unsure, say Y.
+config LEDS_TRIGGER_BLINK
+ tristate "LED Blink Trigger"
+ depends on LEDS_TRIGGERS
+ help
+ This allows LEDs to be controlled by a programmable timer.
+ "blink" blinks LED at a constant cycle.
+ "bitshift" turns LED on and off by the value of pattern.
+ If unsure, say Y.
+
endmenu
diff -urpN OLD/drivers/leds/Makefile NEW/drivers/leds/Makefile
--- OLD/drivers/leds/Makefile 2007-03-27 18:27:18.000000000 +0900
+++ NEW/drivers/leds/Makefile 2007-03-27 18:36:02.000000000 +0900
@@ -22,3 +22,4 @@ obj-$(CONFIG_LEDS_LANDISK) += leds-land
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
+obj-$(CONFIG_LEDS_TRIGGER_BLINK) += ledtrig-blink.o
diff -urpN OLD/drivers/leds/ledtrig-blink.c NEW/drivers/leds/ledtrig-blink.c
--- OLD/drivers/leds/ledtrig-blink.c 1970-01-01 09:00:00.000000000 +0900
+++ NEW/drivers/leds/ledtrig-blink.c 2007-03-27 18:16:55.000000000 +0900
@@ -0,0 +1,235 @@
+/*
+ * LED Blink Trigger
+ *
+ * Copyright (C) 2007 kogiidena
+ *
+ * Based on drivers/leds/ledtrig-heartbeat.c by:
+ * Copyright (C) 2006 Atsushi Nemoto <[email protected]>
+ *
+ * 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/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/leds.h>
+#include <linux/device.h>
+#include <linux/ctype.h>
+#include "leds.h"
+
+struct blink_trig_data {
+ unsigned int mode;
+ signed int phase;
+ unsigned long interval;
+ struct timer_list timer;
+};
+
+static void led_blink_function(unsigned long data)
+{
+ struct led_classdev *led_cdev = (struct led_classdev *)data;
+ struct blink_trig_data *blink_data = led_cdev->trigger_data;
+ unsigned long delay = blink_data->interval;
+
+ led_set_brightness(led_cdev,
+ blink_data->phase & 0x1 ? LED_FULL : LED_OFF);
+
+ if ((blink_data->mode != 0) ||
+ ((blink_data->phase != 0) && (blink_data->phase != 0xffffffff))) {
+ mod_timer(&blink_data->timer,
+ jiffies + msecs_to_jiffies(delay));
+ }
+ if (blink_data->mode != 0)
+ blink_data->phase++;
+ else
+ blink_data->phase >>= 1;
+}
+
+static ssize_t led_interval_show(struct class_device *dev, char *buf)
+{
+ struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct blink_trig_data *blink_data = led_cdev->trigger_data;
+
+ sprintf(buf, "%lu\n", blink_data->interval);
+
+ return strlen(buf) + 1;
+}
+
+static ssize_t led_interval_store(struct class_device *dev, const char *buf,
+ size_t size)
+{
+ struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct blink_trig_data *blink_data = led_cdev->trigger_data;
+ int ret = -EINVAL;
+ char *after;
+ unsigned long state = simple_strtoul(buf, &after, 10);
+ size_t count = after - buf;
+
+ if (*after && isspace(*after))
+ count++;
+
+ if (count == size) {
+ blink_data->interval = state;
+ mod_timer(&blink_data->timer, jiffies + 1);
+ ret = count;
+ }
+ return ret;
+}
+
+static ssize_t led_pattern_show(struct class_device *dev, char *buf)
+{
+ struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct blink_trig_data *blink_data = led_cdev->trigger_data;
+
+ sprintf(buf, "0x%08x\n", blink_data->phase);
+
+ return strlen(buf) + 1;
+}
+
+static ssize_t led_pattern_store(struct class_device *dev, const char *buf,
+ size_t size)
+{
+ struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct blink_trig_data *blink_data = led_cdev->trigger_data;
+ int ret = -EINVAL;
+ char *after;
+ unsigned long state = simple_strtoul(buf, &after, 16);
+ size_t count = after - buf;
+
+ if (*after && isspace(*after))
+ count++;
+
+ if (count == size) {
+ blink_data->phase = state;
+ mod_timer(&blink_data->timer, jiffies + 1);
+ ret = count;
+ }
+ return ret;
+}
+
+static CLASS_DEVICE_ATTR(interval, 0644, led_interval_show, led_interval_store);
+static CLASS_DEVICE_ATTR(pattern, 0644, led_pattern_show, led_pattern_store);
+
+static void blink_trig_activate(struct led_classdev *led_cdev)
+{
+ struct blink_trig_data *blink_data;
+ int rc;
+
+ blink_data = kzalloc(sizeof(*blink_data), GFP_KERNEL);
+ if (!blink_data)
+ return;
+
+ led_cdev->trigger_data = blink_data;
+
+ blink_data->mode = 1;
+ blink_data->phase = 1;
+ blink_data->interval = 250;
+
+ rc = class_device_create_file(led_cdev->class_dev,
+ &class_device_attr_interval);
+ if (rc)
+ goto err_out;
+
+ setup_timer(&blink_data->timer,
+ led_blink_function, (unsigned long)led_cdev);
+
+ led_blink_function(blink_data->timer.data);
+
+ return;
+
+err_out:
+ led_cdev->trigger_data = NULL;
+ kfree(blink_data);
+}
+
+static void bitshift_trig_activate(struct led_classdev *led_cdev)
+{
+ struct blink_trig_data *blink_data;
+ int rc;
+
+ blink_data = kzalloc(sizeof(*blink_data), GFP_KERNEL);
+ if (!blink_data)
+ return;
+
+ led_cdev->trigger_data = blink_data;
+
+ blink_data->mode = 0;
+ blink_data->phase = 0;
+ blink_data->interval = 250;
+
+ rc = class_device_create_file(led_cdev->class_dev,
+ &class_device_attr_interval);
+ if (rc)
+ goto err_out;
+
+ rc = class_device_create_file(led_cdev->class_dev,
+ &class_device_attr_pattern);
+ if (rc)
+ goto err_out_interval;
+
+ setup_timer(&blink_data->timer,
+ led_blink_function, (unsigned long)led_cdev);
+
+ led_blink_function(blink_data->timer.data);
+
+ return;
+
+err_out_interval:
+ class_device_remove_file(led_cdev->class_dev,
+ &class_device_attr_interval);
+err_out:
+ led_cdev->trigger_data = NULL;
+ kfree(blink_data);
+}
+
+static void blink_trig_deactivate(struct led_classdev *led_cdev)
+{
+ struct blink_trig_data *blink_data = led_cdev->trigger_data;
+
+ if (blink_data) {
+ class_device_remove_file(led_cdev->class_dev,
+ &class_device_attr_interval);
+ if (blink_data->mode == 0) {
+ class_device_remove_file(led_cdev->class_dev,
+ &class_device_attr_pattern);
+ }
+ del_timer_sync(&blink_data->timer);
+ kfree(blink_data);
+ }
+}
+
+static struct led_trigger blink_led_trigger = {
+ .name = "blink",
+ .activate = blink_trig_activate,
+ .deactivate = blink_trig_deactivate,
+};
+
+static struct led_trigger bitshift_led_trigger = {
+ .name = "bitshift",
+ .activate = bitshift_trig_activate,
+ .deactivate = blink_trig_deactivate,
+};
+
+static int __init blink_trig_init(void)
+{
+ led_trigger_register(&blink_led_trigger);
+ led_trigger_register(&bitshift_led_trigger);
+ return 0;
+}
+
+static void __exit blink_trig_exit(void)
+{
+ led_trigger_unregister(&blink_led_trigger);
+ led_trigger_unregister(&bitshift_led_trigger);
+}
+
+module_init(blink_trig_init);
+module_exit(blink_trig_exit);
+
+MODULE_AUTHOR("kogiidena <[email protected]>");
+MODULE_DESCRIPTION("Blink LED trigger");
+MODULE_LICENSE("GPL");
On Tue, 2007-05-08 at 21:27 +0900, kogiidena wrote:
> I wrote LED Blink Trigger. Pleas apply if there is no problem.
>
> This allows LEDs to be controlled by a programmable timer.
> "blink" blinks LED at a constant cycle.
> "bitshift" turns LED or Buzzer on and off by the value of pattern.
>
> Kernel version: linux-2.6.21-rc4
> Signed-off-by: kogiidena <[email protected]>
As far as I can tell, the existing timer trigger can do everything the
blink trigger can (and more besides). The driver looks like it would be
a lot easier to read if it just contained the bitshift trigger. To be
accepted, the bitshift trigger needs more documentation, particularly
the Kconfig entry. Its not clear for example that the bits are just
shifted once and don't repeat. Most people would probably want it to
repeat and with a repeat mode, it might be able to replace the heartbeat
trigger too?
Regards,
Richard
Hi Richard-san
>As far as I can tell, the existing timer trigger can do everything the
>blink trigger can (and more besides).
I want to blink LED in the initial state.
Because that of "the existing timer trigger" was impossible, I made "BLINK".
I thought about another solution.
Can the change that sets an initial value to delay_on and delay_off be added?
The matter of "Bitshift" is reserved until this case is solved.
kogiidena
---
diff -urpN OLD/include/linux/leds.h NEW/include/linux/leds.h
--- OLD/include/linux/leds.h 2007-05-07 12:12:15.000000000 +0900
+++ NEW/include/linux/leds.h 2007-05-09 19:17:01.000000000 +0900
@@ -14,6 +14,7 @@
#include <linux/list.h>
#include <linux/spinlock.h>
+#include <linux/timer.h>
struct device;
struct class_device;
@@ -41,6 +42,7 @@ struct led_classdev {
struct class_device *class_dev;
struct list_head node; /* LED Device list */
char *default_trigger; /* Trigger to use */
+ void *default_trigger_data; /* Trigger to use */
#ifdef CONFIG_LEDS_TRIGGERS
/* Protects the trigger data below */
@@ -110,6 +112,14 @@ extern void ledtrig_ide_activity(void);
#define ledtrig_ide_activity() do {} while(0)
#endif
+#ifdef CONFIG_LEDS_TRIGGER_TIMER
+struct timer_trig_data {
+ unsigned long delay_on; /* milliseconds on */
+ unsigned long delay_off; /* milliseconds off */
+ struct timer_list timer;
+};
+#endif
+
/* For the leds-gpio driver */
struct gpio_led {
const char *name;
diff -urpN OLD/drivers/leds/ledtrig-timer.c NEW/drivers/leds/ledtrig-timer.c
--- OLD/drivers/leds/ledtrig-timer.c 2007-04-28 06:49:26.000000000 +0900
+++ NEW/drivers/leds/ledtrig-timer.c 2007-05-09 19:12:35.000000000 +0900
@@ -24,12 +24,6 @@
#include <linux/leds.h>
#include "leds.h"
-struct timer_trig_data {
- unsigned long delay_on; /* milliseconds on */
- unsigned long delay_off; /* milliseconds off */
- struct timer_list timer;
-};
-
static void led_timer_function(unsigned long data)
{
struct led_classdev *led_cdev = (struct led_classdev *) data;
@@ -124,6 +118,7 @@ static CLASS_DEVICE_ATTR(delay_off, 0644
static void timer_trig_activate(struct led_classdev *led_cdev)
{
struct timer_trig_data *timer_data;
+ struct timer_trig_data *def_trig_data = led_cdev->default_trigger_data;
int rc;
timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL);
@@ -143,6 +138,11 @@ static void timer_trig_activate(struct l
&class_device_attr_delay_off);
if (rc) goto err_out_delayon;
+ if (def_trig_data){
+ timer_data->delay_on = def_trig_data->delay_on;
+ timer_data->delay_off = def_trig_data->delay_off;
+ mod_timer(&timer_data->timer, jiffies + 1);
+ }
return;
err_out_delayon:
On Wed, 2007-05-09 at 20:42 +0900, kogiidena wrote:
> >As far as I can tell, the existing timer trigger can do everything the
> >blink trigger can (and more besides).
> I want to blink LED in the initial state.
Are you after to set that per LED or would some standard configurable
default for all LEDs work?
> Because that of "the existing timer trigger" was impossible, I made "BLINK".
>
> I thought about another solution.
> Can the change that sets an initial value to delay_on and delay_off be added?
That would be the preferred solution.
> The matter of "Bitshift" is reserved until this case is solved.
>
> kogiidena
> ---
> diff -urpN OLD/include/linux/leds.h NEW/include/linux/leds.h
> --- OLD/include/linux/leds.h 2007-05-07 12:12:15.000000000 +0900
> +++ NEW/include/linux/leds.h 2007-05-09 19:17:01.000000000 +0900
> @@ -14,6 +14,7 @@
>
> #include <linux/list.h>
> #include <linux/spinlock.h>
> +#include <linux/timer.h>
>
> struct device;
> struct class_device;
> @@ -41,6 +42,7 @@ struct led_classdev {
> struct class_device *class_dev;
> struct list_head node; /* LED Device list */
> char *default_trigger; /* Trigger to use */
> + void *default_trigger_data; /* Trigger to use */
>
> #ifdef CONFIG_LEDS_TRIGGERS
> /* Protects the trigger data below */
> @@ -110,6 +112,14 @@ extern void ledtrig_ide_activity(void);
> #define ledtrig_ide_activity() do {} while(0)
> #endif
>
> +#ifdef CONFIG_LEDS_TRIGGER_TIMER
> +struct timer_trig_data {
> + unsigned long delay_on; /* milliseconds on */
> + unsigned long delay_off; /* milliseconds off */
> + struct timer_list timer;
> +};
> +#endif
> +
> /* For the leds-gpio driver */
> struct gpio_led {
> const char *name;
> diff -urpN OLD/drivers/leds/ledtrig-timer.c NEW/drivers/leds/ledtrig-timer.c
> --- OLD/drivers/leds/ledtrig-timer.c 2007-04-28 06:49:26.000000000 +0900
> +++ NEW/drivers/leds/ledtrig-timer.c 2007-05-09 19:12:35.000000000 +0900
> @@ -24,12 +24,6 @@
> #include <linux/leds.h>
> #include "leds.h"
>
> -struct timer_trig_data {
> - unsigned long delay_on; /* milliseconds on */
> - unsigned long delay_off; /* milliseconds off */
> - struct timer_list timer;
> -};
> -
> static void led_timer_function(unsigned long data)
> {
> struct led_classdev *led_cdev = (struct led_classdev *) data;
> @@ -124,6 +118,7 @@ static CLASS_DEVICE_ATTR(delay_off, 0644
> static void timer_trig_activate(struct led_classdev *led_cdev)
> {
> struct timer_trig_data *timer_data;
> + struct timer_trig_data *def_trig_data = led_cdev->default_trigger_data;
> int rc;
>
> timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL);
> @@ -143,6 +138,11 @@ static void timer_trig_activate(struct l
> &class_device_attr_delay_off);
> if (rc) goto err_out_delayon;
>
> + if (def_trig_data){
> + timer_data->delay_on = def_trig_data->delay_on;
> + timer_data->delay_off = def_trig_data->delay_off;
> + mod_timer(&timer_data->timer, jiffies + 1);
> + }
> return;
>
> err_out_delayon:
The approach is probably a good idea but you'll have to split struct
timer_list timer from the data structure.
Also, if default_trigger wasn't the timer trigger you have a nice oops
waiting to happen.
Regards,
Richard
> On Wed, 2007-05-09 at 20:42 +0900, kogiidena wrote:
>> >As far as I can tell, the existing timer trigger can do everything the
>> >blink trigger can (and more besides).
>> I want to blink LED in the initial state.
>
> Are you after to set that per LED or would some standard configurable
> default for all LEDs work?
I'm sorry.The meaning of the question cannot be understood.
My LED is use in the following.
I want to blink LED while booting it.
When boot ends, LED is turned on.
> The approach is probably a good idea but you'll have to split struct
> timer_list timer from the data structure.
>
> Also, if default_trigger wasn't the timer trigger you have a nice oops
> waiting to happen.
I'm sorry that it is not possible to understand enough.
Please teach concretely.
I think that I become more convenient if the argument can be given to "default_trigger" for "all trigger".
kogiidena
-------------------------------
Use example -- part of leds-landisk.c
-------------------------------
static struct timer_trig_data default_timer_trig_data = {
.delay_on = 250,
.delay_off = 250,
};
static struct led_classdev landisk_leds[] = {
[0] = {
.name = "power",
.brightness_set = landisk_led_set,
.default_trigger = "timer",
.default_trigger_data = &default_timer_trig_data,
},
[1] = {
.name = "status",
.brightness_set = landisk_led_set,
.default_trigger = "timer",
.default_trigger_data = &default_timer_trig_data,
},
[2] = {
On Wed, 2007-05-09 at 22:45 +0900, kogiidena wrote:
> > On Wed, 2007-05-09 at 20:42 +0900, kogiidena wrote:
> >> >As far as I can tell, the existing timer trigger can do everything the
> >> >blink trigger can (and more besides).
> >> I want to blink LED in the initial state.
> >
> > Are you after to set that per LED or would some standard configurable
> > default for all LEDs work?
> I'm sorry.The meaning of the question cannot be understood.
> My LED is use in the following.
> I want to blink LED while booting it.
> When boot ends, LED is turned on.
Your device has more than one LED. Do you need to be able to configure
each LED individually or can they all have the same default settings?
> > The approach is probably a good idea but you'll have to split struct
> > timer_list timer from the data structure.
"struct timer_list timer" in "struct timer_trig_data" is unused when its
used for a default_trigger_data which is wasted space.
> > Also, if default_trigger wasn't the timer trigger you have a nice oops
> > waiting to happen.
> I'm sorry that it is not possible to understand enough.
> Please teach concretely.
You don't check default_trigger == "timer" before using
default_trigger_data.
Imagine we have:
struct led_classdev landisk_leds = {
.name = "power",
.default_trigger = "bitshift",
.default_trigger_data =&default_bitshift_trig_data,
};
where:
struct bitshift_trig_data {
unsigned long single_variable;
};
If you then:
echo "timer" > /sys/class/leds/power/trigger
your patch will use random data and possibly oops.
Regards,
Richard
> Your device has more than one LED. Do you need to be able to configure
> each LED individually or can they all have the same default settings?
Yes. It need to be able to configure each LED individually as following.
this patch supports different two hardware.
LANDISK:
LANDISK have two LED.
power-led = blink.
status-led = hard.
USL-5P:
USK-5P have 7 LED and one BUZZER.
power-led = blink.
status-led = blink.
led1 = none.
led2 = none.
led3 = none.
led4 = none.
led5 = none.
buzzer = bitshift.
>> > The approach is probably a good idea but you'll have to split struct
>> > timer_list timer from the data structure.
>
> "struct timer_list timer" in "struct timer_trig_data" is unused when its
> used for a default_trigger_data which is wasted space.
>
>> > Also, if default_trigger wasn't the timer trigger you have a nice oops
>> > waiting to happen.
>> I'm sorry that it is not possible to understand enough.
>> Please teach concretely.
>
> You don't check default_trigger == "timer" before using
> default_trigger_data.
>
> Imagine we have:
>
> struct led_classdev landisk_leds = {
> .name = "power",
> .default_trigger = "bitshift",
> .default_trigger_data =&default_bitshift_trig_data,
> };
>
> where:
>
> struct bitshift_trig_data {
> unsigned long single_variable;
> };
>
> If you then:
>
> echo "timer" > /sys/class/leds/power/trigger
>
> your patch will use random data and possibly oops.
Thank you for explaining.
I understood the problem.
However, a complete solution is not hit on.
I think that it is the easiest solution to define the new trigger "Blink", and to use it.
kogiidena
Richard-san
Please apply
>As far as I can tell, the existing timer trigger can do everything the
>blink trigger can (and more besides). The driver looks like it would be
>a lot easier to read if it just contained the bitshift trigger. To be
>accepted, the bitshift trigger needs more documentation, particularly
>the Kconfig entry. Its not clear for example that the bits are just
>shifted once and don't repeat. Most people would probably want it to
>repeat and with a repeat mode, it might be able to replace the heartbeat
>trigger too?
Add Bitpattern Trigger.
Bitpattern continuously turns LED on and off according to
the value directed "bitdata". "bitdata" is composed of
the character string that consists of the following three
characters. '0' turn off LED. '1' turn on LED. 'R' is
repeated from the head of the "bitdata".
In addition, the character string of "on", "off", and "blink"
can be set to "bitdata".
The transition time of "bitdata" is set by "delay".
Signed-off-by: kogiidena <[email protected]>
---
diff -urpN OLD/drivers/leds/Kconfig NEW/drivers/leds/Kconfig
--- OLD/drivers/leds/Kconfig 2007-04-28 06:49:26.000000000 +0900
+++ NEW/drivers/leds/Kconfig 2007-05-11 21:15:28.000000000 +0900
@@ -127,5 +133,19 @@ config LEDS_TRIGGER_HEARTBEAT
load average.
If unsure, say Y.
+config LEDS_TRIGGER_BITPAT
+ tristate "LED Bitpattern Trigger"
+ depends on LEDS_TRIGGERS
+ help
+ Bitpattern continuously turns LED on and off according to
+ the value directed "bitdata". "bitdata" is composed of
+ the character string that consists of the following three
+ characters. '0' turn off LED. '1' turn on LED. 'R' is
+ repeated from the head of the "bitdata".
+ In addition, the character string of "on", "off", and "blink"
+ can be set to "bitdata".
+ The transition time of "bitdata" is set by "delay".
+ If unsure, say Y.
+
endmenu
diff -urpN OLD/drivers/leds/Makefile NEW/drivers/leds/Makefile
--- OLD/drivers/leds/Makefile 2007-05-11 23:44:12.000000000 +0900
+++ NEW/drivers/leds/Makefile 2007-05-11 23:46:47.000000000 +0900
@@ -22,3 +22,4 @@ obj-$(CONFIG_LEDS_LANDISK) += leds-land
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
+obj-$(CONFIG_LEDS_TRIGGER_BITPAT) += ledtrig-bitpat.o
diff -urpN OLD/drivers/leds/ledtrig-bitpat.c NEW/drivers/leds/ledtrig-bitpat.c
--- OLD/drivers/leds/ledtrig-bitpat.c 1970-01-01 09:00:00.000000000 +0900
+++ NEW/drivers/leds/ledtrig-bitpat.c 2007-05-11 23:16:12.000000000 +0900
@@ -0,0 +1,229 @@
+/*
+ * LED Bitpattern Trigger
+ *
+ * Copyright (C) 2007 kogiidena
+ *
+ * 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/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/leds.h>
+#include <linux/device.h>
+#include <linux/ctype.h>
+#include "leds.h"
+
+#define BITDATA_LEN 17
+
+struct bitpat_trig_data {
+ char bitdata[BITDATA_LEN + 2];
+ int cnt;
+ unsigned long delay;
+ struct timer_list timer;
+};
+
+void __attribute__ ((weak))
+ledtrig_bitpat_default(struct led_classdev *led_cdev,
+ unsigned long *delay, char *bitdata)
+{
+ /* initial value */
+ *delay = 250;
+ bitdata[0] = '\0';
+}
+
+static void led_bitpat_function(unsigned long data)
+{
+ struct led_classdev *led_cdev = (struct led_classdev *)data;
+ struct bitpat_trig_data *bitpat_data = led_cdev->trigger_data;
+ unsigned long delay = bitpat_data->delay;
+ char bitpat;
+
+ bitpat = bitpat_data->bitdata[bitpat_data->cnt++];
+
+ if (bitpat == 'R') {
+ bitpat_data->cnt = 0;
+ bitpat = bitpat_data->bitdata[bitpat_data->cnt++];
+ }
+
+ if (bitpat == '0' || bitpat == '1') {
+ led_set_brightness(led_cdev,
+ (bitpat == '1') ? LED_FULL : LED_OFF);
+
+ mod_timer(&bitpat_data->timer,
+ jiffies + msecs_to_jiffies(delay));
+ } else {
+ bitpat_data->cnt = 0;
+ }
+}
+
+static ssize_t led_delay_show(struct class_device *dev, char *buf)
+{
+ struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct bitpat_trig_data *bitpat_data = led_cdev->trigger_data;
+
+ sprintf(buf, "%lu\n", bitpat_data->delay);
+
+ return strlen(buf) + 1;
+}
+
+static ssize_t led_delay_store(struct class_device *dev, const char *buf,
+ size_t size)
+{
+ struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct bitpat_trig_data *bitpat_data = led_cdev->trigger_data;
+ int ret = -EINVAL;
+ char *after;
+ unsigned long state = simple_strtoul(buf, &after, 10);
+ size_t count = after - buf;
+
+ if (*after && isspace(*after))
+ count++;
+
+ if (count == size) {
+ bitpat_data->delay = state;
+ mod_timer(&bitpat_data->timer, jiffies + 1);
+ ret = count;
+ }
+ return ret;
+}
+
+static void led_bitdata_check(char *buf)
+{
+ int i;
+
+ if (!strncmp("on", buf, 2)) {
+ buf[0] = '1';
+ } else if (!strncmp("off", buf, 2)) {
+ buf[0] = '0';
+ } else if (!strncmp("blink", buf, 5)) {
+ strcpy(buf, "01R");
+ }
+
+ for (i = 0; i < BITDATA_LEN; i++) {
+ if ((buf[i] == '0') || (buf[i] == '1')) {
+ continue;
+ } else if ((i != 0) && ((buf[i] == 'R') || (buf[i] == 'r'))) {
+ buf[i] = 'R';
+ i++;
+ }
+ break;
+ }
+ buf[i] = '\0';
+}
+
+static ssize_t led_bitdata_show(struct class_device *dev, char *buf)
+{
+ struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct bitpat_trig_data *bitpat_data = led_cdev->trigger_data;
+
+ sprintf(buf,
+ "bitdata : %s\n"
+ "meaning : 0=OFF, 1=ON, R=Repeat\n",
+ (bitpat_data->bitdata[0]) ? bitpat_data->bitdata : "(null)");
+
+ return strlen(buf) + 1;
+}
+
+static ssize_t led_bitdata_store(struct class_device *dev, const char *buf,
+ size_t size)
+{
+ struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct bitpat_trig_data *bitpat_data = led_cdev->trigger_data;
+
+ if (size > BITDATA_LEN)
+ return -EINVAL;
+
+ strncpy(bitpat_data->bitdata, buf, size);
+ led_bitdata_check(bitpat_data->bitdata);
+ bitpat_data->cnt = 0;
+
+ mod_timer(&bitpat_data->timer, jiffies + 1);
+
+ return size;
+}
+
+static CLASS_DEVICE_ATTR(delay, 0644, led_delay_show, led_delay_store);
+static CLASS_DEVICE_ATTR(bitdata, 0644, led_bitdata_show, led_bitdata_store);
+
+static void bitpat_trig_activate(struct led_classdev *led_cdev)
+{
+ struct bitpat_trig_data *bitpat_data;
+ int rc;
+
+ bitpat_data = kzalloc(sizeof(*bitpat_data), GFP_KERNEL);
+ if (!bitpat_data)
+ return;
+
+ led_cdev->trigger_data = bitpat_data;
+
+ ledtrig_bitpat_default(led_cdev,
+ &bitpat_data->delay, &bitpat_data->bitdata[0]);
+ led_bitdata_check(bitpat_data->bitdata);
+ bitpat_data->cnt = 0;
+
+ rc = class_device_create_file(led_cdev->class_dev,
+ &class_device_attr_delay);
+ if (rc)
+ goto err_out;
+
+ rc = class_device_create_file(led_cdev->class_dev,
+ &class_device_attr_bitdata);
+ if (rc)
+ goto err_out_delay;
+
+ setup_timer(&bitpat_data->timer,
+ led_bitpat_function, (unsigned long)led_cdev);
+ led_bitpat_function(bitpat_data->timer.data);
+
+ return;
+
+err_out_delay:
+ class_device_remove_file(led_cdev->class_dev, &class_device_attr_delay);
+err_out:
+ led_cdev->trigger_data = NULL;
+ kfree(bitpat_data);
+}
+
+static void bitpat_trig_deactivate(struct led_classdev *led_cdev)
+{
+ struct bitpat_trig_data *bitpat_data = led_cdev->trigger_data;
+
+ if (bitpat_data) {
+ class_device_remove_file(led_cdev->class_dev,
+ &class_device_attr_delay);
+ class_device_remove_file(led_cdev->class_dev,
+ &class_device_attr_bitdata);
+ del_timer_sync(&bitpat_data->timer);
+ kfree(bitpat_data);
+ }
+}
+
+static struct led_trigger bitpat_led_trigger = {
+ .name = "bitpat",
+ .activate = bitpat_trig_activate,
+ .deactivate = bitpat_trig_deactivate,
+};
+
+static int __init bitpat_trig_init(void)
+{
+ led_trigger_register(&bitpat_led_trigger);
+ return 0;
+}
+
+static void __exit bitpat_trig_exit(void)
+{
+ led_trigger_unregister(&bitpat_led_trigger);
+}
+
+module_init(bitpat_trig_init);
+module_exit(bitpat_trig_exit);
+
+MODULE_AUTHOR("kogiidena <[email protected]>");
+MODULE_DESCRIPTION("Bitpattern LED trigger");
+MODULE_LICENSE("GPL");
To: Richard-san
I'm sorry. The patch sent yesterday is corrected, too.
Because the source had not been read easily, it cleaned it.
There is no change for the basic function.
Add Bitpattern Trigger.
Bitpattern continuously turns LED on and off according to
the value directed "bitdata". "bitdata" is composed of
the character string that consists of the following three
characters. '0' turn off LED. '1' turn on LED. 'R' is
repeated from the head of the "bitdata".
In addition, the character string of "on", "off", and "blink"
can be set to "bitdata".
The transition time of "bitdata" is set by "delay".
Signed-off-by: kogiidena <[email protected]>
---
diff -urpN OLD/drivers/leds/Kconfig NEW/drivers/leds/Kconfig
--- OLD/drivers/leds/Kconfig 2007-04-28 06:49:26.000000000 +0900
+++ NEW/drivers/leds/Kconfig 2007-05-11 21:15:28.000000000 +0900
@@ -127,5 +133,19 @@ config LEDS_TRIGGER_HEARTBEAT
load average.
If unsure, say Y.
+config LEDS_TRIGGER_BITPAT
+ tristate "LED Bitpattern Trigger"
+ depends on LEDS_TRIGGERS
+ help
+ Bitpattern continuously turns LED on and off according to
+ the value directed "bitdata". "bitdata" is composed of
+ the character string that consists of the following three
+ characters. '0' turn off LED. '1' turn on LED. 'R' is
+ repeated from the head of the "bitdata".
+ In addition, the character string of "on", "off", and "blink"
+ can be set to "bitdata".
+ The transition time of "bitdata" is set by "delay".
+ If unsure, say Y.
+
endmenu
diff -urpN OLD/drivers/leds/Makefile NEW/drivers/leds/Makefile
--- OLD/drivers/leds/Makefile 2007-05-11 23:44:12.000000000 +0900
+++ NEW/drivers/leds/Makefile 2007-05-11 23:46:47.000000000 +0900
@@ -22,3 +22,4 @@ obj-$(CONFIG_LEDS_LANDISK) += leds-land
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
+obj-$(CONFIG_LEDS_TRIGGER_BITPAT) += ledtrig-bitpat.o
diff -urpN OLD/drivers/leds/ledtrig-bitpat.c NEW/drivers/leds/ledtrig-bitpat.c
--- OLD/drivers/leds/ledtrig-bitpat.c 1970-01-01 09:00:00.000000000 +0900
+++ NEW/drivers/leds/ledtrig-bitpat.c 2007-05-12 11:29:34.000000000 +0900
@@ -0,0 +1,231 @@
+/*
+ * LED Bitpattern Trigger
+ *
+ * Copyright (C) 2007 kogiidena
+ *
+ * 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/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/leds.h>
+#include <linux/device.h>
+#include <linux/ctype.h>
+#include "leds.h"
+
+#define BITDATA_LEN 18
+
+struct bitpat_trig_data {
+ char bitdata[BITDATA_LEN + 2];
+ int cnt;
+ unsigned long delay;
+ struct timer_list timer;
+};
+
+void __attribute__ ((weak))
+ledtrig_bitpat_default(struct led_classdev *led_cdev,
+ unsigned long *delay, char *bitdata)
+{
+ /* Nothing to do. */
+}
+
+static void led_bitpat_function(unsigned long data)
+{
+ struct led_classdev *led_cdev = (struct led_classdev *)data;
+ struct bitpat_trig_data *bitpat_data = led_cdev->trigger_data;
+ unsigned long delay = bitpat_data->delay;
+ char bitpat;
+
+ bitpat = bitpat_data->bitdata[bitpat_data->cnt++];
+
+ if (bitpat == '0' || bitpat == '1') {
+ led_set_brightness(led_cdev,
+ (bitpat == '1') ? LED_FULL : LED_OFF);
+ } else {
+ bitpat_data->cnt = 0;
+ return;
+ }
+
+ if (bitpat_data->bitdata[bitpat_data->cnt] == 'R')
+ bitpat_data->cnt = 0;
+
+ mod_timer(&bitpat_data->timer, jiffies + msecs_to_jiffies(delay));
+}
+
+static ssize_t led_delay_show(struct class_device *dev, char *buf)
+{
+ struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct bitpat_trig_data *bitpat_data = led_cdev->trigger_data;
+
+ sprintf(buf, "%lu\n", bitpat_data->delay);
+
+ return strlen(buf) + 1;
+}
+
+static ssize_t led_delay_store(struct class_device *dev, const char *buf,
+ size_t size)
+{
+ struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct bitpat_trig_data *bitpat_data = led_cdev->trigger_data;
+ int ret = -EINVAL;
+ char *after;
+ unsigned long state = simple_strtoul(buf, &after, 10);
+ size_t count = after - buf;
+
+ if (*after && isspace(*after))
+ count++;
+
+ if (count == size) {
+ bitpat_data->delay = state;
+ mod_timer(&bitpat_data->timer, jiffies + 1);
+ ret = count;
+ }
+ return ret;
+}
+
+static void led_bitdata_update(struct bitpat_trig_data *bitpat_data,
+ const char *buf)
+{
+ int i;
+ const char *s;
+
+ if (!strncmp("on", buf, 2)) {
+ s = "1";
+ } else if (!strncmp("off", buf, 2)) {
+ s = "0";
+ } else if (!strncmp("blink", buf, 5)) {
+ s = "01R";
+ } else {
+ s = buf;
+ }
+
+ for (i = 0; i < BITDATA_LEN; i++) {
+ if ((s[i] == '0') || (s[i] == '1')) {
+ bitpat_data->bitdata[i] = s[i];
+ } else if ((i != 0) && ((s[i] == 'R') || (s[i] == 'r'))) {
+ bitpat_data->bitdata[i] = 'R';
+ bitpat_data->bitdata[i + 1] = '\0';
+ break;
+ } else {
+ bitpat_data->bitdata[i] = '\0';
+ break;
+ }
+ }
+ bitpat_data->cnt = 0;
+}
+
+static ssize_t led_bitdata_show(struct class_device *dev, char *buf)
+{
+ struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct bitpat_trig_data *bitpat_data = led_cdev->trigger_data;
+
+ sprintf(buf,
+ "bitdata : %s\n"
+ "meaning : 0=OFF, 1=ON, R=Repeat\n",
+ (bitpat_data->bitdata[0]) ? bitpat_data->bitdata : "(null)");
+
+ return strlen(buf) + 1;
+}
+
+static ssize_t led_bitdata_store(struct class_device *dev, const char *buf,
+ size_t size)
+{
+ struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct bitpat_trig_data *bitpat_data = led_cdev->trigger_data;
+
+ if (size > BITDATA_LEN)
+ return -EINVAL;
+
+ led_bitdata_update(bitpat_data, buf);
+ mod_timer(&bitpat_data->timer, jiffies + 1);
+
+ return size;
+}
+
+static CLASS_DEVICE_ATTR(delay, 0644, led_delay_show, led_delay_store);
+static CLASS_DEVICE_ATTR(bitdata, 0644, led_bitdata_show, led_bitdata_store);
+
+static void bitpat_trig_activate(struct led_classdev *led_cdev)
+{
+ struct bitpat_trig_data *bitpat_data;
+ int rc;
+
+ bitpat_data = kzalloc(sizeof(*bitpat_data), GFP_KERNEL);
+ if (!bitpat_data)
+ return;
+
+ led_cdev->trigger_data = bitpat_data;
+
+ /* initial value */
+ bitpat_data->delay = 500;
+ bitpat_data->bitdata[0] = '\0';
+
+ ledtrig_bitpat_default(led_cdev,
+ &bitpat_data->delay, &bitpat_data->bitdata[0]);
+ led_bitdata_update(bitpat_data, bitpat_data->bitdata);
+
+ rc = class_device_create_file(led_cdev->class_dev,
+ &class_device_attr_delay);
+ if (rc)
+ goto err_out;
+ rc = class_device_create_file(led_cdev->class_dev,
+ &class_device_attr_bitdata);
+ if (rc)
+ goto err_out_delay;
+
+ setup_timer(&bitpat_data->timer,
+ led_bitpat_function, (unsigned long)led_cdev);
+ led_bitpat_function(bitpat_data->timer.data);
+
+ return;
+
+err_out_delay:
+ class_device_remove_file(led_cdev->class_dev, &class_device_attr_delay);
+err_out:
+ led_cdev->trigger_data = NULL;
+ kfree(bitpat_data);
+}
+
+static void bitpat_trig_deactivate(struct led_classdev *led_cdev)
+{
+ struct bitpat_trig_data *bitpat_data = led_cdev->trigger_data;
+
+ if (bitpat_data) {
+ class_device_remove_file(led_cdev->class_dev,
+ &class_device_attr_delay);
+ class_device_remove_file(led_cdev->class_dev,
+ &class_device_attr_bitdata);
+ del_timer_sync(&bitpat_data->timer);
+ kfree(bitpat_data);
+ }
+}
+
+static struct led_trigger bitpat_led_trigger = {
+ .name = "bitpat",
+ .activate = bitpat_trig_activate,
+ .deactivate = bitpat_trig_deactivate,
+};
+
+static int __init bitpat_trig_init(void)
+{
+ led_trigger_register(&bitpat_led_trigger);
+ return 0;
+}
+
+static void __exit bitpat_trig_exit(void)
+{
+ led_trigger_unregister(&bitpat_led_trigger);
+}
+
+module_init(bitpat_trig_init);
+module_exit(bitpat_trig_exit);
+
+MODULE_AUTHOR("kogiidena <[email protected]>");
+MODULE_DESCRIPTION("Bitpattern LED trigger");
+MODULE_LICENSE("GPL");