master/master.c
branchstable-1.0
changeset 1619 0d4119024f55
parent 1618 5cff10efb927
child 1621 4bbe090553f7
--- a/master/master.c	Mon Apr 24 10:47:03 2006 +0000
+++ b/master/master.c	Mon May 29 09:08:56 2006 +0000
@@ -8,7 +8,8 @@
  *
  *  The IgH EtherCAT Master is free software; you can redistribute it
  *  and/or modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; version 2 of the License.
+ *  as published by the Free Software Foundation; either version 2 of the
+ *  License, or (at your option) any later version.
  *
  *  The IgH EtherCAT Master is distributed in the hope that it will be
  *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -19,6 +20,15 @@
  *  along with the IgH EtherCAT Master; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
+ *  The right to use EtherCAT Technology is granted and comes free of
+ *  charge under condition of compatibility of product made by
+ *  Licensee. People intending to distribute/sell products based on the
+ *  code, have to sign an agreement to guarantee that products using
+ *  software based on IgH EtherCAT master stay compatible with the actual
+ *  EtherCAT specification (which are released themselves as an open
+ *  standard) as the (only) precondition to have the right to use EtherCAT
+ *  Technology, IP and trade marks.
+ *
  *****************************************************************************/
 
 /**
@@ -45,9 +55,9 @@
 
 /*****************************************************************************/
 
-void ec_master_freerun(unsigned long);
+void ec_master_freerun(void *);
+void ec_master_eoe_run(unsigned long);
 ssize_t ec_show_master_attribute(struct kobject *, struct attribute *, char *);
-void ec_master_process_watch_command(ec_master_t *);
 
 /*****************************************************************************/
 
@@ -83,19 +93,51 @@
 */
 
 int ec_master_init(ec_master_t *master, /**< EtherCAT master */
-                   unsigned int index /**< master index */
+                   unsigned int index, /**< master index */
+                   unsigned int eoe_devices /**< number of EoE devices */
                    )
 {
+    ec_eoe_t *eoe, *next_eoe;
+    unsigned int i;
+
     EC_INFO("Initializing master %i.\n", index);
 
     master->index = index;
     master->device = NULL;
     master->reserved = 0;
-
     INIT_LIST_HEAD(&master->slaves);
     INIT_LIST_HEAD(&master->command_queue);
     INIT_LIST_HEAD(&master->domains);
-    INIT_LIST_HEAD(&master->eoe_slaves);
+    INIT_LIST_HEAD(&master->eoe_handlers);
+    ec_command_init(&master->simple_command);
+    INIT_WORK(&master->freerun_work, ec_master_freerun, (void *) master);
+    init_timer(&master->eoe_timer);
+    master->eoe_timer.function = ec_master_eoe_run;
+    master->eoe_timer.data = (unsigned long) master;
+    master->internal_lock = SPIN_LOCK_UNLOCKED;
+    master->eoe_running = 0;
+
+    // create workqueue
+    if (!(master->workqueue = create_singlethread_workqueue("EtherCAT"))) {
+        EC_ERR("Failed to create master workqueue.\n");
+        goto out_return;
+    }
+
+    // create EoE handlers
+    for (i = 0; i < eoe_devices; i++) {
+        if (!(eoe = (ec_eoe_t *) kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) {
+            EC_ERR("Failed to allocate EoE-Object.\n");
+            goto out_clear_eoe;
+        }
+        if (ec_eoe_init(eoe)) {
+            kfree(eoe);
+            goto out_clear_eoe;
+        }
+        list_add_tail(&eoe->list, &master->eoe_handlers);
+    }
+
+    // create state machine object
+    if (ec_fsm_init(&master->fsm, master)) goto out_clear_eoe;
 
     // init kobject and add it to the hierarchy
     memset(&master->kobj, 0x00, sizeof(struct kobject));
@@ -107,16 +149,18 @@
         return -1;
     }
 
-    // init freerun timer
-    init_timer(&master->freerun_timer);
-    master->freerun_timer.function = ec_master_freerun;
-    master->freerun_timer.data = (unsigned long) master;
-
-    ec_command_init(&master->simple_command);
-    ec_command_init(&master->watch_command);
-
     ec_master_reset(master);
     return 0;
+
+ out_clear_eoe:
+    list_for_each_entry_safe(eoe, next_eoe, &master->eoe_handlers, list) {
+        list_del(&eoe->list);
+        ec_eoe_clear(eoe);
+        kfree(eoe);
+    }
+    destroy_workqueue(master->workqueue);
+ out_return:
+    return -1;
 }
 
 /*****************************************************************************/
@@ -130,21 +174,27 @@
 void ec_master_clear(struct kobject *kobj /**< kobject of the master */)
 {
     ec_master_t *master = container_of(kobj, ec_master_t, kobj);
+    ec_eoe_t *eoe, *next_eoe;
 
     EC_INFO("Clearing master %i...\n", master->index);
 
-    del_timer_sync(&master->freerun_timer);
-
     ec_master_reset(master);
+    ec_fsm_clear(&master->fsm);
+    ec_command_clear(&master->simple_command);
+    destroy_workqueue(master->workqueue);
+
+    // clear EoE objects
+    list_for_each_entry_safe(eoe, next_eoe, &master->eoe_handlers, list) {
+        list_del(&eoe->list);
+        ec_eoe_clear(eoe);
+        kfree(eoe);
+    }
 
     if (master->device) {
         ec_device_clear(master->device);
         kfree(master->device);
     }
 
-    ec_command_clear(&master->simple_command);
-    ec_command_clear(&master->watch_command);
-
     EC_INFO("Master %i cleared.\n", master->index);
 }
 
@@ -158,20 +208,12 @@
 
 void ec_master_reset(ec_master_t *master /**< EtherCAT master */)
 {
-    ec_slave_t *slave, *next_s;
     ec_command_t *command, *next_c;
     ec_domain_t *domain, *next_d;
-    ec_eoe_t *eoe, *next_eoe;
-
+
+    ec_master_eoe_stop(master);
     ec_master_freerun_stop(master);
-
-    // remove all slaves
-    list_for_each_entry_safe(slave, next_s, &master->slaves, list) {
-        list_del(&slave->list);
-        kobject_del(&slave->kobj);
-        kobject_put(&slave->kobj);
-    }
-    master->slave_count = 0;
+    ec_master_clear_slaves(master);
 
     // empty command queue
     list_for_each_entry_safe(command, next_c, &master->command_queue, queue) {
@@ -186,28 +228,41 @@
         kobject_put(&domain->kobj);
     }
 
-    // clear EoE objects
-    list_for_each_entry_safe(eoe, next_eoe, &master->eoe_slaves, list) {
-        list_del(&eoe->list);
-        ec_eoe_clear(eoe);
-        kfree(eoe);
-    }
-
     master->command_index = 0;
     master->debug_level = 0;
     master->timeout = 500; // 500us
 
-    master->slaves_responding = 0;
-    master->slave_states = EC_SLAVE_STATE_UNKNOWN;
-
     master->stats.timeouts = 0;
     master->stats.delayed = 0;
     master->stats.corrupted = 0;
     master->stats.unmatched = 0;
-    master->stats.eoe_errors = 0;
     master->stats.t_last = 0;
 
     master->mode = EC_MASTER_MODE_IDLE;
+
+    master->request_cb = NULL;
+    master->release_cb = NULL;
+    master->cb_data = NULL;
+
+    ec_fsm_reset(&master->fsm);
+}
+
+/*****************************************************************************/
+
+/**
+   Clears all slaves.
+*/
+
+void ec_master_clear_slaves(ec_master_t *master)
+{
+    ec_slave_t *slave, *next_slave;
+
+    list_for_each_entry_safe(slave, next_slave, &master->slaves, list) {
+        list_del(&slave->list);
+        kobject_del(&slave->kobj);
+        kobject_put(&slave->kobj);
+    }
+    master->slave_count = 0;
 }
 
 /*****************************************************************************/
@@ -249,15 +304,14 @@
     size_t command_size;
     uint8_t *frame_data, *cur_data;
     void *follows_word;
-    cycles_t start = 0, end;
+    cycles_t t_start, t_end;
     unsigned int frame_count, more_commands_waiting;
 
     frame_count = 0;
-
-    if (unlikely(master->debug_level > 0)) {
+    t_start = get_cycles();
+
+    if (unlikely(master->debug_level > 0))
         EC_DBG("ec_master_send_commands\n");
-        start = get_cycles();
-    }
 
     do {
         // fetch pointer to transmit socket buffer
@@ -273,12 +327,13 @@
             // does the current command fit in the frame?
             command_size = EC_COMMAND_HEADER_SIZE + command->data_size
                 + EC_COMMAND_FOOTER_SIZE;
-            if (cur_data - frame_data + command_size > EC_MAX_FRAME_SIZE) {
+            if (cur_data - frame_data + command_size > ETH_DATA_LEN) {
                 more_commands_waiting = 1;
                 break;
             }
 
             command->state = EC_CMD_SENT;
+            command->t_sent = t_start;
             command->index = master->command_index++;
 
             if (unlikely(master->debug_level > 0))
@@ -317,7 +372,7 @@
                                    - EC_FRAME_HEADER_SIZE) & 0x7FF) | 0x1000);
 
         // pad frame
-        while (cur_data - frame_data < EC_MIN_FRAME_SIZE)
+        while (cur_data - frame_data < ETH_ZLEN - ETH_HLEN)
             EC_WRITE_U8(cur_data++, 0x00);
 
         if (unlikely(master->debug_level > 0))
@@ -330,9 +385,9 @@
     while (more_commands_waiting);
 
     if (unlikely(master->debug_level > 0)) {
-        end = get_cycles();
+        t_end = get_cycles();
         EC_DBG("ec_master_send_commands sent %i frames in %ius.\n",
-               frame_count, (u32) (end - start) * 1000 / cpu_khz);
+               frame_count, (u32) (t_end - t_start) * 1000 / cpu_khz);
     }
 }
 
@@ -477,11 +532,10 @@
 
 int ec_master_bus_scan(ec_master_t *master /**< EtherCAT master */)
 {
-    ec_slave_t *slave, *next;
+    ec_slave_t *slave;
     ec_slave_ident_t *ident;
+    ec_command_t *command;
     unsigned int i;
-    ec_command_t *command;
-    ec_eoe_t *eoe;
     uint16_t coupler_index, coupler_subindex;
     uint16_t reverse_coupler_index, current_coupler_index;
 
@@ -502,7 +556,8 @@
 
     // init slaves
     for (i = 0; i < master->slave_count; i++) {
-        if (!(slave = (ec_slave_t *) kmalloc(sizeof(ec_slave_t), GFP_KERNEL))) {
+        if (!(slave =
+              (ec_slave_t *) kmalloc(sizeof(ec_slave_t), GFP_KERNEL))) {
             EC_ERR("Failed to allocate slave %i!\n", i);
             goto out_free;
         }
@@ -553,7 +608,7 @@
         if (!slave->type) {
             EC_WARN("Unknown slave device (vendor 0x%08X, code 0x%08X) at"
                     " position %i.\n", slave->sii_vendor_id,
-                    slave->sii_product_code, i);
+                    slave->sii_product_code, slave->ring_position);
         }
         else if (slave->type->special == EC_TYPE_BUS_COUPLER) {
             if (slave->sii_alias)
@@ -566,27 +621,12 @@
         slave->coupler_index = current_coupler_index;
         slave->coupler_subindex = coupler_subindex;
         coupler_subindex++;
-
-        // does the slave support EoE?
-        if (slave->sii_mailbox_protocols & EC_MBOX_EOE) {
-            if (!(eoe = (ec_eoe_t *) kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) {
-                EC_ERR("Failed to allocate EoE-Object.\n");
-                goto out_free;
-            }
-
-            ec_eoe_init(eoe, slave);
-            list_add_tail(&eoe->list, &master->eoe_slaves);
-        }
     }
 
     return 0;
 
  out_free:
-    list_for_each_entry_safe(slave, next, &master->slaves, list) {
-        list_del(&slave->list);
-        kobject_del(&slave->kobj);
-        kobject_put(&slave->kobj);
-    }
+    ec_master_clear_slaves(master);
     return -1;
 }
 
@@ -619,10 +659,6 @@
             EC_WARN("%i command(s) UNMATCHED!\n", master->stats.unmatched);
             master->stats.unmatched = 0;
         }
-        if (master->stats.eoe_errors) {
-            EC_WARN("%i EOE ERROR(S)!\n", master->stats.eoe_errors);
-            master->stats.eoe_errors = 0;
-        }
         master->stats.t_last = t_now;
     }
 }
@@ -645,18 +681,8 @@
     EC_INFO("Starting Free-Run mode.\n");
 
     master->mode = EC_MASTER_MODE_FREERUN;
-
-    if (master->watch_command.state == EC_CMD_INIT) {
-        if (ec_command_brd(&master->watch_command, 0x130, 2)) {
-            EC_ERR("Failed to allocate watchdog command!\n");
-            return;
-        }
-    }
-
-    ecrt_master_prepare_async_io(master);
-
-    master->freerun_timer.expires = jiffies + 10;
-    add_timer(&master->freerun_timer);
+    ec_fsm_reset(&master->fsm);
+    queue_delayed_work(master->workqueue, &master->freerun_work, 1);
 }
 
 /*****************************************************************************/
@@ -669,9 +695,15 @@
 {
     if (master->mode != EC_MASTER_MODE_FREERUN) return;
 
+    ec_master_eoe_stop(master);
+
     EC_INFO("Stopping Free-Run mode.\n");
 
-    del_timer_sync(&master->freerun_timer);
+    if (!cancel_delayed_work(&master->freerun_work)) {
+        flush_workqueue(master->workqueue);
+    }
+
+    ec_master_clear_slaves(master);
     master->mode = EC_MASTER_MODE_IDLE;
 }
 
@@ -681,22 +713,24 @@
    Free-Run mode function.
 */
 
-void ec_master_freerun(unsigned long data /**< private timer data = master */)
+void ec_master_freerun(void *data /**< master pointer */)
 {
     ec_master_t *master = (ec_master_t *) data;
 
+    // aquire master lock
+    spin_lock_bh(&master->internal_lock);
+
     ecrt_master_async_receive(master);
 
-    // watchdog command
-    ec_master_process_watch_command(master);
-    ec_master_queue_command(master, &master->watch_command);
-
-    master->slave_count = master->watch_command.working_counter;
+    // execute master state machine
+    ec_fsm_execute(&master->fsm);
 
     ecrt_master_async_send(master);
 
-    master->freerun_timer.expires += HZ;
-    add_timer(&master->freerun_timer);
+    // release master lock
+    spin_unlock_bh(&master->internal_lock);
+
+    queue_delayed_work(master->workqueue, &master->freerun_work, 1);
 }
 
 /*****************************************************************************/
@@ -791,63 +825,139 @@
 /*****************************************************************************/
 
 /**
-   Processes the watchdog command.
-*/
-
-void ec_master_process_watch_command(ec_master_t *master
-                                     /**< EtherCAT master */
-                                     )
-{
-    unsigned int first;
-
-    if (unlikely(master->watch_command.state == EC_CMD_INIT)) return;
-
-    first = 1;
-
-    if (master->watch_command.working_counter != master->slaves_responding ||
-        master->watch_command.data[0] != master->slave_states)
-    {
-        master->slaves_responding = master->watch_command.working_counter;
-        master->slave_states = master->watch_command.data[0];
-
-        EC_INFO("%i slave%s responding (", master->slaves_responding,
-                master->slaves_responding == 1 ? "" : "s");
-
-        if (master->slave_states & EC_SLAVE_STATE_INIT) {
-            printk("INIT");
-            first = 0;
-        }
-        if (master->slave_states & EC_SLAVE_STATE_PREOP) {
-            if (!first) printk(", ");
-            printk("PREOP");
-            first = 0;
-        }
-        if (master->slave_states & EC_SLAVE_STATE_SAVEOP) {
-            if (!first) printk(", ");
-            printk("SAVEOP");
-            first = 0;
-        }
-        if (master->slave_states & EC_SLAVE_STATE_OP) {
-            if (!first) printk(", ");
-            printk("OP");
-        }
-        printk(")\n");
-    }
-}
-
-/*****************************************************************************/
-
+   Starts Ethernet-over-EtherCAT processing for all EoE-capable slaves.
+*/
+
+void ec_master_eoe_start(ec_master_t *master /**< EtherCAT master */)
+{
+    ec_eoe_t *eoe;
+    ec_slave_t *slave;
+    unsigned int coupled, found;
+
+    if (master->eoe_running) return;
+
+    // decouple all EoE handlers
+    list_for_each_entry(eoe, &master->eoe_handlers, list)
+        eoe->slave = NULL;
+    coupled = 0;
+
+    // couple a free EoE handler to every EoE-capable slave
+    list_for_each_entry(slave, &master->slaves, list) {
+        if (!(slave->sii_mailbox_protocols & EC_MBOX_EOE)) continue;
+
+        found = 0;
+        list_for_each_entry(eoe, &master->eoe_handlers, list) {
+            if (eoe->slave) continue;
+            eoe->slave = slave;
+            found = 1;
+            coupled++;
+            EC_INFO("Coupling device %s to slave %i.\n",
+                    eoe->dev->name, slave->ring_position);
+            if (eoe->opened) {
+                slave->requested_state = EC_SLAVE_STATE_OP;
+            }
+            else {
+                slave->requested_state = EC_SLAVE_STATE_INIT;
+            }
+            slave->state_error = 0;
+            break;
+        }
+
+        if (!found) {
+            EC_WARN("No EoE handler for slave %i!\n", slave->ring_position);
+            slave->requested_state = EC_SLAVE_STATE_INIT;
+            slave->state_error = 0;
+        }
+    }
+
+    if (!coupled) {
+        EC_INFO("No EoE handlers coupled.\n");
+        return;
+    }
+
+    EC_INFO("Starting EoE processing.\n");
+    master->eoe_running = 1;
+
+    // start EoE processing
+    master->eoe_timer.expires = jiffies + 10;
+    add_timer(&master->eoe_timer);
+    return;
+}
+
+/*****************************************************************************/
+
+/**
+   Stops the Ethernet-over-EtherCAT processing.
+*/
+
+void ec_master_eoe_stop(ec_master_t *master /**< EtherCAT master */)
+{
+    ec_eoe_t *eoe;
+
+    if (!master->eoe_running) return;
+
+    EC_INFO("Stopping EoE processing.\n");
+
+    del_timer_sync(&master->eoe_timer);
+
+    // decouple all EoE handlers
+    list_for_each_entry(eoe, &master->eoe_handlers, list) {
+        if (eoe->slave) {
+            eoe->slave->requested_state = EC_SLAVE_STATE_INIT;
+            eoe->slave->state_error = 0;
+            eoe->slave = NULL;
+        }
+    }
+
+    master->eoe_running = 0;
+}
+
+/*****************************************************************************/
 /**
    Does the Ethernet-over-EtherCAT processing.
 */
 
-void ec_master_run_eoe(ec_master_t *master /**< EtherCAT master */)
-{
+void ec_master_eoe_run(unsigned long data /**< master pointer */)
+{
+    ec_master_t *master = (ec_master_t *) data;
     ec_eoe_t *eoe;
-
-    list_for_each_entry(eoe, &master->eoe_slaves, list) {
+    unsigned int active = 0;
+
+    list_for_each_entry(eoe, &master->eoe_handlers, list) {
+        if (ec_eoe_active(eoe)) active++;
+    }
+    if (!active) goto queue_timer;
+
+    // aquire master lock...
+    if (master->mode == EC_MASTER_MODE_RUNNING) {
+        // request_cb must return 0, if the lock has been aquired!
+        if (master->request_cb(master->cb_data))
+            goto queue_timer;
+    }
+    else if (master->mode == EC_MASTER_MODE_FREERUN) {
+        spin_lock(&master->internal_lock);
+    }
+    else
+        goto queue_timer;
+
+    // actual EoE stuff
+    ecrt_master_async_receive(master);
+    list_for_each_entry(eoe, &master->eoe_handlers, list) {
         ec_eoe_run(eoe);
     }
+    ecrt_master_async_send(master);
+
+    // release lock...
+    if (master->mode == EC_MASTER_MODE_RUNNING) {
+        master->release_cb(master->cb_data);
+    }
+    else if (master->mode == EC_MASTER_MODE_FREERUN) {
+        spin_unlock(&master->internal_lock);
+    }
+
+ queue_timer:
+    master->eoe_timer.expires += HZ / EC_EOE_FREQUENCY;
+    add_timer(&master->eoe_timer);
 }
 
 /******************************************************************************
@@ -920,13 +1030,6 @@
 
     command = &master->simple_command;
 
-    if (master->watch_command.state == EC_CMD_INIT) {
-        if (ec_command_brd(&master->watch_command, 0x130, 2)) {
-            EC_ERR("Failed to allocate watchdog command!\n");
-            return -1;
-        }
-    }
-
     // allocate all domains
     domain_offset = 0;
     list_for_each_entry(domain, &master->domains, list) {
@@ -1080,9 +1183,6 @@
             return -1;
     }
 
-    master->slaves_responding = 0;
-    master->slave_states = EC_SLAVE_STATE_INIT;
-
     return 0;
 }
 
@@ -1223,26 +1323,32 @@
 void ecrt_master_async_receive(ec_master_t *master /**< EtherCAT master */)
 {
     ec_command_t *command, *next;
+    cycles_t t_received, t_timeout;
 
     ec_device_call_isr(master->device);
 
+    t_received = get_cycles();
+    t_timeout = (cycles_t) master->timeout * (cpu_khz / 1000);
+
     // dequeue all received commands
     list_for_each_entry_safe(command, next, &master->command_queue, queue)
         if (command->state == EC_CMD_RECEIVED) list_del_init(&command->queue);
 
-    // dequeue all remaining commands
+    // dequeue all commands that timed out
     list_for_each_entry_safe(command, next, &master->command_queue, queue) {
         switch (command->state) {
             case EC_CMD_SENT:
             case EC_CMD_QUEUED:
-                command->state = EC_CMD_TIMEOUT;
-                master->stats.timeouts++;
-                ec_master_output_stats(master);
+                if (t_received - command->t_sent > t_timeout) {
+                    list_del_init(&command->queue);
+                    command->state = EC_CMD_TIMEOUT;
+                    master->stats.timeouts++;
+                    ec_master_output_stats(master);
+                }
                 break;
             default:
                 break;
         }
-        list_del_init(&command->queue);
     }
 }
 
@@ -1288,12 +1394,8 @@
     // output statistics
     ec_master_output_stats(master);
 
-    // watchdog command
-    ec_master_process_watch_command(master);
-    ec_master_queue_command(master, &master->watch_command);
-
-    // Ethernet-over-EtherCAT
-    ec_master_run_eoe(master);
+    // execute master state machine
+    ec_fsm_execute(&master->fsm);
 }
 
 /*****************************************************************************/
@@ -1407,6 +1509,45 @@
 /*****************************************************************************/
 
 /**
+   Sets the locking callbacks.
+   The request_cb function must return zero, to allow another instance
+   (the EoE process for example) to access the master. Non-zero means,
+   that access is forbidden at this time.
+   \ingroup RealtimeInterface
+*/
+
+void ecrt_master_callbacks(ec_master_t *master, /**< EtherCAT master */
+                           int (*request_cb)(void *), /**< request lock CB */
+                           void (*release_cb)(void *), /**< release lock CB */
+                           void *cb_data /**< data parameter */
+                           )
+{
+    master->request_cb = request_cb;
+    master->release_cb = release_cb;
+    master->cb_data = cb_data;
+}
+
+/*****************************************************************************/
+
+/**
+   Starts Ethernet-over-EtherCAT processing for all EoE-capable slaves.
+   \ingroup RealtimeInterface
+*/
+
+int ecrt_master_start_eoe(ec_master_t *master /**< EtherCAT master */)
+{
+    if (!master->request_cb || !master->release_cb) {
+        EC_ERR("EoE requires master callbacks to be set!\n");
+        return -1;
+    }
+
+    ec_master_eoe_start(master);
+    return 0;
+}
+
+/*****************************************************************************/
+
+/**
    Sets the debug level of the master.
    The following levels are valid:
    - 1: only output positions marks and basic data
@@ -1448,9 +1589,9 @@
         list_for_each_entry(slave, &master->slaves, list)
             ec_slave_print(slave, verbosity);
     }
-    if (!list_empty(&master->eoe_slaves)) {
+    if (!list_empty(&master->eoe_handlers)) {
         EC_INFO("Ethernet-over-EtherCAT (EoE) objects:\n");
-        list_for_each_entry(eoe, &master->eoe_slaves, list) {
+        list_for_each_entry(eoe, &master->eoe_handlers, list) {
             ec_eoe_print(eoe);
         }
     }
@@ -1470,6 +1611,8 @@
 EXPORT_SYMBOL(ecrt_master_async_send);
 EXPORT_SYMBOL(ecrt_master_async_receive);
 EXPORT_SYMBOL(ecrt_master_run);
+EXPORT_SYMBOL(ecrt_master_callbacks);
+EXPORT_SYMBOL(ecrt_master_start_eoe);
 EXPORT_SYMBOL(ecrt_master_debug);
 EXPORT_SYMBOL(ecrt_master_print);
 EXPORT_SYMBOL(ecrt_master_get_slave);