Index: kernel/arch/ia32/src/ia32.c
===================================================================
--- kernel/arch/ia32/src/ia32.c	(revision 0cb9fa0b1256166b7043ccb33e483aaac3beeaba)
+++ kernel/arch/ia32/src/ia32.c	(revision cecb07892c77b379e9e44411c961635f85a64910)
@@ -167,5 +167,4 @@
 #endif
 	
-	i8042_grab();
 }
 
@@ -175,5 +174,4 @@
 void arch_release_console(void)
 {
-	i8042_release();
 }
 
Index: kernel/genarch/src/kbd/i8042.c
===================================================================
--- kernel/genarch/src/kbd/i8042.c	(revision 0cb9fa0b1256166b7043ccb33e483aaac3beeaba)
+++ kernel/genarch/src/kbd/i8042.c	(revision cecb07892c77b379e9e44411c961635f85a64910)
@@ -95,36 +95,4 @@
 static irq_t i8042_mouse_irq;
 
-void i8042_grab(void)
-{
-	ipl_t ipl = interrupts_disable();
-	
-	spinlock_lock(&i8042_kbd_irq.lock);
-	i8042_kbd_irq.notif_cfg.notify = false;
-	spinlock_unlock(&i8042_kbd_irq.lock);
-	
-	spinlock_lock(&i8042_mouse_irq.lock);
-	i8042_mouse_irq.notif_cfg.notify = false;
-	spinlock_unlock(&i8042_mouse_irq.lock);
-	
-	interrupts_restore(ipl);
-}
-
-void i8042_release(void)
-{
-	ipl_t ipl = interrupts_disable();
-	
-	spinlock_lock(&i8042_kbd_irq.lock);
-	if (i8042_kbd_irq.notif_cfg.answerbox)
-		i8042_kbd_irq.notif_cfg.notify = true;
-	spinlock_unlock(&i8042_kbd_irq.lock);
-	
-	spinlock_lock(&i8042_mouse_irq.lock);
-	if (i8042_mouse_irq.notif_cfg.answerbox)
-		i8042_mouse_irq.notif_cfg.notify = true;
-	spinlock_unlock(&i8042_mouse_irq.lock);
-	
-	interrupts_restore(ipl);
-}
-
 static irq_ownership_t i8042_claim(irq_t *irq)
 {
@@ -139,12 +107,4 @@
 static void i8042_irq_handler(irq_t *irq)
 {
-	if (irq->notif_cfg.notify && irq->notif_cfg.answerbox) {
-		/*
-		 * This will hopefully go to the IRQ dispatcher code soon.
-		 */ 
-		ipc_irq_send_notif(irq);
-		return;
-	}
-
 	i8042_instance_t *instance = irq->instance;
 	i8042_t *dev = instance->i8042;
@@ -214,6 +174,4 @@
 	sysinfo_set_item_val("mouse.devno", NULL, mouse_devno);
 	sysinfo_set_item_val("mouse.inr", NULL, mouse_inr);
-	
-	i8042_grab();
 }
 
Index: kernel/generic/include/ddi/irq.h
===================================================================
--- kernel/generic/include/ddi/irq.h	(revision 0cb9fa0b1256166b7043ccb33e483aaac3beeaba)
+++ kernel/generic/include/ddi/irq.h	(revision cecb07892c77b379e9e44411c961635f85a64910)
@@ -37,14 +37,14 @@
 
 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_PORT_READ_1,
-	CMD_PORT_WRITE_1,
+	CMD_PIO_READ_8 = 1,
+	CMD_PIO_READ_16,
+	CMD_PIO_READ_32,
+	CMD_PIO_WRITE_8,
+	CMD_PIO_WRITE_16,
+	CMD_PIO_WRITE_32,
+	CMD_BTEST,
+	CMD_PREDICATE,
+	CMD_ACCEPT,
+	CMD_DECLINE,
 	CMD_LAST
 } irq_cmd_type;
@@ -53,6 +53,7 @@
 	irq_cmd_type cmd;
 	void *addr;
-	unsigned long long value; 
-	int dstarg;
+	unsigned long long value;
+	unsigned int srcarg;
+	unsigned int dstarg;
 } irq_cmd_t;
 
@@ -66,6 +67,8 @@
 #include <arch/types.h>
 #include <adt/list.h>
+#include <adt/hash_table.h>
 #include <synch/spinlock.h>
 #include <proc/task.h>
+#include <ipc/ipc.h>
 
 typedef enum {
@@ -97,4 +100,6 @@
 	/** Method to be used for the notification. */
 	unative_t method;
+	/** Arguments that will be sent if the IRQ is claimed. */
+	unative_t scratch[IPC_CALL_LEN];
 	/** Top-half pseudocode. */
 	irq_code_t *code;
@@ -155,9 +160,11 @@
 } irq_t;
 
+SPINLOCK_EXTERN(irq_uspace_hash_table_lock);
+extern hash_table_t irq_uspace_hash_table;
+
 extern void irq_init(count_t, count_t);
 extern void irq_initialize(irq_t *);
 extern void irq_register(irq_t *);
 extern irq_t *irq_dispatch_and_lock(inr_t);
-extern irq_t *irq_find_and_lock(inr_t, devno_t);
 
 #endif
Index: kernel/generic/include/ipc/irq.h
===================================================================
--- kernel/generic/include/ipc/irq.h	(revision 0cb9fa0b1256166b7043ccb33e483aaac3beeaba)
+++ kernel/generic/include/ipc/irq.h	(revision cecb07892c77b379e9e44411c961635f85a64910)
@@ -37,5 +37,5 @@
 
 /** Maximum length of IPC IRQ program */
-#define IRQ_MAX_PROG_SIZE	10
+#define IRQ_MAX_PROG_SIZE	20
 
 #include <ipc/ipc.h>
@@ -44,9 +44,12 @@
 #include <adt/list.h>
 
-extern int ipc_irq_register(answerbox_t *box, inr_t inr, devno_t devno,
-    unative_t method, irq_code_t *ucode);
-extern void ipc_irq_send_notif(irq_t *irq);
-extern void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno);
-extern void ipc_irq_cleanup(answerbox_t *box);
+extern int ipc_irq_register(answerbox_t *, inr_t, devno_t, unative_t,
+    irq_code_t *);
+
+extern irq_ownership_t ipc_irq_top_half_claim(irq_t *);
+extern void ipc_irq_top_half_handler(irq_t *);
+
+extern int ipc_irq_unregister(answerbox_t *, inr_t, devno_t);
+extern void ipc_irq_cleanup(answerbox_t *);
 
 /*
@@ -67,6 +70,6 @@
     ipc_irq_send_msg((irq), (a1), (a2), (a3), (a4), (a5))
 
-extern void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2,
-    unative_t a3, unative_t a4, unative_t a5);
+extern void ipc_irq_send_msg(irq_t *, unative_t, unative_t, unative_t, unative_t,
+    unative_t);
 
 #endif
Index: kernel/generic/src/ddi/irq.c
===================================================================
--- kernel/generic/src/ddi/irq.c	(revision 0cb9fa0b1256166b7043ccb33e483aaac3beeaba)
+++ kernel/generic/src/ddi/irq.c	(revision cecb07892c77b379e9e44411c961635f85a64910)
@@ -70,6 +70,8 @@
 #include <ddi/irq.h>
 #include <adt/hash_table.h>
+#include <mm/slab.h>
 #include <arch/types.h>
 #include <synch/spinlock.h>
+#include <memstr.h>
 #include <arch.h>
 
@@ -78,9 +80,18 @@
 
 /**
- * Spinlock protecting the hash table.
+ * Spinlock protecting the kernel IRQ hash table.
  * This lock must be taken only when interrupts are disabled.
  */
-SPINLOCK_INITIALIZE(irq_hash_table_lock);
-static hash_table_t irq_hash_table;
+static SPINLOCK_INITIALIZE(irq_kernel_hash_table_lock);
+/** The kernel IRQ hash table. */
+static hash_table_t irq_kernel_hash_table;
+
+/**
+ * Spinlock protecting the uspace IRQ hash table.
+ * This lock must be taken only when interrupts are disabled.
+ */
+SPINLOCK_INITIALIZE(irq_uspace_hash_table_lock);
+/** The uspace IRQ hash table. */
+hash_table_t irq_uspace_hash_table;
 
 /**
@@ -112,4 +123,7 @@
 };
 
+/** Number of buckets in either of the hash tables. */
+static count_t buckets;
+
 /** Initialize IRQ subsystem.
  *
@@ -119,4 +133,5 @@
 void irq_init(count_t inrs, count_t chains)
 {
+	buckets = chains;
 	/*
 	 * Be smart about the choice of the hash table operations.
@@ -125,8 +140,15 @@
 	 * different keys), we can use optimized set of operations.
 	 */
-	if (inrs == chains)
-		hash_table_create(&irq_hash_table, chains, 2, &irq_lin_ops);
-	else
-		hash_table_create(&irq_hash_table, chains, 2, &irq_ht_ops);
+	if (inrs == chains) {
+		hash_table_create(&irq_uspace_hash_table, chains, 2,
+		    &irq_lin_ops);
+		hash_table_create(&irq_kernel_hash_table, chains, 2,
+		    &irq_lin_ops);
+	} else {
+		hash_table_create(&irq_uspace_hash_table, chains, 2,
+		    &irq_ht_ops);
+		hash_table_create(&irq_kernel_hash_table, chains, 2,
+		    &irq_ht_ops);
+	}
 }
 
@@ -138,21 +160,10 @@
 void irq_initialize(irq_t *irq)
 {
+	memsetb(irq, 0, sizeof(irq_t));
 	link_initialize(&irq->link);
 	spinlock_initialize(&irq->lock, "irq.lock");
-	irq->preack = false;
+	link_initialize(&irq->notif_cfg.link);
 	irq->inr = -1;
 	irq->devno = -1;
-	irq->trigger = (irq_trigger_t) 0;
-	irq->claim = NULL;
-	irq->handler = NULL;
-	irq->instance = NULL;
-	irq->cir = NULL;
-	irq->cir_arg = NULL;
-	irq->notif_cfg.notify = false;
-	irq->notif_cfg.answerbox = NULL;
-	irq->notif_cfg.code = NULL;
-	irq->notif_cfg.method = 0;
-	irq->notif_cfg.counter = 0;
-	link_initialize(&irq->notif_cfg.link);
 }
 
@@ -161,10 +172,13 @@
  * The irq structure must be filled with information
  * about the interrupt source and with the claim()
- * function pointer and irq_handler() function pointer.
- *
- * @param irq IRQ structure belonging to a device.
+ * function pointer and handler() function pointer.
+ *
+ * @param irq		IRQ structure belonging to a device.
+ * @return		True on success, false on failure.
  */
 void irq_register(irq_t *irq)
 {
+	spinlock_t *lock = &irq_kernel_hash_table_lock;
+	hash_table_t *table = &irq_kernel_hash_table;
 	ipl_t ipl;
 	unative_t key[] = {
@@ -174,7 +188,9 @@
 	
 	ipl = interrupts_disable();
-	spinlock_lock(&irq_hash_table_lock);
-	hash_table_insert(&irq_hash_table, key, &irq->link);
-	spinlock_unlock(&irq_hash_table_lock);
+	spinlock_lock(lock);
+	spinlock_lock(&irq->lock);
+	hash_table_insert(table, key, &irq->link);
+	spinlock_unlock(&irq->lock);	
+	spinlock_unlock(lock);
 	interrupts_restore(ipl);
 }
@@ -202,56 +218,31 @@
 	};
 	
-	spinlock_lock(&irq_hash_table_lock);
-
-	lnk = hash_table_find(&irq_hash_table, key);
+	/*
+	 * Try uspace handlers first.
+	 */
+	spinlock_lock(&irq_uspace_hash_table_lock);
+	lnk = hash_table_find(&irq_uspace_hash_table, key);
 	if (lnk) {
 		irq_t *irq;
 		
 		irq = hash_table_get_instance(lnk, irq_t, link);
-
-		spinlock_unlock(&irq_hash_table_lock);
+		spinlock_unlock(&irq_uspace_hash_table_lock);
 		return irq;
 	}
-	
-	spinlock_unlock(&irq_hash_table_lock);
-
-	return NULL;	
-}
-
-/** Find the IRQ structure corresponding to inr and devno.
- *
- * This functions attempts to lookup the IRQ structure
- * corresponding to its arguments. On success, this
- * function returns with interrups disabled, holding
- * the lock of the respective IRQ structure.
- *
- * This function assumes interrupts are already disabled.
- *
- * @param inr INR being looked up.
- * @param devno Devno being looked up.
- *
- * @return Locked IRQ structure on success or NULL on failure.
- */
-irq_t *irq_find_and_lock(inr_t inr, devno_t devno)
-{
-	link_t *lnk;
-	unative_t keys[] = {
-		(unative_t) inr,
-		(unative_t) devno
-	};
-	
-	spinlock_lock(&irq_hash_table_lock);
-
-	lnk = hash_table_find(&irq_hash_table, keys);
+	spinlock_unlock(&irq_uspace_hash_table_lock);
+
+	/*
+	 * Fallback to kernel handlers.
+	 */
+	spinlock_lock(&irq_kernel_hash_table_lock);
+	lnk = hash_table_find(&irq_kernel_hash_table, key);
 	if (lnk) {
 		irq_t *irq;
 		
 		irq = hash_table_get_instance(lnk, irq_t, link);
-
-		spinlock_unlock(&irq_hash_table_lock);
+		spinlock_unlock(&irq_kernel_hash_table_lock);
 		return irq;
 	}
-	
-	spinlock_unlock(&irq_hash_table_lock);
+	spinlock_unlock(&irq_kernel_hash_table_lock);
 
 	return NULL;	
@@ -274,5 +265,5 @@
 {
 	inr_t inr = (inr_t) key[KEY_INR];
-	return inr % irq_hash_table.entries;
+	return inr % buckets;
 }
 
@@ -309,5 +300,5 @@
 		/* Invoked by irq_dispatch_and_lock(). */
 		rv = ((irq->inr == inr) &&
-		    (irq->claim(irq->instance) == IRQ_ACCEPT));
+		    (irq->claim(irq) == IRQ_ACCEPT));
 	} else {
 		/* Invoked by irq_find_and_lock(). */
@@ -368,5 +359,5 @@
 	if (devno == -1) {
 		/* Invoked by irq_dispatch_and_lock() */
-		rv = (irq->claim(irq->instance) == IRQ_ACCEPT);
+		rv = (irq->claim(irq) == IRQ_ACCEPT);
 	} else {
 		/* Invoked by irq_find_and_lock() */
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision 0cb9fa0b1256166b7043ccb33e483aaac3beeaba)
+++ kernel/generic/src/ipc/irq.c	(revision cecb07892c77b379e9e44411c961635f85a64910)
@@ -45,6 +45,26 @@
  * - ARG2: payload modified by a 'top-half' handler
  * - ARG3: payload modified by a 'top-half' handler
+ * - ARG4: payload modified by a 'top-half' handler
+ * - ARG5: payload modified by a 'top-half' handler
  * - in_phone_hash: interrupt counter (may be needed to assure correct order
  *         in multithreaded drivers)
+ *
+ * Note on synchronization for ipc_irq_register(), ipc_irq_unregister(),
+ * ipc_irq_cleanup() and IRQ handlers:
+ *
+ *   By always taking all of the uspace IRQ hash table lock, IRQ structure lock
+ *   and answerbox lock, we can rule out race conditions between the
+ *   registration functions and also the cleanup function. Thus the observer can
+ *   either see the IRQ structure present in both the hash table and the
+ *   answerbox list or absent in both. Views in which the IRQ structure would be
+ *   linked in the hash table but not in the answerbox list, or vice versa, are
+ *   not possible.
+ *
+ *   By always taking the hash table lock and the IRQ structure lock, we can
+ *   rule out a scenario in which we would free up an IRQ structure, which is
+ *   still referenced by, for example, an IRQ handler. The locking scheme forces
+ *   us to lock the IRQ structure only after any progressing IRQs on that
+ *   structure are finished. Because we hold the hash table lock, we prevent new
+ *   IRQs from taking new references to the IRQ structure.
  */
 
@@ -59,63 +79,5 @@
 #include <print.h>
 
-/** Execute code associated with IRQ notification.
- *
- * @param call		Notification call.
- * @param code		Top-half pseudocode.
- */
-static void code_execute(call_t *call, irq_code_t *code)
-{
-	unsigned int i;
-	unative_t dstval = 0;
-	
-	if (!code)
-		return;
-	
-	for (i = 0; i < code->cmdcount; i++) {
-		switch (code->cmds[i].cmd) {
-		case CMD_MEM_READ_1:
-			dstval = *((uint8_t *) code->cmds[i].addr);
-			break;
-		case CMD_MEM_READ_2:
-			dstval = *((uint16_t *) code->cmds[i].addr);
-			break;
-		case CMD_MEM_READ_4:
-			dstval = *((uint32_t *) code->cmds[i].addr);
-			break;
-		case CMD_MEM_READ_8:
-			dstval = *((uint64_t *) code->cmds[i].addr);
-			break;
-		case CMD_MEM_WRITE_1:
-			*((uint8_t *) code->cmds[i].addr) = code->cmds[i].value;
-			break;
-		case CMD_MEM_WRITE_2:
-			*((uint16_t *) code->cmds[i].addr) =
-			    code->cmds[i].value;
-			break;
-		case CMD_MEM_WRITE_4:
-			*((uint32_t *) code->cmds[i].addr) =
-			    code->cmds[i].value;
-			break;
-		case CMD_MEM_WRITE_8:
-			*((uint64_t *) code->cmds[i].addr) =
-			    code->cmds[i].value;
-			break;
-		case CMD_PORT_READ_1:
-			dstval = pio_read_8((ioport8_t *) code->cmds[i].addr);
-			break;
-		case CMD_PORT_WRITE_1:
-			pio_write_8((ioport8_t *) code->cmds[i].addr, code->cmds[i].value);
-			break;
-		default:
-			break;
-		}
-		if (code->cmds[i].dstarg && code->cmds[i].dstarg <
-		    IPC_CALL_LEN) {
-			call->data.args[code->cmds[i].dstarg] = dstval;
-		}
-	}
-}
-
-/** Free top-half pseudocode.
+/** Free the top-half pseudocode.
  *
  * @param code		Pointer to the top-half pseudocode.
@@ -129,5 +91,5 @@
 }
 
-/** Copy top-half pseudocode from userspace into the kernel.
+/** Copy the top-half pseudocode from userspace into the kernel.
  *
  * @param ucode		Userspace address of the top-half pseudocode.
@@ -165,36 +127,4 @@
 }
 
-/** Unregister task from IRQ notification.
- *
- * @param box		Answerbox associated with the notification.
- * @param inr		IRQ number.
- * @param devno		Device number.
- */
-void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno)
-{
-	ipl_t ipl;
-	irq_t *irq;
-
-	ipl = interrupts_disable();
-	irq = irq_find_and_lock(inr, devno);
-	if (irq) {
-		if (irq->notif_cfg.answerbox == box) {
-			code_free(irq->notif_cfg.code);
-			irq->notif_cfg.notify = false;
-			irq->notif_cfg.answerbox = NULL;
-			irq->notif_cfg.code = NULL;
-			irq->notif_cfg.method = 0;
-			irq->notif_cfg.counter = 0;
-
-			spinlock_lock(&box->irq_lock);
-			list_remove(&irq->notif_cfg.link);
-			spinlock_unlock(&box->irq_lock);
-			
-			spinlock_unlock(&irq->lock);
-		}
-	}
-	interrupts_restore(ipl);
-}
-
 /** Register an answerbox as a receiving end for IRQ notifications.
  *
@@ -213,4 +143,8 @@
 	irq_code_t *code;
 	irq_t *irq;
+	unative_t key[] = {
+		(unative_t) inr,
+		(unative_t) devno
+	};
 
 	if (ucode) {
@@ -222,19 +156,13 @@
 	}
 
-	ipl = interrupts_disable();
-	irq = irq_find_and_lock(inr, devno);
-	if (!irq) {
-		interrupts_restore(ipl);
-		code_free(code);
-		return ENOENT;
-	}
-	
-	if (irq->notif_cfg.answerbox) {
-		spinlock_unlock(&irq->lock);
-		interrupts_restore(ipl);
-		code_free(code);
-		return EEXISTS;
-	}
-	
+	/*
+	 * Allocate and populate the IRQ structure.
+	 */
+	irq = malloc(sizeof(irq_t), 0);
+	irq_initialize(irq);
+	irq->devno = devno;
+	irq->inr = inr;
+	irq->claim = ipc_irq_top_half_claim;
+	irq->handler = ipc_irq_top_half_handler;	
 	irq->notif_cfg.notify = true;
 	irq->notif_cfg.answerbox = box;
@@ -243,12 +171,138 @@
 	irq->notif_cfg.counter = 0;
 
+	/*
+	 * Enlist the IRQ structure in the uspace IRQ hash table and the
+	 * answerbox's list.
+	 */
+	ipl = interrupts_disable();
+	spinlock_lock(&irq_uspace_hash_table_lock);
+	spinlock_lock(&irq->lock);
 	spinlock_lock(&box->irq_lock);
+	if (hash_table_find(&irq_uspace_hash_table, key)) {
+		code_free(code);
+		spinlock_unlock(&box->irq_lock);
+		spinlock_unlock(&irq->lock);
+		spinlock_unlock(&irq_uspace_hash_table_lock);
+		free(irq);
+		interrupts_restore(ipl);
+		return EEXISTS;
+	}
+	hash_table_insert(&irq_uspace_hash_table, key, &irq->link);
 	list_append(&irq->notif_cfg.link, &box->irq_head);
 	spinlock_unlock(&box->irq_lock);
-
 	spinlock_unlock(&irq->lock);
+	spinlock_unlock(&irq_uspace_hash_table_lock);
+
 	interrupts_restore(ipl);
-
-	return 0;
+	return EOK;
+}
+
+/** Unregister task from IRQ notification.
+ *
+ * @param box		Answerbox associated with the notification.
+ * @param inr		IRQ number.
+ * @param devno		Device number.
+ */
+int ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno)
+{
+	ipl_t ipl;
+	unative_t key[] = {
+		(unative_t) inr,
+		(unative_t) devno
+	};
+	link_t *lnk;
+	irq_t *irq;
+
+	ipl = interrupts_disable();
+	spinlock_lock(&irq_uspace_hash_table_lock);
+	lnk = hash_table_find(&irq_uspace_hash_table, key);
+	if (!lnk) {
+		spinlock_unlock(&irq_uspace_hash_table_lock);
+		interrupts_restore(ipl);
+		return ENOENT;
+	}
+	irq = hash_table_get_instance(lnk, irq_t, link);
+	spinlock_lock(&irq->lock);
+	spinlock_lock(&box->irq_lock);
+	
+	ASSERT(irq->notif_cfg.answerbox == box);
+	
+	/* Free up the pseudo code and associated structures. */
+	code_free(irq->notif_cfg.code);
+
+	/* Remove the IRQ from the answerbox's list. */ 
+	list_remove(&irq->notif_cfg.link);
+
+	/* Remove the IRQ from the uspace IRQ hash table. */
+	hash_table_remove(&irq_uspace_hash_table, key, 2);
+	
+	spinlock_unlock(&irq_uspace_hash_table_lock);
+	spinlock_unlock(&irq->lock);
+	spinlock_unlock(&box->irq_lock);
+	
+	/* Free up the IRQ structure. */
+	free(irq);
+	
+	interrupts_restore(ipl);
+	return EOK;
+}
+
+
+/** Disconnect all IRQ notifications from an answerbox.
+ *
+ * This function is effective because the answerbox contains
+ * list of all irq_t structures that are registered to
+ * send notifications to it.
+ *
+ * @param box		Answerbox for which we want to carry out the cleanup.
+ */
+void ipc_irq_cleanup(answerbox_t *box)
+{
+	ipl_t ipl;
+	
+loop:
+	ipl = interrupts_disable();
+	spinlock_lock(&irq_uspace_hash_table_lock);
+	spinlock_lock(&box->irq_lock);
+	
+	while (box->irq_head.next != &box->irq_head) {
+		link_t *cur = box->irq_head.next;
+		irq_t *irq;
+		DEADLOCK_PROBE_INIT(p_irqlock);
+		unative_t key[2];
+		
+		irq = list_get_instance(cur, irq_t, notif_cfg.link);
+		if (!spinlock_trylock(&irq->lock)) {
+			/*
+			 * Avoid deadlock by trying again.
+			 */
+			spinlock_unlock(&box->irq_lock);
+			spinlock_unlock(&irq_uspace_hash_table_lock);
+			interrupts_restore(ipl);
+			DEADLOCK_PROBE(p_irqlock, DEADLOCK_THRESHOLD);
+			goto loop;
+		}
+		key[0] = irq->inr;
+		key[1] = irq->devno;
+		
+		
+		ASSERT(irq->notif_cfg.answerbox == box);
+		
+		/* Unlist from the answerbox. */
+		list_remove(&irq->notif_cfg.link);
+		
+		/* Remove from the hash table. */
+		hash_table_remove(&irq_uspace_hash_table, key, 2);
+		
+		/* Free up the pseudo code and associated structures. */
+		code_free(irq->notif_cfg.code);
+		
+		spinlock_unlock(&irq->lock);
+		free(irq);
+	}
+	
+	spinlock_unlock(&box->irq_lock);
+	spinlock_unlock(&irq_uspace_hash_table_lock);
+	interrupts_restore(ipl);
 }
 
@@ -267,4 +321,120 @@
 		
 	waitq_wakeup(&irq->notif_cfg.answerbox->wq, WAKEUP_FIRST);
+}
+
+/** Apply the top-half pseudo code to find out whether to accept the IRQ or not.
+ *
+ * @param irq		IRQ structure.
+ *
+ * @return		IRQ_ACCEPT if the interrupt is accepted by the
+ *			pseudocode. IRQ_DECLINE otherwise.
+ */
+irq_ownership_t ipc_irq_top_half_claim(irq_t *irq)
+{
+	unsigned int i;
+	unative_t dstval;
+	irq_code_t *code = irq->notif_cfg.code;
+	unative_t *scratch = irq->notif_cfg.scratch;
+
+	
+	if (!irq->notif_cfg.notify)
+		return IRQ_DECLINE;
+	
+	if (!code)
+		return IRQ_DECLINE;
+	
+	for (i = 0; i < code->cmdcount; i++) {
+		unsigned int srcarg = code->cmds[i].srcarg;
+		unsigned int dstarg = code->cmds[i].dstarg;
+		
+		if (srcarg >= IPC_CALL_LEN)
+			break;
+		if (dstarg >= IPC_CALL_LEN)
+			break;
+	
+		switch (code->cmds[i].cmd) {
+		case CMD_PIO_READ_8:
+			dstval = pio_read_8((ioport8_t *) code->cmds[i].addr);
+			if (dstarg)
+				scratch[dstarg] = dstval;
+			break;
+		case CMD_PIO_READ_16:
+			dstval = pio_read_16((ioport16_t *) code->cmds[i].addr);
+			if (dstarg)
+				scratch[dstarg] = dstval;
+			break;
+		case CMD_PIO_READ_32:
+			dstval = pio_read_32((ioport32_t *) code->cmds[i].addr);
+			if (dstarg)
+				scratch[dstarg] = dstval;
+			break;
+		case CMD_PIO_WRITE_8:
+			pio_write_8((ioport8_t *) code->cmds[i].addr,
+			    (uint8_t) code->cmds[i].value);
+			break;
+		case CMD_PIO_WRITE_16:
+			pio_write_16((ioport16_t *) code->cmds[i].addr,
+			    (uint16_t) code->cmds[i].value);
+			break;
+		case CMD_PIO_WRITE_32:
+			pio_write_32((ioport32_t *) code->cmds[i].addr,
+			    (uint32_t) code->cmds[i].value);
+			break;
+		case CMD_BTEST:
+			if (srcarg && dstarg) {
+				dstval = scratch[srcarg] & code->cmds[i].value;
+				scratch[dstarg] = dstval;
+			}
+			break;
+		case CMD_PREDICATE:
+			if (srcarg && !scratch[srcarg]) {
+				i += code->cmds[i].value;
+				continue;
+			}
+			break;
+		case CMD_ACCEPT:
+			return IRQ_ACCEPT;
+			break;
+		case CMD_DECLINE:
+		default:
+			return IRQ_DECLINE;
+		}
+	}
+	
+	return IRQ_DECLINE;
+}
+
+
+/* IRQ top-half handler.
+ *
+ * We expect interrupts to be disabled and the irq->lock already held.
+ *
+ * @param irq		IRQ structure.
+ */
+void ipc_irq_top_half_handler(irq_t *irq)
+{
+	ASSERT(irq);
+
+	if (irq->notif_cfg.answerbox) {
+		call_t *call;
+
+		call = ipc_call_alloc(FRAME_ATOMIC);
+		if (!call)
+			return;
+		
+		call->flags |= IPC_CALL_NOTIF;
+		/* Put a counter to the message */
+		call->priv = ++irq->notif_cfg.counter;
+
+		/* Set up args */
+		IPC_SET_METHOD(call->data, irq->notif_cfg.method);
+		IPC_SET_ARG1(call->data, irq->notif_cfg.scratch[1]);
+		IPC_SET_ARG2(call->data, irq->notif_cfg.scratch[2]);
+		IPC_SET_ARG3(call->data, irq->notif_cfg.scratch[3]);
+		IPC_SET_ARG4(call->data, irq->notif_cfg.scratch[4]);
+		IPC_SET_ARG5(call->data, irq->notif_cfg.scratch[5]);
+
+		send_call(irq, call);
+	}
 }
 
@@ -292,4 +462,7 @@
 		}
 		call->flags |= IPC_CALL_NOTIF;
+		/* Put a counter to the message */
+		call->priv = ++irq->notif_cfg.counter;
+
 		IPC_SET_METHOD(call->data, irq->notif_cfg.method);
 		IPC_SET_ARG1(call->data, a1);
@@ -298,6 +471,4 @@
 		IPC_SET_ARG4(call->data, a4);
 		IPC_SET_ARG5(call->data, a5);
-		/* Put a counter to the message */
-		call->priv = ++irq->notif_cfg.counter;
 		
 		send_call(irq, call);
@@ -306,88 +477,4 @@
 }
 
-/** Notify a task that an IRQ had occurred.
- *
- * We expect interrupts to be disabled and the irq->lock already held.
- *
- * @param irq		IRQ structure.
- */
-void ipc_irq_send_notif(irq_t *irq)
-{
-	call_t *call;
-
-	ASSERT(irq);
-
-	if (irq->notif_cfg.answerbox) {
-		call = ipc_call_alloc(FRAME_ATOMIC);
-		if (!call) {
-			return;
-		}
-		call->flags |= IPC_CALL_NOTIF;
-		/* Put a counter to the message */
-		call->priv = ++irq->notif_cfg.counter;
-		/* Set up args */
-		IPC_SET_METHOD(call->data, irq->notif_cfg.method);
-
-		/* Execute code to handle irq */
-		code_execute(call, irq->notif_cfg.code);
-		
-		send_call(irq, call);
-	}
-}
-
-/** Disconnect all IRQ notifications from an answerbox.
- *
- * This function is effective because the answerbox contains
- * list of all irq_t structures that are registered to
- * send notifications to it.
- *
- * @param box		Answerbox for which we want to carry out the cleanup.
- */
-void ipc_irq_cleanup(answerbox_t *box)
-{
-	ipl_t ipl;
-	
-loop:
-	ipl = interrupts_disable();
-	spinlock_lock(&box->irq_lock);
-	
-	while (box->irq_head.next != &box->irq_head) {
-		link_t *cur = box->irq_head.next;
-		irq_t *irq;
-		DEADLOCK_PROBE_INIT(p_irqlock);
-		
-		irq = list_get_instance(cur, irq_t, notif_cfg.link);
-		if (!spinlock_trylock(&irq->lock)) {
-			/*
-			 * Avoid deadlock by trying again.
-			 */
-			spinlock_unlock(&box->irq_lock);
-			interrupts_restore(ipl);
-			DEADLOCK_PROBE(p_irqlock, DEADLOCK_THRESHOLD);
-			goto loop;
-		}
-		
-		ASSERT(irq->notif_cfg.answerbox == box);
-		
-		list_remove(&irq->notif_cfg.link);
-		
-		/*
-		 * Don't forget to free any top-half pseudocode.
-		 */
-		code_free(irq->notif_cfg.code);
-		
-		irq->notif_cfg.notify = false;
-		irq->notif_cfg.answerbox = NULL;
-		irq->notif_cfg.code = NULL;
-		irq->notif_cfg.method = 0;
-		irq->notif_cfg.counter = 0;
-
-		spinlock_unlock(&irq->lock);
-	}
-	
-	spinlock_unlock(&box->irq_lock);
-	interrupts_restore(ipl);
-}
-
 /** @}
  */
Index: uspace/srv/kbd/port/i8042.c
===================================================================
--- uspace/srv/kbd/port/i8042.c	(revision 0cb9fa0b1256166b7043ccb33e483aaac3beeaba)
+++ uspace/srv/kbd/port/i8042.c	(revision cecb07892c77b379e9e44411c961635f85a64910)
@@ -64,11 +64,33 @@
 #define MOUSE_ACK       0xfa
 
-static irq_cmd_t i8042_cmds[2] = {
-	{ CMD_PORT_READ_1, (void *) 0x64, 0, 1 },
-	{ CMD_PORT_READ_1, (void *) 0x60, 0, 2 }
+static irq_cmd_t i8042_cmds[] = {
+	{
+		.cmd = CMD_PIO_READ_8,
+		.addr = (void *) 0x64,
+		.dstarg = 1
+	},
+	{
+		.cmd = CMD_BTEST,
+		.value = i8042_OUTPUT_FULL,
+		.srcarg = 1,
+		.dstarg = 3
+	},
+	{
+		.cmd = CMD_PREDICATE,
+		.value = 2,
+		.srcarg = 3
+	},
+	{
+		.cmd = CMD_PIO_READ_8,
+		.addr = (void *) 0x60,
+		.dstarg = 2
+	},
+	{
+		.cmd = CMD_ACCEPT
+	}
 };
 
 static irq_code_t i8042_kbd = {
-	2,
+	sizeof(i8042_cmds) / sizeof(irq_cmd_t),
 	i8042_cmds
 };
