From: Graeme Foot <graeme.foot@touchcut.com>
Date: Mon, 01 Feb 2018 11:00:00 +1200

Added ability to explicity add and remove eoe interfaces so
that they can be pre-added before the slaves are scanned and
also added if the slave is not yet connected.  Configured
eoe interfaces now also remain configured if the slave is
disconnected.  Added tool commands eoe_addif and eoe_delif.
Updated tool to allow exact match for commands.

EOE interfaces can now be configured at module load time
("eoe_interfaces" parameter) and also whether to allow auto
or manual only creation of eoe interfaces
("eoe_autocreate" parameter)

EOE slaves no longer being kept in op mode when deactivating
the master.  The eoe port still keeps running anyway and your
app may be waiting for all slaves to be in PREOP before exiting

Fixed "BUG: scheduling while atomic" error with EOE transmit
queue.  ec_eoedev_tx() runs in an interrupt context and is not
allowed to sleep, so it is not allowed to use a semaphore to
protect the queue.  The queue has been replaced with a ring
buffer.

diff --git a/include/ecrt.h b/include/ecrt.h
--- a/include/ecrt.h
+++ b/include/ecrt.h
@@ -1067,11 +1067,37 @@
  *
  * This method has to be called in the send callback function passed via
  * ecrt_master_callbacks() to allow the sending of non-application datagrams.
+ *
+ * Returns the number of bytes sent.
  */
-void ecrt_master_send_ext(
+size_t ecrt_master_send_ext(
         ec_master_t *master /**< EtherCAT master. */
         );
 
+#ifdef EC_EOE
+
+/** add an EOE network interface
+ *
+ * \return 0 on success else negative error code
+ */
+int ecrt_master_eoe_addif(
+        ec_master_t *master, /**< EtherCAT master. */
+        uint16_t alias, /**< slave alias. */
+        uint16_t posn /**< slave position. */
+        );
+        
+/** delete an EOE network interface
+ *
+ * \return 0 on success else negative error code
+ */
+int ecrt_master_eoe_delif(
+        ec_master_t *master, /**< EtherCAT master. */
+        uint16_t alias, /**< slave alias. */
+        uint16_t posn /**< slave position. */
+        );
+
+#endif /* EC_EOE */
+
 /** Reads the current master state.
  *
  * Stores the master state information in the given \a state structure.
diff --git a/lib/master.c b/lib/master.c
--- a/lib/master.c
+++ b/lib/master.c
@@ -727,6 +727,46 @@
 
 /****************************************************************************/
 
+#ifdef EC_EOE
+
+int ecrt_master_eoe_addif(ec_master_t *master, uint16_t alias, uint16_t posn)
+{
+    int ret;
+    ec_ioctl_eoe_if_t data;
+    data.alias = alias;
+    data.position = posn;
+    
+    ret = ioctl(master->fd, EC_IOCTL_EOE_ADDIF, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        EC_PRINT_ERR("Failed to add EoE interface: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+    }
+
+    return ret;
+}
+
+/****************************************************************************/
+
+int ecrt_master_eoe_delif(ec_master_t *master, uint16_t alias, uint16_t posn)
+{
+    int ret;
+    ec_ioctl_eoe_if_t data;
+    data.alias = alias;
+    data.position = posn;
+    
+    ret = ioctl(master->fd, EC_IOCTL_EOE_DELIF, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        EC_PRINT_ERR("Failed to add EoE interface: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+    }
+
+    return ret;
+}
+
+#endif
+
+/****************************************************************************/
+
 void ecrt_master_state(const ec_master_t *master, ec_master_state_t *state)
 {
     int ret;
diff --git a/master/Kbuild.in b/master/Kbuild.in
--- a/master/Kbuild.in
+++ b/master/Kbuild.in
@@ -90,11 +90,11 @@
 ec_master-objs += rtdm.o
 
 ifeq (@ENABLE_XENOMAI@, 1)
-CFLAGS_rtdm.o := -I@XENOMAI_DIR@/include
+EXTRA_CFLAGS := -I@XENOMAI_DIR@/include
 endif
 
 ifeq (@ENABLE_RTAI@, 1)
-CFLAGS_rtdm.o := -I@RTAI_DIR@/include
+EXTRA_CFLAGS := -I@RTAI_DIR@/include
 endif
 
 ec_master-objs += rtdm-ioctl.o
diff --git a/master/ethernet.c b/master/ethernet.c
--- a/master/ethernet.c
+++ b/master/ethernet.c
@@ -55,9 +55,9 @@
  */
 #define EOE_DEBUG_LEVEL 1
 
-/** Size of the EoE tx queue.
+/** Size of the EoE tx ring.
  */
-#define EC_EOE_TX_QUEUE_SIZE 100
+#define EC_EOE_TX_RING_SIZE 100
 
 /** Number of tries.
  */
@@ -66,6 +66,7 @@
 /*****************************************************************************/
 
 void ec_eoe_flush(ec_eoe_t *);
+static unsigned int eoe_tx_unused_frames(ec_eoe_t *);
 
 // state functions
 void ec_eoe_state_rx_start(ec_eoe_t *);
@@ -121,15 +122,93 @@
 
 /*****************************************************************************/
 
-/** EoE constructor.
+/** Parse an eoe interface from a string.
+ *
+ * The eoe interface must match the regular expression
+ * "eoe([0-9]*)([as])([0-9]*)".
  *
- * Initializes the EoE handler, creates a net_device and registers it.
+ * \return 0 on success, else < 0
+ */
+int ec_eoe_parse(const char *eoe, int *master_idx, 
+        uint16_t *alias, uint16_t *posn)
+{
+    unsigned int value;
+    const char *orig = eoe;
+    char *rem;
+
+    if (!strlen(eoe)) {
+        EC_ERR("EOE interface may not be empty.\n");
+        return -EINVAL;
+    }
+    
+    // must start with "eoe"
+    if (strncmp(eoe, "eoe", 3) != 0) {
+        EC_ERR("Invalid EOE interface \"%s\".\n", orig);
+        return -EINVAL;
+    }
+    eoe += 3;
+
+    // get master index, this does not check if the master index
+    // is valid beyond checking that it is not negative
+    value = simple_strtoul(eoe, &rem, 10);
+    if (value < 0) {
+        EC_ERR("Invalid EOE interface \"%s\", master index: %d\n", orig, value);
+        return -EINVAL;
+    }
+    *master_idx = value;
+    eoe = rem;
+    
+    // get alias or position specifier
+    if (eoe[0] == 'a') {
+        eoe++;
+        value = simple_strtoul(eoe, &rem, 10);
+        if ((value <= 0) || (value >= 0xFFFF)) {
+            EC_ERR("Invalid EOE interface \"%s\", invalid alias: %d\n", 
+                    orig, value);
+            return -EINVAL;
+        }
+        *alias = value;
+        *posn = 0;
+    } else if (eoe[0] == 's') {
+        eoe++;
+        value = simple_strtoul(eoe, &rem, 10);
+        if ((value < 0) || (value >= 0xFFFF)) {
+            EC_ERR("Invalid EOE interface \"%s\", invalid ring position: %d\n",
+                    orig, value);
+            return -EINVAL;
+        }
+        *alias = 0;
+        *posn = value;
+    } else {
+        EC_ERR("Invalid EOE interface \"%s\", invalid alias/position specifier: %c\n",
+                orig, eoe[0]);
+        return -EINVAL;
+    }
+    
+    // check no remainder
+    if (rem[0] != '\0') {
+        EC_ERR("Invalid EOE interface \"%s\", unexpected end characters: %s\n",
+                orig, rem);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** EoE explicit init constructor.
+ *
+ * Initializes the EoE handler before a slave is configured, creates a 
+ * net_device and registers it.
  *
  * \return Zero on success, otherwise a negative error code.
  */
 int ec_eoe_init(
+        ec_master_t *master, /**< EtherCAT master */
         ec_eoe_t *eoe, /**< EoE handler */
-        ec_slave_t *slave /**< EtherCAT slave */
+        uint16_t alias, /**< EtherCAT slave alias */
+        uint16_t ring_position /**< EtherCAT slave ring position */
         )
 {
     ec_eoe_t **priv;
@@ -140,7 +219,9 @@
     unsigned char lo_mac[ETH_ALEN] = {0};
     unsigned int use_master_mac = 0;
 
-    eoe->slave = slave;
+    eoe->master = master;
+    eoe->slave = NULL;
+    eoe->have_mbox_lock = 0;
 
     ec_datagram_init(&eoe->datagram);
     eoe->queue_datagram = 0;
@@ -148,13 +229,16 @@
     eoe->opened = 0;
     eoe->rx_skb = NULL;
     eoe->rx_expected_fragment = 0;
-    INIT_LIST_HEAD(&eoe->tx_queue);
-    eoe->tx_frame = NULL;
+
+    eoe->tx_ring_count = EC_EOE_TX_RING_SIZE;
+    eoe->tx_ring_size = sizeof(struct sk_buff *) * eoe->tx_ring_count;
+    eoe->tx_ring = kmalloc(eoe->tx_ring_size, GFP_KERNEL);
+    memset(eoe->tx_ring, 0, eoe->tx_ring_size);
+    eoe->tx_next_to_use = 0;
+    eoe->tx_next_to_clean = 0;
+    eoe->tx_skb = NULL;
     eoe->tx_queue_active = 0;
-    eoe->tx_queue_size = EC_EOE_TX_QUEUE_SIZE;
-    eoe->tx_queued_frames = 0;
 
-    ec_lock_init(&eoe->tx_queue_sem);
     eoe->tx_frame_number = 0xFF;
     memset(&eoe->stats, 0, sizeof(struct net_device_stats));
 
@@ -168,12 +252,10 @@
 
     /* device name eoe<MASTER>[as]<SLAVE>, because networking scripts don't
      * like hyphens etc. in interface names. */
-    if (slave->effective_alias) {
-        snprintf(name, EC_DATAGRAM_NAME_SIZE,
-                "eoe%ua%u", slave->master->index, slave->effective_alias);
+    if (alias) {
+        snprintf(name, EC_DATAGRAM_NAME_SIZE, "eoe%ua%u", master->index, alias);
     } else {
-        snprintf(name, EC_DATAGRAM_NAME_SIZE,
-                "eoe%us%u", slave->master->index, slave->ring_position);
+        snprintf(name, EC_DATAGRAM_NAME_SIZE, "eoe%us%u", master->index, ring_position);
     }
 
     snprintf(eoe->datagram.name, EC_DATAGRAM_NAME_SIZE, name);
@@ -185,7 +267,7 @@
     eoe->dev = alloc_netdev(sizeof(ec_eoe_t *), name, ether_setup);
 #endif
     if (!eoe->dev) {
-        EC_SLAVE_ERR(slave, "Unable to allocate net_device %s"
+        EC_MASTER_ERR(master, "Unable to allocate net_device %s"
                 " for EoE handler!\n", name);
         ret = -ENODEV;
         goto out_return;
@@ -203,7 +285,7 @@
 
     // First check if the MAC address assigned to the master is globally
     // unique
-    if ((slave->master->devices[EC_DEVICE_MAIN].dev->dev_addr[0] & 0x02) !=
+    if ((master->devices[EC_DEVICE_MAIN].dev->dev_addr[0] & 0x02) !=
             0x02) {
         // The master MAC is unique and the NIC part can be used for the EoE
         // interface MAC
@@ -231,7 +313,7 @@
                 // A unique MAC were identified in one of the other network
                 // interfaces and the NIC part can be used for the EoE
                 // interface MAC.
-                EC_SLAVE_INFO(slave, "%s MAC address derived from"
+                EC_MASTER_INFO(master, "%s MAC address derived from"
                         " NIC part of %s MAC address\n",
                     eoe->dev->name, dev->name);
                 eoe->dev->dev_addr[1] = dev->dev_addr[3];
@@ -245,42 +327,43 @@
     }
     if (eoe->dev->addr_len == ETH_ALEN) {
         if (use_master_mac) {
-            EC_SLAVE_INFO(slave, "%s MAC address derived"
+            EC_MASTER_INFO(master, "%s MAC address derived"
                     " from NIC part of %s MAC address\n",
                 eoe->dev->name,
-                slave->master->devices[EC_DEVICE_MAIN].dev->name);
+                master->devices[EC_DEVICE_MAIN].dev->name);
             eoe->dev->dev_addr[1] =
-                slave->master->devices[EC_DEVICE_MAIN].dev->dev_addr[3];
+                master->devices[EC_DEVICE_MAIN].dev->dev_addr[3];
             eoe->dev->dev_addr[2] =
-                slave->master->devices[EC_DEVICE_MAIN].dev->dev_addr[4];
+                master->devices[EC_DEVICE_MAIN].dev->dev_addr[4];
             eoe->dev->dev_addr[3] =
-                slave->master->devices[EC_DEVICE_MAIN].dev->dev_addr[5];
+                master->devices[EC_DEVICE_MAIN].dev->dev_addr[5];
         }
         eoe->dev->dev_addr[0] = 0x02;
-        eoe->dev->dev_addr[4] = (uint8_t)(slave->ring_position >> 8);
-        eoe->dev->dev_addr[5] = (uint8_t)(slave->ring_position);
+        if (alias) {
+            eoe->dev->dev_addr[4] = (uint8_t)(alias >> 8);
+            eoe->dev->dev_addr[5] = (uint8_t)(alias);
+        } else {
+            eoe->dev->dev_addr[4] = (uint8_t)(ring_position >> 8);
+            eoe->dev->dev_addr[5] = (uint8_t)(ring_position);
+        }
     }
 
     // initialize private data
     priv = netdev_priv(eoe->dev);
     *priv = eoe;
 
-    // Usually setting the MTU appropriately makes the upper layers
-    // do the frame fragmenting. In some cases this doesn't work
-    // so the MTU is left on the Ethernet standard value and fragmenting
-    // is done "manually".
-#if 0
-    eoe->dev->mtu = slave->configured_rx_mailbox_size - ETH_HLEN - 10;
-#endif
-
     // connect the net_device to the kernel
     ret = register_netdev(eoe->dev);
     if (ret) {
-        EC_SLAVE_ERR(slave, "Unable to register net_device:"
-                " error %i\n", ret);
+        EC_MASTER_ERR(master, "Unable to register net_device for %s:"
+                " error %i\n", eoe->dev->name, ret);
         goto out_free;
     }
 
+    // set carrier off status BEFORE open */
+    EC_MASTER_DBG(eoe->master, 1, "%s: carrier off.\n", eoe->dev->name);
+    netif_carrier_off(eoe->dev);
+
     return 0;
 
  out_free:
@@ -292,6 +375,109 @@
 
 /*****************************************************************************/
 
+/** EoE auto constructor for slave.
+ *
+ * Initializes the EoE handler, creates a net_device and registers it.
+ *
+ * \return Zero on success, otherwise a negative error code.
+ */
+int ec_eoe_auto_init(
+        ec_eoe_t *eoe, /**< EoE handler */
+        ec_slave_t *slave /**< EtherCAT slave */
+        )
+{
+    int ret = 0;
+
+    if ((ret = ec_eoe_init(slave->master, eoe, slave->effective_alias,
+            slave->ring_position)) != 0) {
+        return ret;
+    }
+
+    ec_eoe_link_slave(eoe, slave);
+
+    return ret;
+}
+
+/*****************************************************************************/
+
+/** EoE link slave.
+ *
+ * links a slave to a handler after a slave is connected or reconfigured
+ * during a rescan.
+ */
+void ec_eoe_link_slave(
+        ec_eoe_t *eoe, /**< EoE handler */
+        ec_slave_t *slave /**< EtherCAT slave */
+        )
+{
+    eoe->slave = slave;
+
+    if (eoe->slave) {
+        EC_SLAVE_INFO(slave, "Linked to EoE handler %s\n",
+                eoe->dev->name);
+
+        // Usually setting the MTU appropriately makes the upper layers
+        // do the frame fragmenting. In some cases this doesn't work
+        // so the MTU is left on the Ethernet standard value and fragmenting
+        // is done "manually".
+#if 0
+        eoe->dev->mtu = slave->configured_rx_mailbox_size - ETH_HLEN - 10;
+#endif
+
+        EC_MASTER_DBG(eoe->master, 1, "%s: carrier on.\n", eoe->dev->name);
+        netif_carrier_on(eoe->dev);
+    } else {
+        EC_MASTER_ERR(eoe->master, "%s : slave not supplied to ec_eoe_link_slave().\n",
+                eoe->dev->name);
+        EC_MASTER_DBG(eoe->master, 1, "%s: carrier off.\n", eoe->dev->name);
+        netif_carrier_off(eoe->dev);
+    }
+}
+
+/*****************************************************************************/
+
+/** EoE clear slave.
+ *
+ * delinks slave from the handler so that the EoE interface is kept if a
+ * slave get disconnected.
+ */
+void ec_eoe_clear_slave(ec_eoe_t *eoe /**< EoE handler */)
+{
+#if EOE_DEBUG_LEVEL >= 1
+    ec_slave_t *slave = eoe->slave;
+#endif
+
+    EC_MASTER_DBG(eoe->master, 1, "%s: carrier off.\n", eoe->dev->name);
+    netif_carrier_off(eoe->dev);
+
+    // empty transmit queue
+    ec_eoe_flush(eoe);
+
+    if (eoe->tx_skb) {
+        dev_kfree_skb(eoe->tx_skb);
+        eoe->tx_skb = NULL;
+        eoe->stats.tx_errors++;
+    }
+
+    if (eoe->rx_skb) {
+        dev_kfree_skb(eoe->rx_skb);
+        eoe->rx_skb = NULL;
+        eoe->stats.rx_errors++;
+    }
+
+    eoe->state = ec_eoe_state_rx_start;
+        
+    eoe->slave = NULL;
+
+#if EOE_DEBUG_LEVEL >= 1
+    if (slave) {
+        EC_MASTER_DBG(eoe->master, 0, "%s slave link cleared.\n", eoe->dev->name);
+    }
+#endif
+}
+
+/*****************************************************************************/
+
 /** EoE destructor.
  *
  * Unregisteres the net_device and frees allocated memory.
@@ -303,14 +489,14 @@
     // empty transmit queue
     ec_eoe_flush(eoe);
 
-    if (eoe->tx_frame) {
-        dev_kfree_skb(eoe->tx_frame->skb);
-        kfree(eoe->tx_frame);
-    }
+    if (eoe->tx_skb)
+        dev_kfree_skb(eoe->tx_skb);
 
     if (eoe->rx_skb)
         dev_kfree_skb(eoe->rx_skb);
 
+    kfree(eoe->tx_ring);
+
     free_netdev(eoe->dev);
 
     ec_datagram_clear(&eoe->datagram);
@@ -322,18 +508,56 @@
  */
 void ec_eoe_flush(ec_eoe_t *eoe /**< EoE handler */)
 {
-    ec_eoe_frame_t *frame, *next;
+    struct sk_buff *skb;
+
+    if (eoe->have_mbox_lock) {
+        eoe->have_mbox_lock = 0;
+        ec_read_mbox_lock_clear(eoe->slave);
+    }
+
+    while (eoe->tx_next_to_clean != eoe->tx_next_to_use) {
+        skb = eoe->tx_ring[eoe->tx_next_to_clean];
+        dev_kfree_skb(skb);
+        eoe->tx_ring[eoe->tx_next_to_clean] = NULL;
 
-    ec_lock_down(&eoe->tx_queue_sem);
+        eoe->stats.tx_dropped++;
+
+        if (unlikely(++eoe->tx_next_to_clean == eoe->tx_ring_count)) {
+            eoe->tx_next_to_clean = 0;
+        }
+    }
+
+    eoe->tx_next_to_use = 0;
+    eoe->tx_next_to_clean = 0;
+}
+
+/*****************************************************************************/
 
-    list_for_each_entry_safe(frame, next, &eoe->tx_queue, queue) {
-        list_del(&frame->queue);
-        dev_kfree_skb(frame->skb);
-        kfree(frame);
+unsigned int ec_eoe_tx_queued_frames(const ec_eoe_t *eoe /**< EoE handler */)
+{
+    unsigned int next_to_use = eoe->tx_next_to_use;
+    unsigned int next_to_clean = eoe->tx_next_to_clean;
+
+    if (next_to_use >= next_to_clean) {
+        return next_to_use - next_to_clean;
+    } else {
+        return next_to_use + eoe->tx_ring_count - next_to_clean;
     }
-    eoe->tx_queued_frames = 0;
+}
+
+/*****************************************************************************/
 
-    ec_lock_up(&eoe->tx_queue_sem);
+static unsigned int eoe_tx_unused_frames(ec_eoe_t *eoe /**< EoE handler */)
+{
+    unsigned int next_to_use = eoe->tx_next_to_use;
+    unsigned int next_to_clean = eoe->tx_next_to_clean;
+
+    // Note: -1 to avoid tail touching head
+    if (next_to_clean > next_to_use) {
+        return next_to_clean - next_to_use - 1;
+    } else {
+        return next_to_clean + eoe->tx_ring_count - next_to_use - 1;
+    }
 }
 
 /*****************************************************************************/
@@ -351,7 +575,11 @@
     unsigned int i;
 #endif
 
-    remaining_size = eoe->tx_frame->skb->len - eoe->tx_offset;
+    if (!eoe->slave) {
+        return -ECHILD;
+    }
+
+    remaining_size = eoe->tx_skb->len - eoe->tx_offset;
 
     if (remaining_size <= eoe->slave->configured_tx_mailbox_size - 10) {
         current_size = remaining_size;
@@ -375,13 +603,13 @@
             " with %zu octets (%zu). %u frames queued.\n",
             eoe->dev->name, eoe->tx_fragment_number,
             last_fragment ? "" : "+", current_size, complete_offset,
-            eoe->tx_queued_frames);
+            ec_eoe_tx_queued_frames(eoe));
 #endif
 
 #if EOE_DEBUG_LEVEL >= 3
     EC_SLAVE_DBG(eoe->slave, 0, "");
     for (i = 0; i < current_size; i++) {
-        printk(KERN_CONT "%02X ", eoe->tx_frame->skb->data[eoe->tx_offset + i]);
+        printk(KERN_CONT "%02X ", eoe->tx_skb->data[eoe->tx_offset + i]);
         if ((i + 1) % 16 == 0) {
             printk(KERN_CONT "\n");
             EC_SLAVE_DBG(eoe->slave, 0, "");
@@ -402,7 +630,7 @@
                             (complete_offset & 0x3F) << 6 |
                             (eoe->tx_frame_number & 0x0F) << 12));
 
-    memcpy(data + 4, eoe->tx_frame->skb->data + eoe->tx_offset, current_size);
+    memcpy(data + 4, eoe->tx_skb->data + eoe->tx_offset, current_size);
     eoe->queue_datagram = 1;
 
     eoe->tx_offset += current_size;
@@ -416,7 +644,7 @@
  */
 void ec_eoe_run(ec_eoe_t *eoe /**< EoE handler */)
 {
-    if (!eoe->opened) {
+    if (!eoe->opened || !eoe->slave || !netif_carrier_ok(eoe->dev)) {
         return;
     }
 
@@ -446,7 +674,7 @@
  */
 void ec_eoe_queue(ec_eoe_t *eoe /**< EoE handler */)
 {
-   if (eoe->queue_datagram) {
+   if (eoe->queue_datagram && eoe->slave) {
        ec_master_queue_datagram_ext(eoe->slave->master, &eoe->datagram);
        eoe->queue_datagram = 0;
    }
@@ -475,6 +703,17 @@
     return eoe->rx_idle && eoe->tx_idle;
 }
 
+/*****************************************************************************/
+
+/** Returns the eoe device name.
+ *
+ * \retval the device name.
+ */
+char *ec_eoe_name(const ec_eoe_t *eoe /**< EoE handler */)
+{
+    return eoe->dev->name;
+}
+
 /******************************************************************************
  *  STATE PROCESSING FUNCTIONS
  *****************************************************************************/
@@ -488,7 +727,7 @@
  */
 void ec_eoe_state_rx_start(ec_eoe_t *eoe /**< EoE handler */)
 {
-    if (eoe->slave->error_flag ||
+    if (!eoe->slave || eoe->slave->error_flag ||
             !eoe->slave->master->devices[EC_DEVICE_MAIN].link_state) {
         eoe->rx_idle = 1;
         eoe->tx_idle = 1;
@@ -499,6 +738,7 @@
     if (ec_read_mbox_locked(eoe->slave)) {
         eoe->state = ec_eoe_state_rx_fetch_data;
     } else {
+        eoe->have_mbox_lock = 1;
         ec_slave_mbox_prepare_check(eoe->slave, &eoe->datagram);
         eoe->queue_datagram = 1;
         eoe->state = ec_eoe_state_rx_check;
@@ -515,18 +755,20 @@
 void ec_eoe_state_rx_check(ec_eoe_t *eoe /**< EoE handler */)
 {
     if (eoe->datagram.state != EC_DATAGRAM_RECEIVED) {
-        eoe->stats.rx_errors++;
 #if EOE_DEBUG_LEVEL >= 1
         EC_SLAVE_WARN(eoe->slave, "Failed to receive mbox"
                 " check datagram for %s.\n", eoe->dev->name);
+        eoe->stats.rx_errors++;
 #endif
         eoe->state = ec_eoe_state_tx_start;
+        eoe->have_mbox_lock = 0;
         ec_read_mbox_lock_clear(eoe->slave);
         return;
     }
 
     if (!ec_slave_mbox_check(&eoe->datagram)) {
         eoe->rx_idle = 1;
+        eoe->have_mbox_lock = 0;
         ec_read_mbox_lock_clear(eoe->slave);
         // check that data is not already received by another read request
         if (eoe->slave->mbox_eoe_data.payload_size > 0) {
@@ -553,7 +795,6 @@
  */
 void ec_eoe_state_rx_fetch(ec_eoe_t *eoe /**< EoE handler */)
 {
-
     if (eoe->datagram.state != EC_DATAGRAM_RECEIVED) {
         eoe->stats.rx_errors++;
 #if EOE_DEBUG_LEVEL >= 1
@@ -561,9 +802,11 @@
                 " fetch datagram for %s.\n", eoe->dev->name);
 #endif
         eoe->state = ec_eoe_state_tx_start;
+        eoe->have_mbox_lock = 0;
         ec_read_mbox_lock_clear(eoe->slave);
         return;
     }
+    eoe->have_mbox_lock = 0;
     ec_read_mbox_lock_clear(eoe->slave);
     eoe->state = ec_eoe_state_rx_fetch_data;
     eoe->state(eoe);
@@ -595,6 +838,7 @@
     } else {
         // initiate a new mailbox read check if required data is not available
         if (!ec_read_mbox_locked(eoe->slave)) {
+            eoe->have_mbox_lock = 1;
             ec_slave_mbox_prepare_check(eoe->slave, &eoe->datagram);
             eoe->queue_datagram = 1;
             eoe->state = ec_eoe_state_rx_check;
@@ -762,17 +1006,20 @@
     unsigned int wakeup = 0;
 #endif
 
-    if (eoe->slave->error_flag ||
+    if (!eoe->slave || eoe->slave->error_flag ||
             !eoe->slave->master->devices[EC_DEVICE_MAIN].link_state) {
         eoe->rx_idle = 1;
         eoe->tx_idle = 1;
         return;
     }
 
-    ec_lock_down(&eoe->tx_queue_sem);
+    if (eoe->tx_next_to_use == eoe->tx_next_to_clean) {
+        // check if the queue needs to be restarted
+        if (!eoe->tx_queue_active) {
+            eoe->tx_queue_active = 1;
+            netif_wake_queue(eoe->dev);
+        }
 
-    if (!eoe->tx_queued_frames || list_empty(&eoe->tx_queue)) {
-        ec_lock_up(&eoe->tx_queue_sem);
         eoe->tx_idle = 1;
         // no data available.
         // start a new receive immediately.
@@ -780,21 +1027,23 @@
         return;
     }
 
-    // take the first frame out of the queue
-    eoe->tx_frame = list_entry(eoe->tx_queue.next, ec_eoe_frame_t, queue);
-    list_del(&eoe->tx_frame->queue);
+    // get the frame and take it out of the ring
+    eoe->tx_skb = eoe->tx_ring[eoe->tx_next_to_clean];
+    eoe->tx_ring[eoe->tx_next_to_clean] = NULL;
+    if (unlikely(++eoe->tx_next_to_clean == eoe->tx_ring_count)) {
+        eoe->tx_next_to_clean = 0;
+    }
+
+    // restart queue?
     if (!eoe->tx_queue_active &&
-        eoe->tx_queued_frames == eoe->tx_queue_size / 2) {
+            (ec_eoe_tx_queued_frames(eoe) <= eoe->tx_ring_count / 2)) {
+        eoe->tx_queue_active = 1;
         netif_wake_queue(eoe->dev);
-        eoe->tx_queue_active = 1;
 #if EOE_DEBUG_LEVEL >= 2
         wakeup = 1;
 #endif
     }
 
-    eoe->tx_queued_frames--;
-    ec_lock_up(&eoe->tx_queue_sem);
-
     eoe->tx_idle = 0;
 
     eoe->tx_frame_number++;
@@ -803,9 +1052,8 @@
     eoe->tx_offset = 0;
 
     if (ec_eoe_send(eoe)) {
-        dev_kfree_skb(eoe->tx_frame->skb);
-        kfree(eoe->tx_frame);
-        eoe->tx_frame = NULL;
+        dev_kfree_skb(eoe->tx_skb);
+        eoe->tx_skb = NULL;
         eoe->stats.tx_errors++;
         eoe->state = ec_eoe_state_rx_start;
 #if EOE_DEBUG_LEVEL >= 1
@@ -815,9 +1063,10 @@
     }
 
 #if EOE_DEBUG_LEVEL >= 2
-    if (wakeup)
+    if (wakeup) {
         EC_SLAVE_DBG(eoe->slave, 0, "EoE %s waking up TX queue...\n",
                 eoe->dev->name);
+    }
 #endif
 
     eoe->tries = EC_EOE_TRIES;
@@ -838,11 +1087,15 @@
             eoe->tries--; // try again
             eoe->queue_datagram = 1;
         } else {
+#if EOE_DEBUG_LEVEL >= 1
+            /* only log every 1000th */
+            if (eoe->stats.tx_errors++ % 1000 == 0) {
+                EC_SLAVE_WARN(eoe->slave, "Failed to receive send"
+                        " datagram for %s after %u tries.\n",
+                        eoe->dev->name, EC_EOE_TRIES);
+            }
+#else
             eoe->stats.tx_errors++;
-#if EOE_DEBUG_LEVEL >= 1
-            EC_SLAVE_WARN(eoe->slave, "Failed to receive send"
-                    " datagram for %s after %u tries.\n",
-                    eoe->dev->name, EC_EOE_TRIES);
 #endif
             eoe->state = ec_eoe_state_rx_start;
         }
@@ -866,20 +1119,18 @@
     }
 
     // frame completely sent
-    if (eoe->tx_offset >= eoe->tx_frame->skb->len) {
+    if (eoe->tx_offset >= eoe->tx_skb->len) {
         eoe->stats.tx_packets++;
-        eoe->stats.tx_bytes += eoe->tx_frame->skb->len;
-        eoe->tx_counter += eoe->tx_frame->skb->len;
-        dev_kfree_skb(eoe->tx_frame->skb);
-        kfree(eoe->tx_frame);
-        eoe->tx_frame = NULL;
+        eoe->stats.tx_bytes += eoe->tx_skb->len;
+        eoe->tx_counter += eoe->tx_skb->len;
+        dev_kfree_skb(eoe->tx_skb);
+        eoe->tx_skb = NULL;
         eoe->state = ec_eoe_state_rx_start;
     }
     else { // send next fragment
         if (ec_eoe_send(eoe)) {
-            dev_kfree_skb(eoe->tx_frame->skb);
-            kfree(eoe->tx_frame);
-            eoe->tx_frame = NULL;
+            dev_kfree_skb(eoe->tx_skb);
+            eoe->tx_skb = NULL;
             eoe->stats.tx_errors++;
 #if EOE_DEBUG_LEVEL >= 1
             EC_SLAVE_WARN(eoe->slave, "Send error at %s.\n", eoe->dev->name);
@@ -900,15 +1151,27 @@
 int ec_eoedev_open(struct net_device *dev /**< EoE net_device */)
 {
     ec_eoe_t *eoe = *((ec_eoe_t **) netdev_priv(dev));
+
+    // set carrier to off until we know link status
+    EC_MASTER_DBG(eoe->master, 1, "%s: carrier off.\n", dev->name);
+    netif_carrier_off(dev);
+
     ec_eoe_flush(eoe);
     eoe->opened = 1;
     eoe->rx_idle = 0;
     eoe->tx_idle = 0;
+    eoe->tx_queue_active = 1;
     netif_start_queue(dev);
-    eoe->tx_queue_active = 1;
 #if EOE_DEBUG_LEVEL >= 2
-    EC_SLAVE_DBG(eoe->slave, 0, "%s opened.\n", dev->name);
+    EC_MASTER_DBG(eoe->master, 0, "%s opened.\n", dev->name);
 #endif
+    
+    // update carrier link status
+    if (eoe->slave) {
+        EC_MASTER_DBG(eoe->master, 1, "%s: carrier on.\n", dev->name);
+        netif_carrier_on(dev);
+    }
+
     return 0;
 }
 
@@ -921,14 +1184,17 @@
 int ec_eoedev_stop(struct net_device *dev /**< EoE net_device */)
 {
     ec_eoe_t *eoe = *((ec_eoe_t **) netdev_priv(dev));
+    
+    EC_MASTER_DBG(eoe->master, 1, "%s: carrier off.\n", dev->name);
+    netif_carrier_off(dev);
     netif_stop_queue(dev);
+    eoe->tx_queue_active = 0;
     eoe->rx_idle = 1;
     eoe->tx_idle = 1;
-    eoe->tx_queue_active = 0;
     eoe->opened = 0;
     ec_eoe_flush(eoe);
 #if EOE_DEBUG_LEVEL >= 2
-    EC_SLAVE_DBG(eoe->slave, 0, "%s stopped.\n", dev->name);
+    EC_MASTER_DBG(eoe->master, 0, "%s stopped.\n", dev->name);
 #endif
     return 0;
 }
@@ -944,8 +1210,16 @@
                 )
 {
     ec_eoe_t *eoe = *((ec_eoe_t **) netdev_priv(dev));
-    ec_eoe_frame_t *frame;
 
+    if (!eoe->slave) {
+        if (skb) {
+            dev_kfree_skb(skb);
+            eoe->stats.tx_dropped++;
+        }
+        
+        return NETDEV_TX_OK;
+    }
+    
 #if 0
     if (skb->len > eoe->slave->configured_tx_mailbox_size - 10) {
         EC_SLAVE_WARN(eoe->slave, "EoE TX frame (%u octets)"
@@ -956,28 +1230,24 @@
     }
 #endif
 
-    if (!(frame =
-          (ec_eoe_frame_t *) kmalloc(sizeof(ec_eoe_frame_t), GFP_ATOMIC))) {
-        if (printk_ratelimit())
-            EC_SLAVE_WARN(eoe->slave, "EoE TX: low on mem. frame dropped.\n");
-        return 1;
+    // set the skb in the ring
+    eoe->tx_ring[eoe->tx_next_to_use] = skb;
+
+    // increment index
+    if (unlikely(++eoe->tx_next_to_use == eoe->tx_ring_count)) {
+        eoe->tx_next_to_use = 0;
     }
 
-    frame->skb = skb;
-
-    ec_lock_down(&eoe->tx_queue_sem);
-    list_add_tail(&frame->queue, &eoe->tx_queue);
-    eoe->tx_queued_frames++;
-    if (eoe->tx_queued_frames == eoe->tx_queue_size) {
+    // stop the queue?
+    if (eoe_tx_unused_frames(eoe) == 0) {
         netif_stop_queue(dev);
         eoe->tx_queue_active = 0;
     }
-    ec_lock_up(&eoe->tx_queue_sem);
 
 #if EOE_DEBUG_LEVEL >= 2
     EC_SLAVE_DBG(eoe->slave, 0, "EoE %s TX queued frame"
             " with %u octets (%u frames queued).\n",
-            eoe->dev->name, skb->len, eoe->tx_queued_frames);
+            eoe->dev->name, skb->len, ec_eoe_tx_queued_frames(eoe));
     if (!eoe->tx_queue_active) {
         EC_SLAVE_WARN(eoe->slave, "EoE TX queue is now full.\n");
     }
diff --git a/master/ethernet.h b/master/ethernet.h
--- a/master/ethernet.h
+++ b/master/ethernet.h
@@ -59,19 +59,6 @@
 
 /*****************************************************************************/
 
-/**
-   Queued frame structure.
-*/
-
-typedef struct
-{
-    struct list_head queue; /**< list item */
-    struct sk_buff *skb; /**< socket buffer */
-}
-ec_eoe_frame_t;
-
-/*****************************************************************************/
-
 typedef struct ec_eoe ec_eoe_t; /**< \see ec_eoe */
 
 /**
@@ -83,6 +70,7 @@
 struct ec_eoe
 {
     struct list_head list; /**< list item */
+    ec_master_t *master; /**< pointer to the corresponding master */
     ec_slave_t *slave; /**< pointer to the corresponding slave */
     ec_datagram_t datagram; /**< datagram */
     unsigned int queue_datagram; /**< the datagram is ready for queuing */
@@ -91,6 +79,7 @@
     struct net_device_stats stats; /**< device statistics */
     unsigned int opened; /**< net_device is opened */
     unsigned long rate_jiffies; /**< time of last rate output */
+    unsigned int have_mbox_lock; /**< flag to track if we have the mbox lock */
 
     struct sk_buff *rx_skb; /**< current rx socket buffer */
     off_t rx_skb_offset; /**< current write pointer in the socket buffer */
@@ -100,12 +89,13 @@
     uint32_t rx_rate; /**< receive rate (bps) */
     unsigned int rx_idle; /**< Idle flag. */
 
-    struct list_head tx_queue; /**< queue for frames to send */
-    unsigned int tx_queue_size; /**< Transmit queue size. */
+    struct sk_buff **tx_ring; /**< ring for frames to send */
+    unsigned int tx_ring_count; /**< Transmit ring count. */
+    unsigned int tx_ring_size; /**< Transmit ring size. */
+    unsigned int tx_next_to_use; /**< index of frames added to the ring */
+    unsigned int tx_next_to_clean; /**< index of frames being used from the ring */
     unsigned int tx_queue_active; /**< kernel netif queue started */
-    unsigned int tx_queued_frames; /**< number of frames in the queue */
-    ec_lock_t tx_queue_sem; /**< Semaphore for the send queue. */
-    ec_eoe_frame_t *tx_frame; /**< current TX frame */
+    struct sk_buff *tx_skb; /**< current TX frame */
     uint8_t tx_frame_number; /**< number of the transmitted frame */
     uint8_t tx_fragment_number; /**< number of the fragment */
     size_t tx_offset; /**< number of octets sent */
@@ -118,12 +108,19 @@
 
 /*****************************************************************************/
 
-int ec_eoe_init(ec_eoe_t *, ec_slave_t *);
+int ec_eoe_parse(const char *, int *, uint16_t *, uint16_t *);
+
+int ec_eoe_init(ec_master_t *, ec_eoe_t *, uint16_t/*alias*/, uint16_t/*posn*/);
+int ec_eoe_auto_init(ec_eoe_t *, ec_slave_t *);
+void ec_eoe_link_slave(ec_eoe_t *, ec_slave_t *);
+void ec_eoe_clear_slave(ec_eoe_t *);
 void ec_eoe_clear(ec_eoe_t *);
 void ec_eoe_run(ec_eoe_t *);
 void ec_eoe_queue(ec_eoe_t *);
 int ec_eoe_is_open(const ec_eoe_t *);
 int ec_eoe_is_idle(const ec_eoe_t *);
+char *ec_eoe_name(const ec_eoe_t *);
+unsigned int ec_eoe_tx_queued_frames(const ec_eoe_t *);
 
 /*****************************************************************************/
 
diff --git a/master/fsm_master.c b/master/fsm_master.c
--- a/master/fsm_master.c
+++ b/master/fsm_master.c
@@ -289,7 +289,11 @@
         ec_master_slaves_not_available(master);
 #ifdef EC_EOE
         ec_master_eoe_stop(master);
-        ec_master_clear_eoe_handlers(master);
+        if (eoe_autocreate) {
+            ec_master_clear_eoe_handlers(master);
+        } else {
+            ec_master_clear_eoe_handler_slaves(master);
+        }
 #endif
         ec_master_clear_slaves(master);
         ec_master_clear_sii_images(master);
@@ -349,7 +353,11 @@
             ec_master_slaves_not_available(master);
 #ifdef EC_EOE
             ec_master_eoe_stop(master);
-            ec_master_clear_eoe_handlers(master);
+            if (eoe_autocreate) {
+                ec_master_clear_eoe_handlers(master);
+            } else {
+                ec_master_clear_eoe_handler_slaves(master);
+            }
 #endif
             ec_master_clear_slaves(master);
             ec_master_clear_sii_images(master);
diff --git a/master/fsm_slave.c b/master/fsm_slave.c
--- a/master/fsm_slave.c
+++ b/master/fsm_slave.c
@@ -325,6 +325,40 @@
 
 /*****************************************************************************/
 
+#ifdef EC_EOE
+/** try to reconnect to an existing EoE handler.
+ */
+static int ec_slave_reconnect_to_eoe_handler(
+        ec_slave_t *slave /**< EtherCAT slave */
+        )
+{
+    ec_master_t *master = slave->master;
+    ec_eoe_t *eoe;
+    char name[EC_DATAGRAM_NAME_SIZE];
+
+    if (slave->effective_alias) {
+        snprintf(name, EC_DATAGRAM_NAME_SIZE,
+                "eoe%ua%u", master->index, slave->effective_alias);
+    } else {
+        snprintf(name, EC_DATAGRAM_NAME_SIZE,
+                "eoe%us%u", master->index, slave->ring_position);
+    }
+
+    list_for_each_entry(eoe, &master->eoe_handlers, list) {
+        if ((eoe->slave == NULL) && 
+                (strncmp(name, ec_eoe_name(eoe), EC_DATAGRAM_NAME_SIZE) == 0)) {
+            ec_eoe_link_slave(eoe, slave);
+            return 0;
+        }
+    }
+    
+    // none found
+    return -1;
+}
+#endif
+
+/*****************************************************************************/
+
 /** Slave state: SCAN.
  */
 void ec_fsm_slave_state_scan(
@@ -344,15 +378,22 @@
 
 #ifdef EC_EOE
     if (slave->sii_image && (slave->sii_image->sii.mailbox_protocols & EC_MBOX_EOE)) {
-        // create EoE handler for this slave
-        ec_eoe_t *eoe;
-        if (!(eoe = kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) {
-            EC_SLAVE_ERR(slave, "Failed to allocate EoE handler memory!\n");
-        } else if (ec_eoe_init(eoe, slave)) {
-            EC_SLAVE_ERR(slave, "Failed to init EoE handler!\n");
-            kfree(eoe);
-        } else {
-            list_add_tail(&eoe->list, &slave->master->eoe_handlers);
+        // try to connect to existing eoe handler, 
+        // otherwise try to create a new one (if master not active)
+        if (ec_slave_reconnect_to_eoe_handler(slave) == 0) {
+            // reconnected
+        } else if (eoe_autocreate) {
+            // auto create EoE handler for this slave
+            ec_eoe_t *eoe;
+        
+            if (!(eoe = kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) {
+                EC_SLAVE_ERR(slave, "Failed to allocate EoE handler memory!\n");
+            } else if (ec_eoe_auto_init(eoe, slave)) {
+                EC_SLAVE_ERR(slave, "Failed to init EoE handler!\n");
+                kfree(eoe);
+            } else {
+                list_add_tail(&eoe->list, &slave->master->eoe_handlers);
+            }
         }
     }
 #endif
diff --git a/master/ioctl.c b/master/ioctl.c
--- a/master/ioctl.c
+++ b/master/ioctl.c
@@ -1747,12 +1747,38 @@
     }
     snprintf(data.name, EC_DATAGRAM_NAME_SIZE, eoe->dev->name);
     data.open = eoe->opened;
-    data.rx_bytes = eoe->stats.tx_bytes;
-    data.rx_rate = eoe->tx_rate;
-    data.tx_bytes = eoe->stats.rx_bytes;
+    data.rx_bytes = eoe->stats.rx_bytes;
+    data.rx_rate = eoe->rx_rate;
+    data.tx_bytes = eoe->stats.tx_bytes;
     data.tx_rate = eoe->tx_rate;
-    data.tx_queued_frames = eoe->tx_queued_frames;
-    data.tx_queue_size = eoe->tx_queue_size;
+    data.tx_queued_frames = ec_eoe_tx_queued_frames(eoe);
+    data.tx_queue_size = eoe->tx_ring_count;
+    
+    EC_MASTER_DBG(master, 1, "EOE %s Info:\n", eoe->dev->name);
+    EC_MASTER_DBG(master, 1, "  opened:               %u\n", eoe->opened);
+    EC_MASTER_DBG(master, 1, "  rate_jiffies:         %lu\n", eoe->rate_jiffies);
+    EC_MASTER_DBG(master, 1, "  queue_datagram:       %u\n", eoe->queue_datagram);
+    EC_MASTER_DBG(master, 1, "  have_mbox_lock:       %u\n", eoe->have_mbox_lock);
+    EC_MASTER_DBG(master, 1, "  rx_skb:               %p\n", eoe->rx_skb);
+    EC_MASTER_DBG(master, 1, "  rx_skb_offset:        %d\n", (int)eoe->rx_skb_offset);
+    EC_MASTER_DBG(master, 1, "  rx_skb_size:          %u\n", eoe->rx_skb_size);
+    EC_MASTER_DBG(master, 1, "  rx_expected_fragment: %hhu\n", eoe->rx_skb_size);
+    EC_MASTER_DBG(master, 1, "  rx_counter:           %u\n", eoe->rx_counter);
+    EC_MASTER_DBG(master, 1, "  rx_rate:              %u\n", eoe->rx_rate);
+    EC_MASTER_DBG(master, 1, "  rx_idle:              %u\n", eoe->rx_idle);
+    EC_MASTER_DBG(master, 1, "  tx_ring_count:        %u\n", eoe->tx_ring_count);
+    EC_MASTER_DBG(master, 1, "  tx_ring_size:         %u\n", eoe->tx_ring_size);
+    EC_MASTER_DBG(master, 1, "  tx_next_to_use:       %u\n", eoe->tx_next_to_use);
+    EC_MASTER_DBG(master, 1, "  tx_next_to_clean:     %u\n", eoe->tx_next_to_clean);
+    EC_MASTER_DBG(master, 1, "  tx_queue_active:      %u\n", eoe->tx_queue_active);
+    EC_MASTER_DBG(master, 1, "  tx_queued_frames:     %u\n", data.tx_queued_frames);
+    EC_MASTER_DBG(master, 1, "  tx_frame_number:      %hhu\n", eoe->tx_frame_number);
+    EC_MASTER_DBG(master, 1, "  tx_fragment_number:   %hhu\n", eoe->tx_fragment_number);
+    EC_MASTER_DBG(master, 1, "  tx_offset:            %u\n", eoe->tx_offset);
+    EC_MASTER_DBG(master, 1, "  tx_counter:           %u\n", eoe->tx_counter);
+    EC_MASTER_DBG(master, 1, "  tx_rate:              %u\n", eoe->tx_rate);
+    EC_MASTER_DBG(master, 1, "  tx_idle:              %u\n", eoe->tx_idle);
+    EC_MASTER_DBG(master, 1, "  tries:                %u\n", eoe->tries);
 
     ec_lock_up(&master->master_sem);
 
@@ -5052,6 +5078,58 @@
 
 /*****************************************************************************/
 
+#ifdef EC_EOE
+
+/** add an EOE interface
+ *
+ * \return Zero on success, otherwise a negative error code.
+ */
+static ATTRIBUTES int ec_ioctl_eoe_addif(
+        ec_master_t *master, /**< EtherCAT master. */
+        void *arg, /**< ioctl() argument. */
+        ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
+        )
+{
+    int ret;
+    ec_ioctl_eoe_if_t data;
+
+    if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+        return -EFAULT;
+    }
+
+    ret = ecrt_master_eoe_addif(master, data.alias, data.position);
+
+    return ret;
+}
+
+/*****************************************************************************/
+
+/** delete an EOE interface
+ *
+ * \return Zero on success, otherwise a negative error code.
+ */
+static ATTRIBUTES int ec_ioctl_eoe_delif(
+        ec_master_t *master, /**< EtherCAT master. */
+        void *arg, /**< ioctl() argument. */
+        ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
+        )
+{
+    int ret;
+    ec_ioctl_eoe_if_t data;
+
+    if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+        return -EFAULT;
+    }
+
+    ret = ecrt_master_eoe_delif(master, data.alias, data.position);
+
+    return ret;
+}
+
+#endif
+
+/*****************************************************************************/
+
 /** ioctl() function to use.
  */
 #ifdef EC_IOCTL_RTDM
@@ -5684,6 +5762,22 @@
         case EC_IOCTL_SLAVE_DICT_UPLOAD:
             ret = ec_ioctl_slave_dict_upload(master, arg);
             break;
+#ifdef EC_EOE
+        case EC_IOCTL_EOE_ADDIF:
+            if (!ctx->writable) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_ioctl_eoe_addif(master, arg, ctx);
+            break;
+        case EC_IOCTL_EOE_DELIF:
+            if (!ctx->writable) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_ioctl_eoe_delif(master, arg, ctx);
+            break;
+#endif
         default:
             ret = -ENOTTY;
             break;
diff --git a/master/ioctl.h b/master/ioctl.h
--- a/master/ioctl.h
+++ b/master/ioctl.h
@@ -172,6 +172,11 @@
 #define EC_IOCTL_RT_SLAVE_REQUESTS     EC_IOW(0x6b, uint32_t)
 #define EC_IOCTL_EXEC_SLAVE_REQUESTS    EC_IO(0x6c)
 
+#ifdef EC_EOE
+#define EC_IOCTL_EOE_ADDIF            EC_IOWR(0x70, ec_ioctl_eoe_if_t)
+#define EC_IOCTL_EOE_DELIF            EC_IOWR(0x71, ec_ioctl_eoe_if_t)
+#endif
+
 /*****************************************************************************/
 
 #define EC_IOCTL_STRING_SIZE 64
@@ -620,6 +625,14 @@
     uint32_t tx_queue_size;
 } ec_ioctl_eoe_handler_t;
 
+/*****************************************************************************/
+
+typedef struct {
+    // input
+    uint16_t alias;
+    uint16_t position;
+} ec_ioctl_eoe_if_t;
+
 #endif
 
 /*****************************************************************************/
diff --git a/master/master.c b/master/master.c
--- a/master/master.c
+++ b/master/master.c
@@ -453,6 +453,21 @@
 /*****************************************************************************/
 
 #ifdef EC_EOE
+/** Clear all EoE handlers of their slaves.
+ */
+void ec_master_clear_eoe_handler_slaves(
+        ec_master_t *master /**< EtherCAT master */
+        )
+{
+    ec_eoe_t *eoe;
+
+    list_for_each_entry(eoe, &master->eoe_handlers, list) {
+        ec_eoe_clear_slave(eoe);
+    }
+}
+
+/*****************************************************************************/
+
 /** Clear and free all EoE handlers.
  */
 void ec_master_clear_eoe_handlers(
@@ -738,6 +753,11 @@
 {
     int ret;
     ec_device_index_t dev_idx;
+#ifdef EC_EOE
+    int i;
+    int master_index = 0;
+    uint16_t alias, ring_position = 0;
+#endif
 
     EC_MASTER_DBG(master, 1, "ORPHANED -> IDLE.\n");
 
@@ -753,6 +773,23 @@
         master->fsm.slaves_responding[dev_idx] = 0;
     }
 
+#ifdef EC_EOE
+    // create eoe interfaces for this master on startup
+    // Note: needs the masters main device to be configured to init the 
+    //   eoe's mac address
+    for (i = 0; i < eoe_count; i++) {
+        ret = ec_eoe_parse(eoe_interfaces[i], &master_index, &alias, 
+                &ring_position);
+        
+        if ((ret == 0) && (master_index == master->index)) {
+            EC_MASTER_INFO(master, "Adding EOE iface \"%s\" for master %d, "
+                    "alias %u, ring position %u.\n",
+                    eoe_interfaces[i], master_index, alias, ring_position);
+            ecrt_master_eoe_addif(master, alias, ring_position);
+        }
+    }
+#endif
+
     ret = ec_master_thread_start(master, ec_master_idle_thread,
             "EtherCAT-IDLE");
     if (ret)
@@ -1962,12 +1999,16 @@
         none_open = 1;
         all_idle = 1;
 
+        ec_lock_down(&master->master_sem);
         list_for_each_entry(eoe, &master->eoe_handlers, list) {
             if (ec_eoe_is_open(eoe)) {
                 none_open = 0;
+                ec_lock_up(&master->master_sem);
                 break;
             }
         }
+        ec_lock_up(&master->master_sem);
+        
         if (none_open) {
             goto schedule;
         }
@@ -1976,6 +2017,7 @@
         master->receive_cb(master->cb_data);
 
         // actual EoE processing
+        ec_lock_down(&master->master_sem);
         sth_to_send = 0;
         list_for_each_entry(eoe, &master->eoe_handlers, list) {
             if ((eoe->slave->current_state == EC_SLAVE_STATE_PREOP) ||
@@ -1990,17 +2032,19 @@
                 }
             }
         }
+        ec_lock_up(&master->master_sem);
 
         if (sth_to_send) {
+            ec_lock_down(&master->master_sem);
             list_for_each_entry(eoe, &master->eoe_handlers, list) {
                 ec_eoe_queue(eoe);
             }
+            ec_lock_up(&master->master_sem);
+            
             // (try to) send datagrams
-            ec_lock_down(&master->ext_queue_sem);
             master->send_cb(master->cb_data);
-            ec_lock_up(&master->ext_queue_sem);
         }
-
+        
 schedule:
         if (all_idle) {
             set_current_state(TASK_INTERRUPTIBLE);
@@ -2662,7 +2706,7 @@
 
     ec_master_thread_stop(master);
 #ifdef EC_EOE
-    eoe_was_running = master->eoe_thread != NULL;
+    eoe_was_running = (master->eoe_thread != NULL);
     ec_master_eoe_stop(master);
 #endif
 
@@ -2705,9 +2749,6 @@
 {
     ec_slave_t *slave;
     ec_slave_config_t *sc, *next;
-#ifdef EC_EOE
-    ec_eoe_t *eoe;
-#endif
 
     EC_MASTER_DBG(master, 1, "%s(master = 0x%p)\n", __func__, master);
 
@@ -2737,14 +2778,6 @@
         // phases.
         slave->force_config = 1;
     }
-
-#ifdef EC_EOE
-    // ... but leave EoE slaves in OP
-    list_for_each_entry(eoe, &master->eoe_handlers, list) {
-        if (ec_eoe_is_open(eoe))
-            ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_OP);
-    }
-#endif
 }
 
 /*****************************************************************************/
@@ -2752,10 +2785,6 @@
 void ecrt_master_deactivate(ec_master_t *master)
 {
     ec_slave_t *slave;
-#ifdef EC_EOE
-    ec_eoe_t *eoe;
-    int eoe_was_running;
-#endif
 
     EC_MASTER_DBG(master, 1, "%s(master = 0x%p)\n", __func__, master);
 
@@ -2767,7 +2796,6 @@
 
     ec_master_thread_stop(master);
 #ifdef EC_EOE
-    eoe_was_running = master->eoe_thread != NULL;
     ec_master_eoe_stop(master);
 #endif
 
@@ -2793,14 +2821,6 @@
         slave->force_config = 1;
     }
 
-#ifdef EC_EOE
-    // ... but leave EoE slaves in OP
-    list_for_each_entry(eoe, &master->eoe_handlers, list) {
-        if (ec_eoe_is_open(eoe))
-            ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_OP);
-    }
-#endif
-
     master->app_time = 0ULL;
     master->app_start_time = 0ULL;
     master->has_app_time = 0;
@@ -2813,9 +2833,7 @@
     master->active = 0;
 
 #ifdef EC_EOE
-    if (eoe_was_running) {
-        ec_master_eoe_start(master);
-    }
+    ec_master_eoe_start(master);
 #endif
     if (ec_master_thread_start(master, ec_master_idle_thread,
                 "EtherCAT-IDLE")) {
@@ -2926,17 +2944,20 @@
 
 /*****************************************************************************/
 
-void ecrt_master_send_ext(ec_master_t *master)
+size_t ecrt_master_send_ext(ec_master_t *master)
 {
     ec_datagram_t *datagram, *next;
 
+    ec_lock_down(&master->ext_queue_sem);
+
     list_for_each_entry_safe(datagram, next, &master->ext_datagram_queue,
             queue) {
         list_del(&datagram->queue);
         ec_master_queue_datagram(master, datagram);
     }
-
-    ecrt_master_send(master);
+    ec_lock_up(&master->ext_queue_sem);
+
+    return ecrt_master_send(master);
 }
 
 /*****************************************************************************/
@@ -3818,6 +3839,84 @@
 
 /*****************************************************************************/
 
+#ifdef EC_EOE
+
+int ecrt_master_eoe_addif(ec_master_t *master,
+        uint16_t alias, uint16_t posn)
+{
+    ec_eoe_t *eoe;
+    char name[EC_DATAGRAM_NAME_SIZE];
+    int res;
+
+    // check if the name already exists
+    if (alias) {
+        snprintf(name, EC_DATAGRAM_NAME_SIZE, "eoe%ua%u", master->index, alias);
+    } else {
+        snprintf(name, EC_DATAGRAM_NAME_SIZE, "eoe%us%u", master->index, posn);
+    }
+
+    ec_lock_down(&master->master_sem);
+    list_for_each_entry(eoe, &master->eoe_handlers, list) {
+        if ((eoe->slave == NULL) && 
+                (strncmp(name, ec_eoe_name(eoe), EC_DATAGRAM_NAME_SIZE) == 0)) {
+            ec_lock_up(&master->master_sem);
+            return -EADDRINUSE;
+        }
+    }
+    
+    // none found, create one
+    if (!(eoe = kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) {
+        EC_MASTER_ERR(master, "Failed to allocate EoE handler memory!\n");
+        ec_lock_up(&master->master_sem);
+        return -EFAULT;
+    }
+    
+    if ((res = ec_eoe_init(master, eoe, alias, posn))) {
+        EC_MASTER_ERR(master, "Failed to init EoE handler!\n");
+        kfree(eoe);
+        ec_lock_up(&master->master_sem);
+        return res;
+    }
+
+    list_add_tail(&eoe->list, &master->eoe_handlers);
+    ec_lock_up(&master->master_sem);
+    
+    return 0;
+}
+
+/*****************************************************************************/
+
+int ecrt_master_eoe_delif(ec_master_t *master,
+        uint16_t alias, uint16_t posn)
+{
+    ec_eoe_t *eoe;
+    char name[EC_DATAGRAM_NAME_SIZE];
+
+    if (alias) {
+        snprintf(name, EC_DATAGRAM_NAME_SIZE, "eoe%ua%u", master->index, alias);
+    } else {
+        snprintf(name, EC_DATAGRAM_NAME_SIZE, "eoe%us%u", master->index, posn);
+    }
+
+    ec_lock_down(&master->master_sem);
+    list_for_each_entry(eoe, &master->eoe_handlers, list) {
+        if (strncmp(name, ec_eoe_name(eoe), EC_DATAGRAM_NAME_SIZE) == 0) {
+            list_del(&eoe->list);
+            ec_eoe_clear(eoe);
+            kfree(eoe);
+            ec_lock_up(&master->master_sem);
+            return 0;
+        }
+    }
+    ec_lock_up(&master->master_sem);
+    
+    return -EFAULT;
+}
+
+#endif
+
+/*****************************************************************************/
+
 void ecrt_master_reset(ec_master_t *master)
 {
     ec_slave_config_t *sc;
@@ -3864,6 +3963,10 @@
 EXPORT_SYMBOL(ecrt_master_read_idn);
 EXPORT_SYMBOL(ecrt_master_rt_slave_requests);
 EXPORT_SYMBOL(ecrt_master_exec_slave_requests);
+#ifdef EC_EOE
+EXPORT_SYMBOL(ecrt_master_eoe_addif);
+EXPORT_SYMBOL(ecrt_master_eoe_delif);
+#endif
 EXPORT_SYMBOL(ecrt_master_reset);
 
 /** \endcond */
diff --git a/master/master.h b/master/master.h
--- a/master/master.h
+++ b/master/master.h
@@ -372,6 +372,7 @@
         uint16_t);
 void ec_master_output_stats(ec_master_t *);
 #ifdef EC_EOE
+void ec_master_clear_eoe_handler_slaves(ec_master_t *);
 void ec_master_clear_eoe_handlers(ec_master_t *);
 #endif
 void ec_master_slaves_not_available(ec_master_t *);
@@ -410,6 +411,14 @@
 
 extern const unsigned int rate_intervals[EC_RATE_COUNT]; // see master.c
 
+#ifdef EC_EOE
+#define MAX_EOE 32 /**< Maximum number of EOE interfaces that can be
+                     *  defined at startup. */
+extern char *eoe_interfaces[MAX_EOE]; // see module.c
+extern unsigned int eoe_count; // see module.c
+extern int eoe_autocreate; // see module.c
+#endif
+
 /*****************************************************************************/
 
 #endif
diff --git a/master/module.c b/master/module.c
--- a/master/module.c
+++ b/master/module.c
@@ -58,6 +58,11 @@
 static unsigned int master_count; /**< Number of masters. */
 static char *backup_devices[MAX_MASTERS]; /**< Backup devices parameter. */
 static unsigned int backup_count; /**< Number of backup devices. */
+#ifdef EC_EOE
+char *eoe_interfaces[MAX_EOE]; /**< EOE interfaces parameter. */
+unsigned int eoe_count; /**< Number of EOE interfaces. */
+int eoe_autocreate = 1;  /**< Auto-create EOE interfaces. */
+#endif
 static unsigned int debug_level;  /**< Debug level parameter. */
 
 static ec_master_t *masters; /**< Array of masters. */
@@ -83,6 +88,12 @@
 MODULE_PARM_DESC(main_devices, "MAC addresses of main devices");
 module_param_array(backup_devices, charp, &backup_count, S_IRUGO);
 MODULE_PARM_DESC(backup_devices, "MAC addresses of backup devices");
+#ifdef EC_EOE
+module_param_array(eoe_interfaces, charp, &eoe_count, S_IRUGO);
+MODULE_PARM_DESC(eoe_interfaces, "EOE interfaces");
+module_param_named(eoe_autocreate, eoe_autocreate, bool, S_IRUGO);
+MODULE_PARM_DESC(eoe_autocreate, "EOE atuo create mode");
+#endif
 module_param_named(debug_level, debug_level, uint, S_IRUGO);
 MODULE_PARM_DESC(debug_level, "Debug level");
 
@@ -154,7 +165,7 @@
         if (ret)
             goto out_free_masters;
     }
-
+    
     EC_INFO("%u master%s waiting for devices.\n",
             master_count, (master_count == 1 ? "" : "s"));
     return ret;
diff --git a/script/init.d/ethercat.in b/script/init.d/ethercat.in
--- a/script/init.d/ethercat.in
+++ b/script/init.d/ethercat.in
@@ -172,9 +172,26 @@
         done
     fi
 
+    # build EOE interfaces command
+    EOE_INTERFACES_CMD=""
+    for IFACE in ${EOE_INTERFACES}; do
+        if [ -z "${EOE_INTERFACES_CMD}" ]; then
+            EOE_INTERFACES_CMD="eoe_interfaces=${IFACE}"
+        else
+            EOE_INTERFACES_CMD="${EOE_INTERFACES_CMD},${IFACE}"
+        fi
+    done
+    
+    # build EOE auto create command
+    EOE_AUTOCREATE_CMD=""
+    if [ -n "${EOE_AUTOCREATE}" ]; then
+        EOE_AUTOCREATE_CMD="eoe_autocreate=${EOE_AUTOCREATE}"
+    fi
+
     # load master module
     if ! ${MODPROBE} ${MODPROBE_FLAGS} ec_master ${MASTER_ARGS} \
-            main_devices=${DEVICES} backup_devices=${BACKUPS}; then
+            main_devices=${DEVICES} backup_devices=${BACKUPS} \
+            ${EOE_INTERFACES_CMD} ${EOE_AUTOCREATE_CMD}; then
         exit_fail
     fi
 
diff --git a/script/sysconfig/ethercat b/script/sysconfig/ethercat
--- a/script/sysconfig/ethercat
+++ b/script/sysconfig/ethercat
@@ -37,6 +37,35 @@
 #MASTER0_BACKUP=""
 
 #
+# Initial EOE interfaces
+#
+# Specify EOE interface names that need to be configured on initialization and
+# be available regardless of whether the related module is installed.
+#
+# EOE interface names can be specified with either of the following formats:
+#   eoe<MASTER>a<SLAVE_ALIAS>
+#   eoe<MASTER>s<SLAVE_RING_POSITION>
+#
+# Note: it is preferable to use the alias version to ensure the slave is matched
+#   regarless of its ring position.  If multiple slaves share the same alias
+#   the first matching EOE slave will claim it.
+#
+# Separate multiple interfaces with commas
+# e.g.: eoe0s20,eoe0a100
+#
+#EOE_INTERFACES=""
+
+#
+# EOE auto create mode
+#
+# If EOE auto create is true (default) then EOE interfaces will be automatically
+# created as required if a new EOE module is connected.  If it is false
+# then you will need to create EOE interfaces by specifying them under the
+# EOE_INTERFACES key above, or by using the "ethercat eoe_addif" tool.
+#
+#EOE_AUTOCREATE="1"
+
+#
 # Ethernet driver modules to use for EtherCAT operation.
 #
 # Specify a non-empty list of Ethernet drivers, that shall be used for
diff --git a/tool/Command.cpp b/tool/Command.cpp
--- a/tool/Command.cpp
+++ b/tool/Command.cpp
@@ -30,6 +30,7 @@
  ****************************************************************************/
 
 #include <map>
+#include <iostream>
 using namespace std;
 
 #include "Command.h"
@@ -242,6 +243,13 @@
 
 /****************************************************************************/
 
+bool Command::matches(const string &cmd) const
+{
+    return name == cmd;
+}
+
+/****************************************************************************/
+
 bool Command::matchesSubstr(const string &cmd) const
 {
     return name.substr(0, cmd.length()) == cmd;
diff --git a/tool/Command.h b/tool/Command.h
--- a/tool/Command.h
+++ b/tool/Command.h
@@ -87,7 +87,7 @@
         typedef list<unsigned int> MasterIndexList;
         void setMasters(const string &);
         MasterIndexList getMasterIndices() const;
-		unsigned int getSingleMasterIndex() const;
+        unsigned int getSingleMasterIndex() const;
 
         enum Verbosity {
             Quiet,
@@ -122,6 +122,7 @@
         void setSkin(const string &);
         const string &getSkin() const;
 
+        bool matches(const string &) const;
         bool matchesSubstr(const string &) const;
         bool matchesAbbrev(const string &) const;
 
@@ -150,13 +151,14 @@
 
         static string alStateString(uint8_t);
 
+        string aliases;
+        string positions;
+    
     private:
         string name;
         string briefDesc;
         string masters;
         Verbosity verbosity;
-        string aliases;
-        string positions;
         string domains;
         string dataType;
         bool emergency;
diff --git a/tool/CommandEoeAddIf.cpp b/tool/CommandEoeAddIf.cpp
new file mode 100644
--- /dev/null
+++ b/tool/CommandEoeAddIf.cpp
@@ -0,0 +1,130 @@
+/*****************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2009  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.
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+using namespace std;
+
+#include "CommandEoeAddIf.h"
+#include "CommandSlaves.h"
+#include "MasterDevice.h"
+#include "NumberListParser.h"
+
+/*****************************************************************************/
+
+class NumberParser:
+    public NumberListParser
+{
+    public:
+        NumberParser() {};
+
+    protected:
+        int getMax() {
+            return 0;
+        };
+};
+
+/*****************************************************************************/
+
+CommandEoeAddIf::CommandEoeAddIf():
+    Command("eoe_addif", "Add an EOE interface to a master.")
+{
+}
+
+/****************************************************************************/
+
+string CommandEoeAddIf::helpString(const string &binaryBaseName) const
+{
+    stringstream str;
+
+    str << binaryBaseName << " " << getName() << " [OPTIONS]" << endl
+        << endl
+        << getBriefDescription() << endl
+        << endl
+        << "An network interface will be created for the given" << endl
+        << "slave alias / position." << endl
+        << endl
+        << "Command-specific options:" << endl
+        << "  --master   -m <indices>  Master index" << endl
+        << "  --alias    -a <alias>    Slave alias" << endl
+        << "  --position -p <pos>      Slave position" << endl
+        << endl << endl
+        << numericInfo();
+
+    return str.str();
+}
+
+/****************************************************************************/
+
+void CommandEoeAddIf::execute(const StringVector &args)
+{
+    MasterIndexList masterIndices;
+    SlaveList slaves;
+    ec_ioctl_master_t master;
+    uint16_t alias = 0;
+    uint16_t posn = 0;
+    stringstream err;
+
+    if (args.size()) {
+        err << "'" << getName() << "' takes no arguments!";
+        throwInvalidUsageException(err);
+    }
+    
+    MasterDevice m(getSingleMasterIndex());
+    m.open(MasterDevice::ReadWrite);
+    slaves = selectedSlaves(m);
+    
+    m.getMaster(&master);
+
+    // get alias
+    NumberParser ap;
+    NumberListParser::List aliasList = ap.parse(aliases.c_str());
+    
+    // get position
+    NumberParser pp;
+    NumberListParser::List posList = pp.parse(positions.c_str());
+
+    if ( (aliases != "-") && (aliasList.size() == 1) && 
+         (positions == "-") ) {
+        alias = aliasList.front();
+        posn  = 0;
+    } else if ( (aliases == "-") && 
+                (positions != "-") && (posList.size() == 1) ) {
+        alias = 0;
+        posn  = posList.front();
+    } else {
+        stringstream err;
+        err << getName() << " requires a single alias or position!";
+        throwInvalidUsageException(err);
+    }    
+    
+    m.addEoeIf(alias, posn);
+}
+
+/*****************************************************************************/
diff --git a/tool/CommandEoeAddIf.h b/tool/CommandEoeAddIf.h
new file mode 100644
--- /dev/null
+++ b/tool/CommandEoeAddIf.h
@@ -0,0 +1,49 @@
+/*****************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2009  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.
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDEOEADDIF_H__
+#define __COMMANDEOEADDIF_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandEoeAddIf:
+    public Command
+{
+    public:
+        CommandEoeAddIf();
+
+        string helpString(const string &) const;
+        void execute(const StringVector &);
+};
+
+/****************************************************************************/
+
+#endif
diff --git a/tool/CommandEoeDelIf.cpp b/tool/CommandEoeDelIf.cpp
new file mode 100644
--- /dev/null
+++ b/tool/CommandEoeDelIf.cpp
@@ -0,0 +1,130 @@
+/*****************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2009  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.
+ *
+ ****************************************************************************/
+
+#include <iostream>
+#include <iomanip>
+using namespace std;
+
+#include "CommandEoeDelIf.h"
+#include "CommandSlaves.h"
+#include "MasterDevice.h"
+#include "NumberListParser.h"
+
+/*****************************************************************************/
+
+class NumberParser:
+    public NumberListParser
+{
+    public:
+        NumberParser() {};
+
+    protected:
+        int getMax() {
+            return 0;
+        };
+};
+
+/*****************************************************************************/
+
+CommandEoeDelIf::CommandEoeDelIf():
+    Command("eoe_delif", "Add an EOE interface to a master.")
+{
+}
+
+/****************************************************************************/
+
+string CommandEoeDelIf::helpString(const string &binaryBaseName) const
+{
+    stringstream str;
+
+    str << binaryBaseName << " " << getName() << " [OPTIONS]" << endl
+        << endl
+        << getBriefDescription() << endl
+        << endl
+        << "Delete an EOE network interface for the given" << endl
+        << "slave alias / position." << endl
+        << endl
+        << "Command-specific options:" << endl
+        << "  --master   -m <indices>  Master index" << endl
+        << "  --alias    -a <alias>    Slave alias" << endl
+        << "  --position -p <pos>      Slave position" << endl
+        << endl << endl
+        << numericInfo();
+
+    return str.str();
+}
+
+/****************************************************************************/
+
+void CommandEoeDelIf::execute(const StringVector &args)
+{
+    MasterIndexList masterIndices;
+    SlaveList slaves;
+    ec_ioctl_master_t master;
+    uint16_t alias = 0;
+    uint16_t posn = 0;
+    stringstream err;
+
+    if (args.size()) {
+        err << "'" << getName() << "' takes no arguments!";
+        throwInvalidUsageException(err);
+    }
+    
+    MasterDevice m(getSingleMasterIndex());
+    m.open(MasterDevice::ReadWrite);
+    slaves = selectedSlaves(m);
+    
+    m.getMaster(&master);
+
+    // get alias
+    NumberParser ap;
+    NumberListParser::List aliasList = ap.parse(aliases.c_str());
+    
+    // get position
+    NumberParser pp;
+    NumberListParser::List posList = pp.parse(positions.c_str());
+
+    if ( (aliases != "-") && (aliasList.size() == 1) && 
+         (positions == "-") ) {
+        alias = aliasList.front();
+        posn  = 0;
+    } else if ( (aliases == "-") && 
+                (positions != "-") && (posList.size() == 1) ) {
+        alias = 0;
+        posn  = posList.front();
+    } else {
+        stringstream err;
+        err << getName() << " requires a single alias or position!";
+        throwInvalidUsageException(err);
+    }    
+    
+    m.delEoeIf(alias, posn);
+}
+
+/*****************************************************************************/
diff --git a/tool/CommandEoeDelIf.h b/tool/CommandEoeDelIf.h
new file mode 100644
--- /dev/null
+++ b/tool/CommandEoeDelIf.h
@@ -0,0 +1,49 @@
+/*****************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2009  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.
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDEOEDELIF_H__
+#define __COMMANDEOEDELIF_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandEoeDelIf:
+    public Command
+{
+    public:
+        CommandEoeDelIf();
+
+        string helpString(const string &) const;
+        void execute(const StringVector &);
+};
+
+/****************************************************************************/
+
+#endif
diff --git a/tool/Makefile.am b/tool/Makefile.am
--- a/tool/Makefile.am
+++ b/tool/Makefile.am
@@ -78,9 +78,13 @@
 	sii_crc.cpp
 
 if ENABLE_EOE
-ethercat_SOURCES += CommandEoe.cpp
+ethercat_SOURCES += CommandEoe.cpp \
+	CommandEoeAddIf.cpp \
+	CommandEoeDelIf.cpp
 else
-EXTRA_DIST += CommandEoe.cpp
+EXTRA_DIST += CommandEoe.cpp \
+	CommandEoeAddIf.cpp \
+	CommandEoeDelIf.cpp
 endif
 
 noinst_HEADERS = \
@@ -124,9 +128,13 @@
 	sii_crc.h
 
 if ENABLE_EOE
-noinst_HEADERS += CommandEoe.h
+noinst_HEADERS += CommandEoe.h \
+	CommandEoeAddIf.h \
+	CommandEoeDelIf.h
 else
-EXTRA_DIST += CommandEoe.h
+EXTRA_DIST += CommandEoe.h \
+	CommandEoeAddIf.h \
+	CommandEoeDelIf.h
 endif
 
 REV = `if test -s $(top_srcdir)/revision; then \
diff --git a/tool/MasterDevice.cpp b/tool/MasterDevice.cpp
--- a/tool/MasterDevice.cpp
+++ b/tool/MasterDevice.cpp
@@ -615,6 +615,42 @@
     }
 }
 
+/****************************************************************************/
+
+void MasterDevice::addEoeIf(
+        uint16_t alias,
+        uint16_t posn
+        )
+{
+    ec_ioctl_eoe_if_t data;
+    data.alias = alias;
+    data.position = posn;
+
+    if (ioctl(fd, EC_IOCTL_EOE_ADDIF, &data)) {
+        stringstream err;
+        err << "Failed to add EoE interface: " << strerror(errno);
+        throw MasterDeviceException(err);
+    }
+}
+
+/****************************************************************************/
+
+void MasterDevice::delEoeIf(
+        uint16_t alias,
+        uint16_t posn
+        )
+{
+    ec_ioctl_eoe_if_t data;
+    data.alias = alias;
+    data.position = posn;
+
+    if (ioctl(fd, EC_IOCTL_EOE_DELIF, &data)) {
+        stringstream err;
+        err << "Failed to delete EoE interface: " << strerror(errno);
+        throw MasterDeviceException(err);
+    }
+}
+
 #endif
 
 /****************************************************************************/
diff --git a/tool/MasterDevice.h b/tool/MasterDevice.h
--- a/tool/MasterDevice.h
+++ b/tool/MasterDevice.h
@@ -161,6 +161,8 @@
         void writeFoe(ec_ioctl_slave_foe_t *);
 #ifdef EC_EOE
         void getEoeHandler(ec_ioctl_eoe_handler_t *, uint16_t);
+        void addEoeIf(uint16_t, uint16_t);
+        void delEoeIf(uint16_t, uint16_t);
 #endif
         void readSoe(ec_ioctl_slave_soe_read_t *);
         void writeSoe(ec_ioctl_slave_soe_write_t *);
diff --git a/tool/main.cpp b/tool/main.cpp
--- a/tool/main.cpp
+++ b/tool/main.cpp
@@ -45,7 +45,9 @@
 #include "CommandDomains.h"
 #include "CommandDownload.h"
 #ifdef EC_EOE
-# include "CommandEoe.h"
+#include "CommandEoe.h"
+#include "CommandEoeAddIf.h"
+#include "CommandEoeDelIf.h"
 #endif
 #include "CommandFoeRead.h"
 #include "CommandFoeWrite.h"
@@ -256,20 +258,30 @@
     CommandList::iterator ci;
     list<Command *> res;
 
-    // find matching commands from beginning of the string
+    // see if there's an exact match
     for (ci = commandList.begin(); ci != commandList.end(); ci++) {
-        if ((*ci)->matchesSubstr(cmdStr)) {
+        if ((*ci)->matches(cmdStr)) {
             res.push_back(*ci);
+            break;
         }
     }
-
+    
     if (!res.size()) { // nothing found
-        // find /any/ matching commands
+        // find matching commands from beginning of the string
         for (ci = commandList.begin(); ci != commandList.end(); ci++) {
-            if ((*ci)->matchesAbbrev(cmdStr)) {
+            if ((*ci)->matchesSubstr(cmdStr)) {
                 res.push_back(*ci);
             }
         }
+        
+        if (!res.size()) { // nothing found
+            // find /any/ matching commands
+            for (ci = commandList.begin(); ci != commandList.end(); ci++) {
+                if ((*ci)->matchesAbbrev(cmdStr)) {
+                    res.push_back(*ci);
+                }
+            }
+        }
     }
 
     return res;
@@ -297,6 +309,8 @@
     commandList.push_back(new CommandDownload());
 #ifdef EC_EOE
     commandList.push_back(new CommandEoe());
+    commandList.push_back(new CommandEoeAddIf());
+    commandList.push_back(new CommandEoeDelIf());
 #endif
     commandList.push_back(new CommandFoeRead());
     commandList.push_back(new CommandFoeWrite());
