Index: linux-2.6.15-rc2/drivers/leds/led-triggers.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.15-rc2/drivers/leds/led-triggers.c	2005-11-28 16:10:29.000000000 +0000
@@ -0,0 +1,240 @@
+/*
+ * LED Triggers 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.
+ *
+ */
+
+#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_device *led_dev = 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_dev->lock);
+		led_trigger_set(led_dev, NULL);
+		write_unlock(&led_dev->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_dev->lock);
+			led_trigger_set(led_dev, trig);
+			write_unlock(&led_dev->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_device *led_dev = dev->class_data;
+	struct led_trigger *trig;
+	int len = 0;
+
+	read_lock(&led_dev->lock);
+
+	if (!led_dev->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_dev->trigger && !strcmp(led_dev->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_dev->lock);
+
+	len += sprintf(len+buf, "\n");
+	return len;
+}
+
+void led_trigger_event(struct led_trigger *trigger, int event)
+{
+	struct list_head *entry;
+
+	if (!trigger)
+		return;
+
+	read_lock(&trigger->led_devs);
+	list_for_each(entry, &trigger->led_devs) {
+		struct led_device *led_dev;
+
+		led_dev = list_entry(entry, struct led_device, trig_list);
+		read_lock(&led_dev->lock);
+		if (event)
+			led_dev->brightness_set(led_dev, 100);
+		else
+			led_dev->brightness_set(led_dev, 0);
+
+		read_unlock(&led_dev->lock);
+	}
+	read_unlock(&trigger->led_devs);
+}
+
+/* Caller must ensure led_dev->lock held for write */
+void led_trigger_set(struct led_device *led_dev, struct led_trigger *trigger)
+{
+	/* Remove any existing trigger */
+	if (led_dev->trigger) {
+		write_lock(&led_dev->trigger->leddev_list_lock);
+		list_del(&led_dev->trig_list);
+		write_unlock(&led_dev->trigger->leddev_list_lock);
+		if (led_dev->trigger->deactivate)
+			led_dev->trigger->deactivate(led_dev);
+
+	}
+	if (trigger) {
+		write_lock(&trigger->leddev_list_lock);
+		list_add_tail(&led_dev->trig_list, &trigger->led_devs);
+		write_unlock(&trigger->leddev_list_lock);
+		if (trigger->activate)
+			trigger->activate(led_dev);
+	}
+	led_dev->trigger = trigger;
+}
+
+void led_trigger_set_default(struct led_device *led_dev)
+{
+	struct led_trigger *trig;
+
+	if (!led_dev->default_trigger)
+		return;
+
+	write_lock(&led_dev->lock);
+	read_lock(&triggers_list_lock);
+	list_for_each_entry(trig, &trigger_list, next_trig) {
+		if (!strcmp(led_dev->default_trigger, trig->name))
+			led_trigger_set(led_dev, trig);
+	}
+	read_unlock(&triggers_list_lock);
+	write_unlock(&led_dev->lock);
+}
+
+int led_trigger_register(struct led_trigger *trigger)
+{
+	struct led_device *led_dev;
+
+	rwlock_init(&trigger->leddev_list_lock);
+	INIT_LIST_HEAD(&trigger->led_devs);
+
+	/* 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_dev, &leds_list, node) {
+		write_lock(&led_dev->lock);
+		if (!led_dev->trigger && led_dev->default_trigger &&
+				!strcmp(led_dev->default_trigger, trigger->name))
+			led_trigger_set(led_dev, trigger);
+		write_unlock(&led_dev->lock);
+	}
+	read_unlock(&leds_list);
+
+	return 0;
+}
+
+void led_trigger_register_simple(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_device *led_dev;
+
+	/* 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_dev, &leds_list, node) {
+		write_lock(&led_dev->lock);
+		if (led_dev->trigger == trigger)
+			led_trigger_set(led_dev, NULL);
+		write_unlock(&led_dev->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");
+

