Added VoE handler.
authorFlorian Pose <fp@igh-essen.com>
Mon, 01 Sep 2008 14:17:18 +0000
changeset 1209 8be462afb7f4
parent 1208 026e35646ab4
child 1210 e9e71d56c3fa
Added VoE handler.
examples/mini/mini.c
include/ecrt.h
master/Kbuild.in
master/Makefile.am
master/cdev.c
master/cdev.h
master/device.h
master/ethernet.c
master/ethernet.h
master/fmmu_config.h
master/fsm_change.h
master/fsm_coe.h
master/fsm_master.c
master/fsm_master.h
master/fsm_pdo.h
master/fsm_pdo_entry.h
master/fsm_sii.h
master/fsm_slave_config.h
master/fsm_slave_scan.h
master/globals.h
master/master.c
master/module.c
master/pdo.h
master/pdo_entry.h
master/pdo_list.h
master/sdo_request.c
master/sdo_request.h
master/slave.h
master/slave_config.c
master/slave_config.h
master/sync.h
master/sync_config.h
master/voe_handler.c
master/voe_handler.h
--- a/examples/mini/mini.c	Wed Aug 27 16:04:18 2008 +0000
+++ b/examples/mini/mini.c	Mon Sep 01 14:17:18 2008 +0000
@@ -48,6 +48,7 @@
 #define EL3152_ALT_PDOS 0
 #define EXTERNAL_MEMORY 1
 #define SDO_ACCESS      0
+#define VOE_ACCESS      0
 
 #define PFX "ec_mini: "
 
@@ -184,6 +185,10 @@
 static ec_sdo_request_t *sdo;
 #endif
 
+#if VOE_ACCESS
+static ec_voe_handler_t *voe;
+#endif
+
 /*****************************************************************************/
 
 void check_domain1_state(void)
@@ -249,18 +254,18 @@
 void read_sdo(void)
 {
     switch (ecrt_sdo_request_state(sdo)) {
-        case EC_SDO_REQUEST_UNUSED: // request was not used yet
+        case EC_REQUEST_UNUSED: // request was not used yet
             ecrt_sdo_request_read(sdo); // trigger first read
             break;
-        case EC_SDO_REQUEST_BUSY:
+        case EC_REQUEST_BUSY:
             printk(KERN_INFO PFX "Still busy...\n");
             break;
-        case EC_SDO_REQUEST_SUCCESS:
+        case EC_REQUEST_SUCCESS:
             printk(KERN_INFO PFX "Sdo value: 0x%04X\n",
                     EC_READ_U16(ecrt_sdo_request_data(sdo)));
             ecrt_sdo_request_read(sdo); // trigger next read
             break;
-        case EC_SDO_REQUEST_ERROR:
+        case EC_REQUEST_ERROR:
             printk(KERN_INFO PFX "Failed to read Sdo!\n");
             ecrt_sdo_request_read(sdo); // retry reading
             break;
@@ -270,6 +275,31 @@
 
 /*****************************************************************************/
 
+#if VOE_ACCESS
+void read_voe(void)
+{
+    switch (ecrt_voe_handler_execute(voe)) {
+        case EC_REQUEST_UNUSED:
+            ecrt_voe_handler_read(voe); // trigger first read
+            break;
+        case EC_REQUEST_BUSY:
+            printk(KERN_INFO PFX "VoE read still busy...\n");
+            break;
+        case EC_REQUEST_SUCCESS:
+            printk(KERN_INFO PFX "VoE received.\n");
+            // get data via ecrt_voe_handler_data(voe)
+            ecrt_voe_handler_read(voe); // trigger next read
+            break;
+        case EC_REQUEST_ERROR:
+            printk(KERN_INFO PFX "Failed to read VoE data!\n");
+            ecrt_voe_handler_read(voe); // retry reading
+            break;
+    }
+}
+#endif
+
+/*****************************************************************************/
+
 void cyclic_task(unsigned long data)
 {
     // receive process data
@@ -299,6 +329,10 @@
         // read process data Sdo
         read_sdo();
 #endif
+
+#if VOE_ACCESS
+        read_voe();
+#endif
     }
 
     // write process data
@@ -401,6 +435,14 @@
     ecrt_sdo_request_timeout(sdo, 500); // ms
 #endif
 
+#if VOE_ACCESS
+    printk(KERN_INFO PFX "Creating VoE handlers...\n");
+    if (!(voe = ecrt_slave_config_create_voe_handler(sc_ana_in, 1000))) {
+        printk(KERN_ERR PFX "Failed to create VoE handler.\n");
+        goto out_release_master;
+    }
+#endif
+
     printk(KERN_INFO PFX "Registering Pdo entries...\n");
     if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
         printk(KERN_ERR PFX "Pdo entry registration failed!\n");
--- a/include/ecrt.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/include/ecrt.h	Mon Sep 01 14:17:18 2008 +0000
@@ -113,7 +113,7 @@
 
 /** EtherCAT realtime interface minor version number.
  */
-#define ECRT_VER_MINOR 4
+#define ECRT_VER_MINOR 5
 
 /** EtherCAT realtime interface version word generator.
  */
@@ -151,6 +151,9 @@
 struct ec_sdo_request;
 typedef struct ec_sdo_request ec_sdo_request_t; /**< \see ec_sdo_request. */
 
+struct ec_voe_handler;
+typedef struct ec_voe_handler ec_voe_handler_t; /**< \see ec_voe_handler. */
+
 /*****************************************************************************/
 
 /** Master state.
@@ -305,16 +308,17 @@
 
 /*****************************************************************************/
 
-/** Sdo request state.
- *
- * This is used as return type of ecrt_sdo_request_state().
+/** Request state.
+ *
+ * This is used as return type for ecrt_sdo_request_state() and
+ * ecrt_voe_handler_state().
  */
 typedef enum {
-    EC_SDO_REQUEST_UNUSED, /**< Not requested. */
-    EC_SDO_REQUEST_BUSY, /**< Request is being processed. */
-    EC_SDO_REQUEST_SUCCESS, /**< Request was processed successfully. */
-    EC_SDO_REQUEST_ERROR, /**< Request processing failed. */
-} ec_sdo_request_state_t;
+    EC_REQUEST_UNUSED, /**< Not requested. */
+    EC_REQUEST_BUSY, /**< Request is being processed. */
+    EC_REQUEST_SUCCESS, /**< Request was processed successfully. */
+    EC_REQUEST_ERROR, /**< Request processing failed. */
+} ec_request_state_t;
 
 /******************************************************************************
  * Global functions
@@ -727,6 +731,17 @@
         size_t size /**< Data size to reserve. */
         );
 
+/** Create an VoE handler to exchange vendor-specific data during realtime
+ * operation.
+ *
+ * The created VoE handler object is freed automatically when the master is
+ * released.
+ */
+ec_voe_handler_t *ecrt_slave_config_create_voe_handler(
+        ec_slave_config_t *sc, /**< Slave configuration. */
+        size_t size /**< Data size to reserve. */
+        );
+
 /** Outputs the state of the slave configuration.
  *
  * Stores the state information in the given \a state structure.
@@ -878,7 +893,7 @@
  *
  * \return Request state.
  */
-ec_sdo_request_state_t ecrt_sdo_request_state(
+ec_request_state_t ecrt_sdo_request_state(
     const ec_sdo_request_t *req /**< Sdo request. */
     );
 
@@ -904,6 +919,73 @@
         ec_sdo_request_t *req /**< Sdo request. */
         );
 
+/*****************************************************************************
+ * VoE handler methods.
+ ****************************************************************************/
+
+/** Access to the VoE handler's data.
+ *
+ * This function returns a pointer to the handler's internal memory.
+ *
+ * - After a read operation was successful, the memory contains the received
+ *   data. The size of the received data can be determined via
+ *   ecrt_voe_handler_data_size().
+ * - Before a write operation is triggered, the data have to be written to
+ *   the internal memory. Be sure, that the data fit into the memory. The
+ *   memory size is a parameter of ecrt_slave_config_create_voe_handler().
+ *
+ * \return Pointer to the internal memory.
+ */
+uint8_t *ecrt_voe_handler_data(
+        ec_voe_handler_t *voe /**< VoE handler. */
+        );
+
+/** Returns the current data size.
+ *
+ * When the VoE handler is created, the data size is set to the size of the
+ * reserved memory. At a write operation, the data size is set to the number
+ * of bytes to write. After a read operation the size is set to the size of
+ * the read data. The size is not modified in any other situation.
+ *
+ * \return Data size in bytes.
+ */
+size_t ecrt_voe_handler_data_size(
+        const ec_voe_handler_t *voe /**< VoE handler. */
+        );
+
+/** Start a VoE write operation.
+ *
+ * After this function has been called, the ecrt_voe_handler_execute() method
+ * must be called in every bus cycle as long as it returns EC_REQUEST_BUSY.
+ */
+void ecrt_voe_handler_write(
+        ec_voe_handler_t *voe, /**< VoE handler. */
+        size_t size /**< Number of bytes to write. */
+        );
+
+/** Start a VoE read operation.
+ *
+ * After this function has been called, the ecrt_voe_handler_execute() method
+ * must be called in every bus cycle as long as it returns EC_REQUEST_BUSY.
+ *
+ * On success, the size of the read data can be determined via
+ * ecrt_voe_handler_data_size().
+ */
+void ecrt_voe_handler_read(
+        ec_voe_handler_t *voe /**< VoE handler. */
+        );
+
+/** Execute the handler.
+ *
+ * This method executes the VoE handler. It has to be called in every bus cycle
+ * as long as it returns EC_REQUEST_BUSY.
+ *
+ * \return Handler state.
+ */
+ec_request_state_t ecrt_voe_handler_execute(
+    ec_voe_handler_t *voe /**< VoE handler. */
+    );
+
 /******************************************************************************
  * Bitwise read/write macros
  *****************************************************************************/
--- a/master/Kbuild.in	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/Kbuild.in	Mon Sep 01 14:17:18 2008 +0000
@@ -61,7 +61,8 @@
 	slave.o \
 	slave_config.o \
 	sync.o \
-	sync_config.o
+	sync_config.o \
+	voe_handler.o
 
 ifeq (@ENABLE_EOE@,1)
 	ec_master-objs += ethernet.o
--- a/master/Makefile.am	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/Makefile.am	Mon Sep 01 14:17:18 2008 +0000
@@ -64,7 +64,8 @@
 	slave.c slave.h \
 	slave_config.c slave_config.h \
 	sync.c sync.h \
-	sync_config.c sync_config.h
+	sync_config.c sync_config.h \
+	voe_handler.c voe_handler.h
 
 BUILT_SOURCES = \
 	Kbuild
--- a/master/cdev.c	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/cdev.c	Mon Sep 01 14:17:18 2008 +0000
@@ -726,10 +726,10 @@
 
     // wait for processing through FSM
     if (wait_event_interruptible(master->sdo_queue,
-                request.req.state != EC_REQUEST_QUEUED)) {
+                request.req.state != EC_INT_REQUEST_QUEUED)) {
         // interrupted by signal
         down(&master->master_sem);
-        if (request.req.state == EC_REQUEST_QUEUED) {
+        if (request.req.state == EC_INT_REQUEST_QUEUED) {
             list_del(&request.req.list);
             up(&master->master_sem);
             ec_sdo_request_clear(&request.req);
@@ -740,11 +740,11 @@
     }
 
     // wait until master FSM has finished processing
-    wait_event(master->sdo_queue, request.req.state != EC_REQUEST_BUSY);
+    wait_event(master->sdo_queue, request.req.state != EC_INT_REQUEST_BUSY);
 
     data.abort_code = request.req.abort_code;
 
-    if (request.req.state != EC_REQUEST_SUCCESS) {
+    if (request.req.state != EC_INT_REQUEST_SUCCESS) {
         data.data_size = 0;
         retval = -EIO;
     } else {
@@ -828,10 +828,10 @@
 
     // wait for processing through FSM
     if (wait_event_interruptible(master->sdo_queue,
-                request.req.state != EC_REQUEST_QUEUED)) {
+                request.req.state != EC_INT_REQUEST_QUEUED)) {
         // interrupted by signal
         down(&master->master_sem);
-        if (request.req.state == EC_REQUEST_QUEUED) {
+        if (request.req.state == EC_INT_REQUEST_QUEUED) {
             list_del(&request.req.list);
             up(&master->master_sem);
             ec_sdo_request_clear(&request.req);
@@ -842,11 +842,11 @@
     }
 
     // wait until master FSM has finished processing
-    wait_event(master->sdo_queue, request.req.state != EC_REQUEST_BUSY);
+    wait_event(master->sdo_queue, request.req.state != EC_INT_REQUEST_BUSY);
 
     data.abort_code = request.req.abort_code;
 
-    retval = request.req.state == EC_REQUEST_SUCCESS ? 0 : -EIO;
+    retval = request.req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
 
     if (__copy_to_user((void __user *) arg, &data, sizeof(data))) {
         retval = -EFAULT;
@@ -954,7 +954,7 @@
     request.words = words;
     request.offset = data.offset;
     request.nwords = data.nwords;
-    request.state = EC_REQUEST_QUEUED;
+    request.state = EC_INT_REQUEST_QUEUED;
 
     // schedule SII write request.
     list_add_tail(&request.list, &master->sii_requests);
@@ -963,10 +963,10 @@
 
     // wait for processing through FSM
     if (wait_event_interruptible(master->sii_queue,
-                request.state != EC_REQUEST_QUEUED)) {
+                request.state != EC_INT_REQUEST_QUEUED)) {
         // interrupted by signal
         down(&master->master_sem);
-        if (request.state == EC_REQUEST_QUEUED) {
+        if (request.state == EC_INT_REQUEST_QUEUED) {
             // abort request
             list_del(&request.list);
             up(&master->master_sem);
@@ -977,11 +977,11 @@
     }
 
     // wait until master FSM has finished processing
-    wait_event(master->sii_queue, request.state != EC_REQUEST_BUSY);
+    wait_event(master->sii_queue, request.state != EC_INT_REQUEST_BUSY);
 
     kfree(words);
 
-    return request.state == EC_REQUEST_SUCCESS ? 0 : -EIO;
+    return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
 }
 
 /*****************************************************************************/
@@ -1027,7 +1027,7 @@
     request.data = contents;
     request.offset = data.offset;
     request.length = data.length;
-    request.state = EC_REQUEST_QUEUED;
+    request.state = EC_INT_REQUEST_QUEUED;
 
     // schedule request.
     list_add_tail(&request.list, &master->phy_requests);
@@ -1036,10 +1036,10 @@
 
     // wait for processing through FSM
     if (wait_event_interruptible(master->phy_queue,
-                request.state != EC_REQUEST_QUEUED)) {
+                request.state != EC_INT_REQUEST_QUEUED)) {
         // interrupted by signal
         down(&master->master_sem);
-        if (request.state == EC_REQUEST_QUEUED) {
+        if (request.state == EC_INT_REQUEST_QUEUED) {
             // abort request
             list_del(&request.list);
             up(&master->master_sem);
@@ -1050,15 +1050,15 @@
     }
 
     // wait until master FSM has finished processing
-    wait_event(master->phy_queue, request.state != EC_REQUEST_BUSY);
-
-    if (request.state == EC_REQUEST_SUCCESS) {
+    wait_event(master->phy_queue, request.state != EC_INT_REQUEST_BUSY);
+
+    if (request.state == EC_INT_REQUEST_SUCCESS) {
         if (copy_to_user((void __user *) data.data, contents, data.length))
             return -EFAULT;
     }
     kfree(contents);
 
-    return request.state == EC_REQUEST_SUCCESS ? 0 : -EIO;
+    return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
 }
 
 /*****************************************************************************/
@@ -1110,7 +1110,7 @@
     request.data = contents;
     request.offset = data.offset;
     request.length = data.length;
-    request.state = EC_REQUEST_QUEUED;
+    request.state = EC_INT_REQUEST_QUEUED;
 
     // schedule request.
     list_add_tail(&request.list, &master->phy_requests);
@@ -1119,10 +1119,10 @@
 
     // wait for processing through FSM
     if (wait_event_interruptible(master->phy_queue,
-                request.state != EC_REQUEST_QUEUED)) {
+                request.state != EC_INT_REQUEST_QUEUED)) {
         // interrupted by signal
         down(&master->master_sem);
-        if (request.state == EC_REQUEST_QUEUED) {
+        if (request.state == EC_INT_REQUEST_QUEUED) {
             // abort request
             list_del(&request.list);
             up(&master->master_sem);
@@ -1133,11 +1133,11 @@
     }
 
     // wait until master FSM has finished processing
-    wait_event(master->phy_queue, request.state != EC_REQUEST_BUSY);
+    wait_event(master->phy_queue, request.state != EC_INT_REQUEST_BUSY);
 
     kfree(contents);
 
-    return request.state == EC_REQUEST_SUCCESS ? 0 : -EIO;
+    return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
 }
 
 /*****************************************************************************/
--- a/master/cdev.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/cdev.h	Mon Sep 01 14:17:18 2008 +0000
@@ -45,7 +45,6 @@
 #include <linux/cdev.h>
 
 #include "globals.h"
-#include "../include/ecrt.h"
 
 /*****************************************************************************/
 
--- a/master/device.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/device.h	Mon Sep 01 14:17:18 2008 +0000
@@ -43,7 +43,6 @@
 
 #include <linux/interrupt.h>
 
-#include "../include/ecrt.h"
 #include "../devices/ecdev.h"
 #include "globals.h"
 
--- a/master/ethernet.c	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/ethernet.c	Mon Sep 01 14:17:18 2008 +0000
@@ -41,7 +41,6 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 
-#include "../include/ecrt.h"
 #include "globals.h"
 #include "master.h"
 #include "slave.h"
--- a/master/ethernet.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/ethernet.h	Mon Sep 01 14:17:18 2008 +0000
@@ -41,7 +41,6 @@
 #include <linux/list.h>
 #include <linux/netdevice.h>
 
-#include "../include/ecrt.h"
 #include "globals.h"
 #include "slave.h"
 #include "datagram.h"
--- a/master/fmmu_config.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/fmmu_config.h	Mon Sep 01 14:17:18 2008 +0000
@@ -40,8 +40,6 @@
 #ifndef __EC_FMMU_CONFIG_H__
 #define __EC_FMMU_CONFIG_H__
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 #include "sync.h"
 
--- a/master/fsm_change.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/fsm_change.h	Mon Sep 01 14:17:18 2008 +0000
@@ -42,7 +42,6 @@
 #define __EC_FSM_CHANGE_H__
 
 #include "globals.h"
-#include "../include/ecrt.h"
 #include "datagram.h"
 #include "slave.h"
 
--- a/master/fsm_coe.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/fsm_coe.h	Mon Sep 01 14:17:18 2008 +0000
@@ -42,7 +42,6 @@
 #define __EC_FSM_COE_H__
 
 #include "globals.h"
-#include "../include/ecrt.h"
 #include "datagram.h"
 #include "slave.h"
 #include "sdo.h"
--- a/master/fsm_master.c	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/fsm_master.c	Mon Sep 01 14:17:18 2008 +0000
@@ -305,7 +305,7 @@
         request = list_entry(master->sii_requests.next,
                 ec_sii_write_request_t, list);
         list_del_init(&request->list); // dequeue
-        request->state = EC_REQUEST_BUSY;
+        request->state = EC_INT_REQUEST_BUSY;
 
         // found pending SII write operation. execute it!
         if (master->debug_level)
@@ -345,7 +345,7 @@
         request = list_entry(master->phy_requests.next,
                 ec_phy_request_t, list);
         list_del_init(&request->list); // dequeue
-        request->state = EC_REQUEST_BUSY;
+        request->state = EC_INT_REQUEST_BUSY;
 
         // found pending request; process it!
         if (master->debug_level)
@@ -360,7 +360,7 @@
             if (request->length > fsm->datagram->mem_size) {
                 EC_ERR("Request length (%u) exceeds maximum datagram size (%u)!\n",
                         request->length, fsm->datagram->mem_size);
-                request->state = EC_REQUEST_FAILURE;
+                request->state = EC_INT_REQUEST_FAILURE;
                 wake_up(&master->phy_queue);
                 continue;
             }
@@ -398,10 +398,10 @@
         if (!slave->config)
             continue;
         list_for_each_entry(req, &slave->config->sdo_requests, list) {
-            if (req->state == EC_REQUEST_QUEUED) {
+            if (req->state == EC_INT_REQUEST_QUEUED) {
 
                 if (ec_sdo_request_timed_out(req)) {
-                    req->state = EC_REQUEST_FAILURE;
+                    req->state = EC_INT_REQUEST_FAILURE;
                     if (master->debug_level)
                         EC_DBG("Sdo request for slave %u timed out...\n",
                                 slave->ring_position);
@@ -409,11 +409,11 @@
                 }
 
                 if (slave->current_state == EC_SLAVE_STATE_INIT) {
-                    req->state = EC_REQUEST_FAILURE;
+                    req->state = EC_INT_REQUEST_FAILURE;
                     continue;
                 }
 
-                req->state = EC_REQUEST_BUSY;
+                req->state = EC_INT_REQUEST_BUSY;
                 if (master->debug_level)
                     EC_DBG("Processing Sdo request for slave %u...\n",
                             slave->ring_position);
@@ -438,13 +438,13 @@
         request = list_entry(master->slave_sdo_requests.next,
                 ec_master_sdo_request_t, list);
         list_del_init(&request->list); // dequeue
-        request->req.state = EC_REQUEST_BUSY;
+        request->req.state = EC_INT_REQUEST_BUSY;
 
         slave = request->slave;
         if (slave->current_state == EC_SLAVE_STATE_INIT) {
             EC_ERR("Discarding Sdo request, slave %u is in INIT.\n",
                     slave->ring_position);
-            request->req.state = EC_REQUEST_FAILURE;
+            request->req.state = EC_INT_REQUEST_FAILURE;
             wake_up(&master->sdo_queue);
             continue;
         }
@@ -812,7 +812,7 @@
     if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
         EC_ERR("Failed to write SII data to slave %u.\n",
                 slave->ring_position);
-        request->state = EC_REQUEST_FAILURE;
+        request->state = EC_INT_REQUEST_FAILURE;
         wake_up(&master->sii_queue);
         ec_fsm_master_restart(fsm);
         return;
@@ -839,7 +839,7 @@
     }
     // TODO: Evaluate other SII contents!
     
-    request->state = EC_REQUEST_SUCCESS;
+    request->state = EC_INT_REQUEST_SUCCESS;
     wake_up(&master->sii_queue);
 
     // check for another SII write request
@@ -898,14 +898,14 @@
     if (!ec_fsm_coe_success(&fsm->fsm_coe)) {
         EC_DBG("Failed to process Sdo request for slave %u.\n",
                 fsm->slave->ring_position);
-        request->state = EC_REQUEST_FAILURE;
+        request->state = EC_INT_REQUEST_FAILURE;
         wake_up(&master->sdo_queue);
         ec_fsm_master_restart(fsm);
         return;
     }
 
     // Sdo request finished 
-    request->state = EC_REQUEST_SUCCESS;
+    request->state = EC_INT_REQUEST_SUCCESS;
     wake_up(&master->sdo_queue);
 
     if (master->debug_level)
@@ -934,7 +934,7 @@
     if (datagram->state != EC_DATAGRAM_RECEIVED) {
         EC_ERR("Failed to receive phy request datagram (state %u).\n",
                 datagram->state);
-        request->state = EC_REQUEST_FAILURE;
+        request->state = EC_INT_REQUEST_FAILURE;
         wake_up(&master->phy_queue);
         ec_fsm_master_restart(fsm);
         return;
@@ -947,7 +947,7 @@
         if (!request->data) {
             EC_ERR("Failed to allocate %u bytes of memory for phy request.\n",
                     request->length);
-            request->state = EC_REQUEST_FAILURE;
+            request->state = EC_INT_REQUEST_FAILURE;
             wake_up(&master->phy_queue);
             ec_fsm_master_restart(fsm);
             return;
@@ -955,7 +955,7 @@
         memcpy(request->data, datagram->data, request->length);
     }
 
-    request->state = EC_REQUEST_SUCCESS;
+    request->state = EC_INT_REQUEST_SUCCESS;
     wake_up(&master->phy_queue);
 
     // check for another PHY request
--- a/master/fsm_master.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/fsm_master.h	Mon Sep 01 14:17:18 2008 +0000
@@ -41,8 +41,6 @@
 #ifndef __EC_FSM_MASTER_H__
 #define __EC_FSM_MASTER_H__
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 #include "datagram.h"
 #include "sdo_request.h"
@@ -60,7 +58,7 @@
     uint16_t offset; /**< SII word offset. */
     size_t nwords; /**< Number of words. */
     const uint16_t *words; /**< Pointer to the data words. */
-    ec_request_state_t state; /**< State of the request. */
+    ec_internal_request_state_t state; /**< State of the request. */
 } ec_sii_write_request_t;
 
 /*****************************************************************************/
@@ -74,7 +72,7 @@
     uint16_t offset; /**< Physical memory offset. */
     size_t length; /**< Number of bytes. */
     uint8_t *data;
-    ec_request_state_t state; /**< State of the request. */
+    ec_internal_request_state_t state; /**< State of the request. */
 } ec_phy_request_t;
 
 /*****************************************************************************/
--- a/master/fsm_pdo.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/fsm_pdo.h	Mon Sep 01 14:17:18 2008 +0000
@@ -41,8 +41,6 @@
 #ifndef __EC_FSM_PDO_H__
 #define __EC_FSM_PDO_H__
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 #include "datagram.h"
 #include "fsm_coe.h"
--- a/master/fsm_pdo_entry.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/fsm_pdo_entry.h	Mon Sep 01 14:17:18 2008 +0000
@@ -41,7 +41,6 @@
 #define __EC_FSM_PDO_ENTRY_H__
 
 #include "globals.h"
-#include "../include/ecrt.h"
 #include "datagram.h"
 #include "fsm_coe.h"
 
--- a/master/fsm_sii.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/fsm_sii.h	Mon Sep 01 14:17:18 2008 +0000
@@ -42,7 +42,6 @@
 #define __EC_FSM_SII_H__
 
 #include "globals.h"
-#include "../include/ecrt.h"
 #include "datagram.h"
 #include "slave.h"
 
--- a/master/fsm_slave_config.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/fsm_slave_config.h	Mon Sep 01 14:17:18 2008 +0000
@@ -41,8 +41,6 @@
 #ifndef __EC_FSM_SLAVE_CONFIG_H__
 #define __EC_FSM_SLAVE_CONFIG_H__
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 #include "slave.h"
 #include "datagram.h"
--- a/master/fsm_slave_scan.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/fsm_slave_scan.h	Mon Sep 01 14:17:18 2008 +0000
@@ -41,8 +41,6 @@
 #ifndef __EC_FSM_SLAVE_SCAN_H__
 #define __EC_FSM_SLAVE_SCAN_H__
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 #include "datagram.h"
 #include "slave.h"
--- a/master/globals.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/globals.h	Mon Sep 01 14:17:18 2008 +0000
@@ -43,6 +43,7 @@
 #include <linux/types.h>
 
 #include "../globals.h"
+#include "../include/ecrt.h"
 
 /******************************************************************************
  * EtherCAT master
@@ -253,12 +254,16 @@
  * state_table in master/sdo_request.c.
  */
 typedef enum {
-    EC_REQUEST_INIT,
-    EC_REQUEST_QUEUED,
-    EC_REQUEST_BUSY,
-    EC_REQUEST_SUCCESS,
-    EC_REQUEST_FAILURE
-} ec_request_state_t;
+    EC_INT_REQUEST_INIT,
+    EC_INT_REQUEST_QUEUED,
+    EC_INT_REQUEST_BUSY,
+    EC_INT_REQUEST_SUCCESS,
+    EC_INT_REQUEST_FAILURE
+} ec_internal_request_state_t;
+
+/*****************************************************************************/
+
+extern const ec_request_state_t ec_request_state_translation_table[];
 
 /*****************************************************************************/
 
--- a/master/master.c	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/master.c	Mon Sep 01 14:17:18 2008 +0000
@@ -46,7 +46,6 @@
 #include <linux/device.h>
 #include <linux/version.h>
 
-#include "../include/ecrt.h"
 #include "globals.h"
 #include "slave.h"
 #include "slave_config.h"
--- a/master/module.c	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/module.c	Mon Sep 01 14:17:18 2008 +0000
@@ -545,6 +545,20 @@
 
 /*****************************************************************************/
 
+/** Global request state type translation table.
+ *
+ * Translates an internal request state to an external one.
+ */
+const ec_request_state_t ec_request_state_translation_table[] = {
+    EC_REQUEST_UNUSED,  // EC_INT_REQUEST_INIT,
+    EC_REQUEST_BUSY,    // EC_INT_REQUEST_QUEUED,
+    EC_REQUEST_BUSY,    // EC_INT_REQUEST_BUSY,
+    EC_REQUEST_SUCCESS, // EC_INT_REQUEST_SUCCESS,
+    EC_REQUEST_ERROR    // EC_INT_REQUEST_FAILURE
+};
+
+/*****************************************************************************/
+
 /** \cond */
 
 module_init(ec_init_module);
--- a/master/pdo.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/pdo.h	Mon Sep 01 14:17:18 2008 +0000
@@ -43,8 +43,6 @@
 
 #include <linux/list.h>
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 #include "pdo_entry.h"
 
--- a/master/pdo_entry.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/pdo_entry.h	Mon Sep 01 14:17:18 2008 +0000
@@ -43,8 +43,6 @@
 
 #include <linux/list.h>
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 
 /*****************************************************************************/
--- a/master/pdo_list.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/pdo_list.h	Mon Sep 01 14:17:18 2008 +0000
@@ -43,8 +43,6 @@
 
 #include <linux/list.h>
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 #include "pdo.h"
 
--- a/master/sdo_request.c	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/sdo_request.c	Mon Sep 01 14:17:18 2008 +0000
@@ -54,18 +54,6 @@
 
 /*****************************************************************************/
 
-/** State type translation table.
- */
-static const ec_sdo_request_state_t state_translation_table[] = {
-    EC_SDO_REQUEST_UNUSED,  // EC_REQUEST_INIT,
-    EC_SDO_REQUEST_BUSY,    // EC_REQUEST_QUEUED,
-    EC_SDO_REQUEST_BUSY,    // EC_REQUEST_BUSY,
-    EC_SDO_REQUEST_SUCCESS, // EC_REQUEST_SUCCESS,
-    EC_SDO_REQUEST_ERROR    // EC_REQUEST_FAILURE
-};
-
-/*****************************************************************************/
-
 /** Sdo request constructor.
  */
 void ec_sdo_request_init(
@@ -78,7 +66,7 @@
     req->dir = EC_DIR_INVALID;
     req->issue_timeout = 0; // no timeout
     req->response_timeout = EC_SDO_REQUEST_RESPONSE_TIMEOUT;
-    req->state = EC_REQUEST_INIT;
+    req->state = EC_INT_REQUEST_INIT;
     req->abort_code = 0x00000000;
 }
 
@@ -207,9 +195,9 @@
 
 /*****************************************************************************/
 
-ec_sdo_request_state_t ecrt_sdo_request_state(const ec_sdo_request_t *req)
-{
-   return state_translation_table[req->state];
+ec_request_state_t ecrt_sdo_request_state(const ec_sdo_request_t *req)
+{
+   return ec_request_state_translation_table[req->state];
 }
 
 /*****************************************************************************/
@@ -217,7 +205,7 @@
 void ecrt_sdo_request_read(ec_sdo_request_t *req)
 {
     req->dir = EC_DIR_INPUT;
-    req->state = EC_REQUEST_QUEUED;
+    req->state = EC_INT_REQUEST_QUEUED;
     req->abort_code = 0x00000000;
     req->jiffies_start = jiffies;
 }
@@ -227,7 +215,7 @@
 void ecrt_sdo_request_write(ec_sdo_request_t *req)
 {
     req->dir = EC_DIR_OUTPUT;
-    req->state = EC_REQUEST_QUEUED;
+    req->state = EC_INT_REQUEST_QUEUED;
     req->abort_code = 0x00000000;
     req->jiffies_start = jiffies;
 }
--- a/master/sdo_request.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/sdo_request.h	Mon Sep 01 14:17:18 2008 +0000
@@ -43,8 +43,6 @@
 
 #include <linux/list.h>
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 
 /*****************************************************************************/
@@ -65,7 +63,7 @@
     ec_direction_t dir; /**< Direction. EC_DIR_OUTPUT means downloading to
                           the slave, EC_DIR_INPUT means uploading from the
                           slave. */
-    ec_request_state_t state; /**< Sdo request state. */
+    ec_internal_request_state_t state; /**< Sdo request state. */
     unsigned long jiffies_start; /**< Jiffies, when the request was issued. */
     unsigned long jiffies_sent; /**< Jiffies, when the upload/download
                                      request was sent. */
--- a/master/slave.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/slave.h	Mon Sep 01 14:17:18 2008 +0000
@@ -44,8 +44,6 @@
 #include <linux/list.h>
 #include <linux/kobject.h>
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 #include "datagram.h"
 #include "pdo.h"
--- a/master/slave_config.c	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/slave_config.c	Mon Sep 01 14:17:18 2008 +0000
@@ -42,6 +42,7 @@
 
 #include "globals.h"
 #include "master.h"
+#include "voe_handler.h"
 
 #include "slave_config.h"
 
@@ -75,6 +76,7 @@
 
     INIT_LIST_HEAD(&sc->sdo_configs);
     INIT_LIST_HEAD(&sc->sdo_requests);
+    INIT_LIST_HEAD(&sc->voe_handlers);
 
     sc->used_fmmus = 0;
 }
@@ -91,6 +93,7 @@
 {
     unsigned int i;
     ec_sdo_request_t *req, *next_req;
+    ec_voe_handler_t *voe, *next_voe;
 
     ec_slave_config_detach(sc);
 
@@ -111,6 +114,13 @@
         ec_sdo_request_clear(req);
         kfree(req);
     }
+
+    // free all VoE handlers
+    list_for_each_entry_safe(voe, next_voe, &sc->voe_handlers, list) {
+        list_del(&voe->list);
+        ec_voe_handler_clear(voe);
+        kfree(voe);
+    }
 }
 
 /*****************************************************************************/
@@ -742,6 +752,35 @@
 
 /*****************************************************************************/
 
+ec_voe_handler_t *ecrt_slave_config_create_voe_handler(ec_slave_config_t *sc,
+        size_t size)
+{
+    ec_voe_handler_t *voe;
+
+    if (sc->master->debug_level)
+        EC_DBG("ecrt_slave_config_create_voe_handler(sc = 0x%x, size = %u)\n",
+                (u32) sc, size);
+
+    if (!(voe = (ec_voe_handler_t *)
+                kmalloc(sizeof(ec_voe_handler_t), GFP_KERNEL))) {
+        EC_ERR("Failed to allocate Sdo request memory!\n");
+        return NULL;
+    }
+
+    if (ec_voe_handler_init(voe, sc, size)) {
+        kfree(voe);
+        return NULL;
+    }
+
+    down(&sc->master->master_sem);
+    list_add_tail(&voe->list, &sc->voe_handlers);
+    up(&sc->master->master_sem);
+
+    return voe; 
+}
+
+/*****************************************************************************/
+
 void ecrt_slave_config_state(const ec_slave_config_t *sc,
         ec_slave_config_state_t *state)
 {
--- a/master/slave_config.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/slave_config.h	Mon Sep 01 14:17:18 2008 +0000
@@ -43,8 +43,6 @@
 
 #include <linux/list.h>
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 #include "slave.h"
 #include "sync_config.h"
@@ -74,7 +72,7 @@
 
     struct list_head sdo_configs; /**< List of Sdo configurations. */
     struct list_head sdo_requests; /**< List of Sdo requests. */
-
+    struct list_head voe_handlers; /**< List of VoE handlers. */
 };
 
 /*****************************************************************************/
--- a/master/sync.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/sync.h	Mon Sep 01 14:17:18 2008 +0000
@@ -40,8 +40,6 @@
 #ifndef __EC_SYNC_H__
 #define __EC_SYNC_H__
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 #include "pdo_list.h"
 
--- a/master/sync_config.h	Wed Aug 27 16:04:18 2008 +0000
+++ b/master/sync_config.h	Mon Sep 01 14:17:18 2008 +0000
@@ -40,8 +40,6 @@
 #ifndef __EC_SYNC_CONFIG_H__
 #define __EC_SYNC_CONFIG_H__
 
-#include "../include/ecrt.h"
-
 #include "globals.h"
 #include "pdo_list.h"
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/voe_handler.c	Mon Sep 01 14:17:18 2008 +0000
@@ -0,0 +1,386 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2 of the
+ *  License, or (at your option) any later version.
+ *
+ *  The IgH EtherCAT Master 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 the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  The right to use EtherCAT Technology is granted and comes free of
+ *  charge under condition of compatibility of product made by
+ *  Licensee. People intending to distribute/sell products based on the
+ *  code, have to sign an agreement to guarantee that products using
+ *  software based on IgH EtherCAT master stay compatible with the actual
+ *  EtherCAT specification (which are released themselves as an open
+ *  standard) as the (only) precondition to have the right to use EtherCAT
+ *  Technology, IP and trade marks.
+ *
+ *****************************************************************************/
+
+/** \file
+ * Vendor-specific-over-EtherCAT protocol handler functions.
+ */
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+
+#include "master.h"
+#include "slave_config.h"
+#include "mailbox.h"
+#include "voe_handler.h"
+
+/** VoE response timeout in [ms].
+ */
+#define EC_VOE_RESPONSE_TIMEOUT 500
+
+/*****************************************************************************/
+
+void ec_voe_handler_clear_data(ec_voe_handler_t *);
+
+void ec_voe_handler_state_write_start(ec_voe_handler_t *);
+void ec_voe_handler_state_write_response(ec_voe_handler_t *);
+
+void ec_voe_handler_state_read_start(ec_voe_handler_t *);
+void ec_voe_handler_state_read_check(ec_voe_handler_t *);
+void ec_voe_handler_state_read_response(ec_voe_handler_t *);
+
+void ec_voe_handler_state_end(ec_voe_handler_t *);
+void ec_voe_handler_state_error(ec_voe_handler_t *);
+
+/*****************************************************************************/
+
+/** VoE handler constructor.
+ */
+int ec_voe_handler_init(
+        ec_voe_handler_t *voe, /**< VoE handler. */
+        ec_slave_config_t *sc, /**< Parent slave configuration. */
+        size_t size /**< Size of memory to reserve. */
+        )
+{
+    voe->config = sc;
+    voe->data_size = 0;
+    voe->dir = EC_DIR_INVALID;
+    voe->state = ec_voe_handler_state_error;
+    voe->request_state = EC_INT_REQUEST_INIT;
+
+    ec_datagram_init(&voe->datagram);
+    if (ec_datagram_prealloc(&voe->datagram, size + 6))
+        return -1;
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** VoE handler destructor.
+ */
+void ec_voe_handler_clear(
+        ec_voe_handler_t *voe /**< VoE handler. */
+        )
+{
+    ec_datagram_clear(&voe->datagram);
+}
+
+/*****************************************************************************
+ * Application interface.
+ ****************************************************************************/
+
+uint8_t *ecrt_voe_handler_data(ec_voe_handler_t *voe)
+{
+    return voe->datagram.data + 6;
+}
+
+/*****************************************************************************/
+
+size_t ecrt_voe_handler_data_size(const ec_voe_handler_t *voe)
+{
+    return voe->data_size;
+}
+
+/*****************************************************************************/
+
+void ecrt_voe_handler_read(ec_voe_handler_t *voe)
+{
+    voe->dir = EC_DIR_INPUT;
+    voe->state = ec_voe_handler_state_read_start;
+    voe->request_state = EC_INT_REQUEST_QUEUED;
+}
+
+/*****************************************************************************/
+
+void ecrt_voe_handler_write(ec_voe_handler_t *voe, size_t size)
+{
+    voe->dir = EC_DIR_OUTPUT;
+    voe->datagram.data_size = size + 6;
+    voe->state = ec_voe_handler_state_write_start;
+    voe->request_state = EC_INT_REQUEST_QUEUED;
+}
+
+/*****************************************************************************/
+
+ec_request_state_t ecrt_voe_handler_execute(ec_voe_handler_t *voe)
+{
+    if (voe->config->slave) {
+        voe->state(voe);
+        if (voe->request_state == EC_REQUEST_BUSY)
+            ec_master_queue_datagram(voe->config->master, &voe->datagram);
+    } else {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+    }
+
+    return ec_request_state_translation_table[voe->request_state];
+}
+
+/******************************************************************************
+ * State functions.
+ *****************************************************************************/
+
+void ec_voe_handler_state_write_start(ec_voe_handler_t *voe)
+{
+    ec_slave_t *slave = voe->config->slave;
+    uint8_t *data;
+
+    if (slave->master->debug_level) {
+        EC_DBG("Writing %u bytes of VoE data to slave %u.\n",
+               voe->data_size, slave->ring_position);
+        ec_print_data(ecrt_voe_handler_data(voe), voe->data_size);
+    }
+
+    if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
+        EC_ERR("Slave %u does not support VoE!\n", slave->ring_position);
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        return;
+    }
+	
+    if (!(data = ec_slave_mbox_prepare_send(
+                    slave, &voe->datagram, 0x01, voe->data_size))) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        return;
+    }
+
+    voe->retries = EC_FSM_RETRIES;
+    voe->jiffies_start = jiffies;
+    voe->state = ec_voe_handler_state_write_response;
+}
+
+/*****************************************************************************/
+
+void ec_voe_handler_state_write_response(ec_voe_handler_t *voe)
+{
+    ec_datagram_t *datagram = &voe->datagram;
+    ec_slave_t *slave = voe->config->slave;
+
+    if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
+        return;
+
+    if (datagram->state != EC_DATAGRAM_RECEIVED) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        EC_ERR("Failed to receive VoE write request datagram for"
+               " slave %u (datagram state %u).\n",
+               slave->ring_position, datagram->state);
+        return;
+    }
+
+    if (datagram->working_counter != 1) {
+        if (!datagram->working_counter) {
+            unsigned long diff_ms =
+                (jiffies - voe->jiffies_start) * 1000 / HZ;
+            if (diff_ms < EC_VOE_RESPONSE_TIMEOUT) {
+                if (slave->master->debug_level) {
+                    EC_DBG("Slave %u did not respond to VoE write request. "
+                            "Retrying after %u ms...\n",
+                            slave->ring_position, (u32) diff_ms);
+                }
+                // no response; send request datagram again
+                return;
+            }
+        }
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        EC_ERR("Reception of VoE write request failed on slave %u: ",
+                slave->ring_position);
+        ec_datagram_print_wc_error(datagram);
+        return;
+    }
+
+    if (voe->config->master->debug_level)
+        EC_DBG("VoE write request successful.\n");
+
+    voe->request_state = EC_INT_REQUEST_SUCCESS;
+    voe->state = ec_voe_handler_state_end;
+}
+
+/*****************************************************************************/
+
+void ec_voe_handler_state_read_start(ec_voe_handler_t *voe)
+{
+    ec_datagram_t *datagram = &voe->datagram;
+    ec_slave_t *slave = voe->config->slave;
+
+    if (slave->master->debug_level)
+        EC_DBG("Reading VoE data to slave %u.\n", slave->ring_position);
+
+    if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
+        EC_ERR("Slave %u does not support VoE!\n", slave->ring_position);
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        return;
+    }
+	
+    ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
+
+    voe->jiffies_start = jiffies;
+    voe->retries = EC_FSM_RETRIES;
+    voe->state = ec_voe_handler_state_read_check;
+}
+
+/*****************************************************************************/
+
+void ec_voe_handler_state_read_check(ec_voe_handler_t *voe)
+{
+    ec_datagram_t *datagram = &voe->datagram;
+    ec_slave_t *slave = voe->config->slave;
+
+    if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
+        return;
+
+    if (datagram->state != EC_DATAGRAM_RECEIVED) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        EC_ERR("Failed to receive VoE mailbox check datagram from slave %u"
+                " (datagram state %u).\n",
+               slave->ring_position, datagram->state);
+        return;
+    }
+
+    if (datagram->working_counter != 1) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        EC_ERR("Reception of VoE mailbox check"
+                " datagram failed on slave %u: ", slave->ring_position);
+        ec_datagram_print_wc_error(datagram);
+        return;
+    }
+
+    if (!ec_slave_mbox_check(datagram)) {
+        unsigned long diff_ms =
+            (datagram->jiffies_received - voe->jiffies_start) * 1000 / HZ;
+        if (diff_ms >= EC_VOE_RESPONSE_TIMEOUT) {
+            voe->state = ec_voe_handler_state_error;
+            voe->request_state = EC_INT_REQUEST_FAILURE;
+            EC_ERR("Timeout while waiting for VoE data on "
+                    "slave %u.\n", slave->ring_position);
+            return;
+        }
+
+        ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
+        voe->retries = EC_FSM_RETRIES;
+        return;
+    }
+
+    // Fetch response
+    ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
+    voe->retries = EC_FSM_RETRIES;
+    voe->state = ec_voe_handler_state_read_response;
+}
+
+/*****************************************************************************/
+
+void ec_voe_handler_state_read_response(ec_voe_handler_t *voe)
+{
+    ec_datagram_t *datagram = &voe->datagram;
+    ec_slave_t *slave = voe->config->slave;
+    ec_master_t *master = voe->config->master;
+    uint8_t *data, mbox_prot;
+    size_t rec_size;
+
+    if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
+        return;
+
+    if (datagram->state != EC_DATAGRAM_RECEIVED) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        EC_ERR("Failed to receive VoE read datagram for"
+               " slave %u (datagram state %u).\n",
+               slave->ring_position, datagram->state);
+        return;
+    }
+
+    if (datagram->working_counter != 1) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        EC_ERR("Reception of VoE read response failed on slave %u: ",
+                slave->ring_position);
+        ec_datagram_print_wc_error(datagram);
+        return;
+    }
+
+    if (!(data = ec_slave_mbox_fetch(slave, datagram,
+				     &mbox_prot, &rec_size))) {
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        return;
+    }
+
+    if (mbox_prot != 0x01) { // VoE
+        voe->state = ec_voe_handler_state_error;
+        voe->request_state = EC_INT_REQUEST_FAILURE;
+        EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
+        ec_print_data(data, rec_size);
+        return;
+    }
+
+    if (master->debug_level) {
+        EC_DBG("VoE data:\n");
+        ec_print_data(data, rec_size);
+    }
+
+    voe->data_size = rec_size;
+    voe->request_state = EC_INT_REQUEST_SUCCESS;
+    voe->state = ec_voe_handler_state_end; // success
+}
+
+/*****************************************************************************/
+
+void ec_voe_handler_state_end(ec_voe_handler_t *voe)
+{
+}
+
+/*****************************************************************************/
+
+void ec_voe_handler_state_error(ec_voe_handler_t *voe)
+{
+}
+
+/*****************************************************************************/
+
+/** \cond */
+
+EXPORT_SYMBOL(ecrt_voe_handler_data);
+EXPORT_SYMBOL(ecrt_voe_handler_data_size);
+EXPORT_SYMBOL(ecrt_voe_handler_read);
+EXPORT_SYMBOL(ecrt_voe_handler_write);
+EXPORT_SYMBOL(ecrt_voe_handler_execute);
+
+/** \endcond */
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/voe_handler.h	Mon Sep 01 14:17:18 2008 +0000
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2 of the
+ *  License, or (at your option) any later version.
+ *
+ *  The IgH EtherCAT Master 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 the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  The right to use EtherCAT Technology is granted and comes free of
+ *  charge under condition of compatibility of product made by
+ *  Licensee. People intending to distribute/sell products based on the
+ *  code, have to sign an agreement to guarantee that products using
+ *  software based on IgH EtherCAT master stay compatible with the actual
+ *  EtherCAT specification (which are released themselves as an open
+ *  standard) as the (only) precondition to have the right to use EtherCAT
+ *  Technology, IP and trade marks.
+ *
+ *****************************************************************************/
+
+/**
+   \file
+   Vendor-specific-over-EtherCAT protocol handler.
+*/
+
+/*****************************************************************************/
+
+#ifndef __EC_VOE_HANDLER_H__
+#define __EC_VOE_HANDLER_H__
+
+#include <linux/list.h>
+
+#include "globals.h"
+#include "datagram.h"
+
+/*****************************************************************************/
+
+/** Vendor-specific-over-EtherCAT handler.
+ */
+struct ec_voe_handler {
+    struct list_head list; /**< List item. */
+    ec_slave_config_t *config; /**< Parent slave configuration. */
+    ec_datagram_t datagram; /**< State machine datagram. */
+    size_t data_size; /**< Size of Sdo data. */
+    ec_direction_t dir; /**< Direction. EC_DIR_OUTPUT means writing to
+                          the slave, EC_DIR_INPUT means reading from the
+                          slave. */
+    void (*state)(ec_voe_handler_t *); /**< State function */
+    ec_internal_request_state_t request_state; /**< Handler state. */
+    unsigned int retries; /**< retries upon datagram timeout */
+    unsigned long jiffies_start; /**< Timestamp for timeout calculation. */
+};
+
+/*****************************************************************************/
+
+int ec_voe_handler_init(ec_voe_handler_t *, ec_slave_config_t *, size_t);
+void ec_voe_handler_clear(ec_voe_handler_t *);
+
+/*****************************************************************************/
+
+#endif