Index: kernel/arch/amd64/src/amd64.c
===================================================================
--- kernel/arch/amd64/src/amd64.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/amd64/src/amd64.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -151,13 +151,18 @@
 		i8254_init();
 		
+#if (defined(CONFIG_FB) || defined(CONFIG_EGA))
+		bool vesa = false;
+#endif
+		
 #ifdef CONFIG_FB
-		if (vesa_present()) 
-			vesa_init();
-		else
-#endif
+		vesa = vesa_init();
+#endif
+		
 #ifdef CONFIG_EGA
-			ega_init(EGA_BASE, EGA_VIDEORAM);  /* video */
-#else
-			{}
+		if (!vesa) {
+			outdev_t *egadev = ega_init(EGA_BASE, EGA_VIDEORAM);
+			if (egadev)
+				stdout_wire(egadev);
+		}
 #endif
 		
@@ -249,28 +254,4 @@
 }
 
-/** Acquire console back for kernel
- *
- */
-void arch_grab_console(void)
-{
-#ifdef CONFIG_FB
-	if (vesa_present())
-		vesa_redraw();
-	else
-#endif
-#ifdef CONFIG_EGA
-		ega_redraw();
-#else
-		{}
-#endif
-}
-
-/** Return console to userspace
- *
- */
-void arch_release_console(void)
-{
-}
-
 /** Construct function pointer
  *
Index: kernel/arch/arm32/include/mach/integratorcp/integratorcp.h
===================================================================
--- kernel/arch/arm32/include/mach/integratorcp/integratorcp.h	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/arm32/include/mach/integratorcp/integratorcp.h	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -98,15 +98,10 @@
 
 extern void icp_init(void);
-extern void icp_fb_init(void);
 extern void icp_output_init(void);
 extern void icp_input_init(void);
-extern void icp_release_console(void);
-extern void icp_grab_console(void);
 extern void icp_timer_irq_start(void);
 extern void icp_cpu_halt(void);
 extern void icp_irq_exception(int exc_no, istate_t *istate);
 extern uintptr_t icp_get_memory_size(void);
-extern uintptr_t icp_get_fb_address(void);
-extern void icp_fb_init(void);
 extern void icp_frame_init(void);
 
Index: kernel/arch/arm32/include/mach/testarm/testarm.h
===================================================================
--- kernel/arch/arm32/include/mach/testarm/testarm.h	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/arm32/include/mach/testarm/testarm.h	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -68,15 +68,10 @@
 
 extern void gxemul_init(void);
-extern void gxemul_fb_init(void);
 extern void gxemul_output_init(void);
 extern void gxemul_input_init(void);
-extern void gxemul_release_console(void);
-extern void gxemul_grab_console(void);
 extern void gxemul_timer_irq_start(void);
 extern void gxemul_cpu_halt(void);
 extern void gxemul_irq_exception(int exc_no, istate_t *istate);
 extern uintptr_t gxemul_get_memory_size(void);
-extern uintptr_t gxemul_get_fb_address(void);
-extern void gxemul_fb_init(void);
 extern void gxemul_frame_init(void);
 
Index: kernel/arch/arm32/include/machine_func.h
===================================================================
--- kernel/arch/arm32/include/machine_func.h	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/arm32/include/machine_func.h	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -49,13 +49,9 @@
 
 struct arm_machine_ops {
-	void		(*machine_grab_console)(void);
-	void		(*machine_release_console)(void);
 	void		(*machine_init)(void);
 	void		(*machine_timer_irq_start)(void);
 	void		(*machine_cpu_halt)(void);
 	uintptr_t	(*machine_get_memory_size)(void);
-	void		(*machine_fb_init)(void);
 	void		(*machine_irq_exception)(int, istate_t*);
-	uintptr_t	(*machine_get_fb_address)(void);
 	void		(*machine_frame_init)(void);
 	void		(*machine_output_init)(void);
@@ -64,11 +60,4 @@
 
 extern struct arm_machine_ops machine_ops;
-
-
-/** Acquire console back for kernel. */
-extern void machine_grab_console(void);
-
-/** Return console to userspace. */
-extern void machine_release_console(void);
 
 
@@ -91,9 +80,4 @@
 extern uintptr_t machine_get_memory_size(void);
 
-/** Initializes the Frame Buffer
- *
- */
-extern void machine_fb_init(void);
-
 
 /** Interrupt exception handler.
@@ -104,10 +88,4 @@
 extern void machine_irq_exception(int exc_no, istate_t *istate);
 
-
-/** Returns address of framebuffer device.
- *
- *  @return Address of framebuffer device.
- */
-extern uintptr_t machine_get_fb_address(void);
 
 /*
Index: kernel/arch/arm32/src/arm32.c
===================================================================
--- kernel/arch/arm32/src/arm32.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/arm32/src/arm32.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -89,11 +89,5 @@
 	interrupt_init();
 	
-#ifdef CONFIG_FB
-	machine_fb_init();
-#else
-#ifdef CONFIG_ARM_PRN
 	machine_output_init();
-#endif /* CONFIG_ARM_PRN */
-#endif /* CONFIG_FB */
 }
 
@@ -182,19 +176,4 @@
 }
 
-/** Acquire console back for kernel. */
-void arch_grab_console(void)
-{
-	machine_grab_console();
-#ifdef CONFIG_FB
-	fb_redraw();
-#endif
-}
-
-/** Return console to userspace. */
-void arch_release_console(void)
-{
-	machine_release_console();
-}
-
 /** @}
  */
Index: kernel/arch/arm32/src/mach/integratorcp/integratorcp.c
===================================================================
--- kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -57,13 +57,9 @@
 static irq_t icp_timer_irq;
 struct arm_machine_ops machine_ops = {
-	MACHINE_GENFUNC,
-	MACHINE_GENFUNC,
 	icp_init,
 	icp_timer_irq_start,
 	icp_cpu_halt,
 	icp_get_memory_size,
-	icp_fb_init,
 	icp_irq_exception,
-	icp_get_fb_address,
 	icp_frame_init,
 	icp_output_init,
@@ -128,22 +124,4 @@
 }
 
-/** Initializes the icp frame buffer */
-void icp_fb_init(void)
-{
-	fb_properties_t prop = {
-		.addr = 0,
-		.offset = 0,
-		.x = 640,
-		.y = 480,
-		.scan = 2560,
-		.visual = VISUAL_BGR_0_8_8_8,
-	};
-	prop.addr = icp_get_fb_address();
-	fb_init(&prop);
-	fb_parea.pbase = ICP_FB;
-	fb_parea.frames = 300;
-	ddi_parea_register(&fb_parea);
-}
-
 /** Initializes icp_hw_map. */
 void icp_init(void)
@@ -172,17 +150,6 @@
 }
 
-
-/** Acquire console back for kernel. */
-void icp_grab_console(void)
-{
-}
-
-/** Return console to userspace. */
-void icp_release_console(void)
-{
-}
-
 /** Starts icp Real Time Clock device, which asserts regular interrupts.
- * 
+ *
  * @param frequency Interrupts frequency (0 disables RTC).
  */
@@ -296,29 +263,39 @@
 }
 
-/** Returns address of framebuffer device.
- *
- *  @return Address of framebuffer device.
- */
-uintptr_t icp_get_fb_address(void)
-{
+/*
+ * Integrator specific frame initialization
+ */
+void
+icp_frame_init(void)
+{
+	frame_mark_unavailable(ICP_FB_FRAME, ICP_FB_NUM_FRAME);
+	frame_mark_unavailable(0, 256);
+}
+
+void icp_output_init(void)
+{
+#ifdef CONFIG_FB
 	if (!vga_init) {
 		icp_vga_init();
 		vga_init = true;
 	}
-	return (uintptr_t) ICP_FB;
-}
-
-/*
- * Integrator specific frame initialization
- */
-void
-icp_frame_init(void)
-{
-	frame_mark_unavailable(ICP_FB_FRAME, ICP_FB_NUM_FRAME);
-	frame_mark_unavailable(0, 256);
-}
-
-void icp_output_init(void)
-{
+	
+	fb_properties_t prop = {
+		.addr = ICP_FB,
+		.offset = 0,
+		.x = 640,
+		.y = 480,
+		.scan = 2560,
+		.visual = VISUAL_BGR_0_8_8_8,
+	};
+	
+	outdev_t *fbdev = fb_init(&prop);
+	if (fbdev) {
+		stdout_wire(fbdev);
+		fb_parea.pbase = ICP_FB;
+		fb_parea.frames = 300;
+		ddi_parea_register(&fb_parea);
+	}
+#endif
 }
 
Index: kernel/arch/arm32/src/mach/testarm/testarm.c
===================================================================
--- kernel/arch/arm32/src/mach/testarm/testarm.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/arm32/src/mach/testarm/testarm.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -57,13 +57,9 @@
 
 struct arm_machine_ops machine_ops = {
-	MACHINE_GENFUNC,
-	MACHINE_GENFUNC,
 	gxemul_init,
 	gxemul_timer_irq_start,
 	gxemul_cpu_halt,
 	gxemul_get_memory_size,
-	gxemul_fb_init,
 	gxemul_irq_exception,
-	gxemul_get_fb_address,
 	gxemul_frame_init,
 	gxemul_output_init,
@@ -78,6 +74,7 @@
 }
 
-void gxemul_fb_init(void)
-{
+void gxemul_output_init(void)
+{
+#ifdef CONFIG_FB
 	fb_properties_t prop = {
 		.addr = GXEMUL_FB_ADDRESS,
@@ -88,10 +85,15 @@
 		.visual = VISUAL_RGB_8_8_8,
 	};
-	fb_init(&prop);
-}
-
-void gxemul_output_init(void)
-{
-	dsrlnout_init((ioport8_t *) gxemul_kbd);
+	
+	outdev_t *fbdev = fb_init(&prop);
+	if (fbdev)
+		stdout_wire(fbdev);
+#endif
+	
+#ifdef CONFIG_ARM_PRN
+	outdev_t *dsrlndev = dsrlnout_init((ioport8_t *) gxemul_kbd);
+	if (dsrlndev)
+		stdout_wire(dsrlndev);
+#endif
 }
 
@@ -233,10 +235,4 @@
 }
 
-uintptr_t gxemul_get_fb_address()
-{
-	return ((uintptr_t)GXEMUL_FB_ADDRESS);
-}
-
-
 /** @}
  */
Index: kernel/arch/arm32/src/machine_func.c
===================================================================
--- kernel/arch/arm32/src/machine_func.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/arm32/src/machine_func.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -41,17 +41,4 @@
 
 
-/** Acquire console back for kernel. */
-void machine_grab_console(void)
-{
-	(machine_ops.machine_grab_console)();
-}
-
-/** Return console to userspace. */
-void machine_release_console(void)
-{
-	(machine_ops.machine_release_console)();
-}
-
-
 /** Maps HW devices to the kernel address space using #hw_map. */
 void machine_init(void)
@@ -84,13 +71,4 @@
 }
 
-/** Initializes the Frame Buffer
- *
- */
-void machine_fb_init(void)
-{
-	(machine_ops.machine_fb_init)();
-}
-
-
 /** Interrupt exception handler.
  *
@@ -103,13 +81,4 @@
 }
 
-
-/** Returns address of framebuffer device.
- *
- *  @return Address of framebuffer device.
- */
-uintptr_t machine_get_fb_address(void)
-{
-	return (machine_ops.machine_get_fb_address)();
-}
 
 /*
Index: kernel/arch/ia32/include/drivers/vesa.h
===================================================================
--- kernel/arch/ia32/include/drivers/vesa.h	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/ia32/include/drivers/vesa.h	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -36,7 +36,7 @@
 #define KERN_ia32_VESA_H_
 
-extern int vesa_present(void);
-extern void vesa_redraw(void);
-extern void vesa_init(void);
+#include <arch/types.h>
+
+extern bool vesa_init(void);
 
 #endif
Index: kernel/arch/ia32/src/drivers/vesa.c
===================================================================
--- kernel/arch/ia32/src/drivers/vesa.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/ia32/src/drivers/vesa.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup ia32	
+/** @addtogroup ia32
  * @{
  */
@@ -40,4 +40,6 @@
 #include <genarch/fb/visuals.h>
 #include <arch/drivers/vesa.h>
+#include <console/chardev.h>
+#include <console/console.h>
 #include <putchar.h>
 #include <mm/page.h>
@@ -66,15 +68,10 @@
 uint8_t vesa_blue_pos;
 
-int vesa_present(void)
+bool vesa_init(void)
 {
-	if ((vesa_width != 0xffff) && (vesa_height != 0xffff))
-		return true;
+	if ((vesa_width == 0xffff) || (vesa_height == 0xffff))
+		return false;
 	
-	return false;
-}
-
-void vesa_init(void)
-{
-	unsigned int visual;
+	visual_t visual;
 	
 	switch (vesa_bpp) {
@@ -97,5 +94,6 @@
 		break;
 	default:
-		panic("Unsupported bits per pixel.");
+		LOG("Unsupported bits per pixel.");
+		return false;
 	}
 	
@@ -108,10 +106,11 @@
 		.visual = visual,
 	};
-	fb_init(&vesa_props);
-}
-
-void vesa_redraw(void)
-{
-	fb_redraw();
+	
+	outdev_t *fbdev = fb_init(&vesa_props);
+	if (!fbdev)
+		return false;
+	
+	stdout_wire(fbdev);
+	return true;
 }
 
Index: kernel/arch/ia32/src/ia32.c
===================================================================
--- kernel/arch/ia32/src/ia32.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/ia32/src/ia32.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -112,13 +112,18 @@
 		i8254_init();
 		
+#if (defined(CONFIG_FB) || defined(CONFIG_EGA))
+		bool vesa = false;
+#endif
+		
 #ifdef CONFIG_FB
-		if (vesa_present())
-			vesa_init();
-		else
-#endif
+		vesa = vesa_init();
+#endif
+		
 #ifdef CONFIG_EGA
-			ega_init(EGA_BASE, EGA_VIDEORAM);  /* video */
-#else
-			{}
+		if (!vesa) {
+			outdev_t *egadev = ega_init(EGA_BASE, EGA_VIDEORAM);
+			if (egadev)
+				stdout_wire(egadev);
+		}
 #endif
 		
@@ -201,30 +206,6 @@
 	THREAD->arch.tls = addr;
 	set_tls_desc(addr);
-
+	
 	return 0;
-}
-
-/** Acquire console back for kernel
- *
- */
-void arch_grab_console(void)
-{
-#ifdef CONFIG_FB
-	if (vesa_present())
-		vesa_redraw();
-	else
-#endif
-#ifdef CONFIG_EGA
-		ega_redraw();
-#else
-		{}
-#endif
-}
-
-/** Return console to userspace
- *
- */
-void arch_release_console(void)
-{
 }
 
Index: kernel/arch/ia64/include/drivers/ski.h
===================================================================
--- kernel/arch/ia64/include/drivers/ski.h	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/ia64/include/drivers/ski.h	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -44,10 +44,8 @@
 } ski_instance_t;
 
-extern void skiout_init(void);
+extern outdev_t *skiout_init(void);
 
 extern ski_instance_t *skiin_init(void);
 extern void skiin_wire(ski_instance_t *, indev_t *);
-extern void ski_kbd_grab(void);
-extern void ski_kbd_release(void);
 
 #endif
Index: kernel/arch/ia64/src/drivers/ski.c
===================================================================
--- kernel/arch/ia64/src/drivers/ski.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/ia64/src/drivers/ski.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -47,23 +47,84 @@
 enum {
 	/** Interval between polling in microseconds */
-	POLL_INTERVAL =  10000,  /* 0.01 s */
-
+	POLL_INTERVAL = 10000,  /* 0.01 s */
+	
 	/** Max. number of characters to pull out at a time */
-	POLL_LIMIT    =     30,
-
-	SKI_INIT_CONSOLE  = 20,
-	SKI_GETCHAR       = 21,
-	SKI_PUTCHAR       = 31
+	POLL_LIMIT = 30,
+	
+	SKI_INIT_CONSOLE = 20,
+	SKI_GETCHAR      = 21,
+	SKI_PUTCHAR      = 31
 };
 
 static void ski_putchar(outdev_t *, const wchar_t, bool);
 
-static outdev_operations_t skiout_ops = {
-	.write = ski_putchar
+static outdev_operations_t skidev_ops = {
+	.write = ski_putchar,
+	.redraw = NULL
 };
 
-static outdev_t skiout;            /**< Ski output device. */
-static bool initialized = false;
-static bool kbd_disabled = false;
+static ski_instance_t *instance = NULL;
+
+/** Ask debug console if a key was pressed.
+ *
+ * Use SSC (Simulator System Call) to
+ * get character from debug console.
+ *
+ * This call is non-blocking.
+ *
+ * @return ASCII code of pressed key or 0 if no key pressed.
+ *
+ */
+static wchar_t ski_getchar(void)
+{
+	uint64_t ch;
+	
+	asm volatile (
+		"mov r15 = %1\n"
+		"break 0x80000;;\n"  /* modifies r8 */
+		"mov %0 = r8;;\n"
+		
+		: "=r" (ch)
+		: "i" (SKI_GETCHAR)
+		: "r15", "r8"
+	);
+	
+	return (wchar_t) ch;
+}
+
+/** Ask keyboard if a key was pressed.
+ *
+ * If so, it will repeat and pull up to POLL_LIMIT characters.
+ */
+static void poll_keyboard(ski_instance_t *instance)
+{
+	if (silent)
+		return;
+	
+	int count = POLL_LIMIT;
+	
+	while (count > 0) {
+		wchar_t ch = ski_getchar();
+		
+		if (ch == '\0')
+			break;
+		
+		indev_push_character(instance->srlnin, ch);
+		--count;
+	}
+}
+
+/** Kernel thread for polling keyboard. */
+static void kskipoll(void *arg)
+{
+	ski_instance_t *instance = (ski_instance_t *) arg;
+	
+	while (true) {
+		if (!silent)
+			poll_keyboard(instance);
+		
+		thread_usleep(POLL_INTERVAL);
+	}
+}
 
 /** Initialize debug console
@@ -75,5 +136,5 @@
 static void ski_init(void)
 {
-	if (initialized)
+	if (instance)
 		return;
 	
@@ -86,5 +147,18 @@
 	);
 	
-	initialized = true;
+	instance = malloc(sizeof(ski_instance_t), FRAME_ATOMIC);
+	
+	if (instance) {
+		instance->thread = thread_create(kskipoll, instance, TASK, 0,
+		    "kskipoll", true);
+		
+		if (!instance->thread) {
+			free(instance);
+			instance = NULL;
+			return;
+		}
+		
+		instance->srlnin = NULL;
+	}
 }
 
@@ -124,77 +198,28 @@
 }
 
-void skiout_init(void)
+outdev_t *skiout_init(void)
 {
 	ski_init();
-	
-	outdev_initialize("skiout", &skiout, &skiout_ops);
-	stdout_wire(&skiout);
-	
-	sysinfo_set_item_val("fb", NULL, false);
-}
-
-/** Ask debug console if a key was pressed.
- *
- * Use SSC (Simulator System Call) to
- * get character from debug console.
- *
- * This call is non-blocking.
- *
- * @return ASCII code of pressed key or 0 if no key pressed.
- *
- */
-static wchar_t ski_getchar(void)
-{
-	uint64_t ch;
-	
-	asm volatile (
-		"mov r15 = %1\n"
-		"break 0x80000;;\n"  /* modifies r8 */
-		"mov %0 = r8;;\n"
-		
-		: "=r" (ch)
-		: "i" (SKI_GETCHAR)
-		: "r15", "r8"
-	);
-	
-	return (wchar_t) ch;
-}
-
-/** Ask keyboard if a key was pressed.
- *
- * If so, it will repeat and pull up to POLL_LIMIT characters.
- */
-static void poll_keyboard(ski_instance_t *instance)
-{
-	wchar_t ch;
-	int count;
-
-	if (kbd_disabled)
-		return;
-
-	count = POLL_LIMIT;
-
-	while (count > 0) {
-		ch = ski_getchar();
-
-		if (ch == '\0')
-			break;
-
-		indev_push_character(instance->srlnin, ch);
-		--count;
-	}
-}
-
-/** Kernel thread for polling keyboard. */
-static void kskipoll(void *arg)
-{
-	ski_instance_t *instance = (ski_instance_t *) arg;
-	
-	while (true) {
-		if (!silent)
-			poll_keyboard(instance);
-		
-		thread_usleep(POLL_INTERVAL);
-	}
+	if (!instance)
+		return NULL;
+	
+	outdev_t *skidev = malloc(sizeof(outdev_t), FRAME_ATOMIC);
+	if (!skidev)
+		return NULL;
+	
+	outdev_initialize("skidev", skidev, &skidev_ops);
+	skidev->data = instance;
+	
+	if (!fb_exported) {
+		/*
+		 * This is the necessary evil until the userspace driver is entirely
+		 * self-sufficient.
+		 */
+		sysinfo_set_item_val("fb", NULL, false);
+		
+		fb_exported = true;
+	}
+	
+	return skidev;
 }
 
@@ -202,20 +227,4 @@
 {
 	ski_init();
-	
-	ski_instance_t *instance =
-	    malloc(sizeof(ski_instance_t), FRAME_ATOMIC);
-	
-	if (instance) {
-		instance->thread = thread_create(kskipoll, instance, TASK, 0,
-		    "kskipoll", true);
-		
-		if (!instance->thread) {
-			free(instance);
-			return NULL;
-		}
-		
-		instance->srlnin = NULL;
-	}
-	
 	return instance;
 }
@@ -233,14 +242,4 @@
 }
 
-void ski_kbd_grab(void)
-{
-	kbd_disabled = false;
-}
-
-void ski_kbd_release(void)
-{
-	kbd_disabled = true;
-}
-
 /** @}
  */
Index: kernel/arch/ia64/src/ia64.c
===================================================================
--- kernel/arch/ia64/src/ia64.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/ia64/src/ia64.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -160,9 +160,13 @@
 	}
 	
-	skiout_init();
+	outdev_t *skidev = skiout_init();
+	if (skidev)
+		stdout_wire(skidev);
 #endif
 	
 #ifdef CONFIG_EGA
-	ega_init(EGA_BASE, EGA_VIDEORAM);
+	outdev_t *egadev = ega_init(EGA_BASE, EGA_VIDEORAM);
+	if (egadev)
+		stdout_wire(egadev);
 #endif
 	
@@ -249,25 +253,5 @@
 unative_t sys_tls_set(unative_t addr)
 {
-        return 0;
-}
-
-/** Acquire console back for kernel
- *
- */
-void arch_grab_console(void)
-{
-#ifdef MACHINE_ski
-	ski_kbd_grab();
-#endif
-}
-
-/** Return console to userspace
- *
- */
-void arch_release_console(void)
-{
-#ifdef MACHINE_ski
-	ski_kbd_release();
-#endif
+	return 0;
 }
 
Index: kernel/arch/mips32/src/mips32.c
===================================================================
--- kernel/arch/mips32/src/mips32.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/mips32/src/mips32.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -144,10 +144,15 @@
 		.visual = VISUAL_RGB_8_8_8,
 	};
-	fb_init(&gxemul_prop);
-#else
+	
+	outdev_t *fbdev = fb_init(&gxemul_prop);
+	if (fbdev)
+		stdout_wire(fbdev);
+#endif
+
 #ifdef CONFIG_MIPS_PRN
-	dsrlnout_init((ioport8_t *) MSIM_KBD_ADDRESS);
-#endif /* CONFIG_MIPS_PRN */
-#endif /* CONFIG_FB */
+	outdev_t *dsrlndev = dsrlnout_init((ioport8_t *) MSIM_KBD_ADDRESS);
+	if (dsrlndev)
+		stdout_wire(dsrlndev);
+#endif
 }
 
@@ -252,18 +257,4 @@
 }
 
-void arch_grab_console(void)
-{
-#ifdef CONFIG_FB
-	fb_redraw();
-#endif
-}
-
-/** Return console to userspace
- *
- */
-void arch_release_console(void)
-{
-}
-
 /** @}
  */
Index: kernel/arch/ppc32/src/ppc32.c
===================================================================
--- kernel/arch/ppc32/src/ppc32.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/ppc32/src/ppc32.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -143,9 +143,11 @@
 			.visual = visual,
 		};
-		fb_init(&fb_prop);
-	}
-	
-	/* Consider only a single device for now */
-	return false;
+		
+		outdev_t *fbdev = fb_init(&fb_prop);
+		if (fbdev)
+			stdout_wire(fbdev);
+	}
+	
+	return true;
 }
 
@@ -235,21 +237,4 @@
 }
 
-/** Acquire console back for kernel
- *
- */
-void arch_grab_console(void)
-{
-#ifdef CONFIG_FB
-	fb_redraw();
-#endif
-}
-
-/** Return console to userspace
- *
- */
-void arch_release_console(void)
-{
-}
-
 /** Construct function pointer
  *
Index: kernel/arch/sparc64/include/drivers/scr.h
===================================================================
--- kernel/arch/sparc64/include/drivers/scr.h	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/sparc64/include/drivers/scr.h	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup sparc64	
+/** @addtogroup sparc64
  * @{
  */
@@ -50,5 +50,4 @@
 
 extern void scr_init(ofw_tree_node_t *node);
-extern void scr_redraw(void);
 
 #endif
Index: kernel/arch/sparc64/include/drivers/sgcn.h
===================================================================
--- kernel/arch/sparc64/include/drivers/sgcn.h	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/sparc64/include/drivers/sgcn.h	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -39,21 +39,22 @@
 #include <console/chardev.h>
 #include <proc/thread.h>
+#include <synch/spinlock.h>
 
 /* number of bytes in the TOC magic, including the NULL-terminator */
-#define TOC_MAGIC_BYTES		8
+#define TOC_MAGIC_BYTES  8
 
 /* number of bytes in the TOC key, including the NULL-terminator */
-#define TOC_KEY_SIZE		8
+#define TOC_KEY_SIZE  8
 
 /* maximum number of entries in the SRAM table of contents */
-#define MAX_TOC_ENTRIES		32
+#define MAX_TOC_ENTRIES  32
 
 /* number of bytes in the SGCN buffer magic, including the NULL-terminator */
-#define SGCN_MAGIC_BYTES	4
+#define SGCN_MAGIC_BYTES  4
 
 /**
  * Entry in the SRAM table of contents. Describes one segment of the SRAM
  * which serves a particular purpose (e.g. OBP serial console, Solaris serial
- * console, Solaris mailbox,...). 
+ * console, Solaris mailbox,...).
  */
 typedef struct {
@@ -84,5 +85,5 @@
 /**
  * SGCN buffer header. It is placed at the very beginning of the SGCN
- * buffer. 
+ * buffer.
  */
 typedef struct {
@@ -104,5 +105,5 @@
 	/** offset within the SGCN buffer of the input buffer write pointer */
 	uint32_t in_wrptr;
-
+	
 	/** offset within the SGCN buffer of the output buffer start */
 	uint32_t out_begin;
@@ -119,13 +120,29 @@
 
 typedef struct {
+	/** Starting address of SRAM */
+	uintptr_t sram_begin;
+	
+	/** Starting address of the SGCN buffer */
+	uintptr_t buffer_begin;
+	
+	/**
+	 * Ensure that writing to the buffer and consequent
+	 * update of the write pointer are one atomic operation.
+	 */
+	SPINLOCK_DECLARE(output_lock);
+	
+	/**
+	 * Prevent the input buffer read/write pointers from
+	 * getting to inconsistent state.
+	 */
+	SPINLOCK_DECLARE(input_lock);
+	
 	thread_t *thread;
 	indev_t *srlnin;
 } sgcn_instance_t;
 
-extern void sgcn_grab(void);
-extern void sgcn_release(void);
 extern sgcn_instance_t *sgcnin_init(void);
 extern void sgcnin_wire(sgcn_instance_t *, indev_t *);
-extern void sgcnout_init(void);
+extern outdev_t *sgcnout_init(void);
 
 #endif
Index: kernel/arch/sparc64/src/console.c
===================================================================
--- kernel/arch/sparc64/src/console.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/sparc64/src/console.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -103,6 +103,9 @@
 	}
 #endif
+	
 #ifdef CONFIG_SGCN_PRN
-	sgcnout_init();
+	outdev_t *sgcndev = sgcnout_init();
+	if (sgcndev)
+		stdout_wire(sgcndev);
 #endif
 }
@@ -131,29 +134,4 @@
 }
 
-
-/** Acquire console back for kernel
- *
- */
-void arch_grab_console(void)
-{
-#ifdef CONFIG_FB
-	scr_redraw();
-#endif
-	
-#ifdef CONFIG_SGCN_KBD
-	sgcn_grab();
-#endif
-}
-
-/** Return console to userspace
- *
- */
-void arch_release_console(void)
-{
-#ifdef CONFIG_SGCN_KBD
-	sgcn_release();
-#endif
-}
-
 /** @}
  */
Index: kernel/arch/sparc64/src/drivers/scr.c
===================================================================
--- kernel/arch/sparc64/src/drivers/scr.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/sparc64/src/drivers/scr.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -40,4 +40,6 @@
 #include <genarch/fb/fb.h>
 #include <genarch/fb/visuals.h>
+#include <console/chardev.h>
+#include <console/console.h>
 #include <arch/types.h>
 #include <string.h>
@@ -238,12 +240,10 @@
 		.visual = visual,
 	};
-	fb_init(&props);
+	
+	outdev_t *fbdev = fb_init(&props);
+	if (fbdev)
+		stdout_wire(fbdev);
 }
 
-void scr_redraw(void)
-{
-	fb_redraw();
-}
-
 /** @}
  */
Index: kernel/arch/sparc64/src/drivers/sgcn.c
===================================================================
--- kernel/arch/sparc64/src/drivers/sgcn.c	(revision b9c742533861d30ff1a3f7a0986e6b524800644d)
+++ kernel/arch/sparc64/src/drivers/sgcn.c	(revision 402a18fea4d8130d968ebe076514596f024af690)
@@ -49,5 +49,5 @@
 #include <synch/spinlock.h>
 
-#define POLL_INTERVAL		10000
+#define POLL_INTERVAL  10000
 
 /*
@@ -57,14 +57,14 @@
  * not sure whether this value is valid generally. 
  */
-#define SBBC_START		0x63000000000
+#define SBBC_START  0x63000000000
 
 /* offset of SRAM within the SBBC memory */
-#define SBBC_SRAM_OFFSET	0x900000
+#define SBBC_SRAM_OFFSET  0x900000
 
 /* size (in bytes) of the physical memory area which will be mapped */
-#define MAPPED_AREA_SIZE	(128 * 1024)
+#define MAPPED_AREA_SIZE  (128 * 1024)
 
 /* magic string contained at the beginning of SRAM */
-#define SRAM_TOC_MAGIC		"TOCSRAM"
+#define SRAM_TOC_MAGIC  "TOCSRAM"
 
 /*
@@ -78,8 +78,8 @@
  * Therefore HelenOS needs to make no such arrangements any more.
  */
-#define CONSOLE_KEY		"OBPCONS"
+#define CONSOLE_KEY  "OBPCONS"
 
 /* magic string contained at the beginning of the console buffer */
-#define SGCN_BUFFER_MAGIC	"CON"
+#define SGCN_BUFFER_MAGIC  "CON"
 
 /*
@@ -87,8 +87,8 @@
  * offset from the SRAM beginning.
  */
-#define SRAM(type, offset)	((type *) (sram_begin + (offset)))
+#define SRAM(type, offset)  ((type *) (instance->sram_begin + (offset)))
 
 /* Returns a pointer to the SRAM table of contents. */
-#define SRAM_TOC		(SRAM(iosram_toc_t, 0))
+#define SRAM_TOC  (SRAM(iosram_toc_t, 0))
 
 /*
@@ -97,43 +97,17 @@
  */
 #define SGCN_BUFFER(type, offset) \
-	((type *) (sgcn_buffer_begin + (offset)))
+	((type *) (instance->buffer_begin + (offset)))
 
 /** Returns a pointer to the console buffer header. */
-#define SGCN_BUFFER_HEADER	(SGCN_BUFFER(sgcn_buffer_header_t, 0))
-
-/** starting address of SRAM, will be set by the init_sram_begin function */
-static uintptr_t sram_begin;
-
-/**
- * starting address of the SGCN buffer, will be set by the
- * init_sgcn_buffer_begin function
- */
-static uintptr_t sgcn_buffer_begin;
-
-/* true iff the kernel driver should ignore pressed keys */
-static bool kbd_disabled;
-
-/* 
- * Ensures that writing to the buffer and consequent update of the write pointer
- * are together one atomic operation.
- */
-SPINLOCK_INITIALIZE(sgcn_output_lock);
-
-/* 
- * Prevents the input buffer read/write pointers from getting to inconsistent
- * state. 
- */
-SPINLOCK_INITIALIZE(sgcn_input_lock);
-
-
-/* functions referenced from definitions of I/O operations structures */
+#define SGCN_BUFFER_HEADER  (SGCN_BUFFER(sgcn_buffer_header_t, 0))
+
 static void sgcn_putchar(outdev_t *, const wchar_t, bool);
 
-/** SGCN output device operations */
-static outdev_operations_t sgcnout_ops = {
-	.write = sgcn_putchar
+static outdev_operations_t sgcndev_ops = {
+	.write = sgcn_putchar,
+	.redraw = NULL
 };
 
-static outdev_t sgcnout;	/**< SGCN output device. */
+static sgcn_instance_t *instance = NULL;
 
 /**
@@ -158,23 +132,68 @@
 static void init_sram_begin(void)
 {
-	ofw_tree_node_t *chosen;
-	ofw_tree_property_t *iosram_toc;
-	uintptr_t sram_begin_physical;
-
-	chosen = ofw_tree_lookup("/chosen");
+	ASSERT(instance)
+	
+	ofw_tree_node_t *chosen = ofw_tree_lookup("/chosen");
 	if (!chosen)
 		panic("Cannot find '/chosen'.");
-
-	iosram_toc = ofw_tree_getprop(chosen, "iosram-toc");
+	
+	ofw_tree_property_t *iosram_toc =
+	    ofw_tree_getprop(chosen, "iosram-toc");
 	if (!iosram_toc)
 		panic("Cannot find property 'iosram-toc'.");
 	if (!iosram_toc->value)
 		panic("Cannot find SRAM TOC.");
-
-	sram_begin_physical = SBBC_START + SBBC_SRAM_OFFSET
+	
+	uintptr_t sram_begin_physical = SBBC_START + SBBC_SRAM_OFFSET
 	    + *((uint32_t *) iosram_toc->value);
-	sram_begin = hw_map(sram_begin_physical, MAPPED_AREA_SIZE);
+	instance->sram_begin = hw_map(sram_begin_physical, MAPPED_AREA_SIZE);
 	
 	register_sram(sram_begin_physical);
+}
+
+/**
+ * Function regularly called by the keyboard polling thread. Finds out whether
+ * there are some unread characters in the input queue. If so, it picks them up
+ * and sends them to the upper layers of HelenOS.
+ */
+static void sgcn_poll(sgcn_instance_t *instance)
+{
+	uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
+	uint32_t end = SGCN_BUFFER_HEADER->in_end;
+	uint32_t size = end - begin;
+	
+	if (silent)
+		return;
+	
+	spinlock_lock(&instance->input_lock);
+	
+	/* we need pointers to volatile variables */
+	volatile char *buf_ptr = (volatile char *)
+	    SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
+	volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
+	volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
+	
+	while (*in_rdptr_ptr != *in_wrptr_ptr) {
+		buf_ptr = (volatile char *)
+		    SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
+		char c = *buf_ptr;
+		*in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
+		
+		indev_push_character(instance->srlnin, c);
+	}
+	
+	spinlock_unlock(&instance->input_lock);
+}
+
+/**
+ * Polling thread function.
+ */
+static void ksgcnpoll(void *instance) {
+	while (true) {
+		if (!silent)
+			sgcn_poll(instance);
+		
+		thread_usleep(POLL_INTERVAL);
+	}
 }
 
@@ -190,29 +209,41 @@
  * under the sram.buffer.offset sysinfo key.
  */
-static void sgcn_buffer_begin_init(void)
-{
-	static bool initialized;
-	
-	if (initialized)
+static void sgcn_init(void)
+{
+	if (instance)
 		return;
-
-	init_sram_begin();
-		
-	ASSERT(str_cmp(SRAM_TOC->magic, SRAM_TOC_MAGIC) == 0);
-	
-	/* lookup TOC entry with the correct key */
-	uint32_t i;
-	for (i = 0; i < MAX_TOC_ENTRIES; i++) {
-		if (str_cmp(SRAM_TOC->keys[i].key, CONSOLE_KEY) == 0)
-			break;
-	}
-	ASSERT(i < MAX_TOC_ENTRIES);
-	
-	sgcn_buffer_begin = sram_begin + SRAM_TOC->keys[i].offset;
-	
-	sysinfo_set_item_val("sram.buffer.offset", NULL,
-	    SRAM_TOC->keys[i].offset);
-	
-	initialized = true;
+	
+	instance = malloc(sizeof(sgcn_instance_t), FRAME_ATOMIC);
+	
+	if (instance) {
+		instance->thread = thread_create(ksgcnpoll, instance, TASK, 0,
+		    "ksgcnpoll", true);
+		
+		if (!instance->thread) {
+			free(instance);
+			instance = NULL;
+			return;
+		}
+		
+		init_sram_begin();
+		
+		ASSERT(str_cmp(SRAM_TOC->magic, SRAM_TOC_MAGIC) == 0);
+		
+		/* Lookup TOC entry with the correct key */
+		uint32_t i;
+		for (i = 0; i < MAX_TOC_ENTRIES; i++) {
+			if (str_cmp(SRAM_TOC->keys[i].key, CONSOLE_KEY) == 0)
+				break;
+		}
+		ASSERT(i < MAX_TOC_ENTRIES);
+		
+		instance->buffer_begin =
+		    instance->sram_begin + SRAM_TOC->keys[i].offset;
+		
+		sysinfo_set_item_val("sram.buffer.offset", NULL,
+		    SRAM_TOC->keys[i].offset);
+		
+		instance->srlnin = NULL;
+	}
 }
 
@@ -228,10 +259,10 @@
 	uint32_t size = end - begin;
 	
-	/* we need pointers to volatile variables */
+	/* We need pointers to volatile variables */
 	volatile char *buf_ptr = (volatile char *)
 	    SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
 	volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
 	volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
-
+	
 	/*
 	 * Write the character and increment the write pointer modulo the
@@ -249,6 +280,6 @@
 	 */
 	uint32_t new_wrptr = (((*out_wrptr_ptr) - begin + 1) % size) + begin;
-	while (*out_rdptr_ptr == new_wrptr)
-		;
+	while (*out_rdptr_ptr == new_wrptr);
+	
 	*buf_ptr = c;
 	*out_wrptr_ptr = new_wrptr;
@@ -259,8 +290,8 @@
  * character is converted to CRLF.
  */
-static void sgcn_putchar(outdev_t *od, const wchar_t ch, bool silent)
+static void sgcn_putchar(outdev_t *dev, const wchar_t ch, bool silent)
 {
 	if (!silent) {
-		spinlock_lock(&sgcn_output_lock);
+		spinlock_lock(&instance->output_lock);
 		
 		if (ascii_check(ch)) {
@@ -271,66 +302,5 @@
 			sgcn_do_putchar(U_SPECIAL);
 		
-		spinlock_unlock(&sgcn_output_lock);
-	}
-}
-
-/**
- * Grabs the input for kernel.
- */
-void sgcn_grab(void)
-{
-	kbd_disabled = false;
-}
-
-/**
- * Releases the input so that userspace can use it.
- */
-void sgcn_release(void)
-{
-	kbd_disabled = true;
-}
-
-/**
- * Function regularly called by the keyboard polling thread. Finds out whether
- * there are some unread characters in the input queue. If so, it picks them up
- * and sends them to the upper layers of HelenOS.
- */
-static void sgcn_poll(sgcn_instance_t *instance)
-{
-	uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
-	uint32_t end = SGCN_BUFFER_HEADER->in_end;
-	uint32_t size = end - begin;
-
-	if (kbd_disabled)
-		return;
-
-	spinlock_lock(&sgcn_input_lock);
-	
-	/* we need pointers to volatile variables */
-	volatile char *buf_ptr = (volatile char *)
-	    SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
-	volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
-	volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
-	
-	while (*in_rdptr_ptr != *in_wrptr_ptr) {
-		buf_ptr = (volatile char *)
-		    SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
-		char c = *buf_ptr;
-		*in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
-			
-		indev_push_character(instance->srlnin, c);	
-	}	
-
-	spinlock_unlock(&sgcn_input_lock);
-}
-
-/**
- * Polling thread function.
- */
-static void ksgcnpoll(void *instance) {
-	while (1) {
-		if (!silent) 
-			sgcn_poll(instance);
-		thread_usleep(POLL_INTERVAL);
+		spinlock_unlock(&instance->output_lock);
 	}
 }
@@ -341,20 +311,5 @@
 sgcn_instance_t *sgcnin_init(void)
 {
-	sgcn_buffer_begin_init();
-	
-	sgcn_instance_t *instance =
-	    malloc(sizeof(sgcn_instance_t), FRAME_ATOMIC);
-	
-	if (instance) {
-		instance->srlnin = NULL;
-		instance->thread = thread_create(ksgcnpoll, instance, TASK, 0,
-		    "ksgcnpoll", true);
-		
-		if (!instance->thread) {
-			free(instance);
-			return NULL;
-		}
-	}
-	
+	sgcn_init();
 	return instance;
 }
@@ -364,8 +319,8 @@
 	ASSERT(instance);
 	ASSERT(srlnin);
-
+	
 	instance->srlnin = srlnin;
 	thread_ready(instance->thread);
-
+	
 	sysinfo_set_item_val("kbd", NULL, true);
 }
@@ -374,12 +329,28 @@
  * A public function which initializes output to the Serengeti console.
  */
-void sgcnout_init(void)
-{
-	sgcn_buffer_begin_init();
-
-	sysinfo_set_item_val("fb.kind", NULL, 4);
-
-	outdev_initialize("sgcnout", &sgcnout, &sgcnout_ops);
-	stdout_wire(&sgcnout);
+outdev_t *sgcnout_init(void)
+{
+	sgcn_init();
+	if (!instance)
+		return NULL;
+	
+	outdev_t *sgcndev = malloc(sizeof(outdev_t), FRAME_ATOMIC);
+	if (!sgcndev)
+		return NULL;
+	
+	outdev_initialize("sgcndev", sgcndev, &sgcndev_ops);
+	sgcndev->data = instance;
+	
+	if (!fb_exported) {
+		/*
+		 * This is the necessary evil until the userspace driver is entirely
+		 * self-sufficient.
+		 */
+		sysinfo_set_item_val("fb.kind", NULL, 4);
+		
+		fb_exported = true;
+	}
+	
+	return sgcndev;
 }
 
