Index: ChangeLog
===================================================================
--- ChangeLog	(revision 5902)
+++ ChangeLog	(revision 5908)
@@ -4,4 +4,5 @@
 	* Added GPIO service.
 	* Added GPIO driver: piface.
+	* Added roard driver: i2cdmx.
 
 v. 1.0beta9 - Mon Feb 18 2013 23:28 CET
Index: configure
===================================================================
--- configure	(revision 5902)
+++ configure	(revision 5908)
@@ -662,6 +662,8 @@
 test_lib_defmake ROAR_HAVE_H_ICONV       %            iconv.h       c          -- iconv.h
 test_lib_defmake ROAR_HAVE_H_NETINET_IN  %            'netinet/in.h' c         -- 'netinet/in.h'
-test_lib_defmake ROAR_HAVE_H_LINUX_REBOOT %            linux/reboot.h c        -- linux/reboot.h
-test_lib_defmake ROAR_HAVE_H_LINUX_SPI_SPIDEV %            linux/spi/spidev.h c        -- linux/spi/spidev.h
+test_lib_defmake ROAR_HAVE_H_LINUX_REBOOT %           linux/reboot.h c         -- linux/reboot.h
+test_lib_defmake ROAR_HAVE_H_LINUX_SPI_SPIDEV %       linux/spi/spidev.h c     -- linux/spi/spidev.h
+test_lib_defmake ROAR_HAVE_H_LINUX_I2C   %            linux/i2c.h   c          -- linux/i2c.h
+test_lib_defmake ROAR_HAVE_H_LINUX_I2C_DEV   %        linux/i2c-dev.h   c      -- linux/i2c-dev.h
 test_lib_defmake ROAR_HAVE_H_WINDOWS     %            windows.h     c          -- windows.h
 test_lib_defmake ROAR_HAVE_H_WINSOCK     %            winsock.h     c          -- winsock.h
Index: roard/Makefile
===================================================================
--- roard/Makefile	(revision 5851)
+++ roard/Makefile	(revision 5908)
@@ -3,5 +3,5 @@
 OBJ=roard.o driver.o mixer.o output.o signals.o loop.o clients.o streams.o network.o commands.o req.o sources.o sample.o meta.o codecfilter.o lib.o ssynth.o container_framework.o plugins.o memlock.o hwmixer.o auth.o caps.o rolestack.o
 SUBSYS=midi.o light.o raw.o rdtcs.o waveform.o beep.o
-DRV=driver_esd.o driver_ao.o driver_roar.o driver_oss.o driver_shout.o driver_sndio.o driver_dmx.o driver_pwmled.o driver_sysclock.o driver_wmm.o driver_dstr.o driver_alsa.o driver_rsound.o driver_portaudio.o driver_pulsesimple.o driver_jack.o driver_artsc.o
+DRV=driver_esd.o driver_ao.o driver_roar.o driver_oss.o driver_shout.o driver_sndio.o driver_dmx.o driver_pwmled.o driver_i2cdmx.o driver_sysclock.o driver_wmm.o driver_dstr.o driver_alsa.o driver_rsound.o driver_portaudio.o driver_pulsesimple.o driver_jack.o driver_artsc.o
 CF_CODEC=codecfilter_cmd.o codecfilter_vorbis.o codecfilter_celt.o codecfilter_speex.o codecfilter_alaw.o codecfilter_mulaw.o codecfilter_sndfile.o codecfilter_fishsound.o codecfilter_flac.o
 CF_CONTAINER=codecfilter_wave.o codecfilter_raum.o codecfilter_au.o
Index: roard/driver.c
===================================================================
--- roard/driver.c	(revision 5823)
+++ roard/driver.c	(revision 5908)
@@ -81,4 +81,8 @@
  {"pwmled", "PWM LED driver", "/dev/ttyS0", STREAM_DIR_OUT, DRV_FLAG_FHSEC, ROAR_SUBSYS_LIGHT,
   NULL, NULL, driver_pwmled_open_vio},
+#endif
+#ifdef ROAR_HAVE_DRIVER_I2CDMX
+ {"i2cdmx", "I^2C DMX Interface driver", "/dev/i2c-1", STREAM_DIR_BIDIR, DRV_FLAG_NONE, ROAR_SUBSYS_LIGHT,
+  NULL, NULL, driver_i2cdmx_open_vio},
 #endif
 #ifdef ROAR_HAVE_DRIVER_SYSCLOCK
Index: roard/driver_i2cdmx.c
===================================================================
--- roard/driver_i2cdmx.c	(revision 5908)
+++ roard/driver_i2cdmx.c	(revision 5908)
@@ -0,0 +1,382 @@
+//driver_i2cdmx.c:
+
+/*
+ *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2011-2013
+ *
+ *  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 "roard.h"
+
+#ifdef ROAR_HAVE_DRIVER_I2CDMX
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define DEFAULT_DEVICE  "/dev/i2c-1"
+
+#define DEV_TYPE        0x00 /* FIXME */
+#define DEV_SUBTYPE     0x00 /* FIXME */
+
+#define MIN_ADDR        0x20
+#define MAX_ADDR        0x70
+#define MAX_BUSSES      8
+
+#define ADDR_IFVERSION  0
+#define ADDR_DEVSTATUS  1
+#define ADDR_COMMAND    2
+#define ADDR_DEVERROR   3
+#define ADDR_BANK       4
+#define ADDR_DATA       5
+#define ADDR_VENDOR     (ADDR_BANK+2)
+#define ADDR_TYPE       (ADDR_BANK+3)
+#define ADDR_SUBTYPE    (ADDR_BANK+4)
+#define ADDR_PVENDOR    (ADDR_BANK+10)
+#define ADDR_PTYPE      (ADDR_BANK+11)
+#define ADDR_PSUBTYPE   (ADDR_BANK+12)
+
+#define COMMAND_DEVINFO 0x00
+#define COMMAND_DMX     0x3f
+
+struct driver_i2cdmx {
+ struct roar_vio_calls vio;
+ uint8_t slave;
+ size_t startaddr;
+ size_t len;
+};
+
+static inline int __i2c_set_slave(struct driver_i2cdmx * self) {
+ struct roar_vio_sysio_ioctl ctl = {.cmd = I2C_SLAVE, .argp = (void*)(int)self->slave};
+
+ return roar_vio_ctl(&(self->vio), ROAR_VIO_CTL_SYSIO_IOCTL, &ctl);
+}
+
+static inline int16_t __i2c_read(struct driver_i2cdmx * self, size_t off) {
+ union i2c_smbus_data data = {.byte = 0};
+ struct i2c_smbus_ioctl_data args = {.read_write = I2C_SMBUS_READ, .command = off, .size = I2C_SMBUS_BYTE_DATA, .data = &data};
+ struct roar_vio_sysio_ioctl ctl = {.cmd = I2C_SMBUS, .argp = &args};
+ int ret = roar_vio_ctl(&(self->vio), ROAR_VIO_CTL_SYSIO_IOCTL, &ctl);
+
+ if ( ret == -1 )
+  return (int16_t)-1;
+
+ return (int16_t)(uint16_t)(uint8_t)data.byte;
+}
+
+static inline int __i2c_write(struct driver_i2cdmx * self, size_t off, const uint8_t value) {
+ union i2c_smbus_data data = {.byte = value};
+ struct i2c_smbus_ioctl_data args = {.read_write = I2C_SMBUS_WRITE, .command = off, .size = I2C_SMBUS_BYTE_DATA, .data = &data};
+ struct roar_vio_sysio_ioctl ctl = {.cmd = I2C_SMBUS, .argp = &args};
+
+ return roar_vio_ctl(&(self->vio), ROAR_VIO_CTL_SYSIO_IOCTL, &ctl);
+}
+
+static inline int __i2c_command(struct driver_i2cdmx * self, uint8_t command) {
+ int16_t ret;
+
+ if ( __i2c_write(self, ADDR_COMMAND, command) == -1 )
+  return -1;
+
+ ret = __i2c_read(self, ADDR_DEVERROR);
+ if ( ret == (int16_t)-1 )
+  return -1;
+
+ if ( ret == ROAR_ERROR_NONE )
+  return 0;
+
+ roar_err_set(ret);
+ return -1;
+}
+
+static inline int __i2c_start_dmx(struct driver_i2cdmx * self) {
+ return __i2c_command(self, COMMAND_DMX);
+}
+
+static int __open_test_device_type(int16_t vendor, int16_t type, int16_t subtype) {
+ if ( vendor == -1 || type == -1 || subtype == -1 )
+  return -1;
+
+ if ( vendor != ROAR_VID_ROARAUDIO || type != DEV_TYPE || subtype != DEV_SUBTYPE ) {
+  roar_err_set(ROAR_ERROR_TYPEMM);
+  return -1;
+ }
+
+ return 0;
+}
+
+static int __open_test_device(struct driver_i2cdmx * self) {
+ int16_t ret;
+ int16_t vendor, type, subtype;
+
+#define __check_response(resp,test,error) if ( (resp) == (int16_t)-1 ) return -1; if ( !(test) ) { roar_err_set((error)); return -1; }
+
+ // test for device interface version
+ ret = __i2c_read(self, ADDR_IFVERSION);
+ __check_response(ret, ret == 0, ROAR_ERROR_NSVERSION);
+
+ // test for device overall status
+ ret = __i2c_read(self, ADDR_IFVERSION);
+ __check_response(ret, ret & 0x01, ROAR_ERROR_NSVERSION);
+
+ // Request device infos
+ if ( __i2c_command(self, COMMAND_DEVINFO) == -1 )
+  return -1;
+
+ // Check device infos
+ // first check device type, then parent device type:
+ vendor  = __i2c_read(self, ADDR_VENDOR);
+ type    = __i2c_read(self, ADDR_TYPE);
+ subtype = __i2c_read(self, ADDR_SUBTYPE);
+
+ if ( __open_test_device_type(vendor, type, subtype) == 0 )
+  return 0;
+
+ vendor  = __i2c_read(self, ADDR_PVENDOR);
+ type    = __i2c_read(self, ADDR_PTYPE);
+ subtype = __i2c_read(self, ADDR_PSUBTYPE);
+
+ return __open_test_device_type(vendor, type, subtype);
+}
+
+static int __open_scan_devices(struct driver_i2cdmx * self) {
+ uint8_t i;
+
+ for (i = MIN_ADDR; i < MAX_ADDR; i++) {
+  self->slave = i;
+
+  if ( __i2c_set_slave(self) == -1 )
+   continue;
+
+  if ( __open_test_device(self) == -1 )
+   continue;
+
+  return 0;
+ }
+
+ self->slave = 0;
+ roar_err_set(ROAR_ERROR_NOENT);
+ return -1;
+}
+
+static int __open_device_and_slave(struct driver_i2cdmx * self, int autoconf, const char * device) {
+ char filename[40];
+ char * p;
+ int need_autoconf = 0;
+ int ret;
+ int err;
+
+ // test if the device exist.
+ if ( roar_vio_open_dstr_simple(&(self->vio), device, ROAR_VIOF_READWRITE) == 0 ) {
+  need_autoconf = 1;
+ } else {
+  // the device doesn't exist. We guss it is in form $device/$slaveid.
+  roar_mm_strlcat(filename, device, sizeof(filename));
+  p = strrchr(filename, '/');
+  if ( p == NULL ) {
+   // it doesn't seem to be in the given form so it seems it was just a device name of an missingd evice.
+   roar_err_set(ROAR_ERROR_NOENT);
+   return -1;
+  }
+
+  *p = 0;
+  p++;
+
+  // now we have the device name in filename, and the slave ID in p.
+  self->slave = atoi(p);
+
+  // little test to protect the user from doing dumb things.
+  if ( self->slave == 0 ) {
+   roar_err_set(ROAR_ERROR_INVAL);
+   return -1;
+  }
+
+  if ( roar_vio_open_dstr_simple(&(self->vio), filename, ROAR_VIOF_READWRITE) == -1 )
+   return -1;
+ }
+
+ // ok, the bus is now open. Let's open the device:
+
+ if ( need_autoconf ) {
+  ret = __open_scan_devices(self);
+ } else {
+  ret = __i2c_set_slave(self);
+  if ( ret == 0 )
+   ret = __open_test_device(self);
+ }
+
+ if ( ret == -1 ) {
+  err = roar_error;
+  roar_vio_close(&(self->vio));
+  roar_err_set(err);
+ }
+
+ return ret;
+}
+
+static int __open_scan_busses(struct driver_i2cdmx * self) {
+ char filename[20];
+ int i;
+ int ret;
+
+ for (i = 0; i < MAX_BUSSES; i++) {
+  snprintf(filename, sizeof(filename), "/dev/i2c-%i", i);
+  ret = __open_device_and_slave(self, 1, filename);
+  if ( ret == 0 )
+   return 0;
+ }
+
+ roar_err_set(ROAR_ERROR_NOENT);
+ return -1;
+}
+
+static int __i2c_write_channel(struct driver_i2cdmx * self, size_t channel, uint8_t value) {
+ size_t bank, offset;
+
+ bank = channel/32;
+ offset = bank*32;
+
+ if ( __i2c_write(self, ADDR_BANK, bank) == -1 )
+  return -1;
+
+ return __i2c_write(self, ADDR_DATA+channel-offset, value);
+}
+
+static ssize_t        __vio_read    (struct roar_vio_calls * vio, void *buf, size_t count) {
+ struct driver_i2cdmx * self;
+
+ if ( vio == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ self = vio->inst;
+
+ if ( __i2c_start_dmx(self) == -1 )
+  return -1;
+
+ roar_err_set(ROAR_ERROR_NOSYS);
+ return -1;
+}
+
+static ssize_t        __vio_write   (struct roar_vio_calls * vio, void *buf, size_t count) {
+ struct driver_i2cdmx * self;
+ size_t i;
+ size_t endaddr;
+
+ if ( vio == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ self = vio->inst;
+
+ if ( count != 512 ) {
+  roar_err_set(ROAR_ERROR_INVAL);
+  return -1;
+ }
+
+ if ( __i2c_start_dmx(self) == -1 )
+  return -1;
+
+ for (i = self->startaddr, endaddr = self->startaddr + self->len; i < endaddr; i++)
+  if ( __i2c_write_channel(self, i, ((uint8_t*)buf)[i]) == -1 )
+   return -1;
+
+ return count;
+}
+
+static int            __vio_ctl     (struct roar_vio_calls * vio, roar_vio_ctl_t cmd, void * data) {
+ struct driver_i2cdmx * self;
+
+ if ( vio == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ self = vio->inst;
+
+ switch (cmd) {
+  case ROAR_VIO_CTL_SET_SSTREAM:
+    if ( ROAR_STREAM(data)->dir != ROAR_DIR_LIGHT_OUT && ROAR_STREAM(data)->dir != ROAR_DIR_LIGHT_IN ) {
+     ROAR_STREAM(data)->dir = ROAR_DIR_LIGHT_OUT;
+    }
+    ROAR_STREAM_SERVER(data)->codec_orgi = ROAR_CODEC_DMX512;
+   break;
+  default:
+   roar_err_set(ROAR_ERROR_BADRQC);
+   return -1;
+ }
+
+ return 0;
+}
+
+static int            __vio_close   (struct roar_vio_calls * vio) {
+ struct driver_i2cdmx * self = vio->inst;
+ roar_vio_close(&(self->vio));
+ roar_mm_free(self);
+ return 0;
+}
+
+int driver_i2cdmx_open_vio  (struct roar_vio_calls * inst, char * device, struct roar_audio_info * info, int fh, struct roar_stream_server * sstream) {
+ struct driver_i2cdmx * self;
+ int autoconf = 1;
+ int ret;
+
+ if ( fh != -1 ) {
+  roar_err_set(ROAR_ERROR_NOSYS);
+  return -1;
+ }
+
+ self = roar_mm_malloc(sizeof(struct driver_i2cdmx));
+ if ( self == NULL ) {
+  return -1;
+ }
+ memset(self, 0, sizeof(*self));
+ self->startaddr = 0;
+ self->len       = info->channels;
+
+ info->bits      = 8;
+ info->codec     = ROAR_CODEC_DMX512;
+
+ if ( device == NULL && !autoconf ) {
+  device = DEFAULT_DEVICE;
+ }
+
+ if ( device == NULL ) {
+  ret = __open_scan_busses(self);
+ } else {
+  ret = __open_device_and_slave(self, autoconf, device);
+ }
+
+ if ( ret == -1 ) {
+  roar_mm_free_noerror(self);
+  return -1;
+ }
+
+ roar_vio_clear_calls(inst);
+ inst->inst  = self;
+ inst->read  = __vio_read;
+ inst->write = __vio_write;
+ inst->close = __vio_close;
+ inst->ctl   = __vio_ctl;
+
+ return 0;
+}
+#endif
Index: roard/include/driver.h
===================================================================
--- roard/include/driver.h	(revision 5823)
+++ roard/include/driver.h	(revision 5908)
@@ -115,4 +115,9 @@
 #endif
 
+#if !defined(ROAR_WITHOUT_VIO_DSTR) && !defined(ROAR_WITHOUT_DCOMP_DMX) && defined(ROAR_HAVE_H_LINUX_I2C) && defined(ROAR_HAVE_H_LINUX_I2C_DEV)
+#define ROAR_HAVE_DRIVER_I2CDMX
+int driver_i2cdmx_open_vio  (struct roar_vio_calls * inst, char * device, struct roar_audio_info * info, int fh, struct roar_stream_server * sstream);
+#endif
+
 #define DRV_FLAG_NONE           0x00
 #define DRV_FLAG_FHSEC          0x01
