Added parameters for vendor ID and product code to ecrt_get_slave(); PDO
authorFlorian Pose <fp@igh-essen.com>
Fri, 09 Mar 2007 10:24:50 +0000
changeset 640 16e9ad7d8e12
parent 639 aa23c48dca2d
child 641 811952909e11
Added parameters for vendor ID and product code to ecrt_get_slave(); PDO
registration functions now take a slave pointer as argument; changed
values for ec_bus_status_t.
NEWS
TODO
include/ecdb.h
include/ecrt.h
master/domain.c
master/master.c
--- a/NEWS	Thu Mar 08 18:15:25 2007 +0000
+++ b/NEWS	Fri Mar 09 10:24:50 2007 +0000
@@ -17,6 +17,12 @@
 * Realtime interface changes:
   - ecrt_master_run() became obsolete, because the master state machine is now
     run in process context.
+  - Parameter changes in PDO registration functions ecrt_domain_register_pdo()
+    and ecrt_register_pdo_range(): Replaced slave_address, vendor ID and
+    product code arguments with a slave pointer, which has to be optained with
+    a prior call to ecrt_master_get_slave().
+  - ecrt_master_get_slave() got additional parameters to check for vendor ID
+    and product code.
   - Added ecrt_master_get_status() to get information about the bus.
   - Added functions to set up an alternative PDO mapping, i. e.
     ec_slave_pdo_mapping_clear(), ec_slave_pdo_mapping_add() and
--- a/TODO	Thu Mar 08 18:15:25 2007 +0000
+++ b/TODO	Fri Mar 09 10:24:50 2007 +0000
@@ -9,8 +9,6 @@
 * Release 1.3:
   - Remove addressing scheme "X:Y".
   - Remove ugly ec_slave_is_coupler().
-  - Replace Vendor ID and product code arguments of ec_domain_register_pdo()
-    by slave pointer.
   - Reset topology_change_pending on successful validation.
   - Dynamic creation of EoE handlers.
 
--- a/include/ecdb.h	Thu Mar 08 18:15:25 2007 +0000
+++ b/include/ecdb.h	Fri Mar 09 10:24:50 2007 +0000
@@ -47,46 +47,87 @@
 
 #define Beckhoff_BK1120 0x00000002, 0x04602C22
 
-#define Beckhoff_EL1004_Inputs 0x00000002, 0x03EC3052, 0x3101, 1
+#define Beckhoff_EL1004 0x00000002, 0x03EC3052
+#define Beckhoff_EL1004_PDO_Inputs 0x3101, 1
+#define Beckhoff_EL1004_Inputs Beckhoff_EL1004, Beckhoff_EL1004_PDO_Inputs
 
-#define Beckhoff_EL1014_Inputs 0x00000002, 0x03F63052, 0x3101, 1
+#define Beckhoff_EL1014 0x00000002, 0x03F63052
+#define Beckhoff_EL1014_PDO_Inputs 0x3101, 1
+#define Beckhoff_EL1014_Inputs Beckhoff_EL1014, Beckhoff_EL1014_PDO_Inputs 
 
-#define Beckhoff_EL2004_Outputs 0x00000002, 0x07D43052, 0x3001, 1
+#define Beckhoff_EL2004 0x00000002, 0x07D43052
+#define Beckhoff_EL2004_PDO_Outputs 0x3001, 1
+#define Beckhoff_EL2004_Outputs Beckhoff_EL2004, Beckhoff_EL2004_PDO_Outputs 
 
-#define Beckhoff_EL2032_Outputs 0x00000002, 0x07F03052, 0x3001, 1
+#define Beckhoff_EL2032 0x00000002, 0x07F03052
+#define Beckhoff_EL2032_PDO_Outputs 0x3001, 1
+#define Beckhoff_EL2032_Outputs Beckhoff_EL2032, Beckhoff_EL2032_PDO_Outputs
 
-#define Beckhoff_EL3102_Status1 0x00000002, 0x0C1E3052, 0x3101, 1
-#define Beckhoff_EL3102_Input1  0x00000002, 0x0C1E3052, 0x3101, 2
-#define Beckhoff_EL3102_Status2 0x00000002, 0x0C1E3052, 0x3102, 1
-#define Beckhoff_EL3102_Input2  0x00000002, 0x0C1E3052, 0x3102, 2
+#define Beckhoff_EL3102 0x00000002, 0x0C1E3052
+#define Beckhoff_EL3102_PDO_Status1 0x3101, 1
+#define Beckhoff_EL3102_PDO_Input1  0x3101, 2
+#define Beckhoff_EL3102_PDO_Status2 0x3102, 1
+#define Beckhoff_EL3102_PDO_Input2  0x3102, 2
+#define Beckhoff_EL3102_Status1 Beckhoff_EL3102, Beckhoff_EL3102_PDO_Status1
+#define Beckhoff_EL3102_Input1  Beckhoff_EL3102, Beckhoff_EL3102_PDO_Input1 
+#define Beckhoff_EL3102_Status2 Beckhoff_EL3102, Beckhoff_EL3102_PDO_Status2
+#define Beckhoff_EL3102_Input2  Beckhoff_EL3102, Beckhoff_EL3102_PDO_Input2
 
-#define Beckhoff_EL3152_Status1 0x00000002, 0x0C503052, 0x3101, 1
-#define Beckhoff_EL3152_Input1  0x00000002, 0x0C503052, 0x3101, 2
-#define Beckhoff_EL3152_Status2 0x00000002, 0x0C503052, 0x3102, 1
-#define Beckhoff_EL3152_Input2  0x00000002, 0x0C503052, 0x3102, 2
+#define Beckhoff_EL3152 0x00000002, 0x0C503052
+#define Beckhoff_EL3152_PDO_Status1 0x3101, 1
+#define Beckhoff_EL3152_PDO_Input1  0x3101, 2
+#define Beckhoff_EL3152_PDO_Status2 0x3102, 1
+#define Beckhoff_EL3152_PDO_Input2  0x3102, 2
+#define Beckhoff_EL3152_Status1 Beckhoff_EL3152, Beckhoff_EL3152_PDO_Status1
+#define Beckhoff_EL3152_Input1  Beckhoff_EL3152, Beckhoff_EL3152_PDO_Input1
+#define Beckhoff_EL3152_Status2 Beckhoff_EL3152, Beckhoff_EL3152_PDO_Status2
+#define Beckhoff_EL3152_Input2  Beckhoff_EL3152, Beckhoff_EL3152_PDO_Input2
 
-#define Beckhoff_EL3162_Status1 0x00000002, 0x0C5A3052, 0x3101, 1
-#define Beckhoff_EL3162_Input1  0x00000002, 0x0C5A3052, 0x3101, 2
-#define Beckhoff_EL3162_Status2 0x00000002, 0x0C5A3052, 0x3102, 1
-#define Beckhoff_EL3162_Input2  0x00000002, 0x0C5A3052, 0x3102, 2
+#define Beckhoff_EL3162 0x00000002, 0x0C5A3052
+#define Beckhoff_EL3162_PDO_Status1 0x3101, 1
+#define Beckhoff_EL3162_PDO_Input1  0x3101, 2
+#define Beckhoff_EL3162_PDO_Status2 0x3102, 1
+#define Beckhoff_EL3162_PDO_Input2  0x3102, 2
+#define Beckhoff_EL3162_Status1 Beckhoff_EL3162, Beckhoff_EL3162_PDO_Status1
+#define Beckhoff_EL3162_Input1  Beckhoff_EL3162, Beckhoff_EL3162_PDO_Input1
+#define Beckhoff_EL3162_Status2 Beckhoff_EL3162, Beckhoff_EL3162_PDO_Status2
+#define Beckhoff_EL3162_Input2  Beckhoff_EL3162, Beckhoff_EL3162_PDO_Input2
 
-#define Beckhoff_EL4102_Output1 0x00000002, 0x10063052, 0x6411, 1
-#define Beckhoff_EL4102_Output2 0x00000002, 0x10063052, 0x6411, 2
+#define Beckhoff_EL4102 0x00000002, 0x10063052
+#define Beckhoff_EL4102_PDO_Output1 0x6411, 1
+#define Beckhoff_EL4102_PDO_Output2 0x6411, 2
+#define Beckhoff_EL4102_Output1 Beckhoff_EL4102, Beckhoff_EL4102_PDO_Output1
+#define Beckhoff_EL4102_Output2 Beckhoff_EL4102, Beckhoff_EL4102_PDO_Output2
 
-#define Beckhoff_EL4132_Output1 0x00000002, 0x10243052, 0x6411, 1
-#define Beckhoff_EL4132_Output2 0x00000002, 0x10243052, 0x6411, 2
+#define Beckhoff_EL4132 0x00000002, 0x10243052
+#define Beckhoff_EL4132_PDO_Output1 0x6411, 1
+#define Beckhoff_EL4132_PDO_Output2 0x6411, 2
+#define Beckhoff_EL4132_Output1 Beckhoff_EL4132, Beckhoff_EL4132_PDO_Output1
+#define Beckhoff_EL4132_Output2 Beckhoff_EL4132, Beckhoff_EL4132_PDO_Output2
 
-#define Beckhoff_EL5001_Status 0x00000002, 0x13893052, 0x3101, 1
-#define Beckhoff_EL5001_Value  0x00000002, 0x13893052, 0x3101, 2
+#define Beckhoff_EL5001 0x00000002, 0x13893052
+#define Beckhoff_EL5001_PDO_Status 0x3101, 1
+#define Beckhoff_EL5001_PDO_Value  0x3101, 2
+#define Beckhoff_EL5001_Status Beckhoff_EL5001, Beckhoff_EL5001_PDO_Status
+#define Beckhoff_EL5001_Value  Beckhoff_EL5001, Beckhoff_EL5001_PDO_Value
 
-#define Beckhoff_EL5101_Status      0x00000002, 0x13ED3052, 0x6000, 1
-#define Beckhoff_EL5101_Value       0x00000002, 0x13ED3052, 0x6000, 2
-#define Beckhoff_EL5101_Latch       0x00000002, 0x13ED3052, 0x6000, 3
-#define Beckhoff_EL5101_Frequency   0x00000002, 0x13ED3052, 0x6000, 4
-#define Beckhoff_EL5101_Period      0x00000002, 0x13ED3052, 0x6000, 5
-#define Beckhoff_EL5101_Window      0x00000002, 0x13ED3052, 0x6000, 6
-#define Beckhoff_EL5101_Ctrl        0x00000002, 0x13ED3052, 0x7000, 1
-#define Beckhoff_EL5101_OutputValue 0x00000002, 0x13ED3052, 0x7000, 2
+#define Beckhoff_EL5101 0x00000002, 0x13ED3052
+#define Beckhoff_EL5101_PDO_Status      0x6000, 1
+#define Beckhoff_EL5101_PDO_Value       0x6000, 2
+#define Beckhoff_EL5101_PDO_Latch       0x6000, 3
+#define Beckhoff_EL5101_PDO_Frequency   0x6000, 4
+#define Beckhoff_EL5101_PDO_Period      0x6000, 5
+#define Beckhoff_EL5101_PDO_Window      0x6000, 6
+#define Beckhoff_EL5101_PDO_Ctrl        0x7000, 1
+#define Beckhoff_EL5101_PDO_OutputValue 0x7000, 2
+#define Beckhoff_EL5101_Status      Beckhoff_EL5101, Beckhoff_EL5101_PDO_Status      
+#define Beckhoff_EL5101_Value       Beckhoff_EL5101, Beckhoff_EL5101_PDO_Value       
+#define Beckhoff_EL5101_Latch       Beckhoff_EL5101, Beckhoff_EL5101_PDO_Latch       
+#define Beckhoff_EL5101_Frequency   Beckhoff_EL5101, Beckhoff_EL5101_PDO_Frequency   
+#define Beckhoff_EL5101_Period      Beckhoff_EL5101, Beckhoff_EL5101_PDO_Period      
+#define Beckhoff_EL5101_Window      Beckhoff_EL5101, Beckhoff_EL5101_PDO_Window      
+#define Beckhoff_EL5101_Ctrl        Beckhoff_EL5101, Beckhoff_EL5101_PDO_Ctrl        
+#define Beckhoff_EL5101_OutputValue Beckhoff_EL5101, Beckhoff_EL5101_PDO_OutputValue 
 
 /** \endcond */
 
--- a/include/ecrt.h	Thu Mar 08 18:15:25 2007 +0000
+++ b/include/ecrt.h	Fri Mar 09 10:24:50 2007 +0000
@@ -81,9 +81,10 @@
  */
 
 typedef enum {
-    EC_BUS_FAILURE,    // some slaves offline
-    EC_BUS_OK,         // all slaves online
-    EC_BUS_REDUNDANCY  // bus interrupted, but redundancy active
+    EC_BUS_FAILURE = -1, /**< At least one slave with process data exchange
+                           is offline. */
+    EC_BUS_OK            /**< All slaves with process data exchange are
+                           online. */
 }
 ec_bus_status_t;
 
@@ -93,22 +94,21 @@
  */
 
 typedef struct {
-    ec_bus_status_t bus_status;
-    unsigned int bus_tainted;
-    unsigned int slaves_responding;
+    ec_bus_status_t bus_status; /**< \see ec_bus_status_t */
+    unsigned int bus_tainted; /**< non-zero, if the bus topology is invalid */
+    unsigned int slaves_responding; /**< number of responging slaves */
 }
 ec_master_status_t;
 
 /**
-   Initialization type for PDO registrations.
-   This type is used as a parameter for the ecrt_domain_register_pdo_list()
-   function.
-*/
-
-typedef struct
-{
-    const char *slave_address; /**< slave address string (see
-                                  ecrt_master_get_slave()) */
+ * List entry for domain PDO registrations.
+ * This type is used as a parameter for the ecrt_domain_register_pdo_list()
+ * convenience function.
+ */
+
+typedef struct {
+    const char *slave_address; /**< slave address string
+                                 \see ec_master_parse_slave_address() */
     uint32_t vendor_id; /**< vendor ID */
     uint32_t product_code; /**< product code */
     uint16_t pdo_entry_index; /**< PDO entry index */
@@ -118,17 +118,17 @@
 ec_pdo_reg_t;
 
 /**
-   Direction type for ecrt_domain_register_pdo_range()
-*/
+ * Direction type for PDO mapping and range registration functions.
+ */
 
 typedef enum {
-    EC_DIR_OUTPUT,
-    EC_DIR_INPUT
+    EC_DIR_OUTPUT, /**< values written by master */
+    EC_DIR_INPUT   /**< values read by master */
 }
 ec_direction_t;
 
 /******************************************************************************
- *  Master request functions
+ *  Global functions
  *****************************************************************************/
 
 ec_master_t *ecrt_request_master(unsigned int master_index);
@@ -145,41 +145,33 @@
 
 ec_domain_t *ecrt_master_create_domain(ec_master_t *master);
 
+ec_slave_t *ecrt_master_get_slave(const ec_master_t *, const char *,
+        uint32_t vendor_id, uint32_t product_code);
+
 int ecrt_master_activate(ec_master_t *master);
 
 void ecrt_master_send(ec_master_t *master);
 void ecrt_master_receive(ec_master_t *master);
 
-ec_slave_t *ecrt_master_get_slave(const ec_master_t *, const char *);
-
 void ecrt_master_get_status(const ec_master_t *master, ec_master_status_t *);
 
 /******************************************************************************
  *  Domain Methods
  *****************************************************************************/
 
-ec_slave_t *ecrt_domain_register_pdo(ec_domain_t *domain,
-                                     const char *address,
-                                     uint32_t vendor_id,
-                                     uint32_t product_code,
-                                     uint16_t pdo_index,
-                                     uint8_t pdo_subindex,
-                                     void **data_ptr);
+int ecrt_domain_register_pdo(ec_domain_t *domain, ec_slave_t *slave,
+        uint16_t pdo_index, uint8_t pdo_subindex, void **data_ptr);
+
+int ecrt_domain_register_pdo_range(ec_domain_t *domain, ec_slave_t *slave,
+        ec_direction_t direction, uint16_t offset, uint16_t length,
+        void **data_ptr);
 
 int ecrt_domain_register_pdo_list(ec_domain_t *domain,
-                                  const ec_pdo_reg_t *pdos);
-
-ec_slave_t *ecrt_domain_register_pdo_range(ec_domain_t *domain,
-                                           const char *address,
-                                           uint32_t vendor_id,
-                                           uint32_t product_code,
-                                           ec_direction_t direction,
-                                           uint16_t offset,
-                                           uint16_t length,
-                                           void **data_ptr);
+        const ec_pdo_reg_t *pdos);
 
 void ecrt_domain_process(ec_domain_t *domain);
 void ecrt_domain_queue(ec_domain_t *domain);
+
 int ecrt_domain_state(const ec_domain_t *domain);
 
 /******************************************************************************
@@ -202,19 +194,19 @@
  *****************************************************************************/
 
 /**
-   Read a certain bit of an EtherCAT data byte.
-   \param DATA EtherCAT data pointer
-   \param POS bit position
-*/
+ * Read a certain bit of an EtherCAT data byte.
+ * \param DATA EtherCAT data pointer
+ * \param POS bit position
+ */
 
 #define EC_READ_BIT(DATA, POS) ((*((uint8_t *) (DATA)) >> (POS)) & 0x01)
 
 /**
-   Write a certain bit of an EtherCAT data byte.
-   \param DATA EtherCAT data pointer
-   \param POS bit position
-   \param VAL new bit value
-*/
+ * Write a certain bit of an EtherCAT data byte.
+ * \param DATA EtherCAT data pointer
+ * \param POS bit position
+ * \param VAL new bit value
+ */
 
 #define EC_WRITE_BIT(DATA, POS, VAL) \
     do { \
@@ -227,68 +219,67 @@
  *****************************************************************************/
 
 /**
-   Read an 8-bit unsigned value from EtherCAT data.
-   \return EtherCAT data value
-*/
+ * Read an 8-bit unsigned value from EtherCAT data.
+ * \return EtherCAT data value
+ */
 
 #define EC_READ_U8(DATA) \
     ((uint8_t) *((uint8_t *) (DATA)))
 
 /**
-   Read an 8-bit signed value from EtherCAT data.
-   \param DATA EtherCAT data pointer
-   \return EtherCAT data value
-*/
+ * Read an 8-bit signed value from EtherCAT data.
+ * \param DATA EtherCAT data pointer
+ * \return EtherCAT data value
+ */
 
 #define EC_READ_S8(DATA) \
      ((int8_t) *((uint8_t *) (DATA)))
 
 /**
-   Read a 16-bit unsigned value from EtherCAT data.
-   \param DATA EtherCAT data pointer
-   \return EtherCAT data value
-*/
+ * Read a 16-bit unsigned value from EtherCAT data.
+ * \param DATA EtherCAT data pointer
+ * \return EtherCAT data value
+ */
 
 #define EC_READ_U16(DATA) \
      ((uint16_t) le16_to_cpup((void *) (DATA)))
 
 /**
-   Read a 16-bit signed value from EtherCAT data.
-   \param DATA EtherCAT data pointer
-   \return EtherCAT data value
-*/
+ * Read a 16-bit signed value from EtherCAT data.
+ * \param DATA EtherCAT data pointer
+ * \return EtherCAT data value
+ */
 
 #define EC_READ_S16(DATA) \
      ((int16_t) le16_to_cpup((void *) (DATA)))
 
 /**
-   Read a 32-bit unsigned value from EtherCAT data.
-   \param DATA EtherCAT data pointer
-   \return EtherCAT data value
-*/
+ * Read a 32-bit unsigned value from EtherCAT data.
+ * \param DATA EtherCAT data pointer
+ * \return EtherCAT data value
+ */
 
 #define EC_READ_U32(DATA) \
      ((uint32_t) le32_to_cpup((void *) (DATA)))
 
 /**
-   Read a 32-bit signed value from EtherCAT data.
-   \param DATA EtherCAT data pointer
-   \return EtherCAT data value
-*/
+ * Read a 32-bit signed value from EtherCAT data.
+ * \param DATA EtherCAT data pointer
+ * \return EtherCAT data value
+ */
 
 #define EC_READ_S32(DATA) \
      ((int32_t) le32_to_cpup((void *) (DATA)))
 
-
 /******************************************************************************
  *  Write macros
  *****************************************************************************/
 
 /**
-   Write an 8-bit unsigned value to EtherCAT data.
-   \param DATA EtherCAT data pointer
-   \param VAL new value
-*/
+ * Write an 8-bit unsigned value to EtherCAT data.
+ * \param DATA EtherCAT data pointer
+ * \param VAL new value
+ */
 
 #define EC_WRITE_U8(DATA, VAL) \
     do { \
@@ -296,18 +287,18 @@
     } while (0)
 
 /**
-   Write an 8-bit signed value to EtherCAT data.
-   \param DATA EtherCAT data pointer
-   \param VAL new value
-*/
+ * Write an 8-bit signed value to EtherCAT data.
+ * \param DATA EtherCAT data pointer
+ * \param VAL new value
+ */
 
 #define EC_WRITE_S8(DATA, VAL) EC_WRITE_U8(DATA, VAL)
 
 /**
-   Write a 16-bit unsigned value to EtherCAT data.
-   \param DATA EtherCAT data pointer
-   \param VAL new value
-*/
+ * Write a 16-bit unsigned value to EtherCAT data.
+ * \param DATA EtherCAT data pointer
+ * \param VAL new value
+ */
 
 #define EC_WRITE_U16(DATA, VAL) \
     do { \
@@ -316,18 +307,18 @@
     } while (0)
 
 /**
-   Write a 16-bit signed value to EtherCAT data.
-   \param DATA EtherCAT data pointer
-   \param VAL new value
-*/
+ * Write a 16-bit signed value to EtherCAT data.
+ * \param DATA EtherCAT data pointer
+ * \param VAL new value
+ */
 
 #define EC_WRITE_S16(DATA, VAL) EC_WRITE_U16(DATA, VAL)
 
 /**
-   Write a 32-bit unsigned value to EtherCAT data.
-   \param DATA EtherCAT data pointer
-   \param VAL new value
-*/
+ * Write a 32-bit unsigned value to EtherCAT data.
+ * \param DATA EtherCAT data pointer
+ * \param VAL new value
+ */
 
 #define EC_WRITE_U32(DATA, VAL) \
     do { \
@@ -336,10 +327,10 @@
     } while (0)
 
 /**
-   Write a 32-bit signed value to EtherCAT data.
-   \param DATA EtherCAT data pointer
-   \param VAL new value
-*/
+ * Write a 32-bit signed value to EtherCAT data.
+ * \param DATA EtherCAT data pointer
+ * \param VAL new value
+ */
 
 #define EC_WRITE_S32(DATA, VAL) EC_WRITE_U32(DATA, VAL)
 
--- a/master/domain.c	Thu Mar 08 18:15:25 2007 +0000
+++ b/master/domain.c	Fri Mar 09 10:24:50 2007 +0000
@@ -236,64 +236,6 @@
 /*****************************************************************************/
 
 /**
-   Registeres a PDO range.
-   \return 0 in case of success, else < 0
-*/
-
-int ec_domain_reg_pdo_range(ec_domain_t *domain, /**< EtherCAT domain */
-                            ec_slave_t *slave, /**< slave */
-                            ec_direction_t dir, /**< data direction */
-                            uint16_t offset, /**< offset */
-                            uint16_t length, /**< length */
-                            void **data_ptr /**< pointer to the process data
-                                               pointer */
-                            )
-{
-    ec_data_reg_t *data_reg;
-    ec_sync_t *sync;
-    uint16_t sync_length;
-
-    if (!(sync = ec_slave_get_pdo_sync(slave, dir))) {
-        EC_ERR("No sync manager found for PDO range.\n");
-        return -1;
-    }
-
-    // Allocate memory for data registration object
-    if (!(data_reg =
-          (ec_data_reg_t *) kmalloc(sizeof(ec_data_reg_t), GFP_KERNEL))) {
-        EC_ERR("Failed to allocate data registration.\n");
-        return -1;
-    }
-
-    if (ec_slave_prepare_fmmu(slave, domain, sync)) {
-        EC_ERR("FMMU configuration failed.\n");
-        kfree(data_reg);
-        return -1;
-    }
-
-    data_reg->slave = slave;
-    data_reg->sync = sync;
-    data_reg->sync_offset = offset;
-    data_reg->data_ptr = data_ptr;
-
-    // estimate sync manager length
-    sync_length = offset + length;
-    if (sync->est_length < sync_length) {
-        sync->est_length = sync_length;
-        if (domain->master->debug_level) {
-            EC_DBG("Estimating length of sync manager %i of slave %i to %i.\n",
-                   sync->index, slave->ring_position, sync_length);
-        }
-    }
-
-    list_add_tail(&data_reg->list, &domain->data_regs);
-
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
    Clears the list of the data registrations.
 */
 
@@ -460,53 +402,44 @@
 
 /**
  * Registers a PDO for a domain.
- * \return pointer to the slave on success, else NULL
+ * \return 0 on success, else non-zero
  * \ingroup RealtimeInterface
  */
 
-ec_slave_t *ecrt_domain_register_pdo(
+int ecrt_domain_register_pdo(
         ec_domain_t *domain, /**< EtherCAT domain */
-        const char *address, /**< ASCII address of the slave,
-                               see ecrt_master_get_slave() */
-        uint32_t vendor_id, /**< vendor ID */
-        uint32_t product_code, /**< product code */
-        uint16_t entry_index, /**< PDO entry index */
-        uint8_t entry_subindex, /**< PDO entry subindex */
+        ec_slave_t *slave, /**< EtherCAT slave */
+        uint16_t pdo_entry_index, /**< PDO entry index */
+        uint8_t pdo_entry_subindex, /**< PDO entry subindex */
         void **data_ptr /**< address of the process data pointer */
         )
 {
-    ec_slave_t *slave;
-    ec_master_t *master;
     ec_sync_t *sync;
     const ec_pdo_t *pdo;
     const ec_pdo_entry_t *entry;
     unsigned int i;
 
-    master = domain->master;
-
-    // translate address and validate slave
-    if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
-    if (ec_slave_validate(slave, vendor_id, product_code)) return NULL;
-
+    // search for PDO entry
     for (i = 0; i < slave->sii_sync_count; i++) {
         sync = &slave->sii_syncs[i];
         list_for_each_entry(pdo, &sync->pdos, list) {
             list_for_each_entry(entry, &pdo->entries, list) {
-                if (entry->index != entry_index ||
-                        entry->subindex != entry_subindex) continue;
-
+                if (entry->index != pdo_entry_index ||
+                        entry->subindex != pdo_entry_subindex) continue;
+
+                // PDO entry found
                 if (ec_domain_reg_pdo_entry(domain, sync, entry, data_ptr)) {
-                    return NULL;
+                    return -1;
                 }
 
-                return slave;
+                return 0;
             }
         }
     }
 
     EC_ERR("PDO entry 0x%04X:%u is not mapped in slave %u.\n",
-           entry_index, entry_subindex, slave->ring_position);
-    return NULL;
+           pdo_entry_index, pdo_entry_subindex, slave->ring_position);
+    return -1;
 }
 
 /*****************************************************************************/
@@ -520,64 +453,82 @@
 
 int ecrt_domain_register_pdo_list(
         ec_domain_t *domain, /**< EtherCAT domain */
-        const ec_pdo_reg_t *pdos /**< array of PDO registrations */
+        const ec_pdo_reg_t *pdo_regs /**< array of PDO registrations */
         )
 {
-    const ec_pdo_reg_t *pdo;
-
-    for (pdo = pdos; pdo->slave_address; pdo++)
-        if (!ecrt_domain_register_pdo(domain, pdo->slave_address,
-                    pdo->vendor_id, pdo->product_code,
-                    pdo->pdo_entry_index, pdo->pdo_entry_subindex,
-                    pdo->data_ptr))
+    const ec_pdo_reg_t *reg;
+    ec_slave_t *slave;
+    
+    for (reg = pdo_regs; reg->slave_address; reg++) {
+        if (!(slave = ecrt_master_get_slave(domain->master,
+                        reg->slave_address, reg->vendor_id,
+                        reg->product_code)))
             return -1;
 
+        if (ecrt_domain_register_pdo(domain, slave, reg->pdo_entry_index,
+                    reg->pdo_entry_subindex, reg->data_ptr))
+            return -1;
+    }
+
     return 0;
 }
 
 /*****************************************************************************/
 
 /**
-   Registers a PDO range in a domain.
-   \return pointer to the slave on success, else NULL
-   \ingroup RealtimeInterface
-*/
-
-ec_slave_t *ecrt_domain_register_pdo_range(ec_domain_t *domain,
-                                           /**< EtherCAT domain */
-                                           const char *address,
-                                           /**< ASCII address of the slave,
-                                              see ecrt_master_get_slave() */
-                                           uint32_t vendor_id,
-                                           /**< vendor ID */
-                                           uint32_t product_code,
-                                           /**< product code */
-                                           ec_direction_t direction,
-                                           /**< data direction */
-                                           uint16_t offset,
-                                           /**< offset in slave's PDO range */
-                                           uint16_t length,
-                                           /**< length of this range */
-                                           void **data_ptr
-                                           /**< address of the process data
-                                              pointer */
-                                           )
-{
-    ec_slave_t *slave;
-    ec_master_t *master;
-
-    master = domain->master;
-
-    // translate address and validate slave
-    if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
-    if (ec_slave_validate(slave, vendor_id, product_code)) return NULL;
-
-    if (ec_domain_reg_pdo_range(domain, slave,
-                                direction, offset, length, data_ptr)) {
-        return NULL;
-    }
-
-    return slave;
+ * Registers a PDO range in a domain.
+ * \return 0 on success, else non-zero
+ * \ingroup RealtimeInterface
+ */
+
+int ecrt_domain_register_pdo_range(
+        ec_domain_t *domain, /**< EtherCAT domain */
+        ec_slave_t *slave, /**< EtherCAT slave */
+        ec_direction_t dir, /**< data direction */
+        uint16_t offset, /**< offset in slave's PDO range */
+        uint16_t length, /**< length of this range */
+        void **data_ptr /**< address of the process data pointer */
+        )
+{
+    ec_data_reg_t *data_reg;
+    ec_sync_t *sync;
+    uint16_t sync_length;
+
+    if (!(sync = ec_slave_get_pdo_sync(slave, dir))) {
+        EC_ERR("No sync manager found for PDO range.\n");
+        return -1;
+    }
+
+    // Allocate memory for data registration object
+    if (!(data_reg =
+          (ec_data_reg_t *) kmalloc(sizeof(ec_data_reg_t), GFP_KERNEL))) {
+        EC_ERR("Failed to allocate data registration.\n");
+        return -1;
+    }
+
+    if (ec_slave_prepare_fmmu(slave, domain, sync)) {
+        EC_ERR("FMMU configuration failed.\n");
+        kfree(data_reg);
+        return -1;
+    }
+
+    data_reg->slave = slave;
+    data_reg->sync = sync;
+    data_reg->sync_offset = offset;
+    data_reg->data_ptr = data_ptr;
+
+    // estimate sync manager length
+    sync_length = offset + length;
+    if (sync->est_length < sync_length) {
+        sync->est_length = sync_length;
+        if (domain->master->debug_level) {
+            EC_DBG("Estimating length of sync manager %i of slave %i to %i.\n",
+                   sync->index, slave->ring_position, sync_length);
+        }
+    }
+
+    list_add_tail(&data_reg->list, &domain->data_regs);
+    return 0;
 }
 
 /*****************************************************************************/
--- a/master/master.c	Thu Mar 08 18:15:25 2007 +0000
+++ b/master/master.c	Fri Mar 09 10:24:50 2007 +0000
@@ -1384,215 +1384,24 @@
     }
 }
 
-/******************************************************************************
- *  Realtime interface
- *****************************************************************************/
-
-/**
-   Creates a domain.
-   \return pointer to new domain on success, else NULL
-   \ingroup RealtimeInterface
-*/
-
-ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< master */)
-{
-    ec_domain_t *domain, *last_domain;
-    unsigned int index;
-
-    if (!(domain = (ec_domain_t *) kmalloc(sizeof(ec_domain_t), GFP_KERNEL))) {
-        EC_ERR("Error allocating domain memory!\n");
-        return NULL;
-    }
-
-    if (list_empty(&master->domains)) index = 0;
-    else {
-        last_domain = list_entry(master->domains.prev, ec_domain_t, list);
-        index = last_domain->index + 1;
-    }
-
-    if (ec_domain_init(domain, master, index)) {
-        EC_ERR("Failed to init domain.\n");
-        return NULL;
-    }
-
-    list_add_tail(&domain->list, &master->domains);
-
-    return domain;
-}
-
-/*****************************************************************************/
-
-/**
-   Configures all slaves and leads them to the OP state.
-   Does the complete configuration and activation for all slaves. Sets sync
-   managers and FMMUs, and does the appropriate transitions, until the slave
-   is operational.
-   \return 0 in case of success, else < 0
-   \ingroup RealtimeInterface
-*/
-
-int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */)
-{
-    uint32_t domain_offset;
-    ec_domain_t *domain;
-    ec_fsm_slave_t fsm_slave;
-    ec_slave_t *slave;
-
-    // allocate all domains
-    domain_offset = 0;
-    list_for_each_entry(domain, &master->domains, list) {
-        if (ec_domain_alloc(domain, domain_offset)) {
-            EC_ERR("Failed to allocate domain %X!\n", (u32) domain);
-            return -1;
-        }
-        domain_offset += domain->data_size;
-    }
-
-    ec_fsm_slave_init(&fsm_slave, &master->fsm_datagram);
-
-    // configure all slaves
-    list_for_each_entry(slave, &master->slaves, list) {
-        ec_fsm_slave_start_conf(&fsm_slave, slave);
-        while (ec_fsm_slave_exec(&fsm_slave)) { 
-            ec_master_queue_datagram(master, &master->fsm_datagram);
-            ec_master_sync_io(master);
-        }
-
-        if (!ec_fsm_slave_success(&fsm_slave)) {
-            ec_fsm_slave_clear(&fsm_slave);
-            EC_ERR("Failed to configure slave %i!\n", slave->ring_position);
-            return -1;
-        }
-    }
-
-    ec_fsm_slave_clear(&fsm_slave);
-    ec_master_prepare(master); // prepare asynchronous IO
-
-    if (master->debug_level)
-        EC_DBG("FSM datagram is %x.\n", (unsigned int) &master->fsm_datagram);
-
-    if (ec_master_thread_start(master)) {
-        EC_ERR("Failed to start master thread!\n");
-        return -1;
-    }
-
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
-   Sends queued datagrams and waits for their reception.
-*/
-
-void ec_master_sync_io(ec_master_t *master /**< EtherCAT master */)
-{
-    ec_datagram_t *datagram;
-    unsigned int datagrams_sent;
-
-    // send all datagrams
-    ecrt_master_send(master);
-
-    while (1) { // active waiting
-        schedule(); // schedule other processes while waiting.
-        ecrt_master_receive(master); // receive and dequeue datagrams
-
-        // count number of datagrams still waiting for response
-        datagrams_sent = 0;
-        list_for_each_entry(datagram, &master->datagram_queue, queue) {
-            // there may be another process that queued commands
-            // in the meantime.
-            if (datagram->state == EC_DATAGRAM_QUEUED) continue;
-            datagrams_sent++;
-        }
-
-        // abort loop if there are no more datagrams marked as sent.
-        if (!datagrams_sent) break;
-    }
-}
-
-/*****************************************************************************/
-
-/**
-   Asynchronous sending of datagrams.
-   \ingroup RealtimeInterface
-*/
-
-void ecrt_master_send(ec_master_t *master /**< EtherCAT master */)
-{
-    ec_datagram_t *datagram, *n;
-
-    if (master->injection_seq_rt != master->injection_seq_fsm) {
-        // inject datagram produced by master FSM
-        ec_master_queue_datagram(master, &master->fsm_datagram);
-        master->injection_seq_rt = master->injection_seq_fsm;
-    }
-
-    if (unlikely(!master->main_device.link_state)) {
-        // link is down, no datagram can be sent
-        list_for_each_entry_safe(datagram, n, &master->datagram_queue, queue) {
-            datagram->state = EC_DATAGRAM_ERROR;
-            list_del_init(&datagram->queue);
-        }
-
-        // query link state
-        ec_device_poll(&master->main_device);
-        return;
-    }
-
-    // send frames
-    ec_master_send_datagrams(master);
-}
-
-/*****************************************************************************/
-
-/**
-   Asynchronous receiving of datagrams.
-   \ingroup RealtimeInterface
-*/
-
-void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */)
-{
-    ec_datagram_t *datagram, *next;
-    cycles_t cycles_timeout;
-
-    // receive datagrams
-    ec_device_poll(&master->main_device);
-
-    cycles_timeout = (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000);
-
-    // dequeue all datagrams that timed out
-    list_for_each_entry_safe(datagram, next, &master->datagram_queue, queue) {
-        if (datagram->state != EC_DATAGRAM_SENT) continue;
-
-        if (master->main_device.cycles_poll - datagram->cycles_sent
-            > cycles_timeout) {
-            list_del_init(&datagram->queue);
-            datagram->state = EC_DATAGRAM_TIMED_OUT;
-            master->stats.timeouts++;
-            ec_master_output_stats(master);
-        }
-    }
-}
-
-/*****************************************************************************/
-
-/**
-   Translates an ASCII coded bus-address to a slave pointer.
-   These are the valid addressing schemes:
-   - \a "X" = the X. slave on the bus,
-   - \a "X:Y" = the Y. slave after the X. branch (bus coupler),
-   - \a "#X" = the slave with alias X,
-   - \a "#X:Y" = the Y. slave after the branch (bus coupler) with alias X.
-   X and Y are zero-based indices and may be provided in hexadecimal or octal
-   notation (with respective prefix).
-   \return pointer to the slave on success, else NULL
-   \ingroup RealtimeInterface
-*/
-
-ec_slave_t *ecrt_master_get_slave(const ec_master_t *master, /**< Master */
-                                  const char *address /**< address string */
-                                  )
+/*****************************************************************************/
+
+/**
+ * Translates an ASCII coded bus-address to a slave pointer.
+ * These are the valid addressing schemes:
+ * - \a "X" = the X. slave on the bus (ring position),
+ * - \a "X:Y" = the Y. slave after the X. branch (bus coupler),
+ * - \a "#X" = the slave with alias X,
+ * - \a "#X:Y" = the Y. slave after the branch (bus coupler) with alias X.
+ * X and Y are zero-based indices and may be provided in hexadecimal or octal
+ * notation (with respective prefix).
+ * \return pointer to the slave on success, else NULL
+ */
+
+ec_slave_t *ec_master_parse_slave_address(
+        const ec_master_t *master, /**< EtherCAT master */
+        const char *address /**< address string */
+        )
 {
     unsigned long first, second;
     char *remainder, *remainder2;
@@ -1685,6 +1494,224 @@
     return NULL;
 }
 
+
+/******************************************************************************
+ *  Realtime interface
+ *****************************************************************************/
+
+/**
+   Creates a domain.
+   \return pointer to new domain on success, else NULL
+   \ingroup RealtimeInterface
+*/
+
+ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< master */)
+{
+    ec_domain_t *domain, *last_domain;
+    unsigned int index;
+
+    if (!(domain = (ec_domain_t *) kmalloc(sizeof(ec_domain_t), GFP_KERNEL))) {
+        EC_ERR("Error allocating domain memory!\n");
+        return NULL;
+    }
+
+    if (list_empty(&master->domains)) index = 0;
+    else {
+        last_domain = list_entry(master->domains.prev, ec_domain_t, list);
+        index = last_domain->index + 1;
+    }
+
+    if (ec_domain_init(domain, master, index)) {
+        EC_ERR("Failed to init domain.\n");
+        return NULL;
+    }
+
+    list_add_tail(&domain->list, &master->domains);
+
+    return domain;
+}
+
+/*****************************************************************************/
+
+/**
+   Configures all slaves and leads them to the OP state.
+   Does the complete configuration and activation for all slaves. Sets sync
+   managers and FMMUs, and does the appropriate transitions, until the slave
+   is operational.
+   \return 0 in case of success, else < 0
+   \ingroup RealtimeInterface
+*/
+
+int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */)
+{
+    uint32_t domain_offset;
+    ec_domain_t *domain;
+    ec_fsm_slave_t fsm_slave;
+    ec_slave_t *slave;
+
+    // allocate all domains
+    domain_offset = 0;
+    list_for_each_entry(domain, &master->domains, list) {
+        if (ec_domain_alloc(domain, domain_offset)) {
+            EC_ERR("Failed to allocate domain %X!\n", (u32) domain);
+            return -1;
+        }
+        domain_offset += domain->data_size;
+    }
+
+    ec_fsm_slave_init(&fsm_slave, &master->fsm_datagram);
+
+    // configure all slaves
+    list_for_each_entry(slave, &master->slaves, list) {
+        ec_fsm_slave_start_conf(&fsm_slave, slave);
+        while (ec_fsm_slave_exec(&fsm_slave)) { 
+            ec_master_queue_datagram(master, &master->fsm_datagram);
+            ec_master_sync_io(master);
+        }
+
+        if (!ec_fsm_slave_success(&fsm_slave)) {
+            ec_fsm_slave_clear(&fsm_slave);
+            EC_ERR("Failed to configure slave %i!\n", slave->ring_position);
+            return -1;
+        }
+    }
+
+    ec_fsm_slave_clear(&fsm_slave);
+    ec_master_prepare(master); // prepare asynchronous IO
+
+    if (master->debug_level)
+        EC_DBG("FSM datagram is %x.\n", (unsigned int) &master->fsm_datagram);
+
+    if (ec_master_thread_start(master)) {
+        EC_ERR("Failed to start master thread!\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/**
+   Sends queued datagrams and waits for their reception.
+*/
+
+void ec_master_sync_io(ec_master_t *master /**< EtherCAT master */)
+{
+    ec_datagram_t *datagram;
+    unsigned int datagrams_sent;
+
+    // send all datagrams
+    ecrt_master_send(master);
+
+    while (1) { // active waiting
+        schedule(); // schedule other processes while waiting.
+        ecrt_master_receive(master); // receive and dequeue datagrams
+
+        // count number of datagrams still waiting for response
+        datagrams_sent = 0;
+        list_for_each_entry(datagram, &master->datagram_queue, queue) {
+            // there may be another process that queued commands
+            // in the meantime.
+            if (datagram->state == EC_DATAGRAM_QUEUED) continue;
+            datagrams_sent++;
+        }
+
+        // abort loop if there are no more datagrams marked as sent.
+        if (!datagrams_sent) break;
+    }
+}
+
+/*****************************************************************************/
+
+/**
+   Asynchronous sending of datagrams.
+   \ingroup RealtimeInterface
+*/
+
+void ecrt_master_send(ec_master_t *master /**< EtherCAT master */)
+{
+    ec_datagram_t *datagram, *n;
+
+    if (master->injection_seq_rt != master->injection_seq_fsm) {
+        // inject datagram produced by master FSM
+        ec_master_queue_datagram(master, &master->fsm_datagram);
+        master->injection_seq_rt = master->injection_seq_fsm;
+    }
+
+    if (unlikely(!master->main_device.link_state)) {
+        // link is down, no datagram can be sent
+        list_for_each_entry_safe(datagram, n, &master->datagram_queue, queue) {
+            datagram->state = EC_DATAGRAM_ERROR;
+            list_del_init(&datagram->queue);
+        }
+
+        // query link state
+        ec_device_poll(&master->main_device);
+        return;
+    }
+
+    // send frames
+    ec_master_send_datagrams(master);
+}
+
+/*****************************************************************************/
+
+/**
+   Asynchronous receiving of datagrams.
+   \ingroup RealtimeInterface
+*/
+
+void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */)
+{
+    ec_datagram_t *datagram, *next;
+    cycles_t cycles_timeout;
+
+    // receive datagrams
+    ec_device_poll(&master->main_device);
+
+    cycles_timeout = (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000);
+
+    // dequeue all datagrams that timed out
+    list_for_each_entry_safe(datagram, next, &master->datagram_queue, queue) {
+        if (datagram->state != EC_DATAGRAM_SENT) continue;
+
+        if (master->main_device.cycles_poll - datagram->cycles_sent
+            > cycles_timeout) {
+            list_del_init(&datagram->queue);
+            datagram->state = EC_DATAGRAM_TIMED_OUT;
+            master->stats.timeouts++;
+            ec_master_output_stats(master);
+        }
+    }
+}
+
+/*****************************************************************************/
+
+/**
+ * Obtains a slave pointer by its bus address.
+ * A valid slave pointer is only returned, if vendor ID and product code are
+ * matching.
+ * \return pointer to the slave on success, else NULL
+ * \ingroup RealtimeInterface
+ */
+
+ec_slave_t *ecrt_master_get_slave(
+        const ec_master_t *master, /**< EtherCAT master */
+        const char *address, /**< address string
+                               \see ec_master_parse_slave_address() */
+        uint32_t vendor_id, /**< vendor ID */
+        uint32_t product_code /**< product code */
+        )
+{
+    ec_slave_t *slave = ec_master_parse_slave_address(master, address);
+
+    if (!slave)
+        return NULL;
+
+    return ec_slave_validate(slave, vendor_id, product_code) ? NULL : slave;
+}
+
 /*****************************************************************************/
 
 /**