Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/Makefile	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -82,4 +82,12 @@
 ifeq ($(CONFIG_TSB),y)
 	DEFS += -DCONFIG_TSB
+endif
+
+ifeq ($(CONFIG_Z8530),y)
+	DEFS += -DCONFIG_Z8530
+endif
+
+ifeq ($(CONFIG_NS16550),y)
+	DEFS += -DCONFIG_NS16550
 endif
 
Index: kernel/arch/sparc64/Makefile.inc
===================================================================
--- kernel/arch/sparc64/Makefile.inc	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/arch/sparc64/Makefile.inc	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -61,27 +61,13 @@
 CONFIG_FB = y
 
+## Compile with support for Sun keyboard.
+#
+
+CONFIG_SUN_KBD = y
+
 ## Compile with support for OpenFirmware device tree.
 #
 
 CONFIG_OFW_TREE = y
-
-ifeq ($(MACHINE),enterprise)
-	## Compile with support for z8530 controller.
-	#
-
-	CONFIG_Z8530 = y
-	DEFS += -DCONFIG_Z8530
-endif
-ifeq ($(MACHINE),ultra)
-	## Compile with support for ns16550 controller.
-	#
-	
-	CONFIG_NS16550 = y
-	DEFS += -DCONFIG_NS16550
-	
-	DEFS += -DKBD_ADDR_OVRD=0x1fff13083f8ULL
-	
-endif
-
 
 ARCH_SOURCES = \
Index: kernel/arch/sparc64/include/boot/boot.h
===================================================================
--- kernel/arch/sparc64/include/boot/boot.h	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/arch/sparc64/include/boot/boot.h	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -80,9 +80,4 @@
 
 typedef struct {
-	uintptr_t addr;
-	uint32_t size;
-} keyboard_t;
-
-typedef struct {
 	uint32_t clock_frequency;
 } processor_t;
@@ -96,5 +91,4 @@
 	memmap_t memmap;
 	screen_t screen;
-	keyboard_t keyboard;
 	processor_t processor;
 	ballocs_t ballocs;
Index: kernel/arch/sparc64/include/drivers/kbd.h
===================================================================
--- kernel/arch/sparc64/include/drivers/kbd.h	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/arch/sparc64/include/drivers/kbd.h	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -37,8 +37,17 @@
 
 #include <arch/types.h>
+#include <genarch/ofw/ofw_tree.h>
+
+typedef enum {
+	KBD_UNKNOWN,
+	KBD_Z8530,
+	KBD_NS16550
+} kbd_type_t;
+
+extern kbd_type_t kbd_type;
 
 extern volatile uint8_t *kbd_virt_address;
 
-extern void kbd_init(void);
+extern void kbd_init(ofw_tree_node_t *node);
 
 #endif
Index: kernel/arch/sparc64/src/console.c
===================================================================
--- kernel/arch/sparc64/src/console.c	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/arch/sparc64/src/console.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -54,5 +54,8 @@
 #include <arch/mm/tlb.h>
 #include <arch/boot/boot.h>
+#include <genarch/ofw/ofw_tree.h>
 #include <arch.h>
+#include <panic.h>
+#include <print.h>
 
 #define KEYBOARD_POLL_PAUSE	50000	/* 50ms */
@@ -62,15 +65,36 @@
 {
 	stdin = NULL;
-		
+
+	ofw_tree_node_t *aliases;
+	ofw_tree_property_t *prop;
+	ofw_tree_node_t *screen;
+	ofw_tree_node_t *keyboard;
+	
+	aliases = ofw_tree_lookup("/aliases");
+	if (!aliases)
+		panic("Can't find /aliases.\n");
+	
+	prop = ofw_tree_getprop(aliases, "screen");
+	if (!prop)
+		panic("Can't find property \"screen\".\n");
+	if (!prop->value)
+		panic("Can't find screen alias.\n");
+	screen = ofw_tree_lookup(prop->value);
+	if (!screen)
+		panic("Can't find %s\n", prop->value);
+
 	fb_init(bootinfo.screen.addr, bootinfo.screen.width, bootinfo.screen.height,
 		bootinfo.screen.bpp, bootinfo.screen.scanline, true);
+	
+	prop = ofw_tree_getprop(aliases, "keyboard");
+	if (!prop)
+		panic("Can't find property \"keyboard\".\n");
+	if (!prop->value)
+		panic("Can't find keyboard alias.\n");
+	keyboard = ofw_tree_lookup(prop->value);
+	if (!keyboard)
+		panic("Can't find %s\n", prop->value);
 
-#ifdef KBD_ADDR_OVRD
-	if (!bootinfo.keyboard.addr)
-		bootinfo.keyboard.addr = KBD_ADDR_OVRD;
-#endif
-
-	if (bootinfo.keyboard.addr)
-		kbd_init();
+	kbd_init(keyboard);
 }
 
@@ -83,13 +107,13 @@
 	thread_detach(THREAD);
 
-	if (!bootinfo.keyboard.addr)
-		return;
-		
-	while (1) {
 #ifdef CONFIG_Z8530
+	if (kbd_type == KBD_Z8530)
 		return;
 #endif
+
+	while (1) {
 #ifdef CONFIG_NS16550
-		ns16550_poll();
+		if (kbd_type == KBD_NS16550)
+			ns16550_poll();
 #endif
 		thread_usleep(KEYBOARD_POLL_PAUSE);
@@ -103,5 +127,6 @@
 {
 #ifdef CONFIG_Z8530
-	z8530_grab();
+	if (kbd_type == KBD_Z8530)
+		z8530_grab();
 #endif
 }
@@ -113,5 +138,6 @@
 {
 #ifdef CONFIG_Z8530
-	z8530_release();
+	if (kbd_type == KBD_Z8530)
+		z8530_release();
 #endif
 }
Index: kernel/arch/sparc64/src/drivers/kbd.c
===================================================================
--- kernel/arch/sparc64/src/drivers/kbd.c	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/arch/sparc64/src/drivers/kbd.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -34,4 +34,5 @@
 
 #include <arch/drivers/kbd.h>
+#include <genarch/ofw/ofw_tree.h>
 #ifdef CONFIG_Z8530
 #include <genarch/kbd/z8530.h>
@@ -41,36 +42,91 @@
 #endif
 
-#include <arch/boot/boot.h>
 #include <arch/mm/page.h>
 #include <arch/types.h>
 #include <typedefs.h>
 #include <align.h>
+#include <func.h>
+#include <print.h>
 
 volatile uint8_t *kbd_virt_address = NULL;
 
-void kbd_init()
+kbd_type_t kbd_type = KBD_UNKNOWN;
+
+/** 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)
 {
 	size_t offset;
 	uintptr_t aligned_addr;
-
-	/* FIXME: supply value read from OpenFirmware */
-	bootinfo.keyboard.size = 8;
-
+	ofw_tree_property_t *prop;
+	const char *name;
+	
+	name = ofw_tree_node_name(node);
+	
+	if (strcmp(name, "zs") == 0)
+		kbd_type = KBD_Z8530;
+	else if (strcmp(name, "su") == 0)
+		kbd_type = KBD_NS16550;
+	
+	if (kbd_type == KBD_UNKNOWN) {
+		printf("Unknown keyboard device.\n");
+		return;
+	}
+	
+	prop = ofw_tree_getprop(node, "reg");
+	if (!prop)
+		panic("Can't find \"reg\" property.\n");
+	
+	uintptr_t pa;
+	size_t size;
+	
+	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;
+		}
+		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;
+		}
+		break;
+	default:
+		panic("Unexpected type.\n");
+	}
+	
 	/*
 	 * We need to pass aligned address to hw_map().
 	 * However, the physical keyboard address can
-	 * be pretty much unaligned on some systems
-	 * (e.g. Ultra 5, Ultra 60).
+	 * be pretty much unaligned, depending on the
+	 * underlying controller.
 	 */
-	aligned_addr = ALIGN_DOWN(bootinfo.keyboard.addr, PAGE_SIZE);
-	offset = bootinfo.keyboard.addr - aligned_addr;
-	kbd_virt_address = (uint8_t *) hw_map(aligned_addr, offset + bootinfo.keyboard.size) + offset;
+	aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
+	offset = pa - aligned_addr;
+	kbd_virt_address = (uint8_t *) hw_map(aligned_addr, offset + size) + offset;
 
+	switch (kbd_type) {
 #ifdef CONFIG_Z8530
-	z8530_init();
+	case KBD_Z8530:
+		z8530_init();
+		break;
 #endif
 #ifdef CONFIG_NS16550
-	ns16550_init();
+	case KBD_NS16550:
+		ns16550_init();
+		break;
 #endif
+	default:
+		printf("Kernel is not compiled with the necessary keyboard driver this machine requires.\n");
+	}
 }
 
Index: kernel/arch/sparc64/src/trap/interrupt.c
===================================================================
--- kernel/arch/sparc64/src/trap/interrupt.c	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/arch/sparc64/src/trap/interrupt.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -37,4 +37,5 @@
 #include <interrupt.h>
 #include <arch/drivers/fhc.h>
+#include <arch/drivers/kbd.h>
 #include <typedefs.h>
 #include <arch/types.h>
@@ -63,5 +64,6 @@
 {
 #ifdef CONFIG_Z8530
-	z8530_belongs_to_kernel = false;
+	if (kbd_type == KBD_Z8530)
+		z8530_belongs_to_kernel = false;
 #endif
 }
@@ -78,4 +80,6 @@
 #ifdef CONFIG_Z8530
 	case Z8530_INTRCV_DATA0:
+		if (kbd_type != KBD_Z8530)
+			break;
 		/*
 		 * So far, we know we got this interrupt through the FHC.
Index: kernel/genarch/Makefile.inc
===================================================================
--- kernel/genarch/Makefile.inc	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/genarch/Makefile.inc	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -73,10 +73,15 @@
 endif
 
+## Sun keyboard
+ifeq ($(CONFIG_SUN_KBD),y)
+	GENARCH_SOURCES += \
+		genarch/src/kbd/key.c \
+		genarch/src/kbd/scanc_sun.c
+endif
+
 ## z8530 controller
 ifeq ($(CONFIG_Z8530),y)
 	GENARCH_SOURCES += \
-		genarch/src/kbd/z8530.c \
-		genarch/src/kbd/key.c \
-		genarch/src/kbd/scanc_sun.c
+		genarch/src/kbd/z8530.c
 endif
 
@@ -84,7 +89,5 @@
 ifeq ($(CONFIG_NS16550),y)
 	GENARCH_SOURCES += \
-		genarch/src/kbd/ns16550.c \
-		genarch/src/kbd/key.c \
-		genarch/src/kbd/scanc_sun.c
+		genarch/src/kbd/ns16550.c
 endif
 
@@ -93,4 +96,7 @@
 ifeq ($(CONFIG_OFW_TREE), y)
 	GENARCH_SOURCES += \
-		genarch/src/ofw/ofw_tree.c
+		genarch/src/ofw/ofw_tree.c \
+		genarch/src/ofw/ebus.c \
+		genarch/src/ofw/fhc.c \
+		genarch/src/ofw/pci.c 
 endif
Index: kernel/genarch/include/kbd/i8042.h
===================================================================
--- kernel/genarch/include/kbd/i8042.h	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/genarch/include/kbd/i8042.h	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -36,8 +36,11 @@
 #define KERN_I8042_H_
 
+#include <typedefs.h>
+
 extern void i8042_init(void);
 extern void i8042_poll(void);
 extern void i8042_grab(void);
 extern void i8042_release(void);
+extern char i8042_key_read(chardev_t *d);
 
 #endif
Index: kernel/genarch/include/kbd/key.h
===================================================================
--- kernel/genarch/include/kbd/key.h	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/genarch/include/kbd/key.h	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -50,6 +50,4 @@
 extern void active_read_key_pressed(uint8_t sc);
 
-extern char key_read(chardev_t *d);
-
 #endif
 
Index: kernel/genarch/include/kbd/ns16550.h
===================================================================
--- kernel/genarch/include/kbd/ns16550.h	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/genarch/include/kbd/ns16550.h	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -38,8 +38,11 @@
 #define KERN_NS16550_H_
 
+#include <typedefs.h>
+
 extern void ns16550_init(void);
 extern void ns16550_poll(void);
 extern void ns16550_grab(void);
 extern void ns16550_release(void);
+extern char ns16550_key_read(chardev_t *d);
 
 #endif
Index: kernel/genarch/include/kbd/z8530.h
===================================================================
--- kernel/genarch/include/kbd/z8530.h	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/genarch/include/kbd/z8530.h	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -49,4 +49,5 @@
 extern void z8530_release(void);
 extern void z8530_interrupt(void);
+extern char z8530_key_read(chardev_t *d);
 
 #endif
Index: kernel/genarch/include/ofw/ofw_tree.h
===================================================================
--- kernel/genarch/include/ofw/ofw_tree.h	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/genarch/include/ofw/ofw_tree.h	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -57,8 +57,80 @@
 };
 
+/*
+ * Definition of 'reg' and 'ranges' properties for various buses.
+ */
+ 
+struct ofw_fhc_reg {
+	uint64_t addr;
+	uint32_t size;
+} __attribute__ ((packed));
+typedef struct ofw_fhc_reg ofw_fhc_reg_t;
+			
+struct ofw_fhc_range {
+	uint64_t child_base;
+	uint64_t parent_base;
+	uint32_t size;
+} __attribute__ ((packed));
+typedef struct ofw_fhc_range ofw_fhc_range_t;
+
+struct ofw_central_reg {
+	uint64_t addr;
+	uint32_t size;
+} __attribute__ ((packed));
+typedef struct ofw_central_reg ofw_central_reg_t;
+
+struct ofw_central_range {
+	uint64_t child_base;
+	uint64_t parent_base;
+	uint32_t size;
+} __attribute__ ((packed));
+typedef struct ofw_central_range ofw_central_range_t;
+
+struct ofw_ebus_reg {
+	uint32_t space;
+	uint32_t addr;
+	uint32_t size;
+} __attribute__ ((packed));
+typedef struct ofw_ebus_reg ofw_ebus_reg_t;
+
+struct ofw_ebus_range {
+	uint32_t child_space;
+	uint32_t child_base;
+	uint32_t parent_space;
+	uint64_t parent_base;		/* group phys.mid and phys.lo together */
+	uint32_t size;
+} __attribute__ ((packed));
+typedef struct ofw_ebus_range ofw_ebus_range_t;
+
+struct ofw_pci_reg {
+	uint32_t space;			/* needs to masked to obtain pure space id */
+	uint64_t addr;			/* group phys.mid and phys.lo together */
+	uint64_t size;
+} __attribute__ ((packed));
+typedef struct ofw_pci_reg ofw_pci_reg_t;
+
+struct ofw_pci_range {
+	uint32_t space;
+	uint64_t child_base;		/* group phys.mid and phys.lo together */
+	uint64_t parent_base;
+	uint64_t size;
+} __attribute__ ((packed));
+typedef struct ofw_pci_range ofw_pci_range_t;
+
+struct ofw_ffb_reg {
+} __attribute__ ((packed));
+typedef struct ofw_ffb_reg ofw_ffb_reg_t;
+
 extern void ofw_tree_init(ofw_tree_node_t *root);
 extern void ofw_tree_print(void);
 extern const char *ofw_tree_node_name(const ofw_tree_node_t *node);
 extern ofw_tree_node_t *ofw_tree_lookup(const char *path);
+extern ofw_tree_property_t *ofw_tree_getprop(const ofw_tree_node_t *node, const char *name);
+
+extern bool ofw_fhc_apply_ranges(ofw_tree_node_t *node, ofw_fhc_reg_t *reg, uintptr_t *pa);
+extern bool ofw_central_apply_ranges(ofw_tree_node_t *node, ofw_central_reg_t *reg, uintptr_t *pa);
+extern bool ofw_ebus_apply_ranges(ofw_tree_node_t *node, ofw_ebus_reg_t *reg, uintptr_t *pa);
+extern bool ofw_pci_apply_ranges(ofw_tree_node_t *node, ofw_pci_reg_t *reg, uintptr_t *pa);
+extern bool ofw_ffb_apply_ranges(ofw_tree_node_t *node, ofw_ffb_reg_t *reg, uintptr_t *pa);
 
 #endif
Index: kernel/genarch/src/kbd/i8042.c
===================================================================
--- kernel/genarch/src/kbd/i8042.c	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/genarch/src/kbd/i8042.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -81,9 +81,8 @@
 static void i8042_resume(chardev_t *);
 
-chardev_t kbrd;
 static chardev_operations_t ops = {
 	.suspend = i8042_suspend,
 	.resume = i8042_resume,
-	.read = key_read
+	.read = i8042_key_read
 };
 
@@ -174,5 +173,5 @@
 }
 
-char key_read(chardev_t *d)
+char i8042_key_read(chardev_t *d)
 {
 	char ch;	
Index: kernel/genarch/src/kbd/key.c
===================================================================
--- kernel/genarch/src/kbd/key.c	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/genarch/src/kbd/key.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -54,4 +54,6 @@
 #define ACTIVE_READ_BUFF_SIZE 16 	/* Must be power of 2 */
 
+chardev_t kbrd;
+
 static uint8_t active_read_buff[ACTIVE_READ_BUFF_SIZE];
 
Index: kernel/genarch/src/kbd/ns16550.c
===================================================================
--- kernel/genarch/src/kbd/ns16550.c	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/genarch/src/kbd/ns16550.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -60,9 +60,8 @@
 static void ns16550_resume(chardev_t *);
 
-chardev_t kbrd;
 static chardev_operations_t ops = {
 	.suspend = ns16550_suspend,
 	.resume = ns16550_resume,
-	.read = key_read
+	.read = ns16550_key_read
 };
 
@@ -119,5 +118,5 @@
 }
 
-char key_read(chardev_t *d)
+char ns16550_key_read(chardev_t *d)
 {
 	char ch;	
Index: kernel/genarch/src/kbd/z8530.c
===================================================================
--- kernel/genarch/src/kbd/z8530.c	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/genarch/src/kbd/z8530.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -63,9 +63,8 @@
 static void z8530_resume(chardev_t *);
 
-chardev_t kbrd;
 static chardev_operations_t ops = {
 	.suspend = z8530_suspend,
 	.resume = z8530_resume,
-	.read = key_read
+	.read = z8530_key_read
 };
 
@@ -142,5 +141,5 @@
 }
 
-char key_read(chardev_t *d)
+char z8530_key_read(chardev_t *d)
 {
 	char ch;	
Index: kernel/genarch/src/ofw/ebus.c
===================================================================
--- kernel/genarch/src/ofw/ebus.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
+++ kernel/genarch/src/ofw/ebus.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup ofw
+ * @{
+ */
+/**
+ * @file
+ * @brief	EBUS 'reg' and 'ranges' properties handling.
+ *
+ */
+
+#include <genarch/ofw/ofw_tree.h>
+#include <arch/memstr.h>
+#include <func.h>
+#include <panic.h>
+#include <macros.h>
+
+bool ofw_ebus_apply_ranges(ofw_tree_node_t *node, ofw_ebus_reg_t *reg, uintptr_t *pa)
+{
+	ofw_tree_property_t *prop;
+	ofw_ebus_range_t *range;
+	count_t ranges;
+
+	prop = ofw_tree_getprop(node, "ranges");
+	if (!prop)
+		return false;
+		
+	ranges = prop->size / sizeof(ofw_ebus_range_t);
+	range = prop->value;
+	
+	int i;
+	
+	for (i = 0; i < ranges; i++) {
+		if (reg->space != range[i].child_space)
+			continue;
+		if (overlaps(reg->addr, reg->size, range[i].child_base, range[i].size)) {
+			ofw_pci_reg_t pci_reg;
+			
+			pci_reg.space = range[i].parent_space;
+			pci_reg.addr = range[i].parent_base + (reg->addr - range[i].child_base);
+			pci_reg.size = reg->size;
+			
+			return ofw_pci_apply_ranges(node->parent, &pci_reg, pa);
+		}
+	}
+
+	return false;
+}
+
+/** @}
+ */
Index: kernel/genarch/src/ofw/fhc.c
===================================================================
--- kernel/genarch/src/ofw/fhc.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
+++ kernel/genarch/src/ofw/fhc.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2006 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup ofw
+ * @{
+ */
+/**
+ * @file
+ * @brief	FHC 'reg' and 'ranges' properties handling.
+ *
+ */
+
+#include <genarch/ofw/ofw_tree.h>
+#include <arch/memstr.h>
+#include <func.h>
+#include <panic.h>
+#include <macros.h>
+
+bool ofw_fhc_apply_ranges(ofw_tree_node_t *node, ofw_fhc_reg_t *reg, uintptr_t *pa)
+{
+	ofw_tree_property_t *prop;
+	ofw_fhc_range_t *range;
+	count_t ranges;
+
+	prop = ofw_tree_getprop(node, "ranges");
+	if (!prop)
+		return false;
+		
+	ranges = prop->size / sizeof(ofw_fhc_range_t);
+	range = prop->value;
+	
+	int i;
+	
+	for (i = 0; i < ranges; i++) {
+		if (overlaps(reg->addr, reg->size, range[i].child_base, range[i].size)) {
+			uintptr_t addr;
+			
+			addr = range[i].parent_base + (reg->addr - range[i].child_base);
+			if (!node->parent->parent) {
+				*pa = addr;
+				return true;
+			}
+			if (strcmp(ofw_tree_node_name(node->parent), "central") != 0)
+				panic("Unexpected parent node: %s.\n", ofw_tree_node_name(node->parent));
+			
+			ofw_central_reg_t central_reg;
+			
+			central_reg.addr = addr;
+			central_reg.size = reg->size;
+			
+			return ofw_central_apply_ranges(node->parent, &central_reg, pa);
+		}
+	}
+
+	return false;
+}
+
+bool ofw_central_apply_ranges(ofw_tree_node_t *node, ofw_central_reg_t *reg, uintptr_t *pa)
+{
+	if (node->parent->parent)
+		panic("Unexpected parent node: %s.\n", ofw_tree_node_name(node->parent));
+	
+	ofw_tree_property_t *prop;
+	ofw_central_range_t *range;
+	count_t ranges;
+	
+	prop = ofw_tree_getprop(node, "ranges");
+	if (!prop)
+		return false;
+		
+	ranges = prop->size / sizeof(ofw_central_range_t);
+	range = prop->value;
+	
+	int i;
+	
+	for (i = 0; i < ranges; i++) {
+		if (overlaps(reg->addr, reg->size, range[i].child_base, range[i].size)) {
+			*pa = range[i].parent_base + (reg->addr - range[i].child_base);
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+/** @}
+ */
Index: kernel/genarch/src/ofw/ofw_tree.c
===================================================================
--- kernel/genarch/src/ofw/ofw_tree.c	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/genarch/src/ofw/ofw_tree.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -52,4 +52,23 @@
 }
 
+/** Get OpenFirmware node property.
+ *
+ * @param node Node in which to lookup the property.
+ * @param name Name of the property.
+ *
+ * @return Pointer to the property structure or NULL if no such property.
+ */
+ofw_tree_property_t *ofw_tree_getprop(const ofw_tree_node_t *node, const char *name)
+{
+	int i;
+	
+	for (i = 0; i < node->properties; i++) {
+		if (strcmp(node->property[i].name, name) == 0)
+			return &node->property[i];
+	}
+
+	return NULL;
+}
+
 /** Return value of the 'name' property.
  *
@@ -60,15 +79,14 @@
 const char *ofw_tree_node_name(const ofw_tree_node_t *node)
 {
-	int i;
+	ofw_tree_property_t *prop;
 	
-	for (i = 0; i < node->properties; i++) {
-		if (strncmp(node->property[i].name, "name", strlen("name")) == 0) {
-			if (node->property[i].size < 2)
-				panic("Invalid name property.\n");
-			return node->property[i].value;
-		}
-	}
+	prop = ofw_tree_getprop(node, "name");
+	if (!prop)
+		panic("Node without name property.\n");
+		
+	if (prop->size < 2)
+		panic("Invalid name property.\n");
 	
-	panic("Node without name property.\n");
+	return prop->value;
 }
 
@@ -76,17 +94,32 @@
  *
  * @param node Node whose child is being looked up.
- * @param da_name Disambigued name of the child being looked up.
+ * @param name Name of the child being looked up.
  *
  * @return NULL if there is no such child or pointer to the matching child node.
  */
-static ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node, const char *da_name)
+static ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node, const char *name)
 {
 	ofw_tree_node_t *cur;
 	
+	/*
+	 * Try to find the disambigued name.
+	 */
 	for (cur = node->child; cur; cur = cur->peer) {
-		if (strncmp(cur->da_name, da_name, strlen(da_name)) == 0)
+		if (strcmp(cur->da_name, name) == 0)
 			return cur;
 	}
 	
+	/*
+	 * Disambigued name not found.
+	 * Lets try our luck with possibly ambiguous "name" property.
+	 *
+	 * We need to do this because paths stored in "/aliases"
+	 * are not always fully-qualified.
+	 */
+	for (cur = node->child; cur; cur = cur->peer) {
+		if (strcmp(ofw_tree_node_name(cur), name) == 0)
+			return cur;
+	}
+		
 	return NULL;
 }
Index: kernel/genarch/src/ofw/pci.c
===================================================================
--- kernel/genarch/src/ofw/pci.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
+++ kernel/genarch/src/ofw/pci.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup ofw
+ * @{
+ */
+/**
+ * @file
+ * @brief	PCI 'reg' and 'ranges' properties handling.
+ *
+ */
+
+#include <genarch/ofw/ofw_tree.h>
+#include <arch/memstr.h>
+#include <func.h>
+#include <panic.h>
+#include <macros.h>
+
+#define PCI_SPACE_MASK	0x03000000
+
+bool ofw_pci_apply_ranges(ofw_tree_node_t *node, ofw_pci_reg_t *reg, uintptr_t *pa)
+{
+	ofw_tree_property_t *prop;
+	ofw_pci_range_t *range;
+	count_t ranges;
+
+	prop = ofw_tree_getprop(node, "ranges");
+	if (!prop) {
+		if (strcmp(ofw_tree_node_name(node->parent), "pci") == 0)
+			return ofw_pci_apply_ranges(node->parent, reg, pa);
+		return false;
+	}
+		
+	ranges = prop->size / sizeof(ofw_pci_range_t);
+	range = prop->value;
+	
+	int i;
+	
+	for (i = 0; i < ranges; i++) {
+		if ((reg->space & PCI_SPACE_MASK) != (range[i].space & PCI_SPACE_MASK))
+			continue;
+		if (overlaps(reg->addr, reg->size, range[i].child_base, range[i].size)) {
+			*pa = range[i].parent_base + (reg->addr - range[i].child_base);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/** @}
+ */
Index: kernel/generic/include/func.h
===================================================================
--- kernel/generic/include/func.h	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/generic/include/func.h	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -45,4 +45,5 @@
 
 extern size_t strlen(const char *str);
+extern int strcmp(const char *src, const char *dst);
 extern int strncmp(const char *src, const char *dst, size_t len);
 extern void strncpy(char *dest, const char *src, size_t len);
Index: kernel/generic/src/lib/func.c
===================================================================
--- kernel/generic/src/lib/func.c	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/generic/src/lib/func.c	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -101,4 +101,32 @@
  * Do a char-by-char comparison of two NULL terminated strings.
  * The strings are considered equal iff they consist of the same
+ * characters on the minimum of their lengths.
+ *
+ * @param src First string to compare.
+ * @param dst Second string to compare.
+ *
+ * @return 0 if the strings are equal, -1 if first is smaller, 1 if second smaller.
+ *
+ */
+int strcmp(const char *src, const char *dst)
+{
+	for (; *src && *dst; src++, dst++) {
+		if (*src < *dst)
+			return -1;
+		if (*src > *dst)
+			return 1;
+	}
+	if (*src == *dst)
+		return 0;
+	if (!*src)
+		return -1;
+	return 1;
+}
+
+
+/** Compare two NULL terminated strings
+ *
+ * Do a char-by-char comparison of two NULL terminated strings.
+ * The strings are considered equal iff they consist of the same
  * characters on the minimum of their lengths and specified maximal
  * length.
@@ -115,6 +143,5 @@
 	int i;
 	
-	i = 0;
-	for (;*src && *dst && i < len;src++,dst++,i++) {
+	for (i = 0; *src && *dst && i < len; src++, dst++, i++) {
 		if (*src < *dst)
 			return -1;
@@ -128,4 +155,6 @@
 	return 1;
 }
+
+
 
 /** Copy NULL terminated string.
Index: kernel/kernel.config
===================================================================
--- kernel/kernel.config	(revision 16529d53af40d438671e67b8969cbe09086dc68f)
+++ kernel/kernel.config	(revision 28ecadba2f66309e3ea4c819f1e768f64d97b699)
@@ -36,9 +36,4 @@
 @ "indy" SGI Indy
 ! [ARCH=mips32] MACHINE (choice)
-
-# Machine type
-@ "ultra" Sun Ultra 5
-@ "enterprise" Sun Enterprise E6500
-! [ARCH=sparc64] MACHINE (choice)
 
 # Framebuffer support
@@ -111,4 +106,10 @@
 ! [ARCH=sparc64] CONFIG_TSB (n/y)
 
+# Support for Z8530 serial port
+! [ARCH=sparc64] CONFIG_Z8530 (y/n)
+
+# Support for NS16550 serial port
+! [ARCH=sparc64] CONFIG_NS16550 (y/n)
+
 ## Run-time configuration directives
 
