~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux-2.6.17/drivers/leds/led-triggers.c

Version: ~ [ 2.6.16 ] ~ [ 2.6.17 ] ~
Architecture: ~ [ ia64 ] ~ [ i386 ] ~ [ arm ] ~ [ ppc ] ~ [ sparc64 ] ~

  1 /*
  2  * LED Triggers Core
  3  *
  4  * Copyright 2005-2006 Openedhand Ltd.
  5  *
  6  * Author: Richard Purdie <rpurdie@openedhand.com>
  7  *
  8  * This program is free software; you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License version 2 as
 10  * published by the Free Software Foundation.
 11  *
 12  */
 13 
 14 #include <linux/config.h>
 15 #include <linux/module.h>
 16 #include <linux/kernel.h>
 17 #include <linux/init.h>
 18 #include <linux/list.h>
 19 #include <linux/spinlock.h>
 20 #include <linux/device.h>
 21 #include <linux/sysdev.h>
 22 #include <linux/timer.h>
 23 #include <linux/leds.h>
 24 #include "leds.h"
 25 
 26 /*
 27  * Nests outside led_cdev->trigger_lock
 28  */
 29 static rwlock_t triggers_list_lock = RW_LOCK_UNLOCKED;
 30 static LIST_HEAD(trigger_list);
 31 
 32 ssize_t led_trigger_store(struct class_device *dev, const char *buf,
 33                         size_t count)
 34 {
 35         struct led_classdev *led_cdev = class_get_devdata(dev);
 36         char trigger_name[TRIG_NAME_MAX];
 37         struct led_trigger *trig;
 38         size_t len;
 39 
 40         trigger_name[sizeof(trigger_name) - 1] = '\0';
 41         strncpy(trigger_name, buf, sizeof(trigger_name) - 1);
 42         len = strlen(trigger_name);
 43 
 44         if (len && trigger_name[len - 1] == '\n')
 45                 trigger_name[len - 1] = '\0';
 46 
 47         if (!strcmp(trigger_name, "none")) {
 48                 write_lock(&led_cdev->trigger_lock);
 49                 led_trigger_set(led_cdev, NULL);
 50                 write_unlock(&led_cdev->trigger_lock);
 51                 return count;
 52         }
 53 
 54         read_lock(&triggers_list_lock);
 55         list_for_each_entry(trig, &trigger_list, next_trig) {
 56                 if (!strcmp(trigger_name, trig->name)) {
 57                         write_lock(&led_cdev->trigger_lock);
 58                         led_trigger_set(led_cdev, trig);
 59                         write_unlock(&led_cdev->trigger_lock);
 60 
 61                         read_unlock(&triggers_list_lock);
 62                         return count;
 63                 }
 64         }
 65         read_unlock(&triggers_list_lock);
 66 
 67         return -EINVAL;
 68 }
 69 
 70 
 71 ssize_t led_trigger_show(struct class_device *dev, char *buf)
 72 {
 73         struct led_classdev *led_cdev = class_get_devdata(dev);
 74         struct led_trigger *trig;
 75         int len = 0;
 76 
 77         read_lock(&triggers_list_lock);
 78         read_lock(&led_cdev->trigger_lock);
 79 
 80         if (!led_cdev->trigger)
 81                 len += sprintf(buf+len, "[none] ");
 82         else
 83                 len += sprintf(buf+len, "none ");
 84 
 85         list_for_each_entry(trig, &trigger_list, next_trig) {
 86                 if (led_cdev->trigger && !strcmp(led_cdev->trigger->name,
 87                                                         trig->name))
 88                         len += sprintf(buf+len, "[%s] ", trig->name);
 89                 else
 90                         len += sprintf(buf+len, "%s ", trig->name);
 91         }
 92         read_unlock(&led_cdev->trigger_lock);
 93         read_unlock(&triggers_list_lock);
 94 
 95         len += sprintf(len+buf, "\n");
 96         return len;
 97 }
 98 
 99 void led_trigger_event(struct led_trigger *trigger,
100                         enum led_brightness brightness)
101 {
102         struct list_head *entry;
103 
104         if (!trigger)
105                 return;
106 
107         read_lock(&trigger->leddev_list_lock);
108         list_for_each(entry, &trigger->led_cdevs) {
109                 struct led_classdev *led_cdev;
110 
111                 led_cdev = list_entry(entry, struct led_classdev, trig_list);
112                 led_set_brightness(led_cdev, brightness);
113         }
114         read_unlock(&trigger->leddev_list_lock);
115 }
116 
117 /* Caller must ensure led_cdev->trigger_lock held */
118 void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
119 {
120         unsigned long flags;
121 
122         /* Remove any existing trigger */
123         if (led_cdev->trigger) {
124                 write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
125                 list_del(&led_cdev->trig_list);
126                 write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
127                 if (led_cdev->trigger->deactivate)
128                         led_cdev->trigger->deactivate(led_cdev);
129         }
130         if (trigger) {
131                 write_lock_irqsave(&trigger->leddev_list_lock, flags);
132                 list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs);
133                 write_unlock_irqrestore(&trigger->leddev_list_lock, flags);
134                 if (trigger->activate)
135                         trigger->activate(led_cdev);
136         }
137         led_cdev->trigger = trigger;
138 }
139 
140 void led_trigger_set_default(struct led_classdev *led_cdev)
141 {
142         struct led_trigger *trig;
143 
144         if (!led_cdev->default_trigger)
145                 return;
146 
147         read_lock(&triggers_list_lock);
148         write_lock(&led_cdev->trigger_lock);
149         list_for_each_entry(trig, &trigger_list, next_trig) {
150                 if (!strcmp(led_cdev->default_trigger, trig->name))
151                         led_trigger_set(led_cdev, trig);
152         }
153         write_unlock(&led_cdev->trigger_lock);
154         read_unlock(&triggers_list_lock);
155 }
156 
157 int led_trigger_register(struct led_trigger *trigger)
158 {
159         struct led_classdev *led_cdev;
160 
161         rwlock_init(&trigger->leddev_list_lock);
162         INIT_LIST_HEAD(&trigger->led_cdevs);
163 
164         /* Add to the list of led triggers */
165         write_lock(&triggers_list_lock);
166         list_add_tail(&trigger->next_trig, &trigger_list);
167         write_unlock(&triggers_list_lock);
168 
169         /* Register with any LEDs that have this as a default trigger */
170         read_lock(&leds_list_lock);
171         list_for_each_entry(led_cdev, &leds_list, node) {
172                 write_lock(&led_cdev->trigger_lock);
173                 if (!led_cdev->trigger && led_cdev->default_trigger &&
174                             !strcmp(led_cdev->default_trigger, trigger->name))
175                         led_trigger_set(led_cdev, trigger);
176                 write_unlock(&led_cdev->trigger_lock);
177         }
178         read_unlock(&leds_list_lock);
179 
180         return 0;
181 }
182 
183 void led_trigger_register_simple(const char *name, struct led_trigger **tp)
184 {
185         struct led_trigger *trigger;
186 
187         trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
188 
189         if (trigger) {
190                 trigger->name = name;
191                 led_trigger_register(trigger);
192         }
193         *tp = trigger;
194 }
195 
196 void led_trigger_unregister(struct led_trigger *trigger)
197 {
198         struct led_classdev *led_cdev;
199 
200         /* Remove from the list of led triggers */
201         write_lock(&triggers_list_lock);
202         list_del(&trigger->next_trig);
203         write_unlock(&triggers_list_lock);
204 
205         /* Remove anyone actively using this trigger */
206         read_lock(&leds_list_lock);
207         list_for_each_entry(led_cdev, &leds_list, node) {
208                 write_lock(&led_cdev->trigger_lock);
209                 if (led_cdev->trigger == trigger)
210                         led_trigger_set(led_cdev, NULL);
211                 write_unlock(&led_cdev->trigger_lock);
212         }
213         read_unlock(&leds_list_lock);
214 }
215 
216 void led_trigger_unregister_simple(struct led_trigger *trigger)
217 {
218         led_trigger_unregister(trigger);
219         kfree(trigger);
220 }
221 
222 /* Used by LED Class */
223 EXPORT_SYMBOL_GPL(led_trigger_set);
224 EXPORT_SYMBOL_GPL(led_trigger_set_default);
225 EXPORT_SYMBOL_GPL(led_trigger_show);
226 EXPORT_SYMBOL_GPL(led_trigger_store);
227 
228 /* LED Trigger Interface */
229 EXPORT_SYMBOL_GPL(led_trigger_register);
230 EXPORT_SYMBOL_GPL(led_trigger_unregister);
231 
232 /* Simple LED Tigger Interface */
233 EXPORT_SYMBOL_GPL(led_trigger_register_simple);
234 EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
235 EXPORT_SYMBOL_GPL(led_trigger_event);
236 
237 MODULE_AUTHOR("Richard Purdie");
238 MODULE_LICENSE("GPL");
239 MODULE_DESCRIPTION("LED Triggers Core");
240 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.