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 --- 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 +#include #include #include #include @@ -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);