X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fleds%2Fled-triggers.c;h=d8ddd9ef89949da41b8b7b1f9e840b302772ff19;hb=8164491dd628ffcac5d61267f747997689ee256c;hp=47f0ff196328d2808268a17701444b08faafee1a;hpb=6ab3d5624e172c553004ecc862bfeac16d9d68b7;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 47f0ff1..d8ddd9e 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -1,7 +1,7 @@ /* * LED Triggers Core * - * Copyright 2005-2006 Openedhand Ltd. + * Copyright 2005-2007 Openedhand Ltd. * * Author: Richard Purdie * @@ -19,19 +19,22 @@ #include #include #include +#include #include #include "leds.h" /* * Nests outside led_cdev->trigger_lock */ -static DEFINE_RWLOCK(triggers_list_lock); +static DECLARE_RWSEM(triggers_list_lock); static LIST_HEAD(trigger_list); -ssize_t led_trigger_store(struct class_device *dev, const char *buf, - size_t count) + /* Used by LED Class */ + +ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct led_classdev *led_cdev = class_get_devdata(dev); + struct led_classdev *led_cdev = dev_get_drvdata(dev); char trigger_name[TRIG_NAME_MAX]; struct led_trigger *trig; size_t len; @@ -44,37 +47,36 @@ ssize_t led_trigger_store(struct class_device *dev, const char *buf, trigger_name[len - 1] = '\0'; if (!strcmp(trigger_name, "none")) { - write_lock(&led_cdev->trigger_lock); - led_trigger_set(led_cdev, NULL); - write_unlock(&led_cdev->trigger_lock); + led_trigger_remove(led_cdev); return count; } - read_lock(&triggers_list_lock); + down_read(&triggers_list_lock); list_for_each_entry(trig, &trigger_list, next_trig) { if (!strcmp(trigger_name, trig->name)) { - write_lock(&led_cdev->trigger_lock); + down_write(&led_cdev->trigger_lock); led_trigger_set(led_cdev, trig); - write_unlock(&led_cdev->trigger_lock); + up_write(&led_cdev->trigger_lock); - read_unlock(&triggers_list_lock); + up_read(&triggers_list_lock); return count; } } - read_unlock(&triggers_list_lock); + up_read(&triggers_list_lock); return -EINVAL; } +EXPORT_SYMBOL_GPL(led_trigger_store); - -ssize_t led_trigger_show(struct class_device *dev, char *buf) +ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct led_classdev *led_cdev = class_get_devdata(dev); + struct led_classdev *led_cdev = dev_get_drvdata(dev); struct led_trigger *trig; int len = 0; - read_lock(&triggers_list_lock); - read_lock(&led_cdev->trigger_lock); + down_read(&triggers_list_lock); + down_read(&led_cdev->trigger_lock); if (!led_cdev->trigger) len += sprintf(buf+len, "[none] "); @@ -88,30 +90,13 @@ ssize_t led_trigger_show(struct class_device *dev, char *buf) else len += sprintf(buf+len, "%s ", trig->name); } - read_unlock(&led_cdev->trigger_lock); - read_unlock(&triggers_list_lock); + up_read(&led_cdev->trigger_lock); + up_read(&triggers_list_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); - led_set_brightness(led_cdev, brightness); - } - read_unlock(&trigger->leddev_list_lock); -} +EXPORT_SYMBOL_GPL(led_trigger_show); /* Caller must ensure led_cdev->trigger_lock held */ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) @@ -122,19 +107,31 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) if (led_cdev->trigger) { write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags); list_del(&led_cdev->trig_list); - write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags); + write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, + flags); if (led_cdev->trigger->deactivate) led_cdev->trigger->deactivate(led_cdev); + led_cdev->trigger = NULL; + led_set_brightness(led_cdev, LED_OFF); } if (trigger) { write_lock_irqsave(&trigger->leddev_list_lock, flags); list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs); write_unlock_irqrestore(&trigger->leddev_list_lock, flags); + led_cdev->trigger = trigger; if (trigger->activate) trigger->activate(led_cdev); } - led_cdev->trigger = trigger; } +EXPORT_SYMBOL_GPL(led_trigger_set); + +void led_trigger_remove(struct led_classdev *led_cdev) +{ + down_write(&led_cdev->trigger_lock); + led_trigger_set(led_cdev, NULL); + up_write(&led_cdev->trigger_lock); +} +EXPORT_SYMBOL_GPL(led_trigger_remove); void led_trigger_set_default(struct led_classdev *led_cdev) { @@ -143,95 +140,124 @@ void led_trigger_set_default(struct led_classdev *led_cdev) if (!led_cdev->default_trigger) return; - read_lock(&triggers_list_lock); - write_lock(&led_cdev->trigger_lock); + down_read(&triggers_list_lock); + down_write(&led_cdev->trigger_lock); list_for_each_entry(trig, &trigger_list, next_trig) { if (!strcmp(led_cdev->default_trigger, trig->name)) led_trigger_set(led_cdev, trig); } - write_unlock(&led_cdev->trigger_lock); - read_unlock(&triggers_list_lock); + up_write(&led_cdev->trigger_lock); + up_read(&triggers_list_lock); } +EXPORT_SYMBOL_GPL(led_trigger_set_default); + +/* LED Trigger Interface */ int led_trigger_register(struct led_trigger *trigger) { struct led_classdev *led_cdev; + struct led_trigger *trig; rwlock_init(&trigger->leddev_list_lock); INIT_LIST_HEAD(&trigger->led_cdevs); + down_write(&triggers_list_lock); + /* Make sure the trigger's name isn't already in use */ + list_for_each_entry(trig, &trigger_list, next_trig) { + if (!strcmp(trig->name, trigger->name)) { + up_write(&triggers_list_lock); + return -EEXIST; + } + } /* 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); + up_write(&triggers_list_lock); /* Register with any LEDs that have this as a default trigger */ - read_lock(&leds_list_lock); + down_read(&leds_list_lock); list_for_each_entry(led_cdev, &leds_list, node) { - write_lock(&led_cdev->trigger_lock); + down_write(&led_cdev->trigger_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->trigger_lock); + up_write(&led_cdev->trigger_lock); } - read_unlock(&leds_list_lock); + up_read(&leds_list_lock); 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; -} +EXPORT_SYMBOL_GPL(led_trigger_register); 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); + down_write(&triggers_list_lock); list_del(&trigger->next_trig); - write_unlock(&triggers_list_lock); + up_write(&triggers_list_lock); /* Remove anyone actively using this trigger */ - read_lock(&leds_list_lock); + down_read(&leds_list_lock); list_for_each_entry(led_cdev, &leds_list, node) { - write_lock(&led_cdev->trigger_lock); + down_write(&led_cdev->trigger_lock); if (led_cdev->trigger == trigger) led_trigger_set(led_cdev, NULL); - write_unlock(&led_cdev->trigger_lock); + up_write(&led_cdev->trigger_lock); } - read_unlock(&leds_list_lock); + up_read(&leds_list_lock); } +EXPORT_SYMBOL_GPL(led_trigger_unregister); -void led_trigger_unregister_simple(struct led_trigger *trigger) +/* Simple LED Tigger Interface */ + +void led_trigger_event(struct led_trigger *trigger, + enum led_brightness brightness) { - led_trigger_unregister(trigger); - kfree(trigger); + 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); + led_set_brightness(led_cdev, brightness); + } + read_unlock(&trigger->leddev_list_lock); } +EXPORT_SYMBOL_GPL(led_trigger_event); -/* 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); +void led_trigger_register_simple(const char *name, struct led_trigger **tp) +{ + struct led_trigger *trigger; + int err; -/* LED Trigger Interface */ -EXPORT_SYMBOL_GPL(led_trigger_register); -EXPORT_SYMBOL_GPL(led_trigger_unregister); + trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); -/* Simple LED Tigger Interface */ + if (trigger) { + trigger->name = name; + err = led_trigger_register(trigger); + if (err < 0) + printk(KERN_WARNING "LED trigger %s failed to register" + " (%d)\n", name, err); + } else + printk(KERN_WARNING "LED trigger %s failed to register" + " (no memory)\n", name); + + *tp = trigger; +} EXPORT_SYMBOL_GPL(led_trigger_register_simple); + +void led_trigger_unregister_simple(struct led_trigger *trigger) +{ + if (trigger) + led_trigger_unregister(trigger); + kfree(trigger); +} EXPORT_SYMBOL_GPL(led_trigger_unregister_simple); -EXPORT_SYMBOL_GPL(led_trigger_event); MODULE_AUTHOR("Richard Purdie"); MODULE_LICENSE("GPL");