Index: kernel/arch/amd64/src/amd64.c
===================================================================
--- kernel/arch/amd64/src/amd64.c	(revision 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/amd64/src/amd64.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/arm32/include/mach/integratorcp/integratorcp.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/arm32/include/mach/testarm/testarm.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/arm32/include/machine_func.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/arm32/src/arm32.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/arm32/src/mach/testarm/testarm.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/arm32/src/machine_func.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/ia32/include/drivers/vesa.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/ia32/src/drivers/vesa.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/ia32/src/ia32.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/ia64/include/drivers/ski.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/ia64/src/drivers/ski.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/ia64/src/ia64.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/mips32/src/mips32.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/ppc32/src/ppc32.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/sparc64/include/drivers/scr.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/sparc64/include/drivers/sgcn.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/sparc64/src/console.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/sparc64/src/drivers/scr.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/arch/sparc64/src/drivers/sgcn.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -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;
 }
 
Index: kernel/genarch/include/drivers/dsrln/dsrlnout.h
===================================================================
--- kernel/genarch/include/drivers/dsrln/dsrlnout.h	(revision 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/genarch/include/drivers/dsrln/dsrlnout.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -40,6 +40,7 @@
 #include <arch/types.h>
 #include <typedefs.h>
+#include <console/chardev.h>
 
-extern void dsrlnout_init(ioport8_t *);
+extern outdev_t *dsrlnout_init(ioport8_t *);
 
 #endif
Index: kernel/genarch/include/drivers/ega/ega.h
===================================================================
--- kernel/genarch/include/drivers/ega/ega.h	(revision 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/genarch/include/drivers/ega/ega.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -38,4 +38,5 @@
 #include <arch/types.h>
 #include <typedefs.h>
+#include <console/chardev.h>
 
 #define EGA_COLS       80
@@ -48,6 +49,5 @@
 #define EGA_DATA_REG   1
 
-extern void ega_redraw(void);
-extern void ega_init(ioport8_t *, uintptr_t);
+extern outdev_t *ega_init(ioport8_t *, uintptr_t);
 
 #endif
Index: kernel/genarch/include/fb/fb.h
===================================================================
--- kernel/genarch/include/fb/fb.h	(revision 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/genarch/include/fb/fb.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -37,5 +37,6 @@
 
 #include <arch/types.h>
-#include <synch/spinlock.h>
+#include <console/chardev.h>
+#include <genarch/fb/visuals.h>
 
 /**
@@ -45,5 +46,5 @@
 	/** Physical address of the framebuffer device. */
 	uintptr_t addr;
-
+	
 	/**
 	 * Address where the first (top left) pixel is mapped,
@@ -51,22 +52,19 @@
 	 */
 	unsigned int offset;
-
+	
 	/** Screen width in pixels. */
 	unsigned int x;
-
+	
 	/** Screen height in pixels. */
 	unsigned int y;
-
+	
 	/** Bytes per one scanline. */
 	unsigned int scan;
-
+	
 	/** Color model. */
-	unsigned int visual;
+	visual_t visual;
 } fb_properties_t;
 
-SPINLOCK_EXTERN(fb_lock);
-
-void fb_redraw(void);
-bool fb_init(fb_properties_t *props);
+outdev_t *fb_init(fb_properties_t *props);
 
 #endif
Index: kernel/genarch/src/drivers/dsrln/dsrlnout.c
===================================================================
--- kernel/genarch/src/drivers/dsrln/dsrlnout.c	(revision 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/genarch/src/drivers/dsrln/dsrlnout.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -35,40 +35,63 @@
  */
 
-
 #include <genarch/drivers/dsrln/dsrlnout.h>
 #include <console/chardev.h>
 #include <arch/asm.h>
+#include <mm/slab.h>
 #include <console/console.h>
 #include <sysinfo/sysinfo.h>
 #include <string.h>
 
-static ioport8_t *dsrlnout_base;
+typedef struct {
+	ioport8_t *base;
+} dsrlnout_instance_t;
 
-static void dsrlnout_putchar(outdev_t *dev __attribute__((unused)), const wchar_t ch, bool silent)
+static void dsrlnout_putchar(outdev_t *dev, const wchar_t ch, bool silent)
 {
+	dsrlnout_instance_t *instance = (dsrlnout_instance_t *) dev->data;
+	
 	if (!silent) {
 		if (ascii_check(ch))
-			pio_write_8(dsrlnout_base, ch);
+			pio_write_8(instance->base, ch);
 		else
-			pio_write_8(dsrlnout_base, U_SPECIAL);
+			pio_write_8(instance->base, U_SPECIAL);
 	}
 }
 
-static outdev_t dsrlnout_console;
-static outdev_operations_t dsrlnout_ops = {
-	.write = dsrlnout_putchar
+static outdev_operations_t dsrlndev_ops = {
+	.write = dsrlnout_putchar,
+	.redraw = NULL
 };
 
-void dsrlnout_init(ioport8_t *base)
+outdev_t *dsrlnout_init(ioport8_t *base)
 {
-	/* Initialize the software structure. */
-	dsrlnout_base = base;
+	outdev_t *dsrlndev = malloc(sizeof(outdev_t), FRAME_ATOMIC);
+	if (!dsrlndev)
+		return NULL;
 	
-	outdev_initialize("dsrlnout", &dsrlnout_console, &dsrlnout_ops);
-	stdout_wire(&dsrlnout_console);
+	dsrlnout_instance_t *instance = malloc(sizeof(dsrlnout_instance_t), FRAME_ATOMIC);
+	if (!instance) {
+		free(dsrlndev);
+		return NULL;
+	}
 	
-	sysinfo_set_item_val("fb", NULL, true);
-	sysinfo_set_item_val("fb.kind", NULL, 3);
-	sysinfo_set_item_val("fb.address.physical", NULL, KA2PA(base));
+	outdev_initialize("dsrlndev", dsrlndev, &dsrlndev_ops);
+	dsrlndev->data = instance;
+	
+	instance->base = base;
+	
+	if (!fb_exported) {
+		/*
+		 * This is the necessary evil until the userspace driver is entirely
+		 * self-sufficient.
+		 */
+		sysinfo_set_item_val("fb", NULL, true);
+		sysinfo_set_item_val("fb.kind", NULL, 3);
+		sysinfo_set_item_val("fb.address.physical", NULL, KA2PA(base));
+		
+		fb_exported = true;
+	}
+	
+	return dsrlndev;
 }
 
Index: kernel/genarch/src/drivers/ega/ega.c
===================================================================
--- kernel/genarch/src/drivers/ega/ega.c	(revision 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/genarch/src/drivers/ega/ega.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -56,10 +56,4 @@
  */
 
-SPINLOCK_INITIALIZE(egalock);
-static uint32_t ega_cursor;
-static uint8_t *videoram;
-static uint8_t *backbuf;
-static ioport8_t *ega_base;
-
 #define SPACE  0x20
 #define STYLE  0x1e
@@ -68,4 +62,21 @@
 #define EMPTY_CHAR  ((STYLE << 8) | SPACE)
 
+typedef struct {
+	SPINLOCK_DECLARE(lock);
+	
+	uint32_t cursor;
+	uint8_t *addr;
+	uint8_t *backbuf;
+	ioport8_t *base;
+} ega_instance_t;
+
+static void ega_putchar(outdev_t *dev, wchar_t ch, bool silent);
+static void ega_redraw(outdev_t *dev);
+
+static outdev_operations_t egadev_ops = {
+	.write = ega_putchar,
+	.redraw = ega_redraw
+};
+
 static uint16_t ega_oem_glyph(const wchar_t ch)
 {
@@ -427,71 +438,80 @@
  * This function takes care of scrolling.
  */
-static void ega_check_cursor(bool silent)
-{
-	if (ega_cursor < EGA_SCREEN)
+static void ega_check_cursor(ega_instance_t *instance, bool silent)
+{
+	if (instance->cursor < EGA_SCREEN)
 		return;
 	
-	memmove((void *) backbuf, (void *) (backbuf + EGA_COLS * 2),
+	memmove((void *) instance->backbuf,
+	    (void *) (instance->backbuf + EGA_COLS * 2),
 	    (EGA_SCREEN - EGA_COLS) * 2);
-	memsetw(backbuf + (EGA_SCREEN - EGA_COLS) * 2, EGA_COLS, EMPTY_CHAR);
+	memsetw(instance->backbuf + (EGA_SCREEN - EGA_COLS) * 2,
+	    EGA_COLS, EMPTY_CHAR);
 	
 	if (!silent) {
-		memmove((void *) videoram, (void *) (videoram + EGA_COLS * 2),
+		memmove((void *) instance->addr,
+		    (void *) (instance->addr + EGA_COLS * 2),
 		    (EGA_SCREEN - EGA_COLS) * 2);
-		memsetw(videoram + (EGA_SCREEN - EGA_COLS) * 2, EGA_COLS, EMPTY_CHAR);
-	}
-	
-	ega_cursor = ega_cursor - EGA_COLS;
-}
-
-static void ega_show_cursor(bool silent)
+		memsetw(instance->addr + (EGA_SCREEN - EGA_COLS) * 2,
+		    EGA_COLS, EMPTY_CHAR);
+	}
+	
+	instance->cursor = instance->cursor - EGA_COLS;
+}
+
+static void ega_show_cursor(ega_instance_t *instance, bool silent)
 {
 	if (!silent) {
-		pio_write_8(ega_base + EGA_INDEX_REG, 0x0a);
-		uint8_t stat = pio_read_8(ega_base + EGA_DATA_REG);
-		pio_write_8(ega_base + EGA_INDEX_REG, 0x0a);
-		pio_write_8(ega_base + EGA_DATA_REG, stat & (~(1 << 5)));
-	}
-}
-
-static void ega_move_cursor(bool silent)
+		pio_write_8(instance->base + EGA_INDEX_REG, 0x0a);
+		uint8_t stat = pio_read_8(instance->base + EGA_DATA_REG);
+		pio_write_8(instance->base + EGA_INDEX_REG, 0x0a);
+		pio_write_8(instance->base + EGA_DATA_REG, stat & (~(1 << 5)));
+	}
+}
+
+static void ega_move_cursor(ega_instance_t *instance, bool silent)
 {
 	if (!silent) {
-		pio_write_8(ega_base + EGA_INDEX_REG, 0x0e);
-		pio_write_8(ega_base + EGA_DATA_REG, (uint8_t) ((ega_cursor >> 8) & 0xff));
-		pio_write_8(ega_base + EGA_INDEX_REG, 0x0f);
-		pio_write_8(ega_base + EGA_DATA_REG, (uint8_t) (ega_cursor & 0xff));
-	}
-}
-
-static void ega_sync_cursor(bool silent)
+		pio_write_8(instance->base + EGA_INDEX_REG, 0x0e);
+		pio_write_8(instance->base + EGA_DATA_REG,
+		    (uint8_t) ((instance->cursor >> 8) & 0xff));
+		pio_write_8(instance->base + EGA_INDEX_REG, 0x0f);
+		pio_write_8(instance->base + EGA_DATA_REG,
+		    (uint8_t) (instance->cursor & 0xff));
+	}
+}
+
+static void ega_sync_cursor(ega_instance_t *instance, bool silent)
 {
 	if (!silent) {
-		pio_write_8(ega_base + EGA_INDEX_REG, 0x0e);
-		uint8_t hi = pio_read_8(ega_base + EGA_DATA_REG);
-		pio_write_8(ega_base + EGA_INDEX_REG, 0x0f);
-		uint8_t lo = pio_read_8(ega_base + EGA_DATA_REG);
+		pio_write_8(instance->base + EGA_INDEX_REG, 0x0e);
+		uint8_t hi = pio_read_8(instance->base + EGA_DATA_REG);
+		pio_write_8(instance->base + EGA_INDEX_REG, 0x0f);
+		uint8_t lo = pio_read_8(instance->base + EGA_DATA_REG);
 		
-		ega_cursor = (hi << 8) | lo;
+		instance->cursor = (hi << 8) | lo;
 	} else
-		ega_cursor = 0;
-	
-	if (ega_cursor >= EGA_SCREEN)
-		ega_cursor = 0;
-	
-	if ((ega_cursor % EGA_COLS) != 0)
-		ega_cursor = (ega_cursor + EGA_COLS) - ega_cursor % EGA_COLS;
-	
-	memsetw(backbuf + ega_cursor * 2, EGA_SCREEN - ega_cursor, EMPTY_CHAR);
+		instance->cursor = 0;
+	
+	if (instance->cursor >= EGA_SCREEN)
+		instance->cursor = 0;
+	
+	if ((instance->cursor % EGA_COLS) != 0)
+		instance->cursor =
+		    (instance->cursor + EGA_COLS) - instance->cursor % EGA_COLS;
+	
+	memsetw(instance->backbuf + instance->cursor * 2,
+	    EGA_SCREEN - instance->cursor, EMPTY_CHAR);
 	
 	if (!silent)
-		memsetw(videoram + ega_cursor * 2, EGA_SCREEN - ega_cursor, EMPTY_CHAR);
-	
-	ega_check_cursor(silent);
-	ega_move_cursor(silent);
-	ega_show_cursor(silent);
-}
-
-static void ega_display_char(wchar_t ch, bool silent)
+		memsetw(instance->addr + instance->cursor * 2,
+		    EGA_SCREEN - instance->cursor, EMPTY_CHAR);
+	
+	ega_check_cursor(instance, silent);
+	ega_move_cursor(instance, silent);
+	ega_show_cursor(instance, silent);
+}
+
+static void ega_display_char(ega_instance_t *instance, wchar_t ch, bool silent)
 {
 	uint16_t index = ega_oem_glyph(ch);
@@ -507,79 +527,114 @@
 	}
 	
-	backbuf[ega_cursor * 2] = glyph;
-	backbuf[ega_cursor * 2 + 1] = style;
+	instance->backbuf[instance->cursor * 2] = glyph;
+	instance->backbuf[instance->cursor * 2 + 1] = style;
 	
 	if (!silent) {
-		videoram[ega_cursor * 2] = glyph;
-		videoram[ega_cursor * 2 + 1] = style;
-	}
-}
-
-static void ega_putchar(outdev_t *dev __attribute__((unused)), wchar_t ch, bool silent)
-{
-	ipl_t ipl;
-	
-	ipl = interrupts_disable();
-	spinlock_lock(&egalock);
+		instance->addr[instance->cursor * 2] = glyph;
+		instance->addr[instance->cursor * 2 + 1] = style;
+	}
+}
+
+static void ega_putchar(outdev_t *dev, wchar_t ch, bool silent)
+{
+	ega_instance_t *instance = (ega_instance_t *) dev->data;
+	
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&instance->lock);
 	
 	switch (ch) {
 	case '\n':
-		ega_cursor = (ega_cursor + EGA_COLS) - ega_cursor % EGA_COLS;
+		instance->cursor = (instance->cursor + EGA_COLS)
+		    - instance->cursor % EGA_COLS;
 		break;
 	case '\t':
-		ega_cursor = (ega_cursor + 8) - ega_cursor % 8;
+		instance->cursor = (instance->cursor + 8)
+		    - instance->cursor % 8;
 		break;
 	case '\b':
-		if (ega_cursor % EGA_COLS)
-			ega_cursor--;
+		if (instance->cursor % EGA_COLS)
+			instance->cursor--;
 		break;
 	default:
-		ega_display_char(ch, silent);
-		ega_cursor++;
+		ega_display_char(instance, ch, silent);
+		instance->cursor++;
 		break;
 	}
-	ega_check_cursor(silent);
-	ega_move_cursor(silent);
-	
-	spinlock_unlock(&egalock);
+	ega_check_cursor(instance, silent);
+	ega_move_cursor(instance, silent);
+	
+	spinlock_unlock(&instance->lock);
 	interrupts_restore(ipl);
 }
 
-static outdev_t ega_console;
-static outdev_operations_t ega_ops = {
-	.write = ega_putchar
-};
-
-void ega_init(ioport8_t *base, uintptr_t videoram_phys)
-{
-	/* Initialize the software structure. */
-	ega_base = base;
-	
-	backbuf = (uint8_t *) malloc(EGA_VRAM_SIZE, 0);
-	if (!backbuf)
-		panic("Unable to allocate backbuffer.");
-	
-	videoram = (uint8_t *) hw_map(videoram_phys, EGA_VRAM_SIZE);
+static void ega_redraw(outdev_t *dev)
+{
+	ega_instance_t *instance = (ega_instance_t *) dev->data;
+	
+	ipl_t ipl = interrupts_disable();
+	spinlock_lock(&instance->lock);
+	
+	memcpy(instance->addr, instance->backbuf, EGA_VRAM_SIZE);
+	ega_move_cursor(instance, silent);
+	ega_show_cursor(instance, silent);
+	
+	spinlock_unlock(&instance->lock);
+	interrupts_restore(ipl);
+}
+
+outdev_t *ega_init(ioport8_t *base, uintptr_t addr)
+{
+	outdev_t *egadev = malloc(sizeof(outdev_t), FRAME_ATOMIC);
+	if (!egadev)
+		return NULL;
+	
+	ega_instance_t *instance = malloc(sizeof(ega_instance_t), FRAME_ATOMIC);
+	if (!instance) {
+		free(egadev);
+		return NULL;
+	}
+	
+	outdev_initialize("egadev", egadev, &egadev_ops);
+	egadev->data = instance;
+	
+	spinlock_initialize(&instance->lock, "*ega_lock");
+	
+	instance->base = base;
+	instance->addr = (uint8_t *) hw_map(addr, EGA_VRAM_SIZE);
+	if (!instance->addr) {
+		LOG("Unable to EGA video memory.");
+		free(instance);
+		free(egadev);
+		return NULL;
+	}
+	
+	instance->backbuf = (uint8_t *) malloc(EGA_VRAM_SIZE, 0);
+	if (!instance->backbuf) {
+		LOG("Unable to allocate backbuffer.");
+		free(instance);
+		free(egadev);
+		return NULL;
+	}
 	
 	/* Synchronize the back buffer and cursor position. */
-	memcpy(backbuf, videoram, EGA_VRAM_SIZE);
-	ega_sync_cursor(silent);
-	
-	outdev_initialize("ega", &ega_console, &ega_ops);
-	stdout_wire(&ega_console);
-	
-	sysinfo_set_item_val("fb", NULL, true);
-	sysinfo_set_item_val("fb.kind", NULL, 2);
-	sysinfo_set_item_val("fb.width", NULL, EGA_COLS);
-	sysinfo_set_item_val("fb.height", NULL, EGA_ROWS);
-	sysinfo_set_item_val("fb.blinking", NULL, true);
-	sysinfo_set_item_val("fb.address.physical", NULL, videoram_phys);
-}
-
-void ega_redraw(void)
-{
-	memcpy(videoram, backbuf, EGA_VRAM_SIZE);
-	ega_move_cursor(silent);
-	ega_show_cursor(silent);
+	memcpy(instance->backbuf, instance->addr, EGA_VRAM_SIZE);
+	ega_sync_cursor(instance, silent);
+	
+	if (!fb_exported) {
+		/*
+		 * This is the necessary evil until the userspace driver is entirely
+		 * self-sufficient.
+		 */
+		sysinfo_set_item_val("fb", NULL, true);
+		sysinfo_set_item_val("fb.kind", NULL, 2);
+		sysinfo_set_item_val("fb.width", NULL, EGA_COLS);
+		sysinfo_set_item_val("fb.height", NULL, EGA_ROWS);
+		sysinfo_set_item_val("fb.blinking", NULL, true);
+		sysinfo_set_item_val("fb.address.physical", NULL, addr);
+		
+		fb_exported = true;
+	}
+	
+	return egadev;
 }
 
Index: kernel/genarch/src/fb/fb.c
===================================================================
--- kernel/genarch/src/fb/fb.c	(revision 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/genarch/src/fb/fb.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -53,49 +53,67 @@
 #include <byteorder.h>
 
-SPINLOCK_INITIALIZE(fb_lock);
-
-static uint8_t *fb_addr;
-static uint16_t *backbuf;
-static uint8_t *glyphs;
-static uint8_t *bgscan;
-
-static unsigned int xres;
-static unsigned int yres;
-
-static unsigned int ylogo;
-static unsigned int ytrim;
-static unsigned int rowtrim;
-
-static unsigned int scanline;
-static unsigned int glyphscanline;
-
-static unsigned int pixelbytes;
-static unsigned int glyphbytes;
-static unsigned int bgscanbytes;
-
-static unsigned int cols;
-static unsigned int rows;
-static unsigned int position = 0;
-
 #define BG_COLOR     0x000080
 #define FG_COLOR     0xffff00
 #define INV_COLOR    0xaaaaaa
 
-#define RED(x, bits)         (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1))
-#define GREEN(x, bits)       (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1))
-#define BLUE(x, bits)        (((x) >> (8 - (bits))) & ((1 << (bits)) - 1))
-
-#define COL2X(col)           ((col) * FONT_WIDTH)
-#define ROW2Y(row)           ((row) * FONT_SCANLINES)
-
-#define X2COL(x)             ((x) / FONT_WIDTH)
-#define Y2ROW(y)             ((y) / FONT_SCANLINES)
-
-#define FB_POS(x, y)         ((y) * scanline + (x) * pixelbytes)
-#define BB_POS(col, row)     ((row) * cols + (col))
-#define GLYPH_POS(glyph, y)  ((glyph) * glyphbytes + (y) * glyphscanline)
-
-
-static void (*rgb_conv)(void *, uint32_t);
+#define RED(x, bits)    (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1))
+#define GREEN(x, bits)  (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1))
+#define BLUE(x, bits)   (((x) >> (8 - (bits))) & ((1 << (bits)) - 1))
+
+#define COL2X(col)  ((col) * FONT_WIDTH)
+#define ROW2Y(row)  ((row) * FONT_SCANLINES)
+
+#define X2COL(x)  ((x) / FONT_WIDTH)
+#define Y2ROW(y)  ((y) / FONT_SCANLINES)
+
+#define FB_POS(instance, x, y) \
+	((y) * (instance)->scanline + (x) * (instance)->pixelbytes)
+
+#define BB_POS(instance, col, row) \
+	((row) * (instance)->cols + (col))
+
+#define GLYPH_POS(instance, glyph, y) \
+	((glyph) * (instance)->glyphbytes + (y) * (instance)->glyphscanline)
+
+typedef void (* rgb_conv_t)(void *, uint32_t);
+
+typedef struct {
+	SPINLOCK_DECLARE(lock);
+	
+	uint8_t *addr;
+	uint16_t *backbuf;
+	uint8_t *glyphs;
+	uint8_t *bgscan;
+	
+	rgb_conv_t rgb_conv;
+	
+	unsigned int xres;
+	unsigned int yres;
+	
+	unsigned int ylogo;
+	unsigned int ytrim;
+	unsigned int rowtrim;
+	
+	unsigned int scanline;
+	unsigned int glyphscanline;
+	
+	unsigned int pixelbytes;
+	unsigned int glyphbytes;
+	unsigned int bgscanbytes;
+	
+	unsigned int cols;
+	unsigned int rows;
+	
+	unsigned int position;
+} fb_instance_t;
+
+static void fb_putchar(outdev_t *dev, wchar_t ch, bool silent);
+static void fb_redraw_internal(fb_instance_t *instance);
+static void fb_redraw(outdev_t *dev);
+
+static outdev_operations_t fbdev_ops = {
+	.write = fb_putchar,
+	.redraw = fb_redraw
+};
 
 /*
@@ -169,5 +187,4 @@
 	    GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
 }
-
 
 /** BGR 3:2:3
@@ -179,5 +196,5 @@
  * and setting it to simulate the 8-bit truecolor.
  *
- * Currently we set the palette on the ia32, amd64 and sparc64 port.
+ * Currently we set the palette on the ia32, amd64, ppc32 and sparc64 port.
  *
  * Note that the byte is being inverted by this function. The reason is
@@ -194,22 +211,22 @@
 }
 
-
 /** Hide logo and refresh screen
  *
  */
-static void logo_hide(bool silent)
-{
-	ylogo = 0;
-	ytrim = yres;
-	rowtrim = rows;
+static void logo_hide(fb_instance_t *instance, bool silent)
+{
+	instance->ylogo = 0;
+	instance->ytrim = instance->yres;
+	instance->rowtrim = instance->rows;
+	
 	if (!silent)
-		fb_redraw();
-}
-
+		fb_redraw_internal(instance);
+}
 
 /** Draw character at given position
  *
  */
-static void glyph_draw(uint16_t glyph, unsigned int col, unsigned int row, bool silent, bool overlay)
+static void glyph_draw(fb_instance_t *instance, uint16_t glyph,
+    unsigned int col, unsigned int row, bool silent, bool overlay)
 {
 	unsigned int x = COL2X(col);
@@ -217,17 +234,17 @@
 	unsigned int yd;
 	
-	if (y >= ytrim)
-		logo_hide(silent);
+	if (y >= instance->ytrim)
+		logo_hide(instance, silent);
 	
 	if (!overlay)
-		backbuf[BB_POS(col, row)] = glyph;
+		instance->backbuf[BB_POS(instance, col, row)] = glyph;
 	
 	if (!silent) {
 		for (yd = 0; yd < FONT_SCANLINES; yd++)
-			memcpy(&fb_addr[FB_POS(x, y + yd + ylogo)],
-			    &glyphs[GLYPH_POS(glyph, yd)], glyphscanline);
-	}
-}
-
+			memcpy(&instance->addr[FB_POS(instance, x, y + yd + instance->ylogo)],
+			    &instance->glyphs[GLYPH_POS(instance, glyph, yd)],
+			    instance->glyphscanline);
+	}
+}
 
 /** Scroll screen down by one row
@@ -235,8 +252,8 @@
  *
  */
-static void screen_scroll(bool silent)
-{
-	if (ylogo > 0) {
-		logo_hide(silent);
+static void screen_scroll(fb_instance_t *instance, bool silent)
+{
+	if (instance->ylogo > 0) {
+		logo_hide(instance, silent);
 		return;
 	}
@@ -245,5 +262,5 @@
 		unsigned int row;
 		
-		for (row = 0; row < rows; row++) {
+		for (row = 0; row < instance->rows; row++) {
 			unsigned int y = ROW2Y(row);
 			unsigned int yd;
@@ -253,20 +270,20 @@
 				unsigned int col;
 				
-				for (col = 0, x = 0; col < cols; col++,
-				    x += FONT_WIDTH) {
+				for (col = 0, x = 0; col < instance->cols;
+				    col++, x += FONT_WIDTH) {
 					uint16_t glyph;
 					
-					if (row < rows - 1) {
-						if (backbuf[BB_POS(col, row)] ==
-						    backbuf[BB_POS(col, row + 1)])
+					if (row < instance->rows - 1) {
+						if (instance->backbuf[BB_POS(instance, col, row)] ==
+						    instance->backbuf[BB_POS(instance, col, row + 1)])
 							continue;
 						
-						glyph = backbuf[BB_POS(col, row + 1)];
+						glyph = instance->backbuf[BB_POS(instance, col, row + 1)];
 					} else
 						glyph = 0;
 					
-					memcpy(&fb_addr[FB_POS(x, y + yd)],
-					    &glyphs[GLYPH_POS(glyph, yd)],
-					    glyphscanline);
+					memcpy(&instance->addr[FB_POS(instance, x, y + yd)],
+					    &instance->glyphs[GLYPH_POS(instance, glyph, yd)],
+					    instance->glyphscanline);
 				}
 			}
@@ -274,80 +291,26 @@
 	}
 	
-	memmove(backbuf, &backbuf[BB_POS(0, 1)], cols * (rows - 1) * sizeof(uint16_t));
-	memsetw(&backbuf[BB_POS(0, rows - 1)], cols, 0);
-}
-
-
-static void cursor_put(bool silent)
-{
-	unsigned int col = position % cols;
-	unsigned int row = position / cols;
-	
-	glyph_draw(fb_font_glyph(U_CURSOR), col, row, silent, true);
-}
-
-
-static void cursor_remove(bool silent)
-{
-	unsigned int col = position % cols;
-	unsigned int row = position / cols;
-	
-	glyph_draw(backbuf[BB_POS(col, row)], col, row, silent, true);
-}
-
-
-/** Print character to screen
- *
- * Emulate basic terminal commands.
- *
- */
-static void fb_putchar(outdev_t *dev, wchar_t ch, bool silent)
-{
-	spinlock_lock(&fb_lock);
-	
-	switch (ch) {
-	case '\n':
-		cursor_remove(silent);
-		position += cols;
-		position -= position % cols;
-		break;
-	case '\r':
-		cursor_remove(silent);
-		position -= position % cols;
-		break;
-	case '\b':
-		cursor_remove(silent);
-		if (position % cols)
-			position--;
-		break;
-	case '\t':
-		cursor_remove(silent);
-		do {
-			glyph_draw(fb_font_glyph(' '), position % cols,
-			    position / cols, silent, false);
-			position++;
-		} while ((position % 8) && (position < cols * rows));
-		break;
-	default:
-		glyph_draw(fb_font_glyph(ch), position % cols,
-		    position / cols, silent, false);
-		position++;
-	}
-	
-	if (position >= cols * rows) {
-		position -= cols;
-		screen_scroll(silent);
-	}
-	
-	cursor_put(silent);
-	
-	spinlock_unlock(&fb_lock);
-}
-
-static outdev_t fb_console;
-static outdev_operations_t fb_ops = {
-	.write = fb_putchar
-};
-
+	memmove(instance->backbuf, &instance->backbuf[BB_POS(instance, 0, 1)],
+	    instance->cols * (instance->rows - 1) * sizeof(uint16_t));
+	memsetw(&instance->backbuf[BB_POS(instance, 0, instance->rows - 1)],
+	    instance->cols, 0);
+}
+
+static void cursor_put(fb_instance_t *instance, bool silent)
+{
+	unsigned int col = instance->position % instance->cols;
+	unsigned int row = instance->position / instance->cols;
+	
+	glyph_draw(instance, fb_font_glyph(U_CURSOR), col, row, silent, true);
+}
+
+static void cursor_remove(fb_instance_t *instance, bool silent)
+{
+	unsigned int col = instance->position % instance->cols;
+	unsigned int row = instance->position / instance->cols;
+	
+	glyph_draw(instance, instance->backbuf[BB_POS(instance, col, row)],
+	    col, row, silent, true);
+}
 
 /** Render glyphs
@@ -357,5 +320,5 @@
  *
  */
-static void glyphs_render(void)
+static void glyphs_render(fb_instance_t *instance)
 {
 	/* Prerender glyphs */
@@ -376,9 +339,10 @@
 			
 			for (x = 0; x < FONT_WIDTH; x++) {
-				void *dst = &glyphs[GLYPH_POS(glyph, y) +
-				    x * pixelbytes];
+				void *dst =
+				    &instance->glyphs[GLYPH_POS(instance, glyph, y) +
+				    x * instance->pixelbytes];
 				uint32_t rgb = (fb_font[glyph][y] &
 				    (1 << (7 - x))) ? fg_color : BG_COLOR;
-				rgb_conv(dst, rgb);
+				instance->rgb_conv(dst, rgb);
 			}
 		}
@@ -388,15 +352,63 @@
 	unsigned int x;
 	
-	for (x = 0; x < xres; x++)
-		rgb_conv(&bgscan[x * pixelbytes], BG_COLOR);
-}
-
-
-/** Refresh the screen
- *
- */
-void fb_redraw(void)
-{
-	if (ylogo > 0) {
+	for (x = 0; x < instance->xres; x++)
+		instance->rgb_conv(&instance->bgscan[x * instance->pixelbytes], BG_COLOR);
+}
+
+/** Print character to screen
+ *
+ * Emulate basic terminal commands.
+ *
+ */
+static void fb_putchar(outdev_t *dev, wchar_t ch, bool silent)
+{
+	fb_instance_t *instance = (fb_instance_t *) dev->data;
+	spinlock_lock(&instance->lock);
+	
+	switch (ch) {
+	case '\n':
+		cursor_remove(instance, silent);
+		instance->position += instance->cols;
+		instance->position -= instance->position % instance->cols;
+		break;
+	case '\r':
+		cursor_remove(instance, silent);
+		instance->position -= instance->position % instance->cols;
+		break;
+	case '\b':
+		cursor_remove(instance, silent);
+		if (instance->position % instance->cols)
+			instance->position--;
+		break;
+	case '\t':
+		cursor_remove(instance, silent);
+		do {
+			glyph_draw(instance, fb_font_glyph(' '),
+			    instance->position % instance->cols,
+			    instance->position / instance->cols, silent, false);
+			instance->position++;
+		} while ((instance->position % 8)
+		    && (instance->position < instance->cols * instance->rows));
+		break;
+	default:
+		glyph_draw(instance, fb_font_glyph(ch),
+		    instance->position % instance->cols,
+		    instance->position / instance->cols, silent, false);
+		instance->position++;
+	}
+	
+	if (instance->position >= instance->cols * instance->rows) {
+		instance->position -= instance->cols;
+		screen_scroll(instance, silent);
+	}
+	
+	cursor_put(instance, silent);
+	
+	spinlock_unlock(&instance->lock);
+}
+
+static void fb_redraw_internal(fb_instance_t *instance)
+{
+	if (instance->ylogo > 0) {
 		unsigned int y;
 		
@@ -404,6 +416,6 @@
 			unsigned int x;
 			
-			for (x = 0; x < xres; x++)
-				rgb_conv(&fb_addr[FB_POS(x, y)],
+			for (x = 0; x < instance->xres; x++)
+				instance->rgb_conv(&instance->addr[FB_POS(instance, x, y)],
 				    (x < LOGO_WIDTH) ?
 				    fb_logo[y * LOGO_WIDTH + x] :
@@ -414,6 +426,6 @@
 	unsigned int row;
 	
-	for (row = 0; row < rowtrim; row++) {
-		unsigned int y = ylogo + ROW2Y(row);
+	for (row = 0; row < instance->rowtrim; row++) {
+		unsigned int y = instance->ylogo + ROW2Y(row);
 		unsigned int yd;
 		
@@ -422,41 +434,51 @@
 			unsigned int col;
 			
-			for (col = 0, x = 0; col < cols;
+			for (col = 0, x = 0; col < instance->cols;
 			    col++, x += FONT_WIDTH) {
-				uint16_t glyph = backbuf[BB_POS(col, row)];
-				void *dst = &fb_addr[FB_POS(x, y + yd)];
-				void *src = &glyphs[GLYPH_POS(glyph, yd)];
-				memcpy(dst, src, glyphscanline);
+				uint16_t glyph =
+				    instance->backbuf[BB_POS(instance, col, row)];
+				void *dst = &instance->addr[FB_POS(instance, x, y + yd)];
+				void *src = &instance->glyphs[GLYPH_POS(instance, glyph, yd)];
+				memcpy(dst, src, instance->glyphscanline);
 			}
 		}
 	}
 	
-	if (COL2X(cols) < xres) {
+	if (COL2X(instance->cols) < instance->xres) {
 		unsigned int y;
-		unsigned int size = (xres - COL2X(cols)) * pixelbytes;
-		
-		for (y = ylogo; y < yres; y++)
-			memcpy(&fb_addr[FB_POS(COL2X(cols), y)], bgscan, size);
-	}
-	
-	if (ROW2Y(rowtrim) + ylogo < yres) {
+		unsigned int size =
+		    (instance->xres - COL2X(instance->cols)) * instance->pixelbytes;
+		
+		for (y = instance->ylogo; y < instance->yres; y++)
+			memcpy(&instance->addr[FB_POS(instance, COL2X(instance->cols), y)],
+			    instance->bgscan, size);
+	}
+	
+	if (ROW2Y(instance->rowtrim) + instance->ylogo < instance->yres) {
 		unsigned int y;
 		
-		for (y = ROW2Y(rowtrim) + ylogo; y < yres; y++)
-			memcpy(&fb_addr[FB_POS(0, y)], bgscan, bgscanbytes);
-	}
-}
-
+		for (y = ROW2Y(instance->rowtrim) + instance->ylogo;
+		    y < instance->yres; y++)
+			memcpy(&instance->addr[FB_POS(instance, 0, y)],
+			    instance->bgscan, instance->bgscanbytes);
+	}
+}
+
+/** Refresh the screen
+ *
+ */
+static void fb_redraw(outdev_t *dev)
+{
+	fb_instance_t *instance = (fb_instance_t *) dev->data;
+	
+	spinlock_lock(&instance->lock);
+	fb_redraw_internal(instance);
+	spinlock_unlock(&instance->lock);
+}
 
 /** Initialize framebuffer as a output character device
  *
- * @param addr   Physical address of the framebuffer
- * @param x      Screen width in pixels
- * @param y      Screen height in pixels
- * @param scan   Bytes per one scanline
- * @param visual Color model
- *
- */
-bool fb_init(fb_properties_t *props)
+ */
+outdev_t *fb_init(fb_properties_t *props)
 {
 	ASSERT(props);
@@ -465,4 +487,7 @@
 	ASSERT(props->scan > 0);
 	
+	rgb_conv_t rgb_conv;
+	unsigned int pixelbytes;
+	
 	switch (props->visual) {
 	case VISUAL_INDIRECT_8:
@@ -512,78 +537,107 @@
 	default:
 		LOG("Unsupported visual.");
-		return false;
-	}
-	
-	xres = props->x;
-	yres = props->y;
-	scanline = props->scan;
-	
-	cols = X2COL(xres);
-	rows = Y2ROW(yres);
-	
-	if (yres > ylogo) {
-		ylogo = LOGO_HEIGHT;
-		rowtrim = rows - Y2ROW(ylogo);
-		if (ylogo % FONT_SCANLINES > 0)
-			rowtrim--;
-		ytrim = ROW2Y(rowtrim);
+		return NULL;
+	}
+	
+	outdev_t *fbdev = malloc(sizeof(outdev_t), FRAME_ATOMIC);
+	if (!fbdev)
+		return NULL;
+	
+	fb_instance_t *instance = malloc(sizeof(fb_instance_t), FRAME_ATOMIC);
+	if (!instance) {
+		free(fbdev);
+		return NULL;
+	}
+	
+	outdev_initialize("fbdev", fbdev, &fbdev_ops);
+	fbdev->data = instance;
+	
+	spinlock_initialize(&instance->lock, "*fb_lock");
+	instance->rgb_conv = rgb_conv;
+	instance->pixelbytes = pixelbytes;
+	instance->xres = props->x;
+	instance->yres = props->y;
+	instance->scanline = props->scan;
+	instance->position = 0;
+	
+	instance->cols = X2COL(instance->xres);
+	instance->rows = Y2ROW(instance->yres);
+	
+	if (instance->yres > LOGO_HEIGHT) {
+		instance->ylogo = LOGO_HEIGHT;
+		instance->rowtrim = instance->rows - Y2ROW(instance->ylogo);
+		if (instance->ylogo % FONT_SCANLINES > 0)
+			instance->rowtrim--;
+		instance->ytrim = ROW2Y(instance->rowtrim);
 	} else {
-		ylogo = 0;
-		ytrim = yres;
-		rowtrim = rows;
-	}
-	
-	glyphscanline = FONT_WIDTH * pixelbytes;
-	glyphbytes = ROW2Y(glyphscanline);
-	bgscanbytes = xres * pixelbytes;
-	
-	size_t fbsize = scanline * yres;
-	size_t bbsize = cols * rows * sizeof(uint16_t);
-	size_t glyphsize = FONT_GLYPHS * glyphbytes;
-	
-	fb_addr = (uint8_t *) hw_map((uintptr_t) props->addr, fbsize);
-	if (!fb_addr) {
+		instance->ylogo = 0;
+		instance->ytrim = instance->yres;
+		instance->rowtrim = instance->rows;
+	}
+	
+	instance->glyphscanline = FONT_WIDTH * instance->pixelbytes;
+	instance->glyphbytes = ROW2Y(instance->glyphscanline);
+	instance->bgscanbytes = instance->xres * instance->pixelbytes;
+	
+	size_t fbsize = instance->scanline * instance->yres;
+	size_t bbsize = instance->cols * instance->rows * sizeof(uint16_t);
+	size_t glyphsize = FONT_GLYPHS * instance->glyphbytes;
+	
+	instance->addr = (uint8_t *) hw_map((uintptr_t) props->addr, fbsize);
+	if (!instance->addr) {
 		LOG("Unable to map framebuffer.");
-		return false;
-	}
-	
-	backbuf = (uint16_t *) malloc(bbsize, 0);
-	if (!backbuf) {
+		free(instance);
+		free(fbdev);
+		return NULL;
+	}
+	
+	instance->backbuf = (uint16_t *) malloc(bbsize, 0);
+	if (!instance->backbuf) {
 		LOG("Unable to allocate backbuffer.");
-		return false;
-	}
-	
-	glyphs = (uint8_t *) malloc(glyphsize, 0);
-	if (!glyphs) {
-		free(backbuf);
+		free(instance);
+		free(fbdev);
+		return NULL;
+	}
+	
+	instance->glyphs = (uint8_t *) malloc(glyphsize, 0);
+	if (!instance->glyphs) {
 		LOG("Unable to allocate glyphs.");
-		return false;
-	}
-	
-	bgscan = malloc(bgscanbytes, 0);
-	if (!bgscan) {
-		free(glyphs);
-		free(backbuf);
+		free(instance->backbuf);
+		free(instance);
+		free(fbdev);
+		return NULL;
+	}
+	
+	instance->bgscan = malloc(instance->bgscanbytes, 0);
+	if (!instance->bgscan) {
 		LOG("Unable to allocate background pixel.");
-		return false;
-	}
-	
-	memsetw(backbuf, cols * rows, 0);
-	glyphs_render();
-	
-	sysinfo_set_item_val("fb", NULL, true);
-	sysinfo_set_item_val("fb.kind", NULL, 1);
-	sysinfo_set_item_val("fb.width", NULL, xres);
-	sysinfo_set_item_val("fb.height", NULL, yres);
-	sysinfo_set_item_val("fb.scanline", NULL, scanline);
-	sysinfo_set_item_val("fb.visual", NULL, props->visual);
-	sysinfo_set_item_val("fb.address.physical", NULL, props->addr);
-	
-	fb_redraw();
-	
-	outdev_initialize("fb", &fb_console, &fb_ops);
-	stdout_wire(&fb_console);
-	
-	return true;
+		free(instance->glyphs);
+		free(instance->backbuf);
+		free(instance);
+		free(fbdev);
+		return NULL;
+	}
+	
+	memsetw(instance->backbuf, instance->cols * instance->rows, 0);
+	glyphs_render(instance);
+	
+	if (!fb_exported) {
+		/*
+		 * This is the necessary evil until the userspace driver is entirely
+		 * self-sufficient.
+		 */
+		sysinfo_set_item_val("fb", NULL, true);
+		sysinfo_set_item_val("fb.kind", NULL, 1);
+		sysinfo_set_item_val("fb.width", NULL, instance->xres);
+		sysinfo_set_item_val("fb.height", NULL, instance->yres);
+		sysinfo_set_item_val("fb.scanline", NULL, instance->scanline);
+		sysinfo_set_item_val("fb.visual", NULL, props->visual);
+		sysinfo_set_item_val("fb.address.physical", NULL, props->addr);
+		
+		fb_exported = true;
+	}
+	
+	fb_redraw(fbdev);
+	return fbdev;
 }
 
Index: kernel/generic/include/console/chardev.h
===================================================================
--- kernel/generic/include/console/chardev.h	(revision 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/generic/include/console/chardev.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -74,4 +74,7 @@
 	/** Write character to output. */
 	void (* write)(struct outdev *, wchar_t, bool);
+	
+	/** Redraw any previously cached characters. */
+	void (* redraw)(struct outdev *);
 } outdev_operations_t;
 
Index: kernel/generic/include/console/console.h
===================================================================
--- kernel/generic/include/console/console.h	(revision 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/generic/include/console/console.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -60,7 +60,4 @@
 extern unative_t sys_debug_disable_console(void);
 
-extern void arch_grab_console(void);
-extern void arch_release_console(void);
-
 #endif /* KERN_CONSOLE_H_ */
 
Index: kernel/generic/include/sysinfo/sysinfo.h
===================================================================
--- kernel/generic/include/sysinfo/sysinfo.h	(revision 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/generic/include/sysinfo/sysinfo.h	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -38,4 +38,6 @@
 #include <arch/types.h>
 #include <string.h>
+
+extern bool fb_exported;
 
 typedef union sysinfo_item_val {
Index: kernel/generic/src/console/console.c
===================================================================
--- kernel/generic/src/console/console.c	(revision 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/generic/src/console/console.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -71,5 +71,5 @@
 
 /** Kernel log spinlock */
-SPINLOCK_INITIALIZE(klog_lock);
+SPINLOCK_STATIC_INITIALIZE_NAME(klog_lock, "*klog_lock");
 
 /** Physical memory area used for klog buffer */
@@ -84,7 +84,9 @@
 
 static void stdout_write(outdev_t *dev, wchar_t ch, bool silent);
+static void stdout_redraw(outdev_t *dev);
 
 static outdev_operations_t stdout_ops = {
-	.write = stdout_write
+	.write = stdout_write,
+	.redraw = stdout_redraw
 };
 
@@ -122,5 +124,17 @@
 	for (cur = dev->list.next; cur != &dev->list; cur = cur->next) {
 		outdev_t *sink = list_get_instance(cur, outdev_t, link);
-		sink->op->write(sink, ch, silent);
+		if ((sink) && (sink->op->write))
+			sink->op->write(sink, ch, silent);
+	}
+}
+
+static void stdout_redraw(outdev_t *dev)
+{
+	link_t *cur;
+	
+	for (cur = dev->list.next; cur != &dev->list; cur = cur->next) {
+		outdev_t *sink = list_get_instance(cur, outdev_t, link);
+		if ((sink) && (sink->op->redraw))
+			sink->op->redraw(sink);
 	}
 }
@@ -156,5 +170,6 @@
 	
 	silent = false;
-	arch_grab_console();
+	if ((stdout) && (stdout->op->redraw))
+		stdout->op->redraw(stdout);
 	
 	/* Force the console to print the prompt */
@@ -165,6 +180,6 @@
 void release_console(void)
 {
+	// FIXME arch_release_console
 	silent = true;
-	arch_release_console();
 }
 
Index: kernel/generic/src/sysinfo/sysinfo.c
===================================================================
--- kernel/generic/src/sysinfo/sysinfo.c	(revision 90c8b8debd741b2a29ed7955b99cd5ea34956065)
+++ kernel/generic/src/sysinfo/sysinfo.c	(revision 0e6dce8fa8d920149a3d88cbaafcdf1ec7d1aca6)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup generic	
+/** @addtogroup generic
  * @{
  */
@@ -38,6 +38,6 @@
 #include <syscall/copy.h>
 
+bool fb_exported = false;
 sysinfo_item_t *_root = NULL;
-
 
 static sysinfo_item_t *sysinfo_find_item(const char *name, sysinfo_item_t *subtree)
