summaryrefslogtreecommitdiff
path: root/kernel/power/tuxonice_ui.c
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 11:24:16 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 11:24:16 -0300
commit376027f2a3888ef3dec73ee41f85d90e51162d78 (patch)
treeac9a9030d31cadc92fdc4145a3d9bf379064721f /kernel/power/tuxonice_ui.c
parente5fd91f1ef340da553f7a79da9540c3db711c937 (diff)
Add TuxOnIce support
Diffstat (limited to 'kernel/power/tuxonice_ui.c')
-rw-r--r--kernel/power/tuxonice_ui.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/kernel/power/tuxonice_ui.c b/kernel/power/tuxonice_ui.c
new file mode 100644
index 000000000..76152f3ff
--- /dev/null
+++ b/kernel/power/tuxonice_ui.c
@@ -0,0 +1,247 @@
+/*
+ * kernel/power/tuxonice_ui.c
+ *
+ * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
+ * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
+ * Copyright (C) 2002-2015 Nigel Cunningham (nigel at nigelcunningham com au)
+ *
+ * This file is released under the GPLv2.
+ *
+ * Routines for TuxOnIce's user interface.
+ *
+ * The user interface code talks to a userspace program via a
+ * netlink socket.
+ *
+ * The kernel side:
+ * - starts the userui program;
+ * - sends text messages and progress bar status;
+ *
+ * The user space side:
+ * - passes messages regarding user requests (abort, toggle reboot etc)
+ *
+ */
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/reboot.h>
+
+#include "tuxonice_sysfs.h"
+#include "tuxonice_modules.h"
+#include "tuxonice.h"
+#include "tuxonice_ui.h"
+#include "tuxonice_netlink.h"
+#include "tuxonice_power_off.h"
+#include "tuxonice_builtin.h"
+
+static char local_printf_buf[1024]; /* Same as printk - should be safe */
+struct ui_ops *toi_current_ui;
+
+/**
+ * toi_wait_for_keypress - Wait for keypress via userui or /dev/console.
+ *
+ * @timeout: Maximum time to wait.
+ *
+ * Wait for a keypress, either from userui or /dev/console if userui isn't
+ * available. The non-userui path is particularly for at boot-time, prior
+ * to userui being started, when we have an important warning to give to
+ * the user.
+ */
+static char toi_wait_for_keypress(int timeout)
+{
+ if (toi_current_ui && toi_current_ui->wait_for_key(timeout))
+ return ' ';
+
+ return toi_wait_for_keypress_dev_console(timeout);
+}
+
+/* toi_early_boot_message()
+ * Description: Handle errors early in the process of booting.
+ * The user may press C to continue booting, perhaps
+ * invalidating the image, or space to reboot.
+ * This works from either the serial console or normally
+ * attached keyboard.
+ *
+ * Note that we come in here from init, while the kernel is
+ * locked. If we want to get events from the serial console,
+ * we need to temporarily unlock the kernel.
+ *
+ * toi_early_boot_message may also be called post-boot.
+ * In this case, it simply printks the message and returns.
+ *
+ * Arguments: int Whether we are able to erase the image.
+ * int default_answer. What to do when we timeout. This
+ * will normally be continue, but the user might
+ * provide command line options (__setup) to override
+ * particular cases.
+ * Char *. Pointer to a string explaining why we're moaning.
+ */
+
+#define say(message, a...) printk(KERN_EMERG message, ##a)
+
+void toi_early_boot_message(int message_detail, int default_answer,
+ char *warning_reason, ...)
+{
+#if defined(CONFIG_VT) || defined(CONFIG_SERIAL_CONSOLE)
+ unsigned long orig_state = get_toi_state(), continue_req = 0;
+ unsigned long orig_loglevel = console_loglevel;
+ int can_ask = 1;
+#else
+ int can_ask = 0;
+#endif
+
+ va_list args;
+ int printed_len;
+
+ if (!toi_wait) {
+ set_toi_state(TOI_CONTINUE_REQ);
+ can_ask = 0;
+ }
+
+ if (warning_reason) {
+ va_start(args, warning_reason);
+ printed_len = vsnprintf(local_printf_buf,
+ sizeof(local_printf_buf),
+ warning_reason,
+ args);
+ va_end(args);
+ }
+
+ if (!test_toi_state(TOI_BOOT_TIME)) {
+ printk("TuxOnIce: %s\n", local_printf_buf);
+ return;
+ }
+
+ if (!can_ask) {
+ continue_req = !!default_answer;
+ goto post_ask;
+ }
+
+#if defined(CONFIG_VT) || defined(CONFIG_SERIAL_CONSOLE)
+ console_loglevel = 7;
+
+ say("=== TuxOnIce ===\n\n");
+ if (warning_reason) {
+ say("BIG FAT WARNING!! %s\n\n", local_printf_buf);
+ switch (message_detail) {
+ case 0:
+ say("If you continue booting, note that any image WILL"
+ "NOT BE REMOVED.\nTuxOnIce is unable to do so "
+ "because the appropriate modules aren't\n"
+ "loaded. You should manually remove the image "
+ "to avoid any\npossibility of corrupting your "
+ "filesystem(s) later.\n");
+ break;
+ case 1:
+ say("If you want to use the current TuxOnIce image, "
+ "reboot and try\nagain with the same kernel "
+ "that you hibernated from. If you want\n"
+ "to forget that image, continue and the image "
+ "will be erased.\n");
+ break;
+ }
+ say("Press SPACE to reboot or C to continue booting with "
+ "this kernel\n\n");
+ if (toi_wait > 0)
+ say("Default action if you don't select one in %d "
+ "seconds is: %s.\n",
+ toi_wait,
+ default_answer == TOI_CONTINUE_REQ ?
+ "continue booting" : "reboot");
+ } else {
+ say("BIG FAT WARNING!!\n\n"
+ "You have tried to resume from this image before.\n"
+ "If it failed once, it may well fail again.\n"
+ "Would you like to remove the image and boot "
+ "normally?\nThis will be equivalent to entering "
+ "noresume on the\nkernel command line.\n\n"
+ "Press SPACE to remove the image or C to continue "
+ "resuming.\n\n");
+ if (toi_wait > 0)
+ say("Default action if you don't select one in %d "
+ "seconds is: %s.\n", toi_wait,
+ !!default_answer ?
+ "continue resuming" : "remove the image");
+ }
+ console_loglevel = orig_loglevel;
+
+ set_toi_state(TOI_SANITY_CHECK_PROMPT);
+ clear_toi_state(TOI_CONTINUE_REQ);
+
+ if (toi_wait_for_keypress(toi_wait) == 0) /* We timed out */
+ continue_req = !!default_answer;
+ else
+ continue_req = test_toi_state(TOI_CONTINUE_REQ);
+
+#endif /* CONFIG_VT or CONFIG_SERIAL_CONSOLE */
+
+post_ask:
+ if ((warning_reason) && (!continue_req))
+ kernel_restart(NULL);
+
+ restore_toi_state(orig_state);
+ if (continue_req)
+ set_toi_state(TOI_CONTINUE_REQ);
+}
+
+#undef say
+
+/*
+ * User interface specific /sys/power/tuxonice entries.
+ */
+
+static struct toi_sysfs_data sysfs_params[] = {
+#if defined(CONFIG_NET) && defined(CONFIG_SYSFS)
+ SYSFS_INT("default_console_level", SYSFS_RW,
+ &toi_bkd.toi_default_console_level, 0, 7, 0, NULL),
+ SYSFS_UL("debug_sections", SYSFS_RW, &toi_bkd.toi_debug_state, 0,
+ 1 << 30, 0),
+ SYSFS_BIT("log_everything", SYSFS_RW, &toi_bkd.toi_action, TOI_LOGALL,
+ 0)
+#endif
+};
+
+static struct toi_module_ops userui_ops = {
+ .type = MISC_HIDDEN_MODULE,
+ .name = "printk ui",
+ .directory = "user_interface",
+ .module = THIS_MODULE,
+ .sysfs_data = sysfs_params,
+ .num_sysfs_entries = sizeof(sysfs_params) /
+ sizeof(struct toi_sysfs_data),
+};
+
+int toi_register_ui_ops(struct ui_ops *this_ui)
+{
+ if (toi_current_ui) {
+ printk(KERN_INFO "Only one TuxOnIce user interface module can "
+ "be loaded at a time.");
+ return -EBUSY;
+ }
+
+ toi_current_ui = this_ui;
+
+ return 0;
+}
+
+void toi_remove_ui_ops(struct ui_ops *this_ui)
+{
+ if (toi_current_ui != this_ui)
+ return;
+
+ toi_current_ui = NULL;
+}
+
+/* toi_console_sysfs_init
+ * Description: Boot time initialisation for user interface.
+ */
+
+int toi_ui_init(void)
+{
+ return toi_register_module(&userui_ops);
+}
+
+void toi_ui_exit(void)
+{
+ toi_unregister_module(&userui_ops);
+}