diff options
Diffstat (limited to 'packages/linux/ixp4xx-kernel/2.6.16/leds-class.patch')
-rw-r--r-- | packages/linux/ixp4xx-kernel/2.6.16/leds-class.patch | 2069 |
1 files changed, 2069 insertions, 0 deletions
diff --git a/packages/linux/ixp4xx-kernel/2.6.16/leds-class.patch b/packages/linux/ixp4xx-kernel/2.6.16/leds-class.patch new file mode 100644 index 0000000000..9fbcae79b9 --- /dev/null +++ b/packages/linux/ixp4xx-kernel/2.6.16/leds-class.patch @@ -0,0 +1,2069 @@ +Add the foundations of a new LEDs subsystem. This patch adds a class +which presents LED devices within sysfs and allows their brightness to +be controlled. + +Signed-off-by: Richard Purdie <rpurdie@rpsys.net> + +Index: linux-2.6.15/drivers/leds/Kconfig +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Kconfig 2006-01-29 16:02:38.000000000 +0000 +@@ -0,0 +1,18 @@ ++ ++menu "LED devices" ++ ++config NEW_LEDS ++ bool "LED Support" ++ help ++ Say Y to enable Linux LED support. This is not related to standard ++ keyboard LEDs which are controlled via the input system. ++ ++config LEDS_CLASS ++ tristate "LED Class Support" ++ depends NEW_LEDS ++ help ++ This option enables the led sysfs class in /sys/class/leds. You'll ++ need this to do anything useful with LEDs. If unsure, say N. ++ ++endmenu ++ +Index: linux-2.6.15/drivers/leds/Makefile +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Makefile 2006-01-29 16:02:38.000000000 +0000 +@@ -0,0 +1,4 @@ ++ ++# LED Core ++obj-$(CONFIG_NEW_LEDS) += led-core.o ++obj-$(CONFIG_LEDS_CLASS) += led-class.o +Index: linux-2.6.15/include/linux/leds.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/include/linux/leds.h 2006-01-29 16:03:21.000000000 +0000 +@@ -0,0 +1,48 @@ ++/* ++ * Driver model for leds and led triggers ++ * ++ * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu> ++ * Copyright (C) 2005 Richard Purdie <rpurdie@openedhand.com> ++ * ++ * 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. ++ * ++ */ ++ ++struct device; ++struct class_device; ++/* ++ * LED Core ++ */ ++ ++enum led_brightness { ++ LED_OFF = 0, ++ LED_HALF = 127, ++ LED_FULL = 255, ++}; ++ ++struct led_classdev { ++ const char *name; ++ int brightness; ++ int flags; ++#define LED_SUSPENDED (1 << 0) ++ ++ /* A function to set the brightness of the led */ ++ void (*brightness_set)(struct led_classdev *led_cdev, enum led_brightness brightness); ++ ++ struct class_device *class_dev; ++ /* LED Device linked list */ ++ struct list_head node; ++ ++ /* Trigger data */ ++ char *default_trigger; ++ ++ /* This protects the data in this structure */ ++ rwlock_t lock; ++}; ++ ++extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev); ++extern void led_classdev_unregister(struct led_classdev *led_cdev); ++extern void led_classdev_suspend(struct led_classdev *led_cdev); ++extern void led_classdev_resume(struct led_classdev *led_cdev); +Index: linux-2.6.15/arch/arm/Kconfig +=================================================================== +--- linux-2.6.15.orig/arch/arm/Kconfig 2006-01-29 14:37:31.000000000 +0000 ++++ linux-2.6.15/arch/arm/Kconfig 2006-01-29 16:02:15.000000000 +0000 +@@ -774,6 +774,8 @@ + + source "drivers/mfd/Kconfig" + ++source "drivers/leds/Kconfig" ++ + source "drivers/media/Kconfig" + + source "drivers/video/Kconfig" +Index: linux-2.6.15/drivers/Makefile +=================================================================== +--- linux-2.6.15.orig/drivers/Makefile 2006-01-29 14:42:52.000000000 +0000 ++++ linux-2.6.15/drivers/Makefile 2006-01-29 14:43:11.000000000 +0000 +@@ -68,6 +68,7 @@ + obj-$(CONFIG_EISA) += eisa/ + obj-$(CONFIG_CPU_FREQ) += cpufreq/ + obj-$(CONFIG_MMC) += mmc/ ++obj-$(CONFIG_NEW_LEDS) += leds/ + obj-$(CONFIG_INFINIBAND) += infiniband/ + obj-$(CONFIG_SGI_IOC4) += sn/ + obj-y += firmware/ +Index: linux-2.6.15/drivers/Kconfig +=================================================================== +--- linux-2.6.15.orig/drivers/Kconfig 2006-01-29 14:42:51.000000000 +0000 ++++ linux-2.6.15/drivers/Kconfig 2006-01-29 14:43:11.000000000 +0000 +@@ -64,6 +64,8 @@ + + source "drivers/mmc/Kconfig" + ++source "drivers/leds/Kconfig" ++ + source "drivers/infiniband/Kconfig" + + source "drivers/sn/Kconfig" +Index: linux-2.6.15/drivers/leds/leds.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/leds.h 2006-01-29 16:02:38.000000000 +0000 +@@ -0,0 +1,26 @@ ++/* ++ * LED Core ++ * ++ * Copyright 2005 Openedhand Ltd. ++ * ++ * Author: Richard Purdie <rpurdie@openedhand.com> ++ * ++ * 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. ++ * ++ */ ++ ++/* led_cdev->lock must be held as write */ ++static inline void led_set_brightness(struct led_classdev *led_cdev, enum led_brightness value) ++{ ++ if (value > LED_FULL) ++ value = LED_FULL; ++ led_cdev->brightness = value; ++ if (!(led_cdev->flags & LED_SUSPENDED)) ++ led_cdev->brightness_set(led_cdev, value); ++} ++ ++extern rwlock_t leds_list_lock; ++extern struct list_head leds_list; ++ +Index: linux-2.6.15/drivers/leds/led-class.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/led-class.c 2006-01-29 16:02:38.000000000 +0000 +@@ -0,0 +1,150 @@ ++/* ++ * LED Class Core ++ * ++ * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu> ++ * Copyright (C) 2005-2006 Richard Purdie <rpurdie@openedhand.com> ++ * ++ * 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/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/list.h> ++#include <linux/spinlock.h> ++#include <linux/device.h> ++#include <linux/sysdev.h> ++#include <linux/timer.h> ++#include <linux/err.h> ++#include <linux/leds.h> ++#include "leds.h" ++ ++static struct class *leds_class; ++ ++static ssize_t led_brightness_show(struct class_device *dev, char *buf) ++{ ++ struct led_classdev *led_cdev = dev->class_data; ++ ssize_t ret = 0; ++ ++ /* no lock needed for this */ ++ sprintf(buf, "%u\n", led_cdev->brightness); ++ ret = strlen(buf) + 1; ++ ++ return ret; ++} ++ ++static ssize_t led_brightness_store(struct class_device *dev, const char *buf, size_t size) ++{ ++ struct led_classdev *led_cdev = dev->class_data; ++ ssize_t ret = -EINVAL; ++ char *after; ++ ++ unsigned long state = simple_strtoul(buf, &after, 10); ++ if (after - buf > 0) { ++ ret = after - buf; ++ write_lock(&led_cdev->lock); ++ led_set_brightness(led_cdev, state); ++ write_unlock(&led_cdev->lock); ++ } ++ ++ return ret; ++} ++ ++static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store); ++ ++ ++/** ++ * led_classdev_suspend - suspend an led_classdev. ++ * @led_cdev: the led_classdev to suspend. ++ */ ++void led_classdev_suspend(struct led_classdev *led_cdev) ++{ ++ write_lock(&led_cdev->lock); ++ led_cdev->flags |= LED_SUSPENDED; ++ led_cdev->brightness_set(led_cdev, 0); ++ write_unlock(&led_cdev->lock); ++} ++ ++/** ++ * led_classdev_resume - resume an led_classdev. ++ * @led_cdev: the led_classdev to resume. ++ */ ++void led_classdev_resume(struct led_classdev *led_cdev) ++{ ++ write_lock(&led_cdev->lock); ++ led_cdev->flags &= ~LED_SUSPENDED; ++ led_cdev->brightness_set(led_cdev, led_cdev->brightness); ++ write_unlock(&led_cdev->lock); ++} ++ ++/** ++ * led_classdev_register - register a new object of led_classdev class. ++ * @dev: The device to register. ++ * @led_cdev: the led_classdev structure for this device. ++ */ ++int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) ++{ ++ led_cdev->class_dev = class_device_create(leds_class, NULL, 0, parent, "%s", led_cdev->name); ++ if (unlikely(IS_ERR(led_cdev->class_dev))) ++ return PTR_ERR(led_cdev->class_dev); ++ ++ rwlock_init(&led_cdev->lock); ++ led_cdev->class_dev->class_data = led_cdev; ++ ++ /* register the attributes */ ++ class_device_create_file(led_cdev->class_dev, &class_device_attr_brightness); ++ ++ /* add to the list of leds */ ++ write_lock(&leds_list_lock); ++ list_add_tail(&led_cdev->node, &leds_list); ++ write_unlock(&leds_list_lock); ++ ++ printk(KERN_INFO "Registered led device: %s\n", led_cdev->class_dev->class_id); ++ ++ return 0; ++} ++ ++/** ++ * led_classdev_unregister - unregisters a object of led_properties class. ++ * @led_cdev: the led device to unreigister ++ * ++ * Unregisters a previously registered via led_classdev_register object. ++ */ ++void led_classdev_unregister(struct led_classdev *led_cdev) ++{ ++ class_device_remove_file(led_cdev->class_dev, &class_device_attr_brightness); ++ ++ class_device_unregister(led_cdev->class_dev); ++ ++ write_lock(&leds_list_lock); ++ list_del(&led_cdev->node); ++ write_unlock(&leds_list_lock); ++} ++ ++EXPORT_SYMBOL_GPL(led_classdev_suspend); ++EXPORT_SYMBOL_GPL(led_classdev_resume); ++EXPORT_SYMBOL_GPL(led_classdev_register); ++EXPORT_SYMBOL_GPL(led_classdev_unregister); ++ ++static int __init leds_init(void) ++{ ++ leds_class = class_create(THIS_MODULE, "leds"); ++ if (IS_ERR(leds_class)) ++ return PTR_ERR(leds_class); ++ return 0; ++} ++ ++static void __exit leds_exit(void) ++{ ++ class_destroy(leds_class); ++} ++ ++subsys_initcall(leds_init); ++module_exit(leds_exit); ++ ++MODULE_AUTHOR("John Lenz, Richard Purdie"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("LED Class Interface"); +Index: linux-2.6.15/drivers/leds/led-core.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/led-core.c 2006-01-29 14:43:11.000000000 +0000 +@@ -0,0 +1,24 @@ ++/* ++ * LED Class Core ++ * ++ * Copyright 2005-2006 Openedhand Ltd. ++ * ++ * Author: Richard Purdie <rpurdie@openedhand.com> ++ * ++ * 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/kernel.h> ++#include <linux/list.h> ++#include <linux/module.h> ++#include <linux/spinlock.h> ++#include <linux/leds.h> ++#include "leds.h" ++ ++rwlock_t leds_list_lock = RW_LOCK_UNLOCKED; ++LIST_HEAD(leds_list); ++ ++EXPORT_SYMBOL_GPL(leds_list); +Add support for LED triggers to the LED subsystem. "Triggers" are events +which change the state of an LED. Two kinds of trigger are available, +simple ones which can be added to exising code with minimum disruption +and complex ones for implementing new or more complex functionality. + +Signed-off-by: Richard Purdie <rpurdie@rpsys.net> + +Index: linux-2.6.15/drivers/leds/Kconfig +=================================================================== +--- linux-2.6.15.orig/drivers/leds/Kconfig 2006-01-29 15:52:16.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Kconfig 2006-01-29 16:02:35.000000000 +0000 +@@ -14,5 +14,13 @@ + This option enables the led sysfs class in /sys/class/leds. You'll + need this to do anything useful with LEDs. If unsure, say N. + ++config LEDS_TRIGGERS ++ bool "LED Trigger support" ++ depends NEW_LEDS ++ help ++ This option enables trigger support for the leds class. ++ These triggers allow kernel events to drive the LEDs and can ++ be configured via sysfs. If unsure, say Y. ++ + endmenu + +Index: linux-2.6.15/drivers/leds/Makefile +=================================================================== +--- linux-2.6.15.orig/drivers/leds/Makefile 2006-01-29 15:52:16.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Makefile 2006-01-29 16:02:35.000000000 +0000 +@@ -2,3 +2,4 @@ + # LED Core + obj-$(CONFIG_NEW_LEDS) += led-core.o + obj-$(CONFIG_LEDS_CLASS) += led-class.o ++obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o +Index: linux-2.6.15/drivers/leds/leds.h +=================================================================== +--- linux-2.6.15.orig/drivers/leds/leds.h 2006-01-29 15:54:46.000000000 +0000 ++++ linux-2.6.15/drivers/leds/leds.h 2006-01-29 15:55:02.000000000 +0000 +@@ -24,3 +24,13 @@ + extern rwlock_t leds_list_lock; + extern struct list_head leds_list; + ++#ifdef CONFIG_LEDS_TRIGGERS ++void led_trigger_set_default(struct led_classdev *led_cdev); ++void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger); ++#else ++#define led_trigger_set_default(x) do {} while(0) ++#define led_trigger_set(x, y) do {} while(0) ++#endif ++ ++ssize_t led_trigger_store(struct class_device *dev, const char *buf, size_t count); ++ssize_t led_trigger_show(struct class_device *dev, char *buf); +Index: linux-2.6.15/include/linux/leds.h +=================================================================== +--- linux-2.6.15.orig/include/linux/leds.h 2006-01-29 15:52:16.000000000 +0000 ++++ linux-2.6.15/include/linux/leds.h 2006-01-29 15:55:02.000000000 +0000 +@@ -38,6 +38,11 @@ + + /* Trigger data */ + char *default_trigger; ++#ifdef CONFIG_LEDS_TRIGGERS ++ struct led_trigger *trigger; ++ struct list_head trig_list; ++ void *trigger_data; ++#endif + + /* This protects the data in this structure */ + rwlock_t lock; +@@ -47,3 +52,47 @@ + extern void led_classdev_unregister(struct led_classdev *led_cdev); + extern void led_classdev_suspend(struct led_classdev *led_cdev); + extern void led_classdev_resume(struct led_classdev *led_cdev); ++ ++ ++/* ++ * LED Triggers ++ */ ++#ifdef CONFIG_LEDS_TRIGGERS ++ ++#define TRIG_NAME_MAX 50 ++ ++struct led_trigger { ++ /* Trigger Properties */ ++ const char *name; ++ void (*activate)(struct led_classdev *led_cdev); ++ void (*deactivate)(struct led_classdev *led_cdev); ++ ++ /* LEDs under control by this trigger (for simple triggers) */ ++ rwlock_t leddev_list_lock; ++ struct list_head led_cdevs; ++ ++ /* Link to next registered trigger */ ++ struct list_head next_trig; ++}; ++ ++/* Registration functions for complex triggers */ ++int led_trigger_register(struct led_trigger *trigger); ++void led_trigger_unregister(struct led_trigger *trigger); ++ ++/* Registration functions for simple triggers */ ++#define INIT_LED_TRIGGER(x) static struct led_trigger *x; ++#define INIT_LED_TRIGGER_GLOBAL(x) struct led_trigger *x; ++void led_trigger_register_simple(const char *name, struct led_trigger **trigger); ++void led_trigger_unregister_simple(struct led_trigger *trigger); ++void led_trigger_event(struct led_trigger *trigger, enum led_brightness event); ++ ++#else ++ ++/* Triggers aren't active - null macros */ ++#define INIT_LED_TRIGGER(x) ++#define INIT_LED_TRIGGER_GLOBAL(x) ++#define led_trigger_register_simple(x, y) do {} while(0) ++#define led_trigger_unregister_simple(x) do {} while(0) ++#define led_trigger_event(x, y) do {} while(0) ++ ++#endif +Index: linux-2.6.15/drivers/leds/led-class.c +=================================================================== +--- linux-2.6.15.orig/drivers/leds/led-class.c 2006-01-29 15:54:02.000000000 +0000 ++++ linux-2.6.15/drivers/leds/led-class.c 2006-01-29 15:55:02.000000000 +0000 +@@ -55,6 +55,9 @@ + + static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store); + ++#ifdef CONFIG_LEDS_TRIGGERS ++static CLASS_DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store); ++#endif + + /** + * led_classdev_suspend - suspend an led_classdev. +@@ -96,12 +99,17 @@ + + /* register the attributes */ + class_device_create_file(led_cdev->class_dev, &class_device_attr_brightness); ++#ifdef CONFIG_LEDS_TRIGGERS ++ class_device_create_file(led_cdev->class_dev, &class_device_attr_trigger); ++#endif + + /* add to the list of leds */ + write_lock(&leds_list_lock); + list_add_tail(&led_cdev->node, &leds_list); + write_unlock(&leds_list_lock); + ++ led_trigger_set_default(led_cdev); ++ + printk(KERN_INFO "Registered led device: %s\n", led_cdev->class_dev->class_id); + + return 0; +@@ -116,6 +124,12 @@ + void led_classdev_unregister(struct led_classdev *led_cdev) + { + class_device_remove_file(led_cdev->class_dev, &class_device_attr_brightness); ++#ifdef CONFIG_LEDS_TRIGGERS ++ class_device_remove_file(led_cdev->class_dev, &class_device_attr_trigger); ++#endif ++ ++ if (led_cdev->trigger) ++ led_trigger_set(led_cdev, NULL); + + class_device_unregister(led_cdev->class_dev); + +Index: linux-2.6.15/drivers/leds/led-triggers.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/led-triggers.c 2006-01-29 15:56:15.000000000 +0000 +@@ -0,0 +1,236 @@ ++/* ++ * LED Triggers Core ++ * ++ * Copyright 2005-2006 Openedhand Ltd. ++ * ++ * Author: Richard Purdie <rpurdie@openedhand.com> ++ * ++ * 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/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/list.h> ++#include <linux/spinlock.h> ++#include <linux/device.h> ++#include <linux/sysdev.h> ++#include <linux/timer.h> ++#include <linux/leds.h> ++#include "leds.h" ++ ++static rwlock_t triggers_list_lock = RW_LOCK_UNLOCKED; ++static LIST_HEAD(trigger_list); ++ ++ssize_t led_trigger_store(struct class_device *dev, const char *buf, size_t count) ++{ ++ struct led_classdev *led_cdev = dev->class_data; ++ char trigger_name[TRIG_NAME_MAX]; ++ struct led_trigger *trig; ++ size_t len; ++ ++ trigger_name[sizeof(trigger_name) - 1] = '\0'; ++ strncpy(trigger_name, buf, sizeof(trigger_name) - 1); ++ len = strlen(trigger_name); ++ ++ if (len && trigger_name[len - 1] == '\n') ++ trigger_name[len - 1] = '\0'; ++ ++ if (!strcmp(trigger_name, "none")) { ++ write_lock(&led_cdev->lock); ++ led_trigger_set(led_cdev, NULL); ++ write_unlock(&led_cdev->lock); ++ return count; ++ } ++ ++ read_lock(&triggers_list_lock); ++ list_for_each_entry(trig, &trigger_list, next_trig) { ++ if (!strcmp(trigger_name, trig->name)) { ++ write_lock(&led_cdev->lock); ++ led_trigger_set(led_cdev, trig); ++ write_unlock(&led_cdev->lock); ++ ++ read_unlock(&triggers_list_lock); ++ return count; ++ } ++ } ++ read_unlock(&triggers_list_lock); ++ ++ return -EINVAL; ++} ++ ++ ++ssize_t led_trigger_show(struct class_device *dev, char *buf) ++{ ++ struct led_classdev *led_cdev = dev->class_data; ++ struct led_trigger *trig; ++ int len = 0; ++ ++ read_lock(&led_cdev->lock); ++ ++ if (!led_cdev->trigger) ++ len += sprintf(buf+len, "[none] "); ++ else ++ len += sprintf(buf+len, "none "); ++ ++ read_lock(&triggers_list_lock); ++ list_for_each_entry(trig, &trigger_list, next_trig) { ++ if (led_cdev->trigger && !strcmp(led_cdev->trigger->name, trig->name)) ++ len += sprintf(buf+len, "[%s] ", trig->name); ++ else ++ len += sprintf(buf+len, "%s ", trig->name); ++ } ++ read_unlock(&triggers_list_lock); ++ read_unlock(&led_cdev->lock); ++ ++ len += sprintf(len+buf, "\n"); ++ return len; ++} ++ ++void led_trigger_event(struct led_trigger *trigger, enum led_brightness brightness) ++{ ++ struct list_head *entry; ++ ++ if (!trigger) ++ return; ++ ++ read_lock(&trigger->leddev_list_lock); ++ list_for_each(entry, &trigger->led_cdevs) { ++ struct led_classdev *led_cdev; ++ ++ led_cdev = list_entry(entry, struct led_classdev, trig_list); ++ write_lock(&led_cdev->lock); ++ led_set_brightness(led_cdev, brightness); ++ write_unlock(&led_cdev->lock); ++ } ++ read_unlock(&trigger->leddev_list_lock); ++} ++ ++/* Caller must ensure led_cdev->lock held for write */ ++void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) ++{ ++ /* Remove any existing trigger */ ++ if (led_cdev->trigger) { ++ write_lock(&led_cdev->trigger->leddev_list_lock); ++ list_del(&led_cdev->trig_list); ++ write_unlock(&led_cdev->trigger->leddev_list_lock); ++ if (led_cdev->trigger->deactivate) ++ led_cdev->trigger->deactivate(led_cdev); ++ ++ } ++ if (trigger) { ++ write_lock(&trigger->leddev_list_lock); ++ list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs); ++ write_unlock(&trigger->leddev_list_lock); ++ if (trigger->activate) ++ trigger->activate(led_cdev); ++ } ++ led_cdev->trigger = trigger; ++} ++ ++void led_trigger_set_default(struct led_classdev *led_cdev) ++{ ++ struct led_trigger *trig; ++ ++ if (!led_cdev->default_trigger) ++ return; ++ ++ write_lock(&led_cdev->lock); ++ read_lock(&triggers_list_lock); ++ list_for_each_entry(trig, &trigger_list, next_trig) { ++ if (!strcmp(led_cdev->default_trigger, trig->name)) ++ led_trigger_set(led_cdev, trig); ++ } ++ read_unlock(&triggers_list_lock); ++ write_unlock(&led_cdev->lock); ++} ++ ++int led_trigger_register(struct led_trigger *trigger) ++{ ++ struct led_classdev *led_cdev; ++ ++ rwlock_init(&trigger->leddev_list_lock); ++ INIT_LIST_HEAD(&trigger->led_cdevs); ++ ++ /* Add to the list of led triggers */ ++ write_lock(&triggers_list_lock); ++ list_add_tail(&trigger->next_trig, &trigger_list); ++ write_unlock(&triggers_list_lock); ++ ++ /* Register with any LEDs that have this as a default trigger */ ++ read_lock(&leds_list); ++ list_for_each_entry(led_cdev, &leds_list, node) { ++ write_lock(&led_cdev->lock); ++ if (!led_cdev->trigger && led_cdev->default_trigger && ++ !strcmp(led_cdev->default_trigger, trigger->name)) ++ led_trigger_set(led_cdev, trigger); ++ write_unlock(&led_cdev->lock); ++ } ++ read_unlock(&leds_list); ++ ++ return 0; ++} ++ ++void led_trigger_register_simple(const char *name, struct led_trigger **tp) ++{ ++ struct led_trigger *trigger; ++ ++ trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); ++ ++ if (trigger) { ++ trigger->name = name; ++ led_trigger_register(trigger); ++ } ++ *tp = trigger; ++} ++ ++ ++void led_trigger_unregister(struct led_trigger *trigger) ++{ ++ struct led_classdev *led_cdev; ++ ++ /* Remove from the list of led triggers */ ++ write_lock(&triggers_list_lock); ++ list_del(&trigger->next_trig); ++ write_unlock(&triggers_list_lock); ++ ++ /* Remove anyone actively using this trigger */ ++ read_lock(&leds_list); ++ list_for_each_entry(led_cdev, &leds_list, node) { ++ write_lock(&led_cdev->lock); ++ if (led_cdev->trigger == trigger) ++ led_trigger_set(led_cdev, NULL); ++ write_unlock(&led_cdev->lock); ++ } ++ read_unlock(&leds_list); ++} ++ ++void led_trigger_unregister_simple(struct led_trigger *trigger) ++{ ++ led_trigger_unregister(trigger); ++ kfree(trigger); ++} ++ ++/* Used by LED Class */ ++EXPORT_SYMBOL_GPL(led_trigger_set); ++EXPORT_SYMBOL_GPL(led_trigger_set_default); ++EXPORT_SYMBOL_GPL(led_trigger_show); ++EXPORT_SYMBOL_GPL(led_trigger_store); ++ ++/* LED Trigger Interface */ ++EXPORT_SYMBOL_GPL(led_trigger_register); ++EXPORT_SYMBOL_GPL(led_trigger_unregister); ++ ++/* Simple LED Tigger Interface */ ++EXPORT_SYMBOL_GPL(led_trigger_register_simple); ++EXPORT_SYMBOL_GPL(led_trigger_unregister_simple); ++EXPORT_SYMBOL_GPL(led_trigger_event); ++ ++MODULE_AUTHOR("Richard Purdie"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("LED Triggers Core"); ++ +Add an example of a complex LED trigger in the form of a generic timer +which triggers the LED its attached to at a user specified frequency +and duty cycle. + +Signed-off-by: Richard Purdie <rpurdie@rpsys.net> + +Index: linux-2.6.15/drivers/leds/Kconfig +=================================================================== +--- linux-2.6.15.orig/drivers/leds/Kconfig 2006-01-29 16:13:48.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Kconfig 2006-01-29 20:32:16.000000000 +0000 +@@ -22,5 +22,12 @@ + These triggers allow kernel events to drive the LEDs and can + be configured via sysfs. If unsure, say Y. + ++config LEDS_TRIGGER_TIMER ++ tristate "LED Timer Trigger" ++ depends LEDS_TRIGGERS ++ help ++ This allows LEDs to be controlled by a programmable timer ++ via sysfs. If unsure, say Y. ++ + endmenu + +Index: linux-2.6.15/drivers/leds/Makefile +=================================================================== +--- linux-2.6.15.orig/drivers/leds/Makefile 2006-01-29 16:13:48.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Makefile 2006-01-29 20:32:16.000000000 +0000 +@@ -3,3 +3,6 @@ + obj-$(CONFIG_NEW_LEDS) += led-core.o + obj-$(CONFIG_LEDS_CLASS) += led-class.o + obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o ++ ++# LED Triggers ++obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o +Index: linux-2.6.15/drivers/leds/ledtrig-timer.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/ledtrig-timer.c 2006-01-29 17:40:11.000000000 +0000 +@@ -0,0 +1,205 @@ ++/* ++ * LED Kernel Timer Trigger ++ * ++ * Copyright 2005-2006 Openedhand Ltd. ++ * ++ * Author: Richard Purdie <rpurdie@openedhand.com> ++ * ++ * 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/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/list.h> ++#include <linux/spinlock.h> ++#include <linux/device.h> ++#include <linux/sysdev.h> ++#include <linux/timer.h> ++#include <linux/leds.h> ++#include "leds.h" ++ ++struct timer_trig_data { ++ unsigned long duty; /* duty cycle, as a percentage */ ++ unsigned long frequency; /* frequency of blinking, in Hz */ ++ 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; ++ struct timer_trig_data *timer_data = led_cdev->trigger_data; ++ unsigned long brightness = LED_OFF; ++ unsigned long delay = timer_data->delay_off; ++ ++ write_lock(&led_cdev->lock); ++ ++ if (!timer_data->frequency) { ++ led_set_brightness(led_cdev, LED_OFF); ++ write_unlock(&led_cdev->lock); ++ return; ++ } ++ ++ if (!led_cdev->brightness) { ++ brightness = LED_FULL; ++ delay = timer_data->delay_on; ++ } ++ ++ led_set_brightness(led_cdev, brightness); ++ ++ mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay)); ++ write_unlock(&led_cdev->lock); ++} ++ ++/* led_cdev write lock needs to be held */ ++static int led_timer_setdata(struct led_classdev *led_cdev, unsigned long duty, unsigned long frequency) ++{ ++ struct timer_trig_data *timer_data = led_cdev->trigger_data; ++ ++ if (frequency > 500) ++ return -EINVAL; ++ ++ if (duty > 100) ++ return -EINVAL; ++ ++ timer_data->duty = duty; ++ timer_data->frequency = frequency; ++ if (frequency != 0) { ++ timer_data->delay_on = duty * 1000 / 50 / frequency / 2; ++ timer_data->delay_off = (100 - duty) * 1000 / 50 / frequency / 2; ++ } ++ ++ mod_timer(&timer_data->timer, jiffies + 1); ++ ++ return 0; ++} ++ ++static ssize_t led_duty_show(struct class_device *dev, char *buf) ++{ ++ struct led_classdev *led_cdev = dev->class_data; ++ struct timer_trig_data *timer_data; ++ ++ read_lock(&led_cdev->lock); ++ timer_data = led_cdev->trigger_data; ++ sprintf(buf, "%lu\n", timer_data->duty); ++ read_unlock(&led_cdev->lock); ++ ++ return strlen(buf) + 1; ++} ++ ++static ssize_t led_duty_store(struct class_device *dev, const char *buf, size_t size) ++{ ++ struct led_classdev *led_cdev = dev->class_data; ++ struct timer_trig_data *timer_data; ++ int ret = -EINVAL; ++ char *after; ++ ++ unsigned long state = simple_strtoul(buf, &after, 10); ++ if (after - buf > 0) { ++ write_lock(&led_cdev->lock); ++ timer_data = led_cdev->trigger_data; ++ ret = led_timer_setdata(led_cdev, state, timer_data->frequency); ++ if (!ret) ++ ret = after - buf; ++ write_unlock(&led_cdev->lock); ++ } ++ ++ return ret; ++} ++ ++ ++static ssize_t led_frequency_show(struct class_device *dev, char *buf) ++{ ++ struct led_classdev *led_cdev = dev->class_data; ++ struct timer_trig_data *timer_data; ++ ++ read_lock(&led_cdev->lock); ++ timer_data = led_cdev->trigger_data; ++ sprintf(buf, "%lu\n", timer_data->frequency); ++ read_unlock(&led_cdev->lock); ++ ++ return strlen(buf) + 1; ++} ++ ++static ssize_t led_frequency_store(struct class_device *dev, const char *buf, size_t size) ++{ ++ struct led_classdev *led_cdev = dev->class_data; ++ struct timer_trig_data *timer_data; ++ int ret = -EINVAL; ++ char *after; ++ ++ unsigned long state = simple_strtoul(buf, &after, 10); ++ if (after - buf > 0) { ++ write_lock(&led_cdev->lock); ++ timer_data = led_cdev->trigger_data; ++ ret = led_timer_setdata(led_cdev, timer_data->duty, state); ++ if (!ret) ++ ret = after - buf; ++ write_unlock(&led_cdev->lock); ++ } ++ ++ return ret; ++} ++ ++static CLASS_DEVICE_ATTR(duty, 0644, led_duty_show, led_duty_store); ++static CLASS_DEVICE_ATTR(frequency, 0644, led_frequency_show, led_frequency_store); ++ ++static void timer_trig_activate(struct led_classdev *led_cdev) ++{ ++ struct timer_trig_data *timer_data; ++ ++ timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL); ++ if (!timer_data) ++ return; ++ ++ led_cdev->trigger_data = timer_data; ++ ++ init_timer(&timer_data->timer); ++ timer_data->timer.function = led_timer_function; ++ timer_data->timer.data = (unsigned long) led_cdev; ++ ++ timer_data->duty = 50; ++ ++ class_device_create_file(led_cdev->class_dev, &class_device_attr_duty); ++ class_device_create_file(led_cdev->class_dev, &class_device_attr_frequency); ++} ++ ++static void timer_trig_deactivate(struct led_classdev *led_cdev) ++{ ++ struct timer_trig_data *timer_data = led_cdev->trigger_data; ++ if (timer_data) { ++ class_device_remove_file(led_cdev->class_dev, &class_device_attr_duty); ++ class_device_remove_file(led_cdev->class_dev, &class_device_attr_frequency); ++ del_timer_sync(&timer_data->timer); ++ kfree(timer_data); ++ } ++} ++ ++static struct led_trigger timer_led_trigger = { ++ .name = "timer", ++ .activate = timer_trig_activate, ++ .deactivate = timer_trig_deactivate, ++}; ++ ++static int __init timer_trig_init(void) ++{ ++ return led_trigger_register(&timer_led_trigger); ++} ++ ++static void __exit timer_trig_exit (void) ++{ ++ led_trigger_unregister(&timer_led_trigger); ++} ++ ++module_init(timer_trig_init); ++module_exit(timer_trig_exit); ++ ++MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); ++MODULE_DESCRIPTION("Timer LED trigger"); ++MODULE_LICENSE("GPL"); +Adds LED drivers for LEDs found on the Sharp Zaurus c7x0 (corgi, +shepherd, husky) and cxx00 (akita, spitz, borzoi) models. + +Signed-off-by: Richard Purdie <rpurdie@rpsys.net> + +Index: linux-2.6.15/arch/arm/mach-pxa/corgi.c +=================================================================== +--- linux-2.6.15.orig/arch/arm/mach-pxa/corgi.c 2006-01-29 16:02:30.000000000 +0000 ++++ linux-2.6.15/arch/arm/mach-pxa/corgi.c 2006-01-29 16:11:47.000000000 +0000 +@@ -165,6 +165,15 @@ + + + /* ++ * Corgi LEDs ++ */ ++static struct platform_device corgiled_device = { ++ .name = "corgi-led", ++ .id = -1, ++}; ++ ++ ++/* + * Corgi Touch Screen Device + */ + static struct resource corgits_resources[] = { +@@ -298,6 +307,7 @@ + &corgikbd_device, + &corgibl_device, + &corgits_device, ++ &corgiled_device, + }; + + static void __init corgi_init(void) +Index: linux-2.6.15/arch/arm/mach-pxa/spitz.c +=================================================================== +--- linux-2.6.15.orig/arch/arm/mach-pxa/spitz.c 2006-01-29 16:02:30.000000000 +0000 ++++ linux-2.6.15/arch/arm/mach-pxa/spitz.c 2006-01-29 16:11:48.000000000 +0000 +@@ -243,6 +243,15 @@ + + + /* ++ * Spitz LEDs ++ */ ++static struct platform_device spitzled_device = { ++ .name = "spitz-led", ++ .id = -1, ++}; ++ ++ ++/* + * Spitz Touch Screen Device + */ + static struct resource spitzts_resources[] = { +@@ -419,6 +428,7 @@ + &spitzkbd_device, + &spitzts_device, + &spitzbl_device, ++ &spitzled_device, + }; + + static void __init common_init(void) +Index: linux-2.6.15/drivers/leds/Kconfig +=================================================================== +--- linux-2.6.15.orig/drivers/leds/Kconfig 2006-01-29 16:04:20.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Kconfig 2006-01-29 16:11:54.000000000 +0000 +@@ -22,6 +22,20 @@ + These triggers allow kernel events to drive the LEDs and can + be configured via sysfs. If unsure, say Y. + ++config LEDS_CORGI ++ tristate "LED Support for the Sharp SL-C7x0 series" ++ depends LEDS_CLASS && PXA_SHARP_C7xx ++ help ++ This option enables support for the LEDs on Sharp Zaurus ++ SL-C7x0 series (C700, C750, C760, C860). ++ ++config LEDS_SPITZ ++ tristate "LED Support for the Sharp SL-Cxx00 series" ++ depends LEDS_CLASS && PXA_SHARP_Cxx00 ++ help ++ This option enables support for the LEDs on Sharp Zaurus ++ SL-Cxx00 series (C1000, C3000, C3100). ++ + config LEDS_TRIGGER_TIMER + tristate "LED Timer Trigger" + depends LEDS_TRIGGERS +Index: linux-2.6.15/drivers/leds/Makefile +=================================================================== +--- linux-2.6.15.orig/drivers/leds/Makefile 2006-01-29 16:04:20.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Makefile 2006-01-29 16:11:54.000000000 +0000 +@@ -4,5 +4,9 @@ + obj-$(CONFIG_LEDS_CLASS) += led-class.o + obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o + ++# LED Platform Drivers ++obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o ++obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o ++ + # LED Triggers + obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o +Index: linux-2.6.15/drivers/leds/leds-corgi.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/leds-corgi.c 2006-01-29 16:08:42.000000000 +0000 +@@ -0,0 +1,121 @@ ++/* ++ * LED Triggers Core ++ * ++ * Copyright 2005-2006 Openedhand Ltd. ++ * ++ * Author: Richard Purdie <rpurdie@openedhand.com> ++ * ++ * 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/config.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/leds.h> ++#include <asm/mach-types.h> ++#include <asm/arch/corgi.h> ++#include <asm/arch/hardware.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/hardware/scoop.h> ++ ++static void corgiled_amber_set(struct led_classdev *led_cdev, enum led_brightness value) ++{ ++ if (value) ++ GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE); ++ else ++ GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE); ++} ++ ++static void corgiled_green_set(struct led_classdev *led_cdev, enum led_brightness value) ++{ ++ if (value) ++ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN); ++ else ++ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN); ++} ++ ++static struct led_classdev corgi_amber_led = { ++ .name = "corgi:amber", ++ .default_trigger = "sharpsl-charge", ++ .brightness_set = corgiled_amber_set, ++}; ++ ++static struct led_classdev corgi_green_led = { ++ .name = "corgi:green", ++ .default_trigger = "nand-disk", ++ .brightness_set = corgiled_green_set, ++}; ++ ++#ifdef CONFIG_PM ++static int corgiled_suspend(struct platform_device *dev, pm_message_t state) ++{ ++#ifdef CONFIG_LEDS_TRIGGERS ++ if (corgi_amber_led.trigger && strcmp(corgi_amber_led.trigger->name, "sharpsl-charge")) ++#endif ++ led_classdev_suspend(&corgi_amber_led); ++ led_classdev_suspend(&corgi_green_led); ++ return 0; ++} ++ ++static int corgiled_resume(struct platform_device *dev) ++{ ++ led_classdev_resume(&corgi_amber_led); ++ led_classdev_resume(&corgi_green_led); ++ return 0; ++} ++#endif ++ ++static int corgiled_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ ret = led_classdev_register(&pdev->dev, &corgi_amber_led); ++ if (ret < 0) ++ return ret; ++ ++ ret = led_classdev_register(&pdev->dev, &corgi_green_led); ++ if (ret < 0) ++ led_classdev_unregister(&corgi_amber_led); ++ ++ return ret; ++} ++ ++static int corgiled_remove(struct platform_device *pdev) ++{ ++ led_classdev_unregister(&corgi_amber_led); ++ led_classdev_unregister(&corgi_green_led); ++ return 0; ++} ++ ++static struct platform_driver corgiled_driver = { ++ .probe = corgiled_probe, ++ .remove = corgiled_remove, ++#ifdef CONFIG_PM ++ .suspend = corgiled_suspend, ++ .resume = corgiled_resume, ++#endif ++ .driver = { ++ .name = "corgi-led", ++ }, ++}; ++ ++static int __devinit corgiled_init(void) ++{ ++ return platform_driver_register(&corgiled_driver); ++} ++ ++static void corgiled_exit(void) ++{ ++ platform_driver_unregister(&corgiled_driver); ++} ++ ++module_init(corgiled_init); ++module_exit(corgiled_exit); ++ ++MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); ++MODULE_DESCRIPTION("Corgi LED driver"); ++MODULE_LICENSE("GPL"); +Index: linux-2.6.15/drivers/leds/leds-spitz.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/leds-spitz.c 2006-01-29 16:08:09.000000000 +0000 +@@ -0,0 +1,125 @@ ++/* ++ * LED Triggers Core ++ * ++ * Copyright 2005-2006 Openedhand Ltd. ++ * ++ * Author: Richard Purdie <rpurdie@openedhand.com> ++ * ++ * 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/config.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/leds.h> ++#include <asm/hardware/scoop.h> ++#include <asm/mach-types.h> ++#include <asm/arch/hardware.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/spitz.h> ++ ++static void spitzled_amber_set(struct led_classdev *led_cdev, enum led_brightness value) ++{ ++ if (value) ++ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE); ++ else ++ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE); ++} ++ ++static void spitzled_green_set(struct led_classdev *led_cdev, enum led_brightness value) ++{ ++ if (value) ++ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN); ++ else ++ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN); ++} ++ ++static struct led_classdev spitz_amber_led = { ++ .name = "spitz:amber", ++ .default_trigger = "sharpsl-charge", ++ .brightness_set = spitzled_amber_set, ++}; ++ ++static struct led_classdev spitz_green_led = { ++ .name = "spitz:green", ++ .default_trigger = "ide-disk", ++ .brightness_set = spitzled_green_set, ++}; ++ ++#ifdef CONFIG_PM ++static int spitzled_suspend(struct platform_device *dev, pm_message_t state) ++{ ++#ifdef CONFIG_LEDS_TRIGGERS ++ if (spitz_amber_led.trigger && strcmp(spitz_amber_led.trigger->name, "sharpsl-charge")) ++#endif ++ led_classdev_suspend(&spitz_amber_led); ++ led_classdev_suspend(&spitz_green_led); ++ return 0; ++} ++ ++static int spitzled_resume(struct platform_device *dev) ++{ ++ led_classdev_resume(&spitz_amber_led); ++ led_classdev_resume(&spitz_green_led); ++ return 0; ++} ++#endif ++ ++static int spitzled_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ if (machine_is_akita()) ++ spitz_green_led.default_trigger = "nand-disk"; ++ ++ ret = led_classdev_register(&pdev->dev, &spitz_amber_led); ++ if (ret < 0) ++ return ret; ++ ++ ret = led_classdev_register(&pdev->dev, &spitz_green_led); ++ if (ret < 0) ++ led_classdev_unregister(&spitz_amber_led); ++ ++ return ret; ++} ++ ++static int spitzled_remove(struct platform_device *pdev) ++{ ++ led_classdev_unregister(&spitz_amber_led); ++ led_classdev_unregister(&spitz_green_led); ++ ++ return 0; ++} ++ ++static struct platform_driver spitzled_driver = { ++ .probe = spitzled_probe, ++ .remove = spitzled_remove, ++#ifdef CONFIG_PM ++ .suspend = spitzled_suspend, ++ .resume = spitzled_resume, ++#endif ++ .driver = { ++ .name = "spitz-led", ++ }, ++}; ++ ++static int __devinit spitzled_init(void) ++{ ++ return platform_driver_register(&spitzled_driver); ++} ++ ++static void spitzled_exit(void) ++{ ++ platform_driver_unregister(&spitzled_driver); ++} ++ ++module_init(spitzled_init); ++module_exit(spitzled_exit); ++ ++MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); ++MODULE_DESCRIPTION("Spitz LED driver"); ++MODULE_LICENSE("GPL"); +Adds an LED driver for LEDs exported by the Sharp LOCOMO chip as found on +some models of Sharp Zaurus. + +Signed-off-by: Richard Purdie <rpurdie@rpsys.net> + +Index: linux-2.6.15/drivers/leds/Kconfig +=================================================================== +--- linux-2.6.15.orig/drivers/leds/Kconfig 2006-01-29 16:04:22.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Kconfig 2006-01-29 16:04:23.000000000 +0000 +@@ -29,6 +29,13 @@ + This option enables support for the LEDs on Sharp Zaurus + SL-C7x0 series (C700, C750, C760, C860). + ++config LEDS_LOCOMO ++ tristate "LED Support for Locomo device" ++ depends LEDS_CLASS && SHARP_LOCOMO ++ help ++ This option enables support for the LEDs on Sharp Locomo. ++ Zaurus models SL-5500 and SL-5600. ++ + config LEDS_SPITZ + tristate "LED Support for the Sharp SL-Cxx00 series" + depends LEDS_CLASS && PXA_SHARP_Cxx00 +Index: linux-2.6.15/drivers/leds/Makefile +=================================================================== +--- linux-2.6.15.orig/drivers/leds/Makefile 2006-01-29 16:04:22.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Makefile 2006-01-29 16:04:23.000000000 +0000 +@@ -6,6 +6,7 @@ + + # LED Platform Drivers + obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o ++obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o + obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o + + # LED Triggers +Index: linux-2.6.15/drivers/leds/leds-locomo.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/leds-locomo.c 2006-01-29 16:09:46.000000000 +0000 +@@ -0,0 +1,91 @@ ++/* ++ * linux/drivers/leds/locomo.c ++ * ++ * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu> ++ * ++ * 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/config.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/device.h> ++#include <linux/leds.h> ++ ++#include <asm/hardware.h> ++#include <asm/hardware/locomo.h> ++ ++static void locomoled_brightness_set(struct led_classdev *led_cdev, enum led_brightness value, int offset) ++{ ++ struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->class_dev->dev); ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ if (value) ++ locomo_writel(LOCOMO_LPT_TOFH, locomo_dev->mapbase + offset); ++ else ++ locomo_writel(LOCOMO_LPT_TOFL, locomo_dev->mapbase + offset); ++ local_irq_restore(flags); ++} ++ ++static void locomoled_brightness_set0(struct led_classdev *led_cdev, enum led_brightness value) ++{ ++ locomoled_brightness_set(led_cdev, value, LOCOMO_LPT0); ++} ++ ++static void locomoled_brightness_set1(struct led_classdev *led_cdev, enum led_brightness value) ++{ ++ locomoled_brightness_set(led_cdev, value, LOCOMO_LPT1); ++} ++ ++static struct led_classdev locomo_led0 = { ++ .name = "locomo:amber", ++ .brightness_set = locomoled_brightness_set0, ++}; ++ ++static struct led_classdev locomo_led1 = { ++ .name = "locomo:green", ++ .brightness_set = locomoled_brightness_set1, ++}; ++ ++static int locomoled_probe(struct locomo_dev *ldev) ++{ ++ int ret; ++ ++ ret = led_classdev_register(&ldev->dev, &locomo_led0); ++ if (ret < 0) ++ return ret; ++ ++ ret = led_classdev_register(&ldev->dev, &locomo_led1); ++ if (ret < 0) ++ led_classdev_unregister(&locomo_led0); ++ ++ return ret; ++} ++ ++static int locomoled_remove(struct locomo_dev *dev) ++{ ++ led_classdev_unregister(&locomo_led0); ++ led_classdev_unregister(&locomo_led1); ++ return 0; ++} ++ ++static struct locomo_driver locomoled_driver = { ++ .drv = { ++ .name = "locomoled" ++ }, ++ .devid = LOCOMO_DEVID_LED, ++ .probe = locomoled_probe, ++ .remove = locomoled_remove, ++}; ++ ++static int __init locomoled_init(void) { ++ return locomo_driver_register(&locomoled_driver); ++} ++module_init(locomoled_init); ++ ++MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); ++MODULE_DESCRIPTION("Locomo LED driver"); ++MODULE_LICENSE("GPL"); +From: John Bowler <jbowler@acm.org> + +NEW_LEDS support for ixp4xx boards where LEDs are connected +to the GPIO lines. + +This includes a new generic ixp4xx driver (leds-ixp4xx-gpio.c +name "IXP4XX-GPIO-LED") + +Signed-off-by: John Bowler <jbowler@acm.org> +Signed-off-by: Richard Purdie <rpurdie@rpsys.net> + +--- linux-2.6.15/drivers/leds/Kconfig 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Kconfig 1970-01-01 00:00:00.000000000 +0000 +@@ -43,6 +43,15 @@ config LEDS_SPITZ + This option enables support for the LEDs on Sharp Zaurus + SL-Cxx00 series (C1000, C3000, C3100). + ++config LEDS_IXP4XX ++ tristate "LED Support for GPIO connected LEDs on IXP4XX processors" ++ depends LEDS_CLASS && ARCH_IXP4XX ++ help ++ This option enables support for the LEDs connected to GPIO ++ outputs of the Intel IXP4XX processors. To be useful the ++ particular board must have LEDs and they must be connected ++ to the GPIO lines. If unsure, say Y. ++ + config LEDS_TRIGGER_TIMER + tristate "LED Timer Trigger" + depends LEDS_TRIGGERS +--- linux-2.6.15/drivers/leds/Makefile 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Makefile 1970-01-01 00:00:00.000000000 +0000 +@@ -8,6 +8,7 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-trig + obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o + obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o + obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o ++obj-$(CONFIG_LEDS_IXP4XX) += leds-ixp4xx-gpio.o + + # LED Triggers + obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o +--- linux-2.6.15/drivers/leds/leds-ixp4xx-gpio.c 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/leds-ixp4xx-gpio.c 1970-01-01 00:00:00.000000000 +0000 +@@ -0,0 +1,209 @@ ++/* ++ * IXP4XX GPIO driver LED driver ++ * ++ * Author: John Bowler <jbowler@acm.org> ++ * ++ * Copyright (c) 2006 John Bowler ++ * ++ * Permission is hereby granted, free of charge, to any ++ * person obtaining a copy of this software and associated ++ * documentation files (the "Software"), to deal in the ++ * Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, ++ * publish, distribute, sublicense, and/or sell copies of ++ * the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the ++ * following conditions: ++ * ++ * The above copyright notice and this permission notice ++ * shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ++ * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED ++ * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ++ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT ++ * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ++ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/spinlock.h> ++#include <linux/leds.h> ++#include <asm/arch/hardware.h> ++ ++extern spinlock_t gpio_lock; ++ ++/* Up to 16 gpio lines are possible. */ ++#define GPIO_MAX 16 ++static struct ixp4xxgpioled_device { ++ struct led_classdev ancestor; ++ int flags; ++} ixp4xxgpioled_devices[GPIO_MAX]; ++ ++void ixp4xxgpioled_brightness_set(struct led_classdev *pled, enum led_brightness value) ++{ ++ const struct ixp4xxgpioled_device *const ixp4xx_dev = ++ container_of(pled, struct ixp4xxgpioled_device, ancestor); ++ const u32 gpio_pin = ixp4xx_dev - ixp4xxgpioled_devices; ++ ++ if (gpio_pin < GPIO_MAX && ixp4xx_dev->ancestor.name != 0) { ++ /* Set or clear the 'gpio_pin' bit according to the style ++ * and the required setting (value > 0 == on) ++ */ ++ const int gpio_value = ++ (value > 0) == (ixp4xx_dev->flags != IXP4XX_GPIO_LOW) ? ++ IXP4XX_GPIO_HIGH : IXP4XX_GPIO_LOW; ++ ++ { ++ unsigned long flags; ++ spin_lock_irqsave(&gpio_lock, flags); ++ gpio_line_set(gpio_pin, gpio_value); ++ spin_unlock_irqrestore(&gpio_lock, flags); ++ } ++ } ++} ++ ++/* LEDs are described in resources, the following iterates over the valid ++ * LED resources. ++ */ ++#define for_all_leds(i, pdev) \ ++ for (i=0; i<pdev->num_resources; ++i) \ ++ if (pdev->resource[i].start < GPIO_MAX && \ ++ pdev->resource[i].name != 0) ++ ++/* The following applies 'operation' to each LED from the given platform, ++ * the function always returns 0 to allow tail call elimination. ++ */ ++static int apply_to_all_leds(struct platform_device *pdev, ++ void (*operation)(struct led_classdev *pled)) { ++ int i; ++ for_all_leds(i, pdev) ++ operation(&ixp4xxgpioled_devices[pdev->resource[i].start].ancestor); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int ixp4xxgpioled_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ return apply_to_all_leds(pdev, led_classdev_suspend); ++} ++ ++static int ixp4xxgpioled_resume(struct platform_device *pdev) ++{ ++ return apply_to_all_leds(pdev, led_classdev_resume); ++} ++#endif ++ ++static void ixp4xxgpioled_remove_one_led(struct led_classdev *pled) { ++ led_classdev_unregister(pled); ++ pled->name = 0; ++} ++ ++static int ixp4xxgpioled_remove(struct platform_device *pdev) ++{ ++ return apply_to_all_leds(pdev, ixp4xxgpioled_remove_one_led); ++} ++ ++static int ixp4xxgpioled_probe(struct platform_device *pdev) ++{ ++ /* The board level has to tell the driver where the ++ * LEDs are connected - there is no way to find out ++ * electrically. It must also say whether the GPIO ++ * lines are active high or active low. ++ * ++ * To do this read the num_resources (the number of ++ * LEDs) and the struct resource (the data for each ++ * LED). The name comes from the resource, and it ++ * isn't copied. ++ */ ++ int i; ++ for_all_leds(i, pdev) { ++ const u8 gpio_pin = pdev->resource[i].start; ++ int rc; ++ ++ if (ixp4xxgpioled_devices[gpio_pin].ancestor.name == 0) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gpio_lock, flags); ++ gpio_line_config(gpio_pin, IXP4XX_GPIO_OUT); ++ /* The config can, apparently, reset the state, ++ * I suspect the gpio line may be an input and ++ * the config may cause the line to be latched, ++ * so the setting depends on how the LED is ++ * connected to the line (which affects how it ++ * floats if not driven). ++ */ ++ gpio_line_set(gpio_pin, IXP4XX_GPIO_HIGH); ++ spin_unlock_irqrestore(&gpio_lock, flags); ++ ++ ixp4xxgpioled_devices[gpio_pin].flags = ++ pdev->resource[i].flags & IORESOURCE_BITS; ++ ++ ixp4xxgpioled_devices[gpio_pin].ancestor.name = ++ pdev->resource[i].name; ++ ++ /* This is how a board manufacturer makes the LED ++ * come on on reset - the GPIO line will be high, so ++ * make the LED light when the line is low... ++ */ ++ if (ixp4xxgpioled_devices[gpio_pin].flags != IXP4XX_GPIO_LOW) ++ ixp4xxgpioled_devices[gpio_pin].ancestor.brightness = 100; ++ else ++ ixp4xxgpioled_devices[gpio_pin].ancestor.brightness = 0; ++ ++ ixp4xxgpioled_devices[gpio_pin].ancestor.flags = 0; ++ ++ ixp4xxgpioled_devices[gpio_pin].ancestor.brightness_set = ++ ixp4xxgpioled_brightness_set; ++ ++ ixp4xxgpioled_devices[gpio_pin].ancestor.default_trigger = 0; ++ } ++ ++ rc = led_classdev_register(&pdev->dev, ++ &ixp4xxgpioled_devices[gpio_pin].ancestor); ++ if (rc < 0) { ++ ixp4xxgpioled_devices[gpio_pin].ancestor.name = 0; ++ ixp4xxgpioled_remove(pdev); ++ return rc; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct platform_driver ixp4xxgpioled_driver = { ++ .probe = ixp4xxgpioled_probe, ++ .remove = ixp4xxgpioled_remove, ++#ifdef CONFIG_PM ++ .suspend = ixp4xxgpioled_suspend, ++ .resume = ixp4xxgpioled_resume, ++#endif ++ .driver = { ++ .name = "IXP4XX-GPIO-LED", ++ }, ++}; ++ ++static int __devinit ixp4xxgpioled_init(void) ++{ ++ return platform_driver_register(&ixp4xxgpioled_driver); ++} ++ ++static void ixp4xxgpioled_exit(void) ++{ ++ platform_driver_unregister(&ixp4xxgpioled_driver); ++} ++ ++module_init(ixp4xxgpioled_init); ++module_exit(ixp4xxgpioled_exit); ++ ++MODULE_AUTHOR("John Bowler <jbowler@acm.org>"); ++MODULE_DESCRIPTION("IXP4XX GPIO LED driver"); ++MODULE_LICENSE("MIT"); +From: Dirk Opfer <dirk@opfer-online.de> + +Adds LED drivers for LEDs found on the Sharp Zaurus c6000 model (tosa). + +Signed-off-by: Dirk Opfer <dirk@opfer-online.de> +Signed-off-by: Richard Purdie <rpurdie@rpsys.net> + +Index: linux-2.6.15/drivers/leds/Kconfig +=================================================================== +--- linux-2.6.15.orig/drivers/leds/Kconfig 2006-01-30 00:25:28.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Kconfig 2006-01-30 00:25:52.000000000 +0000 +@@ -52,6 +52,13 @@ + particular board must have LEDs and they must be connected + to the GPIO lines. If unsure, say Y. + ++config LEDS_TOSA ++ tristate "LED Support for the Sharp SL-6000 series" ++ depends LEDS_CLASS && PXA_SHARPSL ++ help ++ This option enables support for the LEDs on Sharp Zaurus ++ SL-6000 series. ++ + config LEDS_TRIGGER_TIMER + tristate "LED Timer Trigger" + depends LEDS_TRIGGERS +Index: linux-2.6.15/drivers/leds/Makefile +=================================================================== +--- linux-2.6.15.orig/drivers/leds/Makefile 2006-01-30 00:25:28.000000000 +0000 ++++ linux-2.6.15/drivers/leds/Makefile 2006-01-30 00:26:48.000000000 +0000 +@@ -9,6 +9,7 @@ + obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o + obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o + obj-$(CONFIG_LEDS_IXP4XX) += leds-ixp4xx-gpio.o ++obj-$(CONFIG_LEDS_TOSA) += leds-tosa.o + + # LED Triggers + obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o +Index: linux-2.6.15/drivers/leds/leds-tosa.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.15/drivers/leds/leds-tosa.c 2006-01-30 00:28:15.000000000 +0000 +@@ -0,0 +1,123 @@ ++/* ++ * LED Triggers Core ++ * ++ * Copyright 2005 Dirk Opfer ++ * ++ * Author: Dirk Opfer <Dirk@Opfer-Online.de> ++ * based on spitz.c ++ * ++ * 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/config.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/leds.h> ++#include <asm/hardware/scoop.h> ++#include <asm/mach-types.h> ++#include <asm/arch/hardware.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/tosa.h> ++ ++static void tosaled_amber_set(struct led_classdev *led_cdev, enum led_brightness value) ++{ ++ if (value) ++ set_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_CHRG_ERR_LED); ++ else ++ reset_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_CHRG_ERR_LED); ++} ++ ++static void tosaled_green_set(struct led_classdev *led_cdev, enum led_brightness value) ++{ ++ if (value) ++ set_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_NOTE_LED); ++ else ++ reset_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_NOTE_LED); ++} ++ ++static struct led_classdev tosa_amber_led = { ++ .name = "tosa:amber", ++ .default_trigger = "sharpsl-charge", ++ .brightness_set = tosaled_amber_set, ++}; ++ ++static struct led_classdev tosa_green_led = { ++ .name = "tosa:green", ++ .default_trigger = "nand-disk", ++ .brightness_set = tosaled_green_set, ++}; ++ ++#ifdef CONFIG_PM ++static int tosaled_suspend(struct platform_device *dev, pm_message_t state) ++{ ++#ifdef CONFIG_LEDS_TRIGGERS ++ if (tosa_amber_led.trigger && strcmp(tosa_amber_led.trigger->name, "sharpsl-charge")) ++#endif ++ led_classdev_suspend(&tosa_amber_led); ++ led_classdev_suspend(&tosa_green_led); ++ return 0; ++} ++ ++static int tosaled_resume(struct platform_device *dev) ++{ ++ led_classdev_resume(&tosa_amber_led); ++ led_classdev_resume(&tosa_green_led); ++ return 0; ++} ++#endif ++ ++static int tosaled_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ ret = led_classdev_register(&pdev->dev, &tosa_amber_led); ++ if (ret < 0) ++ return ret; ++ ++ ret = led_classdev_register(&pdev->dev, &tosa_green_led); ++ if (ret < 0) ++ led_classdev_unregister(&tosa_amber_led); ++ ++ return ret; ++} ++ ++static int tosaled_remove(struct platform_device *pdev) ++{ ++ led_classdev_unregister(&tosa_amber_led); ++ led_classdev_unregister(&tosa_green_led); ++ ++ return 0; ++} ++ ++static struct platform_driver tosaled_driver = { ++ .probe = tosaled_probe, ++ .remove = tosaled_remove, ++#ifdef CONFIG_PM ++ .suspend = tosaled_suspend, ++ .resume = tosaled_resume, ++#endif ++ .driver = { ++ .name = "tosa-led", ++ }, ++}; ++ ++static int __devinit tosaled_init(void) ++{ ++ return platform_driver_register(&tosaled_driver); ++} ++ ++static void tosaled_exit(void) ++{ ++ platform_driver_unregister(&tosaled_driver); ++} ++ ++module_init(tosaled_init); ++module_exit(tosaled_exit); ++ ++MODULE_AUTHOR("Dirk Opfer <Dirk@Opfer-Online.de>"); ++MODULE_DESCRIPTION("Tosa LED driver"); ++MODULE_LICENSE("GPL"); +Index: linux-2.6.15/arch/arm/mach-pxa/tosa.c +=================================================================== +--- linux-2.6.15.orig/arch/arm/mach-pxa/tosa.c 2006-01-03 03:21:10.000000000 +0000 ++++ linux-2.6.15/arch/arm/mach-pxa/tosa.c 2006-01-30 00:29:25.000000000 +0000 +@@ -252,10 +252,19 @@ + .id = -1, + }; + ++/* ++ * Tosa LEDs ++ */ ++static struct platform_device tosaled_device = { ++ .name = "tosa-led", ++ .id = -1, ++}; ++ + static struct platform_device *devices[] __initdata = { + &tosascoop_device, + &tosascoop_jc_device, + &tosakbd_device, ++ &tosaled_device, + }; + + static void __init tosa_init(void) +Add an LED trigger for IDE disk activity to the IDE subsystem. + +Signed-off-by: Richard Purdie <rpurdie@rpsys.net> + +Index: linux-2.6.15/drivers/ide/ide-disk.c +=================================================================== +--- linux-2.6.15.orig/drivers/ide/ide-disk.c 2006-02-04 13:35:37.000000000 +0000 ++++ linux-2.6.15/drivers/ide/ide-disk.c 2006-02-04 15:17:18.000000000 +0000 +@@ -60,6 +60,7 @@ + #include <linux/genhd.h> + #include <linux/slab.h> + #include <linux/delay.h> ++#include <linux/leds.h> + + #define _IDE_DISK + +@@ -80,6 +81,8 @@ + + static DECLARE_MUTEX(idedisk_ref_sem); + ++INIT_LED_TRIGGER(ide_led_trigger); ++ + #define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref) + + #define ide_disk_g(disk) \ +@@ -311,10 +314,12 @@ + + if (!blk_fs_request(rq)) { + blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command"); +- ide_end_request(drive, 0, 0); ++ ide_end_rw_disk(drive, 0, 0); + return ide_stopped; + } + ++ led_trigger_event(ide_led_trigger, LED_FULL); ++ + pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n", + drive->name, rq_data_dir(rq) == READ ? "read" : "writ", + block, rq->nr_sectors, (unsigned long)rq->buffer); +@@ -325,6 +330,12 @@ + return __ide_do_rw_disk(drive, rq, block); + } + ++static int ide_end_rw_disk(ide_drive_t *drive, int uptodate, int nr_sectors) ++{ ++ led_trigger_event(ide_led_trigger, LED_OFF); ++ ide_end_request(drive, uptodate, nr_sectors); ++} ++ + /* + * Queries for true maximum capacity of the drive. + * Returns maximum LBA address (> 0) of the drive, 0 if failed. +@@ -1097,7 +1108,7 @@ + .media = ide_disk, + .supports_dsc_overlap = 0, + .do_request = ide_do_rw_disk, +- .end_request = ide_end_request, ++ .end_request = ide_end_rw_disk, + .error = __ide_error, + .abort = __ide_abort, + .proc = idedisk_proc, +@@ -1259,11 +1270,13 @@ + + static void __exit idedisk_exit (void) + { ++ led_trigger_unregister_simple(ide_led_trigger); + driver_unregister(&idedisk_driver.gen_driver); + } + + static int __init idedisk_init(void) + { ++ led_trigger_register_simple("ide-disk", &ide_led_trigger); + return driver_register(&idedisk_driver.gen_driver); + } + +Index: linux-2.6.15/drivers/mtd/nand/nand_base.c +=================================================================== +--- linux-2.6.15.orig/drivers/mtd/nand/nand_base.c 2006-01-29 14:37:20.000000000 +0000 ++++ linux-2.6.15/drivers/mtd/nand/nand_base.c 2006-01-29 15:25:11.000000000 +0000 +@@ -80,6 +80,7 @@ + #include <linux/mtd/compatmac.h> + #include <linux/interrupt.h> + #include <linux/bitops.h> ++#include <linux/leds.h> + #include <asm/io.h> + + #ifdef CONFIG_MTD_PARTITIONS +@@ -515,6 +516,8 @@ + return nand_isbad_bbt (mtd, ofs, allowbbt); + } + ++INIT_LED_TRIGGER(nand_led_trigger); ++ + /* + * Wait for the ready pin, after a command + * The timeout is catched later. +@@ -524,12 +527,14 @@ + struct nand_chip *this = mtd->priv; + unsigned long timeo = jiffies + 2; + ++ led_trigger_event(nand_led_trigger, LED_FULL); + /* wait until command is processed or timeout occures */ + do { + if (this->dev_ready(mtd)) +- return; ++ break; + touch_softlockup_watchdog(); + } while (time_before(jiffies, timeo)); ++ led_trigger_event(nand_led_trigger, LED_OFF); + } + + /** +@@ -817,6 +822,8 @@ + else + timeo += (HZ * 20) / 1000; + ++ led_trigger_event(nand_led_trigger, LED_FULL); ++ + /* Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. */ + ndelay (100); +@@ -840,6 +847,8 @@ + } + cond_resched(); + } ++ led_trigger_event(nand_led_trigger, LED_OFF); ++ + status = (int) this->read_byte(mtd); + return status; + } +@@ -2724,6 +2733,21 @@ + EXPORT_SYMBOL_GPL (nand_scan); + EXPORT_SYMBOL_GPL (nand_release); + ++ ++static int __init nand_base_init(void) ++{ ++ led_trigger_register_simple("nand-disk", &nand_led_trigger); ++ return 0; ++} ++ ++static void nand_base_exit(void) ++{ ++ led_trigger_unregister_simple(nand_led_trigger); ++} ++ ++module_init(nand_base_init); ++module_exit(nand_base_exit); ++ + MODULE_LICENSE ("GPL"); + MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>"); + MODULE_DESCRIPTION ("Generic NAND flash driver code"); |