linux-omap 2.6.39: initial add with beagleboard support
[openembedded.git] / recipes / linux / linux-rt-2.6.24 / leds-cpu-activity.patch
blob2495b9b3f707fbe0cb3c2972250063852637d5c3
1 Index: linux-2.6.24.3/drivers/leds/Kconfig
2 ===================================================================
3 --- linux-2.6.24.3.orig/drivers/leds/Kconfig 2008-02-29 13:56:08.000000000 +0100
4 +++ linux-2.6.24.3/drivers/leds/Kconfig 2008-02-29 13:56:11.000000000 +0100
5 @@ -130,6 +130,15 @@
6 This allows LEDs to be controlled by a programmable timer
7 via sysfs. If unsure, say Y.
9 +config LEDS_TRIGGER_CPU_ACTIVITY
10 + tristate "LED CPU Activity Trigger"
11 + depends on LEDS_TRIGGERS
12 + help
13 + This allows LEDs to be set to show cpu activity via sysfs.
14 + The LED will blink when the cpu is active and stay steady
15 + (on or off according to the trigger selected) when idle.
16 + Platform support is needed for this to work. If unsure, say Y.
18 config LEDS_TRIGGER_IDE_DISK
19 bool "LED IDE Disk Trigger"
20 depends on LEDS_TRIGGERS && BLK_DEV_IDEDISK
21 Index: linux-2.6.24.3/drivers/leds/ledtrig-cpu.c
22 ===================================================================
23 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
24 +++ linux-2.6.24.3/drivers/leds/ledtrig-cpu.c 2008-02-29 13:56:11.000000000 +0100
25 @@ -0,0 +1,502 @@
26 +/*
27 + * LEDs CPU activity trigger
28 + *
29 + * Author: John Bowler <jbowler@acm.org>
30 + *
31 + * Copyright (c) 2006 John Bowler
32 + *
33 + * Permission is hereby granted, free of charge, to any
34 + * person obtaining a copy of this software and associated
35 + * documentation files (the "Software"), to deal in the
36 + * Software without restriction, including without
37 + * limitation the rights to use, copy, modify, merge,
38 + * publish, distribute, sublicense, and/or sell copies of
39 + * the Software, and to permit persons to whom the
40 + * Software is furnished to do so, subject to the
41 + * following conditions:
42 + *
43 + * The above copyright notice and this permission notice
44 + * shall be included in all copies or substantial portions
45 + * of the Software.
46 + *
47 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
48 + * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
49 + * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
50 + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
51 + * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
52 + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
53 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
55 + * OTHER DEALINGS IN THE SOFTWARE.
56 + *
57 + */
59 +#include <linux/ctype.h>
60 +#include <linux/kernel.h>
61 +#include <linux/module.h>
62 +#include <linux/init.h>
63 +#include <linux/spinlock.h>
64 +#include <linux/timer.h>
65 +#include <linux/device.h>
67 +#include <linux/leds.h>
68 +#include "leds.h"
70 +//#include <linux/list.h>
71 +//#include <linux/sysdev.h>
74 +/*
75 + * To simplify this the LED state is given for each case of
76 + * CPU state - idle or active. The LED can be:
77 + *
78 + * off
79 + * flash - slow for idle, fast (flicker) for active
80 + * on
81 + *
82 + * This gives two useless states - off/off and on/on
83 + */
84 +typedef enum cpu_trigger_led_state {
85 + cpu_led_off,
86 + cpu_led_flash,
87 + cpu_led_on,
88 + cpu_led_invalid
89 +} cpu_trigger_led_state;
91 +static const char *const cpu_trigger_names[] = {
92 + "off",
93 + "flash",
94 + "on",
95 + "invalid"
96 +};
98 +/* Forward declaration - this is called back when an LED property
99 + * is changed.
100 + */
101 +static void leds_cpu_trigger_state_change(void);
104 + * These constants define the actual mark/space of the flashing
105 + * in jiffies. msecs_to_jiffies rounds up and is compile time
106 + * evaluable for constant arguments. Writing the ?: stuff below
107 + * this way ensures the compiler doesn't think it needs to
108 + * compile in the math of msecs_to_jiffies.
110 + * These values have been determined by experiment to work well
111 + * for the ready/status LED on a LinkSys NSLU2 (light piped) and
112 + * for the user LED on a Loft (Gateway Avila variant) board where
113 + * the LED was directly visible. Light Output Varies Everywhere.
114 + */
115 +#define LEDS_CPU_ACTIVE_MARK msecs_to_jiffies(40)
116 +#define LEDS_CPU_IDLE_MARK msecs_to_jiffies(800)
117 +#define LEDS_CPU_ACTIVE_SPACE msecs_to_jiffies(60)
118 +#define LEDS_CPU_IDLE_SPACE msecs_to_jiffies(800)
122 + * Individual LEDs ------------------------------------------------------------
123 + */
124 +struct cpu_trigger_data {
125 + cpu_trigger_led_state active; /* Behaviour when the CPU is active. */
126 + cpu_trigger_led_state idle; /* Behaviour when the CPU is idle. */
130 + * LED state change - called when the state of a single LED might
131 + * have changed. Returns true if the LED is blinking. The argument
132 + * is the blink state - the brightness of the blinking LED.
133 + */
134 +static int leds_cpu_trigger_led_state_change(struct led_classdev *led,
135 + int is_active, enum led_brightness brightness)
137 + int is_blinking = 0;
139 + struct cpu_trigger_data *data = led->trigger_data;
141 + /* Find the new brightness for the LED, if the LED is
142 + * set to flash then the brightness passed in is the
143 + * required value.
144 + */
145 + if (likely(data != 0))
146 + switch (is_active ? data->active : data->idle) {
147 + case cpu_led_off: brightness = LED_OFF; break;
148 + case cpu_led_flash: is_blinking = 1; break;
149 + case cpu_led_on: brightness = LED_FULL; break;
151 + else
152 + brightness = is_active ? LED_FULL : LED_OFF;
154 + led_set_brightness(led, brightness);
156 + return is_blinking;
160 + * sysfs properties, the property is output at an list of the
161 + * values with the current setting enclosed in []
162 + */
163 +static ssize_t leds_cpu_trigger_show_prop(struct device *dev,
164 + struct device_attribute *attr, char *buf, size_t where)
166 + struct led_classdev *led = dev_get_drvdata(dev);
167 + cpu_trigger_led_state item = cpu_led_invalid, i;
168 + char *next;
170 + if (likely(led->trigger_data != 0))
171 + item = *(const cpu_trigger_led_state*)(
172 + led->trigger_data + where);
174 + for (i=0, next=buf; i<cpu_led_invalid; ++i) {
175 + const char *name = cpu_trigger_names[i];
176 + size_t len = strlen(name);
178 + if (i == item)
179 + *next++ = '[';
180 + memcpy(next, name, len);
181 + next += len;
182 + if (i == item)
183 + *next++ = ']';
184 + *next++ = ' ';
187 + next[-1] = '\n';
188 + *next++ = 0;
190 + return next - buf;
193 +static ssize_t leds_cpu_trigger_show_active(struct device *dev,
194 + struct device_attribute *attr, char *buf)
196 + return leds_cpu_trigger_show_prop(dev, attr, buf,
197 + offsetof(struct cpu_trigger_data, active));
200 +static ssize_t leds_cpu_trigger_show_idle(struct device *dev,
201 + struct device_attribute *attr, char *buf)
203 + return leds_cpu_trigger_show_prop(dev, attr, buf,
204 + offsetof(struct cpu_trigger_data, idle));
208 + * Any matching leading substring selects a property - so "onoffonoff"
209 + * sets the property to off.
210 + */
211 +static ssize_t leds_cpu_trigger_store_prop(struct device *dev,
212 + struct device_attribute *attr, const char *buf,
213 + size_t size, size_t where)
215 + size_t rc = 0;
216 + cpu_trigger_led_state value = 0/*sic*/;
217 + struct led_classdev *led;
219 + /* ignore space characters before the value. */
220 + while (rc < size && isspace(buf[rc]))
221 + ++rc;
222 + if (rc >= size)
223 + return rc;
225 + /* look for a simple match against the trigger name, case
226 + * sensitive.
227 + */
228 + do {
229 + const char *name = cpu_trigger_names[value];
230 + size_t len = strlen(name);
231 + if (len <= size && memcmp(buf+rc, name, len) == 0) {
232 + rc = len;
233 + break;
235 + if (++value >= cpu_led_invalid)
236 + return -EINVAL;
237 + } while (1);
239 + led = dev_get_drvdata(dev);
240 + if (likely(led->trigger_data != 0))
241 + *(cpu_trigger_led_state*)(
242 + led->trigger_data + where) = value;
244 + return rc;
247 +static ssize_t leds_cpu_trigger_store_active(struct device *dev,
248 + struct device_attribute *attr, const char *buf, size_t size)
250 + ssize_t rc = leds_cpu_trigger_store_prop(dev, attr, buf, size,
251 + offsetof(struct cpu_trigger_data, active));
252 + /*
253 + * At least one CPU must be active (otherwise who is doing this?)
254 + * Call down into the global state below to cause an update
255 + * to happen now.
256 + */
257 + leds_cpu_trigger_state_change();
258 + return rc;
261 +static ssize_t leds_cpu_trigger_store_idle(struct device *dev,
262 + struct device_attribute *attr, const char *buf, size_t size)
264 + return leds_cpu_trigger_store_prop(dev, attr, buf, size,
265 + offsetof(struct cpu_trigger_data, idle));
268 +static DEVICE_ATTR(active, 0644, leds_cpu_trigger_show_active,
269 + leds_cpu_trigger_store_active);
271 +static DEVICE_ATTR(idle, 0644, leds_cpu_trigger_show_idle,
272 + leds_cpu_trigger_store_idle);
275 + * Activate and deactivate are called on individual LEDs when the
276 + * LED trigger property is changed.
277 + */
278 +static void leds_cpu_trigger_activate(struct led_classdev *led)
280 + /*
281 + * The initial setting of the trigger is simple CPU activity
282 + * with the LED off for idle and on for active. Consequently
283 + * there is no need to mess with the global state initially,
284 + * we know the CPU is active at this moment!
285 + */
286 + int rc;
287 + struct cpu_trigger_data *data = kmalloc(sizeof *data, GFP_KERNEL);
288 + if (unlikely(data == 0))
289 + return;
291 + data->active = cpu_led_on;
292 + data->idle = cpu_led_off;
293 + led->trigger_data = data;
295 + rc = device_create_file(led->dev, &dev_attr_active);
296 + if (rc)
297 + goto err_out;
298 + rc = device_create_file(led->dev, &dev_attr_idle);
299 + if (rc)
300 + goto err_out_active;
302 + led_set_brightness(led, LED_FULL);
303 + return;
305 +err_out_active:
306 + device_remove_file(led->dev, &dev_attr_active);
307 +err_out:
308 + led->trigger_data = NULL;
309 + kfree(data);
312 +static void leds_cpu_trigger_deactivate(struct led_classdev *led)
314 + struct cpu_trigger_data *data = led->trigger_data;
315 + if (likely(data != 0)) {
316 + led_set_brightness(led, LED_OFF);
318 + device_remove_file(led->dev, &dev_attr_idle);
319 + device_remove_file(led->dev, &dev_attr_active);
321 + led->trigger_data = 0;
322 + kfree(data);
328 + * Global state --------------------------------------------------------------
330 + * This is global because the CPU state is global and we only need one timer to
331 + * do this stuff.
332 + */
333 +typedef struct leds_cpu_trigger_data {
334 + struct led_trigger trigger; /* the lock in here protects everything */
335 + struct timer_list timer;
336 + unsigned long last_active_time; /* record of last jiffies */
337 + unsigned long last_idle_time; /* record of last jiffies */
338 + int count_active; /* number of active CPUs */
339 +} leds_cpu_trigger_data;
342 + * Mark state - uses the current time (jiffies) to work out
343 + * whether this is a mark or space.
344 + */
345 +static int leds_cpu_trigger_mark(struct leds_cpu_trigger_data *data,
346 + unsigned long now) {
347 + if (data->count_active > 0) {
348 + unsigned long elapsed = now - data->last_active_time;
349 + elapsed %= LEDS_CPU_ACTIVE_SPACE + LEDS_CPU_ACTIVE_MARK;
350 + data->last_active_time = now - elapsed;
351 + return elapsed > LEDS_CPU_ACTIVE_SPACE;
352 + } else {
353 + unsigned long elapsed = now - data->last_idle_time;
354 + elapsed %= LEDS_CPU_IDLE_SPACE + LEDS_CPU_IDLE_MARK;
355 + data->last_idle_time = now - elapsed;
356 + return elapsed > LEDS_CPU_IDLE_SPACE;
362 + * State change - given information about the nature of the
363 + * (possible) state change call up to each LED to adjust its
364 + * state. Returns true if any LED is blinking. The lock
365 + * must be held (a read lock is adequate).
366 + */
367 +static int leds_cpu_trigger_scan_leds(struct leds_cpu_trigger_data *data,
368 + unsigned long now)
370 + int blinking = 0;
371 + const int active = data->count_active > 0;
372 + const enum led_brightness brightness =
373 + leds_cpu_trigger_mark(data, now) ? LED_FULL : LED_OFF;
374 + struct list_head *entry;
376 + list_for_each(entry, &data->trigger.led_cdevs) {
377 + struct led_classdev *led =
378 + list_entry(entry, struct led_classdev, trig_list);
380 + blinking |= leds_cpu_trigger_led_state_change(led,
381 + active, brightness);
384 + return blinking;
388 + * Set the timer correctly according to the current state, the lock
389 + * must be held for write.
390 + */
391 +static void leds_cpu_trigger_set_timer(struct leds_cpu_trigger_data *state,
392 + unsigned long now)
394 + unsigned long next;
395 + if (state->count_active > 0) {
396 + next = state->last_active_time;
397 + if (now - next > LEDS_CPU_ACTIVE_SPACE)
398 + next += LEDS_CPU_ACTIVE_MARK;
399 + next += LEDS_CPU_ACTIVE_SPACE;
400 + } else {
401 + next = state->last_idle_time;
402 + if (now - next > LEDS_CPU_IDLE_SPACE)
403 + next += LEDS_CPU_IDLE_MARK;
404 + next += LEDS_CPU_IDLE_SPACE;
406 + mod_timer(&state->timer, next);
410 + * The timer callback if the LED is currently flashing, the callback
411 + * calls the state change function and, if that returns true, meaning
412 + * that at least one LED is still blinking, the timer is restarted
413 + * with the correct timeout.
414 + */
415 +static void leds_cpu_trigger_timer_callback(unsigned long data)
417 + struct leds_cpu_trigger_data *state =
418 + (struct leds_cpu_trigger_data *)data;
420 + write_lock(&state->trigger.leddev_list_lock);
422 + unsigned long now = jiffies;
424 + /* If at least one LED is set to flash; set the timer
425 + * again (this won't reset the timer set within the
426 + * idle loop).
427 + */
428 + if (leds_cpu_trigger_scan_leds(state, now))
429 + leds_cpu_trigger_set_timer(state, now);
431 + write_unlock(&state->trigger.leddev_list_lock);
436 + * There is one global control structure, one timer and one set
437 + * of state for active CPUs shared across all the LEDs. Individual
438 + * LEDs say how this state to be handled. It is currently *not*
439 + * possible to show per-cpu activity on individual LEDs, the code
440 + * maintains a count of active CPUs and the state is only 'idle'
441 + * if all CPUs are idle.
442 + */
443 +static struct leds_cpu_trigger_data leds_cpu_trigger = {
444 + .trigger = {
445 + .name = "cpu",
446 + .activate = leds_cpu_trigger_activate,
447 + .deactivate = leds_cpu_trigger_deactivate,
448 + } ,
449 + .timer = TIMER_INITIALIZER(leds_cpu_trigger_timer_callback, 0,
450 + (unsigned long)&leds_cpu_trigger),
451 + .last_active_time = 0,
452 + .last_idle_time = 0,
453 + .count_active = 0,
457 + * State change - callback from an individual LED on a property change which
458 + * might require a redisplay.
459 + */
460 +static void leds_cpu_trigger_state_change() {
461 + write_lock(&leds_cpu_trigger.trigger.leddev_list_lock);
463 + unsigned long now = jiffies;
465 + if (leds_cpu_trigger_scan_leds(&leds_cpu_trigger, now) &&
466 + !timer_pending(&leds_cpu_trigger.timer))
467 + leds_cpu_trigger_set_timer(&leds_cpu_trigger, now);
469 + write_unlock(&leds_cpu_trigger.trigger.leddev_list_lock);
473 + * Called from every CPU at the start and end of the idle loop.
474 + * The active count is initially 0, even though CPUs are running,
475 + * so the code below must check for the resultant underflow.
477 + * If the idle behaviour is 'flash' then when the timer times out
478 + * it will take the CPU out of idle, set the active state (which
479 + * may also be flash), drop back into idle and reset the timer to
480 + * the idle timeout...
481 + */
482 +static void leds_cpu_trigger_idle(int is_idle)
484 + write_lock(&leds_cpu_trigger.trigger.leddev_list_lock);
485 + if ((is_idle && leds_cpu_trigger.count_active > 0 &&
486 + --leds_cpu_trigger.count_active == 0) ||
487 + (!is_idle && leds_cpu_trigger.count_active < num_online_cpus() &&
488 + ++leds_cpu_trigger.count_active == 1)) {
489 + unsigned long now = jiffies;
491 + /* State change - the system just became idle or active,
492 + * call the del_timer first in an attempt to minimise
493 + * getting a timer interrupt which will take us unnecessarily
494 + * out of idle (this doesn't matter).
495 + */
496 + del_timer(&leds_cpu_trigger.timer);
497 + if (leds_cpu_trigger_scan_leds(&leds_cpu_trigger, now))
498 + leds_cpu_trigger_set_timer(&leds_cpu_trigger, now);
500 + write_unlock(&leds_cpu_trigger.trigger.leddev_list_lock);
504 + * Module init and exit - register the trigger, then store
505 + * the idle callback in the arch-specific global. For this
506 + * module to link (into the kernel) or load (into a running
507 + * kernel) the architecture must define the leds_idle global.
508 + */
509 +static int __init leds_cpu_trigger_init(void)
511 + int rc = led_trigger_register(&leds_cpu_trigger.trigger);
512 + leds_idle = leds_cpu_trigger_idle;
513 + return rc;
515 +module_init(leds_cpu_trigger_init);
517 +static void __exit leds_cpu_trigger_exit(void)
519 + leds_idle = 0;
520 + del_timer_sync(&leds_cpu_trigger.timer);
521 + led_trigger_unregister(&leds_cpu_trigger.trigger);
523 +module_exit(leds_cpu_trigger_exit);
525 +MODULE_AUTHOR("John Bowler <jbowler@acm.org>");
526 +MODULE_DESCRIPTION("CPU activity LED trigger");
527 +MODULE_LICENSE("Dual MIT/GPL");
528 Index: linux-2.6.24.3/drivers/leds/Makefile
529 ===================================================================
530 --- linux-2.6.24.3.orig/drivers/leds/Makefile 2008-02-29 13:56:08.000000000 +0100
531 +++ linux-2.6.24.3/drivers/leds/Makefile 2008-02-29 13:56:11.000000000 +0100
532 @@ -24,3 +24,4 @@
533 obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
534 obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
535 obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
536 +obj-$(CONFIG_LEDS_TRIGGER_CPU_ACTIVITY) += ledtrig-cpu.o
537 Index: linux-2.6.24.3/include/linux/leds.h
538 ===================================================================
539 --- linux-2.6.24.3.orig/include/linux/leds.h 2008-02-29 13:56:08.000000000 +0100
540 +++ linux-2.6.24.3/include/linux/leds.h 2008-02-29 13:56:11.000000000 +0100
541 @@ -124,4 +124,13 @@
546 + * CPU activity indication.
547 + */
548 +/* Idle callback - call with is_idle==1 at the start of the idle loop
549 + * and with is_idle==0 at the end. This symbol must be defined by
550 + * the arch core to be able to use LEDS_TRIGGER_CPU_ACTIVITY
551 + */
552 +extern void (*leds_idle)(int is_idle);
554 #endif /* __LINUX_LEDS_H_INCLUDED */