Basic reading realtime Sdo access working.
authorFlorian Pose <fp@igh-essen.com>
Tue, 04 Mar 2008 09:57:36 +0000
changeset 858 69122084d066
parent 857 7874c884dc2b
child 859 233e32f428e1
Basic reading realtime Sdo access working.
examples/mini/mini.c
include/ecrt.h
master/fsm_coe_map.c
master/fsm_master.c
master/fsm_master.h
master/fsm_pdo_config.c
master/fsm_pdo_mapping.c
master/fsm_slave_config.c
master/globals.h
master/sdo_entry.c
master/sdo_request.c
master/sdo_request.h
master/slave_config.c
master/slave_config.h
--- a/examples/mini/mini.c	Tue Mar 04 09:20:14 2008 +0000
+++ b/examples/mini/mini.c	Tue Mar 04 09:57:36 2008 +0000
@@ -41,10 +41,13 @@
 
 /*****************************************************************************/
 
-// module parameters
+// Module parameters
 #define FREQUENCY 100
+
+// Optional features
 #define CONFIGURE_MAPPING
 #define EXTERNAL_MEMORY
+#define SDO_ACCESS
 
 #define PFX "ec_mini: "
 
@@ -112,6 +115,13 @@
 
 /*****************************************************************************/
 
+#ifdef SDO_ACCESS
+static ec_sdo_request_t *sdo;
+static int not_first_time = 0;
+#endif
+
+/*****************************************************************************/
+
 void check_domain1_state(void)
 {
     ec_domain_state_t ds;
@@ -155,6 +165,32 @@
 
 /*****************************************************************************/
 
+#ifdef SDO_ACCESS
+void read_sdo(void)
+{
+    switch (ecrt_sdo_request_state(sdo)) {
+        case EC_REQUEST_COMPLETE:
+            if (not_first_time) {
+                printk(KERN_INFO PFX "Sdo value: 0x%04X\n",
+                        EC_READ_U16(ecrt_sdo_request_data(sdo)));
+            } else {
+                not_first_time = 1;
+            }
+            ecrt_sdo_request_read(sdo);
+            break;
+        case EC_REQUEST_FAILURE:
+            printk(KERN_INFO PFX "Failed to read Sdo!\n");
+            ecrt_sdo_request_read(sdo);
+            break;
+        default:
+            printk(KERN_INFO PFX "Still busy...\n");
+            break;
+    }
+}
+#endif
+
+/*****************************************************************************/
+
 void cyclic_task(unsigned long data)
 {
     // receive process data
@@ -168,7 +204,7 @@
 
     if (counter) {
         counter--;
-    } else { // do this at FREQUENCY
+    } else { // do this at 1 Hz
         counter = FREQUENCY;
 
         // calculate new process data
@@ -176,6 +212,11 @@
 
         // check for master state (optional)
         check_master_state();
+        
+#ifdef SDO_ACCESS
+        // read process data Sdo
+        read_sdo();
+#endif
     }
 
     // write process data
@@ -256,6 +297,19 @@
     }
 #endif
 
+#ifdef SDO_ACCESS
+    printk(KERN_INFO PFX "Creating Sdo requests...\n");
+    if (!(sc = ecrt_master_slave_config(master, 0, 1, Beckhoff_EL3162))) {
+        printk(KERN_ERR PFX "Failed to get slave configuration.\n");
+        goto out_release_master;
+    }
+
+    if (!(sdo = ecrt_slave_config_create_sdo_request(sc, 0x3102, 2, 2))) {
+        printk(KERN_ERR PFX "Failed to create Sdo request.\n");
+        goto out_release_master;
+    }
+#endif
+
     printk(KERN_INFO PFX "Registering Pdo entries...\n");
     if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
         printk(KERN_ERR PFX "Pdo entry registration failed!\n");
--- a/include/ecrt.h	Tue Mar 04 09:20:14 2008 +0000
+++ b/include/ecrt.h	Tue Mar 04 09:57:36 2008 +0000
@@ -131,6 +131,9 @@
 struct ec_domain;
 typedef struct ec_domain ec_domain_t; /**< \see ec_domain */
 
+struct ec_sdo_request;
+typedef struct ec_sdo_request ec_sdo_request_t; /**< \see ec_sdo_request. */
+
 /*****************************************************************************/
 
 /** Bus state.
@@ -248,6 +251,28 @@
                        offset in the process data. */
 } ec_pdo_entry_reg_t;
 
+/*****************************************************************************/
+
+/** Generic request state.
+ */
+typedef enum {
+    EC_REQUEST_QUEUED,
+    EC_REQUEST_IN_PROGRESS,
+    EC_REQUEST_COMPLETE,
+    EC_REQUEST_FAILURE
+} ec_request_state_t;
+
+/*****************************************************************************/
+
+/** Sdo request error.
+ *
+ * This is used as return type of ecrt_sdo_request_error().
+ */
+typedef enum {
+    EC_SDO_REQUEST_SUCCESS, /**< There is no error. */
+    EC_SDO_REQUEST_TIMEOUT, /**< The request timed out. */
+} ec_sdo_request_error_t;
+
 /******************************************************************************
  * Global functions
  *****************************************************************************/
@@ -513,6 +538,18 @@
         uint32_t value /**< Value to set. */
         );
 
+/** Create an Sdo request to exchange Sdos during realtime operation.
+ *
+ * The created Sdo request object is freed automatically when the master is
+ * released.
+ */
+ec_sdo_request_t *ecrt_slave_config_create_sdo_request(
+        ec_slave_config_t *sc, /**< Slave configuration. */
+        uint16_t index, /**< Sdo index. */
+        uint8_t subindex, /**< Sdo subindex. */
+        size_t size /**< Data size to reserve. */
+        );
+
 /** Outputs the state of the slave configuration.
  *
  * Stores the state information in the given \a state structure.
@@ -599,6 +636,62 @@
                                    information. */
         );
 
+/*****************************************************************************
+ * Sdo request methods.
+ ****************************************************************************/
+
+/** Set the timeout for an Sdo request.
+ *
+ * If the request cannot be processed in the specified time, if will be marked
+ * as failed.
+ */
+void ecrt_sdo_request_timeout(
+        ec_sdo_request_t *req, /**< Sdo request. */
+        uint32_t timeout /**< Timeout in milliseconds. */
+        );
+
+/** Access to the Sdo request's data.
+ *
+ * \attention The return value is invalid during (ecrt_sdo_request_state() !=
+ * EC_REQUEST_COMPLETE) a read operation, because the internal Sdo data
+ * memory could be re-allocated.
+ *
+ * \return Pointer to the internal Sdo data memory.
+ */
+uint8_t *ecrt_sdo_request_data(
+        ec_sdo_request_t *req /**< Sdo request. */
+        );
+
+/** Get the current state of the Sdo request.
+ *
+ * \return Request state.
+ */
+ec_request_state_t ecrt_sdo_request_state(
+    const ec_sdo_request_t *req /**< Sdo request. */
+    );
+
+/** Get the error code of the Sdo request.
+ */
+ec_sdo_request_error_t ecrt_sdo_request_error(
+    const ec_sdo_request_t *req /**< Sdo request. */
+    );
+
+/** Schedule an Sdo write operation.
+ */
+void ecrt_sdo_request_write(
+        ec_sdo_request_t *req /**< Sdo request. */
+        );
+
+/** Schedule an Sdo read operation .
+ *
+ * \attention After calling this function, the return value of
+ * ecrt_sdo_request_data() will be invalid until ecrt_sdo_request_state()
+ * is EC_REQUEST_COMPLETE.
+ */
+void ecrt_sdo_request_read(
+        ec_sdo_request_t *req /**< Sdo request. */
+        );
+
 /******************************************************************************
  * Bitwise read/write macros
  *****************************************************************************/
--- a/master/fsm_coe_map.c	Tue Mar 04 09:20:14 2008 +0000
+++ b/master/fsm_coe_map.c	Tue Mar 04 09:57:36 2008 +0000
@@ -182,7 +182,7 @@
         ec_pdo_mapping_clear_pdos(&fsm->mapping);
 
         ec_sdo_request_address(&fsm->request, fsm->sync_sdo_index, 0);
-        ec_sdo_request_read(&fsm->request);
+        ecrt_sdo_request_read(&fsm->request);
         fsm->state = ec_fsm_coe_map_state_pdo_count;
         ec_fsm_coe_upload(fsm->fsm_coe, fsm->slave, &fsm->request);
         ec_fsm_coe_exec(fsm->fsm_coe); // execute immediately
@@ -238,7 +238,7 @@
     if (fsm->sync_subindex <= fsm->sync_subindices) {
         ec_sdo_request_address(&fsm->request, fsm->sync_sdo_index,
                 fsm->sync_subindex);
-        ec_sdo_request_read(&fsm->request);
+        ecrt_sdo_request_read(&fsm->request);
         fsm->state = ec_fsm_coe_map_state_pdo;
         ec_fsm_coe_upload(fsm->fsm_coe, fsm->slave, &fsm->request);
         ec_fsm_coe_exec(fsm->fsm_coe); // execute immediately
@@ -295,7 +295,7 @@
     list_add_tail(&fsm->pdo->list, &fsm->mapping.pdos);
 
     ec_sdo_request_address(&fsm->request, fsm->pdo->index, 0);
-    ec_sdo_request_read(&fsm->request);
+    ecrt_sdo_request_read(&fsm->request);
     fsm->state = ec_fsm_coe_map_state_pdo_entry_count;
     ec_fsm_coe_upload(fsm->fsm_coe, fsm->slave, &fsm->request);
     ec_fsm_coe_exec(fsm->fsm_coe); // execute immediately
@@ -342,7 +342,7 @@
 {
     if (fsm->pdo_subindex <= fsm->pdo_subindices) {
         ec_sdo_request_address(&fsm->request, fsm->pdo->index, fsm->pdo_subindex);
-        ec_sdo_request_read(&fsm->request);
+        ecrt_sdo_request_read(&fsm->request);
         fsm->state = ec_fsm_coe_map_state_pdo_entry;
         ec_fsm_coe_upload(fsm->fsm_coe, fsm->slave, &fsm->request);
         ec_fsm_coe_exec(fsm->fsm_coe); // execute immediately
--- a/master/fsm_master.c	Tue Mar 04 09:20:14 2008 +0000
+++ b/master/fsm_master.c	Tue Mar 04 09:57:36 2008 +0000
@@ -41,6 +41,7 @@
 #include "globals.h"
 #include "master.h"
 #include "mailbox.h"
+#include "slave_config.h"
 #ifdef EC_EOE
 #include "ethernet.h"
 #endif
@@ -376,9 +377,39 @@
 {
     ec_master_t *master = fsm->master;
     ec_master_sdo_request_t *request;
+    ec_sdo_request_t *req;
     ec_slave_t *slave;
 
-    // search the first request to be processed
+    // search for internal requests to be processed
+    list_for_each_entry(slave, &master->slaves, list) {
+        if (!slave->config)
+            continue;
+        list_for_each_entry(req, &slave->config->sdo_requests, list) {
+            if (req->state == EC_REQUEST_QUEUED) {
+                req->state = EC_REQUEST_IN_PROGRESS;
+
+                if (slave->current_state == EC_SLAVE_STATE_INIT ||
+                        slave->error_flag) {
+                    req->state = EC_REQUEST_FAILURE;
+                    continue;
+                }
+
+                if (master->debug_level)
+                    EC_DBG("Processing Sdo request for slave %u...\n",
+                            slave->ring_position);
+
+                fsm->idle = 0;
+                fsm->sdo_request = req;
+                fsm->slave = slave;
+                fsm->state = ec_fsm_master_state_sdo_request;
+                ec_fsm_coe_upload(&fsm->fsm_coe, slave, req);
+                ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately
+                return 1;
+            }
+        }
+    }
+    
+    // search the first external request to be processed
     while (1) {
         down(&master->sdo_sem);
         if (list_empty(&master->slave_sdo_requests)) {
@@ -410,7 +441,8 @@
 
         // Start uploading Sdo
         fsm->idle = 0;
-        fsm->sdo_request = request;
+        fsm->sdo_request = &request->req;
+        fsm->slave = slave;
         fsm->state = ec_fsm_master_state_sdo_request;
         ec_fsm_coe_upload(&fsm->fsm_coe, slave, &request->req);
         ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately
@@ -499,7 +531,7 @@
             return;
     }
 
-    // Check for a pending Sdo request
+    // Check for pending Sdo requests
     if (ec_fsm_master_action_process_sdo(fsm))
         return;
 
@@ -1026,25 +1058,25 @@
 void ec_fsm_master_state_sdo_request(ec_fsm_master_t *fsm /**< master state machine */)
 {
     ec_master_t *master = fsm->master;
-    ec_master_sdo_request_t *request = fsm->sdo_request;
+    ec_sdo_request_t *request = fsm->sdo_request;
 
     if (ec_fsm_coe_exec(&fsm->fsm_coe)) return;
 
     if (!ec_fsm_coe_success(&fsm->fsm_coe)) {
-        EC_DBG("Failed to process Sdo request for slave %i.\n",
+        EC_DBG("Failed to process Sdo request for slave %u.\n",
                 fsm->slave->ring_position);
-        request->req.state = EC_REQUEST_FAILURE;
+        request->state = EC_REQUEST_FAILURE;
         wake_up(&master->sdo_queue);
         fsm->state = ec_fsm_master_state_error;
         return;
     }
 
     // Sdo request finished 
-    request->req.state = EC_REQUEST_COMPLETE;
+    request->state = EC_REQUEST_COMPLETE;
     wake_up(&master->sdo_queue);
 
     if (master->debug_level)
-        EC_DBG("Finished Sdo request for slave %i.\n",
+        EC_DBG("Finished Sdo request for slave %u.\n",
                 fsm->slave->ring_position);
 
     // check for another Sdo request
--- a/master/fsm_master.h	Tue Mar 04 09:20:14 2008 +0000
+++ b/master/fsm_master.h	Tue Mar 04 09:57:36 2008 +0000
@@ -97,7 +97,7 @@
     ec_slave_t *slave; /**< current slave */
     ec_eeprom_write_request_t *eeprom_request; /**< EEPROM write request */
     off_t eeprom_index; /**< index to EEPROM write request data */
-    ec_master_sdo_request_t *sdo_request; /**< Sdo request to process. */
+    ec_sdo_request_t *sdo_request; /**< Sdo request to process. */
 
     ec_fsm_slave_config_t fsm_slave_config; /**< slave state machine */
     ec_fsm_slave_scan_t fsm_slave_scan; /**< slave state machine */
--- a/master/fsm_pdo_config.c	Tue Mar 04 09:20:14 2008 +0000
+++ b/master/fsm_pdo_config.c	Tue Mar 04 09:57:36 2008 +0000
@@ -214,7 +214,7 @@
     EC_WRITE_U8(&fsm->request.data, 0);
     fsm->request.data_size = 1;
     ec_sdo_request_address(&fsm->request, fsm->pdo->index, 0);
-    ec_sdo_request_write(&fsm->request);
+    ecrt_sdo_request_write(&fsm->request);
     if (fsm->slave->master->debug_level)
         EC_DBG("Setting entry count to zero for Pdo 0x%04X.\n",
                 fsm->pdo->index);
@@ -254,7 +254,7 @@
     EC_WRITE_U32(&fsm->request.data, value);
     fsm->request.data_size = 4;
     ec_sdo_request_address(&fsm->request, fsm->pdo->index, fsm->entry_count);
-    ec_sdo_request_write(&fsm->request);
+    ecrt_sdo_request_write(&fsm->request);
     if (fsm->slave->master->debug_level)
         EC_DBG("Configuring Pdo entry %08X at position %u.\n",
                 value, fsm->entry_count);
@@ -320,7 +320,7 @@
         EC_WRITE_U8(&fsm->request.data, fsm->entry_count);
         fsm->request.data_size = 1;
         ec_sdo_request_address(&fsm->request, fsm->pdo->index, 0);
-        ec_sdo_request_write(&fsm->request);
+        ecrt_sdo_request_write(&fsm->request);
         if (fsm->slave->master->debug_level)
             EC_DBG("Setting number of Pdo entries to %u.\n",
                     fsm->entry_count);
--- a/master/fsm_pdo_mapping.c	Tue Mar 04 09:20:14 2008 +0000
+++ b/master/fsm_pdo_mapping.c	Tue Mar 04 09:57:36 2008 +0000
@@ -205,7 +205,7 @@
         EC_WRITE_U8(&fsm->request.data, 0); // zero Pdos mapped
         fsm->request.data_size = 1;
         ec_sdo_request_address(&fsm->request, 0x1C10 + fsm->sync->index, 0);
-        ec_sdo_request_write(&fsm->request);
+        ecrt_sdo_request_write(&fsm->request);
         if (fsm->slave->master->debug_level)
             EC_DBG("Setting Pdo count to zero for SM%u.\n", fsm->sync->index);
 
@@ -248,7 +248,7 @@
     fsm->request.data_size = 2;
     ec_sdo_request_address(&fsm->request,
             0x1C10 + fsm->sync->index, fsm->pdo_count);
-    ec_sdo_request_write(&fsm->request);
+    ecrt_sdo_request_write(&fsm->request);
     if (fsm->slave->master->debug_level)
         EC_DBG("Mapping Pdo 0x%04X at position %u.\n",
                 fsm->pdo->index, fsm->pdo_count);
@@ -314,7 +314,7 @@
         EC_WRITE_U8(&fsm->request.data, fsm->pdo_count);
         fsm->request.data_size = 1;
         ec_sdo_request_address(&fsm->request, 0x1C10 + fsm->sync->index, 0);
-        ec_sdo_request_write(&fsm->request);
+        ecrt_sdo_request_write(&fsm->request);
         if (fsm->slave->master->debug_level)
             EC_DBG("Setting number of mapped Pdos to %u.\n",
                     fsm->pdo_count);
--- a/master/fsm_slave_config.c	Tue Mar 04 09:20:14 2008 +0000
+++ b/master/fsm_slave_config.c	Tue Mar 04 09:57:36 2008 +0000
@@ -450,7 +450,7 @@
     fsm->state = ec_fsm_slave_config_state_sdo_conf;
     fsm->request = list_entry(fsm->slave->config->sdo_configs.next,
             ec_sdo_request_t, list);
-    ec_sdo_request_write(fsm->request);
+    ecrt_sdo_request_write(fsm->request);
     ec_fsm_coe_download(&fsm->fsm_coe, fsm->slave, fsm->request);
     ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately
 }
@@ -479,7 +479,7 @@
     if (fsm->request->list.next != &fsm->slave->config->sdo_configs) {
         fsm->request = list_entry(fsm->request->list.next, ec_sdo_request_t,
                 list);
-        ec_sdo_request_write(fsm->request);
+        ecrt_sdo_request_write(fsm->request);
         ec_fsm_coe_download(&fsm->fsm_coe, fsm->slave, fsm->request);
         ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately
         return;
--- a/master/globals.h	Tue Mar 04 09:20:14 2008 +0000
+++ b/master/globals.h	Tue Mar 04 09:57:36 2008 +0000
@@ -191,17 +191,6 @@
 
 /*****************************************************************************/
 
-/** Master request state.
- */
-typedef enum {
-    EC_REQUEST_QUEUED,
-    EC_REQUEST_IN_PROGRESS,
-    EC_REQUEST_COMPLETE,
-    EC_REQUEST_FAILURE
-} ec_request_state_t;
-
-/*****************************************************************************/
-
 /** Origin type.
  */
 typedef enum {
--- a/master/sdo_entry.c	Tue Mar 04 09:20:14 2008 +0000
+++ b/master/sdo_entry.c	Tue Mar 04 09:57:36 2008 +0000
@@ -269,7 +269,7 @@
     request.slave = entry->sdo->slave;
     ec_sdo_request_init(&request.req);
     ec_sdo_request_address(&request.req, entry->sdo->index, entry->subindex);
-    ec_sdo_request_read(&request.req);
+    ecrt_sdo_request_read(&request.req);
 
     // schedule request.
     down(&master->sdo_sem);
--- a/master/sdo_request.c	Tue Mar 04 09:20:14 2008 +0000
+++ b/master/sdo_request.c	Tue Mar 04 09:57:36 2008 +0000
@@ -148,26 +148,54 @@
     return 0;
 }
 
-/*****************************************************************************/
-
-/** Start an Sdo read operation (Sdo upload).
- */
-void ec_sdo_request_read(
-        ec_sdo_request_t *req /**< Sdo request. */
-        )
+/*****************************************************************************
+ * Realtime interface.
+ ****************************************************************************/
+
+void ecrt_sdo_request_timeout(ec_sdo_request_t *req, uint32_t timeout)
+{
+}
+
+/*****************************************************************************/
+
+uint8_t *ecrt_sdo_request_data(ec_sdo_request_t *req)
+{
+    return req->data;
+}
+
+/*****************************************************************************/
+
+ec_request_state_t ecrt_sdo_request_state(const ec_sdo_request_t *req)
+{
+    return req->state;
+}
+
+/*****************************************************************************/
+
+ec_sdo_request_error_t ecrt_sdo_request_error(const ec_sdo_request_t *req)
+{
+    return EC_SDO_REQUEST_SUCCESS; // FIXME
+}
+
+/*****************************************************************************/
+
+void ecrt_sdo_request_read(ec_sdo_request_t *req)
 {
     req->state = EC_REQUEST_QUEUED;
 }
 
 /*****************************************************************************/
 
-/** Start an Sdo write operation (Sdo download).
- */
-void ec_sdo_request_write(
-        ec_sdo_request_t *req /**< Sdo request. */
-        )
+void ecrt_sdo_request_write(ec_sdo_request_t *req)
 {
     req->state = EC_REQUEST_QUEUED;
 }
 
 /*****************************************************************************/
+
+EXPORT_SYMBOL(ecrt_sdo_request_timeout);
+EXPORT_SYMBOL(ecrt_sdo_request_data);
+EXPORT_SYMBOL(ecrt_sdo_request_state);
+EXPORT_SYMBOL(ecrt_sdo_request_error);
+EXPORT_SYMBOL(ecrt_sdo_request_read);
+EXPORT_SYMBOL(ecrt_sdo_request_write);
--- a/master/sdo_request.h	Tue Mar 04 09:20:14 2008 +0000
+++ b/master/sdo_request.h	Tue Mar 04 09:57:36 2008 +0000
@@ -43,13 +43,15 @@
 
 #include <linux/list.h>
 
+#include "../include/ecrt.h"
+
 #include "globals.h"
 
 /*****************************************************************************/
 
 /** CANopen Sdo request.
  */
-typedef struct {
+struct ec_sdo_request {
     struct list_head list; /**< List item. */
     uint16_t index; /**< Sdo index. */
     uint8_t subindex; /**< Sdo subindex. */
@@ -57,7 +59,7 @@
     size_t mem_size; /**< Size of Sdo data memory. */
     size_t data_size; /**< Size of Sdo data. */
     ec_request_state_t state; /**< Sdo request state. */
-} ec_sdo_request_t;
+};
 
 /*****************************************************************************/
 
@@ -68,9 +70,6 @@
 int ec_sdo_request_alloc(ec_sdo_request_t *, size_t);
 int ec_sdo_request_copy_data(ec_sdo_request_t *, const uint8_t *, size_t);
 
-void ec_sdo_request_read(ec_sdo_request_t *);
-void ec_sdo_request_write(ec_sdo_request_t *);
-
 /*****************************************************************************/
 
 #endif
--- a/master/slave_config.c	Tue Mar 04 09:20:14 2008 +0000
+++ b/master/slave_config.c	Tue Mar 04 09:57:36 2008 +0000
@@ -105,6 +105,7 @@
         ec_pdo_mapping_init(&sc->mapping[dir]);
 
     INIT_LIST_HEAD(&sc->sdo_configs);
+    INIT_LIST_HEAD(&sc->sdo_requests);
 
     sc->used_fmmus = 0;
 
@@ -174,6 +175,13 @@
         kfree(req);
     }
 
+    // free all Sdo requests
+    list_for_each_entry_safe(req, next_req, &sc->sdo_requests, list) {
+        list_del(&req->list);
+        ec_sdo_request_clear(req);
+        kfree(req);
+    }
+
     kfree(sc);
 }
 
@@ -276,6 +284,16 @@
         buf += sprintf(buf, "\n");
     }
 
+    // type-cast to avoid warnings on some compilers
+    if (!list_empty((struct list_head *) &sc->sdo_requests)) {
+        buf += sprintf(buf, "\nSdo requests:\n");
+
+        list_for_each_entry(req, &sc->sdo_requests, list) {
+            buf += sprintf(buf, "  0x%04X:%u\n", req->index, req->subindex);
+        }
+        buf += sprintf(buf, "\n");
+    }
+
     return buf - buffer;
 }
 
@@ -672,6 +690,32 @@
 
 /*****************************************************************************/
 
+ec_sdo_request_t *ecrt_slave_config_create_sdo_request(ec_slave_config_t *sc,
+        uint16_t index, uint8_t subindex, size_t size)
+{
+    ec_sdo_request_t *req;
+
+    if (!(req = (ec_sdo_request_t *)
+                kmalloc(sizeof(ec_sdo_request_t), GFP_KERNEL))) {
+        EC_ERR("Failed to allocate Sdo request memory!\n");
+        return NULL;
+    }
+
+    ec_sdo_request_init(req);
+    ec_sdo_request_address(req, index, subindex);
+
+    if (ec_sdo_request_alloc(req, size)) {
+        ec_sdo_request_clear(req);
+        kfree(req);
+        return NULL;
+    }
+    
+    list_add_tail(&req->list, &sc->sdo_requests);
+    return req; 
+}
+
+/*****************************************************************************/
+
 /** \cond */
 
 EXPORT_SYMBOL(ecrt_slave_config_pdo);
@@ -681,6 +725,7 @@
 EXPORT_SYMBOL(ecrt_slave_config_sdo8);
 EXPORT_SYMBOL(ecrt_slave_config_sdo16);
 EXPORT_SYMBOL(ecrt_slave_config_sdo32);
+EXPORT_SYMBOL(ecrt_slave_config_create_sdo_request);
 
 /** \endcond */
 
--- a/master/slave_config.h	Tue Mar 04 09:20:14 2008 +0000
+++ b/master/slave_config.h	Tue Mar 04 09:57:36 2008 +0000
@@ -71,7 +71,8 @@
 
     ec_pdo_mapping_t mapping[2]; /**< Output and input Pdo mapping. */
 
-    struct list_head sdo_configs; /**< Sdo configurations. */
+    struct list_head sdo_configs; /**< List of Sdo configurations. */
+    struct list_head sdo_requests; /**< List of Sdo requests. */
 
     ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]; /**< FMMU configurations. */
     uint8_t used_fmmus; /**< Number of FMMUs used. */