Added API for querying CoE emergency requests. stable-1.5
authorFlorian Pose <fp@igh-essen.com>
Tue, 06 Nov 2012 14:23:44 +0100
branchstable-1.5
changeset 2438 9c3e629a220c
parent 2437 7b8078c1ad36
child 2439 0f1622cdb670
Added API for querying CoE emergency requests.
include/ecrt.h
lib/slave_config.c
master/Kbuild.in
master/Makefile.am
master/coe_emerg_ring.c
master/coe_emerg_ring.h
master/fsm_coe.c
master/ioctl.c
master/ioctl.h
master/slave_config.c
master/slave_config.h
--- a/include/ecrt.h	Tue Nov 06 11:49:55 2012 +0100
+++ b/include/ecrt.h	Tue Nov 06 14:23:44 2012 +0100
@@ -48,6 +48,10 @@
  *   redundancy features.
  * - Added ecrt_sdo_request_index() to change SDO index and subindex after
  *   handler creation.
+ * - Added interface for retrieving CoE emergency messages, i. e.
+ *   ecrt_slave_config_emerg_size(), ecrt_slave_config_emerg_pop(),
+ *   ecrt_slave_config_emerg_clear(), ecrt_slave_config_emerg_overruns() and
+ *   the defines EC_HAVE_EMERGENCY and EC_COE_EMERGENCY_MSG_SIZE.
  *
  * Changes in version 1.5:
  *
@@ -140,6 +144,12 @@
  */
 #define EC_HAVE_REDUNDANCY
 
+/** Defined, if the CoE emergency ring feature is available.
+ *
+ * I. e. if the ecrt_slave_config_emerg_*() methods are available.
+ */
+#define EC_HAVE_EMERGENCY
+
 /*****************************************************************************/
 
 /** End of list marker.
@@ -172,6 +182,12 @@
 #define EC_TIMEVAL2NANO(TV) \
     (((TV).tv_sec - 946684800ULL) * 1000000000ULL + (TV).tv_usec * 1000ULL)
 
+/** Size of a CoE emergency message in byte.
+ *
+ * \see ecrt_slave_config_emerg_pop().
+ */
+#define EC_COE_EMERGENCY_MSG_SIZE 8
+
 /******************************************************************************
  * Data types
  *****************************************************************************/
@@ -1283,6 +1299,55 @@
         size_t size /**< Size of the \a data. */
         );
 
+/** Set the size of the CoE emergency ring buffer.
+ *
+ * The initial size is zero, so all messages will be dropped. This method can
+ * be called even after master activation, but it will clear the ring buffer!
+ *
+ * \return 0 on success, or negative error code.
+ */
+int ecrt_slave_config_emerg_size(
+        ec_slave_config_t *sc, /**< Slave configuration. */
+        size_t elements /**< Number of records of the CoE emergency ring. */
+        );
+
+/** Read and remove one record from the CoE emergency ring buffer.
+ *
+ * A record consists of 8 bytes:
+ *
+ * Byte 0-1: Error code (little endian)
+ * Byte   2: Error register
+ * Byte 3-7: Data
+ *
+ * \return 0 on success (record popped), or negative error code (i. e.
+ * -ENOENT, if ring is empty).
+ */
+int ecrt_slave_config_emerg_pop(
+        ec_slave_config_t *sc, /**< Slave configuration. */
+        uint8_t *target /**< Pointer to target memory (at least
+                          EC_COE_EMERGENCY_MSG_SIZE bytes). */
+        );
+
+/** Clears CoE emergency ring buffer and the overrun counter.
+ *
+ * \return 0 on success, or negative error code.
+ */
+int ecrt_slave_config_emerg_clear(
+        ec_slave_config_t *sc /**< Slave configuration. */
+        );
+
+/** Read the number of CoE emergency overruns.
+ *
+ * The overrun counter will be incremented when a CoE emergency message could
+ * not be stored in the ring buffer and had to be dropped. Call
+ * ecrt_slave_config_emerg_clear() to reset the counter.
+ *
+ * \return Number of overruns since last clear, or negative error code.
+ */
+int ecrt_slave_config_emerg_overruns(
+        ec_slave_config_t *sc /**< Slave configuration. */
+        );
+
 /** Create an SDO request to exchange SDOs during realtime operation.
  *
  * The created SDO request object is freed automatically when the master is
--- a/lib/slave_config.c	Tue Nov 06 11:49:55 2012 +0100
+++ b/lib/slave_config.c	Tue Nov 06 14:23:44 2012 +0100
@@ -403,6 +403,84 @@
 
 /*****************************************************************************/
 
+int ecrt_slave_config_emerg_size(ec_slave_config_t *sc, size_t elements)
+{
+    ec_ioctl_sc_emerg_t io;
+    int ret;
+
+    io.config_index = sc->index;
+    io.size = elements;
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_EMERG_SIZE, &io);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to set emergency ring size: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_emerg_pop(ec_slave_config_t *sc, uint8_t *target)
+{
+    ec_ioctl_sc_emerg_t io;
+    int ret;
+
+    io.config_index = sc->index;
+    io.target = target;
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_EMERG_POP, &io);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to get emergency message: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_emerg_clear(ec_slave_config_t *sc)
+{
+    ec_ioctl_sc_emerg_t io;
+    int ret;
+
+    io.config_index = sc->index;
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_EMERG_CLEAR, &io);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to clear emergency ring: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_emerg_overruns(ec_slave_config_t *sc)
+{
+    ec_ioctl_sc_emerg_t io;
+    int ret;
+
+    io.config_index = sc->index;
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_EMERG_OVERRUNS, &io);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to get emergency overruns: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
+    return io.overruns;
+}
+
+/*****************************************************************************/
+
 void ec_slave_config_add_sdo_request(ec_slave_config_t *sc,
         ec_sdo_request_t *req)
 {
--- a/master/Kbuild.in	Tue Nov 06 11:49:55 2012 +0100
+++ b/master/Kbuild.in	Tue Nov 06 14:23:44 2012 +0100
@@ -35,6 +35,7 @@
 
 ec_master-objs := \
 	cdev.o \
+	coe_emerg_ring.o \
 	datagram.o \
 	datagram_pair.o \
 	device.o \
--- a/master/Makefile.am	Tue Nov 06 11:49:55 2012 +0100
+++ b/master/Makefile.am	Tue Nov 06 14:23:44 2012 +0100
@@ -30,6 +30,7 @@
 # using HEADERS to enable tags target
 noinst_HEADERS = \
 	cdev.c cdev.h \
+	coe_emerg_ring.c coe_emerg_ring.h \
 	datagram.c datagram.h \
 	datagram_pair.c datagram_pair.h \
 	debug.c debug.h \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/coe_emerg_ring.c	Tue Nov 06 14:23:44 2012 +0100
@@ -0,0 +1,170 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2012  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 version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  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 license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *  vim: expandtab
+ *
+ *****************************************************************************/
+
+/**
+   \file
+   EtherCAT CoE emergency ring buffer methods.
+*/
+
+/*****************************************************************************/
+
+#include <linux/slab.h>
+
+#include "coe_emerg_ring.h"
+
+/*****************************************************************************/
+
+/** Emergency ring buffer constructor.
+ */
+void ec_coe_emerg_ring_init(
+        ec_coe_emerg_ring_t *ring, /**< Emergency ring. */
+        ec_slave_config_t *sc /**< Slave configuration. */
+        )
+{
+    ring->sc = sc;
+    ring->msgs = NULL;
+    ring->size = 0;
+    ring->read_index = 0;
+    ring->write_index = 0;
+    ring->overruns = 0;
+}
+
+/*****************************************************************************/
+
+/** Emergency ring buffer destructor.
+ */
+void ec_coe_emerg_ring_clear(
+        ec_coe_emerg_ring_t *ring /**< Emergency ring. */
+        )
+{
+    if (ring->msgs) {
+        kfree(ring->msgs);
+    }
+}
+
+/*****************************************************************************/
+
+/** Set the ring size.
+ */
+int ec_coe_emerg_ring_size(
+        ec_coe_emerg_ring_t *ring, /**< Emergency ring. */
+        size_t size /**< Maximum number of messages in the ring. */
+        )
+{
+    ring->size = 0;
+
+    if (size < 0) {
+        size = 0;
+    }
+
+    ring->read_index = ring->write_index = 0;
+
+    if (ring->msgs) {
+        kfree(ring->msgs);
+    }
+    ring->msgs = NULL;
+
+    if (size == 0) {
+        return 0;
+    }
+
+    ring->msgs = kmalloc(sizeof(ec_coe_emerg_msg_t) * (size + 1), GFP_KERNEL);
+    if (!ring->msgs) {
+        return -ENOMEM;
+    }
+
+    ring->size = size;
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** Add a new emergency message.
+ */
+void ec_coe_emerg_ring_push(
+        ec_coe_emerg_ring_t *ring, /**< Emergency ring. */
+        const u8 *msg /**< Emergency message. */
+        )
+{
+    if (!ring->size ||
+            (ring->write_index + 1) % (ring->size + 1) == ring->read_index) {
+        ring->overruns++;
+        return;
+    }
+
+    memcpy(ring->msgs[ring->write_index].data, msg,
+            EC_COE_EMERGENCY_MSG_SIZE);
+    ring->write_index = (ring->write_index + 1) % (ring->size + 1);
+}
+
+/*****************************************************************************/
+
+/** Remove an emergency message from the ring.
+ */
+int ec_coe_emerg_ring_pop(
+        ec_coe_emerg_ring_t *ring, /**< Emergency ring. */
+        u8 *msg /**< Memory to store the emergency message. */
+        )
+{
+    if (ring->read_index == ring->write_index) {
+        return -ENOENT;
+    }
+
+    memcpy(msg, ring->msgs[ring->read_index].data, EC_COE_EMERGENCY_MSG_SIZE);
+    ring->read_index = (ring->read_index + 1) % (ring->size + 1);
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** Clear the ring.
+ */
+int ec_coe_emerg_ring_clear_ring(
+        ec_coe_emerg_ring_t *ring /**< Emergency ring. */
+        )
+{
+    ring->read_index = ring->write_index;
+    ring->overruns = 0;
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** Read the number of overruns.
+ */
+int ec_coe_emerg_ring_overruns(
+        ec_coe_emerg_ring_t *ring /**< Emergency ring. */
+        )
+{
+    return ring->overruns;
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/coe_emerg_ring.h	Tue Nov 06 14:23:44 2012 +0100
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2012  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 version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  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 license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *****************************************************************************/
+
+/**
+   \file
+   EtherCAT CoE emergency ring buffer structure.
+*/
+
+/*****************************************************************************/
+
+#ifndef __EC_COE_EMERG_RING_H__
+#define __EC_COE_EMERG_RING_H__
+
+#include "globals.h"
+
+/*****************************************************************************/
+
+/** EtherCAT CoE emergency message record.
+ */
+typedef struct {
+    u8 data[EC_COE_EMERGENCY_MSG_SIZE];
+} ec_coe_emerg_msg_t;
+
+/*****************************************************************************/
+
+/** EtherCAT CoE emergency ring buffer.
+ */
+typedef struct {
+    ec_slave_config_t *sc; /**< Slave configuration  owning the ring. */
+
+    ec_coe_emerg_msg_t *msgs;
+    size_t size;
+
+    unsigned int read_index;
+    unsigned int write_index;
+    unsigned int overruns;
+} ec_coe_emerg_ring_t;
+
+/*****************************************************************************/
+
+void ec_coe_emerg_ring_init(ec_coe_emerg_ring_t *, ec_slave_config_t *);
+void ec_coe_emerg_ring_clear(ec_coe_emerg_ring_t *);
+
+int ec_coe_emerg_ring_size(ec_coe_emerg_ring_t *, size_t);
+void ec_coe_emerg_ring_push(ec_coe_emerg_ring_t *, const u8 *);
+int ec_coe_emerg_ring_pop(ec_coe_emerg_ring_t *, u8 *);
+int ec_coe_emerg_ring_clear_ring(ec_coe_emerg_ring_t *);
+int ec_coe_emerg_ring_overruns(ec_coe_emerg_ring_t *);
+
+/*****************************************************************************/
+
+#endif
--- a/master/fsm_coe.c	Tue Nov 06 11:49:55 2012 +0100
+++ b/master/fsm_coe.c	Tue Nov 06 14:23:44 2012 +0100
@@ -38,6 +38,7 @@
 #include "master.h"
 #include "mailbox.h"
 #include "fsm_coe.h"
+#include "slave_config.h"
 
 /*****************************************************************************/
 
@@ -269,6 +270,13 @@
         return 1;
     }
 
+    {
+        ec_slave_config_t *sc = fsm->slave->config;
+        if (sc) {
+            ec_coe_emerg_ring_push(&sc->emerg_ring, data + 2);
+        }
+    }
+
     EC_SLAVE_WARN(fsm->slave, "CoE Emergency Request received:\n"
             "Error code 0x%04X, Error register 0x%02X, data:\n",
             EC_READ_U16(data + 2), EC_READ_U8(data + 4));
--- a/master/ioctl.c	Tue Nov 06 11:49:55 2012 +0100
+++ b/master/ioctl.c	Tue Nov 06 14:23:44 2012 +0100
@@ -2276,6 +2276,169 @@
 
 /*****************************************************************************/
 
+/** Set the emergency ring buffer size.
+ */
+static int ec_ioctl_sc_emerg_size(
+        ec_master_t *master, /**< EtherCAT master. */
+        void *arg, /**< ioctl() argument. */
+        ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
+        )
+{
+    ec_ioctl_sc_emerg_t io;
+    ec_slave_config_t *sc;
+    int ret;
+
+    if (unlikely(!ctx->requested))
+        return -EPERM;
+
+    if (copy_from_user(&io, (void __user *) arg, sizeof(io)))
+        return -EFAULT;
+
+    if (down_interruptible(&master->master_sem)) {
+        return -EINTR;
+    }
+
+    if (!(sc = ec_master_get_config(master, io.config_index))) {
+        up(&master->master_sem);
+        return -ENOENT;
+    }
+
+    ret = ecrt_slave_config_emerg_size(sc, io.size);
+
+    up(&master->master_sem);
+
+    return ret;
+}
+
+/*****************************************************************************/
+
+/** Get an emergency message from the ring.
+ */
+static int ec_ioctl_sc_emerg_pop(
+        ec_master_t *master, /**< EtherCAT master. */
+        void *arg, /**< ioctl() argument. */
+        ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
+        )
+{
+    ec_ioctl_sc_emerg_t io;
+    ec_slave_config_t *sc;
+    u8 msg[EC_COE_EMERGENCY_MSG_SIZE];
+    int ret;
+
+    if (unlikely(!ctx->requested))
+        return -EPERM;
+
+    if (copy_from_user(&io, (void __user *) arg, sizeof(io)))
+        return -EFAULT;
+
+    if (down_interruptible(&master->master_sem)) {
+        return -EINTR;
+    }
+
+    if (!(sc = ec_master_get_config(master, io.config_index))) {
+        up(&master->master_sem);
+        return -ENOENT;
+    }
+
+    ret = ecrt_slave_config_emerg_pop(sc, msg);
+
+    up(&master->master_sem);
+
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (copy_to_user((void __user *) io.target, msg, sizeof(msg))) {
+        return -EFAULT;
+    }
+
+    return ret;
+}
+
+/*****************************************************************************/
+
+/** Clear the emergency ring.
+ */
+static int ec_ioctl_sc_emerg_clear(
+        ec_master_t *master, /**< EtherCAT master. */
+        void *arg, /**< ioctl() argument. */
+        ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
+        )
+{
+    ec_ioctl_sc_emerg_t io;
+    ec_slave_config_t *sc;
+    int ret;
+
+    if (unlikely(!ctx->requested))
+        return -EPERM;
+
+    if (copy_from_user(&io, (void __user *) arg, sizeof(io)))
+        return -EFAULT;
+
+    if (down_interruptible(&master->master_sem)) {
+        return -EINTR;
+    }
+
+    if (!(sc = ec_master_get_config(master, io.config_index))) {
+        up(&master->master_sem);
+        return -ENOENT;
+    }
+
+    ret = ecrt_slave_config_emerg_clear(sc);
+
+    up(&master->master_sem);
+
+    return ret;
+}
+
+/*****************************************************************************/
+
+/** Get the number of emergency overruns.
+ */
+static int ec_ioctl_sc_emerg_overruns(
+        ec_master_t *master, /**< EtherCAT master. */
+        void *arg, /**< ioctl() argument. */
+        ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
+        )
+{
+    ec_ioctl_sc_emerg_t io;
+    ec_slave_config_t *sc;
+    int ret;
+
+    if (unlikely(!ctx->requested))
+        return -EPERM;
+
+    if (copy_from_user(&io, (void __user *) arg, sizeof(io)))
+        return -EFAULT;
+
+    if (down_interruptible(&master->master_sem)) {
+        return -EINTR;
+    }
+
+    if (!(sc = ec_master_get_config(master, io.config_index))) {
+        up(&master->master_sem);
+        return -ENOENT;
+    }
+
+    ret = ecrt_slave_config_emerg_overruns(sc);
+
+    up(&master->master_sem);
+
+    if (ret < 0) {
+        return ret;
+    }
+
+    io.overruns = ret;
+
+    if (copy_to_user((void __user *) arg, &io, sizeof(io))) {
+        return -EFAULT;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
 /** Create an SDO request.
  */
 static int ec_ioctl_sc_create_sdo_request(
@@ -3678,6 +3841,34 @@
             }
             ret = ec_ioctl_sc_sdo(master, arg, ctx);
             break;
+        case EC_IOCTL_SC_EMERG_SIZE:
+            if (!ctx->writable) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_ioctl_sc_emerg_size(master, arg, ctx);
+            break;
+        case EC_IOCTL_SC_EMERG_POP:
+            if (!ctx->writable) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_ioctl_sc_emerg_pop(master, arg, ctx);
+            break;
+        case EC_IOCTL_SC_EMERG_CLEAR:
+            if (!ctx->writable) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_ioctl_sc_emerg_clear(master, arg, ctx);
+            break;
+        case EC_IOCTL_SC_EMERG_OVERRUNS:
+            if (!ctx->writable) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_ioctl_sc_emerg_overruns(master, arg, ctx);
+            break;
         case EC_IOCTL_SC_SDO_REQUEST:
             if (!ctx->writable) {
                 ret = -EPERM;
--- a/master/ioctl.h	Tue Nov 06 11:49:55 2012 +0100
+++ b/master/ioctl.h	Tue Nov 06 14:23:44 2012 +0100
@@ -56,7 +56,7 @@
  *
  * Increment this when changing the ioctl interface!
  */
-#define EC_IOCTL_VERSION_MAGIC 20
+#define EC_IOCTL_VERSION_MAGIC 21
 
 // Command-line tool
 #define EC_IOCTL_MODULE                EC_IOR(0x00, ec_ioctl_module_t)
@@ -117,28 +117,32 @@
 #define EC_IOCTL_SC_REG_PDO_ENTRY     EC_IOWR(0x33, ec_ioctl_reg_pdo_entry_t)
 #define EC_IOCTL_SC_DC                 EC_IOW(0x34, ec_ioctl_config_t)
 #define EC_IOCTL_SC_SDO                EC_IOW(0x35, ec_ioctl_sc_sdo_t)
-#define EC_IOCTL_SC_SDO_REQUEST       EC_IOWR(0x36, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SC_VOE               EC_IOWR(0x37, ec_ioctl_voe_t)
-#define EC_IOCTL_SC_STATE             EC_IOWR(0x38, ec_ioctl_sc_state_t)
-#define EC_IOCTL_SC_IDN                EC_IOW(0x39, ec_ioctl_sc_idn_t)
-#define EC_IOCTL_DOMAIN_OFFSET          EC_IO(0x3a)
-#define EC_IOCTL_DOMAIN_PROCESS         EC_IO(0x3b)
-#define EC_IOCTL_DOMAIN_QUEUE           EC_IO(0x3c)
-#define EC_IOCTL_DOMAIN_STATE         EC_IOWR(0x3d, ec_ioctl_domain_state_t)
-#define EC_IOCTL_SDO_REQUEST_INDEX    EC_IOWR(0x3e, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_TIMEOUT  EC_IOWR(0x3f, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_STATE    EC_IOWR(0x40, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_READ     EC_IOWR(0x41, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_WRITE    EC_IOWR(0x42, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_DATA     EC_IOWR(0x43, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x44, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x45, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ              EC_IOW(0x46, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x47, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x48, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x49, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_DATA             EC_IOWR(0x4a, ec_ioctl_voe_t)
-#define EC_IOCTL_SET_SEND_INTERVAL     EC_IOW(0x4b, size_t)
+#define EC_IOCTL_SC_EMERG_SIZE         EC_IOW(0x36, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_EMERG_POP         EC_IOWR(0x37, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_EMERG_CLEAR        EC_IOW(0x38, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_EMERG_OVERRUNS    EC_IOWR(0x39, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_SDO_REQUEST       EC_IOWR(0x3a, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SC_VOE               EC_IOWR(0x3b, ec_ioctl_voe_t)
+#define EC_IOCTL_SC_STATE             EC_IOWR(0x3c, ec_ioctl_sc_state_t)
+#define EC_IOCTL_SC_IDN                EC_IOW(0x3d, ec_ioctl_sc_idn_t)
+#define EC_IOCTL_DOMAIN_OFFSET          EC_IO(0x3e)
+#define EC_IOCTL_DOMAIN_PROCESS         EC_IO(0x3f)
+#define EC_IOCTL_DOMAIN_QUEUE           EC_IO(0x40)
+#define EC_IOCTL_DOMAIN_STATE         EC_IOWR(0x41, ec_ioctl_domain_state_t)
+#define EC_IOCTL_SDO_REQUEST_INDEX    EC_IOWR(0x42, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_TIMEOUT  EC_IOWR(0x43, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_STATE    EC_IOWR(0x44, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_READ     EC_IOWR(0x45, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_WRITE    EC_IOWR(0x46, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_DATA     EC_IOWR(0x47, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x48, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x49, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ              EC_IOW(0x4a, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x4b, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x4c, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x4d, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_DATA             EC_IOWR(0x4e, ec_ioctl_voe_t)
+#define EC_IOCTL_SET_SEND_INTERVAL     EC_IOW(0x4f, size_t)
 
 /*****************************************************************************/
 
@@ -622,6 +626,18 @@
 typedef struct {
     // inputs
     uint32_t config_index;
+    size_t size;
+    uint8_t *target;
+
+    // outputs
+    int32_t overruns;
+} ec_ioctl_sc_emerg_t;
+
+/*****************************************************************************/
+
+typedef struct {
+    // inputs
+    uint32_t config_index;
 
     // outputs
     ec_slave_config_state_t *state;
--- a/master/slave_config.c	Tue Nov 06 11:49:55 2012 +0100
+++ b/master/slave_config.c	Tue Nov 06 14:23:44 2012 +0100
@@ -88,6 +88,8 @@
     INIT_LIST_HEAD(&sc->sdo_requests);
     INIT_LIST_HEAD(&sc->voe_handlers);
     INIT_LIST_HEAD(&sc->soe_configs);
+
+    ec_coe_emerg_ring_init(&sc->emerg_ring, sc);
 }
 
 /*****************************************************************************/
@@ -138,6 +140,8 @@
         ec_soe_request_clear(soe);
         kfree(soe);
     }
+
+    ec_coe_emerg_ring_clear(&sc->emerg_ring);
 }
 
 /*****************************************************************************/
@@ -881,6 +885,34 @@
 
 /*****************************************************************************/
 
+int ecrt_slave_config_emerg_size(ec_slave_config_t *sc, size_t elements)
+{
+    return ec_coe_emerg_ring_size(&sc->emerg_ring, elements);
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_emerg_pop(ec_slave_config_t *sc, uint8_t *target)
+{
+    return ec_coe_emerg_ring_pop(&sc->emerg_ring, target);
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_emerg_clear(ec_slave_config_t *sc)
+{
+    return ec_coe_emerg_ring_clear_ring(&sc->emerg_ring);
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_emerg_overruns(ec_slave_config_t *sc)
+{
+    return ec_coe_emerg_ring_overruns(&sc->emerg_ring);
+}
+
+/*****************************************************************************/
+
 /** Same as ecrt_slave_config_create_sdo_request(), but with ERR_PTR() return
  * value.
  */
@@ -1063,6 +1095,10 @@
 EXPORT_SYMBOL(ecrt_slave_config_sdo16);
 EXPORT_SYMBOL(ecrt_slave_config_sdo32);
 EXPORT_SYMBOL(ecrt_slave_config_complete_sdo);
+EXPORT_SYMBOL(ecrt_slave_config_emerg_size);
+EXPORT_SYMBOL(ecrt_slave_config_emerg_pop);
+EXPORT_SYMBOL(ecrt_slave_config_emerg_clear);
+EXPORT_SYMBOL(ecrt_slave_config_emerg_overruns);
 EXPORT_SYMBOL(ecrt_slave_config_create_sdo_request);
 EXPORT_SYMBOL(ecrt_slave_config_create_voe_handler);
 EXPORT_SYMBOL(ecrt_slave_config_state);
--- a/master/slave_config.h	Tue Nov 06 11:49:55 2012 +0100
+++ b/master/slave_config.h	Tue Nov 06 14:23:44 2012 +0100
@@ -43,6 +43,7 @@
 #include "slave.h"
 #include "sync_config.h"
 #include "fmmu_config.h"
+#include "coe_emerg_ring.h"
 
 /*****************************************************************************/
 
@@ -141,6 +142,8 @@
     struct list_head sdo_requests; /**< List of SDO requests. */
     struct list_head voe_handlers; /**< List of VoE handlers. */
     struct list_head soe_configs; /**< List of SoE configurations. */
+
+    ec_coe_emerg_ring_t emerg_ring; /**< CoE emergency ring buffer. */
 };
 
 /*****************************************************************************/