leds: bcm6358: remove unneeded busy status check
[deliverable/linux.git] / drivers / leds / led-triggers.c
CommitLineData
c3bc9956
RP
1/*
2 * LED Triggers Core
3 *
f8a7c6fe 4 * Copyright 2005-2007 Openedhand Ltd.
c3bc9956
RP
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
c3bc9956
RP
14#include <linux/module.h>
15#include <linux/kernel.h>
c3bc9956
RP
16#include <linux/list.h>
17#include <linux/spinlock.h>
18#include <linux/device.h>
c3bc9956 19#include <linux/timer.h>
dc47206e 20#include <linux/rwsem.h>
c3bc9956 21#include <linux/leds.h>
5a0e3ad6 22#include <linux/slab.h>
c3bc9956
RP
23#include "leds.h"
24
25/*
26 * Nests outside led_cdev->trigger_lock
27 */
dc47206e 28static DECLARE_RWSEM(triggers_list_lock);
c3bc9956
RP
29static LIST_HEAD(trigger_list);
30
4d404fd5
NM
31 /* Used by LED Class */
32
f8a7c6fe
RP
33ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
34 const char *buf, size_t count)
c3bc9956 35{
f8a7c6fe 36 struct led_classdev *led_cdev = dev_get_drvdata(dev);
c3bc9956
RP
37 char trigger_name[TRIG_NAME_MAX];
38 struct led_trigger *trig;
39 size_t len;
acd899e4
JA
40 int ret = count;
41
42 mutex_lock(&led_cdev->led_access);
43
44 if (led_sysfs_is_disabled(led_cdev)) {
45 ret = -EBUSY;
46 goto unlock;
47 }
c3bc9956
RP
48
49 trigger_name[sizeof(trigger_name) - 1] = '\0';
50 strncpy(trigger_name, buf, sizeof(trigger_name) - 1);
51 len = strlen(trigger_name);
52
53 if (len && trigger_name[len - 1] == '\n')
54 trigger_name[len - 1] = '\0';
55
56 if (!strcmp(trigger_name, "none")) {
0013b23d 57 led_trigger_remove(led_cdev);
acd899e4 58 goto unlock;
c3bc9956
RP
59 }
60
dc47206e 61 down_read(&triggers_list_lock);
c3bc9956
RP
62 list_for_each_entry(trig, &trigger_list, next_trig) {
63 if (!strcmp(trigger_name, trig->name)) {
dc47206e 64 down_write(&led_cdev->trigger_lock);
c3bc9956 65 led_trigger_set(led_cdev, trig);
dc47206e 66 up_write(&led_cdev->trigger_lock);
c3bc9956 67
dc47206e 68 up_read(&triggers_list_lock);
acd899e4 69 goto unlock;
c3bc9956
RP
70 }
71 }
dc47206e 72 up_read(&triggers_list_lock);
c3bc9956 73
acd899e4
JA
74unlock:
75 mutex_unlock(&led_cdev->led_access);
76 return ret;
c3bc9956 77}
4d404fd5 78EXPORT_SYMBOL_GPL(led_trigger_store);
c3bc9956 79
f8a7c6fe
RP
80ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
81 char *buf)
c3bc9956 82{
f8a7c6fe 83 struct led_classdev *led_cdev = dev_get_drvdata(dev);
c3bc9956
RP
84 struct led_trigger *trig;
85 int len = 0;
86
dc47206e
RP
87 down_read(&triggers_list_lock);
88 down_read(&led_cdev->trigger_lock);
c3bc9956
RP
89
90 if (!led_cdev->trigger)
91 len += sprintf(buf+len, "[none] ");
92 else
93 len += sprintf(buf+len, "none ");
94
95 list_for_each_entry(trig, &trigger_list, next_trig) {
96 if (led_cdev->trigger && !strcmp(led_cdev->trigger->name,
97 trig->name))
98 len += sprintf(buf+len, "[%s] ", trig->name);
99 else
100 len += sprintf(buf+len, "%s ", trig->name);
101 }
dc47206e
RP
102 up_read(&led_cdev->trigger_lock);
103 up_read(&triggers_list_lock);
c3bc9956
RP
104
105 len += sprintf(len+buf, "\n");
106 return len;
107}
4d404fd5 108EXPORT_SYMBOL_GPL(led_trigger_show);
c3bc9956
RP
109
110/* Caller must ensure led_cdev->trigger_lock held */
eb202621 111void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
c3bc9956
RP
112{
113 unsigned long flags;
52c47742
CC
114 char *event = NULL;
115 char *envp[2];
116 const char *name;
117
118 name = trig ? trig->name : "none";
119 event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name);
c3bc9956
RP
120
121 /* Remove any existing trigger */
122 if (led_cdev->trigger) {
123 write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
124 list_del(&led_cdev->trig_list);
4d404fd5
NM
125 write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
126 flags);
d23a22a7
FB
127 cancel_work_sync(&led_cdev->set_brightness_work);
128 led_stop_software_blink(led_cdev);
c3bc9956
RP
129 if (led_cdev->trigger->deactivate)
130 led_cdev->trigger->deactivate(led_cdev);
fe3025b5 131 led_cdev->trigger = NULL;
19cd67e2 132 led_set_brightness(led_cdev, LED_OFF);
c3bc9956 133 }
eb202621
BW
134 if (trig) {
135 write_lock_irqsave(&trig->leddev_list_lock, flags);
136 list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
137 write_unlock_irqrestore(&trig->leddev_list_lock, flags);
138 led_cdev->trigger = trig;
139 if (trig->activate)
140 trig->activate(led_cdev);
c3bc9956 141 }
52c47742
CC
142
143 if (event) {
144 envp[0] = event;
145 envp[1] = NULL;
146 kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp);
147 kfree(event);
148 }
c3bc9956 149}
4d404fd5 150EXPORT_SYMBOL_GPL(led_trigger_set);
c3bc9956 151
0013b23d
NM
152void led_trigger_remove(struct led_classdev *led_cdev)
153{
154 down_write(&led_cdev->trigger_lock);
155 led_trigger_set(led_cdev, NULL);
156 up_write(&led_cdev->trigger_lock);
157}
4d404fd5 158EXPORT_SYMBOL_GPL(led_trigger_remove);
0013b23d 159
c3bc9956
RP
160void led_trigger_set_default(struct led_classdev *led_cdev)
161{
162 struct led_trigger *trig;
163
164 if (!led_cdev->default_trigger)
165 return;
166
dc47206e
RP
167 down_read(&triggers_list_lock);
168 down_write(&led_cdev->trigger_lock);
c3bc9956
RP
169 list_for_each_entry(trig, &trigger_list, next_trig) {
170 if (!strcmp(led_cdev->default_trigger, trig->name))
171 led_trigger_set(led_cdev, trig);
172 }
dc47206e
RP
173 up_write(&led_cdev->trigger_lock);
174 up_read(&triggers_list_lock);
c3bc9956 175}
4d404fd5
NM
176EXPORT_SYMBOL_GPL(led_trigger_set_default);
177
a8df7b1a
FB
178void led_trigger_rename_static(const char *name, struct led_trigger *trig)
179{
180 /* new name must be on a temporary string to prevent races */
181 BUG_ON(name == trig->name);
182
183 down_write(&triggers_list_lock);
184 /* this assumes that trig->name was originaly allocated to
185 * non constant storage */
186 strcpy((char *)trig->name, name);
187 up_write(&triggers_list_lock);
188}
189EXPORT_SYMBOL_GPL(led_trigger_rename_static);
190
4d404fd5 191/* LED Trigger Interface */
c3bc9956 192
eb202621 193int led_trigger_register(struct led_trigger *trig)
c3bc9956
RP
194{
195 struct led_classdev *led_cdev;
eb202621 196 struct led_trigger *_trig;
c3bc9956 197
eb202621
BW
198 rwlock_init(&trig->leddev_list_lock);
199 INIT_LIST_HEAD(&trig->led_cdevs);
c3bc9956 200
dc47206e 201 down_write(&triggers_list_lock);
700c6ea2 202 /* Make sure the trigger's name isn't already in use */
eb202621
BW
203 list_for_each_entry(_trig, &trigger_list, next_trig) {
204 if (!strcmp(_trig->name, trig->name)) {
700c6ea2
AN
205 up_write(&triggers_list_lock);
206 return -EEXIST;
207 }
208 }
209 /* Add to the list of led triggers */
eb202621 210 list_add_tail(&trig->next_trig, &trigger_list);
dc47206e 211 up_write(&triggers_list_lock);
c3bc9956
RP
212
213 /* Register with any LEDs that have this as a default trigger */
72f8da32 214 down_read(&leds_list_lock);
c3bc9956 215 list_for_each_entry(led_cdev, &leds_list, node) {
dc47206e 216 down_write(&led_cdev->trigger_lock);
c3bc9956 217 if (!led_cdev->trigger && led_cdev->default_trigger &&
eb202621
BW
218 !strcmp(led_cdev->default_trigger, trig->name))
219 led_trigger_set(led_cdev, trig);
dc47206e 220 up_write(&led_cdev->trigger_lock);
c3bc9956 221 }
72f8da32 222 up_read(&leds_list_lock);
c3bc9956
RP
223
224 return 0;
225}
4d404fd5 226EXPORT_SYMBOL_GPL(led_trigger_register);
c3bc9956 227
eb202621 228void led_trigger_unregister(struct led_trigger *trig)
c3bc9956
RP
229{
230 struct led_classdev *led_cdev;
231
14f5716b
SL
232 if (list_empty_careful(&trig->next_trig))
233 return;
234
c3bc9956 235 /* Remove from the list of led triggers */
dc47206e 236 down_write(&triggers_list_lock);
14f5716b 237 list_del_init(&trig->next_trig);
dc47206e 238 up_write(&triggers_list_lock);
c3bc9956
RP
239
240 /* Remove anyone actively using this trigger */
72f8da32 241 down_read(&leds_list_lock);
c3bc9956 242 list_for_each_entry(led_cdev, &leds_list, node) {
dc47206e 243 down_write(&led_cdev->trigger_lock);
eb202621 244 if (led_cdev->trigger == trig)
c3bc9956 245 led_trigger_set(led_cdev, NULL);
dc47206e 246 up_write(&led_cdev->trigger_lock);
c3bc9956 247 }
72f8da32 248 up_read(&leds_list_lock);
c3bc9956 249}
4d404fd5 250EXPORT_SYMBOL_GPL(led_trigger_unregister);
c3bc9956 251
4d404fd5
NM
252/* Simple LED Tigger Interface */
253
eb202621 254void led_trigger_event(struct led_trigger *trig,
4d404fd5 255 enum led_brightness brightness)
c3bc9956 256{
11e043b5 257 struct led_classdev *led_cdev;
4d404fd5 258
eb202621 259 if (!trig)
4d404fd5
NM
260 return;
261
eb202621 262 read_lock(&trig->leddev_list_lock);
11e043b5 263 list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)
d23a22a7 264 led_set_brightness(led_cdev, brightness);
eb202621 265 read_unlock(&trig->leddev_list_lock);
c3bc9956 266}
4d404fd5 267EXPORT_SYMBOL_GPL(led_trigger_event);
c3bc9956 268
20c0e6b8 269static void led_trigger_blink_setup(struct led_trigger *trig,
5bb629c5
FB
270 unsigned long *delay_on,
271 unsigned long *delay_off,
272 int oneshot,
273 int invert)
0b9536c9 274{
11e043b5 275 struct led_classdev *led_cdev;
0b9536c9 276
eb202621 277 if (!trig)
0b9536c9
VK
278 return;
279
eb202621 280 read_lock(&trig->leddev_list_lock);
11e043b5 281 list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
5bb629c5
FB
282 if (oneshot)
283 led_blink_set_oneshot(led_cdev, delay_on, delay_off,
284 invert);
285 else
286 led_blink_set(led_cdev, delay_on, delay_off);
0b9536c9 287 }
eb202621 288 read_unlock(&trig->leddev_list_lock);
0b9536c9 289}
5bb629c5
FB
290
291void led_trigger_blink(struct led_trigger *trig,
292 unsigned long *delay_on,
293 unsigned long *delay_off)
294{
295 led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0);
296}
0b9536c9
VK
297EXPORT_SYMBOL_GPL(led_trigger_blink);
298
5bb629c5
FB
299void led_trigger_blink_oneshot(struct led_trigger *trig,
300 unsigned long *delay_on,
301 unsigned long *delay_off,
302 int invert)
303{
304 led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert);
305}
306EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot);
307
4d404fd5
NM
308void led_trigger_register_simple(const char *name, struct led_trigger **tp)
309{
eb202621 310 struct led_trigger *trig;
4d404fd5 311 int err;
c3bc9956 312
eb202621 313 trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
c3bc9956 314
eb202621
BW
315 if (trig) {
316 trig->name = name;
317 err = led_trigger_register(trig);
cba4c2ac 318 if (err < 0) {
eb202621
BW
319 kfree(trig);
320 trig = NULL;
09f5fe75
SK
321 pr_warn("LED trigger %s failed to register (%d)\n",
322 name, err);
cba4c2ac 323 }
09f5fe75
SK
324 } else {
325 pr_warn("LED trigger %s failed to register (no memory)\n",
326 name);
327 }
eb202621 328 *tp = trig;
4d404fd5 329}
c3bc9956 330EXPORT_SYMBOL_GPL(led_trigger_register_simple);
4d404fd5 331
eb202621 332void led_trigger_unregister_simple(struct led_trigger *trig)
4d404fd5 333{
eb202621
BW
334 if (trig)
335 led_trigger_unregister(trig);
336 kfree(trig);
4d404fd5 337}
c3bc9956 338EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
c3bc9956
RP
339
340MODULE_AUTHOR("Richard Purdie");
341MODULE_LICENSE("GPL");
342MODULE_DESCRIPTION("LED Triggers Core");
This page took 0.741955 seconds and 5 git commands to generate.