Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision a9abe5fc26f08c64433355741f665bc2b7db4789)
+++ uspace/srv/devman/devman.c	(revision 80a96d2355e43d996baf70b026fae98a9d19add6)
@@ -878,5 +878,27 @@
 	
 	return retval;
-
+}
+
+int driver_dev_gone(dev_tree_t *tree, dev_node_t *dev)
+{
+	async_exch_t *exch;
+	sysarg_t retval;
+	driver_t *drv;
+	devman_handle_t handle;
+	
+	assert(dev != NULL);
+	
+	log_msg(LVL_DEBUG, "driver_dev_gone(%p)", dev);
+	
+	fibril_rwlock_read_lock(&tree->rwlock);
+	drv = dev->drv;
+	handle = dev->handle;
+	fibril_rwlock_read_unlock(&tree->rwlock);
+	
+	exch = async_exchange_begin(drv->sess);
+	retval = async_req_1_0(exch, DRIVER_DEV_GONE, handle);
+	async_exchange_end(exch);
+	
+	return retval;
 }
 
Index: uspace/srv/devman/devman.h
===================================================================
--- uspace/srv/devman/devman.h	(revision a9abe5fc26f08c64433355741f665bc2b7db4789)
+++ uspace/srv/devman/devman.h	(revision 80a96d2355e43d996baf70b026fae98a9d19add6)
@@ -263,4 +263,5 @@
 extern bool start_driver(driver_t *);
 extern int driver_dev_remove(dev_tree_t *, dev_node_t *);
+extern int driver_dev_gone(dev_tree_t *, dev_node_t *);
 extern int driver_fun_online(dev_tree_t *, fun_node_t *);
 extern int driver_fun_offline(dev_tree_t *, fun_node_t *);
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision a9abe5fc26f08c64433355741f665bc2b7db4789)
+++ uspace/srv/devman/main.c	(revision 80a96d2355e43d996baf70b026fae98a9d19add6)
@@ -316,10 +316,13 @@
 		if (fun->child != NULL) {
 			dev_node_t *dev = fun->child;
+			device_state_t dev_state;
 			
 			dev_add_ref(dev);
+			dev_state = dev->state;
+			
 			fibril_rwlock_write_unlock(&device_tree.rwlock);
-			
+
 			/* If device is owned by driver, ask driver to give it up. */
-			if (dev->state == DEVICE_USABLE) {
+			if (dev_state == DEVICE_USABLE) {
 				rc = driver_dev_remove(&device_tree, dev);
 				if (rc != EOK) {
@@ -333,6 +336,8 @@
 			if (!list_empty(&dev->functions)) {
 				fibril_rwlock_read_unlock(&device_tree.rwlock);
+				dev_del_ref(dev);
 				return EIO;
 			}
+			
 			driver_t *driver = dev->drv;
 			fibril_rwlock_read_unlock(&device_tree.rwlock);
@@ -579,5 +584,4 @@
 	int rc;
 	
-	
 	fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
 	if (fun == NULL) {
@@ -598,9 +602,53 @@
 	
 	if (fun->ftype == fun_inner) {
-		/* Handle possible descendants */
-		/* TODO - This is a surprise removal */
+		/* This is a surprise removal. Handle possible descendants */
 		if (fun->child != NULL) {
-			log_msg(LVL_WARN, "devman_remove_function(): not handling "
-			    "descendants\n");
+			dev_node_t *dev = fun->child;
+			device_state_t dev_state;
+			int gone_rc;
+			
+			dev_add_ref(dev);
+			dev_state = dev->state;
+			
+			fibril_rwlock_write_unlock(&device_tree.rwlock);
+			
+			/* If device is owned by driver, inform driver it is gone. */
+			if (dev_state == DEVICE_USABLE)
+				gone_rc = driver_dev_gone(&device_tree, dev);
+			else
+				gone_rc = EOK;
+			
+			fibril_rwlock_read_lock(&device_tree.rwlock);
+			
+			/* Verify that driver succeeded and removed all functions */
+			if (gone_rc != EOK || !list_empty(&dev->functions)) {
+				log_msg(LVL_ERROR, "Driver did not remove "
+				    "functions for device that is gone. "
+				    "Device node is now defunct.");
+				
+				/*
+				 * Not much we can do but mark the device
+				 * node as having invalid state. This
+				 * is a driver bug.
+				 */
+				dev->state = DEVICE_INVALID;
+				fibril_rwlock_read_unlock(&device_tree.rwlock);
+				dev_del_ref(dev);
+				return;
+			}
+			
+			driver_t *driver = dev->drv;
+			fibril_rwlock_read_unlock(&device_tree.rwlock);
+			
+			if (driver)
+				detach_driver(&device_tree, dev);
+			
+			fibril_rwlock_write_lock(&device_tree.rwlock);
+			remove_dev_node(&device_tree, dev);
+			
+			/* Delete ref created when node was inserted */
+			dev_del_ref(dev);
+			/* Delete ref created by dev_add_ref(dev) above */
+			dev_del_ref(dev);
 		}
 	} else {
