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