diff -ruNp 833-suspend-ui-old/kernel/power/suspend2_core/ui.c 833-suspend-ui-new/kernel/power/suspend2_core/ui.c
--- 833-suspend-ui-old/kernel/power/suspend2_core/ui.c	1970-01-01 10:00:00.000000000 +1000
+++ 833-suspend-ui-new/kernel/power/suspend2_core/ui.c	2004-12-13 19:31:49.775909640 +1100
@@ -0,0 +1,660 @@
+/*
+ * kernel/power/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-2004 Nigel Cunningham <ncunningham@linuxmail.org>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Routines for Software Suspend's user interface.
+ * 
+ * The user interface is modular, providing support for setting a general
+ * status message, a progress bar, an in-progress-bar message and
+ * displaying debugging messages instead when the console log level is
+ * switched > 1.
+ *
+ * As well as displaying status information, the user has some control
+ * over the software while suspending. Hooks in drivers/char/console.c
+ * and drivers/char/serial.c allow a user on the keyboard or serial
+ * console to...
+ *
+ * 					 	  Key
+ * Toggle rebooting			 	   R
+ * Toggle logging all output		 	   L
+ * Toggle pausing between major steps (1)	   P
+ * Toggle pausing at minor steps		   S
+ * Switch log levels (2)			  0-7
+ * Cancel the suspend (3)			 Escape
+ * Continue when paused				 Space
+ *
+ * (1) Pausing only occurs when the log level is > 1.
+ * (2) When debugging is not compiled in, only levels 0 & 1 work.
+ * (3) Can be disabled using /proc/suspend/enable_escape.
+ *
+ * (The following assumes debugging is compiled in)...
+ * 
+ * Fundamental to the debugging code is the idea that each debug 
+ * message which suspend can display has both a section of code to
+ * which it belongs and a level of verbosity. When suspend is running,
+ * it only displays a message if debugging for the section has been
+ * enabled prior to beginning the cycle and the current loglevel is
+ * greater than or equal to the level of the message.
+ * 
+ * Prior to starting a suspend cycle, a user can select which sections
+ * should display debugging information by setting
+ * /proc/suspend/debug_sections. This is a bit vector (values in
+ * include/linux/suspend-debug.h). The initial log level can be also
+ * be set using /proc/suspend/default_console_level.
+ * The debug sections and level can be changed prior to resuming using
+ * the kernel command line parameters suspend_dbg and suspend_lvl.
+ * 
+ * In addition to the above ability to control whether messages are
+ * displayed, messages can be displayed in two ways. The printlog call
+ * displays a message using printk, with the result that it is also
+ * logged to syslog in the normal way.
+ *
+ * A call to message usually gets the text to the screen using
+ * vt_console_print and is thus not logged. This is the preferred
+ * means of displaying highlevel debugging information, because it
+ * reduces clutter in the logs. (You can easily end up with 1/5645.^M
+ * 2/5645.^M 3/5645.^M... otherwise).
+ * If loggging of this output is wanted, the log all output toggle
+ * can be activated and printk will be used instead of printing to
+ * /dev/console (assuming the text mode module is used).
+ */
+#define SUSPEND_CONSOLE_C
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/suspend.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h>
+ 
+#include "../proc.h"
+#include "../plugins.h"
+#include "suspend.h"
+
+extern char suspend_print_buf[1024];	/* Same as printk - should be safe */
+static char lastheader[512];
+static int lastheader_message_len = 0;
+
+static int lastloglevel = -1;
+static int orig_loglevel = 0;
+static int orig_default_message_loglevel;
+static int orig_kmsg;
+
+/* abort_suspend
+ *
+ * Description: Begin to abort a cycle. If this wasn't at the user's request
+ * 		(and we're displaying output), tell the user why and wait for
+ * 		them to acknowledge the message.
+ * Arguments:	A parameterised string (imagine this is printk) to display,
+ *	 	telling the user why we're aborting.
+ */
+
+void abort_suspend(const char *fmt, ...)
+{
+	va_list args;
+	int printed_len = 0;
+
+	if (!TEST_RESULT_STATE(SUSPEND_ABORTED)) {
+		if (!TEST_RESULT_STATE(SUSPEND_ABORT_REQUESTED)) {
+			va_start(args, fmt);
+			printed_len = vsnprintf(suspend_print_buf, 
+					sizeof(suspend_print_buf), fmt, args);
+			va_end(args);
+			printed_len = sprintf(suspend_print_buf + printed_len,
+					" (Press SPACE to continue)");
+			prepare_status(1, 1, suspend_print_buf);
+
+			/* 
+			 * Make sure message seen - wait for shift to be
+			 * released if being pressed 
+			 */
+			suspend_wait_for_keypress();
+		}
+		/* Turn on aborting flag */
+		SET_RESULT_STATE(SUSPEND_ABORTED);
+	}
+}
+
+/* handle_loglevel_change
+ *
+ * Description:	Update the display when the user changes the log level.
+ * Returns:	Boolean indicating whether the level was changed.
+ */
+
+static int handle_loglevel_change(void)
+{
+	static int recursive = 0;
+	struct suspend_plugin_ops * this_plugin;
+	
+	if ((console_loglevel == lastloglevel) || recursive ||
+		(test_suspend_state(SUSPEND_IGNORE_LOGLEVEL)))
+		return 0;
+
+	recursive = 1;
+
+	list_for_each_entry(this_plugin, &suspend_ui, ops.ui.ui_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->ops.ui.log_level_change)
+			this_plugin->ops.ui.log_level_change();
+	}
+	
+	lastloglevel = console_loglevel;
+
+	recursive = 0;
+	
+	return 1;
+}
+
+/* suspend_message.
+ *
+ * Description:	This function is intended to do the same job as printk, but
+ * 		without normally logging what is printed. The point is to be
+ * 		able to get debugging info on screen without filling the logs
+ * 		with "1/534. ^M 2/534^M. 3/534^M"
+ *
+ * 		It may be called from an interrupt context - can't sleep!
+ *
+ * Arguments:	int mask: The debugging section(s) this message belongs to.
+ * 		int level: The level of verbosity of this message.
+ * 		int restartline: Whether to output a \r or \n with this line
+ * 			(\n if we're logging all output).
+ * 		const char *fmt, ...: Message to be displayed a la printk.
+ */
+void __suspend_message(unsigned long section, unsigned long level,
+		int normally_logged,
+		const char *fmt, ...)
+{
+	va_list args;
+	struct suspend_plugin_ops * this_plugin;
+
+	if ((level) && (level > console_loglevel))
+		return;
+
+	/* Don't do this if not printing anything - suspend_message gets called
+	 * before we prepare the console at resume time */
+	if (console_loglevel != lastloglevel)
+		handle_loglevel_change();
+
+	va_start(args, fmt);
+
+	list_for_each_entry(this_plugin, &suspend_ui, ops.ui.ui_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->ops.ui.message)
+			this_plugin->ops.ui.message(
+					section, level, normally_logged,
+					fmt, args);
+	}
+
+	va_end(args);
+}
+
+
+/* prepare_status
+ * Description:	Prepare the 'nice display', drawing the header and version,
+ * 		along with the current action and perhaps also resetting the
+ * 		progress bar.
+ * Arguments:	int printalways: Whether to print the action when debugging
+ * 		is on.
+ * 		int clearbar: Whether to reset the progress bar.
+ * 		const char *fmt, ...: The action to be displayed.
+ */
+void prepare_status(int printalways, int clearbar, const char *fmt, ...)
+{
+	va_list args;
+	struct suspend_plugin_ops * this_plugin;
+
+	if (console_loglevel != lastloglevel)
+		handle_loglevel_change();
+
+	if (fmt) {
+		va_start(args, fmt);
+		lastheader_message_len = vsnprintf(lastheader, 512, fmt, args);
+		va_end(args);
+	}
+
+	if (clearbar)
+		list_for_each_entry(this_plugin, &suspend_ui, ops.ui.ui_list) {
+			if (this_plugin->disabled)
+				continue;
+			if (this_plugin->ops.ui.update_progress)
+				this_plugin->ops.ui.update_progress(0, 1, NULL, NULL);
+		}
+
+	list_for_each_entry(this_plugin, &suspend_ui, ops.ui.ui_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->ops.ui.message)
+			this_plugin->ops.ui.message(
+				0, SUSPEND_STATUS, 1, lastheader, NULL);
+	}
+}
+
+/* update_status
+ *
+ * Description: Update the progress bar and (if on) in-bar message.
+ * Arguments:	UL value, maximum: Current progress percentage (value/max).
+ * 		const char *fmt, ...: Message to be displayed in the middle
+ * 		of the progress bar.
+ * 		Note that a NULL message does not mean that any previous
+ * 		message is erased! For that, you need prepare_status with
+ * 		clearbar on.
+ * Returns:	Unsigned long: The next value where status needs to be updated.
+ * 		This is to reduce unnecessary calls to update_status.
+ */
+unsigned long update_status(unsigned long value, unsigned long maximum,
+		const char *fmt, ...)
+{
+	unsigned long next_update = maximum, this = 0;
+	va_list args;
+	struct suspend_plugin_ops * this_plugin;
+
+	if (!maximum)
+		return maximum;
+
+	if (value < 0)
+		value = 0;
+
+	if (value > maximum)
+		value = maximum;
+
+	if (console_loglevel != lastloglevel)
+		handle_loglevel_change();
+
+	va_start(args, fmt);
+
+	list_for_each_entry(this_plugin, &suspend_ui, ops.ui.ui_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->ops.ui.update_progress) {
+			this = this_plugin->ops.ui.update_progress(
+					value, maximum, fmt, args);
+			if ((this) && (this < next_update))
+				next_update = this;
+		}
+	}
+
+	va_end(args);
+
+	return next_update;
+}
+
+static struct waiting_message
+{
+	int message;
+	struct waiting_message * next;
+} * waiting_messages = NULL;
+
+/* display_suspend_message
+ *
+ * Description:	Display a message as a result of the user pressing a key
+ * 		and the key being processed in an interrupt handler.
+ */
+
+int display_suspend_messages(void)
+{
+	int did_work;
+	
+	if (console_loglevel != lastloglevel)
+		handle_loglevel_change();
+
+	/* Loglevel change might add a message */
+	did_work = (waiting_messages != NULL);
+
+	while (waiting_messages) {
+		struct waiting_message * this_message = waiting_messages;
+
+		switch(waiting_messages->message) {
+			case 1:
+				prepare_status(1, 0, "Pausing %s.", 
+					TEST_ACTION_STATE(SUSPEND_PAUSE) ?
+					"enabled" : "disabled");
+				break;
+			case 2:
+				prepare_status(1, 0, "Rebooting %s.", 
+					TEST_ACTION_STATE(SUSPEND_REBOOT) ?
+					"enabled" : "disabled");
+				break;
+			case 3:
+				prepare_status(1, 0, "Single step %s.", 
+					TEST_ACTION_STATE(SUSPEND_SINGLESTEP) ?
+					"enabled" : "disabled");
+				break;
+			case 4:
+				prepare_status(1, 0, "Logging all output %s.",
+					TEST_ACTION_STATE(SUSPEND_LOGALL) ?
+					"enabled" : "disabled");
+				break;
+			case 5:
+				prepare_status(1, 1,
+					"--- ESCAPE PRESSED AGAIN :"
+					" TRYING HARDER TO ABORT ---");
+				break;
+			case 6:
+				prepare_status(1, 1, "--- ESCAPE PRESSED :"
+						" ABORTING PROCESS ---");
+				break;
+			case 7:
+				prepare_status(1, 0, "Slowing down %s.",
+					TEST_ACTION_STATE(SUSPEND_SLOW) ?
+					"enabled" : "disabled");
+				break;
+			case 8:
+				prepare_status(1, 0, "Log level changed to %d.",
+					console_loglevel);
+				break;
+			case 20:
+				prepare_status(1, 0, "General messages %s.",
+					TEST_DEBUG_STATE(SUSPEND_ANY_SECTION) ?
+					"enabled" : "disabled");
+				break;
+			case 21:
+				prepare_status(1, 0, "Freezer messages %s.",
+					TEST_DEBUG_STATE(SUSPEND_FREEZER) ?
+					"enabled" : "disabled");
+				break;
+			case 22:
+				prepare_status(1, 0, "Eat memory messages %s.",
+					TEST_DEBUG_STATE(SUSPEND_EAT_MEMORY) ?
+					"enabled" : "disabled");
+				break;
+			case 23:
+				prepare_status(1, 0, "Pageset messages %s.",
+					TEST_DEBUG_STATE(SUSPEND_PAGESETS) ?
+					"enabled" : "disabled");
+				break;
+			case 24:
+				prepare_status(1, 0, "IO messages %s.",
+					TEST_DEBUG_STATE(SUSPEND_IO) ?
+					"enabled" : "disabled");
+				break;
+			case 25:
+				prepare_status(1, 0, "Bmap messages %s.",
+					TEST_DEBUG_STATE(SUSPEND_BMAP) ?
+					"enabled" : "disabled");
+				break;
+			case 26:
+				prepare_status(1, 0, "Writer messages %s.",
+					TEST_DEBUG_STATE(SUSPEND_WRITER) ?
+					"enabled" : "disabled");
+				break;
+			case 27:
+				prepare_status(1, 0, "Memory messages %s.",
+					TEST_DEBUG_STATE(SUSPEND_MEMORY) ?
+					"enabled" : "disabled");
+				break;
+			case 28:
+				prepare_status(1, 0, "Extent messages %s.",
+					TEST_DEBUG_STATE(SUSPEND_EXTENTS) ?
+					"enabled" : "disabled");
+				break;
+			case 29:
+				prepare_status(1, 0, "Memory pool messages %s.",
+					TEST_DEBUG_STATE(SUSPEND_MEM_POOL) ?
+					"enabled" : "disabled");
+				break;
+			case 30:
+				prepare_status(1, 0, "Nosave messages %s.",
+					TEST_DEBUG_STATE(SUSPEND_NOSAVE) ?
+					"enabled" : "disabled");
+				break;
+			case 31:
+				prepare_status(1, 0, "Integrity messages %s.",
+					TEST_DEBUG_STATE(SUSPEND_INTEGRITY) ?
+					"enabled" : "disabled");
+				break;
+			case 99:
+				prepare_status(1, 0, "Timer freezer disabled.");
+		}
+
+		waiting_messages = this_message->next;
+		kfree(this_message);
+	}
+	return did_work;
+}
+
+/* schedule_suspend_message
+ *
+ * Description:
+ * 
+ */
+
+void schedule_suspend_message(int message_number)
+{
+	struct waiting_message * new_message =
+		kmalloc(sizeof(struct waiting_message), GFP_ATOMIC);
+
+	if (!new_message) {
+		printk("Argh. Unable to allocate memory for "
+				"scheduling the display of a message.\n");
+		return;
+	}
+
+	new_message->message = message_number;
+	new_message->next = waiting_messages;
+
+	waiting_messages = new_message;
+	return;
+}
+
+/* request_abort_suspend
+ *
+ * Description:	Handle the user requesting the cancellation of a suspend by
+ * 		pressing escape. Note that on a second press, we try a little
+ * 		harder, attempting to forcefully thaw processes. This shouldn't
+ * 		been needed, and may result in an oops (if we've overwritten
+ * 		memory), but has been useful on ocassion.
+ * Callers:	Called from drivers/char/keyboard.c or drivers/char/serial.c
+ * 		when the user presses escape.
+ */
+void request_abort_suspend(void)
+{
+	if (test_suspend_state(SUSPEND_NOW_RESUMING) || (TEST_RESULT_STATE(SUSPEND_ABORT_REQUESTED)))
+		return;
+
+	if (TEST_RESULT_STATE(SUSPEND_ABORTED)) {
+		schedule_suspend_message(5);
+		show_state();
+		thaw_processes(FREEZER_ALL_THREADS);
+	} else {
+		schedule_suspend_message(6);
+		SET_RESULT_STATE(SUSPEND_ABORTED);
+		SET_RESULT_STATE(SUSPEND_ABORT_REQUESTED);
+	}
+}
+
+/* check_shift_keys
+ * 
+ * Description:	Potentially pause and wait for the user to tell us to continue.
+ * 		We normally only pause when @pause is set.
+ * Arguments:	int pause: Whether we normally pause.
+ * 		char * message: The message to display. Not parameterised
+ * 		 because it's normally a constant.
+ */
+
+void check_shift_keys(int pause, char * message)
+{
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+	int displayed_message = 0, last_key = 0;
+	
+	display_suspend_messages();
+	while (last_key != 32 &&
+		((TEST_ACTION_STATE(SUSPEND_PAUSE) && pause) || 
+		 (TEST_ACTION_STATE(SUSPEND_SINGLESTEP)))) {
+		if (!displayed_message) {
+			prepare_status(1, 0, 
+			   "%s Press SPACE to continue.%s",
+			   message ? message : "",
+			   (TEST_ACTION_STATE(SUSPEND_SINGLESTEP)) ? 
+			   " Single step on." : "");
+			displayed_message = 1;
+		}
+		last_key = suspend_wait_for_keypress();
+		display_suspend_messages();
+	}
+#else
+	display_suspend_messages();
+#endif
+}
+
+extern asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, 
+		unsigned long arg);
+
+/* suspend2_prepare_console
+ *
+ * Description:	Prepare a console for use, save current settings.
+ * Returns:	Boolean: Whether an error occured. Errors aren't
+ * 		treated as fatal, but a warning is printed.
+ */
+int suspend2_prepare_console(void)
+{
+	struct suspend_plugin_ops * this_plugin;
+
+	orig_loglevel = console_loglevel;
+	orig_default_message_loglevel = default_message_loglevel;
+	orig_kmsg = kmsg_redirect;
+
+	kmsg_redirect = fg_console + 1;
+	default_message_loglevel = 1;
+
+	if (!test_suspend_state(SUSPEND_NOW_RESUMING))
+		lastloglevel = console_loglevel = suspend_default_console_level;
+
+	list_for_each_entry(this_plugin, &suspend_ui, ops.ui.ui_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->ops.ui.prepare)
+			this_plugin->ops.ui.prepare();
+	}
+
+	return 0;
+}
+
+/* suspend2_restore_console
+ *
+ * Description: Restore the settings we saved above.
+ */
+
+void suspend2_cleanup_console(void)
+{
+	struct suspend_plugin_ops * this_plugin;
+
+	list_for_each_entry(this_plugin, &suspend_ui, ops.ui.ui_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->ops.ui.cleanup)
+			this_plugin->ops.ui.cleanup();
+	}
+
+	suspend_default_console_level = console_loglevel;
+	console_loglevel = orig_loglevel;
+	lastloglevel = -1;
+	kmsg_redirect = orig_kmsg;
+	default_message_loglevel = orig_default_message_loglevel;
+	return;
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ * User interface specific /proc/suspend entries.
+ */
+
+static struct suspend_proc_data proc_params[] = {
+	{ .filename			= "default_console_level",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_INTEGER,
+	  .data = {
+		  .integer = {
+			  .variable	= &suspend_default_console_level,
+			  .minimum	= 0,
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+			  .maximum	= 7,
+#else
+			  .maximum	= 1,
+#endif
+
+		  }
+	  }
+	},
+
+	{ .filename			= "enable_escape",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_CAN_CANCEL,
+		  }
+	  }
+	},
+
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+	{ .filename			= "debug_sections",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_UL,
+	  .data = {
+		  .ul = {
+			  .variable	= &suspend_debug_state,
+			  .minimum	= 0,
+			  .maximum	= 2 << 30,
+		  }
+	  }
+	},
+
+	{ .filename			= "log_everything",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_LOGALL,
+		  }
+	  }
+	},
+	  
+	{ .filename			= "pause_between_steps",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_PAUSE,
+		  }
+	  }
+	},
+#endif
+};
+
+/* suspend_console_proc_init
+ * Description: Boot time initialisation for user interface.
+ */
+void suspend_console_proc_init(void)
+{
+	int i, numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+
+	for (i=0; i< numfiles; i++)
+		suspend_register_procfile(&proc_params[i]);
+}
+
+void suspend_console_proc_exit(void)
+{
+	int i, numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+
+	for (i=0; i< numfiles; i++)
+		suspend_unregister_procfile(&proc_params[i]);
+}
+
+#endif
+EXPORT_SYMBOL_GPL(__suspend_message);
+EXPORT_SYMBOL_GPL(request_abort_suspend);
+EXPORT_SYMBOL_GPL(prepare_status);
+EXPORT_SYMBOL_GPL(update_status);
+EXPORT_SYMBOL_GPL(check_shift_keys);
+EXPORT_SYMBOL_GPL(abort_suspend);
