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