diff options
Diffstat (limited to 'packages/linux/ixp4xx-kernel/2.6.16/950-leds-timer.patch')
-rw-r--r-- | packages/linux/ixp4xx-kernel/2.6.16/950-leds-timer.patch | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/packages/linux/ixp4xx-kernel/2.6.16/950-leds-timer.patch b/packages/linux/ixp4xx-kernel/2.6.16/950-leds-timer.patch new file mode 100644 index 0000000000..c44ef62ee7 --- /dev/null +++ b/packages/linux/ixp4xx-kernel/2.6.16/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); |