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