Index: ChangeLog
===================================================================
--- ChangeLog	(revision 5977)
+++ ChangeLog	(revision 5982)
@@ -2,4 +2,5 @@
 	* Added user defined RoarDMX events.
 	* Added support for rangeset to libroarlight, roard and roarlight.
+	* Added support to load light control filters into roard.
 
 v. 1.0beta11 - Tue Jan 21 2014 21:04 CET
Index: include/libroar/roardl.h
===================================================================
--- include/libroar/roardl.h	(revision 5961)
+++ include/libroar/roardl.h	(revision 5982)
@@ -60,5 +60,5 @@
 #define ROAR_DL_FN_DRIVER               3 /* Driver, roard? */
 #define ROAR_DL_FN_SOURCE               4 /* Sources, roard? */
-#define ROAR_DL_FN_FILTER               5 /* Filter, libroardsp */
+#define ROAR_DL_FN_FILTER               5 /* Filter, libroardsp, libroarlight */
 #define ROAR_DL_FN_FF                   6 /* file format??? */
 #define ROAR_DL_FN_AUTH                 7 /* Auth */
@@ -357,4 +357,11 @@
 
 
+// Filter Infrastructure (FN_FILTER):
+// Parameters for FNREG registration: 
+#define ROAR_DL_FILTER_SUBTYPE_DSP   0 /* libroardsp */
+#define ROAR_DL_FILTER_SUBTYPE_SLFI  1 /* libroarlight */
+// ROAR_DL_FILTER_{VERSION,SIZE}_* are defined in corresponding headers.
+
+
 // Common protocol interface (CPI):
 struct roar_dl_proto {
@@ -467,4 +474,7 @@
 int                      roar_dl_unregister_fn(struct roar_dl_lhandle * lhandle);
 
+// asking for a object:
+int                      roar_dl_query_fn(struct roar_dl_lhandle ** lhandle, int fn, int subtype, const void ** object, size_t * objectlen, int version, int * options, ssize_t index);
+
 #endif
 
Index: include/libroarlight/libroarlight.h
===================================================================
--- include/libroarlight/libroarlight.h	(revision 5961)
+++ include/libroarlight/libroarlight.h	(revision 5982)
@@ -44,4 +44,5 @@
 #include "pwm.h"
 #include "laser.h"
+#include "slfi.h"
 
 #endif
Index: include/libroarlight/slfi.h
===================================================================
--- include/libroarlight/slfi.h	(revision 5982)
+++ include/libroarlight/slfi.h	(revision 5982)
@@ -0,0 +1,99 @@
+//slfi.h:
+
+/*
+ *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009-2014
+ *
+ *  This file is part of libroar a part of RoarAudio,
+ *  a cross-platform sound system for both, home and professional use.
+ *  See README for details.
+ *
+ *  This file is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3
+ *  as published by the Free Software Foundation.
+ *
+ *  libroar is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ *  NOTE for everyone want's to change something and send patches:
+ *  read README and HACKING! There a addition information on
+ *  the license of this document you need to read before you send
+ *  any patches.
+ *
+ *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
+ *  or libpulse*:
+ *  The libs libroaresd, libroararts and libroarpulse link this lib
+ *  and are therefore GPL. Because of this it may be illigal to use
+ *  them with any software that uses libesd, libartsc or libpulse*.
+ */
+
+// SLFI = Simple Light Filter Infrastructure
+
+#ifndef _LIBROARLIGHT_SLFI_H_
+#define _LIBROARLIGHT_SLFI_H_
+
+#include "libroarlight.h"
+
+enum roar_slfi_command {
+ ROAR_SLFI_CMD_NONE = 0x00000000U,
+ ROAR_SLFI_CMD_PUSH = 0x00000001U, /* push a new filter into the container */
+ ROAR_SLFI_CMD_MAX  = 0xFFFFFFFFU
+};
+
+#define ROAR_SLFI_FLAG_NONE        0x00000000U  /* no flags */
+#define ROAR_SLFI_FLAG_ON_UPDATE   0x00000001U  /* update() only needs to be run if there is an actual update */
+
+struct roar_slfi_inst;
+
+struct roar_slfi_filter {
+ const char * name;
+ const char * description;
+ const uint32_t flags;
+ // init
+ int (*init)(struct roar_slfi_inst * inst, const struct roar_keyval * para, ssize_t paralen);
+ // uninit
+ int (*uninit)(struct roar_slfi_inst * inst);
+ // update
+ int (*update)(struct roar_slfi_inst * inst, uint8_t * universe, ssize_t size_of_universe, int32_t usecspassed, const uint8_t * event, size_t eventlen);
+ // ctl
+ int (*ctl)(struct roar_slfi_inst * inst, enum roar_slfi_command command, void * argp);
+};
+
+#define ROAR_DL_FILTER_VERSION_SLFI   0
+#define ROAR_DL_FILTER_SIZE_SLFI      sizeof(struct roar_slfi_filter)
+
+#define ROAR_DL_PLUGIN_REG_SLFI(obj) \
+static int _roaraudio_library_ROAR_DL_FN_FILTER(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib) { \
+ size_t i; \
+ (void)para, (void)lib; \
+ for (i = 0; i < (sizeof((obj))/sizeof(*(obj))); i++) { \
+  ROAR_DL_PLUGIN_REG_FN(ROAR_DL_FILTER_SUBTYPE_SLFI, (obj)[i], ROAR_DL_FILTER_VERSION_SLFI); \
+ } \
+ return 0; \
+}
+
+struct roar_slfi_inst {
+ size_t refc;
+ const struct roar_slfi_filter * impl;
+ uint32_t flags; // same as flags on *impl. just runtime updateable.
+ void * userdata;
+ struct roar_dl_lhandle * lhandle; // used in case we autoload this as plugin.
+ int (*cb_event_add)(struct roar_slfi_inst * inst, void * userdata, uint8_t event);
+ void * cb_event_add_userdata;
+};
+
+struct roar_slfi_inst * roar_slfi_new(const char * name, int autoload, const struct roar_keyval * para, ssize_t paralen);
+int roar_slfi_ref(struct roar_slfi_inst * inst);
+int roar_slfi_unref(struct roar_slfi_inst * inst);
+int roar_slfi_update(struct roar_slfi_inst * inst, uint8_t * universe, ssize_t size_of_universe, int32_t usecspassed, const uint8_t * event, size_t eventlen);
+int roar_slfi_ctl(struct roar_slfi_inst * inst, enum roar_slfi_command command, void * argp);
+
+#endif
+
+//ll
Index: libroar/roardl.c
===================================================================
--- libroar/roardl.c	(revision 5961)
+++ libroar/roardl.c	(revision 5982)
@@ -1117,4 +1117,43 @@
 }
 
+
+int roar_dl_query_fn(struct roar_dl_lhandle ** lhandle, int fn, int subtype, const void ** object, size_t * objectlen, int version, int * options, ssize_t index) {
+ struct __fnregs * c = NULL;
+ ssize_t found = 0;
+ size_t j;
+
+ if ( lhandle == NULL || object == NULL || objectlen == NULL || options == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ if ( fn <= 0 || fn >= ROAR_DL_FN_MAX || index < 0 || index >= __MAX_FNREGS ) {
+  roar_err_set(ROAR_ERROR_INVAL);
+  return -1;
+ }
+
+ for (j = 0; j < __MAX_FNREGS; j++) {
+  c = &(__fnrefs[fn][j]);
+
+  if ( c->lhandle == NULL )
+   continue;
+  if ( c->subtype != subtype )
+   continue;
+  if ( c->version != version )
+   continue;
+
+  if ( index == found++ ) {
+   *lhandle   = c->lhandle;
+   *object    = c->object;
+   *objectlen = c->objectlen;
+   *options   = c->options;
+   return 0;
+  }
+ }
+
+ roar_err_set(ROAR_ERROR_NOENT);
+ return -1;
+}
+
 static inline int __load_plugin_any_get_api(struct roar_dl_librarypara * para, const char * appname, const char * appabi, const char * servicename, const char * serviceabi, int universal, struct roar_dl_service_api * api) {
  struct roar_dl_lhandle * lhandle = NULL;
Index: libroarlight/Makefile
===================================================================
--- libroarlight/Makefile	(revision 5849)
+++ libroarlight/Makefile	(revision 5982)
@@ -7,5 +7,5 @@
 
 TARGETS=$(SLIB) $(ALIB) $(IMPLIB)
-OBJS=libroarlight.o colors.o roardmx.o pwm.o
+OBJS=libroarlight.o colors.o roardmx.o pwm.o slfi.o
 
 #DEFINES        = -DDEBUG
Index: libroarlight/slfi.c
===================================================================
--- libroarlight/slfi.c	(revision 5982)
+++ libroarlight/slfi.c	(revision 5982)
@@ -0,0 +1,242 @@
+//slfi.h:
+
+/*
+ *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009-2014
+ *
+ *  This file is part of libroardsp a part of RoarAudio,
+ *  a cross-platform sound system for both, home and professional use.
+ *  See README for details.
+ *
+ *  This file is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3
+ *  as published by the Free Software Foundation.
+ *
+ *  libroardsp is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "libroarlight.h"
+
+static const struct roar_slfi_filter * __find_impl_registered(const char * name, struct roar_dl_lhandle ** lhandle) {
+ const void * impl;
+ size_t impl_size;
+ int options;
+ ssize_t i;
+
+ for (i = 0; ; i++) {
+  if ( roar_dl_query_fn(lhandle, ROAR_DL_FN_FILTER, ROAR_DL_FILTER_SUBTYPE_SLFI, &impl, &impl_size, ROAR_DL_FILTER_VERSION_SLFI, &options, i) == -1 ) {
+   return NULL;
+  }
+
+  if ( impl_size != ROAR_DL_FILTER_SIZE_SLFI ) {
+   ROAR_WARN("__find_impl_registered(*): Object %p has wrong size of %u. Strange.", impl, (unsigned int)impl_size);
+   continue;
+  }
+
+  if ( ((const struct roar_slfi_filter *)impl)->name == NULL ) {
+   ROAR_WARN("__find_impl_registered(*): Object %p has no name. Strange.", impl);
+   continue;
+  }
+
+  if ( !!strcmp(((const struct roar_slfi_filter *)impl)->name, name) )
+   continue;
+
+  return impl;
+ }
+}
+
+static struct roar_dl_lhandle * __find_impl_autoload(const char * name) {
+ struct roar_dl_lhandle * lhandle = NULL;
+ struct roar_dl_librarypara * para = NULL;
+ char buf[80];
+ int err;
+
+ para = roar_dl_para_new(NULL, NULL, LIBROAR_DL_APPNAME, LIBROAR_DL_ABIVERSION);
+ if ( para == NULL )
+  return NULL;
+
+ snprintf(buf, sizeof(buf), "filter-slfi-%s", name);
+ lhandle = roar_dl_open(buf, ROAR_DL_FLAG_PLUGIN, 1, para);
+
+ err = roar_error;
+ roar_dl_para_unref(para);
+ roar_error = err;
+
+ return lhandle;
+}
+
+static const struct roar_slfi_filter * __find_impl(const char * name, int autoload, struct roar_dl_lhandle ** lhandle) {
+ const struct roar_slfi_filter * impl;
+ struct roar_dl_lhandle * loaded_lhandle = NULL;
+ int err;
+
+ impl = __find_impl_registered(name, lhandle);
+ if ( impl != NULL ) {
+  roar_dl_ref(*lhandle);
+  return impl;
+ }
+
+ if ( autoload ) {
+  loaded_lhandle = __find_impl_autoload(name);
+  if ( loaded_lhandle == NULL )
+   return NULL;
+
+  impl = __find_impl_registered(name, lhandle);
+  if ( impl == NULL ) {
+   err = roar_error;
+   roar_dl_unref(loaded_lhandle);
+   roar_err_set(err);
+   return NULL;
+  } else if ( *lhandle != loaded_lhandle ) {
+   ROAR_WARN("__find_impl(name='%s', autoload=%i, lhandle=%p): Loaded handle and found handle do not match. Strange.", name, autoload, lhandle);
+   roar_dl_unref(loaded_lhandle);
+   roar_err_set(ROAR_ERROR_BADFH);
+   return NULL;
+  } else {
+   *lhandle = loaded_lhandle;
+   return impl;
+  }
+ }
+
+ roar_err_set(ROAR_ERROR_NOENT);
+ return NULL;
+}
+
+struct roar_slfi_inst * roar_slfi_new(const char * name, int autoload, const struct roar_keyval * para, ssize_t paralen) {
+ const struct roar_slfi_filter * impl;
+ struct roar_dl_lhandle  * lhandle = NULL;
+ struct roar_slfi_inst   * inst;
+ int err;
+
+ impl = __find_impl(name, autoload, &lhandle);
+ if ( impl == NULL )
+  return NULL;
+
+ inst = roar_mm_malloc(sizeof(*inst));
+ if ( inst == NULL )
+  return NULL;
+
+ memset(inst, 0, sizeof(*inst));
+
+ inst->refc = 1;
+ inst->impl = impl;
+ inst->flags = impl->flags;
+ inst->userdata = NULL;
+ inst->lhandle = lhandle;
+
+ if ( inst->impl->init != NULL ) {
+  if ( lhandle != NULL )
+   roar_dl_context_restore(lhandle);
+  if ( inst->impl->init(inst, para, paralen) != 0 ) {
+   err = roar_error;
+   if ( lhandle != NULL )
+    roar_dl_context_store(lhandle);
+   if ( inst->userdata != NULL )
+    roar_mm_free(inst->userdata);
+   roar_mm_free(inst);
+   if ( lhandle != NULL )
+    roar_dl_unref(lhandle);
+   roar_err_set(err);
+   return NULL;
+  }
+  if ( lhandle != NULL )
+   roar_dl_context_store(lhandle);
+ }
+
+ return inst;
+}
+
+int roar_slfi_ref(struct roar_slfi_inst * inst) {
+  if ( inst == NULL || inst->impl == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ inst->refc++;
+
+ return 0;
+}
+
+int roar_slfi_unref(struct roar_slfi_inst * inst) {
+  if ( inst == NULL || inst->impl == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ inst->refc--;
+
+ if ( inst->refc )
+  return 0;
+
+ if ( inst->impl->uninit != NULL ) {
+  if ( inst->lhandle != NULL )
+   roar_dl_context_restore(inst->lhandle);
+  inst->impl->uninit(inst);
+  if ( inst->lhandle != NULL )
+   roar_dl_context_store(inst->lhandle);
+ }
+
+ if ( inst->userdata != NULL )
+  roar_mm_free(inst->userdata);
+
+ if ( inst->lhandle != NULL )
+  roar_dl_unref(inst->lhandle);
+
+ roar_mm_free(inst);
+
+ return 0;
+}
+
+int roar_slfi_update(struct roar_slfi_inst * inst, uint8_t * universe, ssize_t size_of_universe, int32_t usecspassed, const uint8_t * event, size_t eventlen) {
+ int ret;
+
+ if ( inst == NULL || inst->impl == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ if ( inst->impl->update == NULL ) {
+  roar_err_set(ROAR_ERROR_NOSYS);
+  return -1;
+ }
+
+ if ( inst->lhandle != NULL )
+  roar_dl_context_restore(inst->lhandle);
+ ret = inst->impl->update(inst, universe, size_of_universe, usecspassed, event, eventlen);
+ if ( inst->lhandle != NULL )
+  roar_dl_context_store(inst->lhandle);
+
+ return ret;
+}
+
+int roar_slfi_ctl(struct roar_slfi_inst * inst, enum roar_slfi_command command, void * argp) {
+ int ret;
+
+ if ( inst == NULL || inst->impl == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ if ( inst->impl->ctl == NULL ) {
+  roar_err_set(ROAR_ERROR_NOSYS);
+  return -1;
+ }
+
+ if ( inst->lhandle != NULL )
+  roar_dl_context_restore(inst->lhandle);
+ ret = inst->impl->ctl(inst, command, argp);
+ if ( inst->lhandle != NULL )
+  roar_dl_context_store(inst->lhandle);
+
+ return ret;
+}
+
+//ll
Index: plugins/universal/Makefile
===================================================================
--- plugins/universal/Makefile	(revision 5902)
+++ plugins/universal/Makefile	(revision 5982)
@@ -6,5 +6,6 @@
 TARGETS_IO=piface$(SHARED_SUFFIX)
 TARGETS_SERVICE=service-about$(SHARED_SUFFIX)
-TARGETS=$(TARGETS_MISC) $(TARGETS_PROTO) $(TARGETS_SERVICE) $(TARGETS_IO)
+TARGETS_SLFI=filter-slfi-helloworld$(SHARED_SUFFIX)
+TARGETS=$(TARGETS_MISC) $(TARGETS_PROTO) $(TARGETS_SERVICE) $(TARGETS_IO) $(TARGETS_SLFI)
 
 #DEFINES        = -DDEBUG
Index: plugins/universal/filter-slfi-helloworld.c
===================================================================
--- plugins/universal/filter-slfi-helloworld.c	(revision 5982)
+++ plugins/universal/filter-slfi-helloworld.c	(revision 5982)
@@ -0,0 +1,79 @@
+//filter-slfi-helloworld.c:
+
+/*
+ *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2012-2014
+ *
+ *  This file is part of roard a part of RoarAudio,
+ *  a cross-platform sound system for both, home and professional use.
+ *  See README for details.
+ *
+ *  This file is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3
+ *  as published by the Free Software Foundation.
+ *
+ *  RoarAudio is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <roaraudio.h>
+#include <libroarlight/libroarlight.h>
+
+static int __update(struct roar_slfi_inst * inst, uint8_t * universe, ssize_t size_of_universe, int32_t usecspassed, const uint8_t * event, size_t eventlen) {
+ (void)inst, (void)usecspassed, (void)event, (void)eventlen;
+
+ if ( size_of_universe >= 2 )
+  universe[1] = universe[0]/2;
+ return 0;
+}
+
+static const struct roar_slfi_filter filter[1] = {
+ {
+  .name = "helloworld",
+  .description = "example SLFI filter",
+  .flags = ROAR_SLFI_FLAG_ON_UPDATE,
+  .init = NULL,
+  .uninit = NULL,
+  .update = __update,
+  .ctl = NULL
+ }
+};
+
+ROAR_DL_PLUGIN_REG_SLFI(filter);
+
+// This is the plugin control block.
+ROAR_DL_PLUGIN_START(filter_slfi_helloworld) {
+ // Here we set the name and vendor of our plugin.
+ // If you have no Vendor ID you need to use ROAR_DL_PLUGIN_META_PRODUCT_NV().
+ ROAR_DL_PLUGIN_META_PRODUCT_NIV("filter-slfi-helloworld", ROAR_VID_ROARAUDIO, ROAR_VNAME_ROARAUDIO);
+
+ // This sets the version of your plugin.
+ ROAR_DL_PLUGIN_META_VERSION(ROAR_VERSION_STRING);
+
+ // This sets the license of your plugin.
+ // If there is no tag for the license you use you can just
+ // use ROAR_DL_PLUGIN_META_LICENSE().
+ ROAR_DL_PLUGIN_META_LICENSE_TAG(GPLv3_0);
+
+ // This sets the author and contact infos.
+ // There are several other macros to do this with other parameters.
+ // See ROAR_DL_PLUGIN_META_CONTACT*() in the header or documentation.
+ ROAR_DL_PLUGIN_META_CONTACT_FLNE("Philipp", "Schafft", "ph3-der-loewe", "lion@lion.leolix.org");
+
+ // This sets the description for your plugin.
+ ROAR_DL_PLUGIN_META_DESC("This plugin acts as simple example for SLFI plugins.");
+
+ // Load filters.
+ ROAR_DL_PLUGIN_REG_FNFUNC(ROAR_DL_FN_FILTER);
+
+// This is the end of the control block.
+} ROAR_DL_PLUGIN_END
+
+//ll
Index: roard/include/light.h
===================================================================
--- roard/include/light.h	(revision 5980)
+++ roard/include/light.h	(revision 5982)
@@ -42,4 +42,5 @@
  uint8_t * output;
  uint8_t * outputchanges;
+ struct roar_slfi_inst * filter;
 } g_light_state;
 
@@ -57,4 +58,6 @@
 int light_check_stream  (int id);
 int light_send_stream   (int id);
+
+int light_filter_load(int primary, const char * name, int autoload, const struct roar_keyval * para, ssize_t paralen);
 
 // for plugins:
Index: roard/light.c
===================================================================
--- roard/light.c	(revision 5981)
+++ roard/light.c	(revision 5982)
@@ -70,4 +70,5 @@
 
  g_light_state.channels = channels;
+ g_light_state.filter   = NULL;
 
  if ( (g_light_mixer.stream = add_mixer(ROAR_SUBSYS_LIGHT, _MIXER_NAME("Light Control"), &ss)) == -1 ) {
@@ -92,4 +93,8 @@
 
 int light_free  (void) {
+ if ( g_light_state.filter != NULL ) {
+  roar_slfi_unref(g_light_state.filter);
+ }
+
  if ( g_light_state.state != NULL ) {
   roar_mm_free(g_light_state.state);
@@ -162,4 +167,12 @@
 
  // TODO: next run filters
+ if ( g_light_state.filter != NULL ) {
+  if ( roar_slfi_update(g_light_state.filter,
+                        g_light_state.output, g_light_state.channels,
+                        ((int32_t)1000000LU)/(int32_t)ROAR_OUTPUT_CFREQ,
+                        g_light_state.events, g_light_state.eventsqueuelen) == -1 ) {
+   ROAR_WARN("light_update(void): Can not run SLFI filter: %s", roar_errorstring);
+  }
+ }
 
  // calculate diffrence:
@@ -267,4 +280,35 @@
 }
 
+int light_filter_load(int primary, const char * name, int autoload, const struct roar_keyval * para, ssize_t paralen) {
+ struct roar_slfi_inst * filter;
+ int ret;
+ int err;
+
+ if ( primary && g_light_state.filter != NULL ) {
+  roar_err_set(ROAR_ERROR_ALREADY);
+  return -1;
+ } else if ( !primary && g_light_state.filter == NULL ) {
+  roar_err_set(ROAR_ERROR_BADSTATE);
+  return -1;
+ }
+
+ filter = roar_slfi_new(name, autoload, para, paralen);
+ if ( filter == NULL )
+  return -1;
+
+ if ( primary ) {
+  g_light_state.filter = filter;
+  return 0;
+ }
+
+ ret = roar_slfi_ctl(g_light_state.filter, ROAR_SLFI_CMD_PUSH, filter);
+ err = roar_error;
+
+ roar_slfi_unref(filter);
+
+ roar_err_set(err);
+ return ret;
+}
+
 int light_dmxchannel_get(size_t index) {
  if ( (size_t)g_light_state.channels <= index ) {
Index: roard/roard.c
===================================================================
--- roard/roard.c	(revision 5961)
+++ roard/roard.c	(revision 5982)
@@ -1301,4 +1301,42 @@
 
 
+#if defined(ROAR_HAVE_MAIN_ARGS) && !defined(ROAR_WITHOUT_DCOMP_LIGHT)
+struct light_filter {
+ const char * name;
+ char * para;
+};
+
+static int light_filter_add(int primary, struct light_filter * filter) {
+ struct roar_keyval * kv;
+ ssize_t kvlen;
+ int ret;
+ int err;
+
+ if ( filter->para == NULL ) {
+  kvlen = -1;
+  kv = NULL;
+ } else {
+  kvlen = roar_keyval_split(&kv, filter->para, NULL, NULL, 1);
+  if ( kvlen == -1 ) {
+   ROAR_ERR("light_filter_add(primar=%i, filter={name='%s', para=%p}): Can not split string: %s", primary, filter->name, filter->para, roar_errorstring);
+   return -1;
+  }
+ }
+
+ ret = light_filter_load(primary, filter->name, 1, kv, kvlen);
+ err = roar_error;
+ if ( kv != NULL )
+  roar_mm_free(kv);
+
+ if ( ret == -1 ) {
+  roar_err_set(err);
+  ROAR_ERR("light_filter_add(primary=%i, filter={name='%s', para=%p}): Can not load filter: %s", primary, filter->name, filter->para, roar_errorstring);
+  return -1;
+ }
+
+ return 0;
+}
+#endif
+
 // MAIN:
 
@@ -1399,4 +1437,9 @@
  struct roar_vio_calls pidfile_vio;
 #endif
+#if defined(ROAR_HAVE_MAIN_ARGS) && !defined(ROAR_WITHOUT_DCOMP_LIGHT)
+ struct light_filter light_filter[32] = {{"chain", NULL}};
+ int    light_filter_count = 1;
+ char * light_filter_para  = NULL;
+#endif
 
  ROAR_DBG("main(*): starting roard...");
@@ -1677,4 +1720,22 @@
   } else if ( strcmp(k, "--list-plugins") == 0 ) {
    metaaction = MA_LIST_PLUGIN;
+
+  } else if ( strcmp(k, "--light-filter-load") == 0 ) {
+   ROAR_CKHAVEARGS(1);
+   if ( light_filter_count == (sizeof(light_filter)/sizeof(*light_filter)) ) {
+    ROAR_ERR("Can not load any more light filters: %s", argv[++i]);
+   } else {
+    light_filter[light_filter_count].name = argv[++i];
+    light_filter[light_filter_count].para = light_filter_para;
+    light_filter_count++;
+   }
+   light_filter_para = NULL;
+  } else if ( strcmp(k, "--light-filter-load-primary") == 0 ) {
+   ROAR_CKHAVEARGS(1);
+   light_filter[0].name = argv[++i];
+   light_filter[0].para = light_filter_para;
+  } else if ( strcmp(k, "--light-filter-args") == 0 ) {
+   ROAR_CKHAVEARGS(1);
+   light_filter_para = argv[++i];
 
   } else if ( strcmp(k, "--guest-acclev") == 0 ) {
@@ -2335,4 +2396,7 @@
   ROAR_ERR("Can not initialize light control subsystem");
  }
+ light_filter_add(1, &(light_filter[0]));
+ for (i = 1; i < light_filter_count; i++)
+  light_filter_add(0, &(light_filter[i]));
 #endif
 
