Blame view
drivers/leds/led-triggers.c
7.28 KB
c3bc9956e [PATCH] LED: add ... |
1 2 3 |
/* * LED Triggers Core * |
f8a7c6fe1 leds: Convert fro... |
4 |
* Copyright 2005-2007 Openedhand Ltd. |
c3bc9956e [PATCH] LED: add ... |
5 6 7 8 9 10 11 12 |
* * 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. * */ |
c3bc9956e [PATCH] LED: add ... |
13 14 15 16 17 18 |
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/list.h> #include <linux/spinlock.h> #include <linux/device.h> |
c3bc9956e [PATCH] LED: add ... |
19 |
#include <linux/timer.h> |
dc47206e5 leds: Fix led tri... |
20 |
#include <linux/rwsem.h> |
c3bc9956e [PATCH] LED: add ... |
21 |
#include <linux/leds.h> |
5a0e3ad6a include cleanup: ... |
22 |
#include <linux/slab.h> |
c3bc9956e [PATCH] LED: add ... |
23 24 25 26 27 |
#include "leds.h" /* * Nests outside led_cdev->trigger_lock */ |
dc47206e5 leds: Fix led tri... |
28 |
static DECLARE_RWSEM(triggers_list_lock); |
c3bc9956e [PATCH] LED: add ... |
29 |
static LIST_HEAD(trigger_list); |
4d404fd5c leds: Cleanup var... |
30 |
/* Used by LED Class */ |
f8a7c6fe1 leds: Convert fro... |
31 32 |
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
c3bc9956e [PATCH] LED: add ... |
33 |
{ |
f8a7c6fe1 leds: Convert fro... |
34 |
struct led_classdev *led_cdev = dev_get_drvdata(dev); |
c3bc9956e [PATCH] LED: add ... |
35 36 37 38 39 40 41 42 43 44 45 46 47 |
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] == ' ') trigger_name[len - 1] = '\0'; if (!strcmp(trigger_name, "none")) { |
0013b23d6 leds: disable tri... |
48 |
led_trigger_remove(led_cdev); |
c3bc9956e [PATCH] LED: add ... |
49 50 |
return count; } |
dc47206e5 leds: Fix led tri... |
51 |
down_read(&triggers_list_lock); |
c3bc9956e [PATCH] LED: add ... |
52 53 |
list_for_each_entry(trig, &trigger_list, next_trig) { if (!strcmp(trigger_name, trig->name)) { |
dc47206e5 leds: Fix led tri... |
54 |
down_write(&led_cdev->trigger_lock); |
c3bc9956e [PATCH] LED: add ... |
55 |
led_trigger_set(led_cdev, trig); |
dc47206e5 leds: Fix led tri... |
56 |
up_write(&led_cdev->trigger_lock); |
c3bc9956e [PATCH] LED: add ... |
57 |
|
dc47206e5 leds: Fix led tri... |
58 |
up_read(&triggers_list_lock); |
c3bc9956e [PATCH] LED: add ... |
59 60 61 |
return count; } } |
dc47206e5 leds: Fix led tri... |
62 |
up_read(&triggers_list_lock); |
c3bc9956e [PATCH] LED: add ... |
63 64 65 |
return -EINVAL; } |
4d404fd5c leds: Cleanup var... |
66 |
EXPORT_SYMBOL_GPL(led_trigger_store); |
c3bc9956e [PATCH] LED: add ... |
67 |
|
f8a7c6fe1 leds: Convert fro... |
68 69 |
ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr, char *buf) |
c3bc9956e [PATCH] LED: add ... |
70 |
{ |
f8a7c6fe1 leds: Convert fro... |
71 |
struct led_classdev *led_cdev = dev_get_drvdata(dev); |
c3bc9956e [PATCH] LED: add ... |
72 73 |
struct led_trigger *trig; int len = 0; |
dc47206e5 leds: Fix led tri... |
74 75 |
down_read(&triggers_list_lock); down_read(&led_cdev->trigger_lock); |
c3bc9956e [PATCH] LED: add ... |
76 77 78 79 80 81 82 83 84 85 86 87 88 |
if (!led_cdev->trigger) len += sprintf(buf+len, "[none] "); else len += sprintf(buf+len, "none "); 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); } |
dc47206e5 leds: Fix led tri... |
89 90 |
up_read(&led_cdev->trigger_lock); up_read(&triggers_list_lock); |
c3bc9956e [PATCH] LED: add ... |
91 92 93 94 95 |
len += sprintf(len+buf, " "); return len; } |
4d404fd5c leds: Cleanup var... |
96 |
EXPORT_SYMBOL_GPL(led_trigger_show); |
c3bc9956e [PATCH] LED: add ... |
97 98 99 100 101 102 103 104 105 106 |
/* Caller must ensure led_cdev->trigger_lock held */ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) { unsigned long flags; /* Remove any existing trigger */ if (led_cdev->trigger) { write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags); list_del(&led_cdev->trig_list); |
4d404fd5c leds: Cleanup var... |
107 108 |
write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags); |
c3bc9956e [PATCH] LED: add ... |
109 110 |
if (led_cdev->trigger->deactivate) led_cdev->trigger->deactivate(led_cdev); |
fe3025b55 leds: Ensure led-... |
111 |
led_cdev->trigger = NULL; |
5ada28bf7 led-class: always... |
112 |
led_brightness_set(led_cdev, LED_OFF); |
c3bc9956e [PATCH] LED: add ... |
113 114 115 116 117 |
} 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); |
fe3025b55 leds: Ensure led-... |
118 |
led_cdev->trigger = trigger; |
c3bc9956e [PATCH] LED: add ... |
119 120 121 |
if (trigger->activate) trigger->activate(led_cdev); } |
c3bc9956e [PATCH] LED: add ... |
122 |
} |
4d404fd5c leds: Cleanup var... |
123 |
EXPORT_SYMBOL_GPL(led_trigger_set); |
c3bc9956e [PATCH] LED: add ... |
124 |
|
0013b23d6 leds: disable tri... |
125 126 127 128 129 130 |
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); } |
4d404fd5c leds: Cleanup var... |
131 |
EXPORT_SYMBOL_GPL(led_trigger_remove); |
0013b23d6 leds: disable tri... |
132 |
|
c3bc9956e [PATCH] LED: add ... |
133 134 135 136 137 138 |
void led_trigger_set_default(struct led_classdev *led_cdev) { struct led_trigger *trig; if (!led_cdev->default_trigger) return; |
dc47206e5 leds: Fix led tri... |
139 140 |
down_read(&triggers_list_lock); down_write(&led_cdev->trigger_lock); |
c3bc9956e [PATCH] LED: add ... |
141 142 143 144 |
list_for_each_entry(trig, &trigger_list, next_trig) { if (!strcmp(led_cdev->default_trigger, trig->name)) led_trigger_set(led_cdev, trig); } |
dc47206e5 leds: Fix led tri... |
145 146 |
up_write(&led_cdev->trigger_lock); up_read(&triggers_list_lock); |
c3bc9956e [PATCH] LED: add ... |
147 |
} |
4d404fd5c leds: Cleanup var... |
148 149 150 |
EXPORT_SYMBOL_GPL(led_trigger_set_default); /* LED Trigger Interface */ |
c3bc9956e [PATCH] LED: add ... |
151 152 153 154 |
int led_trigger_register(struct led_trigger *trigger) { struct led_classdev *led_cdev; |
700c6ea22 leds: Prevent mul... |
155 |
struct led_trigger *trig; |
c3bc9956e [PATCH] LED: add ... |
156 157 158 |
rwlock_init(&trigger->leddev_list_lock); INIT_LIST_HEAD(&trigger->led_cdevs); |
dc47206e5 leds: Fix led tri... |
159 |
down_write(&triggers_list_lock); |
700c6ea22 leds: Prevent mul... |
160 161 162 163 164 165 166 167 |
/* 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 */ |
c3bc9956e [PATCH] LED: add ... |
168 |
list_add_tail(&trigger->next_trig, &trigger_list); |
dc47206e5 leds: Fix led tri... |
169 |
up_write(&triggers_list_lock); |
c3bc9956e [PATCH] LED: add ... |
170 171 |
/* Register with any LEDs that have this as a default trigger */ |
72f8da329 leds: Fix leds_li... |
172 |
down_read(&leds_list_lock); |
c3bc9956e [PATCH] LED: add ... |
173 |
list_for_each_entry(led_cdev, &leds_list, node) { |
dc47206e5 leds: Fix led tri... |
174 |
down_write(&led_cdev->trigger_lock); |
c3bc9956e [PATCH] LED: add ... |
175 176 177 |
if (!led_cdev->trigger && led_cdev->default_trigger && !strcmp(led_cdev->default_trigger, trigger->name)) led_trigger_set(led_cdev, trigger); |
dc47206e5 leds: Fix led tri... |
178 |
up_write(&led_cdev->trigger_lock); |
c3bc9956e [PATCH] LED: add ... |
179 |
} |
72f8da329 leds: Fix leds_li... |
180 |
up_read(&leds_list_lock); |
c3bc9956e [PATCH] LED: add ... |
181 182 183 |
return 0; } |
4d404fd5c leds: Cleanup var... |
184 |
EXPORT_SYMBOL_GPL(led_trigger_register); |
c3bc9956e [PATCH] LED: add ... |
185 186 187 188 189 190 |
void led_trigger_unregister(struct led_trigger *trigger) { struct led_classdev *led_cdev; /* Remove from the list of led triggers */ |
dc47206e5 leds: Fix led tri... |
191 |
down_write(&triggers_list_lock); |
c3bc9956e [PATCH] LED: add ... |
192 |
list_del(&trigger->next_trig); |
dc47206e5 leds: Fix led tri... |
193 |
up_write(&triggers_list_lock); |
c3bc9956e [PATCH] LED: add ... |
194 195 |
/* Remove anyone actively using this trigger */ |
72f8da329 leds: Fix leds_li... |
196 |
down_read(&leds_list_lock); |
c3bc9956e [PATCH] LED: add ... |
197 |
list_for_each_entry(led_cdev, &leds_list, node) { |
dc47206e5 leds: Fix led tri... |
198 |
down_write(&led_cdev->trigger_lock); |
c3bc9956e [PATCH] LED: add ... |
199 200 |
if (led_cdev->trigger == trigger) led_trigger_set(led_cdev, NULL); |
dc47206e5 leds: Fix led tri... |
201 |
up_write(&led_cdev->trigger_lock); |
c3bc9956e [PATCH] LED: add ... |
202 |
} |
72f8da329 leds: Fix leds_li... |
203 |
up_read(&leds_list_lock); |
c3bc9956e [PATCH] LED: add ... |
204 |
} |
4d404fd5c leds: Cleanup var... |
205 |
EXPORT_SYMBOL_GPL(led_trigger_unregister); |
c3bc9956e [PATCH] LED: add ... |
206 |
|
4d404fd5c leds: Cleanup var... |
207 208 209 210 |
/* Simple LED Tigger Interface */ void led_trigger_event(struct led_trigger *trigger, enum led_brightness brightness) |
c3bc9956e [PATCH] LED: add ... |
211 |
{ |
4d404fd5c leds: Cleanup var... |
212 213 214 215 216 217 218 219 220 221 222 223 224 |
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); |
c3bc9956e [PATCH] LED: add ... |
225 |
} |
4d404fd5c leds: Cleanup var... |
226 |
EXPORT_SYMBOL_GPL(led_trigger_event); |
c3bc9956e [PATCH] LED: add ... |
227 |
|
0b9536c95 leds: Add ability... |
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
void led_trigger_blink(struct led_trigger *trigger, unsigned long *delay_on, unsigned long *delay_off) { 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_blink_set(led_cdev, delay_on, delay_off); } read_unlock(&trigger->leddev_list_lock); } EXPORT_SYMBOL_GPL(led_trigger_blink); |
4d404fd5c leds: Cleanup var... |
247 248 249 250 |
void led_trigger_register_simple(const char *name, struct led_trigger **tp) { struct led_trigger *trigger; int err; |
c3bc9956e [PATCH] LED: add ... |
251 |
|
4d404fd5c leds: Cleanup var... |
252 |
trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); |
c3bc9956e [PATCH] LED: add ... |
253 |
|
4d404fd5c leds: Cleanup var... |
254 255 256 |
if (trigger) { trigger->name = name; err = led_trigger_register(trigger); |
cba4c2ac0 drivers/leds/led-... |
257 258 259 |
if (err < 0) { kfree(trigger); trigger = NULL; |
4d404fd5c leds: Cleanup var... |
260 261 262 |
printk(KERN_WARNING "LED trigger %s failed to register" " (%d) ", name, err); |
cba4c2ac0 drivers/leds/led-... |
263 |
} |
4d404fd5c leds: Cleanup var... |
264 265 266 267 268 269 270 |
} else printk(KERN_WARNING "LED trigger %s failed to register" " (no memory) ", name); *tp = trigger; } |
c3bc9956e [PATCH] LED: add ... |
271 |
EXPORT_SYMBOL_GPL(led_trigger_register_simple); |
4d404fd5c leds: Cleanup var... |
272 273 274 275 276 277 278 |
void led_trigger_unregister_simple(struct led_trigger *trigger) { if (trigger) led_trigger_unregister(trigger); kfree(trigger); } |
c3bc9956e [PATCH] LED: add ... |
279 |
EXPORT_SYMBOL_GPL(led_trigger_unregister_simple); |
c3bc9956e [PATCH] LED: add ... |
280 281 282 283 |
MODULE_AUTHOR("Richard Purdie"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("LED Triggers Core"); |