Index: uspace/drv/bus/isa/isa.dev
===================================================================
--- uspace/drv/bus/isa/isa.dev	(revision 1d5a5405546f3f0a0cab965cb3a4339c902e5e26)
+++ uspace/drv/bus/isa/isa.dev	(revision 2568c94738140fd4f5f3170b8368fb126a30b7e2)
@@ -27,2 +27,6 @@
 	dma 1
 	dma 5
+
+cmos-rtc:
+	match 100 isa/cmos-rtc
+	io_range 70 2
Index: uspace/drv/time/cmos-rtc/Makefile
===================================================================
--- uspace/drv/time/cmos-rtc/Makefile	(revision 2568c94738140fd4f5f3170b8368fb126a30b7e2)
+++ uspace/drv/time/cmos-rtc/Makefile	(revision 2568c94738140fd4f5f3170b8368fb126a30b7e2)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2012 Maurizio Lombardi
+# 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 = cmos-rtc
+
+SOURCES = \
+	cmos-rtc.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/time/cmos-rtc/cmos-regs.h
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-regs.h	(revision 2568c94738140fd4f5f3170b8368fb126a30b7e2)
+++ uspace/drv/time/cmos-rtc/cmos-regs.h	(revision 2568c94738140fd4f5f3170b8368fb126a30b7e2)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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.
+ */
+
+#ifndef _CMOS_RTC_H_
+#define _CMOS_RTC_H_
+
+#define RTC_SEC           0x00
+#define RTC_MIN           0x02
+#define RTC_HOUR          0x04
+#define RTC_DAY           0x07
+#define RTC_MON           0x08
+#define RTC_YEAR          0x09
+
+#define RTC_STATUS_B      0x0B
+#define RTC_B_24H         0x02 /* 24h mode */
+#define RTC_B_BCD         0x04 /* BCD mode */
+#define RTC_B_INH         0x80 /* Inhibit updates */
+
+#define RTC_STATUS_D      0x0D
+#define RTC_D_BATTERY_OK  0x80 /* Battery status */
+
+#define RTC_STATUS_A      0x0A
+#define RTC_A_UPDATE      0x80 /* Update in progress */
+#define RTC_A_CLK_STOP    0x70 /* Stop the clock */
+
+#endif
+
Index: uspace/drv/time/cmos-rtc/cmos-rtc.c
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision 2568c94738140fd4f5f3170b8368fb126a30b7e2)
+++ uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision 2568c94738140fd4f5f3170b8368fb126a30b7e2)
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 CMOS RTC driver.
+ * @brief HelenOS RTC driver.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <errno.h>
+#include <ddi.h>
+#include <as.h>
+#include <sysinfo.h>
+#include <libarch/ddi.h>
+#include <libarch/barrier.h>
+#include <stdio.h>
+#include <ddf/driver.h>
+#include <ddf/log.h>
+#include <ops/clock_dev.h>
+#include <fibril_synch.h>
+#include <device/hw_res.h>
+#include <devman.h>
+#include <macros.h>
+#include <ipc/clock_ctl.h>
+#include <time.h>
+
+#include "cmos-regs.h"
+
+#define NAME "cmos-rtc"
+
+#define REG_COUNT 2
+
+#define RTC_FROM_FNODE(fnode)  ((rtc_t *) ((fnode)->dev->driver_data))
+#define RTC_FROM_DEV(devnode)  ((rtc_t *) ((devnode)->driver_data))
+
+typedef struct rtc {
+	/** DDF device node */
+	ddf_dev_t *dev;
+	/** DDF function node */
+	ddf_fun_t *fun;
+	/** The fibril mutex for synchronizing the access to the device */
+	fibril_mutex_t mutex;
+	/** The base I/O address of the device registers */
+	uint32_t io_addr;
+	/** The I/O port used to access the CMOS registers */
+	ioport8_t *port;
+	/** true if device is removed */
+	bool removed;
+} rtc_t;
+
+static int  rtc_time_get(ddf_fun_t *fun, struct tm *t);
+static int  rtc_time_set(ddf_fun_t *fun, struct tm *t);
+static int  rtc_dev_add(ddf_dev_t *dev);
+static int  rtc_dev_initialize(rtc_t *rtc);
+static bool rtc_pio_enable(rtc_t *rtc);
+static void rtc_dev_cleanup(rtc_t *rtc);
+static int  rtc_open(ddf_fun_t *fun);
+static void rtc_close(ddf_fun_t *fun);
+static bool rtc_update_in_progress(rtc_t *rtc);
+static int  rtc_register_read(rtc_t *rtc, int reg);
+static unsigned bcd2bin(unsigned bcd);
+static unsigned bin2bcd(unsigned binary);
+static void rtc_default_handler(ddf_fun_t *fun,
+    ipc_callid_t callid, ipc_call_t *call);
+static int rtc_dev_remove(ddf_dev_t *dev);
+static void rtc_register_write(rtc_t *rtc, int reg, int data);
+static time_t uptime_get(void);
+
+static ddf_dev_ops_t rtc_dev_ops;
+static time_t boottime = 0;
+
+/** The RTC device driver's standard operations */
+static driver_ops_t rtc_ops = {
+	.dev_add = rtc_dev_add,
+	.dev_remove = rtc_dev_remove,
+};
+
+/** The RTC device driver structure */
+static driver_t rtc_driver = {
+	.name = NAME,
+	.driver_ops = &rtc_ops,
+};
+
+/** Clock interface */
+static clock_dev_ops_t rtc_clock_dev_ops = {
+	.time_get = rtc_time_get,
+	.time_set = rtc_time_set,
+};
+
+/** Initialize the RTC driver */
+static void
+rtc_init(void)
+{
+	ddf_log_init(NAME, LVL_ERROR);
+
+	rtc_dev_ops.open = rtc_open;
+	rtc_dev_ops.close = rtc_close;
+
+	rtc_dev_ops.interfaces[CLOCK_DEV_IFACE] = &rtc_clock_dev_ops;
+	rtc_dev_ops.default_handler = &rtc_default_handler;
+}
+
+/** Clean up the RTC soft state
+ *
+ * @param rtc  The RTC device
+ */
+static void
+rtc_dev_cleanup(rtc_t *rtc)
+{
+	if (rtc->dev->parent_sess) {
+		async_hangup(rtc->dev->parent_sess);
+		rtc->dev->parent_sess = NULL;
+	}
+}
+
+/** Enable the I/O ports of the device
+ *
+ * @param rtc  The real time clock device
+ *
+ * @return  true in case of success, false otherwise
+ */
+static bool
+rtc_pio_enable(rtc_t *rtc)
+{
+	if (pio_enable((void *)(uintptr_t) rtc->io_addr, REG_COUNT,
+	    (void **) &rtc->port)) {
+
+		ddf_msg(LVL_ERROR, "Cannot map the port %#" PRIx32
+		    " for device %s", rtc->io_addr, rtc->dev->name);
+		return false;
+	}
+
+	return true;
+}
+
+/** Initialize the RTC device
+ *
+ * @param rtc  Pointer to the RTC device
+ *
+ * @return  EOK on success or a negative error code
+ */ 
+static int
+rtc_dev_initialize(rtc_t *rtc)
+{
+	int rc;
+	size_t i;
+	hw_resource_t *res;
+	bool ioport = false;
+
+	ddf_msg(LVL_DEBUG, "rtc_dev_initialize %s", rtc->dev->name);
+
+	hw_resource_list_t hw_resources;
+	memset(&hw_resources, 0, sizeof(hw_resource_list_t));
+
+	/* Connect to the parent's driver */
+
+	rtc->dev->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
+	    rtc->dev->handle, IPC_FLAG_BLOCKING);
+	if (!rtc->dev->parent_sess) {
+		ddf_msg(LVL_ERROR, "Failed to connect to parent driver\
+		    of device %s.", rtc->dev->name);
+		rc = ENOENT;
+		goto error;
+	}
+
+	/* Get the HW resources */
+	rc = hw_res_get_resource_list(rtc->dev->parent_sess, &hw_resources);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to get HW resources\
+		    for device %s", rtc->dev->name);
+		goto error;
+	}
+
+	for (i = 0; i < hw_resources.count; ++i) {
+		res = &hw_resources.resources[i];
+
+		if (res->type == IO_RANGE) {
+			if (res->res.io_range.size < REG_COUNT) {
+				ddf_msg(LVL_ERROR, "I/O range assigned to \
+				    device %s is too small", rtc->dev->name);
+				rc = ELIMIT;
+				goto error;
+			}
+			rtc->io_addr = res->res.io_range.address;
+			ioport = true;
+			ddf_msg(LVL_NOTE, "Device %s was assigned I/O address \
+			    0x%x", rtc->dev->name, rtc->io_addr);
+		}
+	}
+
+	if (!ioport) {
+		/* No I/O address assigned to this device */
+		ddf_msg(LVL_ERROR, "Missing HW resource for device %s",
+		    rtc->dev->name);
+		rc = ENOENT;
+		goto error;
+	}
+
+	hw_res_clean_resource_list(&hw_resources);
+
+	return EOK;
+
+error:
+	rtc_dev_cleanup(rtc);
+	hw_res_clean_resource_list(&hw_resources);
+
+	return rc;
+}
+
+/** Read a register from the CMOS memory
+ *
+ * @param rtc    The rtc device
+ * @param reg    The index of the register to read
+ *
+ * @return       The value of the register
+ */
+static int
+rtc_register_read(rtc_t *rtc, int reg)
+{
+	pio_write_8(rtc->port, reg);
+	return pio_read_8(rtc->port + 1);
+}
+
+/** Write a register to the CMOS memory
+ *
+ * @param rtc    The rtc device
+ * @param reg    The index of the register to write
+ * @param data   The data to write
+ */
+static void
+rtc_register_write(rtc_t *rtc, int reg, int data)
+{
+	pio_write_8(rtc->port, reg);
+	pio_write_8(rtc->port + 1, data);
+}
+
+/** Check if an update is in progress
+ *
+ * @param rtc  The rtc device
+ *
+ * @return  true if an update is in progress, false otherwise
+ */
+static bool
+rtc_update_in_progress(rtc_t *rtc)
+{
+	return rtc_register_read(rtc, RTC_STATUS_A) & RTC_A_UPDATE;
+}
+
+/** Read the current time from the CMOS
+ *
+ * @param fun  The RTC function
+ * @param t    Pointer to the time variable
+ *
+ * @return  EOK on success or a negative error code
+ */
+static int
+rtc_time_get(ddf_fun_t *fun, struct tm *t)
+{
+	bool bcd_mode;
+	bool pm_mode = false;
+	rtc_t *rtc = RTC_FROM_FNODE(fun);
+
+	if (boottime != 0) {
+		/* There is no need to read the current time from the
+		 * device because it has already been cached.
+		 */
+
+		time_t cur_time = boottime + uptime_get();
+		return localtime2tm(cur_time, t);
+	}
+
+	fibril_mutex_lock(&rtc->mutex);
+
+	/* now read the registers */
+	do {
+		/* Suspend until the update process has finished */
+		while (rtc_update_in_progress(rtc));
+
+		t->tm_sec  = rtc_register_read(rtc, RTC_SEC);
+		t->tm_min  = rtc_register_read(rtc, RTC_MIN);
+		t->tm_hour = rtc_register_read(rtc, RTC_HOUR);
+		t->tm_mday = rtc_register_read(rtc, RTC_DAY);
+		t->tm_mon  = rtc_register_read(rtc, RTC_MON);
+		t->tm_year = rtc_register_read(rtc, RTC_YEAR);
+
+		/* Now check if it is stable */
+	} while( t->tm_sec  != rtc_register_read(rtc, RTC_SEC) ||
+		 t->tm_min  != rtc_register_read(rtc, RTC_MIN) ||
+		 t->tm_mday != rtc_register_read(rtc, RTC_DAY) ||
+		 t->tm_mon  != rtc_register_read(rtc, RTC_MON) ||
+		 t->tm_year != rtc_register_read(rtc, RTC_YEAR));
+
+	/* Check if the RTC is working in 12h mode */
+	bool _12h_mode = !(rtc_register_read(rtc, RTC_STATUS_B) &
+	    RTC_B_24H);
+
+	if (_12h_mode) {
+		/* The RTC is working in 12h mode, check if it is AM or PM */
+		if (t->tm_hour & 0x80) {
+			/* PM flag is active, it must be cleared */
+			t->tm_hour &= ~0x80;
+			pm_mode = true;
+		}
+	}
+
+	/* Check if the RTC is working in BCD mode */
+	bcd_mode = !(rtc_register_read(rtc, RTC_STATUS_B) & RTC_B_BCD);
+
+	if (bcd_mode) {
+		t->tm_sec  = bcd2bin(t->tm_sec);
+		t->tm_min  = bcd2bin(t->tm_min);
+		t->tm_hour = bcd2bin(t->tm_hour);
+		t->tm_mday = bcd2bin(t->tm_mday);
+		t->tm_mon  = bcd2bin(t->tm_mon);
+		t->tm_year = bcd2bin(t->tm_year);
+	}
+
+	if (_12h_mode) {
+		/* Convert to 24h mode */
+		if (pm_mode) {
+			if (t->tm_hour < 12)
+				t->tm_hour += 12;
+		} else if (t->tm_hour == 12)
+			t->tm_hour = 0;
+	}
+
+	/* Count the months starting from 0, not from 1 */
+	t->tm_mon--;
+
+	if (t->tm_year < 100) {
+		/* tm_year is the number of years since 1900 but the
+		 * RTC epoch is 2000.
+		 */
+		t->tm_year += 100;
+	}
+
+	fibril_mutex_unlock(&rtc->mutex);
+
+	/* Try to normalize the content of the tm structure */
+	time_t r = mktime(t);
+
+	boottime = r - uptime_get();
+
+	return r < 0 ? EINVAL : EOK;
+}
+
+/** Set the time in the RTC
+ *
+ * @param fun  The RTC function
+ * @param t    The time value to set
+ *
+ * @return  EOK or a negative error code
+ */
+static int
+rtc_time_set(ddf_fun_t *fun, struct tm *t)
+{
+	bool bcd_mode;
+	time_t norm_time;
+	time_t uptime;
+	int  reg_b;
+	int  reg_a;
+	int  epoch;
+	rtc_t *rtc = RTC_FROM_FNODE(fun);
+
+	/* Try to normalize the content of the tm structure */
+	if ((norm_time = mktime(t)) < 0)
+		return EINVAL;
+
+	uptime = uptime_get();
+	if (norm_time <= uptime) {
+		/* This is not acceptable */
+		return EINVAL;
+	}
+
+	/* boottime must be recomputed */
+	boottime = 0;
+
+	fibril_mutex_lock(&rtc->mutex);
+
+	/* Detect the RTC epoch */
+	if (rtc_register_read(rtc, RTC_YEAR) < 100)
+		epoch = 2000;
+	else
+		epoch = 1900;
+
+	if (epoch == 2000 && t->tm_year < 100) {
+		/* Can't set a year before the epoch */
+		fibril_mutex_unlock(&rtc->mutex);
+		return EINVAL;
+	}
+
+	t->tm_mon++; /* counts from 1, not from 0 */
+
+	reg_b = rtc_register_read(rtc, RTC_STATUS_B);
+
+	if (!(reg_b & RTC_B_24H)) {
+		/* Force 24h mode of operation */
+		reg_b |= RTC_B_24H;
+		rtc_register_write(rtc, RTC_STATUS_B, reg_b);
+	}
+
+	if (epoch == 2000) {
+		/* The RTC epoch is year 2000  but the tm_year
+		 * field counts years since 1900.
+		 */
+		t->tm_year -= 100;
+	}
+
+	/* Check if the rtc is working in bcd mode */
+	bcd_mode = !(reg_b & RTC_B_BCD);
+	if (bcd_mode) {
+		/* Convert the tm struct fields in BCD mode */
+		t->tm_sec  = bin2bcd(t->tm_sec);
+		t->tm_min  = bin2bcd(t->tm_min);
+		t->tm_hour = bin2bcd(t->tm_hour);
+		t->tm_mday = bin2bcd(t->tm_mday);
+		t->tm_mon  = bin2bcd(t->tm_mon);
+		t->tm_year = bin2bcd(t->tm_year);
+	}
+
+	/* Inhibit updates */
+	rtc_register_write(rtc, RTC_STATUS_B, reg_b | RTC_B_INH);
+
+	/* Write current time to RTC */
+	rtc_register_write(rtc, RTC_SEC, t->tm_sec);
+	rtc_register_write(rtc, RTC_MIN, t->tm_min);
+	rtc_register_write(rtc, RTC_HOUR, t->tm_hour);
+	rtc_register_write(rtc, RTC_DAY, t->tm_mday);
+	rtc_register_write(rtc, RTC_MON, t->tm_mon);
+	rtc_register_write(rtc, RTC_YEAR, t->tm_year);
+
+	/* Stop the clock */
+	reg_a = rtc_register_read(rtc, RTC_STATUS_A);
+	rtc_register_write(rtc, RTC_STATUS_A, RTC_A_CLK_STOP | reg_a);
+	
+	/* Enable updates */
+	rtc_register_write(rtc, RTC_STATUS_B, reg_b);
+	rtc_register_write(rtc, RTC_STATUS_A, reg_a);
+
+	fibril_mutex_unlock(&rtc->mutex);
+
+	return EOK;
+}
+
+/** The dev_add callback of the rtc driver
+ *
+ * @param dev  The RTC device
+ *
+ * @return  EOK on success or a negative error code
+ */
+static int
+rtc_dev_add(ddf_dev_t *dev)
+{
+	rtc_t *rtc;
+	ddf_fun_t *fun = NULL;
+	int rc;
+	bool need_cleanup = false;
+
+	ddf_msg(LVL_DEBUG, "rtc_dev_add %s (handle = %d)",
+	    dev->name, (int) dev->handle);
+
+	rtc = ddf_dev_data_alloc(dev, sizeof(rtc_t));
+	if (!rtc)
+		return ENOMEM;
+
+	rtc->dev = dev;
+	fibril_mutex_initialize(&rtc->mutex);
+
+	rc = rtc_dev_initialize(rtc);
+	if (rc != EOK)
+		goto error;
+
+	need_cleanup = true;
+
+	if (!rtc_pio_enable(rtc)) {
+		rc = EADDRNOTAVAIL;
+		goto error;
+	}
+
+	fun = ddf_fun_create(dev, fun_exposed, "a");
+	if (!fun) {
+		ddf_msg(LVL_ERROR, "Failed creating function");
+		rc = ENOENT;
+		goto error;
+	}
+
+	fun->ops = &rtc_dev_ops;
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding function");
+		goto error;
+	}
+
+	rtc->fun = fun;
+
+	ddf_fun_add_to_category(fun, "clock");
+
+	ddf_msg(LVL_NOTE, "Device %s successfully initialized",
+	    dev->name);
+
+	return rc;
+
+error:
+	if (fun)
+		ddf_fun_destroy(fun);
+	if (need_cleanup)
+		rtc_dev_cleanup(rtc);
+	return rc;
+}
+
+/** The dev_remove callback for the rtc driver
+ *
+ * @param dev   The RTC device
+ *
+ * @return      EOK on success or a negative error code
+ */
+static int
+rtc_dev_remove(ddf_dev_t *dev)
+{
+	rtc_t *rtc = RTC_FROM_DEV(dev);
+	int rc;
+
+	fibril_mutex_lock(&rtc->mutex);
+
+	rtc->removed = true;
+	fibril_mutex_unlock(&rtc->mutex);
+
+	rc = ddf_fun_unbind(rtc->fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to unbind function");
+		return rc;
+	}
+
+	ddf_fun_destroy(rtc->fun);
+	rtc_dev_cleanup(rtc);
+
+	return rc;
+}
+
+/** Default handler for client requests not handled
+ *  by the standard interface
+ */
+static void
+rtc_default_handler(ddf_fun_t *fun, ipc_callid_t callid, ipc_call_t *call)
+{
+	sysarg_t method = IPC_GET_IMETHOD(*call);
+	rtc_t *rtc = RTC_FROM_FNODE(fun);
+	bool batt_ok;
+
+	switch (method) {
+	case CLOCK_GET_BATTERY_STATUS:
+		/* Get the RTC battery status */
+		batt_ok = rtc_register_read(rtc, RTC_STATUS_D) &
+		    RTC_D_BATTERY_OK;
+		async_answer_1(callid, EOK, batt_ok);
+		break;
+	default:
+		async_answer_0(callid, ENOTSUP);
+	}
+}
+
+/** Open the device
+ *
+ * @param fun   The function node
+ *
+ * @return  EOK on success or a negative error code
+ */
+static int
+rtc_open(ddf_fun_t *fun)
+{
+	int rc;
+	rtc_t *rtc = RTC_FROM_FNODE(fun);
+
+	fibril_mutex_lock(&rtc->mutex);
+
+	if (rtc->removed)
+		rc = ENXIO;
+	else
+		rc = EOK;
+
+	fibril_mutex_unlock(&rtc->mutex);
+	return rc;
+}
+
+/** Close the device
+ *
+ * @param fun  The function node
+ */
+static void
+rtc_close(ddf_fun_t *fun)
+{
+}
+
+/** Convert from BCD mode to binary mode
+ *
+ * @param bcd   The number in BCD format to convert
+ *
+ * @return      The converted value
+ */
+static unsigned 
+bcd2bin(unsigned bcd)
+{
+	return ((bcd & 0xF0) >> 1) + ((bcd & 0xF0) >> 3) + (bcd & 0xf);
+}
+
+/** Convert from binary mode to BCD mode
+ *
+ * @param bcd   The number in binary mode to convert
+ *
+ * @return      The converted value
+ */
+static unsigned
+bin2bcd(unsigned binary)
+{
+	return ((binary / 10) << 4) + (binary % 10);
+}
+
+static time_t
+uptime_get(void)
+{
+	struct timeval tv;
+
+	getuptime(&tv);
+
+	return tv.tv_sec;
+}
+
+int
+main(int argc, char **argv)
+{
+	printf(NAME ": HelenOS RTC driver\n");
+	rtc_init();
+	return ddf_driver_main(&rtc_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/time/cmos-rtc/cmos-rtc.ma
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-rtc.ma	(revision 2568c94738140fd4f5f3170b8368fb126a30b7e2)
+++ uspace/drv/time/cmos-rtc/cmos-rtc.ma	(revision 2568c94738140fd4f5f3170b8368fb126a30b7e2)
@@ -0,0 +1,1 @@
+100 isa/cmos-rtc
