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