Improved the callback mechanism.
authorFlorian Pose <fp@igh-essen.com>
Mon, 13 Jul 2009 15:18:28 +0000
changeset 1500 ed1a733efbc5
parent 1499 5461fce4a2ea
child 1501 59990318c95b
Improved the callback mechanism.
NEWS
TODO
examples/dc_rtai/dc_rtai_sample.c
examples/mini/mini.c
examples/rtai/rtai_sample.c
include/ecrt.h
master/cdev.c
master/ethernet.c
master/master.c
master/master.h
--- a/NEWS	Fri Jul 10 10:40:05 2009 +0000
+++ b/NEWS	Mon Jul 13 15:18:28 2009 +0000
@@ -12,6 +12,10 @@
   library is licensed under LGPLv2.
 * Added distributed clocks support.
 * Added VoE mailbox protocol support.
+* Improved the callback mechanism. ecrt_master_callbacks() now takes two
+  callback functions for sending and receiving datagrams.
+  ecrt_master_send_ext() is used to execute the sending of non-application
+  datagrams.
 * Separated datagram initialization from filling the payload with zeros.
   Introduced new method ec_datagram_zero() for that.
 * Added phy_read and phy_write commands to ethercat tool.
--- a/TODO	Fri Jul 10 10:40:05 2009 +0000
+++ b/TODO	Mon Jul 13 15:18:28 2009 +0000
@@ -24,8 +24,6 @@
 * Remove byte-swapping functions from user space.
 * EoE:
     - Only execute one EoE handler per cycle.
-    - Replace locking callbacks.
-    - Allow EoE with userspace application.
 * Implement 'ethercat foe_read --output-file ...'.
 * Fix unloading problem of ec_e100 driver.
 * Use ec_datagram_zero() where possible.
@@ -41,7 +39,6 @@
 * Remove ecrt_domain_state()?
 * Check force_config flag before error.
 * Remove allow_scanning flag.
-* Implement ecrt_master_slave() in kernel space.
 * Check for ioctl() interface version.
 * Improve application-triggered SDO transfers by moving the state machine into
   the SDO handlers.
--- a/examples/dc_rtai/dc_rtai_sample.c	Fri Jul 10 10:40:05 2009 +0000
+++ b/examples/dc_rtai/dc_rtai_sample.c	Mon Jul 13 15:18:28 2009 +0000
@@ -58,7 +58,6 @@
 // EtherCAT
 static ec_master_t *master = NULL;
 static ec_master_state_t master_state = {};
-spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
 
 static ec_domain_t *domain1 = NULL;
 static ec_domain_state_t domain1_state = {};
@@ -125,9 +124,9 @@
 {
     ec_domain_state_t ds;
 
-    spin_lock(&master_lock);
+    rt_sem_wait(&master_sem);
     ecrt_domain_state(domain1, &ds);
-    spin_unlock(&master_lock);
+    rt_sem_signal(&master_sem);
 
     if (ds.working_counter != domain1_state.working_counter)
         printk(KERN_INFO PFX "Domain1: WC %u.\n", ds.working_counter);
@@ -143,9 +142,9 @@
 {
     ec_master_state_t ms;
 
-    spin_lock(&master_lock);
+    rt_sem_wait(&master_sem);
     ecrt_master_state(master, &ms);
-    spin_unlock(&master_lock);
+    rt_sem_signal(&master_sem);
 
     if (ms.slaves_responding != master_state.slaves_responding)
         printk(KERN_INFO PFX "%u slave(s).\n", ms.slaves_responding);
@@ -239,21 +238,26 @@
 
 /*****************************************************************************/
 
-int request_lock(void *data)
+void send_callback(ec_master_t *master)
 {
     // too close to the next real time cycle: deny access...
-    if (get_cycles() - t_last_cycle > t_critical) return -1;
-
-    // allow access
-    rt_sem_wait(&master_sem);
-    return 0;
-}
-
-/*****************************************************************************/
-
-void release_lock(void *data)
-{
-    rt_sem_signal(&master_sem);
+    if (get_cycles() - t_last_cycle <= t_critical) {
+        rt_sem_wait(&master_sem);
+        ecrt_master_send_ext(master);
+        rt_sem_signal(&master_sem);
+    }
+}
+
+/*****************************************************************************/
+
+void receive_callback(ec_master_t *master)
+{
+    // too close to the next real time cycle: deny access...
+    if (get_cycles() - t_last_cycle <= t_critical) {
+        rt_sem_wait(&master_sem);
+        ecrt_master_receive(master);
+        rt_sem_signal(&master_sem);
+    }
 }
 
 /*****************************************************************************/
@@ -277,7 +281,7 @@
         goto out_return;
     }
 
-    ecrt_master_callbacks(master, request_lock, release_lock, NULL);
+    ecrt_master_callbacks(master, send_callback, receive_callback);
 
     printk(KERN_INFO PFX "Registering domain...\n");
     if (!(domain1 = ecrt_master_create_domain(master))) {
--- a/examples/mini/mini.c	Fri Jul 10 10:40:05 2009 +0000
+++ b/examples/mini/mini.c	Mon Jul 13 15:18:28 2009 +0000
@@ -29,7 +29,7 @@
 
 #include <linux/module.h>
 #include <linux/timer.h>
-#include <linux/spinlock.h>
+#include <linux/semaphore.h>
 #include <linux/interrupt.h>
 #include <linux/err.h>
 
@@ -54,7 +54,7 @@
 // EtherCAT
 static ec_master_t *master = NULL;
 static ec_master_state_t master_state = {};
-spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
+struct semaphore master_sem;
 
 static ec_domain_t *domain1 = NULL;
 static ec_domain_state_t domain1_state = {};
@@ -192,9 +192,9 @@
 {
     ec_domain_state_t ds;
 
-    spin_lock(&master_lock);
+    down(&master_sem);
     ecrt_domain_state(domain1, &ds);
-    spin_unlock(&master_lock);
+    up(&master_sem);
 
     if (ds.working_counter != domain1_state.working_counter)
         printk(KERN_INFO PFX "Domain1: WC %u.\n", ds.working_counter);
@@ -210,9 +210,9 @@
 {
     ec_master_state_t ms;
 
-    spin_lock(&master_lock);
+    down(&master_sem);
     ecrt_master_state(master, &ms);
-    spin_unlock(&master_lock);
+    up(&master_sem);
 
     if (ms.slaves_responding != master_state.slaves_responding)
         printk(KERN_INFO PFX "%u slave(s).\n", ms.slaves_responding);
@@ -230,9 +230,9 @@
 {
     ec_slave_config_state_t s;
 
-    spin_lock(&master_lock);
+    down(&master_sem);
     ecrt_slave_config_state(sc_ana_in, &s);
-    spin_unlock(&master_lock);
+    up(&master_sem);
 
     if (s.al_state != sc_ana_in_state.al_state)
         printk(KERN_INFO PFX "AnaIn: State 0x%02X.\n", s.al_state);
@@ -300,10 +300,10 @@
 void cyclic_task(unsigned long data)
 {
     // receive process data
-    spin_lock(&master_lock);
+    down(&master_sem);
     ecrt_master_receive(master);
     ecrt_domain_process(domain1);
-    spin_unlock(&master_lock);
+    up(&master_sem);
 
     // check process data state (optional)
     check_domain1_state();
@@ -336,10 +336,10 @@
     EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x06 : 0x09);
 
     // send process data
-    spin_lock(&master_lock);
+    down(&master_sem);
     ecrt_domain_queue(domain1);
     ecrt_master_send(master);
-    spin_unlock(&master_lock);
+    up(&master_sem);
 
     // restart timer
     timer.expires += HZ / FREQUENCY;
@@ -348,17 +348,20 @@
 
 /*****************************************************************************/
 
-int request_lock(void *data)
-{
-    spin_lock(&master_lock);
-    return 0; // access allowed
-}
-
-/*****************************************************************************/
-
-void release_lock(void *data)
-{
-    spin_unlock(&master_lock);
+void send_callback(ec_master_t *master)
+{
+    down(&master_sem);
+    ecrt_master_send_ext(master);
+    up(&master_sem);
+}
+
+/*****************************************************************************/
+
+void receive_callback(ec_master_t *master)
+{
+    down(&master_sem);
+    ecrt_master_receive(master);
+    up(&master_sem);
 }
 
 /*****************************************************************************/
@@ -382,7 +385,8 @@
         goto out_return;
     }
 
-    ecrt_master_callbacks(master, request_lock, release_lock, NULL);
+    init_MUTEX(&master_sem);
+    ecrt_master_callbacks(master, send_callback, receive_callback);
 
     printk(KERN_INFO PFX "Registering domain...\n");
     if (!(domain1 = ecrt_master_create_domain(master))) {
--- a/examples/rtai/rtai_sample.c	Fri Jul 10 10:40:05 2009 +0000
+++ b/examples/rtai/rtai_sample.c	Mon Jul 13 15:18:28 2009 +0000
@@ -59,7 +59,6 @@
 // EtherCAT
 static ec_master_t *master = NULL;
 static ec_master_state_t master_state = {};
-spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
 
 static ec_domain_t *domain1 = NULL;
 static ec_domain_state_t domain1_state = {};
@@ -146,9 +145,9 @@
 {
     ec_domain_state_t ds;
 
-    spin_lock(&master_lock);
+    rt_sem_wait(&master_sem);
     ecrt_domain_state(domain1, &ds);
-    spin_unlock(&master_lock);
+    rt_sem_signal(&master_sem);
 
     if (ds.working_counter != domain1_state.working_counter)
         printk(KERN_INFO PFX "Domain1: WC %u.\n", ds.working_counter);
@@ -164,9 +163,9 @@
 {
     ec_master_state_t ms;
 
-    spin_lock(&master_lock);
+    rt_sem_wait(&master_sem);
     ecrt_master_state(master, &ms);
-    spin_unlock(&master_lock);
+    rt_sem_signal(&master_sem);
 
     if (ms.slaves_responding != master_state.slaves_responding)
         printk(KERN_INFO PFX "%u slave(s).\n", ms.slaves_responding);
@@ -184,9 +183,9 @@
 {
     ec_slave_config_state_t s;
 
-    spin_lock(&master_lock);
+    rt_sem_wait(&master_sem);
     ecrt_slave_config_state(sc_ana_in, &s);
-    spin_unlock(&master_lock);
+    rt_sem_signal(&master_sem);
 
     if (s.al_state != sc_ana_in_state.al_state)
         printk(KERN_INFO PFX "AnaIn: State 0x%02X.\n", s.al_state);
@@ -244,21 +243,26 @@
 
 /*****************************************************************************/
 
-int request_lock(void *data)
+void send_callback(ec_master_t *master)
 {
     // too close to the next real time cycle: deny access...
-    if (get_cycles() - t_last_cycle > t_critical) return -1;
-
-    // allow access
-    rt_sem_wait(&master_sem);
-    return 0;
-}
-
-/*****************************************************************************/
-
-void release_lock(void *data)
-{
-    rt_sem_signal(&master_sem);
+    if (get_cycles() - t_last_cycle <= t_critical) {
+        rt_sem_wait(&master_sem);
+        ecrt_master_send_ext(master);
+        rt_sem_signal(&master_sem);
+    }
+}
+
+/*****************************************************************************/
+
+void receive_callback(ec_master_t *master)
+{
+    // too close to the next real time cycle: deny access...
+    if (get_cycles() - t_last_cycle <= t_critical) {
+        rt_sem_wait(&master_sem);
+        ecrt_master_receive(master);
+        rt_sem_signal(&master_sem);
+    }
 }
 
 /*****************************************************************************/
@@ -277,7 +281,6 @@
 
     t_critical = cpu_khz * 1000 / FREQUENCY - cpu_khz * INHIBIT_TIME / 1000;
 
-
     master = ecrt_request_master(0);
     if (IS_ERR(master)) {
         ret = PTR_ERR(master); 
@@ -285,7 +288,7 @@
         goto out_return;
     }
 
-    ecrt_master_callbacks(master, request_lock, release_lock, NULL);
+    ecrt_master_callbacks(master, send_callback, receive_callback);
 
     printk(KERN_INFO PFX "Registering domain...\n");
     if (!(domain1 = ecrt_master_create_domain(master))) {
--- a/include/ecrt.h	Fri Jul 10 10:40:05 2009 +0000
+++ b/include/ecrt.h	Mon Jul 13 15:18:28 2009 +0000
@@ -42,24 +42,27 @@
  * Changes in version 1.5:
  *
  * - Added the distributed clocks feature and the respective method
- *   ecrt_slave_config_dc() to configure a slave for cyclic
- *   operation, and ecrt_master_application_time(),
- *   ecrt_master_sync_reference_clock() and  ecrt_master_sync_slave_clocks()
- *   for offset and drift compensation. The EC_TIMEVAL2NANO() macro can be
- *   used for epoch time conversion.
+ *   ecrt_slave_config_dc() to configure a slave for cyclic operation, and
+ *   ecrt_master_application_time(), ecrt_master_sync_reference_clock() and
+ *   ecrt_master_sync_slave_clocks() for offset and drift compensation. The
+ *   EC_TIMEVAL2NANO() macro can be used for epoch time conversion.
+ * - Improved the callback mechanism. ecrt_master_callbacks() now takes two
+ *   callback functions for sending and receiving datagrams.
+ *   ecrt_master_send_ext() is used to execute the sending of non-application
+ *   datagrams.
  * - Added ecrt_open_master() and ecrt_master_reserve() separation for
  *   userspace.
  * - Added ecrt_master() userspace interface, to get information about a
  *   master.
+ * - Added ecrt_master_slave() to get information about a certain slave.
+ * - Added ecrt_slave_sdo_upload() and ecrt_slave_sdo_download() methods to
+ *   let an application transfer SDOs before activating the master.
  * - Changed the meaning of the negative return values of
  *   ecrt_slave_config_reg_pdo_entry() and ecrt_slave_config_sdo*().
  * - Imlemented the Vendor-specific over EtherCAT mailbox protocol. See
  *   ecrt_slave_config_create_voe_handler().
  * - Renamed ec_sdo_request_state_t to ec_request_state_t, because it is also
  *   used by VoE handlers.
- * - Added ecrt_master_slave() to get information about a certain slave.
- * - Added ecrt_slave_sdo_upload() and ecrt_slave_sdo_download() methods to
- *   let an application transfer SDOs before activating the master.
  * - Removed 'const' from argument of ecrt_sdo_request_state(), because the
  *   userspace library has to modify object internals.
  * - Added 64-bit data access macros.
@@ -442,21 +445,23 @@
 
 /** Sets the locking callbacks.
  *
- * For concurrent master access, the application has to provide a locking
- * mechanism (see section FIXME in the docs). The method takes two function
- * pointers and a data value as its parameters. The arbitrary \a cb_data value
- * will be passed as argument on every callback. Asynchronous master access
- * (like EoE processing) is only possible if the callbacks have been set.
- *
- * The request_cb function must return zero, to allow another instance
- * (an EoE process for example) to access the master. Non-zero means,
- * that access is currently forbidden.
+ * For concurrent master access, i. e. if other instances than the application
+ * want to send and receive datagrams on the bus, the application has to
+ * provide a callback mechanism. This method takes two function pointers as
+ * its parameters. Asynchronous master access (like EoE processing) is only
+ * possible if the callbacks have been set.
+ *
+ * The task of the send callback (\a request_cb) is to decide, if the bus is
+ * currently accessible. In this case, it can call the ecrt_master_send_ext()
+ * method.
+ *
+ * The task of the receive callback (\a receive_cb) is to decide, if a call to
+ * ecrt_master_receive() is allowed and to execute it respectively.
  */
 void ecrt_master_callbacks(
         ec_master_t *master, /**< EtherCAT master */
-        int (*request_cb)(void *), /**< Lock request function. */
-        void (*release_cb)(void *), /**< Lock release function. */
-        void *cb_data /**< Arbitrary user data. */
+        void (*send_cb)(ec_master_t *), /**< Datagram sending callback. */
+        void (*receive_cb)(ec_master_t *) /**< Receive callback. */
         );
 
 #endif /* __KERNEL__ */
@@ -591,6 +596,15 @@
         ec_master_t *master /**< EtherCAT master. */
         );
 
+/** Sends non-application datagrams.
+ *
+ * This method has to be called in the send callback function passed via
+ * ecrt_master_callbacks() to allow the sending of non-application datagrams.
+ */
+void ecrt_master_send_ext(
+        ec_master_t *master /**< EtherCAT master. */
+        );
+
 /** Reads the current master state.
  *
  * Stores the master state information in the given \a state structure.
--- a/master/cdev.c	Fri Jul 10 10:40:05 2009 +0000
+++ b/master/cdev.c	Mon Jul 13 15:18:28 2009 +0000
@@ -1621,6 +1621,9 @@
         }
     }
 
+    ecrt_master_callbacks(master, ec_master_internal_send_cb,
+            ec_master_internal_receive_cb);
+
     ret = ecrt_master_activate(master);
     if (ret < 0)
         return ret;
--- a/master/ethernet.c	Fri Jul 10 10:40:05 2009 +0000
+++ b/master/ethernet.c	Mon Jul 13 15:18:28 2009 +0000
@@ -324,7 +324,7 @@
 void ec_eoe_queue(ec_eoe_t *eoe /**< EoE handler */)
 {
    if (eoe->queue_datagram) {
-       ec_master_queue_datagram(eoe->slave->master, &eoe->datagram);
+       ec_master_queue_datagram_ext(eoe->slave->master, &eoe->datagram);
        eoe->queue_datagram = 0;
    }
 }
--- a/master/master.c	Fri Jul 10 10:40:05 2009 +0000
+++ b/master/master.c	Mon Jul 13 15:18:28 2009 +0000
@@ -146,6 +146,9 @@
     INIT_LIST_HEAD(&master->datagram_queue);
     master->datagram_index = 0;
 
+    INIT_LIST_HEAD(&master->ext_datagram_queue);
+    init_MUTEX(&master->ext_queue_sem);
+
     INIT_LIST_HEAD(&master->domains);
 
     master->debug_level = debug_level;
@@ -163,9 +166,10 @@
 #endif
 
     init_MUTEX(&master->io_sem);
-    master->request_cb = NULL;
-    master->release_cb = NULL;
-    master->cb_data = NULL;
+    master->send_cb = NULL;
+    master->receive_cb = NULL;
+    master->app_send_cb = NULL;
+    master->app_receive_cb = NULL;
 
     INIT_LIST_HEAD(&master->sii_requests);
     init_waitqueue_head(&master->sii_queue);
@@ -375,22 +379,27 @@
 
 /*****************************************************************************/
 
-/** Internal locking callback.
- */
-int ec_master_request_cb(void *data /**< callback data */)
-{
-    ec_master_t *master = (ec_master_t *) data;
+/** Internal sending callback.
+ */
+void ec_master_internal_send_cb(
+        ec_master_t *master /**< EtherCAT master. */
+        )
+{
     down(&master->io_sem);
-    return 0;
-}
-
-/*****************************************************************************/
-
-/** Internal unlocking callback.
- */
-void ec_master_release_cb(void *data /**< callback data */)
-{
-    ec_master_t *master = (ec_master_t *) data;
+    ecrt_master_send_ext(master);
+    up(&master->io_sem);
+}
+
+/*****************************************************************************/
+
+/** Internal receiving callback.
+ */
+void ec_master_internal_receive_cb(
+        ec_master_t *master /**< EtherCAT master. */
+        )
+{
+    down(&master->io_sem);
+    ecrt_master_receive(master);
     up(&master->io_sem);
 }
 
@@ -462,9 +471,8 @@
     if (master->debug_level)
         EC_DBG("ORPHANED -> IDLE.\n");
 
-    master->request_cb = ec_master_request_cb;
-    master->release_cb = ec_master_release_cb;
-    master->cb_data = master;
+    master->send_cb = ec_master_internal_send_cb;
+    master->receive_cb = ec_master_internal_receive_cb;
 
     master->phase = EC_IDLE;
     ret = ec_master_thread_start(master, ec_master_idle_thread,
@@ -564,9 +572,8 @@
 #endif
 
     master->phase = EC_OPERATION;
-    master->ext_request_cb = NULL;
-    master->ext_release_cb = NULL;
-    master->ext_cb_data = NULL;
+    master->app_send_cb = NULL;
+    master->app_receive_cb = NULL;
     return ret;
     
 out_allow:
@@ -597,9 +604,8 @@
 #endif
     ec_master_thread_stop(master);
     
-    master->request_cb = ec_master_request_cb;
-    master->release_cb = ec_master_release_cb;
-    master->cb_data = master;
+    master->send_cb = ec_master_internal_send_cb;
+    master->receive_cb = ec_master_internal_receive_cb;
     
     down(&master->master_sem);
     ec_master_clear_domains(master);
@@ -646,9 +652,10 @@
 
 /** Places a datagram in the datagram queue.
  */
-void ec_master_queue_datagram(ec_master_t *master, /**< EtherCAT master */
-                              ec_datagram_t *datagram /**< datagram */
-                              )
+void ec_master_queue_datagram(
+        ec_master_t *master, /**< EtherCAT master */
+        ec_datagram_t *datagram /**< datagram */
+        )
 {
     ec_datagram_t *queued_datagram;
 
@@ -669,6 +676,20 @@
 
 /*****************************************************************************/
 
+/** Places a datagram in the non-application datagram queue.
+ */
+void ec_master_queue_datagram_ext(
+        ec_master_t *master, /**< EtherCAT master */
+        ec_datagram_t *datagram /**< datagram */
+        )
+{
+    down(&master->ext_queue_sem);
+    list_add_tail(&datagram->queue, &master->ext_datagram_queue);
+    up(&master->ext_queue_sem);
+}
+
+/*****************************************************************************/
+
 /** Sends the datagrams in the queue.
  *
  * \return 0 in case of success, else < 0
@@ -1048,8 +1069,8 @@
     if (list_empty(&master->eoe_handlers))
         return;
 
-    if (!master->request_cb || !master->release_cb) {
-        EC_WARN("No EoE processing because of missing locking callbacks!\n");
+    if (!master->send_cb || !master->receive_cb) {
+        EC_WARN("No EoE processing because of missing callbacks!\n");
         return;
     }
 
@@ -1109,11 +1130,7 @@
             goto schedule;
 
         // receive datagrams
-        if (master->request_cb(master->cb_data))
-            goto schedule;
-        
-        ecrt_master_receive(master);
-        master->release_cb(master->cb_data);
+        master->receive_cb(master);
 
         // actual EoE processing
         sth_to_send = 0;
@@ -1128,15 +1145,13 @@
         }
 
         if (sth_to_send) {
-            // send datagrams
-            if (master->request_cb(master->cb_data)) {
-                goto schedule;
-            }
             list_for_each_entry(eoe, &master->eoe_handlers, list) {
                 ec_eoe_queue(eoe);
             }
-            ecrt_master_send(master);
-            master->release_cb(master->cb_data);
+            // (try to) send datagrams
+            down(&master->ext_queue_sem);
+            master->send_cb(master);
+            up(&master->ext_queue_sem);
         }
 
 schedule:
@@ -1641,9 +1656,9 @@
 
     master->injection_seq_fsm = 0;
     master->injection_seq_rt = 0;
-    master->request_cb = master->ext_request_cb;
-    master->release_cb = master->ext_release_cb;
-    master->cb_data = master->ext_cb_data;
+
+    master->send_cb = master->app_send_cb;
+    master->receive_cb = master->app_receive_cb;
     
     ret = ec_master_thread_start(master, ec_master_operation_thread,
                 "EtherCAT-OP");
@@ -1735,6 +1750,21 @@
 
 /*****************************************************************************/
 
+void ecrt_master_send_ext(ec_master_t *master)
+{
+    ec_datagram_t *datagram, *next;
+
+    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);
+}
+
+/*****************************************************************************/
+
 /** Same as ecrt_master_slave_config(), but with ERR_PTR() return value.
  */
 ec_slave_config_t *ecrt_master_slave_config_err(ec_master_t *master,
@@ -1805,17 +1835,16 @@
 
 /*****************************************************************************/
 
-void ecrt_master_callbacks(ec_master_t *master, int (*request_cb)(void *),
-        void (*release_cb)(void *), void *cb_data)
+void ecrt_master_callbacks(ec_master_t *master,
+        void (*send_cb)(ec_master_t *), void (*receive_cb)(ec_master_t *))
 {
     if (master->debug_level)
-        EC_DBG("ecrt_master_callbacks(master = 0x%x, request_cb = 0x%x, "
-                " release_cb = 0x%x, cb_data = 0x%x)\n", (u32) master,
-                (u32) request_cb, (u32) release_cb, (u32) cb_data);
-
-    master->ext_request_cb = request_cb;
-    master->ext_release_cb = release_cb;
-    master->ext_cb_data = cb_data;
+        EC_DBG("ecrt_master_callbacks(master = 0x%x, send_cb = 0x%x, "
+                " receive_cb = 0x%x)\n", (u32) master, (u32) send_cb,
+                (u32) receive_cb);
+
+    master->app_send_cb = send_cb;
+    master->app_receive_cb = receive_cb;
 }
 
 /*****************************************************************************/
@@ -1862,6 +1891,7 @@
 EXPORT_SYMBOL(ecrt_master_create_domain);
 EXPORT_SYMBOL(ecrt_master_activate);
 EXPORT_SYMBOL(ecrt_master_send);
+EXPORT_SYMBOL(ecrt_master_send_ext);
 EXPORT_SYMBOL(ecrt_master_receive);
 EXPORT_SYMBOL(ecrt_master_callbacks);
 EXPORT_SYMBOL(ecrt_master_slave_config);
--- a/master/master.h	Fri Jul 10 10:40:05 2009 +0000
+++ b/master/master.h	Mon Jul 13 15:18:28 2009 +0000
@@ -145,6 +145,11 @@
     struct list_head datagram_queue; /**< Datagram queue. */
     uint8_t datagram_index; /**< Current datagram index. */
 
+    struct list_head ext_datagram_queue; /**< Queue for non-application
+                                           datagrams. */
+    struct semaphore ext_queue_sem; /**< Semaphore protecting the \a
+                                      ext_datagram_queue. */
+
     struct list_head domains; /**< List of domains. */
 
     unsigned int debug_level; /**< Master debug level. */
@@ -160,12 +165,13 @@
 #endif
 
     struct semaphore io_sem; /**< Semaphore used in \a IDLE phase. */
-    int (*request_cb)(void *); /**< Lock request callback. */
-    void (*release_cb)(void *); /**< Lock release callback. */
-    void *cb_data; /**< Data parameter of locking callbacks. */
-    int (*ext_request_cb)(void *); /**< External lock request callback. */
-    void (*ext_release_cb)(void *); /**< External lock release callback. */
-    void *ext_cb_data; /**< Data parameter of external locking callbacks. */
+
+    void (*send_cb)(ec_master_t *); /**< Current send datagrams callback. */
+    void (*receive_cb)(ec_master_t *); /**< Current receive datagrams callback. */
+    void (*app_send_cb)(ec_master_t *); /**< Application's send datagrams
+                                          callback. */
+    void (*app_receive_cb)(ec_master_t *); /**< Application's receive datagrams
+                                      callback. */
 
     struct list_head sii_requests; /**< SII write requests. */
     wait_queue_head_t sii_queue; /**< Wait queue for SII
@@ -208,6 +214,7 @@
 // datagram IO
 void ec_master_receive_datagrams(ec_master_t *, const uint8_t *, size_t);
 void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *);
+void ec_master_queue_datagram_ext(ec_master_t *, ec_datagram_t *);
 
 // misc.
 void ec_master_attach_slave_configs(ec_master_t *);
@@ -240,6 +247,9 @@
 
 void ec_master_calc_dc(ec_master_t *);
 
-/*****************************************************************************/
-
-#endif
+void ec_master_internal_send_cb(ec_master_t *);
+void ec_master_internal_receive_cb(ec_master_t *);
+
+/*****************************************************************************/
+
+#endif