Index: kernel/arch/sparc64/include/drivers/kbd.h
===================================================================
--- kernel/arch/sparc64/include/drivers/kbd.h	(revision f03afad718ff8655274836534b65e4a5b4f6d098)
+++ kernel/arch/sparc64/include/drivers/kbd.h	(revision c2417bcc6cc9caba6dca867e322c9cc5723b35f4)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup sparc64	
+/** @addtogroup sparc64
  * @{
  */
@@ -39,13 +39,4 @@
 #include <genarch/ofw/ofw_tree.h>
 
-typedef enum {
-	KBD_UNKNOWN,
-	KBD_Z8530,
-	KBD_NS16550,
-	KBD_SGCN
-} kbd_type_t;
-
-extern kbd_type_t kbd_type;
-
 extern void kbd_init(ofw_tree_node_t *node);
 
Index: kernel/arch/sparc64/src/console.c
===================================================================
--- kernel/arch/sparc64/src/console.c	(revision f03afad718ff8655274836534b65e4a5b4f6d098)
+++ kernel/arch/sparc64/src/console.c	(revision c2417bcc6cc9caba6dca867e322c9cc5723b35f4)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup sparc64	
+/** @addtogroup sparc64
  * @{
  */
@@ -136,13 +136,7 @@
 #endif
 	
-	switch (kbd_type) {
 #ifdef CONFIG_SGCN_KBD
-	case KBD_SGCN:
-		sgcn_grab();
-		break;
+	sgcn_grab();
 #endif
-	default:
-		break;
-	}
 }
 
@@ -152,13 +146,7 @@
 void arch_release_console(void)
 {
-	switch (kbd_type) {
 #ifdef CONFIG_SGCN_KBD
-	case KBD_SGCN:
-		sgcn_release();
-		break;
+	sgcn_release();
 #endif
-	default:
-		break;
-	}
 }
 
Index: kernel/arch/sparc64/src/drivers/kbd.c
===================================================================
--- kernel/arch/sparc64/src/drivers/kbd.c	(revision f03afad718ff8655274836534b65e4a5b4f6d098)
+++ kernel/arch/sparc64/src/drivers/kbd.c	(revision c2417bcc6cc9caba6dca867e322c9cc5723b35f4)
@@ -55,98 +55,52 @@
 #include <sysinfo/sysinfo.h>
 
-kbd_type_t kbd_type = KBD_UNKNOWN;
-
 #ifdef CONFIG_SUN_KBD
 
-/** Initialize keyboard.
- *
- * Traverse OpenFirmware device tree in order to find necessary
- * info about the keyboard device.
- *
- * @param node Keyboard device node.
- */
-void kbd_init(ofw_tree_node_t *node)
+#ifdef CONFIG_Z8530
+
+static bool kbd_z8530_init(ofw_tree_node_t *node)
 {
-	size_t offset;
-	uintptr_t aligned_addr;
-	ofw_tree_property_t *prop;
-	const char *name;
+	const char *name = ofw_tree_node_name(node);
+	
+	if (str_cmp(name, "zs") != 0)
+		return false;
+	
+	/*
+	 * Read 'interrupts' property.
+	 */
+	ofw_tree_property_t *prop = ofw_tree_getprop(node, "interrupts");
+	if ((!prop) || (!prop->value)) {
+		printf("z8530: Unable to find interrupts property\n");
+		return false;
+	}
+	
+	uint32_t interrupts = *((uint32_t *) prop->value);
+	
+	/*
+	 * Read 'reg' property.
+	 */
+	prop = ofw_tree_getprop(node, "reg");
+	if ((!prop) || (!prop->value)) {
+		printf("z8530: Unable to find reg property\n");
+		return false;
+	}
+	
+	size_t size = ((ofw_fhc_reg_t *) prop->value)->size;
+	
+	uintptr_t pa;
+	if (!ofw_fhc_apply_ranges(node->parent,
+	    ((ofw_fhc_reg_t *) prop->value), &pa)) {
+		printf("z8530: Failed to determine address\n");
+		return false;
+	}
+	
+	inr_t inr;
 	cir_t cir;
 	void *cir_arg;
-	
-#ifdef CONFIG_NS16550
-	ns16550_t *ns16550;
-#endif
-#ifdef CONFIG_Z8530
-	z8530_t *z8530;
-#endif
-	
-	name = ofw_tree_node_name(node);
-	
-	/*
-	 * Determine keyboard serial controller type.
-	 */
-	if (str_cmp(name, "zs") == 0)
-		kbd_type = KBD_Z8530;
-	else if (str_cmp(name, "su") == 0)
-		kbd_type = KBD_NS16550;
-	
-	if (kbd_type == KBD_UNKNOWN) {
-		printf("Unknown keyboard device.\n");
-		return;
-	}
-	
-	/*
-	 * Read 'interrupts' property.
-	 */
-	uint32_t interrupts;
-	prop = ofw_tree_getprop(node, "interrupts");
-	if ((!prop) || (!prop->value))
-		panic("Cannot find 'interrupt' property.");
-	interrupts = *((uint32_t *) prop->value);
-	
-	/*
-	 * Read 'reg' property.
-	 */
-	prop = ofw_tree_getprop(node, "reg");
-	if ((!prop) || (!prop->value))
-		panic("Cannot find 'reg' property.");
-	
-	uintptr_t pa;
-	size_t size;
-	inr_t inr;
-	
-	switch (kbd_type) {
-	case KBD_Z8530:
-		size = ((ofw_fhc_reg_t *) prop->value)->size;
-		if (!ofw_fhc_apply_ranges(node->parent,
-		    ((ofw_fhc_reg_t *) prop->value), &pa)) {
-			printf("Failed to determine keyboard address.\n");
-			return;
-		}
-		if (!ofw_fhc_map_interrupt(node->parent,
-		    ((ofw_fhc_reg_t *) prop->value), interrupts, &inr, &cir,
-		    &cir_arg)) {
-			printf("Failed to determine keyboard interrupt.\n");
-			return;
-		}
-		break;
-		
-	case KBD_NS16550:
-		size = ((ofw_ebus_reg_t *) prop->value)->size;
-		if (!ofw_ebus_apply_ranges(node->parent,
-		    ((ofw_ebus_reg_t *) prop->value), &pa)) {
-			printf("Failed to determine keyboard address.\n");
-			return;
-		}
-		if (!ofw_ebus_map_interrupt(node->parent,
-		    ((ofw_ebus_reg_t *) prop->value), interrupts, &inr, &cir,
-		    &cir_arg)) {
-			printf("Failed to determine keyboard interrupt.\n");
-			return;
-		};
-		break;
-	default:
-		panic("Unexpected keyboard type.");
+	if (!ofw_fhc_map_interrupt(node->parent,
+	    ((ofw_fhc_reg_t *) prop->value), interrupts, &inr, &cir,
+	    &cir_arg)) {
+		printf("z8530: Failed to determine interrupt\n");
+		return false;
 	}
 	
@@ -157,57 +111,142 @@
 	 * underlying controller.
 	 */
-	aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
-	offset = pa - aligned_addr;
-	
-	switch (kbd_type) {
+	uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
+	size_t offset = pa - aligned_addr;
+	
+	z8530_t *z8530 = (z8530_t *)
+	    (hw_map(aligned_addr, offset + size) + offset);
+	
+	z8530_instance_t *z8530_instance = z8530_init(z8530, inr, cir, cir_arg);
+	if (z8530_instance) {
+		kbrd_instance_t *kbrd_instance = kbrd_init();
+		if (kbrd_instance) {
+			indev_t *sink = stdin_wire();
+			indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
+			z8530_wire(z8530_instance, kbrd);
+		}
+	}
+	
+	/*
+	 * This is the necessary evil until the userspace drivers are
+	 * entirely self-sufficient.
+	 */
+	sysinfo_set_item_val("kbd", NULL, true);
+	sysinfo_set_item_val("kbd.inr", NULL, inr);
+	sysinfo_set_item_val("kbd.address.kernel", NULL,
+	    (uintptr_t) z8530);
+	sysinfo_set_item_val("kbd.address.physical", NULL, pa);
+	sysinfo_set_item_val("kbd.type.z8530", NULL, true);
+	
+	return true;
+}
+
+#endif /* CONFIG_Z8530 */
+
+#ifdef CONFIG_NS16550
+
+static bool kbd_ns16550_init(ofw_tree_node_t *node)
+{
+	const char *name = ofw_tree_node_name(node);
+	
+	if (str_cmp(name, "su") != 0)
+		return false;
+	
+	/*
+	 * Read 'interrupts' property.
+	 */
+	ofw_tree_property_t *prop = ofw_tree_getprop(node, "interrupts");
+	if ((!prop) || (!prop->value)) {
+		printf("ns16550: Unable to find interrupts property\n");
+		return false;
+	}
+	
+	uint32_t interrupts = *((uint32_t *) prop->value);
+	
+	/*
+	 * Read 'reg' property.
+	 */
+	prop = ofw_tree_getprop(node, "reg");
+	if ((!prop) || (!prop->value)) {
+		printf("ns16550: Unable to find reg property\n");
+		return false;
+	}
+	
+	size_t size = ((ofw_ebus_reg_t *) prop->value)->size;
+	
+	uintptr_t pa;
+	if (!ofw_ebus_apply_ranges(node->parent,
+	    ((ofw_ebus_reg_t *) prop->value), &pa)) {
+		printf("ns16550: Failed to determine address\n");
+		return false;
+	}
+	
+	inr_t inr;
+	cir_t cir;
+	void *cir_arg;
+	if (!ofw_ebus_map_interrupt(node->parent,
+	    ((ofw_ebus_reg_t *) prop->value), interrupts, &inr, &cir,
+	    &cir_arg)) {
+		printf("ns16550: Failed to determine interrupt\n");
+		return false;
+	}
+	
+	/*
+	 * We need to pass aligned address to hw_map().
+	 * However, the physical keyboard address can
+	 * be pretty much unaligned, depending on the
+	 * underlying controller.
+	 */
+	uintptr_t aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
+	size_t offset = pa - aligned_addr;
+	
+	ns16550_t *ns16550 = (ns16550_t *)
+	   (hw_map(aligned_addr, offset + size) + offset);
+	
+	ns16550_instance_t *ns16550_instance = ns16550_init(ns16550, inr, cir, cir_arg);
+	if (ns16550_instance) {
+		kbrd_instance_t *kbrd_instance = kbrd_init();
+		if (kbrd_instance) {
+			indev_t *sink = stdin_wire();
+			indev_t *kbrd = kbrd_wire(kbrd_instance, sink);
+			ns16550_wire(ns16550_instance, kbrd);
+		}
+	}
+	
+	/*
+	 * This is the necessary evil until the userspace drivers are
+	 * entirely self-sufficient.
+	 */
+	sysinfo_set_item_val("kbd", NULL, true);
+	sysinfo_set_item_val("kbd.inr", NULL, inr);
+	sysinfo_set_item_val("kbd.address.kernel", NULL,
+	    (uintptr_t) ns16550);
+	sysinfo_set_item_val("kbd.address.physical", NULL, pa);
+	sysinfo_set_item_val("kbd.type.ns16550", NULL, true);
+	
+	return true;
+}
+
+#endif /* CONFIG_NS16550 */
+
+/** Initialize keyboard.
+ *
+ * Traverse OpenFirmware device tree in order to find necessary
+ * info about the keyboard device.
+ *
+ * @param node Keyboard device node.
+ *
+ */
+void kbd_init(ofw_tree_node_t *node)
+{
 #ifdef CONFIG_Z8530
-	case KBD_Z8530:
-		z8530 = (z8530_t *)
-		    (hw_map(aligned_addr, offset + size) + offset);
-		
-		indev_t *kbrdin_z8530 = z8530_init(z8530, inr, cir, cir_arg);
-		if (kbrdin_z8530)
-			kbrd_init(kbrdin_z8530);
-		
-		/*
-		 * This is the necessary evil until the userspace drivers are
-		 * entirely self-sufficient.
-		 */
-		sysinfo_set_item_val("kbd", NULL, true);
-		sysinfo_set_item_val("kbd.type", NULL, KBD_Z8530);
-		sysinfo_set_item_val("kbd.inr", NULL, inr);
-		sysinfo_set_item_val("kbd.address.kernel", NULL,
-		    (uintptr_t) z8530);
-		sysinfo_set_item_val("kbd.address.physical", NULL, pa);
-		break;
-#endif
+	kbd_z8530_init(node);
+#endif
+	
 #ifdef CONFIG_NS16550
-	case KBD_NS16550:
-		ns16550 = (ns16550_t *)
-		   (hw_map(aligned_addr, offset + size) + offset);
-		
-		indev_t *kbrdin_ns16550 = ns16550_init(ns16550, inr, cir, cir_arg);
-		if (kbrdin_ns16550)
-			kbrd_init(kbrdin_ns16550);
-		
-		/*
-		 * This is the necessary evil until the userspace driver is
-		 * entirely self-sufficient.
-		 */
-		sysinfo_set_item_val("kbd", NULL, true);
-		sysinfo_set_item_val("kbd.type", NULL, KBD_NS16550);
-		sysinfo_set_item_val("kbd.inr", NULL, inr);
-		sysinfo_set_item_val("kbd.address.kernel", NULL,
-		    (uintptr_t) ns16550);
-		sysinfo_set_item_val("kbd.address.physical", NULL, pa);
-		break;
-#endif
-	default:
-		printf("Kernel is not compiled with the necessary keyboard "
-		    "driver this machine requires.\n");
-	}
+	kbd_ns16550_init(node);
+#endif
 }
 
-#endif
+#endif /* CONFIG_SUN_KBD */
 
 /** @}
Index: kernel/arch/sparc64/src/drivers/sgcn.c
===================================================================
--- kernel/arch/sparc64/src/drivers/sgcn.c	(revision f03afad718ff8655274836534b65e4a5b4f6d098)
+++ kernel/arch/sparc64/src/drivers/sgcn.c	(revision c2417bcc6cc9caba6dca867e322c9cc5723b35f4)
@@ -101,7 +101,4 @@
 /** Returns a pointer to the console buffer header. */
 #define SGCN_BUFFER_HEADER	(SGCN_BUFFER(sgcn_buffer_header_t, 0))
-
-/** defined in drivers/kbd.c */
-extern kbd_type_t kbd_type;
 
 /** starting address of SRAM, will be set by the init_sram_begin function */
@@ -354,8 +351,5 @@
 	sgcn_buffer_begin_init();
 
-	kbd_type = KBD_SGCN;
-
 	sysinfo_set_item_val("kbd", NULL, true);
-	sysinfo_set_item_val("kbd.type", NULL, KBD_SGCN);
 
 	thread_t *t = thread_create(kkbdpoll, NULL, TASK, 0, "kkbdpoll", true);
