diff -ruNp 850-text-ui-old/kernel/power/suspend_text.c 850-text-ui-new/kernel/power/suspend_text.c
--- 850-text-ui-old/kernel/power/suspend_text.c	1970-01-01 10:00:00.000000000 +1000
+++ 850-text-ui-new/kernel/power/suspend_text.c	2004-12-13 18:09:55.000000000 +1100
@@ -0,0 +1,634 @@
+/*
+ * kernel/power/suspend2_text_display.c
+ *
+ * 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 includes support for a text mode 'nice display'.
+ *
+ * The 'nice display' is text based and implements a progress bar and
+ * (optional) textual progress, as well as an overall description of
+ * the current action and the display of a header and the code version.
+ *
+ * It uses /dev/console, and thus also works on a serial console.
+ */
+#define SUSPEND_TEXT_MODE_C
+
+//#define __KERNEL_SYSCALLS__
+
+#include <linux/suspend.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h>
+#include <linux/syscalls.h>
+ 
+#include "plugins.h"
+#include "proc.h"
+#include "suspend.h"
+#include "suspend2_core/version.h"
+
+extern asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, 
+	size_t count);
+
+/*
+ * The original macros use currcons, which we don't have access to.
+ */
+#undef video_num_columns
+#define video_num_columns	(vc_cons[fg_console].d->vc_cols)
+#undef video_num_lines
+#define video_num_lines		(vc_cons[fg_console].d->vc_rows)
+
+static int barwidth = 0, barposn = -1, newbarposn = 0;
+static int draw_progress_bar = 1;
+static char print_buf[1024];	/* Same as printk - should be safe */
+
+/* We remember the last header that was (or could have been) displayed for
+ * use during log level switches */
+static char lastheader[512];
+static int lastheader_message_len = 0;
+
+static void hide_cursor(void);
+static void unblank_screen_via_file(void);
+
+static int suspend_console_fd = -1;
+static struct termios termios;
+static int lastloglevel = -1;
+
+#ifdef CONFIG_DEVFS_FS
+static int mounted_devfs = 0;
+#endif
+
+#define cond_console_print(chars) \
+	if (suspend_console_fd > -1) { \
+		int count = strlen(chars); \
+		sys_write(suspend_console_fd, chars, count); \
+		hide_cursor(); \
+		unblank_screen_via_file();  \
+	}
+
+static void move_cursor_to(unsigned char * xy)
+{
+	char buf[10];
+	
+	snprintf(buf, 10, "\233%d;%dH", xy[1], xy[0]);
+	cond_console_print(buf);
+}
+
+static void clear_display(void)
+{
+	char buf[4] = "\2332J";
+	unsigned char home[2] = { 0, 0 };
+	
+	cond_console_print(buf);
+	move_cursor_to(home);
+}
+
+static void hide_cursor(void)
+{
+	char buf[6] = "\033[?1c";
+	if (suspend_console_fd > -1)
+		sys_write(suspend_console_fd, buf, 5);
+}
+
+static void restore_cursor(void)
+{
+	char buf[6] = "\033[?0c";
+	if (suspend_console_fd > -1)
+		sys_write(suspend_console_fd, buf, 5);
+}
+
+static void unblank_screen_via_file(void)
+{
+	char buf[6] = "\033[13]";
+	if (suspend_console_fd > -1)
+		sys_write(suspend_console_fd, buf, 5);
+}
+
+/* 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.
+ */
+static void text_prepare_status(int printalways, int clearbar, const char *fmt, va_list args)
+{
+	unsigned char posn[2];
+
+	if (fmt)
+		lastheader_message_len = vsnprintf(lastheader, 512, fmt, args);
+
+	if (console_loglevel >= SUSPEND_ERROR) {
+
+		if (printalways)
+			printk("\n** %s\n", lastheader);
+		return;
+	}
+	
+	barwidth = (video_num_columns - 2 * (video_num_columns / 4) - 2);
+
+	/* Print version */
+	posn[0] = (unsigned char) (0);
+	posn[1] = (unsigned char) (video_num_lines);
+	move_cursor_to(posn);
+	cond_console_print(SUSPEND_CORE_VERSION);
+
+	/* Print header */
+	posn[0] = (unsigned char) ((video_num_columns - 31) / 2);
+	posn[1] = (unsigned char) ((video_num_lines / 3) - 3);
+	move_cursor_to(posn);
+
+	cond_console_print("S O F T W A R E   S U S P E N D");
+		
+	/* Print action */
+	posn[1] = (unsigned char) (video_num_lines / 3);
+	posn[0] = (unsigned char) 0;
+	move_cursor_to(posn);
+	
+	/* Clear old message */
+	for (barposn = 0; barposn < video_num_columns; barposn++) 
+		cond_console_print(" ");
+
+	posn[0] = (unsigned char)
+		((video_num_columns - lastheader_message_len) / 2);
+	move_cursor_to(posn);
+	cond_console_print(lastheader);
+	
+	if (draw_progress_bar) {
+		/* Draw left bracket of progress bar. */
+		posn[0] = (unsigned char) (video_num_columns / 4);
+		posn[1]++;
+		move_cursor_to(posn);
+		cond_console_print("[");
+
+		/* Draw right bracket of progress bar. */
+		posn[0] = (unsigned char) 
+			(video_num_columns - (video_num_columns / 4) - 1);
+		move_cursor_to(posn);
+		cond_console_print("]");
+
+		if (clearbar) {
+			/* Position at start of progress */
+			posn[0] = (unsigned char) (video_num_columns / 4 + 1);
+			move_cursor_to(posn);
+
+			/* Clear bar */
+			for (barposn = 0; barposn < barwidth; barposn++)
+				cond_console_print(" ");
+			move_cursor_to(posn);
+		}
+	}
+	
+	hide_cursor();
+
+	barposn = 0;
+}
+
+/* text_loglevel_change
+ *
+ * Description:	Update the display when the user changes the log level.
+ * Returns:	Boolean indicating whether the level was changed.
+ */
+
+static void text_loglevel_change(void)
+{
+	/* Calculate progress bar width. Note that whether the
+	 * splash screen is on might have changed (this might be
+	 * the first call in a new cycle), so we can't take it
+	 * for granted that the width is the same as last time
+	 * we came in here */
+	barwidth = (video_num_columns - 2 * (video_num_columns / 4) - 2);
+	barposn = 0;
+
+	/* Only reset the display if we're switching between nice display
+	 * and displaying debugging output */
+	
+	if (console_loglevel >= SUSPEND_ERROR) {
+		char message[35];
+		if (lastloglevel < SUSPEND_ERROR)
+			clear_display();
+
+		snprintf(message, 35,
+			"Switched to console loglevel %d.\n", 
+			console_loglevel);
+		cond_console_print(message);
+
+		if (lastloglevel < SUSPEND_ERROR) {
+			cond_console_print(lastheader);
+			cond_console_print("\n");
+		}
+	
+	} else if (lastloglevel >= SUSPEND_ERROR) {
+		clear_display();
+	
+		/* Get the nice display or last action [re]drawn */
+		text_prepare_status(1, 0, NULL, NULL);
+	}
+	
+	lastloglevel = console_loglevel;
+}
+/* text_update_progress
+ *
+ * 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 text_update_progress.
+ */
+unsigned long text_update_progress(unsigned long value, unsigned long maximum,
+		const char *fmt, va_list args)
+{
+	unsigned long next_update = 0;
+	int bitshift = generic_fls(maximum) - 16;
+	unsigned char posn[2];
+	int message_len = 0;
+
+	if (!barwidth)
+		barwidth = (video_num_columns - 2 * (video_num_columns / 4) - 2);
+
+	if (!maximum)
+		return maximum;
+
+	if (value < 0)
+		value = 0;
+
+	if (value > maximum)
+		value = maximum;
+
+	/* Try to avoid math problems - we can't do 64 bit math here
+	 * (and shouldn't need it - anyone got screen resolution
+	 * of 65536 pixels or more?) */
+	if (bitshift > 0) {
+		unsigned long temp_maximum = maximum >> bitshift;
+		unsigned long temp_value = value >> bitshift;
+		newbarposn = (int) (temp_value * barwidth / temp_maximum);
+	} else
+		newbarposn = (int) (value * barwidth / maximum);
+	
+	if (newbarposn < barposn)
+		barposn = 0;
+
+	next_update = ((newbarposn + 1) * maximum / barwidth) + 1;
+
+	if ((console_loglevel >= SUSPEND_ERROR) || (!draw_progress_bar))
+		return next_update;
+
+	/* Update bar */
+	if (draw_progress_bar) {
+		posn[1] = (unsigned char) ((video_num_lines / 3) + 1);
+
+		/* Clear bar if at start */
+		if (!barposn) {
+			posn[0] = (unsigned char) (video_num_columns / 4 + 1);
+			move_cursor_to(posn);
+			for (; barposn < barwidth; barposn++)
+				cond_console_print(" ");
+			barposn = 0;
+		}
+		posn[0] = (unsigned char) (video_num_columns / 4 + 1 + barposn);
+		move_cursor_to(posn);
+
+		for (; barposn < newbarposn; barposn++)
+			cond_console_print("-");
+	}
+
+	/* Print string in progress bar on loglevel 1 */
+	if ((fmt) && (console_loglevel)) {
+		message_len = vsnprintf(print_buf, sizeof(print_buf), " ", NULL);
+		message_len += vsnprintf(print_buf + message_len,
+				sizeof(print_buf) - message_len, fmt, args);
+		message_len += vsnprintf(print_buf + message_len,
+				sizeof(print_buf) - message_len, " ", NULL);
+
+		if (message_len) {
+			posn[0] = (unsigned char)
+				((video_num_columns - message_len) / 2);
+			posn[1] = (unsigned char)
+				((video_num_lines / 3) + 1);
+			move_cursor_to(posn);
+			cond_console_print(print_buf);
+		}
+	}
+
+	barposn = newbarposn;
+	hide_cursor();
+	
+	return next_update;
+}
+
+extern asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, 
+		unsigned long arg);
+
+static void text_message(unsigned long section, unsigned long level,
+		int normally_logged,
+		const char *fmt, va_list args)
+{
+	int printed_len = 0;
+
+	if ((section) && (!TEST_DEBUG_STATE(section)))
+		return;
+
+	if (level == SUSPEND_STATUS) {
+		text_prepare_status(1, 0, fmt, args);
+		return;
+	}
+	
+	if (level > console_loglevel)
+		return;
+
+	printed_len = vsnprintf(print_buf + printed_len,
+			sizeof(print_buf) - printed_len, fmt, args);
+
+
+	if ((TEST_ACTION_STATE(SUSPEND_LOGALL)) ||
+	    (normally_logged)) {
+		/* If we didn't print anything, don't do the \n anyway! */
+		if (!printed_len)
+			return;
+		printk(print_buf);
+	} else
+		cond_console_print(print_buf);
+}
+/*
+ *
+ */
+
+static void suspend_get_dev_console(void)
+{
+	if (suspend_console_fd > -1)
+		return;
+
+	suspend_console_fd = sys_open("/dev/console", O_RDWR | O_NONBLOCK, 0);
+	if (suspend_console_fd < 0) {
+		sys_mkdir("/dev", 0700);
+#ifdef CONFIG_DEVFS_FS
+		sys_mount("devfs", "/dev", "devfs", 0, NULL);
+		mounted_devfs = 1;
+#endif
+		suspend_console_fd = sys_open("/dev/console", O_RDWR | O_NONBLOCK, 0);
+	}
+	if (suspend_console_fd < 0) {
+		printk("Can't open /dev/console. Error value was %d.\n",
+				suspend_console_fd);
+		suspend_console_fd = -1;
+		return;
+	}
+
+	sys_ioctl(suspend_console_fd, TCGETS, (long)&termios);
+	termios.c_lflag &= ~ICANON;
+	sys_ioctl(suspend_console_fd, TCSETSF, (long)&termios);
+}
+
+/* prepare_console
+ *
+ */
+static void text_prepare_console(void)
+{
+	suspend_get_dev_console();
+
+	if (console_loglevel < 2)
+		clear_display();
+
+	lastloglevel = console_loglevel;
+}
+
+/* cleanup_console
+ *
+ * Description: Close our handle on /dev/console. Must be done
+ * earlier than pm_restore_console to avoid problems with other
+ * processes trying to grab it when thawed.
+ */
+
+static void cleanup_console(void)
+{
+	if (console_loglevel < 2)
+		clear_display();
+	restore_cursor();
+	termios.c_lflag |= ICANON;
+	sys_ioctl(suspend_console_fd, TCSETSF, (long)&termios);
+	sys_close(suspend_console_fd);
+	suspend_console_fd = -1;
+
+#ifdef CONFIG_DEVFS_FS
+	if (mounted_devfs)
+		sys_umount("/dev", 0);
+#endif
+	
+	lastloglevel = -1;
+	return;
+}
+
+static void text_redraw(void)
+{
+	sys_ioctl(suspend_console_fd, TIOCL_BLANKSCREEN, (long)&termios);
+	sys_ioctl(suspend_console_fd, TIOCL_UNBLANKSCREEN, (long)&termios);
+}
+
+static int text_keypress(unsigned int key)
+{
+	switch (key) {
+		case 48:
+			console_loglevel = 0;
+			break;
+		case 49:
+			console_loglevel = 1;
+			break;
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+		case 122:
+			/* `: Toggle slow */
+			suspend_action ^= (1 << SUSPEND_SLOW);
+			suspend2_core_ops->schedule_message(7);
+			break;
+		case 1:
+			/* F1: Toggle any section debugging. */
+			suspend_debug_state ^= (1 << SUSPEND_ANY_SECTION);
+			suspend2_core_ops->schedule_message(20);
+			break;
+		case 2:
+			/* F2: Freeze. */
+			suspend_debug_state ^= (1 << SUSPEND_FREEZER);
+			suspend2_core_ops->schedule_message(21);
+			break;
+		case 3:
+			/* F3: Eat Memory */
+			suspend_debug_state ^= (1 << SUSPEND_EAT_MEMORY);
+			suspend2_core_ops->schedule_message(22);
+			break;
+		case 4:
+			/* F4: Pagesets. */
+			suspend_debug_state ^= (1 << SUSPEND_PAGESETS);
+			suspend2_core_ops->schedule_message(23);
+			break;
+		case 5:
+			/* F5: IO. */
+			suspend_debug_state ^= (1 << SUSPEND_IO);
+			suspend2_core_ops->schedule_message(24);
+			break;
+		case 6:
+			/* F6: Bmapping of pages */
+			suspend_debug_state ^= (1 << SUSPEND_BMAP);
+			suspend2_core_ops->schedule_message(25);
+			break;
+		case 7:
+			/* F7: Writer */
+			suspend_debug_state ^= (1 << SUSPEND_WRITER);
+			suspend2_core_ops->schedule_message(26);
+			break;
+		case 8:
+			/* F8: Memory */
+			suspend_debug_state ^= (1 << SUSPEND_MEMORY);
+			suspend2_core_ops->schedule_message(27);
+			break;
+		case 9:
+			/* F9: Extents */
+			suspend_debug_state ^= (1 << SUSPEND_EXTENTS);
+			suspend2_core_ops->schedule_message(28);
+			break;
+		case 10:
+			/* F10: Memory Pool */
+			suspend_debug_state ^= (1 << SUSPEND_MEM_POOL);
+			suspend2_core_ops->schedule_message(29);
+			break;
+		case 11:
+			/* F11: Nosave */
+			suspend_debug_state ^= (1 << SUSPEND_NOSAVE);
+			suspend2_core_ops->schedule_message(30);
+			break;
+		case 12:
+			/* F12: Integrity */
+			suspend_debug_state ^= (1 << SUSPEND_INTEGRITY);
+			suspend2_core_ops->schedule_message(31);
+			break;
+		case 112:
+			/* During suspend, toggle pausing with P */
+			suspend_action ^= (1 << SUSPEND_PAUSE);
+			suspend2_core_ops->schedule_message(1);
+			break;
+		case 115:
+			/* Otherwise, if S pressed, toggle single step */
+			suspend_action ^= (1 << SUSPEND_SINGLESTEP);
+			suspend2_core_ops->schedule_message(3);
+			break;
+		case 108:
+			/* Otherwise, if L pressed, toggle logging everything */
+			suspend_action ^= (1 << SUSPEND_LOGALL);
+			suspend2_core_ops->schedule_message(4);
+			break;
+		case 116:
+			/* T: Toggle freezing timers */
+			clear_suspend_state(SUSPEND_TIMER_FREEZER_ON);
+			suspend2_core_ops->schedule_message(99);
+			break;
+		case 50:
+		case 51:
+		case 52:
+		case 53:
+		case 54:
+		case 55:
+		case 56:
+		case 57:
+			console_loglevel = ((key - 48));
+			break;
+#endif
+		default:
+			return 0;
+	}
+	return 1;
+}
+
+/*
+ * User interface specific /proc/suspend entries.
+ */
+
+static struct suspend_plugin_ops text_mode_ops;
+
+static struct suspend_proc_data proc_params[] = {
+	{ .filename			= "text_mode_progress_bar",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_INTEGER,
+	  .data = {
+		  .integer = {
+			  .variable	= &draw_progress_bar,
+			  .minimum	= 0,
+			  .maximum	= 1,
+
+		  }
+	  }
+	},
+	
+	{ .filename			= "disable_textmode_support",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_INTEGER,
+	  .data = {
+		.integer = {
+			.variable	= &text_mode_ops.disabled,
+			.minimum	= 0,
+			.maximum	= 1,
+		}
+	  }
+	}
+};
+
+static struct suspend_plugin_ops text_mode_ops = {
+	.type					= UI_PLUGIN,
+	.name					= "Text Mode Support",
+	.ops = {
+		.ui = {
+			.prepare		= text_prepare_console,	
+			.log_level_change	= text_loglevel_change,
+			.message		= text_message,
+			.update_progress	= text_update_progress,
+			.cleanup		= cleanup_console,
+			.keypress		= text_keypress,
+			.post_kernel_restore_redraw =
+				text_redraw,
+		}
+	}
+};
+
+/* ---- Registration ---- */
+
+static __init int text_mode_load(void)
+{
+	int i, numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+	int result;
+
+	if (!(result = suspend_register_plugin(&text_mode_ops))) {
+		printk("Software Suspend text mode support loaded.\n");
+		for (i=0; i< numfiles; i++)
+			suspend_register_procfile(&proc_params[i]);
+	}
+	return result;
+}
+
+#ifdef MODULE
+static __exit void text_mode_unload(void)
+{
+	int i, numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+
+	printk("Software Suspend text mode support unloading.\n");
+
+	for (i=0; i< numfiles; i++)
+		suspend_unregister_procfile(&proc_params[i]);
+	
+	suspend_unregister_plugin(&text_mode_ops);
+}
+
+module_init(text_mode_load);
+module_exit(text_mode_unload);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nigel Cunningham");
+MODULE_DESCRIPTION("Suspend2 Text Mode support");
+#else
+late_initcall(text_mode_load);
+#endif
