Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision f480d7e1f5cf4ba7a6678d2d63060e7f8756330d)
+++ uspace/drv/bus/isa/isa.c	(revision f2789301293c7a4b55f9cbde30a415bdc4412c5d)
@@ -37,4 +37,5 @@
  */
 
+#include <adt/list.h>
 #include <assert.h>
 #include <stdio.h>
@@ -63,12 +64,24 @@
 #define CHILD_FUN_CONF_PATH "/drv/isa/isa.dev"
 
-/** Obtain soft-state pointer from function node pointer */
-#define ISA_FUN(fnode) ((isa_fun_t *) ((fnode)->driver_data))
+/** Obtain soft-state from device node */
+#define ISA_BUS(dev) ((isa_bus_t *) ((dev)->driver_data))
+
+/** Obtain soft-state from function node */
+#define ISA_FUN(fun) ((isa_fun_t *) ((fun)->driver_data))
 
 #define ISA_MAX_HW_RES 4
 
+typedef struct {
+	fibril_mutex_t mutex;
+	ddf_dev_t *dev;
+	ddf_fun_t *fctl;
+	list_t functions;
+} isa_bus_t;
+
 typedef struct isa_fun {
+	fibril_mutex_t mutex;
 	ddf_fun_t *fnode;
 	hw_resource_list_t hw_resources;
+	link_t bus_link;
 } isa_fun_t;
 
@@ -96,4 +109,5 @@
 
 static int isa_add_device(ddf_dev_t *dev);
+static int isa_dev_remove(ddf_dev_t *dev);
 static int isa_fun_online(ddf_fun_t *fun);
 static int isa_fun_offline(ddf_fun_t *fun);
@@ -102,4 +116,5 @@
 static driver_ops_t isa_ops = {
 	.add_device = &isa_add_device,
+	.dev_remove = &isa_dev_remove,
 	.fun_online = &isa_fun_online,
 	.fun_offline = &isa_fun_offline
@@ -112,18 +127,16 @@
 };
 
-static isa_fun_t *isa_fun_create(ddf_dev_t *dev, const char *name)
-{
-	isa_fun_t *fun = calloc(1, sizeof(isa_fun_t));
+static isa_fun_t *isa_fun_create(isa_bus_t *isa, const char *name)
+{
+	ddf_fun_t *fnode = ddf_fun_create(isa->dev, fun_inner, name);
+	if (fnode == NULL)
+		return NULL;
+
+	isa_fun_t *fun = ddf_fun_data_alloc(fnode, sizeof(isa_fun_t));
 	if (fun == NULL)
 		return NULL;
 
-	ddf_fun_t *fnode = ddf_fun_create(dev, fun_inner, name);
-	if (fnode == NULL) {
-		free(fun);
-		return NULL;
-	}
-
+	fibril_mutex_initialize(&fun->mutex);
 	fun->fnode = fnode;
-	fnode->driver_data = fun;
 	return fun;
 }
@@ -396,5 +409,11 @@
 }
 
-static char *isa_fun_read_info(char *fun_conf, ddf_dev_t *dev)
+static void fun_hw_res_free(isa_fun_t *fun)
+{
+	free(fun->hw_resources.resources);
+	fun->hw_resources.resources = NULL;
+}
+
+static char *isa_fun_read_info(char *fun_conf, isa_bus_t *isa)
 {
 	char *line;
@@ -419,5 +438,5 @@
 		return NULL;
 
-	isa_fun_t *fun = isa_fun_create(dev, fun_name);
+	isa_fun_t *fun = isa_fun_create(isa, fun_name);
 	if (fun == NULL) {
 		free(fun_name);
@@ -452,15 +471,17 @@
 	(void) ddf_fun_bind(fun->fnode);
 
+	list_append(&fun->bus_link, &isa->functions);
+
 	return fun_conf;
 }
 
-static void fun_conf_parse(char *conf, ddf_dev_t *dev)
+static void fun_conf_parse(char *conf, isa_bus_t *isa)
 {
 	while (conf != NULL && *conf != '\0') {
-		conf = isa_fun_read_info(conf, dev);
-	}
-}
-
-static void isa_functions_add(ddf_dev_t *dev)
+		conf = isa_fun_read_info(conf, isa);
+	}
+}
+
+static void isa_functions_add(isa_bus_t *isa)
 {
 	char *fun_conf;
@@ -468,5 +489,5 @@
 	fun_conf = fun_conf_read(CHILD_FUN_CONF_PATH);
 	if (fun_conf != NULL) {
-		fun_conf_parse(fun_conf, dev);
+		fun_conf_parse(fun_conf, isa);
 		free(fun_conf);
 	}
@@ -475,17 +496,30 @@
 static int isa_add_device(ddf_dev_t *dev)
 {
+	isa_bus_t *isa;
+
 	ddf_msg(LVL_DEBUG, "isa_add_device, device handle = %d",
 	    (int) dev->handle);
 
+	isa = ddf_dev_data_alloc(dev, sizeof(isa_bus_t));
+	if (isa == NULL)
+		return ENOMEM;
+
+	fibril_mutex_initialize(&isa->mutex);
+	isa->dev = dev;
+	list_initialize(&isa->functions);
+
 	/* Make the bus device more visible. Does not do anything. */
 	ddf_msg(LVL_DEBUG, "Adding a 'ctl' function");
 
-	ddf_fun_t *ctl = ddf_fun_create(dev, fun_exposed, "ctl");
-	if (ctl == NULL) {
+	fibril_mutex_lock(&isa->mutex);
+
+	isa->fctl = ddf_fun_create(dev, fun_exposed, "ctl");
+	if (isa->fctl == NULL) {
 		ddf_msg(LVL_ERROR, "Failed creating control function.");
 		return EXDEV;
 	}
 
-	if (ddf_fun_bind(ctl) != EOK) {
+	if (ddf_fun_bind(isa->fctl) != EOK) {
+		ddf_fun_destroy(isa->fctl);
 		ddf_msg(LVL_ERROR, "Failed binding control function.");
 		return EXDEV;
@@ -493,6 +527,50 @@
 
 	/* Add functions as specified in the configuration file. */
-	isa_functions_add(dev);
+	isa_functions_add(isa);
 	ddf_msg(LVL_NOTE, "Finished enumerating legacy functions");
+
+	fibril_mutex_unlock(&isa->mutex);
+
+	return EOK;
+}
+
+static int isa_dev_remove(ddf_dev_t *dev)
+{
+	isa_bus_t *isa = ISA_BUS(dev);
+	int rc;
+
+	fibril_mutex_lock(&isa->mutex);
+
+	while (!list_empty(&isa->functions)) {
+		isa_fun_t *fun = list_get_instance(list_first(&isa->functions),
+		    isa_fun_t, bus_link);
+
+		rc = ddf_fun_offline(fun->fnode);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&isa->mutex);
+			ddf_msg(LVL_ERROR, "Failed offlining %s", fun->fnode->name);
+			return rc;
+		}
+
+		rc = ddf_fun_unbind(fun->fnode);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&isa->mutex);
+			ddf_msg(LVL_ERROR, "Failed unbinding %s", fun->fnode->name);
+			return rc;
+		}
+
+		list_remove(&fun->bus_link);
+
+		fun_hw_res_free(fun);
+		ddf_fun_destroy(fun->fnode);
+	}
+
+	if (ddf_fun_unbind(isa->fctl) != EOK) {
+		fibril_mutex_unlock(&isa->mutex);
+		ddf_msg(LVL_ERROR, "Failed unbinding control function.");
+		return EXDEV;
+	}
+
+	fibril_mutex_unlock(&isa->mutex);
 
 	return EOK;
Index: uspace/drv/bus/pci/pciintel/pci.c
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.c	(revision f480d7e1f5cf4ba7a6678d2d63060e7f8756330d)
+++ uspace/drv/bus/pci/pciintel/pci.c	(revision f2789301293c7a4b55f9cbde30a415bdc4412c5d)
@@ -203,8 +203,12 @@
 
 static int pci_add_device(ddf_dev_t *);
+static int pci_fun_online(ddf_fun_t *);
+static int pci_fun_offline(ddf_fun_t *);
 
 /** PCI bus driver standard operations */
 static driver_ops_t pci_ops = {
-	.add_device = &pci_add_device
+	.add_device = &pci_add_device,
+	.fun_online = &pci_fun_online,
+	.fun_offline = &pci_fun_offline,
 };
 
@@ -651,4 +655,16 @@
 }
 
+static int pci_fun_online(ddf_fun_t *fun)
+{
+	ddf_msg(LVL_DEBUG, "pci_fun_online()");
+	return ddf_fun_online(fun);
+}
+
+static int pci_fun_offline(ddf_fun_t *fun)
+{
+	ddf_msg(LVL_DEBUG, "pci_fun_offline()");
+	return ddf_fun_offline(fun);
+}
+
 static void pciintel_init(void)
 {
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision f480d7e1f5cf4ba7a6678d2d63060e7f8756330d)
+++ uspace/lib/drv/generic/driver.c	(revision f2789301293c7a4b55f9cbde30a415bdc4412c5d)
@@ -313,5 +313,6 @@
 	fibril_mutex_lock(&devices_mutex);
 	dev = driver_get_device(devh);
-	dev_add_ref(dev);
+	if (dev != NULL)
+		dev_add_ref(dev);
 	fibril_mutex_unlock(&devices_mutex);
 	
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision f480d7e1f5cf4ba7a6678d2d63060e7f8756330d)
+++ uspace/srv/devman/main.c	(revision f2789301293c7a4b55f9cbde30a415bdc4412c5d)
@@ -320,8 +320,11 @@
 			fibril_rwlock_write_unlock(&device_tree.rwlock);
 			
-			rc = driver_dev_remove(&device_tree, dev);
-			if (rc != EOK) {
-				dev_del_ref(dev);
-				return ENOTSUP;
+			/* If device is owned by driver, ask driver to give it up. */
+			if (dev->state == DEVICE_USABLE) {
+				rc = driver_dev_remove(&device_tree, dev);
+				if (rc != EOK) {
+					dev_del_ref(dev);
+					return ENOTSUP;
+				}
 			}
 			
@@ -332,7 +335,9 @@
 				return EIO;
 			}
+			driver_t *driver = dev->drv;
 			fibril_rwlock_read_unlock(&device_tree.rwlock);
 			
-			detach_driver(&device_tree, dev);
+			if (driver)
+				detach_driver(&device_tree, dev);
 			
 			fibril_rwlock_write_lock(&device_tree.rwlock);
