diff --git a/Makefile b/Makefile
index acf30dc1c502706a173b38430864690dd7b1d2a6..c0c47ed8572fdb7076379e03e017cfb70654c01e 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,8 @@ CCFLAGS+=-Wall -Werror -I$(shell pwd) -g
 LDFLAGS+=-L$(shell pwd)/build/ -lmoberg
 MODULES:=$(wildcard modules/*)
 export CCFLAGS LDFLAGS
-LDFLAGS_parse_config=-ldl -export-dynamic
+LDFLAGS_parse_config=-ldl
+#-export-dynamic
 
 all: $(LIBRARIES:%=build/%) $(MODULES) 
 	echo $(MODULES)
diff --git a/moberg.c b/moberg.c
index 59de337df28ae1d040e9933a4bb8c4c43a3ba1a1..f66eac786437ad2640b5fa2774b80e11d6adcdfe 100644
--- a/moberg.c
+++ b/moberg.c
@@ -14,19 +14,66 @@
 #include <moberg_config.h>
 #include <moberg_parser.h>
 
-struct moberg_digital_in_t {
-  int index;
-  char *driver;
-};
+static struct deferred_action {
+  struct deferred_action *next;
+  int (*action)(void *param);
+  void *param;
+} *deferred_action = NULL;
 
 struct moberg {
   struct moberg_config *config;
-  struct {
-    int count;
-    struct moberg_digital_in_t *value;
-  } digital_in;
+  struct channel_list {
+    int capacity;
+    struct moberg_channel **value;
+  } analog_in, analog_out, digital_in, digital_out, encoder_in;
 };
 
+static int channel_list_set(struct channel_list *list,
+                            int index,
+                            struct moberg_channel *value)
+{
+  if (list->capacity <= index) {
+    int capacity;
+    for (capacity = 2 ; capacity <= index ; capacity *= 2);
+    void *new = realloc(list->value, capacity * sizeof(**list->value));
+    if (!new) {
+      goto err;
+    }
+    void *p = new + list->capacity * sizeof(*list->value);
+    memset(p, 0, (capacity - list->capacity) * sizeof(**list->value));
+    list->value = new;
+    list->capacity = capacity;
+  }
+
+  if (0 <= index && index < list->capacity) {
+    list->value[index] = value;
+    return 1;
+  }
+err:
+  return 0;
+}
+                                   
+static int channel_list_get(struct channel_list *list,
+                            int index,
+                            struct moberg_channel **value)
+{
+  if (0 <= index && index < list->capacity) {
+    *value = list->value[index];
+    return 1;
+  }
+  return 0;
+}
+
+static void channel_list_free(struct channel_list *list)
+{
+  for (int i = 0 ; i < list->capacity ; i++) {
+    if (list->value[i]) {
+      list->value[i]->down(list->value[i]);
+    }
+  }
+  free(list->value);
+}
+
 static void parse_config_at(
   struct moberg *moberg,
   int dirfd,
@@ -88,12 +135,77 @@ static void parse_config_dir_at(
   
 }
 
+static int install_channel(struct moberg *moberg,
+                           int index,
+                           struct moberg_device* device,
+                           struct moberg_channel *channel)
+{
+  fprintf(stderr, "CHAN %p %d %d\n", channel, channel->kind, index);
+  if (channel) {
+    struct moberg_channel *old = NULL;
+    switch (channel->kind) {
+      case chan_ANALOGIN:
+        channel_list_get(&moberg->analog_in, index, &old);
+        break;
+      case chan_ANALOGOUT:
+        channel_list_get(&moberg->analog_out, index, &old);
+        break;
+      case chan_DIGITALIN:
+        channel_list_get(&moberg->digital_in, index, &old);
+        break;
+      case chan_DIGITALOUT:
+        channel_list_get(&moberg->digital_out, index, &old);
+        break;
+      case chan_ENCODERIN:
+        channel_list_get(&moberg->encoder_in, index, &old);
+        break;
+    }
+    if (old) {
+      old->down(old);
+    }
+    channel->up(channel);
+    /* TODO: Clean up old channel */
+    switch (channel->kind) {
+      case chan_ANALOGIN:
+        if (! channel_list_set(&moberg->analog_in, index, channel)) {
+          goto err;
+        }
+        break;
+      case chan_ANALOGOUT:
+        if (! channel_list_set(&moberg->analog_out, index, channel)) {
+          goto err;
+        }
+        break;
+      case chan_DIGITALIN:
+        if (! channel_list_set(&moberg->digital_in, index, channel)) {
+          goto err;
+        }
+        break;
+      case chan_DIGITALOUT:
+        if (! channel_list_set(&moberg->digital_out, index, channel)) {
+          goto err;
+        }
+        break;
+      case chan_ENCODERIN:
+        if (! channel_list_set(&moberg->encoder_in, index, channel)) {
+          goto err;
+        }
+        break;
+    }
+  }
+  return 1;
+err:
+  return 0;
+}
+
 static int install_config(struct moberg *moberg)
 {
-  struct moberg_install_channels install = {
-    .context=moberg
+  struct moberg_channel_install install = {
+    .context=moberg,
+    .channel=install_channel
   };
   return moberg_config_install_channels(moberg->config, &install);
+  /* TODO cleanup unused devices...*/
 }
 
 struct moberg *moberg_new(
@@ -104,6 +216,16 @@ struct moberg *moberg_new(
     fprintf(stderr, "Failed to allocate moberg struct\n");
     goto err;
   }
+  result->analog_in.capacity = 0;
+  result->analog_in.value = NULL;
+  result->analog_out.capacity = 0;
+  result->analog_out.value = NULL;
+  result->digital_in.capacity = 0;
+  result->digital_in.value = NULL;
+  result->digital_out.capacity = 0;
+  result->digital_out.value = NULL;
+  result->encoder_in.capacity = 0;
+  result->encoder_in.value = NULL;
   if (config) {
     result->config = config;
   } else {
@@ -118,7 +240,6 @@ struct moberg *moberg_new(
         parse_config_at(result, dirfd1, "moberg.conf");
         int dirfd2 = openat(dirfd1, "moberg.d", O_DIRECTORY);
         if (dirfd2 >= 0) { 
-          parse_config_dir_at(result, dirfd2);
           parse_config_dir_at(result, dirfd2);
           close(dirfd2);
         }
@@ -141,8 +262,20 @@ void moberg_free(struct moberg *moberg)
 {
   if (moberg) {
     moberg_config_free(moberg->config);
+    channel_list_free(&moberg->analog_in);
+    channel_list_free(&moberg->analog_out);
+    channel_list_free(&moberg->digital_in);
+    channel_list_free(&moberg->digital_out);
+    channel_list_free(&moberg->encoder_in);
     free(moberg);
   }
+  while (deferred_action) {
+    fprintf(stderr, "RUNNING deferred\n");
+    struct deferred_action *deferred = deferred_action;
+    deferred_action = deferred_action->next;
+    deferred->action(deferred->param);
+    free(deferred);
+  }
 }
 
 enum moberg_status moberg_start(
@@ -160,3 +293,16 @@ enum moberg_status moberg_stop(
   return moberg_OK;
 }
 
+void moberg_deferred_action(
+  int (*action)(void *param),
+  void *param)
+{
+  struct deferred_action *deferred = malloc(sizeof(*deferred));
+  if (deferred) {
+    fprintf(stderr, "DEFERRED %p %p\n", action, param);
+    deferred->next = deferred_action;
+    deferred->action = action;
+    deferred->param = param;
+    deferred_action = deferred;
+  }
+}
diff --git a/moberg_config.c b/moberg_config.c
index 98491e068497723b9489bc6ece7caa842435e001..aac3855000b642f256850d527f04b534a2e5fa05 100644
--- a/moberg_config.c
+++ b/moberg_config.c
@@ -2,71 +2,12 @@
 #include <string.h>
 #include <moberg_config.h>
 
-#define LIST_COND_GROW(LIST, INDEX, ONERR)                                \
-  ({                                                                    \
-    if (LIST.capacity <= INDEX) {                                       \
-      int new_cap;                                                      \
-      for (new_cap = 2 ; new_cap <= INDEX ; new_cap *= 2);              \
-      void *new = realloc(LIST.value, new_cap * sizeof(*LIST.value));   \
-      if (! new) { ONERR; }                                             \
-      void *p = new + LIST.capacity * sizeof(*LIST.value);              \
-      memset(p, 0, (new_cap - LIST.capacity) * sizeof(*LIST.value));    \
-      LIST.value = new;                                                 \
-      LIST.capacity= new_cap;                                           \
-    }                                                                   \
-  })
-
-#define LIST_SET(LIST, INDEX, VALUE, ONERR)       \
-  ( LIST_COND_GROW(LIST, INDEX, ONERR),           \
-    LIST.value[INDEX] = VALUE )
-
-#define LIST_GET(LIST, INDEX, VALUE, ONERR)       \
-  ( LIST_COND_GROW(LIST, INDEX, ONERR),           \
-    LIST.value[INDEX] )
-
 struct moberg_config
 {
   struct device_entry {
     struct device_entry *next;
     struct moberg_device *device;
-  } *device;
-#if 0
-  struct  {
-    int capacity;
-    struct analog_in_entry {
-      struct moberg_device* device;
-      struct moberg_device_analog_in *channel;
-    } *value;
-  } analog_in;
-  struct  {
-    int capacity;
-    struct analog_out_entry {
-      struct moberg_device* device;
-      struct moberg_device_analog_out *channel;
-    } *value;
-  } analog_out;
-  struct  {
-    int capacity;
-    struct digital_in_entry {
-      struct moberg_device* device;
-      struct moberg_device_digital_in *channel;
-    } *value;
-  } digital_in;
-  struct  {
-    int capacity;
-    struct digital_out_entry {
-      struct moberg_device* device;
-      struct moberg_device_digital_out *channel;
-    } *value;
-  } digital_out;
-  struct  {
-    int capacity;
-    struct encoder_in_entry {
-      struct moberg_device* device;
-      struct moberg_device_encoder_in *channel;
-    } *value;
-  } encoder_in;
-#endif
+  } *device_head, **device_tail;
 };
 
 struct moberg_config *moberg_config_new()
@@ -74,19 +15,8 @@ struct moberg_config *moberg_config_new()
   struct moberg_config *result = malloc(sizeof *result);
 
   if (result) {
-    result->device = NULL;
-#if 0
-    result->analog_in.capacity = 0;
-    result->analog_in.value = NULL;
-    result->analog_out.capacity = 0;
-    result->analog_out.value = NULL;
-    result->digital_in.capacity = 0;
-    result->digital_in.value = NULL;
-    result->digital_out.capacity = 0;
-    result->digital_out.value = NULL;
-    result->encoder_in.capacity = 0;
-    result->encoder_in.value = NULL;
-#endif
+    result->device_head = NULL;
+    result->device_tail = &result->device_head;
   }
   
   return result;
@@ -94,31 +24,30 @@ struct moberg_config *moberg_config_new()
 
 void moberg_config_free(struct moberg_config *config)
 {
-  struct device_entry *entry = config->device;
+  struct device_entry *entry = config->device_head;
   while (entry) {
     struct device_entry *tmp = entry;
     entry = entry->next;
     moberg_device_free(tmp->device);
     free(tmp);
   }
-#if 0
-  free(config->analog_in.value);
-  free(config->analog_out.value);
-  free(config->digital_in.value);
-  free(config->digital_out.value);
-  free(config->encoder_in.value);
-#endif
   free(config);
 }
 
 int moberg_config_join(struct moberg_config *dest,
                        struct moberg_config *src)
 {
-  if (src && dest) {   
-    struct device_entry **tail;
-    for (tail = &dest->device ; *tail ; tail = &(*tail)->next) { }
-    *tail = src->device;
-    src->device = NULL;
+  if (src && dest) {
+    while (src->device_head) {
+      struct device_entry *d = src->device_head;
+      src->device_head = d->next;
+      if (! src->device_head) {
+        src->device_tail = &src->device_head;
+      }
+        
+      *dest->device_tail = d;
+      dest->device_tail = &d->next;
+    }
     return 1;
   }
   return 0;
@@ -129,79 +58,25 @@ int moberg_config_add_device(struct moberg_config *config,
 {
   struct device_entry *entry = malloc(sizeof(*entry));
 
-  entry->next = config->device;
+  if (! entry) { goto err; }
+  entry->next = NULL;
   entry->device = device;
-  config->device = entry;
+  *config->device_tail = entry;
+  config->device_tail = &entry->next;
 
   return 1;
+err:
+  return 0;
 }
 
 int moberg_config_install_channels(struct moberg_config *config,
-                                   struct moberg_install_channels *install)
+                                   struct moberg_channel_install *install)
 {
-  return moberg_device_install_channels(config->device->device, install);
+  int result = 1;
+  for (struct device_entry *d = config->device_head ; d ; d = d->next) {
+    result &= moberg_device_install_channels(d->device, install);
+  }
+  return result;
 }
 
 
-#if 0
-int moberg_config_add_analog_in(struct moberg_config *config,
-                                int index,
-                                struct moberg_device* device,
-                                struct moberg_device_analog_in *channel)
-{
-  struct analog_in_entry e = { device, channel };
-  LIST_SET(config->analog_in, index, e, goto err);
-  return 1;
-err:
-  return 0;
-}
-                            
-int moberg_config_add_analog_out(struct moberg_config *config,
-                                 int index,
-                                 struct moberg_device* device,
-                                 struct moberg_device_analog_out *channel)
-{
-  struct analog_out_entry e = { device, channel };
-  LIST_SET(config->analog_out, index, e, goto err);
-  return 1;
-err:
-  return 0;
-}
-                            
-int moberg_config_add_digital_in(struct moberg_config *config,
-                                int index,
-                                struct moberg_device* device,
-                                struct moberg_device_digital_in *channel)
-{
-  struct digital_in_entry e = { device, channel };
-  LIST_SET(config->digital_in, index, e, goto err);
-  return 1;
-err:
-  return 0;
-}
-                            
-int moberg_config_add_digital_out(struct moberg_config *config,
-                                 int index,
-                                 struct moberg_device* device,
-                                 struct moberg_device_digital_out *channel)
-{
-  struct digital_out_entry e = { device, channel };
-  LIST_SET(config->digital_out, index, e, goto err);
-  return 1;
-err:
-  return 0;
-}
-                            
-int moberg_config_add_encoder_in(struct moberg_config *config,
-                                int index,
-                                struct moberg_device* device,
-                                struct moberg_device_encoder_in *channel)
-{
-  struct encoder_in_entry e = { device, channel };
-  LIST_SET(config->encoder_in, index, e, goto err);
-  return 1;
-err:
-  return 0;
-}
-                            
-#endif
diff --git a/moberg_config.h b/moberg_config.h
index 25401c303740abea1336a370cc3dfbd2929fb5a5..1aae2e4dbd0489415c2ad192e8a6c4fb3d2ffc1e 100644
--- a/moberg_config.h
+++ b/moberg_config.h
@@ -15,33 +15,6 @@ int moberg_config_add_device(struct moberg_config *config,
                              struct moberg_device *device);
 
 int moberg_config_install_channels(struct moberg_config *config,
-                                   struct moberg_install_channels *install);
-
-#if 0
-int moberg_config_add_analog_in(struct moberg_config *config,
-                                int index,
-                                struct moberg_device* device,
-                                struct moberg_device_analog_in *channel);
-                            
-int moberg_config_add_analog_out(struct moberg_config *config,
-                                 int index,
-                                 struct moberg_device* device,
-                                 struct moberg_device_analog_out *channel);
-                            
-int moberg_config_add_digital_in(struct moberg_config *config,
-                                 int index,
-                                 struct moberg_device* device,
-                                 struct moberg_device_digital_in *channel);
-                            
-int moberg_config_add_digital_out(struct moberg_config *config,
-                                  int index,
-                                  struct moberg_device* device,
-                                  struct moberg_device_digital_out *channel);
-                            
-int moberg_config_add_encoder_in(struct moberg_config *config,
-                                 int index,
-                                 struct moberg_device* device,
-                                 struct moberg_device_encoder_in *channel);
-# endif
+                                   struct moberg_channel_install *install);
 
 #endif
diff --git a/moberg_device.c b/moberg_device.c
index 0d7226e5f36a1c96a48926cafd9c832a9d6862de..a6e6d8649a6ab915552e01e74c165d62e5417c0d 100644
--- a/moberg_device.c
+++ b/moberg_device.c
@@ -4,25 +4,26 @@
 #include <dlfcn.h>
 #include <moberg_config.h>
 #include <moberg_device.h>
+#include <moberg_channel.h>
 
 struct moberg_device {
-  void *driver_handle;
   struct moberg_device_driver driver;
-  struct moberg_device_config *device_config;
+  struct moberg_device_context *device_context;
   struct channel_list {
     struct channel_list *next;
     enum moberg_channel_kind kind;
     int index;
     union channel {
-      struct moberg_device_analog_in *analog_in;
-      struct moberg_device_analog_out *analog_out;
-      struct moberg_device_digital_in *digital_in;
-      struct moberg_device_digital_out *digital_out;
-      struct moberg_device_encoder_in *encoder_in;
+      struct moberg_channel_analog_in *analog_in;
+      struct moberg_channel_analog_out *analog_out;
+      struct moberg_channel_digital_in *digital_in;
+      struct moberg_channel_digital_out *digital_out;
+      struct moberg_channel_encoder_in *encoder_in;
+      struct moberg_channel *channel;
     } u;
   } *channel_head, **channel_tail;
   struct map_range {
-    struct moberg_config *config;
+    struct moberg_device *device;
     enum moberg_channel_kind kind;
     int min;
     int max;
@@ -52,15 +53,21 @@ struct moberg_device *moberg_device_new(const char *driver)
     fprintf(stderr, "Could not allocate result for %s\n", name);
     goto dlclose_driver;
   }
-  result->driver_handle = handle;
   result->driver = *device_driver;
-  result->device_config = NULL;
+  result->device_context = result->driver.new(dlclose, handle);
+  if (result->device_context) {
+    result->driver.up(result->device_context);
+  } else {
+    fprintf(stderr, "Could not allocate context for %s\n", name);
+    goto free_result;
+  }
   result->channel_head = NULL;
   result->channel_tail = &result->channel_head;
   result->range = NULL;
-  
   goto free_name;
   
+free_result:
+  free(result);
 dlclose_driver:
   dlclose(handle);
 free_name:
@@ -78,48 +85,15 @@ void moberg_device_free(struct moberg_device *device)
     free(channel);
     channel = next;
   }
-  device->driver.config_free(device->device_config);
-  free(device->device_config);
-  dlclose(device->driver_handle);
+  int use = device->driver.down(device->device_context);
+  fprintf(stderr, "USE: %d\n", use);
   free(device);
 }
 
 int moberg_device_parse_config(struct moberg_device *device,
-                               struct moberg_parser_context *context)
-{
-  return device->driver.parse_config(device, context);
-}
-
-int moberg_device_set_config(struct moberg_device *device,
-                             struct moberg_device_config *config)
+                               struct moberg_parser_context *parser)
 {
-  if (device->device_config) {
-    device->driver.config_free(device->device_config);
-    free(device->device_config);
-  }
-  device->device_config = config;
-  return 1;
-}
-
-int moberg_device_parse_map(struct moberg_device* device,
-                            struct moberg_config *config,
-                            struct moberg_parser_context *context,
-                            enum moberg_channel_kind kind,
-                            int min,
-                            int max)
-{
-  int result;
-  struct map_range r = {
-    .config=config,
-    .kind=kind,
-    .min=min,
-    .max=max
-  };
-  device->range = &r;
-  result = device->driver.parse_map(device, context, kind);
-  device->range = NULL;
-  printf("RRR %d %d\n", r.min, r.max);
-  return result;
+  return device->driver.parse_config(device->device_context, parser);
 }
 
 static int add_channel(struct moberg_device* device,
@@ -141,7 +115,7 @@ err:
 }
 
 int moberg_device_add_analog_in(struct moberg_device* device,
-                                struct moberg_device_analog_in *channel)
+                                struct moberg_channel_analog_in *channel)
 {
   int result = 0;
   
@@ -156,7 +130,7 @@ int moberg_device_add_analog_in(struct moberg_device* device,
 }
                             
 int moberg_device_add_analog_out(struct moberg_device* device,
-                                 struct moberg_device_analog_out *channel)
+                                 struct moberg_channel_analog_out *channel)
 {
   int result = 0;
   
@@ -171,7 +145,7 @@ int moberg_device_add_analog_out(struct moberg_device* device,
 }
                             
 int moberg_device_add_digital_in(struct moberg_device* device,
-                                struct moberg_device_digital_in *channel)
+                                struct moberg_channel_digital_in *channel)
 {
   int result = 0;
   
@@ -186,7 +160,7 @@ int moberg_device_add_digital_in(struct moberg_device* device,
 }
                             
 int moberg_device_add_digital_out(struct moberg_device* device,
-                                 struct moberg_device_digital_out *channel)
+                                 struct moberg_channel_digital_out *channel)
 {
   int result = 0;
   
@@ -201,7 +175,7 @@ int moberg_device_add_digital_out(struct moberg_device* device,
 }
                             
 int moberg_device_add_encoder_in(struct moberg_device* device,
-                                struct moberg_device_encoder_in *channel)
+                                 struct moberg_channel_encoder_in *channel)
 {
   int result = 0;
   
@@ -215,10 +189,112 @@ int moberg_device_add_encoder_in(struct moberg_device* device,
   return result;
 }
 
+static int map(struct moberg_device* device,
+               struct moberg_channel *channel)
+{
+  int result = 0;
+ 
+  if (device->range->kind == channel->kind &&
+      device->range->min <= device->range->max) {
+    printf("XX Mapping %d\n", device->range->min);
+    result = add_channel(device, device->range->kind, device->range->min,
+                         (union channel) { .channel=channel });
+    device->range->min++;
+  }
+  return result;
+  
+}
+
+int moberg_device_parse_map(struct moberg_device* device,
+                            struct moberg_parser_context *parser,
+                            enum moberg_channel_kind kind,
+                            int min,
+                            int max)
+{
+  int result;
+  struct map_range r = {
+    .device=device,
+    .kind=kind,
+    .min=min,
+    .max=max
+  };
+  struct moberg_channel_map map_channel = {
+    .device=device,
+#if 0
+    .analog_in=moberg_device_add_analog_in,
+    .analog_out=moberg_device_add_analog_out,
+    .digital_in=moberg_device_add_digital_in,
+    .digital_out= moberg_device_add_digital_out,
+    .encoder_in= moberg_device_add_encoder_in,
+#endif
+    .map=map
+  };
+  
+  device->range = &r;
+  result = device->driver.parse_map(device->device_context, parser,
+                                    kind, &map_channel);
+  device->range = NULL;
+  printf("RRR %d %d\n", r.min, r.max);
+  return result;
+}
+
 int moberg_device_install_channels(struct moberg_device *device,
-                                   struct moberg_install_channels *install)
+                                   struct moberg_channel_install *install)
 {
+  
   printf("INSTALL\n");
+  struct channel_list *channel = device->channel_head;
+  while (channel) {
+    struct channel_list *next;
+    next = channel->next;
+    install->channel(install->context,
+                     channel->index,
+                     device,
+                     channel->u.channel);
+    switch (channel->kind) {
+      case chan_ANALOGIN: {
+/*
+        install->analog_in(install->context,
+                           channel->index,
+                           device,
+                           channel->u.analog_in);
+*/
+      } break;
+      case chan_ANALOGOUT:  {
+/*
+        install->analog_out(install->context,
+                            channel->index,
+                            device,
+                            channel->u.analog_out);
+*/
+      } break;
+      case chan_DIGITALIN:  {
+/*
+        install->digital_in(install->context,
+                            channel->index,
+                            device,
+                            channel->u.digital_in);
+*/
+      } break;
+      case chan_DIGITALOUT:  {
+/*
+        install->digital_out(install->context,
+                             channel->index,
+                             device,
+                             channel->u.digital_out);
+*/
+      } break;
+      case chan_ENCODERIN: {
+/*
+        install->encoder_in(install->context,
+                            channel->index,
+                            device,
+                            channel->u.encoder_in);
+*/
+      } break;
+    }
+    channel = next;
+  }
   return 1;
 }
 
diff --git a/moberg_device.h b/moberg_device.h
index 275c540b21abd5e6e0d5c9cc86bff88e2c36f1e5..6a5085eefed7c20bacb59aa89ab320cfe63475e0 100644
--- a/moberg_device.h
+++ b/moberg_device.h
@@ -1,76 +1,32 @@
 #ifndef __MOBERG_DEVICE_H__
 #define __MOBERG_DEVICE_H__
 
+struct moberg_device;
+struct moberg_device_context;
+
 #include <moberg.h>
 #include <moberg_config.h>
 #include <moberg_parser.h>
-
-enum moberg_channel_kind {
-    chan_ANALOGIN,
-    chan_ANALOGOUT,
-    chan_DIGITALIN,
-    chan_DIGITALOUT,
-    chan_ENCODERIN
-};
-
-struct moberg_device_analog_in {
-  struct moberg_device_analog_in_context *context;
-  int (*open)(struct moberg_device_analog_in_context *);
-  int (*close)(struct moberg_device_analog_in_context *);
-  int (*read)(struct moberg_device_analog_in_context *, double *value);
-};
-  
-struct moberg_device_analog_out {
-  struct moberg_device_analog_out_context *context;
-  int (*open)(struct moberg_device_analog_out_context *);
-  int (*close)(struct moberg_device_analog_out_context *);
-  int (*write)(struct moberg_device_analog_out_context *, double value);
-};
-  
-struct moberg_device_digital_in {
-  struct moberg_device_digital_in_context *context;
-  int (*open)(struct moberg_device_digital_in_context *);
-  int (*close)(struct moberg_device_digital_in_context *);
-  int (*read)(struct moberg_device_digital_in_context *, int *value);
-};
-  
-struct moberg_device_digital_out {
-  struct moberg_device_digital_out_context *context;
-  int (*open)(struct moberg_device_digital_out_context *);
-  int (*close)(struct moberg_device_digital_out_context *);
-  int (*write)(struct moberg_device_digital_out_context *, int value);
-};
-  
-struct moberg_device_encoder_in {
-  struct moberg_device_encoder_in_context *context;
-  int (*open)(struct moberg_device_encoder_in_context *);
-  int (*close)(struct moberg_device_encoder_in_context *);
-  int (*read)(struct moberg_device_encoder_in_context *, long *value);
-};
-  
-struct moberg_install_channels {
-  struct moberg *context;
-  int (*analog_in)(int index, struct moberg_device_analog_in *channel);
-  int (*analog_out)(int index, struct moberg_device_analog_out *channel);
-  int (*digital_in)(int index, struct moberg_device_digital_in *channel);
-  int (*digital_out)(int index, struct moberg_device_digital_in *channel);
-  int (*encoder_in)(int index, struct moberg_device_encoder_in *channel);
-};
+#include <moberg_channel.h>
 
 struct moberg_parser_context;
-struct moberg_device;
-struct moberg_device_config;
 
 struct moberg_device_driver {
+  /* Create new device context */
+  struct moberg_device_context *(*new)(int (*dlclose)(void *dlhandle),
+                                       void *dlhandle);
+  /* Use-count of device, when it reaches zero, device will be free'd */
+  int (*up)(struct moberg_device_context *context);
+  int (*down)(struct moberg_device_context *context);
+  /* Parse driver dependent parts of config file */
   int (*parse_config)(
-    struct moberg_device* device,
-    struct moberg_parser_context *context);
+    struct moberg_device_context *device,
+    struct moberg_parser_context *parser);
   int (*parse_map)(
-    struct moberg_device* device,
-    struct moberg_parser_context *context,
-    enum moberg_channel_kind kind);
-  int (*config_free)(
-    struct moberg_device_config *config);
+    struct moberg_device_context *device,
+    struct moberg_parser_context *parser,
+    enum moberg_channel_kind kind,
+    struct moberg_channel_map *map);
 };
 
 struct moberg_device;
@@ -82,33 +38,14 @@ void moberg_device_free(struct moberg_device *device);
 int moberg_device_parse_config(struct moberg_device* device,
                                struct moberg_parser_context *context);
 
-int moberg_device_set_config(struct moberg_device* device,
-                             struct moberg_device_config *config);
-
 int moberg_device_parse_map(struct moberg_device* device,
-                            struct moberg_config *config,
-                            struct moberg_parser_context *context,
+                            struct moberg_parser_context *parser,
                             enum moberg_channel_kind kind,
                             int min,
                             int max);
 
-int moberg_device_add_analog_in(struct moberg_device* device,
-                                struct moberg_device_analog_in *channel);
-                            
-int moberg_device_add_analog_out(struct moberg_device* device,
-                                 struct moberg_device_analog_out *channel);
-                            
-int moberg_device_add_digital_in(struct moberg_device* device,
-                                 struct moberg_device_digital_in *channel);
-                            
-int moberg_device_add_digital_out(struct moberg_device* device,
-                                  struct moberg_device_digital_out *channel);
-                            
-int moberg_device_add_encoder_in(struct moberg_device* device,
-                                 struct moberg_device_encoder_in *channel);
-
 int moberg_device_install_channels(struct moberg_device *device,
-                                   struct moberg_install_channels *install);
+                                   struct moberg_channel_install *install);
 
 
 #endif
diff --git a/moberg_module.h b/moberg_module.h
index 29ce50166c323fd44e6f763a6b1e09cfa9a643b6..6916bbf88d6b85120846bf81b4d0916afa1488b7 100644
--- a/moberg_module.h
+++ b/moberg_module.h
@@ -55,4 +55,8 @@ void moberg_parser_failed(
   struct moberg_parser_context *c,
   FILE *f);
 
+void moberg_deferred_action(
+  int (*action)(void *param),
+  void *param);
+
 #endif
diff --git a/moberg_parser.c b/moberg_parser.c
index da0c64600ef7d81e9029d25d19e1ee441a267f6a..61cd5cce769e879697846b4df74c40702554d6f7 100644
--- a/moberg_parser.c
+++ b/moberg_parser.c
@@ -328,7 +328,7 @@ static int parse_map(context_t *c,
   else { goto syntax_err; }
   if (! parse_map_range(c, &min, &max)) { goto syntax_err; }
   if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; }
-  if (! moberg_device_parse_map(device, c->config, c, kind, min, max)) {
+  if (! moberg_device_parse_map(device, c, kind, min, max)) {
     goto err;
   }
   if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto syntax_err; }
diff --git a/modules/comedi/comedi.c b/modules/comedi/comedi.c
index 4c078e6bda4a794c3999f4383cdfa2ce5d9314d0..c53521cda07ec014bc11c0a94befd1fb395f687c 100644
--- a/modules/comedi/comedi.c
+++ b/modules/comedi/comedi.c
@@ -11,11 +11,115 @@ typedef struct moberg_parser_token token_t;
 typedef struct moberg_parser_ident ident_t;
 typedef struct moberg_parser_context context_t;
 
-struct moberg_device_map {};
-struct moberg_device_config {
+struct moberg_device_context {
+  int (*dlclose)(void *dlhandle);
+  void *dlhandle;
+  int use_count;
   char *device;
 };
 
+struct moberg_channel_context {
+  void *to_free; /* To be free'd when use_count goes to zero */
+  struct moberg_device_context *device;
+  int use_count;
+};
+
+struct moberg_channel_analog_in {
+  struct moberg_channel channel;
+  struct moberg_channel_context channel_context;
+};
+
+struct moberg_channel_analog_out {
+  struct moberg_channel channel;
+  struct moberg_channel_context channel_context;
+};
+
+struct moberg_channel_digital_in {
+  struct moberg_channel channel;
+  struct moberg_channel_context channel_context;
+};
+
+struct moberg_channel_digital_out {
+  struct moberg_channel channel;
+  struct moberg_channel_context channel_context;
+};
+
+struct moberg_channel_encoder_in {
+  struct moberg_channel channel;
+  struct moberg_channel_context channel_context;
+};
+
+static struct moberg_device_context *new_context(
+  int (*dlclose)(void *dlhandle),
+  void *dlhandle)
+{
+  struct moberg_device_context *result = malloc(sizeof(*result));
+  if (result) {
+    memset(result, 0, sizeof(*result));
+    result->dlclose = dlclose;
+    result->dlhandle = dlhandle;
+  }
+  return result;
+}
+
+static int device_up(struct moberg_device_context *context)
+{
+  context->use_count++;
+  return context->use_count;
+}
+
+static int device_down(struct moberg_device_context *context)
+{
+  context->use_count--;
+  int result = context->use_count;
+  if (context->use_count <= 0) {
+    moberg_deferred_action(context->dlclose, context->dlhandle);
+    free(context->device);
+    free(context);
+    return 0;
+  }
+  return result;
+}
+
+static int channel_up(struct moberg_channel *channel)
+{
+  device_up(channel->context->device);
+  channel->context->use_count++;
+  return channel->context->use_count;
+}
+
+static int channel_down(struct moberg_channel *channel)
+{
+  device_down(channel->context->device);
+  channel->context->use_count--;
+  if (channel->context->use_count <= 0) {
+    free(channel->context->to_free);
+    return 0;
+  }
+  return channel->context->use_count;
+}
+
+static void init_channel(
+  struct moberg_channel *channel,
+  void *to_free,
+  struct moberg_channel_context *context,
+  struct moberg_device_context *device,
+  enum moberg_channel_kind kind,
+  union moberg_channel_action action)
+{
+  context->to_free = to_free;
+  context->device = device;
+  context->use_count = 0;
+  
+  channel->context = context;
+  channel->up = channel_up;
+  channel->down = channel_down;
+  channel->open = NULL;
+  channel->close = NULL;
+  channel->kind = kind;
+  channel->action = action;
+};
+
 static inline int acceptsym(context_t *c,
 			   kind_t kind,
 			   token_t *token)
@@ -30,24 +134,19 @@ static inline int acceptkeyword(context_t *c,
 }
   
 static int parse_config(
-  struct moberg_device *device,
+  struct moberg_device_context *device,
   struct moberg_parser_context *c)
 {
-  struct moberg_device_config *config = malloc(sizeof *config);
-  if (! config) {
-    fprintf(stderr, "Failed to allocate moberg device config\n");
-    goto err;
-  }
   if (! acceptsym(c, tok_LBRACE, NULL)) { goto syntax_err; }
   for (;;) {
     if (acceptsym(c, tok_RBRACE, NULL)) {
 	break;
     } else if (acceptkeyword(c, "device")) {
-      token_t device;
+      token_t name;
       if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; }
-      if (! acceptsym(c, tok_STRING, &device)) { goto syntax_err; }
+      if (! acceptsym(c, tok_STRING, &name)) { goto syntax_err; }
       if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto syntax_err; }
-      config->device = strndup(device.u.string.value, device.u.string.length);
+      device->device = strndup(name.u.string.value, name.u.string.length);
     } else if (acceptkeyword(c, "config")) {
       if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; }
       if (! acceptsym(c, tok_LBRACKET, NULL)) { goto syntax_err; }
@@ -78,19 +177,17 @@ static int parse_config(
       goto syntax_err;
     }
   }
-  moberg_device_set_config(device, config);
   return 1;
 syntax_err:
   moberg_parser_failed(c, stderr);
-  free(config);
-err:
   return 0;
 }
 
 static int parse_map(
-  struct moberg_device *device,
+  struct moberg_device_context *device,
   struct moberg_parser_context *c,
-  enum moberg_channel_kind kind)
+  enum moberg_channel_kind kind,
+  struct moberg_channel_map *map)
 {
   token_t min, max;
 
@@ -114,21 +211,86 @@ static int parse_map(
     }
     for (int i = min.u.integer.value ; i <= max.u.integer.value ; i++) {
       switch (kind) {
-        case chan_ANALOGIN:
-          moberg_device_add_analog_in(device, NULL);
-          break;
-        case chan_ANALOGOUT:
-          moberg_device_add_analog_out(device, NULL);
-          break;
-        case chan_DIGITALIN:
-          moberg_device_add_digital_in(device, NULL);
-          break;
-        case chan_DIGITALOUT:
-          moberg_device_add_digital_out(device, NULL);
-          break;
-        case chan_ENCODERIN:
-          moberg_device_add_encoder_in(device, NULL);
-          break;
+        case chan_ANALOGIN: {
+          struct moberg_channel_analog_in *channel =
+            malloc(sizeof(*channel));
+          
+          if (channel) {
+            init_channel(&channel->channel,
+                         channel,
+                         &channel->channel_context,
+                         device,
+                         kind,
+                         (union moberg_channel_action) {
+                           .analog_in.context=channel,
+                           .analog_in.read=NULL });
+            map->map(map->device, &channel->channel);
+          }
+        } break;
+        case chan_ANALOGOUT: {
+          struct moberg_channel_analog_out *channel =
+            malloc(sizeof(*channel));
+          
+          if (channel) {
+            init_channel(&channel->channel,
+                         channel,
+                         &channel->channel_context,
+                         device,
+                         kind,
+                         (union moberg_channel_action) {
+                           .analog_out.context=channel,
+                           .analog_out.write=NULL });
+            map->map(map->device, &channel->channel);
+          }
+        } break;
+        case chan_DIGITALIN: {
+          struct moberg_channel_digital_in *channel =
+            malloc(sizeof(*channel));
+          
+          if (channel) {
+            init_channel(&channel->channel,
+                         channel,
+                         &channel->channel_context,
+                         device,
+                         kind,
+                         (union moberg_channel_action) {
+                           .digital_in.context=channel,
+                           .digital_in.read=NULL });
+            map->map(map->device, &channel->channel);
+          }
+        } break;
+        case chan_DIGITALOUT: {
+          struct moberg_channel_digital_out *channel =
+            malloc(sizeof(*channel));
+          
+          if (channel) {
+            init_channel(&channel->channel,
+                         channel,
+                         &channel->channel_context,
+                         device,
+                         kind,
+                         (union moberg_channel_action) {
+                           .digital_out.context=channel,
+                           .digital_out.write=NULL });
+            map->map(map->device, &channel->channel);
+          }
+        } break;
+        case chan_ENCODERIN: {
+          struct moberg_channel_encoder_in *channel =
+            malloc(sizeof(*channel));
+          
+          if (channel) {
+            init_channel(&channel->channel,
+                         channel,
+                         &channel->channel_context,
+                         device,
+                         kind,
+                         (union moberg_channel_action) {
+                           .encoder_in.context=channel,
+                           .encoder_in.read=NULL });
+            map->map(map->device, &channel->channel);
+          }
+        } break;
       }
     }
     if (! acceptsym(c, tok_RBRACKET, NULL)) { goto err; }
@@ -142,14 +304,10 @@ err:
   return 0;
 }
 
-static int config_free(struct moberg_device_config *config)
-{
-  free(config->device);
-  return 1;
-}
-
 struct moberg_device_driver moberg_device_driver = {
-  .parse_config = parse_config,
-  .parse_map = parse_map,
-  .config_free = config_free
+  .new=new_context,
+  .up=device_up,
+  .down=device_down,
+  .parse_config=parse_config,
+  .parse_map=parse_map,
 };
diff --git a/modules/serial2002/serial2002.c b/modules/serial2002/serial2002.c
index 0c3448d94dd1aa52601b8a0521e72549146c90e7..9ab9e43fb108835ca3a56bb562133b8c875f42bf 100644
--- a/modules/serial2002/serial2002.c
+++ b/modules/serial2002/serial2002.c
@@ -10,6 +10,115 @@ typedef enum moberg_parser_token_kind kind_t;
 typedef struct moberg_parser_token token_t;
 typedef struct moberg_parser_context context_t;
 
+struct moberg_device_context {
+  int (*dlclose)(void *dlhandle);
+  void *dlhandle;
+  int use_count;
+  char *name;
+  int baud;
+};
+
+struct moberg_channel_context {
+  void *to_free; /* To be free'd when use_count goes to zero */
+  struct moberg_device_context *device;
+  int use_count;
+};
+
+struct moberg_channel_analog_in {
+  struct moberg_channel channel;
+  struct moberg_channel_context channel_context;
+};
+
+struct moberg_channel_analog_out {
+  struct moberg_channel channel;
+  struct moberg_channel_context channel_context;
+};
+
+struct moberg_channel_digital_in {
+  struct moberg_channel channel;
+  struct moberg_channel_context channel_context;
+};
+
+struct moberg_channel_digital_out {
+  struct moberg_channel channel;
+  struct moberg_channel_context channel_context;
+};
+
+struct moberg_channel_encoder_in {
+  struct moberg_channel channel;
+  struct moberg_channel_context channel_context;
+};
+
+static struct moberg_device_context *new_context(
+  int (*dlclose)(void *dlhandle),
+  void *dlhandle)
+{
+  struct moberg_device_context *result = malloc(sizeof(*result));
+  if (result) {
+    memset(result, 0, sizeof(*result));
+    result->dlclose = dlclose;
+    result->dlhandle = dlhandle;
+  }
+  return result;
+}
+
+static int device_up(struct moberg_device_context *context)
+{
+  context->use_count++;
+  return context->use_count;
+}
+
+static int device_down(struct moberg_device_context *context)
+{
+  context->use_count--;
+  if (context->use_count <= 0) {
+    moberg_deferred_action(context->dlclose, context->dlhandle);
+    free(context->name);
+    free(context);
+    return 0;
+  }
+  return context->use_count;
+}
+
+static int channel_up(struct moberg_channel *channel)
+{
+  device_up(channel->context->device);
+  channel->context->use_count++;
+  return channel->context->use_count;
+}
+
+static int channel_down(struct moberg_channel *channel)
+{
+  device_down(channel->context->device);
+  channel->context->use_count--;
+  if (channel->context->use_count <= 0) {
+    free(channel->context->to_free);
+    return 0;
+  }
+  return channel->context->use_count;
+}
+
+static void init_channel(
+  struct moberg_channel *channel,
+  void *to_free,
+  struct moberg_channel_context *context,
+  struct moberg_device_context *device,  
+  enum moberg_channel_kind kind,
+  union moberg_channel_action action)
+{
+  context->to_free = to_free;
+  context->device = device;
+  context->use_count = 0;
+
+  channel->context = context;
+  channel->up = channel_up;
+  channel->down = channel_down;
+  channel->open = NULL;
+  channel->close = NULL;
+  channel->kind = kind;
+  channel->action = action;
+};
+
 static inline int acceptsym(context_t *c,
                             kind_t kind,
                             token_t *token)
@@ -23,53 +132,41 @@ static inline int acceptkeyword(context_t *c,
   return moberg_parser_acceptkeyword(c, keyword);
 }
   
-struct moberg_device_config {
-  char *device;
-  int baud;
-};
-
 static int parse_config(
-  struct moberg_device *device,
+  struct moberg_device_context *device,
   struct moberg_parser_context *c)
 {
-  struct moberg_device_config *config = malloc(sizeof *config);
-  if (! config) {
-    fprintf(stderr, "Failed to allocate moberg device config\n");
-    goto err;
-  }
   if (! acceptsym(c, tok_LBRACE, NULL)) { goto syntax_err; }
   for (;;) {
     if (acceptsym(c, tok_RBRACE, NULL)) {
 	break;
     } else if (acceptkeyword(c, "device")) {
-      token_t device;
+      token_t name;
       if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; }
-      if (! acceptsym(c, tok_STRING, &device)) { goto syntax_err; }
+      if (! acceptsym(c, tok_STRING, &name)) { goto syntax_err; }
       if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto syntax_err; }
-      config->device = strndup(device.u.string.value, device.u.string.length);
+      device->name = strndup(name.u.string.value, name.u.string.length);
     } else if (acceptkeyword(c, "baud")) {
       token_t baud;
       if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; }
       if (! acceptsym(c, tok_INTEGER, &baud)) { goto syntax_err; }
       if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto syntax_err; }
-      config->baud = baud.u.integer.value;
+      device->baud = baud.u.integer.value;
     } else {
       goto syntax_err;
     }
   }
-  moberg_device_set_config(device, config);
   return 1;
 syntax_err:
   moberg_parser_failed(c, stderr);
-  free(config);
-err:
   return 0;
 }
 
 static int parse_map(
-  struct moberg_device *device,
+  struct moberg_device_context *device,
   struct moberg_parser_context *c,
-  enum moberg_channel_kind ignore)
+  enum moberg_channel_kind ignore,
+  struct moberg_channel_map *map)
 {
   enum moberg_channel_kind kind;
   token_t min, max;
@@ -90,21 +187,86 @@ static int parse_map(
   if (! acceptsym(c, tok_RBRACKET, NULL)) { goto syntax_err; }
   for (int i = min.u.integer.value ; i <= max.u.integer.value ; i++) {
     switch (kind) {
-      case chan_ANALOGIN:
-        moberg_device_add_analog_in(device, NULL);
-        break;
-      case chan_ANALOGOUT:
-        moberg_device_add_analog_out(device, NULL);
-        break;
-      case chan_DIGITALIN:
-        moberg_device_add_digital_in(device, NULL);
-        break;
-      case chan_DIGITALOUT:
-        moberg_device_add_digital_out(device, NULL);
-        break;
-      case chan_ENCODERIN:
-        moberg_device_add_encoder_in(device, NULL);
-        break;
+      case chan_ANALOGIN: {
+        struct moberg_channel_analog_in *channel =
+          malloc(sizeof(*channel));
+        
+        if (channel) {
+          init_channel(&channel->channel,
+                       channel,
+                       &channel->channel_context,
+                       device,
+                       kind,
+                       (union moberg_channel_action) {
+                         .analog_in.context=channel,
+                         .analog_in.read=NULL });
+          map->map(map->device, &channel->channel);
+        }
+      } break;
+      case chan_ANALOGOUT: {
+        struct moberg_channel_analog_out *channel =
+          malloc(sizeof(*channel));
+        
+        if (channel) {
+          init_channel(&channel->channel,
+                       channel,
+                       &channel->channel_context,
+                       device,
+                       kind,
+                       (union moberg_channel_action) {
+                         .analog_out.context=channel,
+                         .analog_out.write=NULL });
+          map->map(map->device, &channel->channel);
+        }
+      } break;
+      case chan_DIGITALIN: {
+        struct moberg_channel_digital_in *channel =
+          malloc(sizeof(*channel));
+        
+        if (channel) {
+          init_channel(&channel->channel,
+                       channel,
+                       &channel->channel_context,
+                       device,
+                       kind,
+                       (union moberg_channel_action) {
+                         .digital_in.context=channel,
+                         .digital_in.read=NULL });
+          map->map(map->device, &channel->channel);
+        }
+      } break;
+      case chan_DIGITALOUT: {
+        struct moberg_channel_digital_out *channel =
+          malloc(sizeof(*channel));
+        
+        if (channel) {
+          init_channel(&channel->channel,
+                       channel,
+                       &channel->channel_context,
+                       device,
+                       kind,
+                       (union moberg_channel_action) {
+                         .digital_out.context=channel,
+                         .digital_out.write=NULL });
+          map->map(map->device, &channel->channel);
+        }
+      } break;
+      case chan_ENCODERIN: {
+        struct moberg_channel_encoder_in *channel =
+          malloc(sizeof(*channel));
+        
+        if (channel) {
+          init_channel(&channel->channel,
+                       channel,
+                       &channel->channel_context,
+                       device,
+                       kind,
+                       (union moberg_channel_action) {
+                         .encoder_in.context=channel,
+                         .encoder_in.read=NULL });
+          map->map(map->device, &channel->channel);
+        }
+      } break;
     }
   }
   return 1;
@@ -113,15 +275,10 @@ syntax_err:
   return 0;
 }
 
-static int config_free(struct moberg_device_config *config)
-{
-  free(config->device);
-  return 1;
-}
-
-
 struct moberg_device_driver moberg_device_driver = {
-  .parse_config = parse_config,
-  .parse_map = parse_map,
-  .config_free = config_free
+  .new=new_context,
+  .up=device_up,
+  .down=device_down,
+  .parse_config=parse_config,
+  .parse_map=parse_map,
 };