summaryrefslogtreecommitdiff
path: root/packages/linux/ixp4xx-kernel/2.6.15/950-leds-timer.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/ixp4xx-kernel/2.6.15/950-leds-timer.patch')
-rw-r--r--packages/linux/ixp4xx-kernel/2.6.15/950-leds-timer.patch151
1 files changed, 151 insertions, 0 deletions
diff --git a/packages/linux/ixp4xx-kernel/2.6.15/950-leds-timer.patch b/packages/linux/ixp4xx-kernel/2.6.15/950-leds-timer.patch
new file mode 100644
index 0000000000..c44ef62ee7
--- /dev/null
+++ b/packages/linux/ixp4xx-kernel/2.6.15/950-leds-timer.patch
@@ -0,0 +1,151 @@
+Fix for a bug in led-triggers.c plus an update to the
+timer trigger code to allow for fractional frequency
+values and to correct the evaluation of frequency so
+that it is the actual frequency.
+
+Signed-off-by: John Bowler <jbowler@acm.org>
+
+--- linux-2.6.15/drivers/leds/led-triggers.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/leds/led-triggers.c 1970-01-01 00:00:00.000000000 +0000
+@@ -98,7 +98,7 @@ void led_trigger_event(struct led_trigge
+ if (!trigger)
+ return;
+
+- read_lock(&trigger->led_devs);
++ read_lock(&trigger->leddev_list_lock);
+ list_for_each(entry, &trigger->led_devs) {
+ struct led_device *led_dev;
+
+@@ -107,7 +107,7 @@ void led_trigger_event(struct led_trigge
+ led_set_brightness(led_dev, brightness);
+ write_unlock(&led_dev->lock);
+ }
+- read_unlock(&trigger->led_devs);
++ read_unlock(&trigger->leddev_list_lock);
+ }
+
+ /* Caller must ensure led_dev->lock held for write */
+--- linux-2.6.15/drivers/leds/ledtrig-timer.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/leds/ledtrig-timer.c 1970-01-01 00:00:00.000000000 +0000
+@@ -12,6 +12,7 @@
+ */
+
+ #include <linux/config.h>
++#include <linux/ctype.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+@@ -61,21 +62,19 @@ static void led_timer_function(unsigned
+ static void led_timer_setdata(struct led_device *led_dev, unsigned long duty, unsigned long frequency)
+ {
+ struct timer_trig_data *timer_data = led_dev->trigger_data;
+- signed long duty1;
+-
+- if (frequency > 500)
+- frequency = 500;
+
+ if (duty > 100)
+ duty = 100;
+
+- duty1 = duty - 50;
+-
+ timer_data->duty = duty;
+ timer_data->frequency = frequency;
+ if (frequency != 0) {
+- timer_data->delay_on = (50 - duty1) * 1000 / 50 / frequency;
+- timer_data->delay_off = (50 + duty1) * 1000 / 50 / frequency;
++ timer_data->delay_on = duty * 10000U / frequency;
++ if (timer_data->delay_on == 0)
++ timer_data->delay_on = 1;
++ timer_data->delay_off = (100U-duty) * 10000U / frequency;
++ if (timer_data->delay_off == 0)
++ timer_data->delay_off = 1;
+ }
+
+ mod_timer(&timer_data->timer, jiffies);
+@@ -100,8 +99,8 @@ static ssize_t led_duty_store(struct cla
+ struct timer_trig_data *timer_data;
+ int ret = -EINVAL;
+ char *after;
+-
+ unsigned long state = simple_strtoul(buf, &after, 10);
++
+ if (after - buf > 0) {
+ ret = after - buf;
+ write_lock(&led_dev->lock);
+@@ -118,32 +117,63 @@ static ssize_t led_frequency_show(struct
+ {
+ struct led_device *led_dev = dev->class_data;
+ struct timer_trig_data *timer_data;
++ unsigned long freq000;
+
+ read_lock(&led_dev->lock);
+ timer_data = led_dev->trigger_data;
+- sprintf(buf, "%lu\n", timer_data->frequency);
++ freq000 = timer_data->frequency;
+ read_unlock(&led_dev->lock);
+
++ if (freq000 % 1000)
++ sprintf(buf, "%lu.%.3lu\n", freq000 / 1000, freq000 % 1000);
++ else
++ sprintf(buf, "%lu\n", freq000 / 1000);
++
+ return strlen(buf) + 1;
+ }
+
+ static ssize_t led_frequency_store(struct class_device *dev, const char *buf, size_t size)
+ {
+ struct led_device *led_dev = dev->class_data;
+- struct timer_trig_data *timer_data;
+- int ret = -EINVAL;
+- char *after;
++ size_t rc = 0;
++ unsigned long freq000 = 0;
++ int have_digit = 0;
++
++ while (rc < size && isspace(buf[rc]))
++ ++rc;
++ if (rc >= size)
++ return rc;
++
++ /* number before decimal point */
++ while (rc < size && isdigit(buf[rc]))
++ freq000 *= 10, freq000 += buf[rc++] - '0', have_digit = 1;
++
++ if (rc < size && (buf[rc] == '.' || buf[rc] == ',')) {
++ int dp = 0;
++ ++rc;
++ while (rc < size && isdigit(buf[rc])) {
++ if (++dp <= 3)
++ freq000 *= 10, freq000 += buf[rc] - '0';
++ ++rc;
++ have_digit = 1;
++ }
++ while (++dp <= 3)
++ freq000 *= 10;
++ } else
++ freq000 *= 1000;
+
+- unsigned long state = simple_strtoul(buf, &after, 10);
+- if (after - buf > 0) {
+- ret = after - buf;
+- write_lock(&led_dev->lock);
+- timer_data = led_dev->trigger_data;
+- led_timer_setdata(led_dev, timer_data->duty, state);
+- write_unlock(&led_dev->lock);
++ if (!have_digit)
++ return -EINVAL;
++
++ write_lock(&led_dev->lock);
++ {
++ struct timer_trig_data *timer_data = led_dev->trigger_data;
++ led_timer_setdata(led_dev, timer_data->duty, freq000);
+ }
++ write_unlock(&led_dev->lock);
+
+- return ret;
++
++ return rc;
+ }
+
+ static CLASS_DEVICE_ATTR(duty, 0644, led_duty_show, led_duty_store);