diff --git a/moberg.c b/moberg.c
index bc9e52905c7b3a2fea511b2e1772878e53c767c4..ad8de2e688fb073540df72de91f4f25a7d368ab6 100644
--- a/moberg.c
+++ b/moberg.c
@@ -31,7 +31,6 @@ static struct deferred_action {
 static void run_deferred_actions()
 {
   while (deferred_action) {
-    fprintf(stderr, "RUNNING deferred\n");
     struct deferred_action *deferred = deferred_action;
     deferred_action = deferred_action->next;
     deferred->action(deferred->param);
@@ -288,6 +287,7 @@ enum moberg_status moberg_start(
   struct moberg *moberg,
   FILE *f)
 {
+  return moberg_config_start(moberg->config, f);
   return moberg_OK;
 }
 
@@ -296,6 +296,7 @@ enum moberg_status moberg_stop(
   struct moberg *moberg,
   FILE *f)
 {
+  return moberg_config_stop(moberg->config, f);
   return moberg_OK;
 }
 
@@ -305,7 +306,6 @@ void moberg_deferred_action(
 {
   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;
diff --git a/moberg_config.c b/moberg_config.c
index 6f7e6e4497fc3b33167e93b2d6a844a7550cb974..879b6e851347c3306d6ff582e72da69ec0f35196 100644
--- a/moberg_config.c
+++ b/moberg_config.c
@@ -94,4 +94,21 @@ int moberg_config_install_channels(struct moberg_config *config,
   return result;
 }
 
+int moberg_config_start(struct moberg_config *config,
+                        FILE *f)
+{
+  for (struct device_entry *d = config->device_head ; d ; d = d->next) {
+    moberg_device_start(d->device, f);
+  }
+  return 1;
+}
+
 
+int moberg_config_stop(struct moberg_config *config,
+                       FILE *f)
+{
+  for (struct device_entry *d = config->device_head ; d ; d = d->next) {
+    moberg_device_stop(d->device, f);
+  }
+  return 1;
+}
diff --git a/moberg_config.h b/moberg_config.h
index 1aae2e4dbd0489415c2ad192e8a6c4fb3d2ffc1e..a107d8a15bb0b2e879593ec9d27fee8de399c1c4 100644
--- a/moberg_config.h
+++ b/moberg_config.h
@@ -17,4 +17,10 @@ int moberg_config_add_device(struct moberg_config *config,
 int moberg_config_install_channels(struct moberg_config *config,
                                    struct moberg_channel_install *install);
 
+int moberg_config_start(struct moberg_config *config,
+                        FILE *f);
+
+int moberg_config_stop(struct moberg_config *config,
+                       FILE *f);
+
 #endif
diff --git a/moberg_device.c b/moberg_device.c
index b2daf2ff5a48640496f708aa8d2ddbd546742975..638179b26a8203f5122722aa084c3b72098fd0b1 100644
--- a/moberg_device.c
+++ b/moberg_device.c
@@ -228,13 +228,6 @@ int moberg_device_parse_map(struct moberg_device* device,
   };
   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
   };
   
@@ -259,50 +252,19 @@ int moberg_device_install_channels(struct moberg_device *device,
                      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;
 }
 
+int moberg_device_start(struct moberg_device *device,
+                        FILE *f)
+{
+  return device->driver.start(device->device_context, f);
+}
+
+int moberg_device_stop(struct moberg_device *device,
+                       FILE *f)
+{
+  return device->driver.stop(device->device_context, f);
+}
diff --git a/moberg_device.h b/moberg_device.h
index de4a90d62f5345ca3eb0f33d9f35429731f98355..0acafb29d9a4ee3270dbadc9c25835252197b5ff 100644
--- a/moberg_device.h
+++ b/moberg_device.h
@@ -18,6 +18,7 @@ struct moberg_device_driver {
   /* 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_context *device,
@@ -27,6 +28,15 @@ struct moberg_device_driver {
     struct moberg_parser_context *parser,
     enum moberg_channel_kind kind,
     struct moberg_channel_map *map);
+
+  /* Shell commands for starting and stopping */
+  int (*start)(
+    struct moberg_device_context *device,
+    FILE *f);
+  int (*stop)(
+    struct moberg_device_context *device,
+    FILE *f);
+  
 };
 
 struct moberg_device;
@@ -49,5 +59,13 @@ int moberg_device_parse_map(struct moberg_device* device,
 int moberg_device_install_channels(struct moberg_device *device,
                                    struct moberg_channel_install *install);
 
+int moberg_device_start(struct moberg_device *device,
+                        FILE *f);
+
+int moberg_device_stop(struct moberg_device *device,
+                       FILE *f);
+
+
+
 
 #endif
diff --git a/moberg_module.h b/moberg_module.h
index 6916bbf88d6b85120846bf81b4d0916afa1488b7..434f2c385397ad22339f0c6a99bbd9f8bf235b5d 100644
--- a/moberg_module.h
+++ b/moberg_module.h
@@ -36,8 +36,7 @@ struct moberg_parser_integer {
 struct moberg_parser_token {
   enum moberg_parser_token_kind kind;
   union {
-    struct moberg_parser_ident ident;
-    struct moberg_parser_ident string;
+    struct moberg_parser_ident idstr;
     struct moberg_parser_integer integer;
   } u;
 };
diff --git a/moberg_parser.c b/moberg_parser.c
index 61cd5cce769e879697846b4df74c40702554d6f7..ac7bdbdde46996210e30d1d1e3893ca545df8d16 100644
--- a/moberg_parser.c
+++ b/moberg_parser.c
@@ -44,8 +44,8 @@ static inline int acceptkeyword(context_t *c,
 static const void nextsym_ident(context_t *c)
 {
   c->token.kind = tok_IDENT;
-  c->token.u.ident.length = 1;
-  c->token.u.ident.value = c->p;
+  c->token.u.idstr.length = 1;
+  c->token.u.idstr.value = c->p;
   c->p++;
   while (*c->p) {
     switch (*c->p) {
@@ -54,7 +54,7 @@ static const void nextsym_ident(context_t *c)
       case '0'...'9':
       case '_':
         c->p++;
-        c->token.u.ident.length++;
+        c->token.u.idstr.length++;
         break;
       default:
         return;
@@ -77,15 +77,15 @@ static const void nextsym_string(context_t *c)
 {
   c->token.kind = tok_STRING;
   c->p++;
-  c->token.u.string.value = c->p;
-  c->token.u.string.length = 0;
+  c->token.u.idstr.value = c->p;
+  c->token.u.idstr.length = 0;
   while (*c->p && *c->p != '"') {
     if (*c->p == '\\') {
-      c->token.u.string.length++;
+      c->token.u.idstr.length++;
       c->p++;
     }
     if (*c->p) {
-      c->token.u.string.length++;
+      c->token.u.idstr.length++;
       c->p++;
     }
   }
@@ -235,7 +235,7 @@ int moberg_parser_acceptkeyword(context_t *c,
 {
   token_t t;
   if (peeksym(c, tok_IDENT, &t) &&
-      strncmp(keyword, t.u.ident.value, t.u.ident.length) == 0) {
+      strncmp(keyword, t.u.idstr.value, t.u.idstr.length) == 0) {
     nextsym(c);
     c->expected.n = 0;
     return 1;
@@ -277,11 +277,11 @@ void moberg_parser_failed(
       break;
     case tok_IDENT:
       fprintf(f, "%.*s (<IDENT>)",
-              c->token.u.ident.length, c->token.u.ident.value);
+              c->token.u.idstr.length, c->token.u.idstr.value);
       break;
     case tok_STRING:
       fprintf(f, "\"%.*s'\" (<STRING>)",
-              c->token.u.string.length, c->token.u.string.value);
+              c->token.u.idstr.length, c->token.u.idstr.value);
       break;
   }
   fprintf(f, "\n%s\n", c->p);
@@ -375,10 +375,10 @@ static int parse(context_t *c)
       if (! acceptsym(c, tok_IDENT, &t)) { goto syntax_err; }
       if (! acceptsym(c, tok_RPAREN, NULL)) { goto syntax_err; }
 
-      char *name = strndup(t.u.ident.value, t.u.ident.length);
+      char *name = strndup(t.u.idstr.value, t.u.idstr.length);
       if (! name) {
         fprintf(stderr, "Failed to allocate driver name '%.*s'\n",
-                t.u.ident.length, t.u.ident.value);
+                t.u.idstr.length, t.u.idstr.value);
         goto err;
       }
       device = moberg_device_new(name);
diff --git a/modules/comedi/comedi.c b/modules/comedi/comedi.c
index c53521cda07ec014bc11c0a94befd1fb395f687c..d0ddead90b22b440ee0423391a8543c0a79427bd 100644
--- a/modules/comedi/comedi.c
+++ b/modules/comedi/comedi.c
@@ -15,7 +15,13 @@ struct moberg_device_context {
   int (*dlclose)(void *dlhandle);
   void *dlhandle;
   int use_count;
-  char *device;
+  char *name;
+  struct idstr {
+    struct idstr *next;
+    struct idstr *prev;
+    kind_t kind;
+    char *value;
+  } modprobe_list, config_list;
 };
 
 struct moberg_channel_context {
@@ -58,6 +64,10 @@ static struct moberg_device_context *new_context(
     memset(result, 0, sizeof(*result));
     result->dlclose = dlclose;
     result->dlhandle = dlhandle;
+    result->modprobe_list.next = &result->modprobe_list;
+    result->modprobe_list.prev = &result->modprobe_list;
+    result->config_list.next = &result->config_list;
+    result->config_list.prev = &result->config_list;
   }
   return result;
 }
@@ -74,7 +84,23 @@ static int device_down(struct moberg_device_context *context)
   int result = context->use_count;
   if (context->use_count <= 0) {
     moberg_deferred_action(context->dlclose, context->dlhandle);
-    free(context->device);
+    free(context->name);
+    struct idstr *e;
+    
+    e = context->modprobe_list.next;
+    while (e != &context->modprobe_list) {
+      struct idstr *next = e->next;
+      free(e->value);
+      free(e);
+      e = next;
+    }
+    e = context->config_list.next;
+    while (e != &context->config_list) {
+      struct idstr *next = e->next;
+      free(e->value);
+      free(e);
+      e = next;
+    }
     free(context);
     return 0;
   }
@@ -99,13 +125,12 @@ static int channel_down(struct moberg_channel *channel)
   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)
+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;
@@ -132,10 +157,45 @@ static inline int acceptkeyword(context_t *c,
 {
   return moberg_parser_acceptkeyword(c, keyword);
 }
+
+static int append_modprobe(struct moberg_device_context *device,
+                           token_t token)
+{
+  struct idstr *modprobe = malloc(sizeof(*modprobe));
+  if (! modprobe) { goto err; }
+  modprobe->value = strndup(token.u.idstr.value, token.u.idstr.length);
+  if (! modprobe->value) { goto free_modprobe; }
+  modprobe->prev = device->modprobe_list.prev;
+  modprobe->next = modprobe->prev->next;
+  modprobe->prev->next = modprobe;
+  modprobe->next->prev = modprobe;
+  return 1;
+free_modprobe:
+  free(modprobe);
+err:
+  return 0;
+}
+  
+static int append_config(struct moberg_device_context *device,
+                           token_t token)
+{
+  struct idstr *config = malloc(sizeof(*config));
+  if (! config) { goto err; }
+  config->value = strndup(token.u.idstr.value, token.u.idstr.length);
+  if (! config->value) { goto free_config; }
+  config->prev = device->config_list.prev;
+  config->next = config->prev->next;
+  config->prev->next = config;
+  config->next->prev = config;
+  return 1;
+free_config:
+  free(config);
+err:
+  return 0;
+}
   
-static int parse_config(
-  struct moberg_device_context *device,
-  struct moberg_parser_context *c)
+static int parse_config(struct moberg_device_context *device,
+                        struct moberg_parser_context *c)
 {
   if (! acceptsym(c, tok_LBRACE, NULL)) { goto syntax_err; }
   for (;;) {
@@ -146,15 +206,17 @@ static int parse_config(
       if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; }
       if (! acceptsym(c, tok_STRING, &name)) { goto syntax_err; }
       if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto syntax_err; }
-      device->device = strndup(name.u.string.value, name.u.string.length);
+      device->name = strndup(name.u.idstr.value, name.u.idstr.length);
     } else if (acceptkeyword(c, "config")) {
       if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; }
       if (! acceptsym(c, tok_LBRACKET, NULL)) { goto syntax_err; }
       for (;;) {
+        token_t config;
 	if (acceptsym(c, tok_RBRACKET, NULL)) {
 	  break;
-	} else if (acceptsym(c, tok_IDENT, NULL) ||
-		   acceptsym(c, tok_STRING, NULL)) {
+	} else if (acceptsym(c, tok_IDENT, &config) ||
+		   acceptsym(c, tok_STRING, &config)) {
+          append_config(device, config);
 	} else {
 	  goto syntax_err;
 	}
@@ -164,10 +226,12 @@ static int parse_config(
       if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; }
       if (! acceptsym(c, tok_LBRACKET, NULL)) { goto syntax_err; }
       for (;;) {
+        token_t modprobe;
 	if (acceptsym(c, tok_RBRACKET, NULL)) {
 	  break;
-	} else if (acceptsym(c, tok_IDENT, NULL) ||
-		   acceptsym(c, tok_STRING, NULL)) {
+	} else if (acceptsym(c, tok_IDENT, &modprobe) ||
+		   acceptsym(c, tok_STRING, &modprobe)) {
+          append_modprobe(device, modprobe);
 	} else {
 	  goto syntax_err;
 	}
@@ -183,11 +247,10 @@ syntax_err:
   return 0;
 }
 
-static int parse_map(
-  struct moberg_device_context *device,
-  struct moberg_parser_context *c,
-  enum moberg_channel_kind kind,
-  struct moberg_channel_map *map)
+static int parse_map(struct moberg_device_context *device,
+                     struct moberg_parser_context *c,
+                     enum moberg_channel_kind kind,
+                     struct moberg_channel_map *map)
 {
   token_t min, max;
 
@@ -304,10 +367,49 @@ err:
   return 0;
 }
 
+static int start(struct moberg_device_context *device,
+                 FILE *f)
+{
+  for (struct idstr *e = device->modprobe_list.next ;
+       e != &device->modprobe_list ;
+       e = e->next) {
+    fprintf(f, "modprobe %s\n", e->value);
+  }
+  fprintf(f, "comedi_config %s ", device->name);
+  int i = 0;
+  for (struct idstr *e = device->config_list.next ;
+       e != &device->config_list ;
+       e = e->next) {
+    switch (i) {
+      case 0: fprintf(f, "%s", e->value); break;
+      case 1: fprintf(f, " %s", e->value); break;
+      default: fprintf(f, ",%s", e->value); break;
+    }
+    i++;
+  }
+  fprintf(f, "\n");
+  
+  return 1;
+}
+
+static int stop(struct moberg_device_context *device,
+                 FILE *f)
+{
+  fprintf(f, "comedi_config --remove %s\n", device->name);
+  for (struct idstr *e = device->modprobe_list.prev ;
+       e != &device->modprobe_list ;
+       e = e->prev) {
+    fprintf(f, "rmmod %s\n", e->value);
+  }
+  return 1;
+}
+
 struct moberg_device_driver moberg_device_driver = {
   .new=new_context,
   .up=device_up,
   .down=device_down,
   .parse_config=parse_config,
   .parse_map=parse_map,
+  .start=start,
+  .stop=stop
 };
diff --git a/modules/serial2002/serial2002.c b/modules/serial2002/serial2002.c
index 9ab9e43fb108835ca3a56bb562133b8c875f42bf..8b9404eea7efbed7fdda5ae96b4c0200d452199f 100644
--- a/modules/serial2002/serial2002.c
+++ b/modules/serial2002/serial2002.c
@@ -145,7 +145,7 @@ static int parse_config(
       if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; }
       if (! acceptsym(c, tok_STRING, &name)) { goto syntax_err; }
       if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto syntax_err; }
-      device->name = strndup(name.u.string.value, name.u.string.length);
+      device->name = strndup(name.u.idstr.value, name.u.idstr.length);
     } else if (acceptkeyword(c, "baud")) {
       token_t baud;
       if (! acceptsym(c, tok_EQUAL, NULL)) { goto syntax_err; }
@@ -275,10 +275,24 @@ syntax_err:
   return 0;
 }
 
+static int start(struct moberg_device_context *device,
+                 FILE *f)
+{
+  return 1;
+}
+
+static int stop(struct moberg_device_context *device,
+                 FILE *f)
+{
+  return 1;
+}
+
 struct moberg_device_driver moberg_device_driver = {
   .new=new_context,
   .up=device_up,
   .down=device_down,
   .parse_config=parse_config,
   .parse_map=parse_map,
+  .start=start,
+  .stop=stop
 };