1 | // SPDX-License-Identifier: GPL-2.0-only |
---|---|
2 | /* |
3 | * Kernel Panic LED Trigger |
4 | * |
5 | * Copyright 2016 Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> |
6 | */ |
7 | |
8 | #include <linux/kernel.h> |
9 | #include <linux/init.h> |
10 | #include <linux/notifier.h> |
11 | #include <linux/panic_notifier.h> |
12 | #include <linux/leds.h> |
13 | #include "../leds.h" |
14 | |
15 | static struct led_trigger *trigger; |
16 | |
17 | /* |
18 | * This is called in a special context by the atomic panic |
19 | * notifier. This means the trigger can be changed without |
20 | * worrying about locking. |
21 | */ |
22 | static void led_trigger_set_panic(struct led_classdev *led_cdev) |
23 | { |
24 | if (led_cdev->trigger) |
25 | list_del(entry: &led_cdev->trig_list); |
26 | list_add_tail(new: &led_cdev->trig_list, head: &trigger->led_cdevs); |
27 | |
28 | /* Avoid the delayed blink path */ |
29 | led_cdev->blink_delay_on = 0; |
30 | led_cdev->blink_delay_off = 0; |
31 | |
32 | led_cdev->trigger = trigger; |
33 | } |
34 | |
35 | static int led_trigger_panic_notifier(struct notifier_block *nb, |
36 | unsigned long code, void *unused) |
37 | { |
38 | struct led_classdev *led_cdev; |
39 | |
40 | list_for_each_entry(led_cdev, &leds_list, node) |
41 | if (led_cdev->flags & LED_PANIC_INDICATOR) |
42 | led_trigger_set_panic(led_cdev); |
43 | return NOTIFY_DONE; |
44 | } |
45 | |
46 | static struct notifier_block led_trigger_panic_nb = { |
47 | .notifier_call = led_trigger_panic_notifier, |
48 | }; |
49 | |
50 | static long led_panic_blink(int state) |
51 | { |
52 | led_trigger_event(trigger, event: state ? LED_FULL : LED_OFF); |
53 | return 0; |
54 | } |
55 | |
56 | static int __init ledtrig_panic_init(void) |
57 | { |
58 | led_trigger_register_simple(name: "panic", trigger: &trigger); |
59 | if (!trigger) |
60 | return -ENOMEM; |
61 | |
62 | atomic_notifier_chain_register(nh: &panic_notifier_list, |
63 | nb: &led_trigger_panic_nb); |
64 | |
65 | panic_blink = led_panic_blink; |
66 | return 0; |
67 | } |
68 | device_initcall(ledtrig_panic_init); |
69 |