Index: uspace/drv/bus/amba/Makefile
===================================================================
--- uspace/drv/bus/amba/Makefile	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
+++ uspace/drv/bus/amba/Makefile	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Lenka Trochtova
+# 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.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = amba
+
+SOURCES = \
+	amba.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/bus/amba/amba.c
===================================================================
--- uspace/drv/bus/amba/amba.c	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
+++ uspace/drv/bus/amba/amba.c	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2013 Jakub Klama
+ * 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.
+ */
+
+/**
+ * @defgroup amba AMBA bus driver.
+ * @brief HelenOS AMBA bus driver.
+ * @{
+ */
+/** @file
+ */
+
+#include <assert.h>
+#include <byteorder.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <fibril_synch.h>
+#include <str.h>
+#include <ctype.h>
+#include <macros.h>
+#include <str_error.h>
+#include <ddf/driver.h>
+#include <ddf/log.h>
+#include <ipc/dev_iface.h>
+#include <ipc/irc.h>
+#include <ns.h>
+#include <ipc/services.h>
+#include <sysinfo.h>
+#include <ops/hw_res.h>
+#include <device/hw_res.h>
+#include <ddi.h>
+#include "ambapp.h"
+
+#define NAME  "amba"
+#define ID_MAX_STR_LEN  32
+
+#define LVL_DEBUG  LVL_ERROR
+
+typedef struct leon_amba_bus {
+	/** DDF device node */
+	ddf_dev_t *dnode;
+	uintptr_t master_area_addr;
+	uintptr_t slave_area_addr;
+	size_t master_area_size;
+	size_t slave_area_size;
+	void *master_area;
+	void *slave_area;
+	fibril_mutex_t area_mutex;
+} amba_bus_t;
+
+typedef struct amba_fun_data {
+	amba_bus_t *busptr;
+	ddf_fun_t *fnode;
+	int bus;
+	int index;
+	uint8_t vendor_id;
+	uint32_t device_id;
+	int version;
+	hw_resource_list_t hw_resources;
+	hw_resource_t resources[AMBA_MAX_HW_RES];
+} amba_fun_t;
+
+static amba_fun_t *amba_fun_new(amba_bus_t *);
+static void amba_fun_set_name(amba_fun_t *);
+static void amba_fun_create_match_ids(amba_fun_t *);
+static int amba_fun_online(ddf_fun_t *);
+static int amba_fun_offline(ddf_fun_t *);
+static hw_resource_list_t *amba_get_resources(ddf_fun_t *);
+static bool amba_enable_interrupt(ddf_fun_t *);
+static void amba_add_bar(amba_fun_t *, uintptr_t, size_t);
+static void amba_add_interrupt(amba_fun_t *, int);
+static int amba_bus_scan(amba_bus_t *, void *, unsigned int);
+static void amba_fake_scan(amba_bus_t *);
+static int amba_dev_add(ddf_dev_t *);
+
+static hw_res_ops_t amba_fun_hw_res_ops = {
+	.get_resource_list = &amba_get_resources,
+	.enable_interrupt = &amba_enable_interrupt
+};
+
+static ddf_dev_ops_t amba_fun_ops = {
+	.interfaces[HW_RES_DEV_IFACE] = &amba_fun_hw_res_ops
+};
+
+static driver_ops_t amba_ops = {
+	.dev_add = &amba_dev_add,
+	.fun_online = &amba_fun_online,
+	.fun_offline = &amba_fun_offline
+};
+
+static driver_t amba_driver = {
+	.name = NAME,
+	.driver_ops = &amba_ops
+};
+
+static amba_fun_t *amba_fun_new(amba_bus_t *bus)
+{
+	ddf_msg(LVL_DEBUG, "amba_fun_new(): bus=%p, bus->dnode=%p", bus,
+	    bus->dnode);
+	
+	ddf_fun_t *fnode = ddf_fun_create(bus->dnode, fun_inner, NULL);
+	if (fnode == NULL)
+		return NULL;
+	
+	ddf_msg(LVL_DEBUG, "amba_fun_new(): created");
+	
+	amba_fun_t *fun = ddf_fun_data_alloc(fnode, sizeof(amba_fun_t));
+	if (fun == NULL)
+		return NULL;
+	
+	ddf_msg(LVL_DEBUG, "amba_fun_new(): allocated data");
+	
+	fun->busptr = bus;
+	fun->fnode = fnode;
+	return fun;
+}
+
+static void amba_fun_set_name(amba_fun_t *fun)
+{
+	char *name = NULL;
+	
+	asprintf(&name, "%02x:%02x", fun->bus, fun->index);
+	ddf_fun_set_name(fun->fnode, name);
+}
+
+static void amba_fun_create_match_ids(amba_fun_t *fun)
+{
+	/* Vendor ID & Device ID */
+	char match_id_str[ID_MAX_STR_LEN];
+	int rc = snprintf(match_id_str, ID_MAX_STR_LEN, "amba/ven=%02x&dev=%08x",
+	    fun->vendor_id, fun->device_id);
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
+		    str_error(rc));
+	}
+	
+	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 90);
+}
+
+static int amba_fun_online(ddf_fun_t *fun)
+{
+	ddf_msg(LVL_DEBUG, "amba_fun_online()");
+	return ddf_fun_online(fun);
+
+}
+
+static int amba_fun_offline(ddf_fun_t *fun)
+{
+	ddf_msg(LVL_DEBUG, "amba_fun_offline()");
+	return ddf_fun_offline(fun);
+}
+
+static hw_resource_list_t *amba_get_resources(ddf_fun_t *fnode)
+{
+	amba_fun_t *fun = ddf_fun_data_get(fnode);
+	
+	if (fun == NULL)
+		return NULL;
+	
+	return &fun->hw_resources;
+}
+
+static bool amba_enable_interrupt(ddf_fun_t *fnode)
+{
+	return true;
+}
+
+static void amba_alloc_resource_list(amba_fun_t *fun)
+{
+	fun->hw_resources.resources = fun->resources;
+}
+
+static void amba_add_bar(amba_fun_t *fun, uintptr_t addr, size_t size)
+{
+	hw_resource_list_t *hw_res_list = &fun->hw_resources;
+	hw_resource_t *hw_resources =  hw_res_list->resources;
+	size_t count = hw_res_list->count;
+	
+	assert(hw_resources != NULL);
+	assert(count < AMBA_MAX_HW_RES);
+	
+	hw_resources[count].type = MEM_RANGE;
+	hw_resources[count].res.mem_range.address = addr;
+	hw_resources[count].res.mem_range.size = size;
+	hw_resources[count].res.mem_range.endianness = BIG_ENDIAN;
+	
+	hw_res_list->count++;
+}
+
+static void amba_add_interrupt(amba_fun_t *fun, int irq)
+{
+	hw_resource_list_t *hw_res_list = &fun->hw_resources;
+	hw_resource_t *hw_resources = hw_res_list->resources;
+	size_t count = hw_res_list->count;
+	
+	assert(NULL != hw_resources);
+	assert(count < AMBA_MAX_HW_RES);
+	
+	hw_resources[count].type = INTERRUPT;
+	hw_resources[count].res.interrupt.irq = irq;
+	
+	hw_res_list->count++;
+	
+	ddf_msg(LVL_NOTE, "Function %s uses irq %x.", ddf_fun_get_name(fun->fnode), irq);
+}
+
+static int amba_bus_scan(amba_bus_t *bus, void *area, unsigned int max_entries)
+{
+	ddf_msg(LVL_DEBUG, "amba_bus_scan(): area=%p, max_entries=%u", area, max_entries);
+	
+	ambapp_entry_t *devices = (ambapp_entry_t *) area;
+	int found = 0;
+	
+	for (unsigned int i = 0; i < max_entries; i++) {
+		ambapp_entry_t *entry = &devices[i];
+		if (entry->vendor_id == 0xff)
+			continue;
+		
+		amba_fun_t *fun = amba_fun_new(bus);
+		fun->bus = 0;
+		fun->index = i;
+		fun->vendor_id = entry->vendor_id;
+		fun->device_id = entry->device_id;
+		fun->version = entry->version;
+		
+		for (unsigned int bnum = 0; bnum < 4; bnum++) {
+			ambapp_bar_t *bar = &entry->bar[bnum];
+			amba_add_bar(fun, bar->addr << 20, bar->mask);
+		}
+		
+		if (entry->irq != -1)
+			amba_add_interrupt(fun, entry->irq);
+		
+		ddf_fun_set_ops(fun->fnode, &amba_fun_ops);
+		ddf_fun_bind(fun->fnode);
+	}
+	
+	return found;
+}
+
+static void amba_fake_scan(amba_bus_t *bus)
+{
+	ddf_msg(LVL_DEBUG, "amba_fake_scan()");
+	
+	/* UART */
+	amba_fun_t *fun = amba_fun_new(bus);
+	fun->bus = 0;
+	fun->index = 0;
+	fun->vendor_id = GAISLER;
+	fun->device_id = GAISLER_APBUART;
+	fun->version = 1;
+	amba_alloc_resource_list(fun);
+	amba_add_bar(fun, 0x80000100, 0x100);
+	amba_add_interrupt(fun, 3);
+	amba_fun_set_name(fun);
+	amba_fun_create_match_ids(fun);
+	ddf_fun_set_ops(fun->fnode, &amba_fun_ops);
+	ddf_fun_bind(fun->fnode);
+	
+	ddf_msg(LVL_DEBUG, "added uart");
+	
+	/* IRQMP */
+	fun = amba_fun_new(bus);
+	fun->bus = 0;
+	fun->index = 1;
+	fun->vendor_id = GAISLER;
+	fun->device_id = GAISLER_IRQMP;
+	fun->version = 1;
+	amba_alloc_resource_list(fun);
+	amba_add_bar(fun, 0x80000200, 0x100);
+	amba_fun_set_name(fun);
+	amba_fun_create_match_ids(fun);
+	ddf_fun_set_ops(fun->fnode, &amba_fun_ops);
+	ddf_fun_bind(fun->fnode);
+	
+	ddf_msg(LVL_DEBUG, "added irqmp");
+	
+	/* GPTIMER */
+	fun = amba_fun_new(bus);
+	fun->bus = 0;
+	fun->index = 2;
+	fun->vendor_id = GAISLER;
+	fun->device_id = GAISLER_GPTIMER;
+	fun->version = 1;
+	amba_alloc_resource_list(fun);
+	amba_add_bar(fun, 0x80000300, 0x100);
+	amba_add_interrupt(fun, 8);
+	amba_fun_set_name(fun);
+	amba_fun_create_match_ids(fun);
+	ddf_fun_set_ops(fun->fnode, &amba_fun_ops);
+	ddf_fun_bind(fun->fnode);
+	
+	ddf_msg(LVL_DEBUG, "added timer");
+}
+
+static int amba_dev_add(ddf_dev_t *dnode)
+{
+	int rc = 0;
+	int found = 0;
+	bool got_res = false;
+	
+	amba_bus_t *bus = ddf_dev_data_alloc(dnode, sizeof(amba_bus_t));
+	if (bus == NULL) {
+		ddf_msg(LVL_ERROR, "amba_dev_add: allocation failed.");
+		rc = ENOMEM;
+		goto fail;
+	}
+	
+	bus->dnode = dnode;
+	async_sess_t *sess = ddf_dev_parent_sess_create(dnode, EXCHANGE_SERIALIZE);
+	if (sess == NULL) {
+		ddf_msg(LVL_ERROR, "amba_dev_add failed to connect to the "
+		    "parent driver.");
+		rc = ENOENT;
+		goto fail;
+	}
+	
+	hw_resource_list_t hw_resources;
+	rc = hw_res_get_resource_list(sess, &hw_resources);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "amba_dev_add failed to get hw resources "
+		    "for the device.");
+		goto fail;
+	}
+	
+	got_res = true;
+	assert(hw_resources.count > 1);
+	
+	bus->master_area_addr = hw_resources.resources[0].res.mem_range.address;
+	bus->master_area_size = hw_resources.resources[0].res.mem_range.size;
+	bus->slave_area_addr = hw_resources.resources[1].res.mem_range.address;
+	bus->slave_area_size = hw_resources.resources[1].res.mem_range.size;
+	
+	ddf_msg(LVL_DEBUG, "AMBA master area: 0x%08x", bus->master_area_addr);
+	ddf_msg(LVL_DEBUG, "AMBA slave area: 0x%08x", bus->slave_area_addr);
+	
+	if (pio_enable((void *)bus->master_area_addr, bus->master_area_size, &bus->master_area)) {
+		ddf_msg(LVL_ERROR, "Failed to enable master area.");
+		rc = EADDRNOTAVAIL;
+		goto fail;
+	}
+	
+	if (pio_enable((void *)bus->slave_area_addr, bus->slave_area_size, &bus->slave_area)) {
+		ddf_msg(LVL_ERROR, "Failed to enable slave area.");
+		rc = EADDRNOTAVAIL;
+		goto fail;
+	}
+	
+	/*
+	 * If nothing is found, we are probably running inside QEMU
+	 * and need to fake AMBA P&P entries.
+	 */
+	if (found == 0)
+		amba_fake_scan(bus);
+	
+	ddf_msg(LVL_DEBUG, "done");
+	
+	return EOK;
+	
+fail:
+	if (got_res)
+		hw_res_clean_resource_list(&hw_resources);
+	
+	return rc;
+}
+
+int main(int argc, char *argv[])
+{
+	printf("%s: HelenOS LEON3 AMBA bus driver\n", NAME);
+	ddf_log_init(NAME);
+	return ddf_driver_main(&amba_driver);
+}
Index: uspace/drv/bus/amba/amba.ma
===================================================================
--- uspace/drv/bus/amba/amba.ma	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
+++ uspace/drv/bus/amba/amba.ma	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
@@ -0,0 +1,1 @@
+10 amba
Index: uspace/drv/bus/amba/ambapp.h
===================================================================
--- uspace/drv/bus/amba/ambapp.h	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
+++ uspace/drv/bus/amba/ambapp.h	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2011 Jiri Svoboda
+ * Copyright (c) 2013 Jakub Klama
+ * 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 amba
+ * @{
+ */
+/** @file
+ */
+
+#ifndef AMBAPP_H_
+#define AMBAPP_H_
+
+#include <ddf/driver.h>
+
+#define AMBAPP_MAX_DEVICES     64
+#define AMBAPP_AHBMASTER_AREA  0xfffff000
+#define AMBAPP_AHBSLAVE_AREA   0xfffff800
+#define AMBAPP_CONF_AREA       0xff000
+
+#define AMBA_MAX_HW_RES  (4 + 1)
+
+typedef enum {
+	GAISLER = 1,
+	ESA = 4
+} amba_vendor_id_t;
+
+typedef enum {
+	GAISLER_LEON3    = 0x003,
+	GAISLER_LEON3DSU = 0x004,
+	GAISLER_ETHAHB   = 0x005,
+	GAISLER_APBMST   = 0x006,
+	GAISLER_AHBUART  = 0x007,
+	GAISLER_SRCTRL   = 0x008,
+	GAISLER_SDCTRL   = 0x009,
+	GAISLER_APBUART  = 0x00c,
+	GAISLER_IRQMP    = 0x00d,
+	GAISLER_AHBRAM   = 0x00e,
+	GAISLER_GPTIMER  = 0x011,
+	GAISLER_PCITRG   = 0x012,
+	GAISLER_PCISBRG  = 0x013,
+	GAISLER_PCIFBRG  = 0x014,
+	GAISLER_PCITRACE = 0x015,
+	GAISLER_PCIDMA   = 0x016,
+	GAISLER_AHBTRACE = 0x017,
+	GAISLER_ETHDSU   = 0x018,
+	GAISLER_PIOPORT  = 0x01a,
+	GAISLER_AHBJTAG  = 0x01c,
+	GAISLER_SPW      = 0x01f,
+	GAISLER_ATACTRL  = 0x024,
+	GAISLER_VGA      = 0x061,
+	GAISLER_KBD      = 0x060,
+	GAISLER_ETHMAC   = 0x01d,
+	GAISLER_DDRSPA   = 0x025,
+	GAISLER_EHCI     = 0x026,
+	GAISLER_UHCI     = 0x027,
+	GAISLER_SPW2     = 0x029,
+	GAISLER_DDR2SPA  = 0x02e,
+	GAISLER_AHBSTAT  = 0x052,
+	GAISLER_FTMCTRL  = 0x054,
+	ESA_MCTRL        = 0x00f
+} amba_device_id_t;
+
+typedef struct {
+	unsigned int addr : 12;
+	unsigned int reserved : 2;
+	unsigned int prefetchable : 1;
+	unsigned int cacheable : 1;
+	unsigned int mask : 12;
+	unsigned int type : 4;
+} __attribute__((packed)) ambapp_bar_t;
+
+typedef struct {
+	unsigned int vendor_id : 8;
+	unsigned int device_id : 24;
+	unsigned int reserved : 2;
+	unsigned int version : 5;
+	unsigned int irq : 5;
+	uint32_t user_defined[3];
+	ambapp_bar_t bar[4];
+} __attribute__((packed)) ambapp_entry_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/char/grlib_uart/Makefile
===================================================================
--- uspace/drv/char/grlib_uart/Makefile	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
+++ uspace/drv/char/grlib_uart/Makefile	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2013 Jakub Klama
+# 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.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = grlib_uart
+
+SOURCES = \
+	grlib_uart.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/char/grlib_uart/cyclic_buffer.h
===================================================================
--- uspace/drv/char/grlib_uart/cyclic_buffer.h	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
+++ uspace/drv/char/grlib_uart/cyclic_buffer.h	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2010 Lenka Trochtova
+ * 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 ns8250
+ * @{
+ */
+/** @file
+ */
+
+#ifndef CYCLIC_BUFFER_H_
+#define CYCLIC_BUFFER_H_
+
+#define BUF_LEN 4096
+
+typedef struct cyclic_buffer {
+	uint8_t buf[BUF_LEN];
+	int start;
+	int cnt;
+}  cyclic_buffer_t;
+
+/*
+ * @return		False if the buffer is full.
+ */
+static inline bool buf_push_back(cyclic_buffer_t *buf, uint8_t item)
+{
+	if (buf->cnt >= BUF_LEN)
+		return false;
+	
+	int pos = (buf->start + buf->cnt) % BUF_LEN;
+	buf->buf[pos] = item;
+	buf->cnt++;
+	return true;
+}
+
+static inline bool buf_is_empty(cyclic_buffer_t *buf)
+{
+	return buf->cnt == 0;
+}
+
+static inline uint8_t buf_pop_front(cyclic_buffer_t *buf)
+{
+	assert(!buf_is_empty(buf));
+	
+	uint8_t res = buf->buf[buf->start];
+	buf->start = (buf->start + 1) % BUF_LEN;
+	buf->cnt--;
+	return res;
+}
+
+static inline void buf_clear(cyclic_buffer_t *buf)
+{
+	buf->cnt = 0;
+}
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/char/grlib_uart/grlib_uart.c
===================================================================
--- uspace/drv/char/grlib_uart/grlib_uart.c	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
+++ uspace/drv/char/grlib_uart/grlib_uart.c	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
@@ -0,0 +1,872 @@
+/*
+ * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2011 Jiri Svoboda
+ * Copyright (c) 2013 Jakub Klama
+ * 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.
+ */
+
+/**
+ * @defgroup grlib_uart Serial port driver.
+ * @brief HelenOS serial port driver.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <fibril_synch.h>
+#include <stdlib.h>
+#include <str.h>
+#include <ctype.h>
+#include <macros.h>
+#include <malloc.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <ddi.h>
+
+#include <ddf/driver.h>
+#include <ddf/interrupt.h>
+#include <ddf/log.h>
+#include <ops/char_dev.h>
+
+#include <ns.h>
+#include <ipc/services.h>
+#include <ipc/irc.h>
+#include <device/hw_res.h>
+#include <ipc/serial_ctl.h>
+
+#include "cyclic_buffer.h"
+
+#define NAME "grlib_uart"
+
+#define REG_COUNT 5
+#define MAX_BAUD_RATE 115200
+
+#define LVL_DEBUG LVL_ERROR
+
+#define GRLIB_UART_STATUS_DR  (1 << 0)
+#define GRLIB_UART_STATUS_TS  (1 << 1)
+#define GRLIB_UART_STATUS_TE  (1 << 2)
+#define GRLIB_UART_STATUS_BR  (1 << 3)
+#define GRLIB_UART_STATUS_OV  (1 << 4)
+#define GRLIB_UART_STATUS_PE  (1 << 5)
+#define GRLIB_UART_STATUS_FE  (1 << 6)
+#define GRLIB_UART_STATUS_TH  (1 << 7)
+#define GRLIB_UART_STATUS_RH  (1 << 8)
+#define GRLIB_UART_STATUS_TF  (1 << 9)
+#define GRLIB_UART_STATUS_RF  (1 << 10)
+
+#define GRLIB_UART_CONTROL_RE  (1 << 0)
+#define GRLIB_UART_CONTROL_TE  (1 << 1)
+#define GRLIB_UART_CONTROL_RI  (1 << 2)
+#define GRLIB_UART_CONTROL_TI  (1 << 3)
+#define GRLIB_UART_CONTROL_PS  (1 << 4)
+#define GRLIB_UART_CONTROL_PE  (1 << 5)
+#define GRLIB_UART_CONTROL_FL  (1 << 6)
+#define GRLIB_UART_CONTROL_LB  (1 << 7)
+#define GRLIB_UART_CONTROL_EC  (1 << 8)
+#define GRLIB_UART_CONTROL_TF  (1 << 9)
+#define GRLIB_UART_CONTROL_RF  (1 << 10)
+#define GRLIB_UART_CONTROL_DB  (1 << 11)
+#define GRLIB_UART_CONTROL_BI  (1 << 12)
+#define GRLIB_UART_CONTROL_DI  (1 << 13)
+#define GRLIB_UART_CONTROL_SI  (1 << 14)
+#define GRLIB_UART_CONTROL_FA  (1 << 31)
+
+typedef struct {
+	unsigned int fa : 1;
+	unsigned int : 16;
+	unsigned int si : 1;
+	unsigned int di : 1;
+	unsigned int bi : 1;
+	unsigned int db : 1;
+	unsigned int rf : 1;
+	unsigned int tf : 1;
+	unsigned int ec : 1;
+	unsigned int lb : 1;
+	unsigned int fl : 1;
+	unsigned int pe : 1;
+	unsigned int ps : 1;
+	unsigned int ti : 1;
+	unsigned int ri : 1;
+	unsigned int te : 1;
+	unsigned int re : 1;
+} grlib_uart_control_t;
+
+/** GRLIB UART registers */
+typedef struct {
+	ioport32_t data;
+	ioport32_t status;
+	ioport32_t control;
+	ioport32_t scaler;
+	ioport32_t debug;
+} grlib_uart_regs_t;
+
+/** The number of bits of one data unit send by the serial port. */
+typedef enum {
+	WORD_LENGTH_5,
+	WORD_LENGTH_6,
+	WORD_LENGTH_7,
+	WORD_LENGTH_8
+} word_length_t;
+
+/** The number of stop bits used by the serial port. */
+typedef enum {
+	/** Use one stop bit. */
+	ONE_STOP_BIT,
+	/** 1.5 stop bits for word length 5, 2 stop bits otherwise. */
+	TWO_STOP_BITS
+} stop_bit_t;
+
+/** The driver data for the serial port devices. */
+typedef struct grlib_uart {
+	/** DDF device node */
+	ddf_dev_t *dev;
+	/** DDF function node */
+	ddf_fun_t *fun;
+	/** I/O registers **/
+	grlib_uart_regs_t *regs;
+	/** Are there any clients connected to the device? */
+	unsigned client_connections;
+	/** The irq assigned to this device. */
+	int irq;
+	/** The base i/o address of the devices registers. */
+	uintptr_t regs_addr;
+	/** The buffer for incoming data. */
+	cyclic_buffer_t input_buffer;
+	/** The fibril mutex for synchronizing the access to the device. */
+	fibril_mutex_t mutex;
+	/** Indicates that some data has become available */
+	fibril_condvar_t input_buffer_available;
+	/** True if device is removed. */
+	bool removed;
+} grlib_uart_t;
+
+/** Obtain soft-state structure from device node */
+static grlib_uart_t *dev_grlib_uart(ddf_dev_t *dev)
+{
+	return ddf_dev_data_get(dev);
+}
+
+/** Obtain soft-state structure from function node */
+static grlib_uart_t *fun_grlib_uart(ddf_fun_t *fun)
+{
+	return dev_grlib_uart(ddf_fun_get_dev(fun));
+}
+
+/** Find out if there is some incoming data available on the serial port.
+ *
+ * @param port The base address of the serial port device's ports.
+ *
+ * @return True if there are data waiting to be read.
+ * @return False otherwise.
+ *
+ */
+static bool grlib_uart_received(grlib_uart_regs_t *regs)
+{
+	return ((pio_read_32(&regs->status) & GRLIB_UART_STATUS_DR) != 0);
+}
+
+/** Read one byte from the serial port.
+ *
+ * @param port The base address of the serial port device's ports.
+ *
+ * @return The data read.
+ *
+ */
+static uint8_t grlib_uart_read_8(grlib_uart_regs_t *regs)
+{
+	return (uint8_t) pio_read_32(&regs->data);
+}
+
+/** Find out wheter it is possible to send data.
+ *
+ * @param port The base address of the serial port device's ports.
+ *
+ */
+static bool is_transmit_empty(grlib_uart_regs_t *regs)
+{
+	return ((pio_read_32(&regs->status) & GRLIB_UART_STATUS_TS) != 0);
+}
+
+/** Write one character on the serial port.
+ *
+ * @param port The base address of the serial port device's ports.
+ * @param c    The character to be written to the serial port device.
+ *
+ */
+static void grlib_uart_write_8(grlib_uart_regs_t *regs, uint8_t c)
+{
+	while (!is_transmit_empty(regs));
+	
+	pio_write_32(&regs->data, (uint32_t) c);
+}
+
+/** Read data from the serial port device.
+ *
+ * @param fun   The serial port function
+ * @param buf   The output buffer for read data.
+ * @param count The number of bytes to be read.
+ *
+ * @return The number of bytes actually read on success,
+ * @return Negative error number otherwise.
+ *
+ */
+static int grlib_uart_read(ddf_fun_t *fun, char *buf, size_t count)
+{
+	if (count == 0)
+		return 0;
+	
+	grlib_uart_t *ns = fun_grlib_uart(fun);
+	
+	fibril_mutex_lock(&ns->mutex);
+	
+	while (buf_is_empty(&ns->input_buffer))
+		fibril_condvar_wait(&ns->input_buffer_available, &ns->mutex);
+	
+	int ret = 0;
+	while ((!buf_is_empty(&ns->input_buffer)) && ((size_t) ret < count)) {
+		buf[ret] = (char) buf_pop_front(&ns->input_buffer);
+		ret++;
+	}
+	
+	fibril_mutex_unlock(&ns->mutex);
+	
+	return ret;
+}
+
+/** Write a character to the serial port.
+ *
+ * @param ns Serial port device
+ * @param c  The character to be written
+ *
+ */
+static inline void grlib_uart_putchar(grlib_uart_t *ns, uint8_t c)
+{
+	fibril_mutex_lock(&ns->mutex);
+	grlib_uart_write_8(ns->regs, c);
+	fibril_mutex_unlock(&ns->mutex);
+}
+
+/** Write data to the serial port.
+ *
+ * @param fun   The serial port function
+ * @param buf   The data to be written
+ * @param count The number of bytes to be written
+ *
+ * @return Zero on success
+ *
+ */
+static int grlib_uart_write(ddf_fun_t *fun, char *buf, size_t count)
+{
+	grlib_uart_t *ns = fun_grlib_uart(fun);
+	
+	for (size_t idx = 0; idx < count; idx++)
+		grlib_uart_putchar(ns, (uint8_t) buf[idx]);
+	
+	return count;
+}
+
+static ddf_dev_ops_t grlib_uart_dev_ops;
+
+/** The character interface's callbacks. */
+static char_dev_ops_t grlib_uart_char_dev_ops = {
+	.read = &grlib_uart_read,
+	.write = &grlib_uart_write
+};
+
+static int grlib_uart_dev_add(ddf_dev_t *);
+static int grlib_uart_dev_remove(ddf_dev_t *);
+
+/** The serial port device driver's standard operations. */
+static driver_ops_t grlib_uart_ops = {
+	.dev_add = &grlib_uart_dev_add,
+	.dev_remove = &grlib_uart_dev_remove
+};
+
+/** The serial port device driver structure. */
+static driver_t grlib_uart_driver = {
+	.name = NAME,
+	.driver_ops = &grlib_uart_ops
+};
+
+/** Clean up the serial port soft-state
+ *
+ * @param ns Serial port device
+ *
+ */
+static void grlib_uart_dev_cleanup(grlib_uart_t *ns)
+{
+}
+
+/** Enable the i/o ports of the device.
+ *
+ * @param ns Serial port device
+ *
+ * @return True on success, false otherwise
+ *
+ */
+static bool grlib_uart_pio_enable(grlib_uart_t *ns)
+{
+	ddf_msg(LVL_DEBUG, "grlib_uart_pio_enable %s", ddf_dev_get_name(ns->dev));
+	
+	/* Gain control over port's registers. */
+	if (pio_enable((void *) ns->regs_addr, REG_COUNT,
+	    (void **) &ns->regs)) {
+		ddf_msg(LVL_ERROR, "Cannot map the port %#" PRIx32
+		    " for device %s.", ns->regs_addr, ddf_dev_get_name(ns->dev));
+		return false;
+	}
+	
+	return true;
+}
+
+/** Probe the serial port device for its presence.
+ *
+ * @param ns Serial port device
+ *
+ * @return True if the device is present, false otherwise
+ *
+ */
+static bool grlib_uart_dev_probe(grlib_uart_t *ns)
+{
+	ddf_msg(LVL_DEBUG, "grlib_uart_dev_probe %s", ddf_dev_get_name(ns->dev));
+	
+	return true;
+}
+
+/** Initialize serial port device.
+ *
+ * @param ns Serial port device
+ *
+ * @return Zero on success, negative error number otherwise
+ *
+ */
+static int grlib_uart_dev_initialize(grlib_uart_t *ns)
+{
+	ddf_msg(LVL_DEBUG, "grlib_uart_dev_initialize %s", ddf_dev_get_name(ns->dev));
+	
+	hw_resource_list_t hw_resources;
+	memset(&hw_resources, 0, sizeof(hw_resource_list_t));
+	
+	int ret = EOK;
+	
+	/* Connect to the parent's driver. */
+	async_sess_t *parent_sess = ddf_dev_parent_sess_create(ns->dev,
+	    EXCHANGE_SERIALIZE);
+	if (parent_sess == NULL) {
+		ddf_msg(LVL_ERROR, "Failed to connect to parent driver of "
+		    "device %s.", ddf_dev_get_name(ns->dev));
+		ret = ENOENT;
+		goto failed;
+	}
+	
+	/* Get hw resources. */
+	ret = hw_res_get_resource_list(parent_sess, &hw_resources);
+	if (ret != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to get HW resources for device "
+		    "%s.", ddf_dev_get_name(ns->dev));
+		goto failed;
+	}
+	
+	bool irq = false;
+	bool ioport = false;
+	
+	for (size_t i = 0; i < hw_resources.count; i++) {
+		hw_resource_t *res = &hw_resources.resources[i];
+		switch (res->type) {
+		case INTERRUPT:
+			ns->irq = res->res.interrupt.irq;
+			irq = true;
+			ddf_msg(LVL_NOTE, "Device %s was assigned irq = 0x%x.",
+			    ddf_dev_get_name(ns->dev), ns->irq);
+			break;
+			
+		case MEM_RANGE:
+			ns->regs_addr = res->res.mem_range.address;
+			if (res->res.mem_range.size < REG_COUNT) {
+				ddf_msg(LVL_ERROR, "I/O range assigned to "
+				    "device %s is too small.", ddf_dev_get_name(ns->dev));
+				ret = ELIMIT;
+				goto failed;
+			}
+			ioport = true;
+			ddf_msg(LVL_NOTE, "Device %s was assigned I/O address = "
+			    "0x%x.", ddf_dev_get_name(ns->dev), ns->regs_addr);
+    			break;
+			
+		default:
+			break;
+		}
+	}
+	
+	if ((!irq) || (!ioport)) {
+		ddf_msg(LVL_ERROR, "Missing HW resource(s) for device %s.",
+		    ddf_dev_get_name(ns->dev));
+		ret = ENOENT;
+		goto failed;
+	}
+	
+	hw_res_clean_resource_list(&hw_resources);
+	return ret;
+	
+failed:
+	grlib_uart_dev_cleanup(ns);
+	hw_res_clean_resource_list(&hw_resources);
+	return ret;
+}
+
+/** Enable interrupts on the serial port device.
+ *
+ * Interrupt when data is received
+ *
+ * @param port The base address of the serial port device's ports.
+ *
+ */
+static inline void grlib_uart_port_interrupts_enable(grlib_uart_regs_t *regs)
+{
+	/* Interrupt when data received. */
+	uint32_t control = pio_read_32(&regs->control);
+	pio_write_32(&regs->control, control | GRLIB_UART_CONTROL_RE);
+}
+
+/** Disable interrupts on the serial port device.
+ *
+ * @param port The base address of the serial port device's ports.
+ *
+ */
+static inline void grlib_uart_port_interrupts_disable(grlib_uart_regs_t *regs)
+{
+	uint32_t control = pio_read_32(&regs->control);
+	pio_write_32(&regs->control, control & (~GRLIB_UART_CONTROL_RE));
+}
+
+/** Enable interrupts for the serial port device.
+ *
+ * @param ns Serial port device
+ *
+ * @return Zero on success, negative error number otherwise
+ *
+ */
+static int grlib_uart_interrupt_enable(grlib_uart_t *ns)
+{
+	/* Enable interrupt on the serial port. */
+	grlib_uart_port_interrupts_enable(ns->regs);
+	
+	return EOK;
+}
+
+static int grlib_uart_port_set_baud_rate(grlib_uart_regs_t *regs,
+    unsigned int baud_rate)
+{
+	if ((baud_rate < 50) || (MAX_BAUD_RATE % baud_rate != 0)) {
+		ddf_msg(LVL_ERROR, "Invalid baud rate %d requested.",
+		    baud_rate);
+		return EINVAL;
+	}
+	
+	/* XXX: Set baud rate */
+	
+	return EOK;
+}
+
+/** Set the parameters of the serial communication on the serial port device.
+ *
+ * @param parity      The parity to be used.
+ * @param word_length The length of one data unit in bits.
+ * @param stop_bits   The number of stop bits used (one or two).
+ *
+ * @return Zero on success.
+ * @return EINVAL if some of the specified values is invalid.
+ *
+ */
+static int grlib_uart_port_set_com_props(grlib_uart_regs_t *regs,
+    unsigned int parity, unsigned int word_length, unsigned int stop_bits)
+{
+	uint32_t val = pio_read_32(&regs->control);
+	
+	switch (parity) {
+	case SERIAL_NO_PARITY:
+	case SERIAL_ODD_PARITY:
+	case SERIAL_EVEN_PARITY:
+	case SERIAL_MARK_PARITY:
+	case SERIAL_SPACE_PARITY:
+		val |= GRLIB_UART_CONTROL_PE;
+		break;
+	default:
+		return EINVAL;
+	}
+	
+	pio_write_32(&regs->control, val);
+	
+	return EOK;
+}
+
+/** Initialize the serial port device.
+ *
+ * Set the default parameters of the serial communication.
+ *
+ * @param ns Serial port device
+ *
+ */
+static void grlib_uart_initialize_port(grlib_uart_t *ns)
+{
+	/* Disable interrupts. */
+	grlib_uart_port_interrupts_disable(ns->regs);
+	
+	/* Set baud rate. */
+	grlib_uart_port_set_baud_rate(ns->regs, 38400);
+	
+	/* 8 bits, no parity, two stop bits. */
+	grlib_uart_port_set_com_props(ns->regs, SERIAL_NO_PARITY, 8, 2);
+	
+	/*
+	 * Enable FIFO, clear them, with 4-byte threshold for greater
+	 * reliability.
+	 */
+	pio_write_32(&ns->regs->control, GRLIB_UART_CONTROL_RE |
+	    GRLIB_UART_CONTROL_TE | GRLIB_UART_CONTROL_RF |
+	    GRLIB_UART_CONTROL_TF | GRLIB_UART_CONTROL_RI |
+	    GRLIB_UART_CONTROL_FA);
+}
+
+/** Deinitialize the serial port device.
+ *
+ * @param ns Serial port device
+ *
+ */
+static void grlib_uart_port_cleanup(grlib_uart_t *ns)
+{
+	grlib_uart_port_interrupts_disable(ns->regs);
+}
+
+/** Read the data from the serial port device and store them to the input
+ * buffer.
+ *
+ * @param ns Serial port device
+ *
+ */
+static void grlib_uart_read_from_device(grlib_uart_t *ns)
+{
+	grlib_uart_regs_t *regs = ns->regs;
+	bool cont = true;
+	
+	fibril_mutex_lock(&ns->mutex);
+	
+	while (cont) {
+		cont = grlib_uart_received(regs);
+		if (cont) {
+			uint8_t val = grlib_uart_read_8(regs);
+			
+			if (ns->client_connections > 0) {
+				bool buf_was_empty = buf_is_empty(&ns->input_buffer);
+				if (!buf_push_back(&ns->input_buffer, val)) {
+					ddf_msg(LVL_WARN, "Buffer overflow on "
+					    "%s.", ddf_dev_get_name(ns->dev));
+					break;
+				} else {
+					ddf_msg(LVL_DEBUG2, "Character %c saved "
+					    "to the buffer of %s.",
+					    val, ddf_dev_get_name(ns->dev));
+					if (buf_was_empty)
+						fibril_condvar_broadcast(&ns->input_buffer_available);
+				}
+			}
+		}
+	}
+	
+	fibril_mutex_unlock(&ns->mutex);
+	fibril_yield();
+}
+
+/** The interrupt handler.
+ *
+ * The serial port is initialized to interrupt when some data come or line
+ * status register changes, so the interrupt is handled by reading the incoming
+ * data and reading the line status register.
+ *
+ * @param dev The serial port device.
+ *
+ */
+static inline void grlib_uart_interrupt_handler(ddf_dev_t *dev,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	grlib_uart_t *ns = dev_grlib_uart(dev);
+	
+	uint32_t status = pio_read_32(&ns->regs->status);
+	
+	if (status & GRLIB_UART_STATUS_RF) {
+		if (status & GRLIB_UART_STATUS_OV)
+			ddf_msg(LVL_WARN, "Overrun error on %s", ddf_dev_get_name(ns->dev));
+	}
+	
+	grlib_uart_read_from_device(ns);
+}
+
+/** Register the interrupt handler for the device.
+ *
+ * @param ns Serial port device
+ *
+ */
+static inline int grlib_uart_register_interrupt_handler(grlib_uart_t *ns)
+{
+	return register_interrupt_handler(ns->dev, ns->irq,
+	    grlib_uart_interrupt_handler, NULL);
+}
+
+/** Unregister the interrupt handler for the device.
+ *
+ * @param ns Serial port device
+ *
+ */
+static inline int grlib_uart_unregister_interrupt_handler(grlib_uart_t *ns)
+{
+	return unregister_interrupt_handler(ns->dev, ns->irq);
+}
+
+/** The dev_add callback method of the serial port driver.
+ *
+ * Probe and initialize the newly added device.
+ *
+ * @param dev The serial port device.
+ *
+ */
+static int grlib_uart_dev_add(ddf_dev_t *dev)
+{
+	grlib_uart_t *ns = NULL;
+	ddf_fun_t *fun = NULL;
+	bool need_cleanup = false;
+	bool need_unreg_intr_handler = false;
+	int rc;
+	
+	ddf_msg(LVL_DEBUG, "grlib_uart_dev_add %s (handle = %d)",
+	    ddf_dev_get_name(dev), (int) ddf_dev_get_handle(dev));
+	
+	/* Allocate soft-state for the device */
+	ns = ddf_dev_data_alloc(dev, sizeof(grlib_uart_t));
+	if (ns == NULL) {
+		rc = ENOMEM;
+		goto fail;
+	}
+	
+	fibril_mutex_initialize(&ns->mutex);
+	fibril_condvar_initialize(&ns->input_buffer_available);
+	ns->dev = dev;
+	
+	rc = grlib_uart_dev_initialize(ns);
+	if (rc != EOK)
+		goto fail;
+	
+	need_cleanup = true;
+	
+	if (!grlib_uart_pio_enable(ns)) {
+		rc = EADDRNOTAVAIL;
+		goto fail;
+	}
+	
+	/* Find out whether the device is present. */
+	if (!grlib_uart_dev_probe(ns)) {
+		rc = ENOENT;
+		goto fail;
+	}
+	
+	/* Serial port initialization (baud rate etc.). */
+	grlib_uart_initialize_port(ns);
+	
+	/* Register interrupt handler. */
+	if (grlib_uart_register_interrupt_handler(ns) != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to register interrupt handler.");
+		rc = EADDRNOTAVAIL;
+		goto fail;
+	}
+	need_unreg_intr_handler = true;
+	
+	/* Enable interrupt. */
+	rc = grlib_uart_interrupt_enable(ns);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to enable the interrupt. Error code = "
+		    "%d.", rc);
+		goto fail;
+	}
+	
+	fun = ddf_fun_create(dev, fun_exposed, "a");
+	if (fun == NULL) {
+		ddf_msg(LVL_ERROR, "Failed creating function.");
+		goto fail;
+	}
+	
+	/* Set device operations. */
+	ddf_fun_set_ops(fun, &grlib_uart_dev_ops);
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding function.");
+		goto fail;
+	}
+	
+	ns->fun = fun;
+	
+	ddf_fun_add_to_category(fun, "serial");
+	
+	ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
+	    ddf_dev_get_name(dev));
+	
+	return EOK;
+	
+fail:
+	if (fun != NULL)
+		ddf_fun_destroy(fun);
+	
+	if (need_unreg_intr_handler)
+		grlib_uart_unregister_interrupt_handler(ns);
+	
+	if (need_cleanup)
+		grlib_uart_dev_cleanup(ns);
+	
+	return rc;
+}
+
+static int grlib_uart_dev_remove(ddf_dev_t *dev)
+{
+	grlib_uart_t *ns = dev_grlib_uart(dev);
+	
+	fibril_mutex_lock(&ns->mutex);
+	if (ns->client_connections > 0) {
+		fibril_mutex_unlock(&ns->mutex);
+		return EBUSY;
+	}
+	ns->removed = true;
+	fibril_mutex_unlock(&ns->mutex);
+	
+	int rc = ddf_fun_unbind(ns->fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to unbind function.");
+		return rc;
+	}
+	
+	ddf_fun_destroy(ns->fun);
+	
+	grlib_uart_port_cleanup(ns);
+	grlib_uart_unregister_interrupt_handler(ns);
+	grlib_uart_dev_cleanup(ns);
+	return EOK;
+}
+
+/** Open the device.
+ *
+ * This is a callback function called when a client tries to connect to the
+ * device.
+ *
+ * @param dev The device.
+ *
+ */
+static int grlib_uart_open(ddf_fun_t *fun)
+{
+	grlib_uart_t *ns = fun_grlib_uart(fun);
+	int res;
+	
+	fibril_mutex_lock(&ns->mutex);
+	if (ns->removed) {
+		res = ENXIO;
+	} else {
+		res = EOK;
+		ns->client_connections++;
+	}
+	fibril_mutex_unlock(&ns->mutex);
+	
+	return res;
+}
+
+/** Close the device.
+ *
+ * This is a callback function called when a client tries to disconnect from
+ * the device.
+ *
+ * @param dev The device.
+ *
+ */
+static void grlib_uart_close(ddf_fun_t *fun)
+{
+	grlib_uart_t *data = fun_grlib_uart(fun);
+	
+	fibril_mutex_lock(&data->mutex);
+	
+	assert(data->client_connections > 0);
+	
+	if (!(--data->client_connections))
+		buf_clear(&data->input_buffer);
+	
+	fibril_mutex_unlock(&data->mutex);
+}
+
+/** Default handler for client requests which are not handled by the standard
+ * interfaces.
+ *
+ * Configure the parameters of the serial communication.
+ *
+ */
+static void grlib_uart_default_handler(ddf_fun_t *fun, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	sysarg_t method = IPC_GET_IMETHOD(*call);
+	
+	switch (method) {
+	default:
+		async_answer_0(callid, ENOTSUP);
+	}
+}
+
+/** Initialize the serial port driver.
+ *
+ * Initialize device operations structures with callback methods for handling
+ * client requests to the serial port devices.
+ *
+ */
+static void grlib_uart_init(void)
+{
+	ddf_log_init(NAME);
+	
+	grlib_uart_dev_ops.open = &grlib_uart_open;
+	grlib_uart_dev_ops.close = &grlib_uart_close;
+	
+	grlib_uart_dev_ops.interfaces[CHAR_DEV_IFACE] = &grlib_uart_char_dev_ops;
+	grlib_uart_dev_ops.default_handler = &grlib_uart_default_handler;
+}
+
+int main(int argc, char *argv[])
+{
+	printf("%s: HelenOS serial port driver\n", NAME);
+	grlib_uart_init();
+	return ddf_driver_main(&grlib_uart_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/char/grlib_uart/grlib_uart.ma
===================================================================
--- uspace/drv/char/grlib_uart/grlib_uart.ma	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
+++ uspace/drv/char/grlib_uart/grlib_uart.ma	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
@@ -0,0 +1,1 @@
+10 amba/ven=01&dev=0000000c
Index: uspace/drv/infrastructure/rootleon3/Makefile
===================================================================
--- uspace/drv/infrastructure/rootleon3/Makefile	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
+++ uspace/drv/infrastructure/rootleon3/Makefile	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2012 Jan Vesely
+# 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.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = rootleon3
+
+SOURCES = \
+	rootleon3.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/infrastructure/rootleon3/rootleon3.c
===================================================================
--- uspace/drv/infrastructure/rootleon3/rootleon3.c	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
+++ uspace/drv/infrastructure/rootleon3/rootleon3.c	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2012 Jan Vesely
+ * Copyright (c) 2013 Jakub Klama
+ * 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.
+ */
+
+/**
+ * @defgroup root_leon3 SPARC LEON3 platform driver.
+ * @brief HelenOS SPARC LEON3 platform driver.
+ * @{
+ */
+/** @file
+ */
+
+#include <ddf/log.h>
+#include <errno.h>
+#include <ops/hw_res.h>
+#include <stdio.h>
+#include "rootleon3.h"
+
+#define NAME  "rootleon3"
+
+typedef struct {
+	const char *name;
+	match_id_t match_id;
+	hw_resource_list_t hw_resources;
+} rootleon3_fun_t;
+
+static hw_resource_t amba_res[] = {
+	{
+		.type = MEM_RANGE,
+		.res.mem_range = {
+			.address = AMBAPP_MASTER_AREA,
+			.size = AMBAPP_MASTER_SIZE,
+			.endianness = BIG_ENDIAN
+		}
+	},
+	{
+		.type = MEM_RANGE,
+		.res.mem_range = {
+			.address = AMBAPP_SLAVE_AREA,
+			.size = AMBAPP_SLAVE_SIZE,
+			.endianness = BIG_ENDIAN,
+		}
+	}
+};
+
+static const rootleon3_fun_t leon3_func = {
+	.name = "leon_amba",
+	.match_id = {
+		.id =  "leon_amba",
+		.score = 90 
+	},
+	.hw_resources = {
+		.count = 2,
+		.resources = amba_res
+	}
+};
+
+static hw_resource_list_t *rootleon3_get_resources(ddf_fun_t *);
+static bool rootleon3_enable_interrupt(ddf_fun_t *);
+
+static hw_res_ops_t fun_hw_res_ops = {
+	.get_resource_list = &rootleon3_get_resources,
+	.enable_interrupt = &rootleon3_enable_interrupt
+};
+
+static ddf_dev_ops_t rootleon3_fun_ops = {
+	.interfaces[HW_RES_DEV_IFACE] = &fun_hw_res_ops
+};
+
+static int rootleon3_add_fun(ddf_dev_t *dev, const rootleon3_fun_t *fun)
+{
+	assert(dev);
+	assert(fun);
+	
+	ddf_msg(LVL_DEBUG, "Adding new function '%s'.", fun->name);
+	
+	/* Create new device function. */
+	ddf_fun_t *fnode = ddf_fun_create(dev, fun_inner, fun->name);
+	if (fnode == NULL)
+		return ENOMEM;
+	
+	/* Add match id */
+	int ret = ddf_fun_add_match_id(fnode, fun->match_id.id,
+	    fun->match_id.score);
+	if (ret != EOK) {
+		ddf_fun_destroy(fnode);
+		return ret;
+	}
+	
+	/* Allocate needed data */
+	rootleon3_fun_t *rf =
+	    ddf_fun_data_alloc(fnode, sizeof(rootleon3_fun_t));
+	if (!rf) {
+		ddf_fun_destroy(fnode);
+		return ENOMEM;
+	}
+	*rf = *fun;
+	
+	/* Set provided operations to the device. */
+	ddf_fun_set_ops(fnode, &rootleon3_fun_ops);
+	
+	/* Register function. */
+	ret = ddf_fun_bind(fnode);
+	if (ret != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding function %s.", fun->name);
+		ddf_fun_destroy(fnode);
+		return ret;
+	}
+	
+	return EOK;
+}
+
+/** Add the root device.
+ *
+ * @param dev Device which is root of the whole device tree
+ *            (both of HW and pseudo devices).
+ *
+ * @return Zero on success, negative error number otherwise.
+ *
+ */
+static int rootleon3_dev_add(ddf_dev_t *dev)
+{
+	assert(dev);
+	
+	/* Register functions */
+	if (rootleon3_add_fun(dev, &leon3_func) != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to add %s function for "
+		    "LEON3 platform.", leon3_func.name);
+	}
+	
+	return EOK;
+}
+
+/** The root device driver's standard operations. */
+static driver_ops_t rootleon3_ops = {
+	.dev_add = &rootleon3_dev_add
+};
+
+/** The root device driver structure. */
+static driver_t rootleon3_driver = {
+	.name = NAME,
+	.driver_ops = &rootleon3_ops
+};
+
+static hw_resource_list_t *rootleon3_get_resources(ddf_fun_t *fnode)
+{
+	rootleon3_fun_t *fun = ddf_fun_data_get(fnode);
+	assert(fun != NULL);
+	
+	printf("rootleon3_get_resources() called\n");
+	
+	return &fun->hw_resources;
+}
+
+static bool rootleon3_enable_interrupt(ddf_fun_t *fun)
+{
+	// FIXME TODO
+	return false;
+}
+
+int main(int argc, char *argv[])
+{
+	printf("%s: HelenOS SPARC LEON3 platform driver\n", NAME);
+	ddf_log_init(NAME);
+	return ddf_driver_main(&rootleon3_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/infrastructure/rootleon3/rootleon3.h
===================================================================
--- uspace/drv/infrastructure/rootleon3/rootleon3.h	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
+++ uspace/drv/infrastructure/rootleon3/rootleon3.h	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013 Jakub Klama
+ * 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 leon3drv
+ * @{
+ */
+/** @file
+ * @brief LEON3 root device.
+ */
+
+#ifndef ROOTLEON3_H
+#define ROOTLEON3_H
+
+#define AMBAPP_MASTER_AREA  0xfffff000
+#define AMBAPP_SLAVE_AREA   0xfffff800
+#define AMBAPP_MASTER_SIZE  0x800
+#define AMBAPP_SLAVE_SIZE   0x800
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/infrastructure/rootleon3/rootleon3.ma
===================================================================
--- uspace/drv/infrastructure/rootleon3/rootleon3.ma	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
+++ uspace/drv/infrastructure/rootleon3/rootleon3.ma	(revision 0caa075ea82d03f424199300f84ace6747f5bd02)
@@ -0,0 +1,1 @@
+100 platform/leon3
