1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Functions for saving/restoring console. 4 * 5 * Originally from swsusp. 6 */ 7 8 #include <linux/console.h> 9 #include <linux/vt_kern.h> 10 #include <linux/kbd_kern.h> 11 #include <linux/vt.h> 12 #include <linux/module.h> 13 #include <linux/slab.h> 14 #include "power.h" 15 16 #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1) 17 18 static int orig_fgconsole, orig_kmsg; 19 static bool vt_switch_done; 20 21 static DEFINE_MUTEX(vt_switch_mutex); 22 23 struct pm_vt_switch { 24 struct list_head head; 25 struct device *dev; 26 bool required; 27 }; 28 29 static LIST_HEAD(pm_vt_switch_list); 30 31 32 /** 33 * pm_vt_switch_required - indicate VT switch at suspend requirements 34 * @dev: device 35 * @required: if true, caller needs VT switch at suspend/resume time 36 * 37 * The different console drivers may or may not require VT switches across 38 * suspend/resume, depending on how they handle restoring video state and 39 * what may be running. 40 * 41 * Drivers can indicate support for switchless suspend/resume, which can 42 * save time and flicker, by using this routine and passing 'false' as 43 * the argument. If any loaded driver needs VT switching, or the 44 * no_console_suspend argument has been passed on the command line, VT 45 * switches will occur. 46 */ 47 void pm_vt_switch_required(struct device *dev, bool required) 48 { 49 struct pm_vt_switch *entry, *tmp; 50 51 mutex_lock(&vt_switch_mutex); 52 list_for_each_entry(tmp, &pm_vt_switch_list, head) { 53 if (tmp->dev == dev) { 54 /* already registered, update requirement */ 55 tmp->required = required; 56 goto out; 57 } 58 } 59 60 entry = kmalloc(sizeof(*entry), GFP_KERNEL); 61 if (!entry) 62 goto out; 63 64 entry->required = required; 65 entry->dev = dev; 66 67 list_add(&entry->head, &pm_vt_switch_list); 68 out: 69 mutex_unlock(&vt_switch_mutex); 70 } 71 EXPORT_SYMBOL(pm_vt_switch_required); 72 73 /** 74 * pm_vt_switch_unregister - stop tracking a device's VT switching needs 75 * @dev: device 76 * 77 * Remove @dev from the vt switch list. 78 */ 79 void pm_vt_switch_unregister(struct device *dev) 80 { 81 struct pm_vt_switch *tmp; 82 83 mutex_lock(&vt_switch_mutex); 84 list_for_each_entry(tmp, &pm_vt_switch_list, head) { 85 if (tmp->dev == dev) { 86 list_del(&tmp->head); 87 kfree(tmp); 88 break; 89 } 90 } 91 mutex_unlock(&vt_switch_mutex); 92 } 93 EXPORT_SYMBOL(pm_vt_switch_unregister); 94 95 /* 96 * There are three cases when a VT switch on suspend/resume are required: 97 * 1) no driver has indicated a requirement one way or another, so preserve 98 * the old behavior 99 * 2) console suspend is disabled, we want to see debug messages across 100 * suspend/resume 101 * 3) any registered driver indicates it needs a VT switch 102 * 103 * If none of these conditions is present, meaning we have at least one driver 104 * that doesn't need the switch, and none that do, we can avoid it to make 105 * resume look a little prettier (and suspend too, but that's usually hidden, 106 * e.g. when closing the lid on a laptop). 107 */ 108 static bool pm_vt_switch(void) 109 { 110 struct pm_vt_switch *entry; 111 bool ret = true; 112 113 mutex_lock(&vt_switch_mutex); 114 if (list_empty(&pm_vt_switch_list)) 115 goto out; 116 117 if (!console_suspend_enabled) 118 goto out; 119 120 list_for_each_entry(entry, &pm_vt_switch_list, head) { 121 if (entry->required) 122 goto out; 123 } 124 125 ret = false; 126 out: 127 mutex_unlock(&vt_switch_mutex); 128 return ret; 129 } 130 131 void pm_prepare_console(void) 132 { 133 if (!pm_vt_switch()) 134 return; 135 136 orig_fgconsole = vt_move_to_console(SUSPEND_CONSOLE, 1); 137 if (orig_fgconsole < 0) 138 return; 139 140 vt_switch_done = true; 141 142 orig_kmsg = vt_kmsg_redirect(SUSPEND_CONSOLE); 143 return; 144 } 145 146 void pm_restore_console(void) 147 { 148 if (!pm_vt_switch() && !vt_switch_done) 149 return; 150 151 if (orig_fgconsole >= 0) { 152 vt_move_to_console(orig_fgconsole, 0); 153 vt_kmsg_redirect(orig_kmsg); 154 } 155 156 vt_switch_done = false; 157 } 158