summaryrefslogtreecommitdiff
path: root/packages/linux/ixp4xx-kernel/2.6.16/leds-class.patch
diff options
context:
space:
mode:
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.patch2069
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");