Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * LED Triggers Core
4 : : *
5 : : * Copyright 2005-2007 Openedhand Ltd.
6 : : *
7 : : * Author: Richard Purdie <rpurdie@openedhand.com>
8 : : */
9 : :
10 : : #include <linux/export.h>
11 : : #include <linux/kernel.h>
12 : : #include <linux/list.h>
13 : : #include <linux/spinlock.h>
14 : : #include <linux/device.h>
15 : : #include <linux/timer.h>
16 : : #include <linux/rwsem.h>
17 : : #include <linux/leds.h>
18 : : #include <linux/slab.h>
19 : : #include "leds.h"
20 : :
21 : : /*
22 : : * Nests outside led_cdev->trigger_lock
23 : : */
24 : : static DECLARE_RWSEM(triggers_list_lock);
25 : : LIST_HEAD(trigger_list);
26 : :
27 : : /* Used by LED Class */
28 : :
29 : 0 : ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
30 : : const char *buf, size_t count)
31 : : {
32 : : struct led_classdev *led_cdev = dev_get_drvdata(dev);
33 : : struct led_trigger *trig;
34 : 0 : int ret = count;
35 : :
36 : 0 : mutex_lock(&led_cdev->led_access);
37 : :
38 : 0 : if (led_sysfs_is_disabled(led_cdev)) {
39 : : ret = -EBUSY;
40 : : goto unlock;
41 : : }
42 : :
43 : 0 : if (sysfs_streq(buf, "none")) {
44 : 0 : led_trigger_remove(led_cdev);
45 : 0 : goto unlock;
46 : : }
47 : :
48 : 0 : down_read(&triggers_list_lock);
49 : 0 : list_for_each_entry(trig, &trigger_list, next_trig) {
50 : 0 : if (sysfs_streq(buf, trig->name)) {
51 : 0 : down_write(&led_cdev->trigger_lock);
52 : 0 : led_trigger_set(led_cdev, trig);
53 : 0 : up_write(&led_cdev->trigger_lock);
54 : :
55 : 0 : up_read(&triggers_list_lock);
56 : 0 : goto unlock;
57 : : }
58 : : }
59 : : /* we come here only if buf matches no trigger */
60 : : ret = -EINVAL;
61 : 0 : up_read(&triggers_list_lock);
62 : :
63 : : unlock:
64 : 0 : mutex_unlock(&led_cdev->led_access);
65 : 0 : return ret;
66 : : }
67 : : EXPORT_SYMBOL_GPL(led_trigger_store);
68 : :
69 : 0 : ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
70 : : char *buf)
71 : : {
72 : : struct led_classdev *led_cdev = dev_get_drvdata(dev);
73 : : struct led_trigger *trig;
74 : : int len = 0;
75 : :
76 : 0 : down_read(&triggers_list_lock);
77 : 0 : down_read(&led_cdev->trigger_lock);
78 : :
79 : 0 : if (!led_cdev->trigger)
80 : 0 : len += scnprintf(buf+len, PAGE_SIZE - len, "[none] ");
81 : : else
82 : 0 : len += scnprintf(buf+len, PAGE_SIZE - len, "none ");
83 : :
84 : 0 : list_for_each_entry(trig, &trigger_list, next_trig) {
85 : 0 : if (led_cdev->trigger && !strcmp(led_cdev->trigger->name,
86 : : trig->name))
87 : 0 : len += scnprintf(buf+len, PAGE_SIZE - len, "[%s] ",
88 : 0 : trig->name);
89 : : else
90 : 0 : len += scnprintf(buf+len, PAGE_SIZE - len, "%s ",
91 : : trig->name);
92 : : }
93 : 0 : up_read(&led_cdev->trigger_lock);
94 : 0 : up_read(&triggers_list_lock);
95 : :
96 : 0 : len += scnprintf(len+buf, PAGE_SIZE - len, "\n");
97 : 0 : return len;
98 : : }
99 : : EXPORT_SYMBOL_GPL(led_trigger_show);
100 : :
101 : : /* Caller must ensure led_cdev->trigger_lock held */
102 : 3 : int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
103 : : {
104 : : unsigned long flags;
105 : : char *event = NULL;
106 : : char *envp[2];
107 : : const char *name;
108 : : int ret;
109 : :
110 : 3 : if (!led_cdev->trigger && !trig)
111 : : return 0;
112 : :
113 : 3 : name = trig ? trig->name : "none";
114 : 3 : event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name);
115 : :
116 : : /* Remove any existing trigger */
117 : 3 : if (led_cdev->trigger) {
118 : 0 : write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
119 : : list_del(&led_cdev->trig_list);
120 : 0 : write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
121 : : flags);
122 : 0 : cancel_work_sync(&led_cdev->set_brightness_work);
123 : 0 : led_stop_software_blink(led_cdev);
124 : 0 : if (led_cdev->trigger->deactivate)
125 : 0 : led_cdev->trigger->deactivate(led_cdev);
126 : 0 : device_remove_groups(led_cdev->dev, led_cdev->trigger->groups);
127 : 0 : led_cdev->trigger = NULL;
128 : 0 : led_cdev->trigger_data = NULL;
129 : 0 : led_cdev->activated = false;
130 : 0 : led_set_brightness(led_cdev, LED_OFF);
131 : : }
132 : 3 : if (trig) {
133 : 3 : write_lock_irqsave(&trig->leddev_list_lock, flags);
134 : 3 : list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
135 : 3 : write_unlock_irqrestore(&trig->leddev_list_lock, flags);
136 : 3 : led_cdev->trigger = trig;
137 : :
138 : 3 : if (trig->activate)
139 : 3 : ret = trig->activate(led_cdev);
140 : : else
141 : : ret = 0;
142 : :
143 : 3 : if (ret)
144 : : goto err_activate;
145 : :
146 : 3 : ret = device_add_groups(led_cdev->dev, trig->groups);
147 : 3 : if (ret) {
148 : 0 : dev_err(led_cdev->dev, "Failed to add trigger attributes\n");
149 : : goto err_add_groups;
150 : : }
151 : : }
152 : :
153 : 3 : if (event) {
154 : 3 : envp[0] = event;
155 : 3 : envp[1] = NULL;
156 : 3 : if (kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp))
157 : 0 : dev_err(led_cdev->dev,
158 : : "%s: Error sending uevent\n", __func__);
159 : 3 : kfree(event);
160 : : }
161 : :
162 : : return 0;
163 : :
164 : : err_add_groups:
165 : :
166 : 0 : if (trig->deactivate)
167 : 0 : trig->deactivate(led_cdev);
168 : : err_activate:
169 : :
170 : 0 : write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
171 : : list_del(&led_cdev->trig_list);
172 : 0 : write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
173 : 0 : led_cdev->trigger = NULL;
174 : 0 : led_cdev->trigger_data = NULL;
175 : 0 : led_set_brightness(led_cdev, LED_OFF);
176 : 0 : kfree(event);
177 : :
178 : 0 : return ret;
179 : : }
180 : : EXPORT_SYMBOL_GPL(led_trigger_set);
181 : :
182 : 0 : void led_trigger_remove(struct led_classdev *led_cdev)
183 : : {
184 : 0 : down_write(&led_cdev->trigger_lock);
185 : 0 : led_trigger_set(led_cdev, NULL);
186 : 0 : up_write(&led_cdev->trigger_lock);
187 : 0 : }
188 : : EXPORT_SYMBOL_GPL(led_trigger_remove);
189 : :
190 : 3 : void led_trigger_set_default(struct led_classdev *led_cdev)
191 : : {
192 : : struct led_trigger *trig;
193 : :
194 : 3 : if (!led_cdev->default_trigger)
195 : 3 : return;
196 : :
197 : 3 : down_read(&triggers_list_lock);
198 : 3 : down_write(&led_cdev->trigger_lock);
199 : 3 : list_for_each_entry(trig, &trigger_list, next_trig) {
200 : 3 : if (!strcmp(led_cdev->default_trigger, trig->name)) {
201 : 3 : led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
202 : 3 : led_trigger_set(led_cdev, trig);
203 : 3 : break;
204 : : }
205 : : }
206 : 3 : up_write(&led_cdev->trigger_lock);
207 : 3 : up_read(&triggers_list_lock);
208 : : }
209 : : EXPORT_SYMBOL_GPL(led_trigger_set_default);
210 : :
211 : 0 : void led_trigger_rename_static(const char *name, struct led_trigger *trig)
212 : : {
213 : : /* new name must be on a temporary string to prevent races */
214 : 0 : BUG_ON(name == trig->name);
215 : :
216 : 0 : down_write(&triggers_list_lock);
217 : : /* this assumes that trig->name was originaly allocated to
218 : : * non constant storage */
219 : 0 : strcpy((char *)trig->name, name);
220 : 0 : up_write(&triggers_list_lock);
221 : 0 : }
222 : : EXPORT_SYMBOL_GPL(led_trigger_rename_static);
223 : :
224 : : /* LED Trigger Interface */
225 : :
226 : 3 : int led_trigger_register(struct led_trigger *trig)
227 : : {
228 : : struct led_classdev *led_cdev;
229 : : struct led_trigger *_trig;
230 : :
231 : 3 : rwlock_init(&trig->leddev_list_lock);
232 : 3 : INIT_LIST_HEAD(&trig->led_cdevs);
233 : :
234 : 3 : down_write(&triggers_list_lock);
235 : : /* Make sure the trigger's name isn't already in use */
236 : 3 : list_for_each_entry(_trig, &trigger_list, next_trig) {
237 : 3 : if (!strcmp(_trig->name, trig->name)) {
238 : 0 : up_write(&triggers_list_lock);
239 : 0 : return -EEXIST;
240 : : }
241 : : }
242 : : /* Add to the list of led triggers */
243 : 3 : list_add_tail(&trig->next_trig, &trigger_list);
244 : 3 : up_write(&triggers_list_lock);
245 : :
246 : : /* Register with any LEDs that have this as a default trigger */
247 : 3 : down_read(&leds_list_lock);
248 : 3 : list_for_each_entry(led_cdev, &leds_list, node) {
249 : 3 : down_write(&led_cdev->trigger_lock);
250 : 3 : if (!led_cdev->trigger && led_cdev->default_trigger &&
251 : 3 : !strcmp(led_cdev->default_trigger, trig->name)) {
252 : 3 : led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
253 : 3 : led_trigger_set(led_cdev, trig);
254 : : }
255 : 3 : up_write(&led_cdev->trigger_lock);
256 : : }
257 : 3 : up_read(&leds_list_lock);
258 : :
259 : 3 : return 0;
260 : : }
261 : : EXPORT_SYMBOL_GPL(led_trigger_register);
262 : :
263 : 0 : void led_trigger_unregister(struct led_trigger *trig)
264 : : {
265 : : struct led_classdev *led_cdev;
266 : :
267 : 0 : if (list_empty_careful(&trig->next_trig))
268 : 0 : return;
269 : :
270 : : /* Remove from the list of led triggers */
271 : 0 : down_write(&triggers_list_lock);
272 : : list_del_init(&trig->next_trig);
273 : 0 : up_write(&triggers_list_lock);
274 : :
275 : : /* Remove anyone actively using this trigger */
276 : 0 : down_read(&leds_list_lock);
277 : 0 : list_for_each_entry(led_cdev, &leds_list, node) {
278 : 0 : down_write(&led_cdev->trigger_lock);
279 : 0 : if (led_cdev->trigger == trig)
280 : 0 : led_trigger_set(led_cdev, NULL);
281 : 0 : up_write(&led_cdev->trigger_lock);
282 : : }
283 : 0 : up_read(&leds_list_lock);
284 : : }
285 : : EXPORT_SYMBOL_GPL(led_trigger_unregister);
286 : :
287 : 0 : static void devm_led_trigger_release(struct device *dev, void *res)
288 : : {
289 : 0 : led_trigger_unregister(*(struct led_trigger **)res);
290 : 0 : }
291 : :
292 : 0 : int devm_led_trigger_register(struct device *dev,
293 : : struct led_trigger *trig)
294 : : {
295 : : struct led_trigger **dr;
296 : : int rc;
297 : :
298 : : dr = devres_alloc(devm_led_trigger_release, sizeof(*dr),
299 : : GFP_KERNEL);
300 : 0 : if (!dr)
301 : : return -ENOMEM;
302 : :
303 : 0 : *dr = trig;
304 : :
305 : 0 : rc = led_trigger_register(trig);
306 : 0 : if (rc)
307 : 0 : devres_free(dr);
308 : : else
309 : 0 : devres_add(dev, dr);
310 : :
311 : 0 : return rc;
312 : : }
313 : : EXPORT_SYMBOL_GPL(devm_led_trigger_register);
314 : :
315 : : /* Simple LED Tigger Interface */
316 : :
317 : 3 : void led_trigger_event(struct led_trigger *trig,
318 : : enum led_brightness brightness)
319 : : {
320 : : struct led_classdev *led_cdev;
321 : :
322 : 3 : if (!trig)
323 : 3 : return;
324 : :
325 : 3 : read_lock(&trig->leddev_list_lock);
326 : 3 : list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)
327 : 3 : led_set_brightness(led_cdev, brightness);
328 : : read_unlock(&trig->leddev_list_lock);
329 : : }
330 : : EXPORT_SYMBOL_GPL(led_trigger_event);
331 : :
332 : 0 : static void led_trigger_blink_setup(struct led_trigger *trig,
333 : : unsigned long *delay_on,
334 : : unsigned long *delay_off,
335 : : int oneshot,
336 : : int invert)
337 : : {
338 : : struct led_classdev *led_cdev;
339 : :
340 : 0 : if (!trig)
341 : 0 : return;
342 : :
343 : 0 : read_lock(&trig->leddev_list_lock);
344 : 0 : list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
345 : 0 : if (oneshot)
346 : 0 : led_blink_set_oneshot(led_cdev, delay_on, delay_off,
347 : : invert);
348 : : else
349 : 0 : led_blink_set(led_cdev, delay_on, delay_off);
350 : : }
351 : : read_unlock(&trig->leddev_list_lock);
352 : : }
353 : :
354 : 0 : void led_trigger_blink(struct led_trigger *trig,
355 : : unsigned long *delay_on,
356 : : unsigned long *delay_off)
357 : : {
358 : 0 : led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0);
359 : 0 : }
360 : : EXPORT_SYMBOL_GPL(led_trigger_blink);
361 : :
362 : 0 : void led_trigger_blink_oneshot(struct led_trigger *trig,
363 : : unsigned long *delay_on,
364 : : unsigned long *delay_off,
365 : : int invert)
366 : : {
367 : 0 : led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert);
368 : 0 : }
369 : : EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot);
370 : :
371 : 3 : void led_trigger_register_simple(const char *name, struct led_trigger **tp)
372 : : {
373 : : struct led_trigger *trig;
374 : : int err;
375 : :
376 : 3 : trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
377 : :
378 : 3 : if (trig) {
379 : 3 : trig->name = name;
380 : 3 : err = led_trigger_register(trig);
381 : 3 : if (err < 0) {
382 : 0 : kfree(trig);
383 : : trig = NULL;
384 : 0 : pr_warn("LED trigger %s failed to register (%d)\n",
385 : : name, err);
386 : : }
387 : : } else {
388 : 0 : pr_warn("LED trigger %s failed to register (no memory)\n",
389 : : name);
390 : : }
391 : 3 : *tp = trig;
392 : 3 : }
393 : : EXPORT_SYMBOL_GPL(led_trigger_register_simple);
394 : :
395 : 0 : void led_trigger_unregister_simple(struct led_trigger *trig)
396 : : {
397 : 0 : if (trig)
398 : 0 : led_trigger_unregister(trig);
399 : 0 : kfree(trig);
400 : 0 : }
401 : : EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
|