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_