Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision a416d070e73ee834d63f21236a755f5a56114201)
+++ uspace/drv/bus/isa/isa.c	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -453,4 +453,27 @@
 }
 
+static void isa_fun_add_mem_range(isa_fun_t *fun, uintptr_t addr, size_t len)
+{
+	size_t count = fun->hw_resources.count;
+	hw_resource_t *resources = fun->hw_resources.resources;
+
+	isa_bus_t *isa = isa_bus(ddf_fun_get_dev(fun->fnode));
+
+	if (count < ISA_MAX_HW_RES) {
+		resources[count].type = MEM_RANGE;
+		resources[count].res.mem_range.address = addr;
+		resources[count].res.mem_range.address += isa->pio_win.mem.base;
+		resources[count].res.mem_range.size = len;
+		resources[count].res.mem_range.relative = true;
+		resources[count].res.mem_range.endianness = LITTLE_ENDIAN;
+
+		fun->hw_resources.count++;
+
+		ddf_msg(LVL_NOTE, "Added mem range (addr=0x%zx, size=0x%x) to "
+		    "function %s", (uintptr_t) addr, (unsigned int) len,
+		    ddf_fun_get_name(fun->fnode));
+	}
+}
+
 static void fun_parse_irq(isa_fun_t *fun, const char *val)
 {
@@ -496,4 +519,25 @@
 }
 
+static void fun_parse_mem_range(isa_fun_t *fun, const char *val)
+{
+	uintptr_t addr;
+	size_t len;
+	char *end = NULL;
+
+	val = skip_spaces(val);
+	addr = strtoul(val, &end, 0x10);
+
+	if (val == end)
+		return;
+
+	val = skip_spaces(end);
+	len = strtol(val, &end, 0x10);
+
+	if (val == end)
+		return;
+
+	isa_fun_add_mem_range(fun, addr, len);
+}
+
 static void get_match_id(char **id, const char *val)
 {
@@ -564,4 +608,5 @@
 
 	if (!prop_parse(fun, line, "io_range", &fun_parse_io_range) &&
+	    !prop_parse(fun, line, "mem_range", &fun_parse_mem_range) &&
 	    !prop_parse(fun, line, "irq", &fun_parse_irq) &&
 	    !prop_parse(fun, line, "dma", &fun_parse_dma) &&
Index: uspace/drv/bus/isa/isa.dev
===================================================================
--- uspace/drv/bus/isa/isa.dev	(revision a416d070e73ee834d63f21236a755f5a56114201)
+++ uspace/drv/bus/isa/isa.dev	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -1,2 +1,10 @@
+i8259:
+	match 100 isa/i8259
+	mem_range 0x20 2
+	mem_range 0xa0 2
+
+apic:
+	match 100 isa/apic
+	mem_range 0xfec00000 0x14
 com1:
 	match 100 isa/ns8250
Index: uspace/drv/intctl/apic/Makefile
===================================================================
--- uspace/drv/intctl/apic/Makefile	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
+++ uspace/drv/intctl/apic/Makefile	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2011 Martin Decky
+# 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 = apic
+
+SOURCES = \
+	apic.c \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/intctl/apic/apic.c
===================================================================
--- uspace/drv/intctl/apic/apic.c	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
+++ uspace/drv/intctl/apic/apic.c	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * 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 apic
+ * @{
+ */
+
+/**
+ * @file apic.c
+ * @brief APIC driver.
+ */
+
+#include <ipc/irc.h>
+#include <loc.h>
+#include <sysinfo.h>
+#include <as.h>
+#include <ddf/driver.h>
+#include <ddf/log.h>
+#include <ddi.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <async.h>
+#include <stdio.h>
+
+#include "apic.h"
+
+#define NAME  "apic"
+
+#define APIC_MAX_IRQ	15
+
+#define IOREGSEL  (0x00U / sizeof(uint32_t))
+#define IOWIN     (0x10U / sizeof(uint32_t))
+
+#define IOREDTBL   0x10U
+
+/** I/O Register Select Register. */
+typedef union {
+	uint32_t value;
+	struct {
+		uint8_t reg_addr;	/**< APIC Register Address. */
+		unsigned int : 24;	/**< Reserved. */
+	} __attribute__ ((packed));
+} io_regsel_t;
+
+/** I/O Redirection Register. */
+typedef struct io_redirection_reg {
+	union {
+		uint32_t lo;
+		struct {
+			uint8_t intvec;			/**< Interrupt Vector. */
+			unsigned int delmod : 3;	/**< Delivery Mode. */
+			unsigned int destmod : 1;	/**< Destination mode. */
+			unsigned int delivs : 1;	/**< Delivery status (RO). */
+			unsigned int intpol : 1;	/**< Interrupt Input Pin Polarity. */
+			unsigned int irr : 1;		/**< Remote IRR (RO). */
+			unsigned int trigger_mode : 1;	/**< Trigger Mode. */
+			unsigned int masked : 1;	/**< Interrupt Mask. */
+			unsigned int : 15;		/**< Reserved. */
+		} __attribute__ ((packed));
+	};
+	union {
+		uint32_t hi;
+		struct {
+			unsigned int : 24;	/**< Reserved. */
+			uint8_t dest : 8;  	/**< Destination Field. */
+		} __attribute__ ((packed));
+	};
+} __attribute__ ((packed)) io_redirection_reg_t;
+
+#define IO_APIC_SIZE	20
+
+/** Read from IO APIC register.
+ *
+ * @param apic APIC
+ * @param address IO APIC register address.
+ *
+ * @return Content of the addressed IO APIC register.
+ *
+ */
+static uint32_t io_apic_read(apic_t *apic, uint8_t address)
+{
+	io_regsel_t regsel;
+
+	regsel.value = pio_read_32(&apic->regs[IOREGSEL]);
+	regsel.reg_addr = address;
+	pio_write_32(&apic->regs[IOREGSEL], regsel.value);
+	return pio_read_32(&apic->regs[IOWIN]);
+}
+
+/** Write to IO APIC register.
+ *
+ * @param apic    APIC
+ * @param address IO APIC register address.
+ * @param val     Content to be written to the addressed IO APIC register.
+ *
+ */
+static void io_apic_write(apic_t *apic, uint8_t address, uint32_t val)
+{
+	io_regsel_t regsel;
+
+	regsel.value = pio_read_32(&apic->regs[IOREGSEL]);
+	regsel.reg_addr = address;
+	pio_write_32(&apic->regs[IOREGSEL], regsel.value);
+	pio_write_32(&apic->regs[IOWIN], val);
+}
+
+static int irq_to_pin(int irq)
+{
+	// FIXME: get the map from the kernel, even though this may work
+	//	  for simple cases
+	if (irq == 0)
+		return 2;
+	return irq;
+}
+
+static int apic_enable_irq(apic_t *apic, sysarg_t irq)
+{
+	io_redirection_reg_t reg;
+
+	if (irq > APIC_MAX_IRQ)
+		return ELIMIT;
+
+	int pin = irq_to_pin(irq);
+ 	if (pin == -1)
+		return ENOENT;
+
+	reg.lo = io_apic_read(apic, (uint8_t) (IOREDTBL + pin * 2));
+	reg.masked = false;
+	io_apic_write(apic, (uint8_t) (IOREDTBL + pin * 2), reg.lo);
+
+	return EOK;
+}
+
+/** Handle one connection to APIC.
+ *
+ * @param iid   Hash of the request that opened the connection.
+ * @param icall Call data of the request that opened the connection.
+ * @param arg	Local argument.
+ */
+static void apic_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	ipc_callid_t callid;
+	ipc_call_t call;
+	apic_t *apic;
+	
+	/*
+	 * Answer the first IPC_M_CONNECT_ME_TO call.
+	 */
+	async_answer_0(iid, EOK);
+	
+	apic = (apic_t *)ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *)arg));
+	
+	while (true) {
+		callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call)) {
+			/* The other side has hung up. */
+			async_answer_0(callid, EOK);
+			return;
+		}
+		
+		switch (IPC_GET_IMETHOD(call)) {
+		case IRC_ENABLE_INTERRUPT:
+			async_answer_0(callid, apic_enable_irq(apic,
+			    IPC_GET_ARG1(call)));
+			break;
+		case IRC_DISABLE_INTERRUPT:
+			/* XXX TODO */
+			async_answer_0(callid, EOK);
+			break;
+		case IRC_CLEAR_INTERRUPT:
+			/* Noop */
+			async_answer_0(callid, EOK);
+			break;
+		default:
+			async_answer_0(callid, EINVAL);
+			break;
+		}
+	}
+}
+
+/** Add APIC device. */
+int apic_add(apic_t *apic, apic_res_t *res)
+{
+	sysarg_t have_apic;
+	ddf_fun_t *fun_a = NULL;
+	void *regs;
+	int rc;
+	
+	if ((sysinfo_get_value("apic", &have_apic) != EOK) || (!have_apic)) {
+		printf("%s: No APIC found\n", NAME);
+		return ENOTSUP;
+	}
+	
+	rc = pio_enable((void *) res->base, IO_APIC_SIZE, &regs);
+	if (rc != EOK) {
+		printf("%s: Failed to enable PIO for APIC: %d\n", NAME, rc);
+		return EIO;
+	}
+
+	apic->regs = (ioport32_t *)regs;
+
+	fun_a = ddf_fun_create(apic->dev, fun_exposed, "a");
+	if (fun_a == NULL) {
+		ddf_msg(LVL_ERROR, "Failed creating function 'a'.");
+		rc = ENOMEM;
+		goto error;
+	}
+
+	ddf_fun_set_conn_handler(fun_a, apic_connection);
+
+	rc = ddf_fun_bind(fun_a);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding function 'a'. (%d)", rc);
+		goto error;
+	}
+
+	rc = ddf_fun_add_to_category(fun_a, "irc");
+	if (rc != EOK)
+		goto error;
+
+	return EOK;
+error:
+	if (fun_a != NULL)
+		ddf_fun_destroy(fun_a);
+	return rc;
+}
+
+/** Remove APIC device */
+int apic_remove(apic_t *apic)
+{
+	return ENOTSUP;
+}
+
+/** APIC device gone */
+int apic_gone(apic_t *apic)
+{
+	return ENOTSUP;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/intctl/apic/apic.h
===================================================================
--- uspace/drv/intctl/apic/apic.h	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
+++ uspace/drv/intctl/apic/apic.h	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017 Jiri Svoboda
+ * 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 genarch
+ * @{
+ */
+/** @file
+ */
+
+#ifndef ICP_IC_H_
+#define ICP_IC_H
+
+#include <ddf/driver.h>
+#include <ddi.h>
+#include <loc.h>
+#include <stdint.h>
+
+typedef struct {
+	uintptr_t base;
+} apic_res_t;
+
+/** APIC */
+typedef struct {
+	ioport32_t *regs;
+	uintptr_t phys_base;
+	ddf_dev_t *dev;
+} apic_t;
+
+extern int apic_add(apic_t *, apic_res_t *);
+extern int apic_remove(apic_t *);
+extern int apic_gone(apic_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/drv/intctl/apic/apic.ma
===================================================================
--- uspace/drv/intctl/apic/apic.ma	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
+++ uspace/drv/intctl/apic/apic.ma	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -0,0 +1,1 @@
+10 isa/apic
Index: uspace/drv/intctl/apic/main.c
===================================================================
--- uspace/drv/intctl/apic/main.c	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
+++ uspace/drv/intctl/apic/main.c	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017 Jiri Svoboda
+ * 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 genarch
+ * @{
+ */
+/** @file APIC driver
+ */
+
+#include <ddf/driver.h>
+#include <ddf/log.h>
+#include <device/hw_res_parsed.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "apic.h"
+
+#define NAME  "apic"
+
+static int apic_dev_add(ddf_dev_t *dev);
+static int apic_dev_remove(ddf_dev_t *dev);
+static int apic_dev_gone(ddf_dev_t *dev);
+static int apic_fun_online(ddf_fun_t *fun);
+static int apic_fun_offline(ddf_fun_t *fun);
+
+static driver_ops_t driver_ops = {
+	.dev_add = apic_dev_add,
+	.dev_remove = apic_dev_remove,
+	.dev_gone = apic_dev_gone,
+	.fun_online = apic_fun_online,
+	.fun_offline = apic_fun_offline
+};
+
+static driver_t apic_driver = {
+	.name = NAME,
+	.driver_ops = &driver_ops
+};
+
+static int apic_get_res(ddf_dev_t *dev, apic_res_t *res)
+{
+	async_sess_t *parent_sess;
+	hw_res_list_parsed_t hw_res;
+	int rc;
+
+	parent_sess = ddf_dev_parent_sess_get(dev);
+	if (parent_sess == NULL)
+		return ENOMEM;
+
+	hw_res_list_parsed_init(&hw_res);
+	rc = hw_res_get_list_parsed(parent_sess, &hw_res, 0);
+	if (rc != EOK)
+		return rc;
+
+	if (hw_res.mem_ranges.count != 1) {
+		rc = EINVAL;
+		goto error;
+	}
+
+	res->base = RNGABS(hw_res.mem_ranges.ranges[0]);
+
+	return EOK;
+error:
+	hw_res_list_parsed_clean(&hw_res);
+	return rc;
+}
+
+static int apic_dev_add(ddf_dev_t *dev)
+{
+	apic_t *apic;
+	apic_res_t apic_res;
+	int rc;
+
+        ddf_msg(LVL_DEBUG, "apic_dev_add(%p)", dev);
+	apic = ddf_dev_data_alloc(dev, sizeof(apic_t));
+	if (apic == NULL) {
+		ddf_msg(LVL_ERROR, "Failed allocating soft state.");
+		return ENOMEM;
+	}
+
+	apic->dev = dev;
+
+	rc = apic_get_res(dev, &apic_res);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed getting hardware resource list.\n");
+		return EIO;
+	}
+
+	return apic_add(apic, &apic_res);
+}
+
+static int apic_dev_remove(ddf_dev_t *dev)
+{
+        apic_t *apic = (apic_t *)ddf_dev_data_get(dev);
+
+        ddf_msg(LVL_DEBUG, "apic_dev_remove(%p)", dev);
+
+        return apic_remove(apic);
+}
+
+static int apic_dev_gone(ddf_dev_t *dev)
+{
+        apic_t *apic = (apic_t *)ddf_dev_data_get(dev);
+
+        ddf_msg(LVL_DEBUG, "apic_dev_gone(%p)", dev);
+
+        return apic_gone(apic);
+}
+
+static int apic_fun_online(ddf_fun_t *fun)
+{
+        ddf_msg(LVL_DEBUG, "apic_fun_online()");
+        return ddf_fun_online(fun);
+}
+
+static int apic_fun_offline(ddf_fun_t *fun)
+{
+        ddf_msg(LVL_DEBUG, "apic_fun_offline()");
+        return ddf_fun_offline(fun);
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": APIC driver\n");
+	ddf_log_init(NAME);
+	return ddf_driver_main(&apic_driver);
+}
+
+/** @}
+ */
Index: uspace/drv/intctl/i8259/Makefile
===================================================================
--- uspace/drv/intctl/i8259/Makefile	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
+++ uspace/drv/intctl/i8259/Makefile	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2011 Martin Decky
+# 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 = i8259
+
+SOURCES = \
+	i8259.c \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/intctl/i8259/i8259.c
===================================================================
--- uspace/drv/intctl/i8259/i8259.c	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
+++ uspace/drv/intctl/i8259/i8259.c	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * 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 i8259
+ * @{
+ */
+
+/**
+ * @file i8259.c
+ * @brief i8259 driver.
+ */
+
+#include <ipc/irc.h>
+#include <loc.h>
+#include <sysinfo.h>
+#include <as.h>
+#include <ddf/log.h>
+#include <ddi.h>
+#include <align.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <async.h>
+#include <stdio.h>
+
+#include "i8259.h"
+
+#define NAME  "i8259"
+
+#define IO_RANGE0_SIZE   2
+#define IO_RANGE1_SIZE   2
+
+#define PIC_PIC0PORT1  0
+#define PIC_PIC0PORT2  1
+
+#define PIC_PIC1PORT1  0
+#define PIC_PIC1PORT2  1
+
+#define PIC_MAX_IRQ  15
+
+static int pic_enable_irq(i8259_t *i8259, sysarg_t irq)
+{
+	if (irq > PIC_MAX_IRQ)
+		return ENOENT;
+	
+	uint16_t irqmask = 1 << irq;
+	uint8_t val;
+	
+	if (irqmask & 0xff) {
+		val = pio_read_8(i8259->regs0 + PIC_PIC0PORT2);
+		pio_write_8(i8259->regs0 + PIC_PIC0PORT2,
+		    (uint8_t) (val & (~(irqmask & 0xff))));
+	}
+	
+	if (irqmask >> 8) {
+		val = pio_read_8(i8259->regs1 + PIC_PIC1PORT2);
+		pio_write_8(i8259->regs1 + PIC_PIC1PORT2,
+		    (uint8_t) (val & (~(irqmask >> 8))));
+	}
+	
+	return EOK;
+}
+
+/** Handle one connection to i8259.
+ *
+ * @param iid   Hash of the request that opened the connection.
+ * @param icall Call data of the request that opened the connection.
+ * @param arg	Local argument.
+ */
+static void i8259_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	ipc_callid_t callid;
+	ipc_call_t call;
+	i8259_t *i8259 = NULL /* XXX */;
+	
+	/*
+	 * Answer the first IPC_M_CONNECT_ME_TO call.
+	 */
+	async_answer_0(iid, EOK);
+	
+	i8259 = (i8259_t *)ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *)arg));
+	
+	while (true) {
+		callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call)) {
+			/* The other side has hung up. */
+			async_answer_0(callid, EOK);
+			return;
+		}
+		
+		switch (IPC_GET_IMETHOD(call)) {
+		case IRC_ENABLE_INTERRUPT:
+			async_answer_0(callid, pic_enable_irq(i8259,
+			    IPC_GET_ARG1(call)));
+			break;
+		case IRC_DISABLE_INTERRUPT:
+			/* XXX TODO */
+			async_answer_0(callid, EOK);
+			break;
+		case IRC_CLEAR_INTERRUPT:
+			/* Noop */
+			async_answer_0(callid, EOK);
+			break;
+		default:
+			async_answer_0(callid, EINVAL);
+			break;
+		}
+	}
+}
+
+/** Add i8259 device. */
+int i8259_add(i8259_t *i8259, i8259_res_t *res)
+{
+	sysarg_t have_i8259;
+	ioport8_t *regs0;
+	ioport8_t *regs1;
+	ddf_fun_t *fun_a = NULL;
+	int rc;
+	
+	if ((sysinfo_get_value("i8259", &have_i8259) != EOK) || (!have_i8259)) {
+		printf("%s: No i8259 found\n", NAME);
+		return ENOTSUP;
+	}
+	
+	if ((pio_enable((void *) res->base0, IO_RANGE0_SIZE,
+	    (void **) &regs0) != EOK) ||
+	    (pio_enable((void *) res->base1, IO_RANGE1_SIZE,
+	    (void **) &regs1) != EOK)) {
+		printf("%s: i8259 not accessible\n", NAME);
+		return EIO;
+	}
+	
+	i8259->regs0 = regs0;
+	i8259->regs1 = regs1;
+	
+	fun_a = ddf_fun_create(i8259->dev, fun_exposed, "a");
+	if (fun_a == NULL) {
+		ddf_msg(LVL_ERROR, "Failed creating function 'a'.");
+		rc = ENOMEM;
+		goto error;
+	}
+	
+	ddf_fun_set_conn_handler(fun_a, i8259_connection);
+	
+	rc = ddf_fun_bind(fun_a);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding function 'a'. (%d)", rc);
+		goto error;
+	}
+	
+	rc = ddf_fun_add_to_category(fun_a, "irc");
+	if (rc != EOK)
+		goto error;
+	
+	return EOK;
+error:
+	if (fun_a != NULL)
+		ddf_fun_destroy(fun_a);
+	return rc;
+}
+
+/** Remove i8259 device */
+int i8259_remove(i8259_t *i8259)
+{
+	return ENOTSUP;
+}
+
+/** i8259 device gone */
+int i8259_gone(i8259_t *i8259)
+{
+	return ENOTSUP;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/intctl/i8259/i8259.h
===================================================================
--- uspace/drv/intctl/i8259/i8259.h	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
+++ uspace/drv/intctl/i8259/i8259.h	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017 Jiri Svoboda
+ * 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 genarch
+ * @{
+ */
+/** @file
+ */
+
+#ifndef ICP_IC_H_
+#define ICP_IC_H
+
+#include <ddf/driver.h>
+#include <ddi.h>
+#include <stdint.h>
+
+typedef struct {
+	uintptr_t base0;
+	uintptr_t base1;
+} i8259_res_t;
+
+/** IntegratorCP Interrupt Controller */
+typedef struct {
+	ioport8_t *regs0;
+	ioport8_t *regs1;
+	ddf_dev_t *dev;
+} i8259_t;
+
+extern int i8259_add(i8259_t *, i8259_res_t *);
+extern int i8259_remove(i8259_t *);
+extern int i8259_gone(i8259_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/drv/intctl/i8259/i8259.ma
===================================================================
--- uspace/drv/intctl/i8259/i8259.ma	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
+++ uspace/drv/intctl/i8259/i8259.ma	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -0,0 +1,1 @@
+10 isa/i8259
Index: uspace/drv/intctl/i8259/main.c
===================================================================
--- uspace/drv/intctl/i8259/main.c	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
+++ uspace/drv/intctl/i8259/main.c	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017 Jiri Svoboda
+ * 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 genarch
+ * @{
+ */
+/** @file i8259 Interrupt Controller driver
+ */
+
+#include <ddf/driver.h>
+#include <ddf/log.h>
+#include <device/hw_res_parsed.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "i8259.h"
+
+#define NAME  "i8259"
+
+static int i8259_dev_add(ddf_dev_t *dev);
+static int i8259_dev_remove(ddf_dev_t *dev);
+static int i8259_dev_gone(ddf_dev_t *dev);
+static int i8259_fun_online(ddf_fun_t *fun);
+static int i8259_fun_offline(ddf_fun_t *fun);
+
+static driver_ops_t driver_ops = {
+	.dev_add = i8259_dev_add,
+	.dev_remove = i8259_dev_remove,
+	.dev_gone = i8259_dev_gone,
+	.fun_online = i8259_fun_online,
+	.fun_offline = i8259_fun_offline
+};
+
+static driver_t i8259_driver = {
+	.name = NAME,
+	.driver_ops = &driver_ops
+};
+
+static int i8259_get_res(ddf_dev_t *dev, i8259_res_t *res)
+{
+	async_sess_t *parent_sess;
+	hw_res_list_parsed_t hw_res;
+	int rc;
+
+	parent_sess = ddf_dev_parent_sess_get(dev);
+	if (parent_sess == NULL)
+		return ENOMEM;
+
+	hw_res_list_parsed_init(&hw_res);
+	rc = hw_res_get_list_parsed(parent_sess, &hw_res, 0);
+	if (rc != EOK)
+		return rc;
+
+	if (hw_res.mem_ranges.count != 2) {
+		rc = EINVAL;
+		goto error;
+	}
+
+	res->base0 = RNGABS(hw_res.mem_ranges.ranges[0]);
+	res->base1 = RNGABS(hw_res.mem_ranges.ranges[1]);
+
+	return EOK;
+error:
+	hw_res_list_parsed_clean(&hw_res);
+	return rc;
+}
+
+static int i8259_dev_add(ddf_dev_t *dev)
+{
+	i8259_t *i8259;
+	i8259_res_t i8259_res;
+	int rc;
+
+        ddf_msg(LVL_DEBUG, "i8259_dev_add(%p)", dev);
+	i8259 = ddf_dev_data_alloc(dev, sizeof(i8259_t));
+	if (i8259 == NULL) {
+		ddf_msg(LVL_ERROR, "Failed allocating soft state.");
+		return ENOMEM;
+	}
+
+	i8259->dev = dev;
+
+	rc = i8259_get_res(dev, &i8259_res);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed getting hardware resource list.\n");
+		return EIO;
+	}
+
+	return i8259_add(i8259, &i8259_res);
+}
+
+static int i8259_dev_remove(ddf_dev_t *dev)
+{
+        i8259_t *i8259 = (i8259_t *)ddf_dev_data_get(dev);
+
+        ddf_msg(LVL_DEBUG, "i8259_dev_remove(%p)", dev);
+
+        return i8259_remove(i8259);
+}
+
+static int i8259_dev_gone(ddf_dev_t *dev)
+{
+        i8259_t *i8259 = (i8259_t *)ddf_dev_data_get(dev);
+
+        ddf_msg(LVL_DEBUG, "i8259_dev_gone(%p)", dev);
+
+        return i8259_gone(i8259);
+}
+
+static int i8259_fun_online(ddf_fun_t *fun)
+{
+        ddf_msg(LVL_DEBUG, "i8259_fun_online()");
+        return ddf_fun_online(fun);
+}
+
+static int i8259_fun_offline(ddf_fun_t *fun)
+{
+        ddf_msg(LVL_DEBUG, "i8259_fun_offline()");
+        return ddf_fun_offline(fun);
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": i8259 Interrupt Controller driver\n");
+	ddf_log_init(NAME);
+	return ddf_driver_main(&i8259_driver);
+}
+
+/** @}
+ */
Index: uspace/drv/intctl/icp-ic/icp-ic.c
===================================================================
--- uspace/drv/intctl/icp-ic/icp-ic.c	(revision a416d070e73ee834d63f21236a755f5a56114201)
+++ uspace/drv/intctl/icp-ic/icp-ic.c	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -42,5 +42,4 @@
 #include <errno.h>
 #include <ipc/irc.h>
-#include <loc.h>
 #include <stdint.h>
 
Index: uspace/drv/platform/icp/icp.c
===================================================================
--- uspace/drv/platform/icp/icp.c	(revision a416d070e73ee834d63f21236a755f5a56114201)
+++ uspace/drv/platform/icp/icp.c	(revision b446b02d16cef27e33c81855d516b2f1a5ce70b2)
@@ -279,12 +279,4 @@
 	int rc;
 
-	rc = icp_add_fun(dev, "kbd", "arm/pl050", &icp_kbd_fun_proto);
-	if (rc != EOK)
-		return rc;
-
-	rc = icp_add_fun(dev, "mouse", "arm/pl050", &icp_mouse_fun_proto);
-	if (rc != EOK)
-		return rc;
-
 	rc = icp_add_fun(dev, "intctl", "integratorcp/intctl",
 	    &icp_ic_fun_proto);
@@ -292,4 +284,12 @@
 		return rc;
 
+	rc = icp_add_fun(dev, "kbd", "arm/pl050", &icp_kbd_fun_proto);
+	if (rc != EOK)
+		return rc;
+
+	rc = icp_add_fun(dev, "mouse", "arm/pl050", &icp_mouse_fun_proto);
+	if (rc != EOK)
+		return rc;
+
 	return EOK;
 }
