Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision 5b68e0ca93e8b5310f537cf69218025800ed6aab)
+++ uspace/drv/bus/isa/isa.c	(revision deac215ea66a4a2ddb5875cf4489fe576060ec0d)
@@ -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;
