Index: kernel/generic/src/cap/cap.c
===================================================================
--- kernel/generic/src/cap/cap.c	(revision dd20cbb2102cf289216c9c608ceeb8cdca8749b5)
+++ kernel/generic/src/cap/cap.c	(revision 48bcf4941bbfdcd0432cdae89d208c3fd44aecf5)
@@ -40,9 +40,10 @@
 #include <adt/list.h>
 
-void cap_initialize(cap_t *cap, int handle)
-{
-	cap->type = CAP_TYPE_INVALID;
+static kobject_t *cap_unpublish_locked(task_t *, cap_handle_t, kobject_type_t);
+
+void cap_initialize(cap_t *cap, cap_handle_t handle)
+{
+	cap->state = CAP_STATE_FREE;
 	cap->handle = handle;
-	cap->can_reclaim = NULL;
 	link_initialize(&cap->link);
 }
@@ -58,9 +59,9 @@
 	mutex_initialize(&task->cap_info->lock, MUTEX_PASSIVE);
 
-	for (int i = 0; i < CAP_TYPE_MAX; i++)
-		list_initialize(&task->cap_info->type_list[i]);
-
-	for (int i = 0; i < MAX_CAPS; i++)
-		cap_initialize(&task->cap_info->caps[i], i);
+	for (kobject_type_t t = 0; t < KOBJECT_TYPE_MAX; t++)
+		list_initialize(&task->cap_info->type_list[t]);
+
+	for (cap_handle_t h = 0; h < MAX_CAPS; h++)
+		cap_initialize(&task->cap_info->caps[h], h);
 }
 
@@ -71,5 +72,5 @@
 }
 
-bool caps_apply_to_type(task_t *task, cap_type_t type,
+bool caps_apply_to_kobject_type(task_t *task, kobject_type_t type,
     bool (*cb)(cap_t *, void *), void *arg)
 {
@@ -88,15 +89,5 @@
 }
 
-void caps_lock(task_t *task)
-{
-	mutex_lock(&task->cap_info->lock);
-}
-
-void caps_unlock(task_t *task)
-{
-	mutex_unlock(&task->cap_info->lock);
-}
-
-cap_t *cap_get(task_t *task, int handle, cap_type_t type)
+static cap_t *cap_get(task_t *task, cap_handle_t handle, cap_state_t state)
 {
 	assert(mutex_locked(&task->cap_info->lock));
@@ -104,24 +95,25 @@
 	if ((handle < 0) || (handle >= MAX_CAPS))
 		return NULL;
-	if (task->cap_info->caps[handle].type != type)
+	if (task->cap_info->caps[handle].state != state)
 		return NULL;
 	return &task->cap_info->caps[handle];
 }
 
-int cap_alloc(task_t *task)
-{
-	int handle;
-
-	mutex_lock(&task->cap_info->lock);
-	for (handle = 0; handle < MAX_CAPS; handle++) {
+cap_handle_t cap_alloc(task_t *task)
+{
+	mutex_lock(&task->cap_info->lock);
+	for (cap_handle_t handle = 0; handle < MAX_CAPS; handle++) {
 		cap_t *cap = &task->cap_info->caps[handle];
-		if (cap->type > CAP_TYPE_ALLOCATED) {
-			if (cap->can_reclaim && cap->can_reclaim(cap)) {
-				list_remove(&cap->link);
-				cap_initialize(cap, handle);
-			}
-		}
-		if (cap->type == CAP_TYPE_INVALID) {
-			cap->type = CAP_TYPE_ALLOCATED;
+		/* See if the capability should be garbage-collected */
+		if (cap->state == CAP_STATE_PUBLISHED &&
+		    cap->kobject->ops->reclaim &&
+		    cap->kobject->ops->reclaim(cap->kobject)) {
+			kobject_t *kobj = cap_unpublish_locked(task, handle,
+			    cap->kobject->type);
+			kobject_put(kobj);
+			cap_initialize(&task->cap_info->caps[handle], handle);
+		}
+		if (cap->state == CAP_STATE_FREE) {
+			cap->state = CAP_STATE_ALLOCATED;
 			mutex_unlock(&task->cap_info->lock);
 			return handle;
@@ -133,35 +125,50 @@
 }
 
-void cap_publish(task_t *task, int handle, cap_type_t type, void *kobject)
-{
-	mutex_lock(&task->cap_info->lock);
-	cap_t *cap = cap_get(task, handle, CAP_TYPE_ALLOCATED);
+void
+cap_publish(task_t *task, cap_handle_t handle, kobject_t *kobj)
+{
+	mutex_lock(&task->cap_info->lock);
+	cap_t *cap = cap_get(task, handle, CAP_STATE_ALLOCATED);
 	assert(cap);
-	cap->type = type;
-	cap->kobject = kobject;
-	list_append(&cap->link, &task->cap_info->type_list[type]);
-	mutex_unlock(&task->cap_info->lock);
-}
-
-cap_t *cap_unpublish(task_t *task, int handle, cap_type_t type)
-{
-	cap_t *cap;
-
-	mutex_lock(&task->cap_info->lock);
-	cap = cap_get(task, handle, type);
+	cap->state = CAP_STATE_PUBLISHED;
+	/* Hand over kobj's reference to cap */
+	cap->kobject = kobj;
+	list_append(&cap->link, &task->cap_info->type_list[kobj->type]);
+	mutex_unlock(&task->cap_info->lock);
+}
+
+static kobject_t *
+cap_unpublish_locked(task_t *task, cap_handle_t handle, kobject_type_t type)
+{
+	kobject_t *kobj = NULL;
+
+	cap_t *cap = cap_get(task, handle, CAP_STATE_PUBLISHED);
 	if (cap) {
-		list_remove(&cap->link);
-		cap->type = CAP_TYPE_ALLOCATED;
-	}
-	mutex_unlock(&task->cap_info->lock);
-
-	return cap;
-}
-
-void cap_free(task_t *task, int handle)
+		if (cap->kobject->type == type) {
+			/* Hand over cap's reference to kobj */
+			kobj = cap->kobject;
+			cap->kobject = NULL;
+			list_remove(&cap->link);
+			cap->state = CAP_STATE_ALLOCATED;
+		}
+	}
+
+	return kobj;
+}
+kobject_t *cap_unpublish(task_t *task, cap_handle_t handle, kobject_type_t type)
+{
+
+	mutex_lock(&task->cap_info->lock);
+	kobject_t *kobj = cap_unpublish_locked(task, handle, type);
+	mutex_unlock(&task->cap_info->lock);
+
+	return kobj;
+}
+
+void cap_free(task_t *task, cap_handle_t handle)
 {
 	assert(handle >= 0);
 	assert(handle < MAX_CAPS);
-	assert(task->cap_info->caps[handle].type == CAP_TYPE_ALLOCATED);
+	assert(task->cap_info->caps[handle].state == CAP_STATE_ALLOCATED);
 
 	mutex_lock(&task->cap_info->lock);
@@ -170,4 +177,39 @@
 }
 
+void kobject_initialize(kobject_t *kobj, kobject_type_t type, void *raw,
+    kobject_ops_t *ops)
+{
+	atomic_set(&kobj->refcnt, 1);
+	kobj->type = type;
+	kobj->raw = raw;
+	kobj->ops = ops;
+}
+
+kobject_t *
+kobject_get(struct task *task, cap_handle_t handle, kobject_type_t type)
+{
+	kobject_t *kobj = NULL;
+
+	mutex_lock(&task->cap_info->lock);
+	cap_t *cap = cap_get(task, handle, CAP_STATE_PUBLISHED);
+	if (cap) {
+		if (cap->kobject->type == type) {
+			kobj = cap->kobject;
+			atomic_inc(&kobj->refcnt);
+		}
+	}
+	mutex_unlock(&task->cap_info->lock);
+
+	return kobj;
+}
+
+void kobject_put(kobject_t *kobj)
+{
+	if (atomic_postdec(&kobj->refcnt) == 1) {
+		kobj->ops->destroy(kobj->raw);
+		free(kobj);
+	}
+}
+
 /** @}
  */
Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision dd20cbb2102cf289216c9c608ceeb8cdca8749b5)
+++ kernel/generic/src/ipc/ipc.c	(revision 48bcf4941bbfdcd0432cdae89d208c3fd44aecf5)
@@ -154,7 +154,9 @@
 /** Connect a phone to an answerbox.
  *
- * @param phone Initialized phone structure.
- * @param box   Initialized answerbox structure.
- * @return      True if the phone was connected, false otherwise.
+ * This function must be passed a reference to phone->kobject.
+ *
+ * @param phone  Initialized phone structure.
+ * @param box    Initialized answerbox structure.
+ * @return       True if the phone was connected, false otherwise.
  */
 bool ipc_phone_connect(phone_t *phone, answerbox_t *box)
@@ -169,4 +171,5 @@
 		phone->state = IPC_PHONE_CONNECTED;
 		phone->callee = box;
+		/* Pass phone->kobject reference to box->connected_phones */
 		list_append(&phone->link, &box->connected_phones);
 	}
@@ -174,4 +177,9 @@
 	irq_spinlock_unlock(&box->lock, true);
 	mutex_unlock(&phone->lock);
+
+	if (!active) {
+		/* We still have phone->kobject's reference; drop it */
+		kobject_put(phone->kobject);
+	}
 
 	return active;
@@ -191,4 +199,5 @@
 	phone->state = IPC_PHONE_FREE;
 	atomic_set(&phone->active_calls, 0);
+	phone->kobject = NULL;
 }
 
@@ -456,4 +465,7 @@
 		list_remove(&phone->link);
 		irq_spinlock_unlock(&box->lock, true);
+
+		/* Drop the answerbox reference */
+		kobject_put(phone->kobject);
 		
 		call_t *call = ipc_call_alloc(0);
@@ -658,4 +670,6 @@
 
 			task_release(phone->caller);
+
+			kobject_put(phone->kobject);
 			
 			/* Must start again */
@@ -664,4 +678,5 @@
 		
 		mutex_unlock(&phone->lock);
+		kobject_put(phone->kobject);
 	}
 	
@@ -734,5 +749,5 @@
 static bool phone_cap_wait_cb(cap_t *cap, void *arg)
 {
-	phone_t *phone = (phone_t *) cap->kobject;
+	phone_t *phone = cap->kobject->phone;
 	bool *restart = (bool *) arg;
 
@@ -790,6 +805,6 @@
 	 */
 	restart = false;
-	if (caps_apply_to_type(TASK, CAP_TYPE_PHONE, phone_cap_wait_cb,
-	    &restart)) {
+	if (caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE,
+	    phone_cap_wait_cb, &restart)) {
 		/* Got into cleanup */
 		return;
@@ -810,6 +825,5 @@
 static bool phone_cap_cleanup_cb(cap_t *cap, void *arg)
 {
-	phone_t *phone = (phone_t *) cap->kobject;
-	ipc_phone_hangup(phone);
+	ipc_phone_hangup(cap->kobject->phone);
 	return true;
 }
@@ -840,5 +854,6 @@
 
 	/* Disconnect all our phones ('ipc_phone_hangup') */
-	caps_apply_to_type(TASK, CAP_TYPE_PHONE, phone_cap_cleanup_cb, NULL);
+	caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE,
+	    phone_cap_cleanup_cb, NULL);
 	
 	/* Unsubscribe from any event notifications. */
@@ -846,5 +861,6 @@
 	
 	/* Disconnect all connected IRQs */
-	caps_apply_to_type(TASK, CAP_TYPE_IRQ, irq_cap_cleanup_cb, NULL);
+	caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_IRQ, irq_cap_cleanup_cb,
+	    NULL);
 	
 	/* Disconnect all phones connected to our regular answerbox */
@@ -912,5 +928,5 @@
 static bool print_task_phone_cb(cap_t *cap, void *arg)
 {
-	phone_t *phone = (phone_t *) cap->kobject;
+	phone_t *phone = cap->kobject->phone;
 
 	mutex_lock(&phone->lock);
@@ -963,5 +979,6 @@
 	printf("[phone cap] [calls] [state\n");
 	
-	caps_apply_to_type(task, CAP_TYPE_PHONE, print_task_phone_cb, NULL);
+	caps_apply_to_kobject_type(task, KOBJECT_TYPE_PHONE,
+	    print_task_phone_cb, NULL);
 	
 	irq_spinlock_lock(&task->lock, true);
Index: kernel/generic/src/ipc/ipcrsc.c
===================================================================
--- kernel/generic/src/ipc/ipcrsc.c	(revision dd20cbb2102cf289216c9c608ceeb8cdca8749b5)
+++ kernel/generic/src/ipc/ipcrsc.c	(revision 48bcf4941bbfdcd0432cdae89d208c3fd44aecf5)
@@ -164,41 +164,28 @@
 }
 
-/** Get phone from the current task by capability handle.
- *
- * @param handle  Phone capability handle.
- * @param phone   Place to store pointer to phone.
- *
- * @return  Address of the phone kernel object.
- * @return  NULL if the capability is invalid.
- *
- */
-phone_t *phone_get(task_t *task, int handle)
-{
-	phone_t *phone;
-
-	caps_lock(task);
-	cap_t *cap = cap_get(task, handle, CAP_TYPE_PHONE);
-	phone = (phone_t *) cap->kobject;
-	caps_unlock(task);
-	if (!cap)
-		return NULL;
-	
-	return phone;
-}
-
-phone_t *phone_get_current(int handle)
-{
-	return phone_get(TASK, handle);
-}
-
-static bool phone_can_reclaim(cap_t *cap)
-{
-	assert(cap->type == CAP_TYPE_PHONE);
-
-	phone_t *phone = (phone_t *) cap->kobject;
-
-	return (phone->state == IPC_PHONE_HUNGUP) &&
-	    (atomic_get(&phone->active_calls) == 0);
-}
+static bool phone_reclaim(kobject_t *kobj)
+{
+	bool gc = false;
+
+	mutex_lock(&kobj->phone->lock);
+	if (kobj->phone->state == IPC_PHONE_HUNGUP &&
+	    atomic_get(&kobj->phone->active_calls) == 0)
+		gc = true;
+	mutex_unlock(&kobj->phone->lock);
+
+	return gc;
+}
+
+static void phone_destroy(void *arg)
+{
+	phone_t *phone = (phone_t *) arg;
+	slab_free(phone_slab, phone);
+}
+
+static kobject_ops_t phone_kobject_ops = {
+	.reclaim = phone_reclaim,
+	.destroy = phone_destroy
+};
+
 
 /** Allocate new phone in the specified task.
@@ -209,7 +196,7 @@
  * @return  Negative error code if a new capability cannot be allocated.
  */
-int phone_alloc(task_t *task)
-{
-	int handle = cap_alloc(task);
+cap_handle_t phone_alloc(task_t *task)
+{
+	cap_handle_t handle = cap_alloc(task);
 	if (handle >= 0) {
 		phone_t *phone = slab_alloc(phone_slab, FRAME_ATOMIC);
@@ -218,15 +205,19 @@
 			return ENOMEM;
 		}
-		
+		kobject_t *kobject = malloc(sizeof(kobject_t), FRAME_ATOMIC);
+		if (!kobject) {
+			cap_free(TASK, handle);
+			slab_free(phone_slab, phone);
+			return ENOMEM;
+		}
+
 		ipc_phone_init(phone, task);
 		phone->state = IPC_PHONE_CONNECTING;
+
+		kobject_initialize(kobject, KOBJECT_TYPE_PHONE, phone,
+		    &phone_kobject_ops);
+		phone->kobject = kobject;
 		
-		// FIXME: phase this out eventually
-		mutex_lock(&task->cap_info->lock);
-		cap_t *cap = cap_get(task, handle, CAP_TYPE_ALLOCATED);
-		cap->can_reclaim = phone_can_reclaim;
-		mutex_unlock(&task->cap_info->lock);
-
-		cap_publish(task, handle, CAP_TYPE_PHONE, phone);
+		cap_publish(task, handle, kobject);
 	}
 	
@@ -241,15 +232,14 @@
  *
  */
-void phone_dealloc(int handle)
-{
-	cap_t *cap = cap_unpublish(TASK, handle, CAP_TYPE_PHONE);
-	assert(cap);
-	
-	phone_t *phone = (phone_t *) cap->kobject;
-	
-	assert(phone);
-	assert(phone->state == IPC_PHONE_CONNECTING);
-	
-	slab_free(phone_slab, phone);
+void phone_dealloc(cap_handle_t handle)
+{
+	kobject_t *kobj = cap_unpublish(TASK, handle, KOBJECT_TYPE_PHONE);
+	if (!kobj)
+		return;
+	
+	assert(kobj->phone);
+	assert(kobj->phone->state == IPC_PHONE_CONNECTING);
+	
+	kobject_put(kobj);
 	cap_free(TASK, handle);
 }
@@ -260,18 +250,15 @@
  * @param box     Answerbox to which to connect the phone.
  * @return        True if the phone was connected, false otherwise.
- *
- * The procedure _enforces_ that the user first marks the phone busy (e.g. via
- * phone_alloc) and then connects the phone, otherwise race condition may
- * appear.
- *
- */
-bool phone_connect(int handle, answerbox_t *box)
-{
-	phone_t *phone = phone_get_current(handle);
-	
-	assert(phone);
-	assert(phone->state == IPC_PHONE_CONNECTING);
-	
-	return ipc_phone_connect(phone, box);
+ */
+bool phone_connect(cap_handle_t handle, answerbox_t *box)
+{
+	kobject_t *phone_obj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
+	if (!phone_obj)
+		return false;
+	
+	assert(phone_obj->phone->state == IPC_PHONE_CONNECTING);
+	
+	/* Hand over phone_obj reference to the answerbox */
+	return ipc_phone_connect(phone_obj->phone, box);
 }
 
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision dd20cbb2102cf289216c9c608ceeb8cdca8749b5)
+++ kernel/generic/src/ipc/irq.c	(revision 48bcf4941bbfdcd0432cdae89d208c3fd44aecf5)
@@ -271,4 +271,17 @@
 }
 
+static void irq_destroy(void *arg)
+{
+	irq_t *irq = (irq_t *) arg;
+
+	/* Free up the IRQ code and associated structures. */
+	code_free(irq->notif_cfg.code);
+	slab_free(irq_slab, irq);
+}
+
+static kobject_ops_t irq_kobject_ops = {
+	.destroy = irq_destroy
+};
+
 /** Subscribe an answerbox as a receiving end for IRQ notifications.
  *
@@ -304,5 +317,5 @@
 	 * Allocate and populate the IRQ kernel object.
 	 */
-	int handle = cap_alloc(TASK);
+	cap_handle_t handle = cap_alloc(TASK);
 	if (handle < 0)
 		return handle;
@@ -311,4 +324,11 @@
 	if (!irq) {
 		cap_free(TASK, handle);
+		return ENOMEM;
+	}
+
+	kobject_t *kobject = malloc(sizeof(kobject_t), FRAME_ATOMIC);
+	if (!kobject) {
+		cap_free(TASK, handle);
+		slab_free(irq_slab, irq);
 		return ENOMEM;
 	}
@@ -330,4 +350,5 @@
 	irq_spinlock_lock(&irq->lock, false);
 	
+	irq->notif_cfg.hashed_in = true;
 	hash_table_insert(&irq_uspace_hash_table, key, &irq->link);
 	
@@ -335,5 +356,6 @@
 	irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
 
-	cap_publish(TASK, handle, CAP_TYPE_IRQ, irq);
+	kobject_initialize(kobject, KOBJECT_TYPE_IRQ, irq, &irq_kobject_ops);
+	cap_publish(TASK, handle, kobject);
 	
 	return handle;
@@ -350,26 +372,24 @@
 int ipc_irq_unsubscribe(answerbox_t *box, int handle)
 {
-	cap_t *cap = cap_unpublish(TASK, handle, CAP_TYPE_IRQ);
-	if (!cap)
+	kobject_t *kobj = cap_unpublish(TASK, handle, KOBJECT_TYPE_IRQ);
+	if (!kobj)
 		return ENOENT;
 	
-	irq_t *irq = (irq_t *) cap->kobject;
-	
+	assert(kobj->irq->notif_cfg.answerbox == box);
+
 	irq_spinlock_lock(&irq_uspace_hash_table_lock, true);
-	irq_spinlock_lock(&irq->lock, false);
-	
-	assert(irq->notif_cfg.answerbox == box);
-	
-	/* Remove the IRQ from the uspace IRQ hash table. */
-	hash_table_remove_item(&irq_uspace_hash_table, &irq->link);
-	
-	/* irq->lock unlocked by the hash table remove_callback */
+	irq_spinlock_lock(&kobj->irq->lock, false);
+	
+	if (kobj->irq->notif_cfg.hashed_in) {
+		/* Remove the IRQ from the uspace IRQ hash table. */
+		hash_table_remove_item(&irq_uspace_hash_table,
+		    &kobj->irq->link);
+		kobj->irq->notif_cfg.hashed_in = false;
+	}
+
+	/* kobj->irq->lock unlocked by the hash table remove_callback */
 	irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
-	
-	/* Free up the IRQ code and associated structures. */
-	code_free(irq->notif_cfg.code);
-	
-	/* Free up the IRQ capability and the underlying kernel object. */
-	slab_free(irq_slab, cap->kobject);
+
+	kobject_put(kobj);
 	cap_free(TASK, handle);
 	
Index: kernel/generic/src/ipc/kbox.c
===================================================================
--- kernel/generic/src/ipc/kbox.c	(revision dd20cbb2102cf289216c9c608ceeb8cdca8749b5)
+++ kernel/generic/src/ipc/kbox.c	(revision 48bcf4941bbfdcd0432cdae89d208c3fd44aecf5)
@@ -206,5 +206,5 @@
  * cleanup code.
  *
- * @return Phone capability on success, or negative error code.
+ * @return Phone capability handle on success, or negative error code.
  *
  */
@@ -236,16 +236,19 @@
 	}
 	
-	int cap = phone_alloc(TASK);
-	if (cap < 0) {
-		mutex_unlock(&task->kb.cleanup_lock);
-		return ELIMIT;
-	}
-	
+	cap_handle_t phone_handle = phone_alloc(TASK);
+	if (phone_handle < 0) {
+		mutex_unlock(&task->kb.cleanup_lock);
+		return phone_handle;
+	}
+	
+	kobject_t *phone_obj = kobject_get(TASK, phone_handle,
+	    KOBJECT_TYPE_PHONE);
 	/* Connect the newly allocated phone to the kbox */
-	(void) ipc_phone_connect(phone_get_current(cap), &task->kb.box);
+	/* Hand over phone_obj's reference to ipc_phone_connect() */
+	(void) ipc_phone_connect(phone_obj->phone, &task->kb.box);
 	
 	if (task->kb.thread != NULL) {
 		mutex_unlock(&task->kb.cleanup_lock);
-		return cap;
+		return phone_handle;
 	}
 	
@@ -263,5 +266,5 @@
 	mutex_unlock(&task->kb.cleanup_lock);
 	
-	return cap;
+	return phone_handle;
 }
 
Index: kernel/generic/src/ipc/ops/conctmeto.c
===================================================================
--- kernel/generic/src/ipc/ops/conctmeto.c	(revision dd20cbb2102cf289216c9c608ceeb8cdca8749b5)
+++ kernel/generic/src/ipc/ops/conctmeto.c	(revision 48bcf4941bbfdcd0432cdae89d208c3fd44aecf5)
@@ -1,5 +1,5 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
- * Copyright (c) 2012 Jakub Jermar 
+ * Copyright (c) 2012 Jakub Jermar
  * All rights reserved.
  *
@@ -42,13 +42,16 @@
 static int request_preprocess(call_t *call, phone_t *phone)
 {
-	int cap = phone_alloc(TASK);
+	cap_handle_t phone_handle = phone_alloc(TASK);
 
 	/* Remember the phone capability or the error. */
-	call->priv = cap;
-	if (cap < 0)
-		return ELIMIT;
-		
+	call->priv = phone_handle;
+	if (phone_handle < 0)
+		return phone_handle;
+
 	/* Set arg5 for server */
-	IPC_SET_ARG5(call->data, (sysarg_t) phone_get_current(cap));
+	kobject_t *phone_obj = kobject_get(TASK, phone_handle,
+	    KOBJECT_TYPE_PHONE);
+	/* Hand over phone_obj's reference to ARG5 */
+	IPC_SET_ARG5(call->data, (sysarg_t) phone_obj->phone);
 
 	return EOK;
@@ -57,5 +60,10 @@
 static int request_forget(call_t *call)
 {
-	phone_dealloc(call->priv);
+	cap_handle_t phone_handle = (cap_handle_t) call->priv;
+	phone_dealloc(phone_handle);
+	/* Hand over reference from ARG5 to phone->kobject */
+	phone_t *phone = (phone_t *) IPC_GET_ARG5(call->data);
+	/* Drop phone_obj's reference */
+	kobject_put(phone->kobject);
 	return EOK;
 }
@@ -63,9 +71,14 @@
 static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
 {
+	/* Hand over reference from ARG5 to phone */
 	phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
 
 	/* If the user accepted call, connect */
-	if (IPC_GET_RETVAL(answer->data) == EOK)
+	if (IPC_GET_RETVAL(answer->data) == EOK) {
+		/* Hand over reference from phone to the answerbox */
 		(void) ipc_phone_connect(phone, &TASK->answerbox);
+	} else {
+		kobject_put(phone->kobject);
+	}
 
 	return EOK;
@@ -74,16 +87,16 @@
 static int answer_process(call_t *answer)
 {
-	int cap = (int) answer->priv;
+	cap_handle_t phone_handle = (cap_handle_t) answer->priv;
 
 	if (IPC_GET_RETVAL(answer->data)) {
-		if (cap >= 0) {
+		if (phone_handle >= 0) {
 			/*
 			 * The phone was indeed allocated and now needs
 			 * to be deallocated.
 			 */
-			phone_dealloc(cap);
+			phone_dealloc(phone_handle);
 		}
 	} else {
-		IPC_SET_ARG5(answer->data, cap);
+		IPC_SET_ARG5(answer->data, phone_handle);
 	}
 	
Index: kernel/generic/src/ipc/ops/concttome.c
===================================================================
--- kernel/generic/src/ipc/ops/concttome.c	(revision dd20cbb2102cf289216c9c608ceeb8cdca8749b5)
+++ kernel/generic/src/ipc/ops/concttome.c	(revision 48bcf4941bbfdcd0432cdae89d208c3fd44aecf5)
@@ -1,5 +1,5 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
- * Copyright (c) 2012 Jakub Jermar 
+ * Copyright (c) 2012 Jakub Jermar
  * All rights reserved.
  *
@@ -42,7 +42,7 @@
 static int request_process(call_t *call, answerbox_t *box)
 {
-	int cap = phone_alloc(TASK);
+	cap_handle_t phone_handle = phone_alloc(TASK);
 
-	IPC_SET_ARG5(call->data, cap);
+	IPC_SET_ARG5(call->data, phone_handle);
 	
 	return EOK;
@@ -51,8 +51,8 @@
 static int answer_cleanup(call_t *answer, ipc_data_t *olddata)
 {
-	int cap = (int) IPC_GET_ARG5(*olddata);
+	cap_handle_t phone_handle = (cap_handle_t) IPC_GET_ARG5(*olddata);
 
-	if (cap >= 0)
-		phone_dealloc(cap);
+	if (phone_handle >= 0)
+		phone_dealloc(phone_handle);
 
 	return EOK;
@@ -61,15 +61,18 @@
 static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
 {
-	int cap = (int) IPC_GET_ARG5(*olddata);
+	cap_handle_t phone_handle = (cap_handle_t) IPC_GET_ARG5(*olddata);
 
 	if (IPC_GET_RETVAL(answer->data) != EOK) {
 		/* The connection was not accepted */
 		answer_cleanup(answer, olddata);
-	} else if (cap >= 0) {
+	} else if (phone_handle >= 0) {
 		/* The connection was accepted */
-		if (phone_connect(cap, &answer->sender->answerbox)) {
-			/* Set 'phone hash' as arg5 of response */
+		if (phone_connect(phone_handle, &answer->sender->answerbox)) {
+			/* Set 'phone hash' as ARG5 of response */
+			kobject_t *phone_obj = kobject_get(TASK, phone_handle,
+			    KOBJECT_TYPE_PHONE);
 			IPC_SET_ARG5(answer->data,
-			    (sysarg_t) phone_get_current(cap));
+			    (sysarg_t) phone_obj->phone);
+			kobject_put(phone_obj);
 		} else {
 			/* The answerbox is shutting down. */
Index: kernel/generic/src/ipc/ops/stchngath.c
===================================================================
--- kernel/generic/src/ipc/ops/stchngath.c	(revision dd20cbb2102cf289216c9c608ceeb8cdca8749b5)
+++ kernel/generic/src/ipc/ops/stchngath.c	(revision 48bcf4941bbfdcd0432cdae89d208c3fd44aecf5)
@@ -45,21 +45,24 @@
 	task_t *other_task_s;
 
-	phone_t *sender_phone = phone_get_current(IPC_GET_ARG5(call->data));
-	if (!sender_phone)
+	kobject_t *sender_obj = kobject_get(TASK, IPC_GET_ARG5(call->data),
+	    KOBJECT_TYPE_PHONE);
+	if (!sender_obj)
 		return ENOENT;
 
-	mutex_lock(&sender_phone->lock);
-	if (sender_phone->state != IPC_PHONE_CONNECTED) {
-		mutex_unlock(&sender_phone->lock);
+	mutex_lock(&sender_obj->phone->lock);
+	if (sender_obj->phone->state != IPC_PHONE_CONNECTED) {
+		mutex_unlock(&sender_obj->phone->lock);
+		kobject_put(sender_obj);
 		return EINVAL;
 	}
 
-	other_task_s = sender_phone->callee->task;
+	other_task_s = sender_obj->phone->callee->task;
 
-	mutex_unlock(&sender_phone->lock);
+	mutex_unlock(&sender_obj->phone->lock);
 
 	/* Remember the third party task hash. */
 	IPC_SET_ARG5(call->data, (sysarg_t) other_task_s);
 
+	kobject_put(sender_obj);
 	return EOK;
 }
@@ -71,22 +74,23 @@
 	if (!IPC_GET_RETVAL(answer->data)) {
 		/* The recipient authorized the change of state. */
-		phone_t *recipient_phone;
 		task_t *other_task_s;
 		task_t *other_task_r;
 
-		recipient_phone = phone_get_current(IPC_GET_ARG1(answer->data));
-		if (!recipient_phone) {
+		kobject_t *recipient_obj = kobject_get(TASK,
+		    IPC_GET_ARG1(answer->data), KOBJECT_TYPE_PHONE);
+		if (!recipient_obj) {
 			IPC_SET_RETVAL(answer->data, ENOENT);
 			return ENOENT;
 		}
 
-		mutex_lock(&recipient_phone->lock);
-		if (recipient_phone->state != IPC_PHONE_CONNECTED) {
-			mutex_unlock(&recipient_phone->lock);
+		mutex_lock(&recipient_obj->phone->lock);
+		if (recipient_obj->phone->state != IPC_PHONE_CONNECTED) {
+			mutex_unlock(&recipient_obj->phone->lock);
 			IPC_SET_RETVAL(answer->data, EINVAL);
+			kobject_put(recipient_obj);
 			return EINVAL;
 		}
 
-		other_task_r = recipient_phone->callee->task;
+		other_task_r = recipient_obj->phone->callee->task;
 		other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
 
@@ -109,5 +113,6 @@
 		}
 
-		mutex_unlock(&recipient_phone->lock);
+		mutex_unlock(&recipient_obj->phone->lock);
+		kobject_put(recipient_obj);
 	}
 
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision dd20cbb2102cf289216c9c608ceeb8cdca8749b5)
+++ kernel/generic/src/ipc/sysipc.c	(revision 48bcf4941bbfdcd0432cdae89d208c3fd44aecf5)
@@ -260,5 +260,5 @@
 /** Make a call over IPC and wait for reply.
  *
- * @param phone_cap    Phone capability for the call.
+ * @param handle       Phone capability handle for the call.
  * @param data[inout]  Structure with request/reply data.
  * @param priv         Value to be stored in call->priv.
@@ -268,8 +268,8 @@
  *
  */
-int ipc_req_internal(int phone_cap, ipc_data_t *data, sysarg_t priv)
-{
-	phone_t *phone = phone_get_current(phone_cap);
-	if (!phone)
+int ipc_req_internal(cap_handle_t handle, ipc_data_t *data, sysarg_t priv)
+{
+	kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
+	if (!kobj->phone)
 		return ENOENT;
 	
@@ -278,5 +278,5 @@
 	memcpy(call->data.args, data->args, sizeof(data->args));
 	
-	int rc = request_preprocess(call, phone);
+	int rc = request_preprocess(call, kobj->phone);
 	if (!rc) {
 #ifdef CONFIG_UDEBUG
@@ -285,5 +285,5 @@
 
 		ipc_call_hold(call);
-		rc = ipc_call_sync(phone, call);
+		rc = ipc_call_sync(kobj->phone, call);
 		spinlock_lock(&call->forget_lock);
 		bool forgotten = call->forget;
@@ -312,5 +312,6 @@
 				assert(rc == EINTR);
 			}
-			return rc;	
+			kobject_put(kobj);
+			return rc;
 		}
 
@@ -321,4 +322,5 @@
 	memcpy(data->args, call->data.args, sizeof(data->args));
 	ipc_call_free(call);
+	kobject_put(kobj);
 	
 	return EOK;
@@ -346,10 +348,10 @@
  * the generic function sys_ipc_call_async_slow().
  *
- * @param phone_cap  Phone capability for the call.
- * @param imethod    Interface and method of the call.
- * @param arg1       Service-defined payload argument.
- * @param arg2       Service-defined payload argument.
- * @param arg3       Service-defined payload argument.
- * @param arg4       Service-defined payload argument.
+ * @param handle   Phone capability handle for the call.
+ * @param imethod  Interface and method of the call.
+ * @param arg1     Service-defined payload argument.
+ * @param arg2     Service-defined payload argument.
+ * @param arg3     Service-defined payload argument.
+ * @param arg4     Service-defined payload argument.
  *
  * @return Call hash on success.
@@ -359,13 +361,15 @@
  *
  */
-sysarg_t sys_ipc_call_async_fast(sysarg_t phone_cap, sysarg_t imethod,
+sysarg_t sys_ipc_call_async_fast(sysarg_t handle, sysarg_t imethod,
     sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
 {
-	phone_t *phone = phone_get_current(phone_cap);
-	if (!phone)
+	kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
+	if (!kobj)
 		return IPC_CALLRET_FATAL;
 	
-	if (check_call_limit(phone))
+	if (check_call_limit(kobj->phone)) {
+		kobject_put(kobj);
 		return IPC_CALLRET_TEMPORARY;
+	}
 	
 	call_t *call = ipc_call_alloc(0);
@@ -382,11 +386,12 @@
 	IPC_SET_ARG5(call->data, 0);
 	
-	int res = request_preprocess(call, phone);
+	int res = request_preprocess(call, kobj->phone);
 	
 	if (!res)
-		ipc_call(phone, call);
+		ipc_call(kobj->phone, call);
 	else
-		ipc_backsend_err(phone, call, res);
-	
+		ipc_backsend_err(kobj->phone, call, res);
+	
+	kobject_put(kobj);
 	return (sysarg_t) call;
 }
@@ -394,18 +399,20 @@
 /** Make an asynchronous IPC call allowing to transmit the entire payload.
  *
- * @param phone_cap  Phone capability for the call.
- * @param data       Userspace address of call data with the request.
+ * @param handle  Phone capability for the call.
+ * @param data    Userspace address of call data with the request.
  *
  * @return See sys_ipc_call_async_fast().
  *
  */
-sysarg_t sys_ipc_call_async_slow(sysarg_t phone_cap, ipc_data_t *data)
-{
-	phone_t *phone = phone_get_current(phone_cap);
-	if (!phone)
+sysarg_t sys_ipc_call_async_slow(sysarg_t handle, ipc_data_t *data)
+{
+	kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
+	if (!kobj)
 		return IPC_CALLRET_FATAL;
 
-	if (check_call_limit(phone))
+	if (check_call_limit(kobj->phone)) {
+		kobject_put(kobj);
 		return IPC_CALLRET_TEMPORARY;
+	}
 
 	call_t *call = ipc_call_alloc(0);
@@ -414,14 +421,16 @@
 	if (rc != 0) {
 		ipc_call_free(call);
+		kobject_put(kobj);
 		return (sysarg_t) rc;
 	}
 	
-	int res = request_preprocess(call, phone);
+	int res = request_preprocess(call, kobj->phone);
 	
 	if (!res)
-		ipc_call(phone, call);
+		ipc_call(kobj->phone, call);
 	else
-		ipc_backsend_err(phone, call, res);
-	
+		ipc_backsend_err(kobj->phone, call, res);
+	
+	kobject_put(kobj);
 	return (sysarg_t) call;
 }
@@ -431,16 +440,16 @@
  * Common code for both the fast and the slow version.
  *
- * @param callid     Hash of the call to forward.
- * @param phone_cap  Phone capability to use for forwarding.
- * @param imethod    New interface and method to use for the forwarded call.
- * @param arg1       New value of the first argument for the forwarded call.
- * @param arg2       New value of the second argument for the forwarded call.
- * @param arg3       New value of the third argument for the forwarded call.
- * @param arg4       New value of the fourth argument for the forwarded call.
- * @param arg5       New value of the fifth argument for the forwarded call.
- * @param mode       Flags that specify mode of the forward operation.
- * @param slow       If true, arg3, arg4 and arg5 are considered. Otherwise
- *                   the function considers only the fast version arguments:
- *                   i.e. arg1 and arg2.
+ * @param callid   Hash of the call to forward.
+ * @param handle   Phone capability to use for forwarding.
+ * @param imethod  New interface and method to use for the forwarded call.
+ * @param arg1     New value of the first argument for the forwarded call.
+ * @param arg2     New value of the second argument for the forwarded call.
+ * @param arg3     New value of the third argument for the forwarded call.
+ * @param arg4     New value of the fourth argument for the forwarded call.
+ * @param arg5     New value of the fifth argument for the forwarded call.
+ * @param mode     Flags that specify mode of the forward operation.
+ * @param slow     If true, arg3, arg4 and arg5 are considered. Otherwise
+ *                 the function considers only the fast version arguments:
+ *                 i.e. arg1 and arg2.
  *
  * @return 0 on succes, otherwise an error code.
@@ -449,5 +458,5 @@
  *
  */
-static sysarg_t sys_ipc_forward_common(sysarg_t callid, sysarg_t phone_cap,
+static sysarg_t sys_ipc_forward_common(sysarg_t callid, sysarg_t handle,
     sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
     sysarg_t arg4, sysarg_t arg5, unsigned int mode, bool slow)
@@ -465,6 +474,6 @@
 	int rc;
 
-	phone_t *phone = phone_get_current(phone_cap);
-	if (!phone) {
+	kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
+	if (!kobj) {
 		rc = ENOENT;
 		goto error;
@@ -512,5 +521,5 @@
 	}
 	
-	rc = ipc_forward(call, phone, &TASK->answerbox, mode);
+	rc = ipc_forward(call, kobj->phone, &TASK->answerbox, mode);
 	if (rc != EOK) {
 		after_forward = true;
@@ -518,4 +527,5 @@
 	}
 
+	kobject_put(kobj);
 	return EOK;
 
@@ -528,4 +538,6 @@
 		ipc_answer(&TASK->answerbox, call);
 
+	if (kobj)
+		kobject_put(kobj);
 	return rc;
 }
@@ -540,18 +552,18 @@
  * arguments are not set and these values are ignored.
  *
- * @param callid  Hash of the call to forward.
- * @param phoneid Phone handle to use for forwarding.
- * @param imethod New interface and method to use for the forwarded call.
- * @param arg1    New value of the first argument for the forwarded call.
- * @param arg2    New value of the second argument for the forwarded call.
- * @param mode    Flags that specify mode of the forward operation.
+ * @param callid   Hash of the call to forward.
+ * @param handle   Phone handle to use for forwarding.
+ * @param imethod  New interface and method to use for the forwarded call.
+ * @param arg1     New value of the first argument for the forwarded call.
+ * @param arg2     New value of the second argument for the forwarded call.
+ * @param mode     Flags that specify mode of the forward operation.
  *
  * @return 0 on succes, otherwise an error code.
  *
  */
-sysarg_t sys_ipc_forward_fast(sysarg_t callid, sysarg_t phoneid,
+sysarg_t sys_ipc_forward_fast(sysarg_t callid, sysarg_t handle,
     sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
 {
-	return sys_ipc_forward_common(callid, phoneid, imethod, arg1, arg2, 0, 0,
+	return sys_ipc_forward_common(callid, handle, imethod, arg1, arg2, 0, 0,
 	    0, mode, false); 
 }
@@ -567,5 +579,5 @@
  *
  * @param callid  Hash of the call to forward.
- * @param phoneid Phone handle to use for forwarding.
+ * @param handle  Phone handle to use for forwarding.
  * @param data    Userspace address of the new IPC data.
  * @param mode    Flags that specify mode of the forward operation.
@@ -574,5 +586,5 @@
  *
  */
-sysarg_t sys_ipc_forward_slow(sysarg_t callid, sysarg_t phoneid,
+sysarg_t sys_ipc_forward_slow(sysarg_t callid, sysarg_t handle,
     ipc_data_t *data, unsigned int mode)
 {
@@ -583,5 +595,5 @@
 		return (sysarg_t) rc;
 	
-	return sys_ipc_forward_common(callid, phoneid,
+	return sys_ipc_forward_common(callid, handle,
 	    IPC_GET_IMETHOD(newdata), IPC_GET_ARG1(newdata),
 	    IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
@@ -681,18 +693,21 @@
 /** Hang up a phone.
  *
- * @param phone_cap  Phone capability of the phone to be hung up.
+ * @param handle  Phone capability handle of the phone to be hung up.
  *
  * @return 0 on success or an error code.
  *
  */
-sysarg_t sys_ipc_hangup(sysarg_t phone_cap)
-{
-	phone_t *phone = phone_get_current(phone_cap);
-	if (!phone)
+sysarg_t sys_ipc_hangup(sysarg_t handle)
+{
+	kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
+	if (!kobj)
 		return ENOENT;
 	
-	if (ipc_phone_hangup(phone))
+	if (ipc_phone_hangup(kobj->phone)) {
+		kobject_put(kobj);
 		return -1;
-	
+	}
+	
+	kobject_put(kobj);
 	return 0;
 }
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision dd20cbb2102cf289216c9c608ceeb8cdca8749b5)
+++ kernel/generic/src/proc/task.c	(revision 48bcf4941bbfdcd0432cdae89d208c3fd44aecf5)
@@ -239,7 +239,8 @@
 	if ((ipc_phone_0) &&
 	    (container_check(ipc_phone_0->task->container, task->container))) {
-		int cap = phone_alloc(task);
-		assert(cap == 0);
-		(void) ipc_phone_connect(phone_get(task, 0), ipc_phone_0);
+		cap_handle_t phone_handle = phone_alloc(task);
+		kobject_t *phone_obj = kobject_get(task, phone_handle,
+		    KOBJECT_TYPE_PHONE);
+		(void) ipc_phone_connect(phone_obj->phone, ipc_phone_0);
 	}
 	
