0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/console.h>
0009 #include <linux/vt_kern.h>
0010 #include <linux/kbd_kern.h>
0011 #include <linux/vt.h>
0012 #include <linux/module.h>
0013 #include <linux/slab.h>
0014 #include "power.h"
0015
0016 #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
0017
0018 static int orig_fgconsole, orig_kmsg;
0019
0020 static DEFINE_MUTEX(vt_switch_mutex);
0021
0022 struct pm_vt_switch {
0023 struct list_head head;
0024 struct device *dev;
0025 bool required;
0026 };
0027
0028 static LIST_HEAD(pm_vt_switch_list);
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046 void pm_vt_switch_required(struct device *dev, bool required)
0047 {
0048 struct pm_vt_switch *entry, *tmp;
0049
0050 mutex_lock(&vt_switch_mutex);
0051 list_for_each_entry(tmp, &pm_vt_switch_list, head) {
0052 if (tmp->dev == dev) {
0053
0054 tmp->required = required;
0055 goto out;
0056 }
0057 }
0058
0059 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
0060 if (!entry)
0061 goto out;
0062
0063 entry->required = required;
0064 entry->dev = dev;
0065
0066 list_add(&entry->head, &pm_vt_switch_list);
0067 out:
0068 mutex_unlock(&vt_switch_mutex);
0069 }
0070 EXPORT_SYMBOL(pm_vt_switch_required);
0071
0072
0073
0074
0075
0076
0077
0078 void pm_vt_switch_unregister(struct device *dev)
0079 {
0080 struct pm_vt_switch *tmp;
0081
0082 mutex_lock(&vt_switch_mutex);
0083 list_for_each_entry(tmp, &pm_vt_switch_list, head) {
0084 if (tmp->dev == dev) {
0085 list_del(&tmp->head);
0086 kfree(tmp);
0087 break;
0088 }
0089 }
0090 mutex_unlock(&vt_switch_mutex);
0091 }
0092 EXPORT_SYMBOL(pm_vt_switch_unregister);
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 static bool pm_vt_switch(void)
0108 {
0109 struct pm_vt_switch *entry;
0110 bool ret = true;
0111
0112 mutex_lock(&vt_switch_mutex);
0113 if (list_empty(&pm_vt_switch_list))
0114 goto out;
0115
0116 if (!console_suspend_enabled)
0117 goto out;
0118
0119 list_for_each_entry(entry, &pm_vt_switch_list, head) {
0120 if (entry->required)
0121 goto out;
0122 }
0123
0124 ret = false;
0125 out:
0126 mutex_unlock(&vt_switch_mutex);
0127 return ret;
0128 }
0129
0130 void pm_prepare_console(void)
0131 {
0132 if (!pm_vt_switch())
0133 return;
0134
0135 orig_fgconsole = vt_move_to_console(SUSPEND_CONSOLE, 1);
0136 if (orig_fgconsole < 0)
0137 return;
0138
0139 orig_kmsg = vt_kmsg_redirect(SUSPEND_CONSOLE);
0140 return;
0141 }
0142
0143 void pm_restore_console(void)
0144 {
0145 if (!pm_vt_switch())
0146 return;
0147
0148 if (orig_fgconsole >= 0) {
0149 vt_move_to_console(orig_fgconsole, 0);
0150 vt_kmsg_redirect(orig_kmsg);
0151 }
0152 }