Index: kernel/generic/include/ipc/irq.h
===================================================================
--- kernel/generic/include/ipc/irq.h	(revision 1c85bae15aa87bd11bf412120eaf4e1906a9ea73)
+++ kernel/generic/include/ipc/irq.h	(revision e9d15d9f0efb393d698245b131a15268dc1cd68f)
@@ -53,5 +53,5 @@
 extern void ipc_irq_top_half_handler(irq_t *);
 
-extern int ipc_irq_unsubscribe(answerbox_t *, inr_t, devno_t);
+extern int ipc_irq_unsubscribe(answerbox_t *, int);
 extern void ipc_irq_cleanup(answerbox_t *);
 
Index: kernel/generic/include/ipc/sysipc.h
===================================================================
--- kernel/generic/include/ipc/sysipc.h	(revision 1c85bae15aa87bd11bf412120eaf4e1906a9ea73)
+++ kernel/generic/include/ipc/sysipc.h	(revision e9d15d9f0efb393d698245b131a15268dc1cd68f)
@@ -57,5 +57,5 @@
 
 extern sysarg_t sys_ipc_irq_subscribe(inr_t, devno_t, sysarg_t, irq_code_t *);
-extern sysarg_t sys_ipc_irq_unsubscribe(inr_t, devno_t);
+extern sysarg_t sys_ipc_irq_unsubscribe(sysarg_t);
 
 #ifdef __32_BITS__
Index: kernel/generic/include/kobject/kobject.h
===================================================================
--- kernel/generic/include/kobject/kobject.h	(revision 1c85bae15aa87bd11bf412120eaf4e1906a9ea73)
+++ kernel/generic/include/kobject/kobject.h	(revision e9d15d9f0efb393d698245b131a15268dc1cd68f)
@@ -38,13 +38,13 @@
 #include <typedefs.h>
 #include <ipc/ipc.h>
+#include <ddi/irq.h>
 
 #define MAX_KERNEL_OBJECTS  64
-
-#define KOBJECT_INVALID_CAP -1
 
 typedef enum {
 	KOBJECT_TYPE_INVALID,
 	KOBJECT_TYPE_ALLOCATED,
-	KOBJECT_TYPE_PHONE
+	KOBJECT_TYPE_PHONE,
+	KOBJECT_TYPE_IRQ
 } kobject_type_t;
 
@@ -55,4 +55,5 @@
 	union {
 		phone_t phone;
+		irq_t irq;
 	};
 } kobject_t;
@@ -60,5 +61,5 @@
 struct task;
 
-extern void kobject_init(kobject_t *);
+extern void kobject_initialize(kobject_t *);
 extern kobject_t *kobject_get(struct task *, int, kobject_type_t);
 extern kobject_t *kobject_get_current(int, kobject_type_t);
Index: kernel/generic/include/proc/task.h
===================================================================
--- kernel/generic/include/proc/task.h	(revision 1c85bae15aa87bd11bf412120eaf4e1906a9ea73)
+++ kernel/generic/include/proc/task.h	(revision e9d15d9f0efb393d698245b131a15268dc1cd68f)
@@ -37,5 +37,4 @@
 
 #include <cpu.h>
-#include <kobject/kobject.h>
 #include <ipc/ipc.h>
 #include <ipc/event.h>
@@ -66,4 +65,5 @@
 
 struct thread;
+struct kobject;
 
 /** Task structure. */
@@ -98,5 +98,5 @@
 
 	/** Kernel objects */
-	kobject_t kobject[MAX_KERNEL_OBJECTS];
+	struct kobject *kobject;
 	
 	/* IPC stuff */
Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision 1c85bae15aa87bd11bf412120eaf4e1906a9ea73)
+++ kernel/generic/src/ipc/ipc.c	(revision e9d15d9f0efb393d698245b131a15268dc1cd68f)
@@ -59,4 +59,5 @@
 #include <arch/interrupt.h>
 #include <ipc/irq.h>
+#include <kobject/kobject.h>
 
 static void ipc_forget_call(call_t *);
Index: kernel/generic/src/ipc/ipcrsc.c
===================================================================
--- kernel/generic/src/ipc/ipcrsc.c	(revision 1c85bae15aa87bd11bf412120eaf4e1906a9ea73)
+++ kernel/generic/src/ipc/ipcrsc.c	(revision e9d15d9f0efb393d698245b131a15268dc1cd68f)
@@ -133,4 +133,5 @@
 #include <assert.h>
 #include <abi/errno.h>
+#include <kobject/kobject.h>
 
 /** Find call_t * in call table according to callid.
@@ -198,10 +199,10 @@
  *
  * @return  New phone capability.
- * @return  KOBJECT_INVALID_CAP if a new capability cannot be allocated.
+ * @return  Negative error code if a new capability cannot be allocated.
  */
 int phone_alloc(task_t *task)
 {
 	int cap = kobject_alloc(task);
-	if (cap != KOBJECT_INVALID_CAP) {
+	if (cap >= 0) {
 		irq_spinlock_lock(&task->lock, true);
 		kobject_t *kobj = &task->kobject[cap];
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision 1c85bae15aa87bd11bf412120eaf4e1906a9ea73)
+++ kernel/generic/src/ipc/irq.c	(revision e9d15d9f0efb393d698245b131a15268dc1cd68f)
@@ -84,4 +84,5 @@
 #include <print.h>
 #include <macros.h>
+#include <kobject/kobject.h>
 
 static void ranges_unmap(irq_pio_range_t *ranges, size_t rangecount)
@@ -298,5 +299,6 @@
  * @param ucode   Uspace pointer to top-half pseudocode.
  *
- * @return EOK on success or a negative error code.
+ * @return  IRQ capability.
+ * @return  Negative error code.
  *
  */
@@ -321,8 +323,14 @@
 	
 	/*
-	 * Allocate and populate the IRQ structure.
+	 * Allocate and populate the IRQ kernel object.
 	 */
-	irq_t *irq = malloc(sizeof(irq_t), 0);
-	
+	int cap = kobject_alloc(TASK);
+	if (cap < 0)
+		return cap;
+	kobject_t *kobj = kobject_get_current(cap, KOBJECT_TYPE_ALLOCATED);
+	assert(kobj);
+	kobj->type = KOBJECT_TYPE_IRQ;
+
+	irq_t *irq = &kobj->irq;
 	irq_initialize(irq);
 	irq->devno = devno;
@@ -351,5 +359,5 @@
 		irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
 		
-		free(irq);
+		kobject_free(TASK, cap);
 		return EEXIST;
 	}
@@ -366,36 +374,24 @@
 	irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
 	
-	return EOK;
+	return cap;
 }
 
 /** Unsubscribe task from IRQ notification.
  *
- * @param box   Answerbox associated with the notification.
- * @param inr   IRQ number.
- * @param devno Device number.
+ * @param box      Answerbox associated with the notification.
+ * @param irq_cap  IRQ capability.
  *
  * @return EOK on success or a negative error code.
  *
  */
-int ipc_irq_unsubscribe(answerbox_t *box, inr_t inr, devno_t devno)
-{
-	sysarg_t key[] = {
-		(sysarg_t) inr,
-		(sysarg_t) devno
-	};
-	
-	if ((inr < 0) || (inr > last_inr))
-		return ELIMIT;
-	
+int ipc_irq_unsubscribe(answerbox_t *box, int irq_cap)
+{
+	kobject_t *kobj = kobject_get_current(irq_cap, KOBJECT_TYPE_IRQ);
+	if (!kobj)
+		return ENOENT;
+	irq_t *irq = &kobj->irq;
+
 	irq_spinlock_lock(&irq_uspace_hash_table_lock, true);
-	link_t *lnk = hash_table_find(&irq_uspace_hash_table, key);
-	if (!lnk) {
-		irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
-		return ENOENT;
-	}
-	
-	irq_t *irq = hash_table_get_instance(lnk, irq_t, link);
-	
-	/* irq is locked */
+	irq_spinlock_lock(&irq->lock, false);
 	irq_spinlock_lock(&box->irq_lock, false);
 	
@@ -405,17 +401,9 @@
 	list_remove(&irq->notif_cfg.link);
 	
-	/*
-	 * We need to drop the IRQ lock now because hash_table_remove() will try
-	 * to reacquire it. That basically violates the natural locking order,
-	 * but a deadlock in hash_table_remove() is prevented by the fact that
-	 * we already held the IRQ lock and didn't drop the hash table lock in
-	 * the meantime.
-	 */
-	irq_spinlock_unlock(&irq->lock, false);
-	
 	/* Remove the IRQ from the uspace IRQ hash table. */
-	hash_table_remove(&irq_uspace_hash_table, key, 2);
+	hash_table_remove_item(&irq_uspace_hash_table, &irq->link);
 	
 	irq_spinlock_unlock(&box->irq_lock, false);
+	/* irq->lock unlocked by the hash table remove_callback */
 	irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
 	
@@ -423,6 +411,6 @@
 	code_free(irq->notif_cfg.code);
 	
-	/* Free up the IRQ structure. */
-	free(irq);
+	/* Free up the IRQ kernel object. */
+	kobject_free(TASK, irq_cap);
 	
 	return EOK;
@@ -431,7 +419,6 @@
 /** Disconnect all IRQ notifications from an answerbox.
  *
- * This function is effective because the answerbox contains
- * list of all irq_t structures that are subscribed to
- * send notifications to it.
+ * This function is effective because the answerbox contains list of all irq_t
+ * structures that are subscribed to send notifications to it.
  *
  * @param box Answerbox for which we want to carry out the cleanup.
@@ -460,8 +447,4 @@
 		}
 		
-		sysarg_t key[2];
-		key[0] = irq->inr;
-		key[1] = irq->devno;
-		
 		assert(irq->notif_cfg.answerbox == box);
 		
@@ -469,15 +452,6 @@
 		list_remove(&irq->notif_cfg.link);
 		
-		/*
-		 * We need to drop the IRQ lock now because hash_table_remove()
-		 * will try to reacquire it. That basically violates the natural
-		 * locking order, but a deadlock in hash_table_remove() is
-		 * prevented by the fact that we already held the IRQ lock and
-		 * didn't drop the hash table lock in the meantime.
-		 */
-		irq_spinlock_unlock(&irq->lock, false);
-		
 		/* Remove from the hash table. */
-		hash_table_remove(&irq_uspace_hash_table, key, 2);
+		hash_table_remove_item(&irq_uspace_hash_table, &irq->link);
 		
 		/*
@@ -488,5 +462,7 @@
 		
 		code_free(irq->notif_cfg.code);
-		free(irq);
+		
+		// XXX: what to do about the irq capability? The task is in
+		// clean-up anyway.
 		
 		/* Reacquire both locks before taking another round. */
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision 1c85bae15aa87bd11bf412120eaf4e1906a9ea73)
+++ kernel/generic/src/ipc/sysipc.c	(revision e9d15d9f0efb393d698245b131a15268dc1cd68f)
@@ -805,5 +805,7 @@
  * @param ucode   Uspace pointer to the top-half pseudocode.
  *
- * @return EPERM or a return code returned by ipc_irq_subscribe().
+ * @return IRQ kernel object capability
+ * @return EPERM
+ * @return Error code returned by ipc_irq_subscribe().
  *
  */
@@ -825,10 +827,10 @@
  *
  */
-sysarg_t sys_ipc_irq_unsubscribe(inr_t inr, devno_t devno)
+sysarg_t sys_ipc_irq_unsubscribe(sysarg_t cap)
 {
 	if (!(perm_get(TASK) & PERM_IRQ_REG))
 		return EPERM;
 	
-	ipc_irq_unsubscribe(&TASK->answerbox, inr, devno);
+	ipc_irq_unsubscribe(&TASK->answerbox, cap);
 	
 	return 0;
Index: kernel/generic/src/kobject/kobject.c
===================================================================
--- kernel/generic/src/kobject/kobject.c	(revision 1c85bae15aa87bd11bf412120eaf4e1906a9ea73)
+++ kernel/generic/src/kobject/kobject.c	(revision e9d15d9f0efb393d698245b131a15268dc1cd68f)
@@ -36,6 +36,7 @@
 #include <proc/task.h>
 #include <synch/spinlock.h>
+#include <abi/errno.h>
 
-void kobject_init(kobject_t *kobj)
+void kobject_initialize(kobject_t *kobj)
 {
 	kobj->type = KOBJECT_TYPE_INVALID;
@@ -66,5 +67,5 @@
 		if (kobj->type > KOBJECT_TYPE_ALLOCATED) {
 			if (kobj->can_reclaim && kobj->can_reclaim(kobj))
-				kobject_init(kobj);
+				kobject_initialize(kobj);
 		}
 		if (kobj->type == KOBJECT_TYPE_INVALID) {
@@ -76,5 +77,5 @@
 	irq_spinlock_unlock(&task->lock, true);
 
-	return KOBJECT_INVALID_CAP;
+	return ELIMIT;
 }
 
@@ -86,5 +87,5 @@
 
 	irq_spinlock_lock(&task->lock, true);
-	kobject_init(&task->kobject[cap]);
+	kobject_initialize(&task->kobject[cap]);
 	irq_spinlock_unlock(&task->lock, true);
 }
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision 1c85bae15aa87bd11bf412120eaf4e1906a9ea73)
+++ kernel/generic/src/proc/task.c	(revision e9d15d9f0efb393d698245b131a15268dc1cd68f)
@@ -50,4 +50,5 @@
 #include <adt/btree.h>
 #include <adt/list.h>
+#include <kobject/kobject.h>
 #include <ipc/ipc.h>
 #include <ipc/ipcrsc.h>
@@ -166,8 +167,6 @@
 	
 	list_initialize(&task->threads);
-
-	int cap;
-	for (cap = 0; cap < MAX_KERNEL_OBJECTS; cap++)
-		kobject_init(&task->kobject[cap]);
+	
+	task->kobject = malloc(sizeof(kobject_t) * MAX_KERNEL_OBJECTS, 0);
 	
 	ipc_answerbox_init(&task->answerbox, task);
@@ -206,4 +205,8 @@
 	task->ucycles = 0;
 	task->kcycles = 0;
+
+	int cap;
+	for (cap = 0; cap < MAX_KERNEL_OBJECTS; cap++)
+		kobject_initialize(&task->kobject[cap]);
 
 	task->ipc_info.call_sent = 0;
@@ -282,4 +285,6 @@
 	as_release(task->as);
 	
+	free(task->kobject);
+
 	slab_free(task_slab, task);
 }
