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