18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Kernel Panic LED Trigger 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2016 Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/notifier.h> 118c2ecf20Sopenharmony_ci#include <linux/leds.h> 128c2ecf20Sopenharmony_ci#include "../leds.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic struct led_trigger *trigger; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* 178c2ecf20Sopenharmony_ci * This is called in a special context by the atomic panic 188c2ecf20Sopenharmony_ci * notifier. This means the trigger can be changed without 198c2ecf20Sopenharmony_ci * worrying about locking. 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_cistatic void led_trigger_set_panic(struct led_classdev *led_cdev) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct led_trigger *trig; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci list_for_each_entry(trig, &trigger_list, next_trig) { 268c2ecf20Sopenharmony_ci if (strcmp("panic", trig->name)) 278c2ecf20Sopenharmony_ci continue; 288c2ecf20Sopenharmony_ci if (led_cdev->trigger) 298c2ecf20Sopenharmony_ci list_del(&led_cdev->trig_list); 308c2ecf20Sopenharmony_ci list_add_tail(&led_cdev->trig_list, &trig->led_cdevs); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci /* Avoid the delayed blink path */ 338c2ecf20Sopenharmony_ci led_cdev->blink_delay_on = 0; 348c2ecf20Sopenharmony_ci led_cdev->blink_delay_off = 0; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci led_cdev->trigger = trig; 378c2ecf20Sopenharmony_ci if (trig->activate) 388c2ecf20Sopenharmony_ci trig->activate(led_cdev); 398c2ecf20Sopenharmony_ci break; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int led_trigger_panic_notifier(struct notifier_block *nb, 448c2ecf20Sopenharmony_ci unsigned long code, void *unused) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct led_classdev *led_cdev; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci list_for_each_entry(led_cdev, &leds_list, node) 498c2ecf20Sopenharmony_ci if (led_cdev->flags & LED_PANIC_INDICATOR) 508c2ecf20Sopenharmony_ci led_trigger_set_panic(led_cdev); 518c2ecf20Sopenharmony_ci return NOTIFY_DONE; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic struct notifier_block led_trigger_panic_nb = { 558c2ecf20Sopenharmony_ci .notifier_call = led_trigger_panic_notifier, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic long led_panic_blink(int state) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci led_trigger_event(trigger, state ? LED_FULL : LED_OFF); 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int __init ledtrig_panic_init(void) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci led_trigger_register_simple("panic", &trigger); 678c2ecf20Sopenharmony_ci if (!trigger) 688c2ecf20Sopenharmony_ci return -ENOMEM; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci atomic_notifier_chain_register(&panic_notifier_list, 718c2ecf20Sopenharmony_ci &led_trigger_panic_nb); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci panic_blink = led_panic_blink; 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_cidevice_initcall(ledtrig_panic_init); 77