Index: Makefile
===================================================================
--- Makefile	(revision 281224aeb3d8da7b9f59d258df830ad80784c70c)
+++ Makefile	(revision 162f9196160de579344bdc123782df70adf3940f)
@@ -157,4 +157,5 @@
 	generic/src/ipc/sysipc.c \
 	generic/src/ipc/ipcrsc.c \
+	generic/src/ipc/irq.c \
 	generic/src/security/cap.c
 
Index: arch/amd64/src/interrupt.c
===================================================================
--- arch/amd64/src/interrupt.c	(revision 281224aeb3d8da7b9f59d258df830ad80784c70c)
+++ arch/amd64/src/interrupt.c	(revision 162f9196160de579344bdc123782df70adf3940f)
@@ -46,5 +46,5 @@
 #include <arch/ddi/ddi.h>
 #include <interrupt.h>
-#include <ipc/sysipc.h>
+#include <ipc/irq.h>
 
 void print_info_errcode(int n, istate_t *istate)
Index: generic/include/errno.h
===================================================================
--- generic/include/errno.h	(revision 281224aeb3d8da7b9f59d258df830ad80784c70c)
+++ generic/include/errno.h	(revision 162f9196160de579344bdc123782df70adf3940f)
@@ -42,4 +42,5 @@
 			* to close the connection.  */
 #define EEXISTS    -8  /* Entry already exists */
+#define EBADMEM    -9  /* Bad memory pointer */
 
 #endif
Index: generic/include/ipc/ipc.h
===================================================================
--- generic/include/ipc/ipc.h	(revision 281224aeb3d8da7b9f59d258df830ad80784c70c)
+++ generic/include/ipc/ipc.h	(revision 162f9196160de579344bdc123782df70adf3940f)
@@ -211,8 +211,4 @@
 extern void ipc_backsend_err(phone_t *phone, call_t *call, __native err);
 
-extern int ipc_irq_register(answerbox_t *box, int irq);
-extern void ipc_irq_send_notif(int irq);
-extern void ipc_irq_unregister(answerbox_t *box, int irq);
-
 
 extern answerbox_t *ipc_phone_0;
Index: generic/include/ipc/irq.h
===================================================================
--- generic/include/ipc/irq.h	(revision 162f9196160de579344bdc123782df70adf3940f)
+++ generic/include/ipc/irq.h	(revision 162f9196160de579344bdc123782df70adf3940f)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2006 Ondrej Palkovsky
+ * 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 __IRQ_H__
+#define __IRQ_H__
+
+#define IRQ_MAX_PROG_SIZE 10
+
+typedef enum {
+	CMD_MEM_READ_1 = 0,
+	CMD_MEM_READ_2,
+	CMD_MEM_READ_4,
+	CMD_MEM_READ_8,
+	CMD_MEM_WRITE_1,
+	CMD_MEM_WRITE_2,
+	CMD_MEM_WRITE_4,
+	CMD_MEM_WRITE_8,
+	CMD_LAST
+} irq_cmd_type;
+
+typedef struct {
+	irq_cmd_type cmd;
+	void *addr;
+	unsigned long long value; 
+} irq_cmd_t;
+
+typedef struct {
+	unsigned int cmdcount;
+	irq_cmd_t *cmds;
+} irq_code_t;
+
+#ifdef KERNEL
+
+extern void ipc_irq_make_table(int irqcount);
+extern int ipc_irq_register(answerbox_t *box, int irq, irq_code_t *ucode);
+extern void ipc_irq_send_notif(int irq);
+extern void ipc_irq_unregister(answerbox_t *box, int irq);
+extern void irq_ipc_bind_arch(__native irq);
+extern void ipc_irq_cleanup(answerbox_t *box);
+
+#endif
+
+#endif
Index: generic/include/ipc/sysipc.h
===================================================================
--- generic/include/ipc/sysipc.h	(revision 281224aeb3d8da7b9f59d258df830ad80784c70c)
+++ generic/include/ipc/sysipc.h	(revision 162f9196160de579344bdc123782df70adf3940f)
@@ -31,4 +31,5 @@
 
 #include <ipc/ipc.h>
+#include <ipc/irq.h>
 
 __native sys_ipc_call_sync_fast(__native phoneid, __native method, 
@@ -46,8 +47,6 @@
 			      __native method, __native arg1);
 __native sys_ipc_hangup(int phoneid);
-__native sys_ipc_register_irq(__native irq);
+__native sys_ipc_register_irq(__native irq, irq_code_t *ucode);
 __native sys_ipc_unregister_irq(__native irq);
 
-void irq_ipc_bind_arch(__native irq);
-
 #endif
Index: generic/src/ipc/ipc.c
===================================================================
--- generic/src/ipc/ipc.c	(revision 281224aeb3d8da7b9f59d258df830ad80784c70c)
+++ generic/src/ipc/ipc.c	(revision 162f9196160de579344bdc123782df70adf3940f)
@@ -45,4 +45,5 @@
 #include <proc/thread.h>
 #include <arch/interrupt.h>
+#include <ipc/irq.h>
 
 /* Open channel that is assigned automatically to new tasks */
@@ -50,12 +51,4 @@
 
 static slab_cache_t *ipc_call_slab;
-
-typedef struct {
-	SPINLOCK_DECLARE(lock);
-	answerbox_t *box;
-} ipc_irq_t;
-
-static ipc_irq_t *irq_conns = NULL;
-static int irq_conns_size;
 
 /* Initialize new call */
@@ -329,5 +322,5 @@
 		spinlock_lock(&box->irq_lock);
 
-		request = list_get_instance(box->answers.next, call_t, list);
+		request = list_get_instance(box->irq_notifs.next, call_t, list);
 		list_remove(&request->list);
 
@@ -371,24 +364,4 @@
 }
 
-/** Disconnect all irq's notifications
- *
- * TODO: It may be better to do some linked list, so that
- *       we wouldn't need to go through whole array every cleanup
- */
-static void ipc_irq_cleanup(answerbox_t *box)
-{
-	int i;
-	ipl_t ipl;
-	
-	for (i=0; i < irq_conns_size; i++) {
-		ipl = interrupts_disable();
-		spinlock_lock(&irq_conns[i].lock);
-		if (irq_conns[i].box == box)
-			irq_conns[i].box = NULL;
-		spinlock_unlock(&irq_conns[i].lock);
-		interrupts_restore(ipl);
-	}
-}
-
 /** Cleans up all IPC communication of the given task
  *
@@ -444,78 +417,4 @@
 }
 
-/** Initialize table of interrupt handlers */
-static void ipc_irq_make_table(int irqcount)
-{
-	int i;
-
-	irq_conns_size = irqcount;
-	irq_conns = malloc(irqcount * (sizeof(*irq_conns)), 0);
-	for (i=0; i < irqcount; i++) {
-		spinlock_initialize(&irq_conns[i].lock, "irq_ipc_lock");
-		irq_conns[i].box = NULL;
-	}
-}
-
-void ipc_irq_unregister(answerbox_t *box, int irq)
-{
-	ipl_t ipl;
-
-	ipl = interrupts_disable();
-	spinlock_lock(&irq_conns[irq].lock);
-	if (irq_conns[irq].box == box)
-		irq_conns[irq].box = NULL;
-
-	spinlock_unlock(&irq_conns[irq].lock);
-	interrupts_restore(ipl);
-}
-
-/** Register an answerbox as a receiving end of interrupts notifications */
-int ipc_irq_register(answerbox_t *box, int irq)
-{
-	ipl_t ipl;
-
-	ASSERT(irq_conns);
-
-	ipl = interrupts_disable();
-	spinlock_lock(&irq_conns[irq].lock);
-
-	if (irq_conns[irq].box) {
-		spinlock_unlock(&irq_conns[irq].lock);
-		interrupts_restore(ipl);
-		return EEXISTS;
-	}
-	irq_conns[irq].box = box;
-	spinlock_unlock(&irq_conns[irq].lock);
-	interrupts_restore(ipl);
-
-	return 0;
-}
-
-/** Notify process that an irq had happend
- *
- * We expect interrupts to be disabled
- */
-void ipc_irq_send_notif(int irq)
-{
-	call_t *call;
-
-	ASSERT(irq_conns);
-	spinlock_lock(&irq_conns[irq].lock);
-
-	if (irq_conns[irq].box) {
-		call = ipc_call_alloc(FRAME_ATOMIC);
-		call->flags |= IPC_CALL_NOTIF;
-		IPC_SET_METHOD(call->data, IPC_M_INTERRUPT);
-		IPC_SET_ARG1(call->data, irq);
-
-		spinlock_lock(&irq_conns[irq].box->irq_lock);
-		list_append(&call->list, &irq_conns[irq].box->irq_notifs);
-		spinlock_unlock(&irq_conns[irq].box->irq_lock);
-
-		waitq_wakeup(&irq_conns[irq].box->wq, 0);
-	}
-		
-	spinlock_unlock(&irq_conns[irq].lock);
-}
 
 /** Initilize ipc subsystem */
Index: generic/src/ipc/irq.c
===================================================================
--- generic/src/ipc/irq.c	(revision 162f9196160de579344bdc123782df70adf3940f)
+++ generic/src/ipc/irq.c	(revision 162f9196160de579344bdc123782df70adf3940f)
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2006 Ondrej Palkovsky
+ * 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.
+ */
+
+#include <arch.h>
+#include <mm/slab.h>
+#include <errno.h>
+#include <ipc/ipc.h>
+#include <ipc/irq.h>
+
+typedef struct {
+	SPINLOCK_DECLARE(lock);
+	answerbox_t *box;
+	irq_code_t *code;
+} ipc_irq_t;
+
+
+static ipc_irq_t *irq_conns = NULL;
+static int irq_conns_size;
+
+#include <print.h>
+/* Execute code associated with IRQ notification */
+static void code_execute(call_t *call, irq_code_t *code)
+{
+	int i;
+
+	if (!code)
+		return;
+	
+	for (i=0; i < code->cmdcount;i++) {
+		switch (code->cmds[i].cmd) {
+		case CMD_MEM_READ_1:
+			IPC_SET_ARG2(call->data, *((__u8 *)code->cmds[i].addr));
+			break;
+		case CMD_MEM_READ_2:
+			IPC_SET_ARG2(call->data, *((__u16 *)code->cmds[i].addr));
+			break;
+		case CMD_MEM_READ_4:
+			IPC_SET_ARG2(call->data, *((__u32 *)code->cmds[i].addr));
+			break;
+		case CMD_MEM_READ_8:
+			IPC_SET_ARG2(call->data, *((__u64 *)code->cmds[i].addr));
+			break;
+		case CMD_MEM_WRITE_1:
+			*((__u8 *)code->cmds[i].addr) = code->cmds[i].value;
+			break;
+		case CMD_MEM_WRITE_2:
+			*((__u16 *)code->cmds[i].addr) = code->cmds[i].value;
+			break;
+		case CMD_MEM_WRITE_4:
+			*((__u32 *)code->cmds[i].addr) = code->cmds[i].value;
+			break;
+		case CMD_MEM_WRITE_8:
+			*((__u64 *)code->cmds[i].addr) = code->cmds[i].value;
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static void code_free(irq_code_t *code)
+{
+	if (code) {
+		free(code->cmds);
+		free(code);
+	}
+}
+
+static irq_code_t * code_from_uspace(irq_code_t *ucode)
+{
+	irq_code_t *code;
+	irq_cmd_t *ucmds;
+
+	code = malloc(sizeof(*code), 0);
+	copy_from_uspace(code, ucode, sizeof(*code));
+	
+	if (code->cmdcount > IRQ_MAX_PROG_SIZE) {
+		free(code);
+		return NULL;
+	}
+	ucmds = code->cmds;
+	code->cmds = malloc(sizeof(code->cmds[0]) * (code->cmdcount), 0);
+	copy_from_uspace(code->cmds, ucmds, sizeof(code->cmds[0]) * (code->cmdcount));
+
+	return code;
+}
+
+/** Unregister task from irq */
+void ipc_irq_unregister(answerbox_t *box, int irq)
+{
+	ipl_t ipl;
+
+	ipl = interrupts_disable();
+	spinlock_lock(&irq_conns[irq].lock);
+	if (irq_conns[irq].box == box) {
+		irq_conns[irq].box = NULL;
+		code_free(irq_conns[irq].code);
+		irq_conns[irq].code = NULL;
+	}
+
+	spinlock_unlock(&irq_conns[irq].lock);
+	interrupts_restore(ipl);
+}
+
+/** Register an answerbox as a receiving end of interrupts notifications */
+int ipc_irq_register(answerbox_t *box, int irq, irq_code_t *ucode)
+{
+	ipl_t ipl;
+	irq_code_t *code;
+
+	ASSERT(irq_conns);
+
+	if (ucode) {
+		code = code_from_uspace(ucode);
+		if (!code)
+			return EBADMEM;
+	} else
+		code = NULL;
+
+	ipl = interrupts_disable();
+	spinlock_lock(&irq_conns[irq].lock);
+
+	if (irq_conns[irq].box) {
+		spinlock_unlock(&irq_conns[irq].lock);
+		interrupts_restore(ipl);
+		code_free(code);
+		return EEXISTS;
+	}
+	irq_conns[irq].box = box;
+	irq_conns[irq].code = code;
+	spinlock_unlock(&irq_conns[irq].lock);
+	interrupts_restore(ipl);
+
+	return 0;
+}
+
+/** Notify process that an irq had happend
+ *
+ * We expect interrupts to be disabled
+ */
+void ipc_irq_send_notif(int irq)
+{
+	call_t *call;
+
+	ASSERT(irq_conns);
+	spinlock_lock(&irq_conns[irq].lock);
+
+	if (irq_conns[irq].box) {
+		call = ipc_call_alloc(FRAME_ATOMIC);
+		call->flags |= IPC_CALL_NOTIF;
+		IPC_SET_METHOD(call->data, IPC_M_INTERRUPT);
+		IPC_SET_ARG1(call->data, irq);
+
+		/* Execute code to handle irq */
+		code_execute(call, irq_conns[irq].code);
+
+		spinlock_lock(&irq_conns[irq].box->irq_lock);
+		list_append(&call->list, &irq_conns[irq].box->irq_notifs);
+		spinlock_unlock(&irq_conns[irq].box->irq_lock);
+
+		waitq_wakeup(&irq_conns[irq].box->wq, 0);
+	}
+		
+	spinlock_unlock(&irq_conns[irq].lock);
+}
+
+
+/** Initialize table of interrupt handlers */
+void ipc_irq_make_table(int irqcount)
+{
+	int i;
+
+	irq_conns_size = irqcount;
+	irq_conns = malloc(irqcount * (sizeof(*irq_conns)), 0);
+	for (i=0; i < irqcount; i++) {
+		spinlock_initialize(&irq_conns[i].lock, "irq_ipc_lock");
+		irq_conns[i].box = NULL;
+		irq_conns[i].code = NULL;
+	}
+}
+
+/** Disconnect all irq's notifications
+ *
+ * TODO: It may be better to do some linked list, so that
+ *       we wouldn't need to go through whole array every cleanup
+ */
+void ipc_irq_cleanup(answerbox_t *box)
+{
+	int i;
+	ipl_t ipl;
+	
+	for (i=0; i < irq_conns_size; i++) {
+		ipl = interrupts_disable();
+		spinlock_lock(&irq_conns[i].lock);
+		if (irq_conns[i].box == box)
+			irq_conns[i].box = NULL;
+		spinlock_unlock(&irq_conns[i].lock);
+		interrupts_restore(ipl);
+	}
+}
Index: generic/src/ipc/sysipc.c
===================================================================
--- generic/src/ipc/sysipc.c	(revision 281224aeb3d8da7b9f59d258df830ad80784c70c)
+++ generic/src/ipc/sysipc.c	(revision 162f9196160de579344bdc123782df70adf3940f)
@@ -36,4 +36,5 @@
 #include <ipc/ipc.h>
 #include <ipc/sysipc.h>
+#include <ipc/irq.h>
 #include <ipc/ipcrsc.h>
 #include <arch/interrupt.h>
@@ -478,5 +479,5 @@
 
 /** Connect irq handler to task */
-__native sys_ipc_register_irq(__native irq)
+__native sys_ipc_register_irq(__native irq, irq_code_t *ucode)
 {
 	if (irq >= IRQ_COUNT)
@@ -484,5 +485,6 @@
 
 	irq_ipc_bind_arch(irq);
-	return ipc_irq_register(&TASK->answerbox, irq);
+
+	return ipc_irq_register(&TASK->answerbox, irq, ucode);
 }
 
