1 // SPDX-License-Identifier: GPL-2.0 or MIT 2 3 #include <linux/sysrq.h> 4 5 #include <drm/drm_client_event.h> 6 #include <drm/drm_device.h> 7 #include <drm/drm_print.h> 8 9 #include "drm_internal.h" 10 11 #ifdef CONFIG_MAGIC_SYSRQ 12 static LIST_HEAD(drm_client_sysrq_dev_list); 13 static DEFINE_MUTEX(drm_client_sysrq_dev_lock); 14 15 /* emergency restore, don't bother with error reporting */ 16 static void drm_client_sysrq_restore_work_fn(struct work_struct *ignored) 17 { 18 struct drm_device *dev; 19 20 guard(mutex)(&drm_client_sysrq_dev_lock); 21 22 list_for_each_entry(dev, &drm_client_sysrq_dev_list, client_sysrq_list) { 23 if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 24 continue; 25 26 drm_client_dev_restore(dev, true); 27 } 28 } 29 30 static DECLARE_WORK(drm_client_sysrq_restore_work, drm_client_sysrq_restore_work_fn); 31 32 static void drm_client_sysrq_restore_handler(u8 ignored) 33 { 34 schedule_work(&drm_client_sysrq_restore_work); 35 } 36 37 static const struct sysrq_key_op drm_client_sysrq_restore_op = { 38 .handler = drm_client_sysrq_restore_handler, 39 .help_msg = "force-fb(v)", 40 .action_msg = "Restore framebuffer console", 41 }; 42 43 void drm_client_sysrq_register(struct drm_device *dev) 44 { 45 guard(mutex)(&drm_client_sysrq_dev_lock); 46 47 if (list_empty(&drm_client_sysrq_dev_list)) 48 register_sysrq_key('v', &drm_client_sysrq_restore_op); 49 50 list_add(&dev->client_sysrq_list, &drm_client_sysrq_dev_list); 51 } 52 53 void drm_client_sysrq_unregister(struct drm_device *dev) 54 { 55 guard(mutex)(&drm_client_sysrq_dev_lock); 56 57 /* remove device from global restore list */ 58 if (!drm_WARN_ON(dev, list_empty(&dev->client_sysrq_list))) 59 list_del(&dev->client_sysrq_list); 60 61 /* no devices left; unregister key */ 62 if (list_empty(&drm_client_sysrq_dev_list)) 63 unregister_sysrq_key('v', &drm_client_sysrq_restore_op); 64 } 65 #endif 66