Implemented most realtime interface changes for version 1.4, improved
authorFlorian Pose <fp@igh-essen.com>
Tue, 19 Feb 2008 08:22:20 +0000
changeset 792 3778920f61e4
parent 791 3b81d074735c
child 793 3b297ff8284f
Implemented most realtime interface changes for version 1.4, improved
ec_pdo_t and ec_pdo_entry_t classes, added fmmu_config_t, adjusted
minimal example, etc...
NEWS
TODO
documentation/graphs/fsm_slave_conf.dot
examples/mini/mini.c
include/ecrt.h
master/Kbuild.in
master/Makefile.am
master/domain.c
master/domain.h
master/fmmu.c
master/fmmu.h
master/fmmu_config.c
master/fmmu_config.h
master/fsm_coe_map.c
master/fsm_coe_map.h
master/fsm_mapping.c
master/fsm_mapping.h
master/fsm_master.c
master/fsm_master.h
master/fsm_slave.c
master/globals.h
master/master.c
master/master.h
master/module.c
master/pdo.c
master/pdo.h
master/pdo_mapping.c
master/pdo_mapping.h
master/slave.c
master/slave.h
master/slave_config.c
master/slave_config.h
master/sync.c
master/sync.h
--- a/NEWS	Thu Feb 14 09:18:55 2008 +0000
+++ b/NEWS	Tue Feb 19 08:22:20 2008 +0000
@@ -6,6 +6,40 @@
 
 Changes in version 1.4.0:
 
+* Realtime interface changes:
+    - Replaced ec_slave_t with ec_slave_config_t, separating the slave objects
+      from the requested bus configuration. Therefore, renamed
+      ecrt_master_get_slave() to ecrt_master_slave_config().
+    - Replaced slave address string with alias and position values. See
+      ecrt_master_slave_config().
+    - Removed ecrt_master_get_slave_by_pos(), because it is no longer
+      necessary (alias/position, slave configurations).
+    - Added ec_slave_config_state_t for the new method
+      ecrt_slave_config_state().
+    - Process data memory for a domain can now be allocated externally. This
+      offers the possibility to use a shared-memory-region. Therefore,
+      added the domain methods ecrt_domain_size() and ecrt_domain_memory().
+    - Replaced the process data pointers in the Pdo entry registration
+      functions with a process data offset, that is now returned by
+      ecrt_domain_reg_pdo_entry(). This was necessary for the external
+      domain memory. An additional advantage is, that the returned offset value
+      is directly usable.
+    - Replaced ecrt_slave_pdo_mapping/add/clear() with
+      ecrt_slave_config_mapping() that is now able to specify Pdo mapping and
+      Pdo configuration. Pdo entries mapped in this way can now immediately be
+      registered. The Pdo mapping and the configuration are described with the
+      new data types ec_pdo_info_t and ec_pdo_entry_info_t.
+    - Renamed ec_bus_status_t, ec_master_status_t to ec_bus_state_t and
+      ec_master_state_t, respectively. Renamed ecrt_master_get_status() to
+      ecrt_master_state(), for consistency reasons.
+    - Added ec_domain_state_t and ec_wc_state_t for a new output parameter
+      of ecrt_domain_state().
+    - Former "Pdo registration" meant Pdo entry registration in fact, therefore
+      renamed ec_pdo_reg_t to ec_pdo_entry_reg_t and ecrt_domain_register_pdo()
+      to ecrt_domain_reg_pdo_entry().
+    - Removed ecrt_domain_register_pdo_range(), because it's functionality can
+      be reached by specifying an explicit Pdo mapping and registering those
+      Pdo entries.
 * Added 8139too driver for kernel 2.6.22, thanks to Erwin Burgstaller.
 * Added e1000 driver for kernel 2.6.22.
 * Allow gaps in PDO mapping read from CoE.
--- a/TODO	Thu Feb 14 09:18:55 2008 +0000
+++ b/TODO	Tue Feb 19 08:22:20 2008 +0000
@@ -11,9 +11,7 @@
 * Realtime interface changes:
     - PDO configuration.
     - SDO access.
-    - Replace process data pointers with offset.
     - External memory for domains.
-    - Separate slave configuration from slave structure.
 * Mailbox handler
 * Read PDO mapping via CoE during bus scan.
 * SDO write access in sysfs.
@@ -22,6 +20,11 @@
 * Remove ecdb.h and let lsec output PDO information 'cut-and-pastable' for
   applications.
 * Update documentation.
+* READMEs for examples.
+* Calculate expected working counter for domains.
+* Distributed clocks.
+* Support slaves, that don't support the LRW datagram, only LRD/LWR.
+* Implement all EtherCAT datagram types.
 
 Future issues:
 
@@ -30,10 +33,7 @@
               to replace lsec.
     - Step 2: Move kernel threads to user space daemon with a TCP interface
               replacing the cdev.
-* Distributed clocks.
 * Redundancy with 2 network adapters.
-* Support slaves, that don't support the LRW datagram, only LRD/LWR.
-* PDO reading in IDLE mode.
 * Interface/buffers for asynchronous domain IO.
 
 Smaller issues:
@@ -42,12 +42,9 @@
 * Clear sync managers in INIT.
 * Simplify FSMs with <state>_enter() functions.
 * Read out CRC counters.
-* Calculate expected working counter for domains.
 * Optimize alignment of process data.
 * Evaluate EEPROM contents after writing.
 * Configure slave ports to automatically open on link detection.
-* Calculate cycle time of operation state machine.
-* Locking for serveral slave variables for sysfs access.
 * Interrupt master state machines state scan for other jobs.
 * Master state machine, slave configuration: Do not check every slave on
   a cycle.
@@ -55,7 +52,6 @@
 
 Less important issues:
 
-* Implement all EtherCAT datagram types.
 * File access over EtherCAT (FoE).
 * Allow VLAN tagging.
 * Determine number of frames, the NIC can handle.
--- a/documentation/graphs/fsm_slave_conf.dot	Thu Feb 14 09:18:55 2008 +0000
+++ b/documentation/graphs/fsm_slave_conf.dot	Tue Feb 19 08:22:20 2008 +0000
@@ -8,6 +8,7 @@
     enter_sdoconf [shape=point,label=""]
     enter_mapconf [shape=point,label=""]
     enter_pdo_sync [shape=point,label=""]
+    enter_saveop [shape=point,label=""]
 
     start -> init [weight=10]
     init -> init
@@ -18,8 +19,8 @@
     clear_fmmus -> error
     clear_fmmus -> enter_mbox_sync [weight=10]
     enter_mbox_sync -> end [label="INIT req."]
-    enter_mbox_sync -> preop
-    enter_mbox_sync -> mbox_sync [label="mailbox SMs", weight=10]
+    enter_mbox_sync -> preop [label="No mailboxes"]
+    enter_mbox_sync -> mbox_sync [label="Has mailboxes", weight=10]
     mbox_sync -> mbox_sync
     mbox_sync -> error
     mbox_sync -> preop [weight=10]
@@ -27,8 +28,9 @@
     preop -> error
     preop -> end [label="PREOP req."]
     preop -> enter_sdoconf [weight=10]
-    enter_sdoconf -> enter_mapconf
-    enter_sdoconf -> sdoconf [label="SDOs to configure", weight=10]
+    enter_sdoconf -> enter_saveop [label="No configuration"]
+    enter_sdoconf -> enter_mapconf [label="No SDO configs"]
+    enter_sdoconf -> sdoconf [label="SDO configs", weight=10]
     sdoconf -> sdoconf
     sdoconf -> error
     sdoconf -> enter_mapconf [weight=10]
@@ -42,11 +44,12 @@
     pdo_sync -> pdo_sync
     pdo_sync -> error
     pdo_sync -> enter_fmmu [weight=10]
-    enter_fmmu -> saveop
+    enter_fmmu -> enter_saveop
     enter_fmmu -> fmmu [label="FMMUs to configure", weight=10]
     fmmu -> fmmu
     fmmu -> error
-    fmmu -> saveop [weight=10]
+    fmmu -> enter_saveop [weight=10]
+    enter_saveop -> saveop
     saveop -> saveop
     saveop -> error
     saveop -> end [label="SAVEOP req."]
--- a/examples/mini/mini.c	Thu Feb 14 09:18:55 2008 +0000
+++ b/examples/mini/mini.c	Tue Feb 19 08:22:20 2008 +0000
@@ -44,6 +44,8 @@
 #define FREQUENCY 100
 
 //#define KBUS
+#define PDOS
+#define MAPPING
 
 /*****************************************************************************/
 
@@ -53,7 +55,7 @@
 static ec_master_t *master = NULL;
 static ec_domain_t *domain1 = NULL;
 spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
-static ec_master_status_t master_status, old_status = {};
+static ec_master_state_t master_state, old_state = {};
 
 // data fields
 #ifdef KBUS
@@ -61,17 +63,20 @@
 static void *r_outputs;
 #endif
 
-static void *r_dig_out;
-static void *r_ana_out;
-static void *r_count;
-static void *r_freq;
-
-#if 1
-const static ec_pdo_reg_t domain1_pdo_regs[] = {
-    {"2",      Beckhoff_EL2004_Outputs,   &r_dig_out},
-    {"3",      Beckhoff_EL4132_Output1,   &r_ana_out},
-    {"#888:1", Beckhoff_EL5101_Value,     &r_count},
-    {"4",      Beckhoff_EL5101_Frequency, &r_freq},
+#ifdef MAPPING
+const ec_pdo_info_t mapping[] = {
+    {EC_DIR_INPUT, 0x1A00}, // channel 1
+    {EC_DIR_INPUT, 0x1A01} // channel 2
+};
+#endif
+
+#ifdef PDOS
+static uint8_t off_ana_in;
+static uint8_t off_ana_out;
+
+const static ec_pdo_entry_reg_t domain1_regs[] = {
+    {0, 1, Beckhoff_EL3162, 0x3101, 2, &off_ana_in},
+    {0, 2, Beckhoff_EL4102, 0x3001, 1, &off_ana_out},
     {}
 };
 #endif
@@ -91,7 +96,7 @@
 
     // process data
     // k_pos = EC_READ_U32(r_ssi);
-    EC_WRITE_U8(r_dig_out, blink ? 0x0F : 0x00);
+    //EC_WRITE_U8(r_dig_out, blink ? 0x0F : 0x00);
 
     if (counter) {
         counter--;
@@ -101,24 +106,24 @@
         blink = !blink;
 
         spin_lock(&master_lock);
-        ecrt_master_get_status(master, &master_status);
+        ecrt_master_state(master, &master_state);
         spin_unlock(&master_lock);
 
-        if (master_status.bus_status != old_status.bus_status) {
-            printk(KERN_INFO PFX "bus status changed to %i.\n",
-                    master_status.bus_status);
+        if (master_state.bus_state != old_state.bus_state) {
+            printk(KERN_INFO PFX "bus state changed to %i.\n",
+                    master_state.bus_state);
         }
-        if (master_status.bus_tainted != old_status.bus_tainted) {
+        if (master_state.bus_tainted != old_state.bus_tainted) {
             printk(KERN_INFO PFX "tainted flag changed to %u.\n",
-                    master_status.bus_tainted);
+                    master_state.bus_tainted);
         }
-        if (master_status.slaves_responding !=
-                old_status.slaves_responding) {
+        if (master_state.slaves_responding !=
+                old_state.slaves_responding) {
             printk(KERN_INFO PFX "slaves_responding changed to %u.\n",
-                    master_status.slaves_responding);
+                    master_state.slaves_responding);
         }
        
-        old_status = master_status;
+        old_state = master_state;
     }
 
 #ifdef KBUS
@@ -158,10 +163,10 @@
 
 int __init init_mini_module(void)
 {
-#if 1
-    ec_slave_t *slave;
-#endif
-
+#ifdef MAPPING
+    ec_slave_config_t *sc;
+#endif
+    
     printk(KERN_INFO PFX "Starting...\n");
 
     if (!(master = ecrt_request_master(0))) {
@@ -177,49 +182,25 @@
         goto out_release_master;
     }
 
-#if 1
-    printk(KERN_INFO PFX "Configuring alternative PDO mapping...\n");
-    if (!(slave = ecrt_master_get_slave(master, "4", Beckhoff_EL5101)))
-        goto out_release_master;
-
-    if (ecrt_slave_pdo_mapping(slave, EC_DIR_INPUT, 2, 0x1A00, 0x1A02))
-        goto out_release_master;
-#endif
-
-    printk(KERN_INFO PFX "Registering PDOs...\n");
-#if 1
-    if (ecrt_domain_register_pdo_list(domain1, domain1_pdo_regs)) {
-        printk(KERN_ERR PFX "PDO registration failed!\n");
-        goto out_release_master;
-    }
-#endif
-
-#ifdef KBUS
-    if (!(slave = ecrt_master_get_slave(master, "0", Beckhoff_BK1120)))
-        goto out_release_master;
-    
-    if (!ecrt_domain_register_pdo_range(
-                domain1, slave, EC_DIR_OUTPUT, 0, 4, &r_outputs)) {
-        printk(KERN_ERR PFX "PDO registration failed!\n");
-        goto out_release_master;
-    }
-    
-    if (!ecrt_domain_register_pdo_range(
-                domain1, slave, EC_DIR_INPUT, 0, 4, &r_inputs)) {
-        printk(KERN_ERR PFX "PDO registration failed!\n");
-        goto out_release_master;
-    }
-#endif
-
-#if 0
-    if (!(slave = ecrt_master_get_slave(master, "4", Beckhoff_EL5001)))
-        goto out_release_master;
-
-    if (ecrt_slave_conf_sdo8(slave, 0x4061, 1, 0))
-        goto out_release_master;
-#endif
-
-#if 1
+#ifdef MAPPING
+    printk(KERN_INFO PFX "Configuring Pdo mapping...\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 (ecrt_slave_config_mapping(sc, 2, mapping)) {
+        printk(KERN_ERR PFX "Failed to configure Pdo mapping.\n");
+        goto out_release_master;
+    }
+#endif
+
+    printk(KERN_INFO PFX "Registering PDO entries...\n");
+#ifdef PDOS
+    if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
+        printk(KERN_ERR PFX "PDO entry registration failed!\n");
+        goto out_release_master;
+    }
 #endif
 
     printk(KERN_INFO PFX "Activating master...\n");
--- a/include/ecrt.h	Thu Feb 14 09:18:55 2008 +0000
+++ b/include/ecrt.h	Tue Feb 19 08:22:20 2008 +0000
@@ -41,6 +41,44 @@
  * realtime modules that want to use EtherCAT. There are functions to request
  * a master, to map process data, to communicate with slaves via CoE and to
  * configure and activate the bus.
+ *
+ * Changes in Version 1.4:
+ *
+ * - Replaced ec_slave_t with ec_slave_config_t, separating the slave objects
+ *   from the requested bus configuration. Therefore, renamed
+ *   ecrt_master_get_slave() to ecrt_master_slave_config().
+ * - Replaced slave address string with alias and position values. See
+ *   ecrt_master_slave_config().
+ * - Removed ecrt_master_get_slave_by_pos(), because it is no longer
+ *   necessary (alias/position, slave configurations).
+ * - Added ec_slave_config_state_t for the new method
+ *   ecrt_slave_config_state().
+ * - Process data memory for a domain can now be allocated externally. This
+ *   offers the possibility to use a shared-memory-region. Therefore,
+ *   added the domain methods ecrt_domain_size() and ecrt_domain_memory().
+ * - Replaced the process data pointers in the Pdo entry registration
+ *   functions with a process data offset, that is now returned by
+ *   ecrt_domain_reg_pdo_entry(). This was necessary for the external
+ *   domain memory. An additional advantage is, that the returned offset value
+ *   is directly usable.
+ * - Replaced ecrt_slave_pdo_mapping/add/clear() with
+ *   ecrt_slave_config_mapping() that is now able to specify Pdo mapping and
+ *   Pdo configuration. Pdo entries mapped in this way can now immediately be
+ *   registered. The Pdo mapping and the configuration are described with the
+ *   new data types ec_pdo_info_t and ec_pdo_entry_info_t.
+ * - Renamed ec_bus_status_t, ec_master_status_t to ec_bus_state_t and
+ *   ec_master_state_t, respectively. Renamed ecrt_master_get_status() to
+ *   ecrt_master_state(), for consistency reasons.
+ * - Added ec_domain_state_t and ec_wc_state_t for a new output parameter
+ *   of ecrt_domain_state().
+ * - Former "Pdo registration" meant Pdo entry registration in fact, therefore
+ *   renamed ec_pdo_reg_t to ec_pdo_entry_reg_t and ecrt_domain_register_pdo()
+ *   to ecrt_domain_reg_pdo_entry().
+ * - Removed ecrt_domain_register_pdo_range(), because it's functionality can
+ *   be reached by specifying an explicit Pdo mapping and registering those
+ *   Pdo entries.
+ *
+ * @{
  */
 
 /*****************************************************************************/
@@ -83,127 +121,422 @@
 struct ec_master;
 typedef struct ec_master ec_master_t; /**< \see ec_master */
 
+struct ec_slave_config;
+typedef struct ec_slave_config ec_slave_config_t; /**< \see ec_slave_config */
+
 struct ec_domain;
 typedef struct ec_domain ec_domain_t; /**< \see ec_domain */
 
-struct ec_slave;
-typedef struct ec_slave ec_slave_t; /**< \see ec_slave */
-
-/*****************************************************************************/
-
-/** Bus status.
- * This is used in ec_master_status_t.
+/*****************************************************************************/
+
+/** Bus state.
+ *
+ * This is used in ec_master_state_t.
  */
 typedef enum {
-    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;
-
-/*****************************************************************************/
-
-/** Master status.
- * This is used for the output parameter of ecrt_master_get_status().
+    EC_BUS_FAILURE = -1, /**< At least one configured slave is offline. */
+    EC_BUS_OK            /**< All configured slaves are online. */
+} ec_bus_state_t;
+
+/*****************************************************************************/
+
+/** Master state.
+ *
+ * This is used for the output parameter of ecrt_master_state().
  */
 typedef struct {
-    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 responding slaves */
-}
-ec_master_status_t;
-
-/*****************************************************************************/
-
-/** List entry for domain PDO registrations.
- * This type is used as a parameter for the ecrt_domain_register_pdo_list()
- * convenience function.
+    ec_bus_state_t bus_state; /**< \see ec_bus_state_t */
+    unsigned int bus_tainted; /**< Non-zero, if the bus topology differs from
+                                the requested configuration. */
+    unsigned int slaves_responding; /**< Number of slaves in the bus. */
+} ec_master_state_t;
+
+/*****************************************************************************/
+
+/** Slave configuration state.
+ *
+ * \see ecrt_slave_config_state().
+ */
+typedef struct  {
+    unsigned int online : 1; /**< The slave is online. */
+    unsigned int configured : 1; /**< The slave was configured according to
+                                   the specified configuration. */
+} ec_slave_config_state_t;
+
+/*****************************************************************************/
+
+/** Domain working counter interpretation.
+ *
+ * This is used in ec_domain_state_t.
+ */
+typedef enum {
+    EC_WC_ZERO = 0,   /**< No Pdos were exchanged. */
+    EC_WC_INCOMPLETE, /**< Some of the registered Pdos were exchanged. */
+    EC_WC_COMPLETE    /**< All registered Pdos were exchanged. */
+} ec_wc_state_t;
+
+/*****************************************************************************/
+
+/** Domain state.
+ *
+ * This is used for the output parameter of ecrt_domain_state().
  */
 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 */
-    uint8_t pdo_entry_subindex; /**< PDO entry subindex */
-    void **data_ptr; /**< address of the process data pointer */
-}
-ec_pdo_reg_t;
-
-/*****************************************************************************/
-
-/** Direction type for PDO mapping and range registration functions.
+    unsigned int working_counter; /**< Value of the last working counter. */
+    ec_wc_state_t wc_state; /**< Working counter interpretation. */
+} ec_domain_state_t;
+
+/*****************************************************************************/
+
+/** Direction type for Pdo mapping functions.
  */
 typedef enum {
-    EC_DIR_OUTPUT, /**< values written by master */
-    EC_DIR_INPUT   /**< values read by master */
-}
-ec_direction_t;
+    EC_DIR_OUTPUT, /**< Values written by the master. */
+    EC_DIR_INPUT   /**< Values read by the master. */
+} ec_direction_t;
+
+/*****************************************************************************/
+
+/** Pdo entry mapping.
+ *
+ * \see ecrt_slave_config_mapping().
+ */
+typedef struct {
+    uint16_t index; /**< Index of the Pdo entry to add to the Pdo
+                            configuration. */
+    uint8_t subindex; /**< Subindex of the Pdo entry to add to the
+                              Pdo configuration. */
+    uint8_t bit_length; /**< Size of the Pdo entry in bit. */
+} ec_pdo_entry_info_t;
+
+/*****************************************************************************/
+
+/** Pdo information.
+ *
+ * \see ecrt_slave_config_mapping().
+ */
+typedef struct {
+    ec_direction_t dir; /**< Pdo direction (input/output). */
+    uint16_t index; /**< Index of the Pdo to map. */
+    unsigned int n_entries; /**< Number of Pdo entries for the Pdo
+                              configuration. Zero means, that the default Pdo
+                              configuration shall be used. */
+    const ec_pdo_entry_info_t entries[]; /**< Pdo configuration list. */
+} ec_pdo_info_t;
+
+/*****************************************************************************/
+
+/** List record type for Pdo entry mass-registration.
+ *
+ * This type is used for the array parameter of the
+ * ecrt_domain_reg_pdo_entry_list() convenience function.
+ */
+typedef struct {
+    uint16_t alias; /**< Slave alias address. */
+    uint16_t position; /**< Slave position. */
+    uint32_t vendor_id; /**< Slave vendor ID. */
+    uint32_t product_code; /**< Slave product code. */
+    uint16_t index; /**< Pdo entry index. */
+    uint8_t subindex; /**< Pdo entry subindex. */
+    uint8_t *offset; /**< Pointer to a variable to store the Pdo's
+                       offset in the process data. */
+} ec_pdo_entry_reg_t;
 
 /******************************************************************************
  * Global functions
  *****************************************************************************/
 
-ec_master_t *ecrt_request_master(unsigned int master_index);
-void ecrt_release_master(ec_master_t *master);
-
+/** Returns the version magic of the realtime interface.
+ *
+ * \return Value of ECRT_VERSION_MAGIC() at EtherCAT master compile time.
+ */
 unsigned int ecrt_version_magic(void);
 
+/** Requests an EtherCAT master for realtime operation.
+ * 
+ * \return pointer to reserved master, or NULL on error
+ */
+ec_master_t *ecrt_request_master(
+        unsigned int master_index /**< Index of the master to request. */
+        );
+
+/** Releases a requested EtherCAT master.
+ */
+void ecrt_release_master(
+        ec_master_t *master /**< EtherCAT master */
+        );
+
 /******************************************************************************
  * Master methods
  *****************************************************************************/
 
-void ecrt_master_callbacks(ec_master_t *master, int (*request_cb)(void *),
-                           void (*release_cb)(void *), void *cb_data);
-
-ec_domain_t *ecrt_master_create_domain(ec_master_t *master);
-
-ec_slave_t *ecrt_master_get_slave(const ec_master_t *master,
-        const char *address, uint32_t vendor_id, uint32_t product_code);
-ec_slave_t *ecrt_master_get_slave_by_pos(const ec_master_t *master,
-        uint16_t position, 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);
-
-void ecrt_master_get_status(const ec_master_t *master, ec_master_status_t *s);
+/** 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.
+ */
+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. */
+        );
+
+/** Creates a new domain.
+ *
+ * \return Pointer to the new domain on success, else NULL.
+ */
+ec_domain_t *ecrt_master_create_domain(
+        ec_master_t *master /**< EtherCAT master. */
+        );
+
+/** Obtains a slave configuration.
+ *
+ * Creates a slave configuration object for the given \a alias and \a position
+ * tuple and returns it. If a configuration with the same \a alias and \a
+ * position already exists, it will be re-used. In the latter case, the given
+ * vendor ID and product code are compared to the stored ones. On mismatch, an
+ * error message is raised and the function returns \a NULL.
+ *
+ * Slaves are addressed with the \a alias and \a position parameters.
+ * - If \a alias is zero, \a position is interpreted as the desired slave's
+ *   ring position.
+ * - If \a alias is non-zero, it matches a slave with the given alias. In this
+ *   case, \a position is interpreted as ring offset, starting from the
+ *   aliased slave, so a position of zero means the aliased slave itself and a
+ *   positive value matches the n-th slave behind the aliased one.
+ *
+ * If the slave with the given address is found during the bus configuration,
+ * its vendor ID and product code are matched against the given value. On
+ * mismatch, the slave is not configured and an error message is raised.
+ *
+ * If different slave configurations are pointing to the same slave during bus
+ * configuration, a warning is raised and only the first configuration is
+ * applied.
+ *
+ * \retval >0 Pointer to the slave configuration structure.
+ * \retval NULL in the error case.
+ */
+ec_slave_config_t *ecrt_master_slave_config(
+        ec_master_t *master, /**< EtherCAT master */
+        uint16_t alias, /**< Slave alias. */
+        uint16_t position, /**< Slave position. */
+        uint32_t vendor_id, /**< Expected vendor ID. */
+        uint32_t product_code /**< Expected product code. */
+        );
+
+/** Applies the bus configuration and switches to realtime mode.
+ *
+ * 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
+ */
+int ecrt_master_activate(
+        ec_master_t *master /**< EtherCAT master. */
+        );
+
+/** Sends all datagrams in the queue.
+ *
+ * \todo doc
+ */
+void ecrt_master_send(
+        ec_master_t *master /**< EtherCAT master. */
+        );
+
+/** Fetches received frames from the hardware and processes the datagrams.
+ */
+void ecrt_master_receive(
+        ec_master_t *master /**< EtherCAT master. */
+        );
+
+/** Reads the current master state.
+ *
+ * Stores the master state information in the given \a state structure.
+ */
+void ecrt_master_state(
+        const ec_master_t *master, /**< EtherCAT master. */
+        ec_master_state_t *state /**< Structure to store the information. */
+        );
+
+/******************************************************************************
+ * Slave configuration methods
+ *****************************************************************************/
+
+/** Specify the Pdo mapping and (optionally) the Pdo configuration.
+ *
+ * The following example shows, how to specify a complete Pdo mapping
+ * including the Pdo configuration. With this information, the master is able
+ * to reserve the complete process data, even if the slave is not present
+ * at configuration time:
+ *
+ * \code
+ * const ec_pdo_info_t complete_mapping[] = {
+ *     {EC_DIR_INPUT, 0x1600, 2, { // channel 1
+ *         {0x7000, 0, 16}, // value
+ *         {0x7000, 1, 8},  // status
+ *     }},
+ *     {EC_DIR_INPUT, 0x1601, 2, { // channel 2 
+ *         {0x7001, 0, 16}, // value
+ *         {0x7001, 1, 8},  // status
+ *     }}
+ * };
+ * 
+ * if (ecrt_slave_config_mapping(slave_config_ana_in, 2, complete_mapping)) {
+ *     // error
+ * }
+ * \endcode
+ *
+ * The next example shows, how to configure only the Pdo mapping. The entries
+ * for each mapped Pdo are taken from the default Pdo configuration. Please
+ * note, that Pdo entry registration will fail, if no Pdo configuration is
+ * specified and the slave is offline.
+ *
+ * \code
+ * const ec_pdo_info_t pdo_mapping[] = {
+ *     {EC_DIR_INPUT, 0x1600}, // Channel 1
+ *     {EC_DIR_INPUT, 0x1601}  // Channel 2
+ * };
+ * 
+ * if (ecrt_slave_config_mapping(slave_config_ana_in, 2, pdo_mapping)) {
+ *     // error
+ * }
+ * \endcode
+ *
+ * \return zero on success, else non-zero
+ */
+int ecrt_slave_config_mapping(
+        ec_slave_config_t *sc, /**< Slave configuration. */
+        unsigned int n_entries, /**< Number of Pdos in \a pdos to map. */
+        const ec_pdo_info_t pdos[] /**< List with Pdo mapping. */
+        );
+
+/** Add a configuration value for an 8-bit SDO.
+ *
+ * \todo doc
+ * \return 0 in case of success, else < 0
+ */
+int ecrt_slave_config_sdo8(
+        ec_slave_config_t *sc, /**< Slave configuration */
+        uint16_t sdo_index, /**< Index of the SDO to configure. */
+        uint8_t sdo_subindex, /**< Subindex of the SDO to configure. */
+        uint8_t value /**< Value to set. */
+        );
+
+/** Add a configuration value for a 16-bit SDO.
+ *
+ * \todo doc
+ * \return 0 in case of success, else < 0
+ */
+int ecrt_slave_config_sdo16(
+        ec_slave_config_t *sc, /**< Slave configuration */
+        uint16_t sdo_index, /**< Index of the SDO to configure. */
+        uint8_t sdo_subindex, /**< Subindex of the SDO to configure. */
+        uint16_t value /**< Value to set. */
+        );
+
+/** Add a configuration value for a 32-bit SDO.
+ *
+ * \todo doc
+ * \return 0 in case of success, else < 0
+ */
+int ecrt_slave_config_sdo32(
+        ec_slave_config_t *sc, /**< Slave configuration */
+        uint16_t sdo_index, /**< Index of the SDO to configure. */
+        uint8_t sdo_subindex, /**< Subindex of the SDO to configure. */
+        uint32_t value /**< Value to set. */
+        );
+
+/** Outputs the state of the slave configuration.
+ *
+ * Stores the state information in the given \a state structure.
+ */
+void ecrt_slave_config_state(
+        const ec_slave_config_t *sc, /**< Slave configuration */
+        ec_slave_config_state_t *state /**< State object to write to. */
+        );
 
 /******************************************************************************
  * Domain methods
  *****************************************************************************/
 
-int ecrt_domain_register_pdo(ec_domain_t *domain, ec_slave_t *slave,
-        uint16_t pdo_entry_index, uint8_t pdo_entry_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);
-
-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);
-
-/******************************************************************************
- * Slave methods
- *****************************************************************************/
-
-int ecrt_slave_conf_sdo8(ec_slave_t *slave, uint16_t sdo_index,
-                         uint8_t sdo_subindex, uint8_t value);
-int ecrt_slave_conf_sdo16(ec_slave_t *slave, uint16_t sdo_index,
-                          uint8_t sdo_subindex, uint16_t value);
-int ecrt_slave_conf_sdo32(ec_slave_t *slave, uint16_t sdo_index,
-                          uint8_t sdo_subindex, uint32_t value);
-
-void ecrt_slave_pdo_mapping_clear(ec_slave_t *, ec_direction_t);
-int ecrt_slave_pdo_mapping_add(ec_slave_t *, ec_direction_t, uint16_t);
-int ecrt_slave_pdo_mapping(ec_slave_t *, ec_direction_t, unsigned int, ...);
+/** Registers a single Pdo entry for a domain.
+ *
+ * \return On success, the function returns the offset in the domain's process
+ *         data, which can be zero or greater. On failure, it returns a value
+ *         less than zero.
+ */
+
+int ecrt_domain_reg_pdo_entry(
+        ec_domain_t *domain, /**< Domain. */
+        ec_slave_config_t *sc, /**< Slave configuration. */
+        uint16_t entry_index, /**< Index of the Pdo entry to register. */
+        uint8_t entry_subindex /**< Subindex of the Pdo entry to register. */
+        );
+
+/** Registers a bunch of Pdo entries for a domain.
+ *
+ * \todo doc
+ * \attention The registration array has to be terminated with an empty
+ *            structure, or one with the \a index field set to zero!
+ * \return 0 on success, else non-zero.
+ */
+int ecrt_domain_reg_pdo_entry_list(
+        ec_domain_t *domain, /**< Domain. */
+        const ec_pdo_entry_reg_t *pdo_entry_regs /**< Array of Pdo
+                                                   registrations. */
+        );
+
+/** Returns the current size of the domain's process data.
+ *
+ * \return Size of the process data image.
+ */
+size_t ecrt_domain_size(
+        ec_domain_t *domain /**< Domain. */
+        );
+
+/** Provide memory to store the domain's process data.
+ *
+ * Call this after all Pdo entries have been registered. Since interface
+ * version 1.4, you'll have to provide an external memory for the domain
+ * process data.
+ *
+ * The size of the allocated memory must be at least the return value of
+ * ecrt_domain_size(), after all Pdo entries have been registered.
+ */
+void ecrt_domain_memory(
+        ec_domain_t *domain, /**< Domain. */
+        uint8_t *memory /**< Address of the memory to store the process
+                          data in. */
+        );
+
+/** Processes received datagrams.
+ *
+ * \todo doc
+ */
+void ecrt_domain_process(
+        ec_domain_t *domain /**< Domain. */
+        );
+
+/** (Re-)queues all domain datagrams in the master's datagram queue.
+ *
+ * \todo doc
+ */
+void ecrt_domain_queue(
+        ec_domain_t *domain /**< Domain. */
+        );
+
+/** Reads the state of a domain.
+ *
+ * Stores the domain state in the giveb \a state structure.
+ */
+void ecrt_domain_state(
+        const ec_domain_t *domain, /**< Domain. */
+        ec_domain_state_t *state /**< Pointer to a state object to store the
+                                   information. */
+        );
 
 /******************************************************************************
  * Bitwise read/write macros
@@ -324,4 +657,6 @@
 
 /*****************************************************************************/
 
+/** @} */
+
 #endif
--- a/master/Kbuild.in	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/Kbuild.in	Tue Feb 19 08:22:20 2008 +0000
@@ -33,9 +33,10 @@
 
 obj-m := ec_master.o
 
-ec_master-objs := module.o master.o device.o pdo.o sync.o fmmu.o slave.o \
-    datagram.o domain.o mailbox.o canopen.o fsm_sii.o fsm_change.o \
-    fsm_coe.o fsm_coe_map.o fsm_mapping.o fsm_slave.o fsm_master.o xmldev.o
+ec_master-objs := module.o master.o device.o pdo.o sync.o fmmu_config.o \
+    slave.o slave_config.o pdo_mapping.o datagram.o domain.o mailbox.o \
+    canopen.o fsm_sii.o fsm_change.o fsm_coe.o fsm_coe_map.o fsm_mapping.o \
+    fsm_slave.o fsm_master.o xmldev.o
 
 ifeq (@ENABLE_EOE@,1)
 	ec_master-objs += ethernet.o
--- a/master/Makefile.am	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/Makefile.am	Tue Feb 19 08:22:20 2008 +0000
@@ -39,7 +39,7 @@
 	device.c device.h \
 	pdo.c pdo.h \
 	sync.c sync.h \
-	fmmu.c fmmu.h \
+	fmmu_config.c fmmu_config.h \
 	domain.c domain.h \
 	doxygen.c \
 	ethernet.c ethernet.h \
@@ -55,6 +55,8 @@
 	master.c master.h \
 	module.c \
 	slave.c slave.h \
+	slave_config.c slave_config.h \
+	pdo_mapping.c pdo_mapping.h \
 	xmldev.c xmldev.h
 
 modules:
--- a/master/domain.c	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/domain.c	Tue Feb 19 08:22:20 2008 +0000
@@ -41,29 +41,14 @@
 #include <linux/module.h>
 
 #include "globals.h"
+#include "master.h"
+#include "slave_config.h"
+
 #include "domain.h"
-#include "master.h"
-
-/*****************************************************************************/
-
-/**
-   Data registration type.
-*/
-
-typedef struct
-{
-    struct list_head list; /**< list item */
-    ec_slave_t *slave; /**< slave */
-    const ec_sync_t *sync; /**< sync manager */
-    off_t sync_offset; /**< pdo offset */
-    void **data_ptr; /**< pointer to process data pointer(s) */
-}
-ec_data_reg_t;
 
 /*****************************************************************************/
 
 void ec_domain_clear(struct kobject *);
-void ec_domain_clear_data_regs(ec_domain_t *);
 ssize_t ec_show_domain_attribute(struct kobject *, struct attribute *, char *);
 
 /*****************************************************************************/
@@ -92,25 +77,24 @@
 
 /*****************************************************************************/
 
-/**
-   Domain constructor.
-   \return 0 in case of success, else < 0
-*/
-
-int ec_domain_init(ec_domain_t *domain, /**< EtherCAT domain */
-                   ec_master_t *master, /**< owning master */
-                   unsigned int index /**< domain index */
-                   )
+/** Domain constructor.
+ *
+ * \return 0 in case of success, else < 0
+ */
+int ec_domain_init(
+        ec_domain_t *domain, /**< EtherCAT domain. */
+        ec_master_t *master, /**< Parent master. */
+        unsigned int index /**< Index. */
+        )
 {
     domain->master = master;
     domain->index = index;
     domain->data_size = 0;
     domain->base_address = 0;
-    domain->response_count = 0xFFFFFFFF;
+    domain->working_counter = 0xFFFFFFFF;
     domain->notify_jiffies = 0;
     domain->working_counter_changes = 0;
 
-    INIT_LIST_HEAD(&domain->data_regs);
     INIT_LIST_HEAD(&domain->datagrams);
 
     // init kobject and add it to the hierarchy
@@ -164,8 +148,8 @@
 
 void ec_domain_clear(struct kobject *kobj /**< kobject of the domain */)
 {
+    ec_domain_t *domain;
     ec_datagram_t *datagram, *next;
-    ec_domain_t *domain;
 
     domain = container_of(kobj, ec_domain_t, kobj);
 
@@ -174,91 +158,21 @@
         kfree(datagram);
     }
 
-    ec_domain_clear_data_regs(domain);
-
     kfree(domain);
 }
 
 /*****************************************************************************/
 
-/**
- * Registers a PDO entry.
+/** Allocates a domain datagram and appends it to the list.
+ *
  * \return 0 in case of success, else < 0
  */
-
-int ec_domain_reg_pdo_entry(
-        ec_domain_t *domain, /**< EtherCAT domain */
-        ec_sync_t *sync, /**< sync manager */
-        const ec_pdo_entry_t *entry, /**< PDO entry to register */
-        void **data_ptr /**< pointer to the process data pointer */
+int ec_domain_add_datagram(
+        ec_domain_t *domain, /**< EtherCAT domain. */
+        uint32_t offset, /**< Logical offset. */
+        size_t data_size /**< Size of the data. */
         )
 {
-    ec_data_reg_t *data_reg;
-    const ec_pdo_t *other_pdo;
-    const ec_pdo_entry_t *other_entry;
-    unsigned int bit_offset, byte_offset;
-
-    // Calculate offset (in sync manager) for process data pointer
-    bit_offset = 0;
-    list_for_each_entry(other_pdo, &sync->pdos, list) {
-        list_for_each_entry(other_entry, &other_pdo->entries, list) {
-            if (other_entry == entry)
-                goto out;
-            bit_offset += other_entry->bit_length;
-        }
-    }
-out:
-    byte_offset = bit_offset / 8;
-
-    // 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(sync->slave, domain, sync)) {
-        EC_ERR("FMMU configuration failed.\n");
-        kfree(data_reg);
-        return -1;
-    }
-
-    data_reg->slave = sync->slave;
-    data_reg->sync = sync;
-    data_reg->sync_offset = byte_offset;
-    data_reg->data_ptr = data_ptr;
-    list_add_tail(&data_reg->list, &domain->data_regs);
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
-   Clears the list of the data registrations.
-*/
-
-void ec_domain_clear_data_regs(ec_domain_t *domain /**< EtherCAT domain */)
-{
-    ec_data_reg_t *data_reg, *next;
-
-    list_for_each_entry_safe(data_reg, next, &domain->data_regs, list) {
-        list_del(&data_reg->list);
-        kfree(data_reg);
-    }
-}
-
-/*****************************************************************************/
-
-/**
-   Allocates a process data datagram and appends it to the list.
-   \return 0 in case of success, else < 0
-*/
-
-int ec_domain_add_datagram(ec_domain_t *domain, /**< EtherCAT domain */
-                           uint32_t offset, /**< logical offset */
-                           size_t data_size /**< size of the datagram data */
-                           )
-{
     ec_datagram_t *datagram;
 
     if (!(datagram = kmalloc(sizeof(ec_datagram_t), GFP_KERNEL))) {
@@ -281,50 +195,47 @@
 
 /*****************************************************************************/
 
-/**
-   Creates a domain.
-   Reserves domain memory, calculates the logical addresses of the
-   corresponding FMMUs and sets the process data pointer of the registered
-   process data.
-   \return 0 in case of success, else < 0
-*/
-
-int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
-                    uint32_t base_address /**< logical base address */
-                    )
-{
-    ec_data_reg_t *data_reg;
-    ec_slave_t *slave;
-    ec_fmmu_t *fmmu;
-    unsigned int i, j, datagram_count;
-    uint32_t pdo_off, pdo_off_datagram;
-    uint32_t datagram_offset, log_addr;
-    size_t datagram_data_size, sync_size;
-    ec_datagram_t *datagram;
+/** Finishes a domain.
+ *
+ * This allocates the necessary datagrams and writes the correct logical
+ * addresses to every configured FMMU.
+ *
+ * \retval 0 in case of success
+ * \retval <0 on failure.
+ */
+int ec_domain_finish(
+        ec_domain_t *domain, /**< EtherCAT domain. */
+        uint32_t base_address /**< Logical base address. */
+        )
+{
+    uint32_t datagram_offset;
+    size_t datagram_data_size;
+    unsigned int datagram_count, i;
+    ec_slave_config_t *sc;
+    ec_fmmu_config_t *fmmu;
 
     domain->base_address = base_address;
 
-    // calculate size of process data and allocate memory
-    domain->data_size = 0;
+    // Cycle through all domain FMMUS, add the logical base address and assign
+    // as many PDO entries as possible to the datagrams.
     datagram_offset = base_address;
     datagram_data_size = 0;
     datagram_count = 0;
-    list_for_each_entry(slave, &domain->master->slaves, list) {
-        for (j = 0; j < slave->fmmu_count; j++) {
-            fmmu = &slave->fmmus[j];
-            if (fmmu->domain == domain) {
-                fmmu->logical_start_address = base_address + domain->data_size;
-                sync_size = ec_sync_size(fmmu->sync);
-                domain->data_size += sync_size;
-                if (datagram_data_size + sync_size > EC_MAX_DATA_SIZE) {
-                    if (ec_domain_add_datagram(domain, datagram_offset,
-                                               datagram_data_size)) return -1;
-                    datagram_offset += datagram_data_size;
-                    datagram_data_size = 0;
-                    datagram_count++;
-                }
-                datagram_data_size += sync_size;
+    list_for_each_entry(sc, &domain->master->configs, list) {
+        for (i = 0; i < sc->used_fmmus; i++) {
+            fmmu = &sc->fmmu_configs[i];
+            if (fmmu->domain != domain)
+                continue;
+
+            fmmu->logical_start_address += base_address;
+            if (datagram_data_size + fmmu->data_size > EC_MAX_DATA_SIZE) {
+                if (ec_domain_add_datagram(domain, datagram_offset,
+                            datagram_data_size)) return -1;
+                datagram_offset += datagram_data_size;
+                datagram_data_size = 0;
+                datagram_count++;
             }
+            datagram_data_size += fmmu->data_size;
         }
     }
 
@@ -336,41 +247,9 @@
         datagram_count++;
     }
 
-    if (datagram_count) {
-        // set all process data pointers
-        list_for_each_entry(data_reg, &domain->data_regs, list) {
-            for (i = 0; i < data_reg->slave->fmmu_count; i++) {
-                fmmu = &data_reg->slave->fmmus[i];
-                if (fmmu->domain == domain && fmmu->sync == data_reg->sync) {
-                    pdo_off =
-                        fmmu->logical_start_address + data_reg->sync_offset;
-                    // search datagram
-                    list_for_each_entry(datagram, &domain->datagrams, list) {
-                        log_addr = EC_READ_U32(datagram->address);
-                        pdo_off_datagram = pdo_off - log_addr;
-                        if (pdo_off >= log_addr &&
-                                pdo_off_datagram < datagram->mem_size) {
-                            *data_reg->data_ptr = datagram->data +
-                                pdo_off_datagram;
-                        }
-                    }
-                    if (!data_reg->data_ptr) {
-                        EC_ERR("Failed to assign data pointer!\n");
-                        return -1;
-                    }
-                    break;
-                }
-            }
-        }
-
-        EC_INFO("Domain %u - Allocated %u bytes in %u datagram%s.\n",
-                domain->index, domain->data_size, datagram_count,
-                datagram_count == 1 ? "" : "s");
-    } else { // !datagram_count
-        EC_WARN("Domain %u contains no data!\n", domain->index);
-    }
-
-    ec_domain_clear_data_regs(domain);
+    EC_INFO("Domain %u with logical offset %u contains %u bytes in %u"
+            " datagram%s.\n", domain->index, domain->base_address,
+            domain->data_size, datagram_count, datagram_count == 1 ? "" : "s");
     return 0;
 }
 
@@ -399,143 +278,39 @@
  *  Realtime interface
  *****************************************************************************/
 
-/**
- * Registers a PDO for a domain.
- * \return 0 on success, else non-zero
- * \ingroup RealtimeInterface
- */
-
-int ecrt_domain_register_pdo(
-        ec_domain_t *domain, /**< EtherCAT domain */
-        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_sync_t *sync;
-    const ec_pdo_t *pdo;
-    const ec_pdo_entry_t *entry;
-    unsigned int i;
-
-    // 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 != pdo_entry_index ||
-                        entry->subindex != pdo_entry_subindex) continue;
-                // PDO entry found
-                if (ec_domain_reg_pdo_entry(domain, sync, entry, data_ptr)) {
-                    return -1;
-                }
-                return 0;
-            }
-        }
-    }
-
-    EC_ERR("PDO entry 0x%04X:%u is not mapped in slave %u.\n",
-           pdo_entry_index, pdo_entry_subindex, slave->ring_position);
-    return -1;
-}
-
-/*****************************************************************************/
-
-/**
- * Registers a bunch of data fields.
- * \attention The list has to be terminated with a NULL structure ({})!
- * \return 0 in case of success, else < 0
- * \ingroup RealtimeInterface
- */
-
-int ecrt_domain_register_pdo_list(
-        ec_domain_t *domain, /**< EtherCAT domain */
-        const ec_pdo_reg_t *pdo_regs /**< array of PDO registrations */
-        )
-{
-    const ec_pdo_reg_t *reg;
-    ec_slave_t *slave;
+int ecrt_domain_reg_pdo_entry(ec_domain_t *domain, ec_slave_config_t *sc,
+        uint16_t index, uint8_t subindex)
+{
+    return ec_slave_config_reg_pdo_entry(sc, domain, index, subindex);
+}
+
+/*****************************************************************************/
+
+int ecrt_domain_reg_pdo_entry_list(ec_domain_t *domain,
+        const ec_pdo_entry_reg_t *regs)
+{
+    const ec_pdo_entry_reg_t *reg;
+    ec_slave_config_t *sc;
+    int ret;
     
-    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)))
+    for (reg = regs; reg->index; reg++) {
+        if (!(sc = ecrt_master_slave_config(domain->master, reg->alias,
+                        reg->position, 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))
+        if ((ret = ecrt_domain_reg_pdo_entry(domain, sc, reg->index,
+                        reg->subindex)) < 0)
             return -1;
-    }
-
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
- * 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 %u of slave %u to %u.\n",
-                   sync->index, slave->ring_position, sync_length);
-        }
-    }
-
-    list_add_tail(&data_reg->list, &domain->data_regs);
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
-   Processes received process data and requeues the domain datagram(s).
-   \ingroup RealtimeInterface
-*/
-
-void ecrt_domain_process(ec_domain_t *domain /**< EtherCAT domain */)
+
+        *reg->offset = ret;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+void ecrt_domain_process(ec_domain_t *domain)
 {
     unsigned int working_counter_sum;
     ec_datagram_t *datagram;
@@ -552,9 +327,9 @@
         }
     }
 
-    if (working_counter_sum != domain->response_count) {
+    if (working_counter_sum != domain->working_counter) {
         domain->working_counter_changes++;
-        domain->response_count = working_counter_sum;
+        domain->working_counter = working_counter_sum;
     }
 
     if (domain->working_counter_changes &&
@@ -562,12 +337,12 @@
         domain->notify_jiffies = jiffies;
         if (domain->working_counter_changes == 1) {
             EC_INFO("Domain %u working counter change: %u\n", domain->index,
-                    domain->response_count);
+                    domain->working_counter);
         }
         else {
-            EC_INFO("Domain %u: %u WC changes. Current response count: %u\n",
+            EC_INFO("Domain %u: %u working counter changes. Currently %u\n",
                     domain->index, domain->working_counter_changes,
-                    domain->response_count);
+                    domain->working_counter);
         }
         domain->working_counter_changes = 0;
     }
@@ -575,12 +350,7 @@
 
 /*****************************************************************************/
 
-/**
-   Places all process data datagrams in the masters datagram queue.
-   \ingroup RealtimeInterface
-*/
-
-void ecrt_domain_queue(ec_domain_t *domain /**< EtherCAT domain */)
+void ecrt_domain_queue(ec_domain_t *domain)
 {
     ec_datagram_t *datagram;
 
@@ -591,24 +361,20 @@
 
 /*****************************************************************************/
 
-/**
-   Returns the state of a domain.
-   \return 0 if all datagrams were received, else -1.
-   \ingroup RealtimeInterface
-*/
-
-int ecrt_domain_state(const ec_domain_t *domain /**< EtherCAT domain */)
-{
-    return domain->state;
+void ecrt_domain_state(const ec_domain_t *domain, ec_domain_state_t *state)
+{
+    state->working_counter = domain->working_counter;
+    state->wc_state = EC_WC_ZERO; // FIXME
 }
 
 /*****************************************************************************/
 
 /** \cond */
 
-EXPORT_SYMBOL(ecrt_domain_register_pdo);
-EXPORT_SYMBOL(ecrt_domain_register_pdo_list);
-EXPORT_SYMBOL(ecrt_domain_register_pdo_range);
+EXPORT_SYMBOL(ecrt_domain_reg_pdo_entry);
+EXPORT_SYMBOL(ecrt_domain_reg_pdo_entry_list);
+//EXPORT_SYMBOL(ecrt_domain_size);
+//EXPORT_SYMBOL(ecrt_domain_memory);
 EXPORT_SYMBOL(ecrt_domain_process);
 EXPORT_SYMBOL(ecrt_domain_queue);
 EXPORT_SYMBOL(ecrt_domain_state);
--- a/master/domain.h	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/domain.h	Tue Feb 19 08:22:20 2008 +0000
@@ -58,19 +58,18 @@
 
 struct ec_domain
 {
-    struct kobject kobj; /**< kobject */
-    struct list_head list; /**< list item */
-    unsigned int index; /**< domain index (just a number) */
-    ec_master_t *master; /**< EtherCAT master owning the domain */
-    size_t data_size; /**< size of the process data */
-    struct list_head datagrams; /**< process data datagrams */
-    uint32_t base_address; /**< logical offset address of the process data */
-    unsigned int response_count; /**< number of responding slaves */
-    unsigned int state; /**< domain error state */
-    struct list_head data_regs; /**< PDO data registrations */
-    unsigned int working_counter_changes; /**< working counter changes
-                                             since last notification */
-    unsigned long notify_jiffies; /**< time of last notification */
+    struct kobject kobj; /**< kobject. */
+    struct list_head list; /**< List item. */
+    unsigned int index; /**< Index (just a number). */
+    ec_master_t *master; /**< EtherCAT master owning the domain. */
+    size_t data_size; /**< Size of the process data. */
+    struct list_head datagrams; /**< Datagrams for process data exchange. */
+    uint32_t base_address; /**< Logical offset address of the process data. */
+    unsigned int working_counter; /**< Last working counter value. */
+    unsigned int state; /**< Error state. */
+    unsigned int working_counter_changes; /**< Working counter changes
+                                             since last notification. */
+    unsigned long notify_jiffies; /**< Time of last notification. */
 };
 
 /*****************************************************************************/
@@ -78,7 +77,7 @@
 int ec_domain_init(ec_domain_t *, ec_master_t *, unsigned int);
 void ec_domain_destroy(ec_domain_t *);
 
-int ec_domain_alloc(ec_domain_t *, uint32_t);
+int ec_domain_finish(ec_domain_t *, uint32_t);
 
 /*****************************************************************************/
 
--- a/master/fmmu.c	Thu Feb 14 09:18:55 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-/******************************************************************************
- *
- *  $Id$
- *
- *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
- *
- *  This file is part of the IgH EtherCAT Master.
- *
- *  The IgH EtherCAT Master is free software; you can redistribute it
- *  and/or modify it under the terms of the GNU General Public License
- *  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
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with the IgH EtherCAT Master; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- *  The 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.
- *
- *****************************************************************************/
-
-/**
-   \file
-   EtherCAT FMMU methods.
-*/
-
-/*****************************************************************************/
-
-#include "globals.h"
-#include "slave.h"
-#include "master.h"
-#include "fmmu.h"
-
-/*****************************************************************************/
-
-/**
- * FMMU Constructor.
- */
-
-void ec_fmmu_init(
-        ec_fmmu_t *fmmu, /**< EtherCAT FMMU */
-        ec_slave_t *slave, /**< EtherCAT slave */
-        unsigned int index /**< FMMU index */
-        )
-{
-    fmmu->slave = slave;
-    fmmu->index = index;
-}
-
-/*****************************************************************************/
-
-/**
- * Initializes an FMMU configuration page.
- * The referenced memory (\a data) must be at least EC_FMMU_SIZE bytes.
- */
-
-void ec_fmmu_config(
-        const ec_fmmu_t *fmmu, /**< EtherCAT FMMU */
-        uint8_t *data /**> configuration memory */
-        )
-{
-    size_t sync_size = ec_sync_size(fmmu->sync);
-
-    if (fmmu->slave->master->debug_level) {
-        EC_DBG("FMMU%u: LogAddr 0x%08X, Size %3i, PhysAddr 0x%04X, Dir %s\n",
-               fmmu->index, fmmu->logical_start_address,
-               sync_size, fmmu->sync->physical_start_address,
-               ((fmmu->sync->control_register & 0x04) ? "out" : "in"));
-    }
-
-    EC_WRITE_U32(data,      fmmu->logical_start_address);
-    EC_WRITE_U16(data + 4,  sync_size); // size of fmmu
-    EC_WRITE_U8 (data + 6,  0x00); // logical start bit
-    EC_WRITE_U8 (data + 7,  0x07); // logical end bit
-    EC_WRITE_U16(data + 8,  fmmu->sync->physical_start_address);
-    EC_WRITE_U8 (data + 10, 0x00); // physical start bit
-    EC_WRITE_U8 (data + 11, ((fmmu->sync->control_register & 0x04)
-                             ? 0x02 : 0x01));
-    EC_WRITE_U16(data + 12, 0x0001); // enable
-    EC_WRITE_U16(data + 14, 0x0000); // reserved
-}
-
-/*****************************************************************************/
--- a/master/fmmu.h	Thu Feb 14 09:18:55 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/******************************************************************************
- *
- *  $Id$
- *
- *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
- *
- *  This file is part of the IgH EtherCAT Master.
- *
- *  The IgH EtherCAT Master is free software; you can redistribute it
- *  and/or modify it under the terms of the GNU General Public License
- *  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
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with the IgH EtherCAT Master; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- *  The 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.
- *
- *****************************************************************************/
-
-/**
-   \file
-   EtherCAT FMMU structure.
-*/
-
-/*****************************************************************************/
-
-#ifndef _EC_FMMU_H_
-#define _EC_FMMU_H_
-
-#include "../include/ecrt.h"
-
-#include "globals.h"
-
-/*****************************************************************************/
-
-/** size of an FMMU configuration page */
-#define EC_FMMU_SIZE 16
-
-/*****************************************************************************/
-
-/**
- * FMMU configuration.
- */
-
-typedef struct
-{
-    const ec_slave_t *slave; /**< EtherCAT slave, the FMMU belongs to */
-    unsigned int index; /**< FMMU index */
-    const ec_domain_t *domain; /**< domain */
-    const ec_sync_t *sync; /**< sync manager */
-    uint32_t logical_start_address; /**< logical start address */
-}
-ec_fmmu_t;
-
-/*****************************************************************************/
-
-void ec_fmmu_init(ec_fmmu_t *, ec_slave_t *, unsigned int);
-
-void ec_fmmu_config(const ec_fmmu_t *, uint8_t *);
-
-/*****************************************************************************/
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/fmmu_config.c	Tue Feb 19 08:22:20 2008 +0000
@@ -0,0 +1,100 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU General Public License
+ *  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
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  The 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.
+ *
+ *****************************************************************************/
+
+/** \file
+ * EtherCAT FMMU configuration methods.
+ */
+
+/*****************************************************************************/
+
+#include "globals.h"
+#include "slave_config.h"
+#include "master.h"
+
+#include "fmmu_config.h"
+
+/*****************************************************************************/
+
+/** FMMU configuration constructor.
+ *
+ * Inits an FMMU configuration, sets the logical start address and adds the
+ * process data size for the mapped PDOs of the given direction to the domain
+ * data size.
+ */
+void ec_fmmu_config_init(
+        ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
+        ec_slave_config_t *sc, /**< EtherCAT slave configuration. */
+        ec_domain_t *domain, /**< EtherCAT domain. */
+        ec_direction_t dir /**< PDO direction. */
+        )
+{
+    fmmu->sc = sc;
+    fmmu->domain = domain;
+    fmmu->dir = dir;
+
+    fmmu->logical_start_address = domain->data_size;
+    fmmu->data_size = ec_pdo_mapping_total_size(&sc->mapping[dir]);
+    domain->data_size += fmmu->data_size;
+}
+
+/*****************************************************************************/
+
+/** Initializes an FMMU configuration page.
+ *
+ * The referenced memory (\a data) must be at least EC_FMMU_PAGE_SIZE bytes.
+ */
+void ec_fmmu_config_page(
+        const ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
+        const ec_sync_t *sync, /**< Sync manager. */
+        uint8_t *data /**> Configuration page memory. */
+        )
+{
+    if (fmmu->sc->master->debug_level) {
+        EC_DBG("FMMU: LogAddr 0x%08X, Size %3i, PhysAddr 0x%04X, Dir %s\n",
+               fmmu->logical_start_address, fmmu->data_size,
+               sync->physical_start_address,
+               (sync->control_register & 0x04) ? "out" : "in");
+    }
+
+    EC_WRITE_U32(data,      fmmu->logical_start_address);
+    EC_WRITE_U16(data + 4,  fmmu->data_size); // size of fmmu
+    EC_WRITE_U8 (data + 6,  0x00); // logical start bit
+    EC_WRITE_U8 (data + 7,  0x07); // logical end bit
+    EC_WRITE_U16(data + 8,  sync->physical_start_address);
+    EC_WRITE_U8 (data + 10, 0x00); // physical start bit
+    EC_WRITE_U8 (data + 11, (sync->control_register & 0x04) ? 0x02 : 0x01);
+    EC_WRITE_U16(data + 12, 0x0001); // enable
+    EC_WRITE_U16(data + 14, 0x0000); // reserved
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/fmmu_config.h	Tue Feb 19 08:22:20 2008 +0000
@@ -0,0 +1,72 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU General Public License
+ *  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
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  The 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.
+ *
+ *****************************************************************************/
+
+/** \file
+ * EtherCAT FMMU configuration structure.
+ */
+
+/*****************************************************************************/
+
+#ifndef _EC_FMMU_CONFIG_H_
+#define _EC_FMMU_CONFIG_H_
+
+#include "../include/ecrt.h"
+
+#include "globals.h"
+
+/*****************************************************************************/
+
+/** FMMU configuration.
+ */
+typedef struct
+{
+    const ec_slave_config_t *sc; /**< EtherCAT slave config. */
+    const ec_domain_t *domain; /**< Domain. */
+    ec_direction_t dir; /**< PDO direction. */
+
+    uint32_t logical_start_address; /**< Logical start address. */
+    unsigned int data_size; /**< Covered PDO size. */
+}
+ec_fmmu_config_t;
+
+/*****************************************************************************/
+
+void ec_fmmu_config_init(ec_fmmu_config_t *, ec_slave_config_t *,
+        ec_domain_t *, ec_direction_t);
+
+void ec_fmmu_config_page(const ec_fmmu_config_t *, const ec_sync_t *,
+        uint8_t *);
+
+/*****************************************************************************/
+
+#endif
--- a/master/fsm_coe_map.c	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_coe_map.c	Tue Feb 19 08:22:20 2008 +0000
@@ -59,8 +59,6 @@
 void ec_fsm_coe_map_action_next_pdo(ec_fsm_coe_map_t *);
 void ec_fsm_coe_map_action_next_pdo_entry(ec_fsm_coe_map_t *);
 
-void ec_fsm_coe_map_clear_pdos(ec_fsm_coe_map_t *);
-
 /*****************************************************************************/
 
 /**
@@ -74,7 +72,7 @@
 {
     fsm->state = NULL;
     fsm->fsm_coe = fsm_coe;
-    INIT_LIST_HEAD(&fsm->pdos);
+    ec_pdo_mapping_init(&fsm->mapping);
 }
 
 /*****************************************************************************/
@@ -85,27 +83,7 @@
 
 void ec_fsm_coe_map_clear(ec_fsm_coe_map_t *fsm /**< finite state machine */)
 {
-    ec_fsm_coe_map_clear_pdos(fsm);
-}
-
-/*****************************************************************************/
-
-/**
- * Clear FSM PDOs.
- */
-
-void ec_fsm_coe_map_clear_pdos(
-        ec_fsm_coe_map_t *fsm /**< finite state machine */
-        )
-{
-    ec_pdo_t *pdo, *next;
-
-    // free all PDOs
-    list_for_each_entry_safe(pdo, next, &fsm->pdos, list) {
-        list_del(&pdo->list);
-        ec_pdo_clear(pdo);
-        kfree(pdo);
-    }
+    ec_pdo_mapping_clear(&fsm->mapping);
 }
 
 /*****************************************************************************/
@@ -188,7 +166,7 @@
             EC_DBG("Reading PDO mapping of sync manager %u of slave %u.\n",
                     fsm->sync_index, slave->ring_position);
 
-        ec_fsm_coe_map_clear_pdos(fsm);
+        ec_pdo_mapping_clear_pdos(&fsm->mapping);
 
         if (!(entry = ec_sdo_get_entry(fsm->sync_sdo, 0))) {
             EC_ERR("SDO 0x%04X has no subindex 0 on slave %u.\n",
@@ -269,15 +247,14 @@
 
     {
         ec_sync_t *sync = fsm->slave->sii_syncs + fsm->sync_index;
-        ec_pdo_t *pdo;
-
-        // exchange sync manager PDO mapping
-        ec_sync_clear_pdos(sync);
-        list_for_each_entry(pdo, &fsm->pdos, list) {
-            ec_sync_add_pdo(sync, pdo);
-        }
+
+        if (ec_pdo_mapping_copy(&sync->mapping, &fsm->mapping)) {
+            fsm->state = ec_fsm_coe_map_state_error;
+            return;
+        }
+        
         sync->mapping_source = EC_SYNC_MAPPING_COE;
-        ec_fsm_coe_map_clear_pdos(fsm);
+        ec_pdo_mapping_clear_pdos(&fsm->mapping);
 
         // next sync manager
         fsm->sync_index++;
@@ -316,8 +293,8 @@
 
         ec_pdo_init(fsm->pdo);
         fsm->pdo->index = EC_READ_U16(fsm->request.data);
-        fsm->pdo->type =
-            ec_sync_get_pdo_type(fsm->slave->sii_syncs + fsm->sync_index);
+        fsm->pdo->dir =
+            ec_sync_direction(fsm->slave->sii_syncs + fsm->sync_index);
 
         if (fsm->slave->master->debug_level)
             EC_DBG("  PDO 0x%04X.\n", fsm->pdo->index);
@@ -331,19 +308,11 @@
             return;
         }
 
-        if (fsm->pdo_sdo->name && strlen(fsm->pdo_sdo->name)) {
-            if (!(fsm->pdo->name = (char *)
-                        kmalloc(strlen(fsm->pdo_sdo->name) + 1, GFP_KERNEL))) {
-                EC_ERR("Failed to allocate PDO name.\n");
-                ec_pdo_clear(fsm->pdo);
-                kfree(fsm->pdo);
-                fsm->state = ec_fsm_coe_map_state_error;
-                return;
-            }
-            memcpy(fsm->pdo->name, fsm->pdo_sdo->name,
-                    strlen(fsm->pdo_sdo->name) + 1);
-        } else {
-            fsm->pdo->name = NULL;
+        if (ec_pdo_set_name(fsm->pdo, fsm->pdo_sdo->name)) {
+            ec_pdo_clear(fsm->pdo);
+            kfree(fsm->pdo);
+            fsm->state = ec_fsm_coe_map_state_error;
+            return;
         }
 
         if (!(entry = ec_sdo_get_entry(fsm->pdo_sdo, 0))) {
@@ -356,7 +325,7 @@
             return;
         }
 
-        list_add_tail(&fsm->pdo->list, &fsm->pdos);
+        list_add_tail(&fsm->pdo->list, &fsm->mapping.pdos);
 
         ec_sdo_request_init_read(&fsm->request, entry);
         fsm->state = ec_fsm_coe_map_state_pdo_entry_count;
@@ -463,28 +432,25 @@
             return;
         }
 
+        ec_pdo_entry_init(pdo_entry);
         pdo_entry->index = pdo_entry_info >> 16;
         pdo_entry->subindex = (pdo_entry_info >> 8) & 0xFF;
         pdo_entry->bit_length = pdo_entry_info & 0xFF;
 
         if (!pdo_entry->index && !pdo_entry->subindex) {
-            char gapname[] = "Gap";
-
             // we have a gap in the PDO, next PDO entry
             if (fsm->slave->master->debug_level) {
                 EC_DBG("    PDO entry gap: %u bit.\n",
                         pdo_entry->bit_length);
             }
 
-            if (!(pdo_entry->name = (char *)
-                        kmalloc(strlen(gapname) + 1, GFP_KERNEL))) {
-                EC_ERR("Failed to allocate GAP entry name.\n");
+            if (ec_pdo_entry_set_name(pdo_entry, "Gap")) {
+                ec_pdo_entry_clear(pdo_entry);
                 kfree(pdo_entry);
                 fsm->state = ec_fsm_coe_map_state_error;
                 return;
             }
 
-            memcpy(pdo_entry->name, gapname, strlen(gapname) + 1);
             list_add_tail(&pdo_entry->list, &fsm->pdo->entries);
             fsm->pdo_subindex++;
             ec_fsm_coe_map_action_next_pdo_entry(fsm);
@@ -494,6 +460,7 @@
         if (!(sdo = ec_slave_get_sdo(fsm->slave, pdo_entry->index))) {
             EC_ERR("Slave %u has no SDO 0x%04X.\n",
                     fsm->slave->ring_position, pdo_entry->index);
+            ec_pdo_entry_clear(pdo_entry);
             kfree(pdo_entry);
             fsm->state = ec_fsm_coe_map_state_error;
             return;
@@ -503,27 +470,22 @@
             EC_ERR("Slave %u has no SDO entry 0x%04X:%u.\n",
                     fsm->slave->ring_position, pdo_entry->index,
                     pdo_entry->subindex);
+            ec_pdo_entry_clear(pdo_entry);
             kfree(pdo_entry);
             fsm->state = ec_fsm_coe_map_state_error;
             return;
         }
 
-        if (entry->description && strlen(entry->description)) {
-            if (!(pdo_entry->name = (char *)
-                        kmalloc(strlen(entry->description) + 1, GFP_KERNEL))) {
-                EC_ERR("Failed to allocate PDO entry name.\n");
-                kfree(pdo_entry);
-                fsm->state = ec_fsm_coe_map_state_error;
-                return;
-            }
-            memcpy(pdo_entry->name, entry->description, strlen(entry->description) + 1);
-        } else {
-            pdo_entry->name = NULL;
+        if (ec_pdo_entry_set_name(pdo_entry, entry->description)) {
+            ec_pdo_entry_clear(pdo_entry);
+            kfree(pdo_entry);
+            fsm->state = ec_fsm_coe_map_state_error;
+            return;
         }
 
         if (fsm->slave->master->debug_level) {
-            EC_DBG("    PDO entry 0x%04X \"%s\" (%u bit).\n",
-                    pdo_entry->index, pdo_entry->name ? pdo_entry->name : "???",
+            EC_DBG("    PDO entry 0x%04X \"%s\" (%u bit).\n", pdo_entry->index,
+                    pdo_entry->name ? pdo_entry->name : "???",
                     pdo_entry->bit_length);
         }
 
--- a/master/fsm_coe_map.h	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_coe_map.h	Tue Feb 19 08:22:20 2008 +0000
@@ -51,8 +51,8 @@
 typedef struct ec_fsm_coe_map ec_fsm_coe_map_t; /**< \see ec_fsm_coe_map */
 
 /**
+ * \todo doc
  */
-
 struct ec_fsm_coe_map
 {
     void (*state)(ec_fsm_coe_map_t *); /**< CoE mapping state function */
@@ -66,7 +66,7 @@
     uint8_t sync_subindices; /**< number of mapped PDOs */
     uint16_t sync_subindex; /**< current subindex in mapping SDO */
 
-    struct list_head pdos; /**< list of mapped PDOs */
+    ec_pdo_mapping_t mapping; /**< Mapping to apply. */
     ec_pdo_t *pdo; /**< current PDO */
     ec_sdo_t *pdo_sdo; /**< current PDO SDO */
     uint8_t pdo_subindices; /**< number of PDO entries */
--- a/master/fsm_mapping.c	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_mapping.c	Tue Feb 19 08:22:20 2008 +0000
@@ -31,16 +31,17 @@
  *
  *****************************************************************************/
 
-/**
-   \file
-   EtherCAT PDO mapping state machine.
-*/
+/** \file
+ * EtherCAT PDO mapping state machine.
+ */
 
 /*****************************************************************************/
 
 #include "globals.h"
 #include "master.h"
 #include "mailbox.h"
+#include "slave_config.h"
+
 #include "fsm_mapping.h"
 
 /*****************************************************************************/
@@ -56,11 +57,10 @@
 
 /*****************************************************************************/
 
-/**
- * Constructor.
- */
-
-void ec_fsm_mapping_init(ec_fsm_mapping_t *fsm, /**< mapping state machine */
+/** Constructor.
+ */
+void ec_fsm_mapping_init(
+        ec_fsm_mapping_t *fsm, /**< mapping state machine */
         ec_fsm_coe_t *fsm_coe /**< CoE state machine to use */
         )
 {
@@ -70,20 +70,18 @@
 
 /*****************************************************************************/
 
-/**
- * Destructor.
- */
-
-void ec_fsm_mapping_clear(ec_fsm_mapping_t *fsm /**< mapping state machine */)
-{
-}
-
-/*****************************************************************************/
-
-/**
- * Start PDO mapping configuration state machine.
- */
-
+/** Destructor.
+ */
+void ec_fsm_mapping_clear(
+        ec_fsm_mapping_t *fsm /**< mapping state machine */
+        )
+{
+}
+
+/*****************************************************************************/
+
+/** Start PDO mapping configuration state machine.
+ */
 void ec_fsm_mapping_start(
         ec_fsm_mapping_t *fsm, /**< mapping state machine */
         ec_slave_t *slave /**< slave to configure */
@@ -95,10 +93,10 @@
 
 /*****************************************************************************/
 
-/**
+/** Get running state.
+ *
  * \return false, if state machine has terminated
  */
-
 int ec_fsm_mapping_running(
         const ec_fsm_mapping_t *fsm /**< mapping state machine */
         )
@@ -109,13 +107,13 @@
 
 /*****************************************************************************/
 
-/**
- * Executes the current state of the state machine.
+/** Executes the current state of the state machine.
+ *
  * If the state machine's datagram is not sent or received yet, the execution
  * of the state machine is delayed to the next cycle.
+ *
  * \return false, if state machine has terminated
  */
-
 int ec_fsm_mapping_exec(
         ec_fsm_mapping_t *fsm /**< mapping state machine */
         )
@@ -126,10 +124,10 @@
 
 /*****************************************************************************/
 
-/**
+/** Get execution result.
+ *
  * \return true, if the state machine terminated gracefully
  */
-
 int ec_fsm_mapping_success(
         const ec_fsm_mapping_t *fsm /**< mapping state machine */
         )
@@ -138,27 +136,28 @@
 }
 
 /******************************************************************************
- * state functions
+ * State functions.
  *****************************************************************************/
 
-/**
- * Start mapping configuration.
- */
-
+/** Start mapping configuration.
+ */
 void ec_fsm_mapping_state_start(
         ec_fsm_mapping_t *fsm /**< mapping state machine */
         )
 {
+    if (!fsm->slave->config) {
+        fsm->state = ec_fsm_mapping_state_end;
+        return;
+    }
+
     fsm->dir = EC_DIR_OUTPUT;
     ec_fsm_mapping_next_sync(fsm);
 }
 
 /*****************************************************************************/
 
-/**
- * Process mapping of next sync manager.
- */
-
+/** Process mapping of next sync manager.
+ */
 void ec_fsm_mapping_next_sync(
         ec_fsm_mapping_t *fsm /**< mapping state machine */
         )
@@ -171,18 +170,25 @@
         }
 
         if (!(fsm->sync = ec_slave_get_pdo_sync(fsm->slave, fsm->dir))) {
-            // no sync manager found for this direction
+            EC_WARN("next_sync(): No sync manager!\n");
             fsm->dir++;
             continue;
         }
 
-        fsm->dir++;
-        if (fsm->sync->alt_mapping)
+        fsm->mapping = &fsm->slave->config->mapping[fsm->dir];
+
+        if (ec_pdo_mapping_equal(&fsm->sync->mapping, fsm->mapping)) {
+            // the mapping for this direction does not have to be altered
+            fsm->dir++;
+            continue;
+        } else {
+            fsm->dir++;
             break;
+        }
     }
 
     if (fsm->slave->master->debug_level) {
-        EC_DBG("Configuring PDO mapping for SM%u of slave %i.\n",
+        EC_DBG("Configuring PDO mapping for SM%u of slave %u.\n",
                 fsm->sync->index, fsm->slave->ring_position);
     }
 
@@ -201,34 +207,23 @@
 
 /*****************************************************************************/
 
-/**
- * Process mapping of next PDO.
- */
-
+/** Process mapping of next PDO.
+ */
 ec_pdo_t *ec_fsm_mapping_next_pdo(
-        ec_fsm_mapping_t *fsm, /**< mapping state machine */
-        struct list_head *list /**< current PDO list item */
-        )
-{
-    ec_pdo_t *pdo;
-
-    do {
-        list = list->next; 
-        if (list == &fsm->sync->pdos)
-            return NULL; // no next PDO
-        pdo = list_entry(list, ec_pdo_t, list);
-    }
-    while (pdo->sync_index != fsm->sync->index);
-    
-    return pdo;
-}
-
-/*****************************************************************************/
-
-/**
- * Set the number of mapped PDOs to zero.
- */
-
+        const ec_fsm_mapping_t *fsm, /**< mapping state machine */
+        const struct list_head *list /**< current PDO list item */
+        )
+{
+    list = list->next; 
+    if (list == &fsm->mapping->pdos)
+        return NULL; // no next PDO
+    return list_entry(list, ec_pdo_t, list);
+}
+
+/*****************************************************************************/
+
+/** Set the number of mapped PDOs to zero.
+ */
 void ec_fsm_mapping_state_zero_count(
         ec_fsm_mapping_t *fsm /**< mapping state machine */
         )
@@ -245,8 +240,7 @@
     // map all PDOs belonging to the current sync manager
     
     // find first PDO
-    if (!(fsm->pdo = ec_fsm_mapping_next_pdo(
-                    fsm, &fsm->sync->pdos))) {
+    if (!(fsm->pdo = ec_fsm_mapping_next_pdo(fsm, &fsm->mapping->pdos))) {
         if (fsm->slave->master->debug_level)
             EC_DBG("No PDOs to map for SM%u of slave %u.\n",
                     fsm->sync->index, fsm->slave->ring_position);
@@ -271,10 +265,8 @@
 
 /*****************************************************************************/
 
-/**
- * Add a PDO to the sync managers mapping.
- */
-
+/** Add a PDO to the sync managers mapping.
+ */
 void ec_fsm_mapping_state_add_pdo(
         ec_fsm_mapping_t *fsm /**< mapping state machine */
         )
@@ -289,8 +281,7 @@
     }
 
     // find next PDO
-    if (!(fsm->pdo = ec_fsm_mapping_next_pdo(
-                    fsm, &fsm->pdo->list))) {
+    if (!(fsm->pdo = ec_fsm_mapping_next_pdo(fsm, &fsm->pdo->list))) {
         // no more PDOs to map. write PDO count
         fsm->sdodata.subindex = 0;
         EC_WRITE_U8(&fsm->sdo_value, fsm->pdo_count);
@@ -322,10 +313,8 @@
 
 /*****************************************************************************/
 
-/**
- * Set the number of mapped PDOs.
- */
-
+/** Set the number of mapped PDOs.
+ */
 void ec_fsm_mapping_state_pdo_count(
         ec_fsm_mapping_t *fsm /**< mapping state machine */
         )
@@ -351,10 +340,8 @@
  * Common state functions
  *****************************************************************************/
 
-/**
-   State: ERROR.
-*/
-
+/** State: ERROR.
+ */
 void ec_fsm_mapping_state_error(
         ec_fsm_mapping_t *fsm /**< mapping state machine */
         )
@@ -363,10 +350,8 @@
 
 /*****************************************************************************/
 
-/**
-   State: END.
-*/
-
+/** State: END.
+ */
 void ec_fsm_mapping_state_end(
         ec_fsm_mapping_t *fsm /**< mapping state machine */
         )
--- a/master/fsm_mapping.h	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_mapping.h	Tue Feb 19 08:22:20 2008 +0000
@@ -63,6 +63,7 @@
 
     ec_direction_t dir; /**< current PDO direction */
     ec_sync_t *sync; /**< current sync manager */
+    const ec_pdo_mapping_t *mapping; /**< Mapping to assign. */
     ec_pdo_t *pdo; /**< current PDO */
     ec_sdo_data_t sdodata; /**< SDO configuration data */
     uint16_t sdo_value; /**< SDO value */
--- a/master/fsm_master.c	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_master.c	Tue Feb 19 08:22:20 2008 +0000
@@ -205,7 +205,7 @@
         fsm->topology_change_pending = 1;
         fsm->slaves_responding = datagram->working_counter;
 
-        EC_INFO("%i slave%s responding.\n",
+        EC_INFO("%u slave%s responding.\n",
                 fsm->slaves_responding,
                 fsm->slaves_responding == 1 ? "" : "s");
 
@@ -483,12 +483,11 @@
     down(&master->config_sem);
     if (!master->allow_config) {
         up(&master->config_sem);
-    }
-    else {
+    } else {
         master->config_state = EC_REQUEST_IN_PROGRESS;
         fsm->config_error = 0;
         up(&master->config_sem);
-        
+
         // check for pending slave configurations
         if (ec_fsm_master_action_configure(fsm))
             return;
@@ -911,6 +910,9 @@
     EC_INFO("Bus scanning completed in %u ms.\n",
             (u32) (jiffies - fsm->scan_jiffies) * 1000 / HZ);
 
+    // Attach slave configurations
+    ec_master_attach_slave_configs(master);
+
 #ifdef EC_EOE
     // check if EoE processing has to be started
     ec_master_eoe_start(master);
--- a/master/fsm_master.h	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_master.h	Tue Feb 19 08:22:20 2008 +0000
@@ -44,7 +44,7 @@
 #include "globals.h"
 #include "../include/ecrt.h"
 #include "datagram.h"
-#include "slave.h"
+//#include "slave.h"
 #include "canopen.h"
 
 #include "fsm_slave.h"
--- a/master/fsm_slave.c	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/fsm_slave.c	Tue Feb 19 08:22:20 2008 +0000
@@ -41,8 +41,9 @@
 #include "globals.h"
 #include "master.h"
 #include "mailbox.h"
+#include "fsm_mapping.h"
+#include "slave_config.h"
 #include "fsm_slave.h"
-#include "fsm_mapping.h"
 
 /*****************************************************************************/
 
@@ -569,12 +570,12 @@
                 break;
             case 0x0032:
                 if (ec_slave_fetch_sii_pdos( slave, (uint8_t *) cat_word,
-                            cat_size * 2, EC_TX_PDO))
+                            cat_size * 2, EC_DIR_INPUT)) // TxPdo
                     goto end;
                 break;
             case 0x0033:
                 if (ec_slave_fetch_sii_pdos( slave, (uint8_t *) cat_word,
-                            cat_size * 2, EC_RX_PDO))
+                            cat_size * 2, EC_DIR_OUTPUT)) // RxPdo
                     goto end;
                 break;
             default:
@@ -662,8 +663,8 @@
 
     // clear FMMU configurations
     ec_datagram_npwr(datagram, slave->station_address,
-                     0x0600, EC_FMMU_SIZE * slave->base_fmmu_count);
-    memset(datagram->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
+            0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
+    memset(datagram->data, 0x00, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
     fsm->retries = EC_FSM_RETRIES;
     fsm->state = ec_fsm_slave_conf_state_clear_fmmus;
 }
@@ -729,7 +730,7 @@
     if (!slave->sii_mailbox_protocols) {
         // no mailbox protocols supported
         if (master->debug_level)
-            EC_DBG("Slave %i does not support mailbox communication.\n",
+            EC_DBG("Slave %u does not support mailbox communication.\n",
                     slave->ring_position);
         ec_fsm_slave_conf_enter_preop(fsm);
         return;
@@ -740,41 +741,41 @@
                slave->ring_position);
     }
 
-    if (slave->sii_sync_count >= 2) {
-        // configure sync managers
+    if (slave->sii_sync_count >= 2) { // mailbox configuration provided
         ec_datagram_npwr(datagram, slave->station_address, 0x0800,
-                EC_SYNC_SIZE * slave->sii_sync_count);
-        memset(datagram->data, 0x00, EC_SYNC_SIZE * slave->sii_sync_count);
+                EC_SYNC_PAGE_SIZE * slave->sii_sync_count);
+        memset(datagram->data, 0x00,
+                EC_SYNC_PAGE_SIZE * slave->sii_sync_count);
 
         for (i = 0; i < 2; i++) {
-            ec_sync_config(&slave->sii_syncs[i],
-                    datagram->data + EC_SYNC_SIZE * i);
+            ec_sync_config(&slave->sii_syncs[i], slave->sii_syncs[i].length,
+                    datagram->data + EC_SYNC_PAGE_SIZE * i);
         }
     } else { // no mailbox sync manager configurations provided
         ec_sync_t sync;
 
         if (master->debug_level)
-            EC_DBG("Slave %i does not provide"
+            EC_DBG("Slave %u does not provide"
                     " mailbox sync manager configurations.\n",
                     slave->ring_position);
 
         ec_datagram_npwr(datagram, slave->station_address, 0x0800,
-                EC_SYNC_SIZE * 2);
-        memset(datagram->data, 0x00, EC_SYNC_SIZE * 2);
+                EC_SYNC_PAGE_SIZE * 2);
+        memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * 2);
 
         ec_sync_init(&sync, slave, 0);
         sync.physical_start_address = slave->sii_rx_mailbox_offset;
-        sync.length = slave->sii_rx_mailbox_size;
         sync.control_register = 0x26;
         sync.enable = 1;
-        ec_sync_config(&sync, datagram->data + EC_SYNC_SIZE * sync.index);
+        ec_sync_config(&sync, slave->sii_rx_mailbox_size,
+                datagram->data + EC_SYNC_PAGE_SIZE * sync.index);
 
         ec_sync_init(&sync, slave, 1);
         sync.physical_start_address = slave->sii_tx_mailbox_offset;
-        sync.length = slave->sii_tx_mailbox_size;
         sync.control_register = 0x22;
         sync.enable = 1;
-        ec_sync_config(&sync, datagram->data + EC_SYNC_SIZE * sync.index);
+        ec_sync_config(&sync, slave->sii_tx_mailbox_size,
+                datagram->data + EC_SYNC_PAGE_SIZE * sync.index);
     }
 
     fsm->retries = EC_FSM_RETRIES;
@@ -877,15 +878,22 @@
 {
     ec_slave_t *slave = fsm->slave;
 
-    // No CoE configuration to be applied?
-    if (list_empty(&slave->sdo_confs)) { // skip SDO configuration
+    if (!slave->config) {
+        EC_DBG("Slave %u is not configured.\n", slave->ring_position);
+        ec_fsm_slave_conf_enter_saveop(fsm);
+        return;
+    }
+
+    // No CoE configuration to be applied? FIXME
+    if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
         ec_fsm_slave_conf_enter_mapconf(fsm);
         return;
     }
 
     // start SDO configuration
     fsm->state = ec_fsm_slave_conf_state_sdoconf;
-    fsm->sdodata = list_entry(fsm->slave->sdo_confs.next, ec_sdo_data_t, list);
+    fsm->sdodata =
+        list_entry(fsm->slave->config->sdo_configs.next, ec_sdo_data_t, list);
     ec_fsm_coe_download(&fsm->fsm_coe, fsm->slave, fsm->sdodata);
     ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately
 }
@@ -911,9 +919,9 @@
     }
 
     // Another SDO to configure?
-    if (fsm->sdodata->list.next != &fsm->slave->sdo_confs) {
-        fsm->sdodata = list_entry(fsm->sdodata->list.next,
-                                  ec_sdo_data_t, list);
+    if (fsm->sdodata->list.next != &fsm->slave->config->sdo_configs) {
+        fsm->sdodata =
+            list_entry(fsm->sdodata->list.next, ec_sdo_data_t, list);
         ec_fsm_coe_download(&fsm->fsm_coe, fsm->slave, fsm->sdodata);
         ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately
         return;
@@ -982,21 +990,34 @@
 {
     ec_slave_t *slave = fsm->slave;
     ec_datagram_t *datagram = fsm->datagram;
-    unsigned int i;
+    unsigned int i, offset, num_syncs;
+    const ec_sync_t *sync;
+    ec_direction_t dir;
+    uint16_t size;
 
     if (!slave->sii_sync_count) {
         ec_fsm_slave_conf_enter_fmmu(fsm);
         return;
     }
 
+    if (slave->sii_mailbox_protocols) {
+        offset = 2; // slave has mailboxes
+    } else {
+        offset = 0;
+    }
+    num_syncs = slave->sii_sync_count - offset;
+
     // configure sync managers for process data
-    ec_datagram_npwr(datagram, slave->station_address, 0x0800,
-                     EC_SYNC_SIZE * slave->sii_sync_count);
-    memset(datagram->data, 0x00, EC_SYNC_SIZE * slave->sii_sync_count);
-
-    for (i = 0; i < slave->sii_sync_count; i++) {
-        ec_sync_config(&slave->sii_syncs[i],
-                datagram->data + EC_SYNC_SIZE * i);
+    ec_datagram_npwr(datagram, slave->station_address,
+            0x0800 + EC_SYNC_PAGE_SIZE * offset,
+            EC_SYNC_PAGE_SIZE * num_syncs);
+    memset(datagram->data, 0x00, EC_SYNC_PAGE_SIZE * num_syncs);
+
+    for (i = 0; i < num_syncs; i++) {
+        sync = &slave->sii_syncs[i + offset];
+        dir = ec_sync_direction(sync);
+        size = ec_pdo_mapping_total_size(&slave->config->mapping[dir]);
+        ec_sync_config(sync, size, datagram->data + EC_SYNC_PAGE_SIZE * i);
     }
 
     fsm->retries = EC_FSM_RETRIES;
@@ -1047,7 +1068,9 @@
 {
     ec_slave_t *slave = fsm->slave;
     ec_datagram_t *datagram = fsm->datagram;
-    unsigned int j;
+    unsigned int i;
+    const ec_fmmu_config_t *fmmu;
+    const ec_sync_t *sync;
 
     if (!slave->base_fmmu_count) { // skip FMMU configuration
         ec_fsm_slave_conf_enter_saveop(fsm);
@@ -1056,10 +1079,18 @@
 
     // configure FMMUs
     ec_datagram_npwr(datagram, slave->station_address,
-                     0x0600, EC_FMMU_SIZE * slave->base_fmmu_count);
-    memset(datagram->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
-    for (j = 0; j < slave->fmmu_count; j++) {
-        ec_fmmu_config(&slave->fmmus[j], datagram->data + EC_FMMU_SIZE * j);
+                     0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
+    memset(datagram->data, 0x00, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
+    for (i = 0; i < slave->config->used_fmmus; i++) {
+        fmmu = &slave->config->fmmu_configs[i];
+        if (!(sync = ec_slave_get_pdo_sync(slave, fmmu->dir))) {
+            fsm->state = ec_fsm_slave_state_error;
+            EC_ERR("Failed to determine PDO sync manager for FMMU on slave"
+                    " %u!\n", slave->ring_position);
+            return;
+        }
+        ec_fmmu_config_page(fmmu, sync,
+                datagram->data + EC_FMMU_PAGE_SIZE * i);
     }
 
     fsm->retries = EC_FSM_RETRIES;
--- a/master/globals.h	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/globals.h	Tue Feb 19 08:22:20 2008 +0000
@@ -31,10 +31,9 @@
  *
  *****************************************************************************/
 
-/**
-   \file
-   Global definitions and macros.
-*/
+/** \file
+ * Global definitions and macros.
+ */
 
 /*****************************************************************************/
 
@@ -46,112 +45,121 @@
 #include "../globals.h"
 
 /******************************************************************************
- *  EtherCAT master
+ * EtherCAT master
  *****************************************************************************/
 
-/** clock frequency for the EoE state machines */
+/** Clock frequency for the EoE state machines. */
 #define EC_EOE_FREQUENCY 1000
 
-/** datagram timeout in microseconds */
+/** Datagram timeout in microseconds. */
 #define EC_IO_TIMEOUT 500
 
-/** number of state machine retries on datagram timeout */
+/** Number of state machine retries on datagram timeout. */
 #define EC_FSM_RETRIES 3
 
 /** Seconds to wait before fetching SDO dictionary
     after slave entered PREOP state. */
 #define EC_WAIT_SDO_DICT 3
 
-/** minimum size of a buffer used with ec_state_string() */
+/** Minimum size of a buffer used with ec_state_string(). */
 #define EC_STATE_STRING_SIZE 32
 
-/** maximum EEPROM size in words, to avoid infinite reading. */
+/** Maximum EEPROM size in words, to avoid infinite reading. */
 #define EC_MAX_EEPROM_SIZE 1024
 
 /******************************************************************************
- *  EtherCAT protocol
+ * EtherCAT protocol
  *****************************************************************************/
 
-/** size of an EtherCAT frame header */
+/** Size of an EtherCAT frame header. */
 #define EC_FRAME_HEADER_SIZE 2
 
-/** size of an EtherCAT datagram header */
+/** Size of an EtherCAT datagram header. */
 #define EC_DATAGRAM_HEADER_SIZE 10
 
-/** size of an EtherCAT datagram footer */
+/** Size of an EtherCAT datagram footer. */
 #define EC_DATAGRAM_FOOTER_SIZE 2
 
-/** size of the EtherCAT address field */
+/** Size of the EtherCAT address field. */
 #define EC_ADDR_LEN 4
 
-/** resulting maximum data size of a single datagram in a frame */
+/** Resulting maximum data size of a single datagram in a frame. */
 #define EC_MAX_DATA_SIZE (ETH_DATA_LEN - EC_FRAME_HEADER_SIZE \
                           - EC_DATAGRAM_HEADER_SIZE - EC_DATAGRAM_FOOTER_SIZE)
 
-/** word offset of first EEPROM category. */
+/** Word offset of first EEPROM category. */
 #define EC_FIRST_EEPROM_CATEGORY_OFFSET 0x40
 
-/*****************************************************************************/
-
-/**
-   Convenience macro for printing EtherCAT-specific information to syslog.
-   This will print the message in \a fmt with a prefixed "EtherCAT: ".
-   \param fmt format string (like in printf())
-   \param args arguments (optional)
-*/
-
+/** Size of a sync manager configuration page. */
+#define EC_SYNC_PAGE_SIZE 8
+
+/** Maximum number of FMMUs per slave. */
+#define EC_MAX_FMMUS 16
+
+/** Size of an FMMU configuration page. */
+#define EC_FMMU_PAGE_SIZE 16
+
+/*****************************************************************************/
+
+/** Convenience macro for printing EtherCAT-specific information to syslog.
+ *
+ * This will print the message in \a fmt with a prefixed "EtherCAT: ".
+ *
+ * \param fmt format string (like in printf())
+ * \param args arguments (optional)
+ */
 #define EC_INFO(fmt, args...) \
     printk(KERN_INFO "EtherCAT: " fmt, ##args)
 
-/**
-   Convenience macro for printing EtherCAT-specific errors to syslog.
-   This will print the message in \a fmt with a prefixed "EtherCAT ERROR: ".
-   \param fmt format string (like in printf())
-   \param args arguments (optional)
-*/
-
+/** Convenience macro for printing EtherCAT-specific errors to syslog.
+ *
+ * This will print the message in \a fmt with a prefixed "EtherCAT ERROR: ".
+ *
+ * \param fmt format string (like in printf())
+ * \param args arguments (optional)
+ */
 #define EC_ERR(fmt, args...) \
     printk(KERN_ERR "EtherCAT ERROR: " fmt, ##args)
 
-/**
-   Convenience macro for printing EtherCAT-specific warnings to syslog.
-   This will print the message in \a fmt with a prefixed "EtherCAT WARNING: ".
-   \param fmt format string (like in printf())
-   \param args arguments (optional)
-*/
-
+/** Convenience macro for printing EtherCAT-specific warnings to syslog.
+ *
+ * This will print the message in \a fmt with a prefixed "EtherCAT WARNING: ".
+ *
+ * \param fmt format string (like in printf())
+ * \param args arguments (optional)
+ */
 #define EC_WARN(fmt, args...) \
     printk(KERN_WARNING "EtherCAT WARNING: " fmt, ##args)
 
-/**
-   Convenience macro for printing EtherCAT debug messages to syslog.
-   This will print the message in \a fmt with a prefixed "EtherCAT DEBUG: ".
-   \param fmt format string (like in printf())
-   \param args arguments (optional)
-*/
-
+/** Convenience macro for printing EtherCAT debug messages to syslog.
+ *
+ * This will print the message in \a fmt with a prefixed "EtherCAT DEBUG: ".
+ *
+ * \param fmt format string (like in printf())
+ * \param args arguments (optional)
+ */
 #define EC_DBG(fmt, args...) \
     printk(KERN_DEBUG "EtherCAT DEBUG: " fmt, ##args)
 
-/**
-   Convenience macro for defining read-only SysFS attributes.
-   This results in creating a static variable called attr_\a NAME. The SysFS
-   file will be world-readable.
-   \param NAME name of the attribute to create.
-*/
-
+/** Convenience macro for defining read-only SysFS attributes.
+ *
+ * This results in creating a static variable called attr_\a NAME. The SysFS
+ * file will be world-readable.
+ *
+ * \param NAME name of the attribute to create.
+ */
 #define EC_SYSFS_READ_ATTR(NAME) \
     static struct attribute attr_##NAME = { \
         .name = EC_STR(NAME), .owner = THIS_MODULE, .mode = S_IRUGO \
     }
 
-/**
-   Convenience macro for defining read-write SysFS attributes.
-   This results in creating a static variable called attr_\a NAME. The SysFS
-   file will be word-readable plus owner-writable.
-   \param NAME name of the attribute to create.
-*/
-
+/** Convenience macro for defining read-write SysFS attributes.
+ *
+ * This results in creating a static variable called attr_\a NAME. The SysFS
+ * file will be word-readable plus owner-writable.
+ *
+ * \param NAME name of the attribute to create.
+ */
 #define EC_SYSFS_READ_WRITE_ATTR(NAME) \
     static struct attribute attr_##NAME = { \
         .name = EC_STR(NAME), .owner = THIS_MODULE, .mode = S_IRUGO | S_IWUSR \
@@ -171,27 +179,22 @@
 
 /*****************************************************************************/
 
-/**
-   Code - Message pair.
-   Some EtherCAT datagrams support reading a status code to display a certain
-   message. This type allows to map a code to a message string.
-*/
-
-typedef struct
-{
-    uint32_t code; /**< code */
-    const char *message; /**< message belonging to \a code */
+/** Code - Message pair.
+ *
+ * Some EtherCAT datagrams support reading a status code to display a certain
+ * message. This type allows to map a code to a message string.
+ */
+typedef struct {
+    uint32_t code; /**< Code. */
+    const char *message; /**< Message belonging to \a code. */
 }
 ec_code_msg_t;
 
 /*****************************************************************************/
 
-/**
- * Master request state.
- */
-
-typedef enum
-{
+/** Master request state.
+ */
+typedef enum {
     EC_REQUEST_QUEUED,
     EC_REQUEST_IN_PROGRESS,
     EC_REQUEST_COMPLETE,
@@ -201,6 +204,7 @@
 
 /*****************************************************************************/
 
+typedef struct ec_slave ec_slave_t; /**< \see ec_slave. */
 typedef struct ec_sdo ec_sdo_t; /**< \see ec_sdo */
 
 /*****************************************************************************/
--- a/master/master.c	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/master.c	Tue Feb 19 08:22:20 2008 +0000
@@ -46,16 +46,18 @@
 
 #include "../include/ecrt.h"
 #include "globals.h"
-#include "master.h"
 #include "slave.h"
+#include "slave_config.h"
 #include "device.h"
 #include "datagram.h"
 #ifdef EC_EOE
 #include "ethernet.h"
 #endif
-
-/*****************************************************************************/
-
+#include "master.h"
+
+/*****************************************************************************/
+
+void ec_master_destroy_slave_configs(ec_master_t *);
 void ec_master_destroy_domains(ec_master_t *);
 static int ec_master_idle_thread(ec_master_t *);
 static int ec_master_operation_thread(ec_master_t *);
@@ -122,6 +124,8 @@
     INIT_LIST_HEAD(&master->slaves);
     master->slave_count = 0;
     
+    INIT_LIST_HEAD(&master->configs);
+
     master->scan_state = EC_REQUEST_IN_PROGRESS;
     master->allow_scan = 1;
     init_MUTEX(&master->scan_sem);
@@ -136,12 +140,14 @@
     master->datagram_index = 0;
 
     INIT_LIST_HEAD(&master->domains);
+
     master->debug_level = 0;
-
     master->stats.timeouts = 0;
     master->stats.corrupted = 0;
     master->stats.unmatched = 0;
     master->stats.output_jiffies = 0;
+    master->pdo_slaves_offline = 0; // assume all PDO slaves online
+    master->frames_timed_out = 0;
 
     for (i = 0; i < HZ; i++) {
         master->idle_cycle_times[i] = 0;
@@ -236,6 +242,7 @@
 #ifdef EC_EOE
     ec_master_clear_eoe_handlers(master);
 #endif
+    ec_master_destroy_slave_configs(master);
     ec_master_destroy_slaves(master);
     ec_master_destroy_domains(master);
     ec_fsm_master_clear(&master->fsm);
@@ -251,10 +258,8 @@
 /*****************************************************************************/
 
 #ifdef EC_EOE
-/**
- * Clear and free all EoE handlers.
+/** Clear and free all EoE handlers.
  */
-
 void ec_master_clear_eoe_handlers(
         ec_master_t *master /**< EtherCAT master */
         )
@@ -271,15 +276,27 @@
 
 /*****************************************************************************/
 
-/**
-   Destroy all slaves.
-*/
-
+/** Destroy all slave configurations.
+ */
+void ec_master_destroy_slave_configs(ec_master_t *master)
+{
+    ec_slave_config_t *sc, *next;
+
+    list_for_each_entry_safe(sc, next, &master->configs, list) {
+        list_del(&sc->list);
+        ec_slave_config_destroy(sc);
+    }
+}
+
+/*****************************************************************************/
+
+/** Destroy all slaves.
+ */
 void ec_master_destroy_slaves(ec_master_t *master)
 {
-    ec_slave_t *slave, *next_slave;
-
-    list_for_each_entry_safe(slave, next_slave, &master->slaves, list) {
+    ec_slave_t *slave, *next;
+
+    list_for_each_entry_safe(slave, next, &master->slaves, list) {
         list_del(&slave->list);
         ec_slave_destroy(slave);
     }
@@ -295,9 +312,9 @@
 
 void ec_master_destroy_domains(ec_master_t *master)
 {
-    ec_domain_t *domain, *next_d;
-
-    list_for_each_entry_safe(domain, next_d, &master->domains, list) {
+    ec_domain_t *domain, *next;
+
+    list_for_each_entry_safe(domain, next, &master->domains, list) {
         list_del(&domain->list);
         ec_domain_destroy(domain);
     }
@@ -467,8 +484,6 @@
         EC_DBG("Switching to operation mode.\n");
 
     master->mode = EC_MASTER_MODE_OPERATION;
-    master->pdo_slaves_offline = 0; // assume all PDO slaves online
-    master->frames_timed_out = 0;
     master->ext_request_cb = NULL;
     master->ext_release_cb = NULL;
     master->ext_cb_data = NULL;
@@ -505,9 +520,11 @@
     master->release_cb = ec_master_release_cb;
     master->cb_data = master;
     
+    ec_master_destroy_slave_configs(master);
+    ec_master_destroy_domains(master);
+
     // set states for all slaves
     list_for_each_entry(slave, &master->slaves, list) {
-        ec_slave_reset(slave);
         ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
     }
 #ifdef EC_EOE
@@ -518,8 +535,6 @@
     }
 #endif
 
-    ec_master_destroy_domains(master);
-    
     if (ec_master_thread_start(master, ec_master_idle_thread))
         EC_WARN("Failed to restart master thread!\n");
 #ifdef EC_EOE
@@ -1241,101 +1256,51 @@
 
 /*****************************************************************************/
 
-/**
- * Translates an ASCII coded bus-address to a slave pointer.
- * These are the valid addressing schemes:
- * - \a "X" = the Xth slave on the bus (ring position),
- * - \a "#X" = the slave with alias X,
- * - \a "#X:Y" = the Yth slave after the slave with alias X.
- * X and Y are zero-based indices and may be provided in hexadecimal or octal
- * notation (with appropriate prefix).
- * \return pointer to the slave on success, else NULL
+/** Detaches the slave configurations from the slaves.
  */
-
-ec_slave_t *ec_master_parse_slave_address(
-        const ec_master_t *master, /**< EtherCAT master */
-        const char *address /**< address string */
+void ec_master_detach_slave_configs(
+        ec_master_t *master /**< EtherCAT master. */
         )
 {
-    unsigned long first, second;
-    char *remainder, *remainder2;
-    const char *original;
-    unsigned int alias_requested = 0, alias_not_found = 1;
-    ec_slave_t *alias_slave = NULL, *slave;
-
-    original = address;
-
-    if (!address[0])
-        goto out_invalid;
-
-    if (address[0] == '#') {
-        alias_requested = 1;
-        address++;
-    }
-
-    first = simple_strtoul(address, &remainder, 0);
-    if (remainder == address)
-        goto out_invalid;
-
-    if (alias_requested) {
-        list_for_each_entry(alias_slave, &master->slaves, list) {
-            if (alias_slave->sii_alias == first) {
-                alias_not_found = 0;
-                break;
-            }
-        }
-        if (alias_not_found) {
-            EC_ERR("Alias not found!\n");
-            goto out_invalid;
-        }
-    }
-
-    if (!remainder[0]) {
-        if (alias_requested) { // alias addressing
-            return alias_slave;
-        }
-        else { // position addressing
-            list_for_each_entry(slave, &master->slaves, list) {
-                if (slave->ring_position == first) return slave;
-            }
-            EC_ERR("Slave index out of range!\n");
-            goto out_invalid;
-        }
-    }
-    else if (alias_requested && remainder[0] == ':') { // field addressing
-        struct list_head *list;
-        remainder++;
-        second = simple_strtoul(remainder, &remainder2, 0);
-
-        if (remainder2 == remainder || remainder2[0])
-            goto out_invalid;
-
-        list = &alias_slave->list;
-        while (second--) {
-            list = list->next;
-            if (list == &master->slaves) { // last slave exceeded
-                EC_ERR("Slave index out of range!\n");
-                goto out_invalid;
-            }
-        }
-        return list_entry(list, ec_slave_t, list);
-    }
-
-out_invalid:
-    EC_ERR("Invalid slave address string \"%s\"!\n", original);
-    return NULL;
+    ec_slave_config_t *sc;
+
+    if (!master->configs_attached)
+        return;
+
+    list_for_each_entry(sc, &master->configs, list) {
+        ec_slave_config_detach(sc); 
+    }
+
+    master->configs_attached = 0;
+}
+
+/*****************************************************************************/
+
+/** Attaches the slave configurations to the slaves.
+ */
+int ec_master_attach_slave_configs(
+        ec_master_t *master /**< EtherCAT master. */
+        )
+{
+    ec_slave_config_t *sc;
+    unsigned int errors = 0;
+
+    if (master->configs_attached)
+        return 0;
+
+    list_for_each_entry(sc, &master->configs, list) {
+        if (ec_slave_config_attach(sc))
+            errors = 1;
+    }
+
+    master->configs_attached = !errors;
+    return errors ? -1 : 0;
 }
 
 /******************************************************************************
  *  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;
@@ -1364,25 +1329,16 @@
 
 /*****************************************************************************/
 
-/**
-   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 */)
+int ecrt_master_activate(ec_master_t *master)
 {
     uint32_t domain_offset;
     ec_domain_t *domain;
 
-    // allocate all domains
+    // finish 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);
+        if (ec_domain_finish(domain, domain_offset)) {
+            EC_ERR("Failed to finish domain %X!\n", (u32) domain);
             return -1;
         }
         domain_offset += domain->data_size;
@@ -1435,12 +1391,7 @@
 
 /*****************************************************************************/
 
-/**
-   Asynchronous sending of datagrams.
-   \ingroup RealtimeInterface
-*/
-
-void ecrt_master_send(ec_master_t *master /**< EtherCAT master */)
+void ecrt_master_send(ec_master_t *master)
 {
     ec_datagram_t *datagram, *n;
 
@@ -1468,12 +1419,7 @@
 
 /*****************************************************************************/
 
-/**
-   Asynchronous receiving of datagrams.
-   \ingroup RealtimeInterface
-*/
-
-void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */)
+void ecrt_master_receive(ec_master_t *master)
 {
     ec_datagram_t *datagram, *next;
     cycles_t cycles_timeout;
@@ -1510,80 +1456,65 @@
 
 /*****************************************************************************/
 
-/**
- * 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;
-}
-
-/*****************************************************************************/
-
-/**
- * Obtains a slave pointer by its ring position.
- * 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_by_pos(
-        const ec_master_t *master, /**< EtherCAT master */
-        uint16_t ring_position, /**< ring position */
-        uint32_t vendor_id, /**< vendor ID */
-        uint32_t product_code /**< product code */
-        )
-{
-    ec_slave_t *slave;
+ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
+        uint16_t alias, uint16_t position, uint32_t vendor_id,
+        uint32_t product_code)
+{
+    ec_slave_config_t *sc;
     unsigned int found = 0;
 
-    list_for_each_entry(slave, &master->slaves, list) {
-        if (slave->ring_position == ring_position) {
+    list_for_each_entry(sc, &master->configs, list) {
+        if (sc->alias == alias && sc->position == position) {
             found = 1;
             break;
         }
     }
 
-    if (!found) {
-        EC_ERR("Slave index out of range!\n");
-        return NULL;
-    }
-
-    return ec_slave_validate(slave, vendor_id, product_code) ? NULL : slave;
-}
-
-/*****************************************************************************/
-
-/**
-   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 */
-                           )
+    if (found) {
+        if (master->debug_level) {
+            EC_INFO("Using existing slave configuration for %u:%u\n",
+                    alias, position);
+        }
+        if (sc->vendor_id != vendor_id || sc->product_code != product_code) {
+            EC_ERR("Slave type mismatch. Slave was configured as"
+                    " 0x%08X/0x%08X before. Now configuring with"
+                    " 0x%08X/0x%08X.\n", sc->vendor_id, sc->product_code,
+                    vendor_id, product_code);
+            return NULL;
+        }
+    } else {
+        if (master->debug_level) {
+            EC_INFO("Creating slave configuration for %u:%u,"
+                    " 0x%08X/0x%08X.\n", alias, position, vendor_id,
+                    product_code);
+        }
+
+        if (!(sc = (ec_slave_config_t *) kmalloc(sizeof(ec_slave_config_t),
+                        GFP_KERNEL))) {
+            EC_ERR("Failed to allocate memory for slave configuration.\n");
+            return NULL;
+        }
+
+        if (ec_slave_config_init(sc, master, alias, position, vendor_id,
+                    product_code)) {
+            EC_ERR("Failed to init slave configuration.\n");
+            return NULL;
+        }
+
+        // try to find the addressed slave
+        ec_slave_config_attach(sc);
+        ec_slave_config_load_default_mapping(sc);
+
+        list_add_tail(&sc->list, &master->configs);
+    }
+
+    return sc;
+}
+
+/*****************************************************************************/
+
+void ecrt_master_callbacks(ec_master_t *master, int (*request_cb)(void *),
+        void (*release_cb)(void *), void *cb_data)
 {
     master->ext_request_cb = request_cb;
     master->ext_release_cb = release_cb;
@@ -1592,19 +1523,13 @@
 
 /*****************************************************************************/
 
-/**
- * Reads the current master status.
- */
-
-void ecrt_master_get_status(const ec_master_t *master, /**< EtherCAT master */
-        ec_master_status_t *status /**< target status object */
-        )
-{
-    status->bus_status =
+void ecrt_master_state(const ec_master_t *master, ec_master_state_t *state)
+{
+    state->bus_state =
         (master->pdo_slaves_offline || master->frames_timed_out)
         ? EC_BUS_FAILURE : EC_BUS_OK;
-    status->bus_tainted = master->fsm.tainted; 
-    status->slaves_responding = master->fsm.slaves_responding;
+    state->bus_tainted = master->fsm.tainted; 
+    state->slaves_responding = master->fsm.slaves_responding;
 }
 
 /*****************************************************************************/
@@ -1616,9 +1541,8 @@
 EXPORT_SYMBOL(ecrt_master_send);
 EXPORT_SYMBOL(ecrt_master_receive);
 EXPORT_SYMBOL(ecrt_master_callbacks);
-EXPORT_SYMBOL(ecrt_master_get_slave);
-EXPORT_SYMBOL(ecrt_master_get_slave_by_pos);
-EXPORT_SYMBOL(ecrt_master_get_status);
+EXPORT_SYMBOL(ecrt_master_slave_config);
+EXPORT_SYMBOL(ecrt_master_state);
 
 /** \endcond */
 
--- a/master/master.h	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/master.h	Tue Feb 19 08:22:20 2008 +0000
@@ -53,12 +53,9 @@
 
 /*****************************************************************************/
 
-/**
-   EtherCAT master mode.
-*/
-
-typedef enum
-{
+/** EtherCAT master mode.
+ */
+typedef enum {
     EC_MASTER_MODE_ORPHANED,
     EC_MASTER_MODE_IDLE,
     EC_MASTER_MODE_OPERATION
@@ -67,12 +64,9 @@
 
 /*****************************************************************************/
 
-/**
-   Cyclic statistics.
-*/
-
-typedef struct
-{
+/** Cyclic statistics.
+ */
+typedef struct {
     unsigned int timeouts; /**< datagram timeouts */
     unsigned int corrupted; /**< corrupted frames */
     unsigned int unmatched; /**< unmatched datagrams (received, but not
@@ -83,11 +77,10 @@
 
 /*****************************************************************************/
 
-/**
-   EtherCAT master.
-   Manages slaves, domains and IO.
-*/
-
+/** EtherCAT master.
+ *
+ * Manages slaves, domains and IO.
+ */
 struct ec_master
 {
     struct kobject kobj; /**< kobject */
@@ -110,6 +103,9 @@
 
     struct list_head slaves; /**< list of slaves on the bus */
     unsigned int slave_count; /**< number of slaves on the bus */
+
+    struct list_head configs; /**< Bus configuration list. */
+    unsigned int configs_attached; /**< Slave configurations were attached. */
     
     ec_request_state_t scan_state; /**< current scanning state */
     unsigned int allow_scan; /**< non-zero, if slave scanning is allowed */
@@ -196,6 +192,7 @@
 void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *);
 
 // misc.
+int ec_master_attach_slave_configs(ec_master_t *);
 void ec_master_output_stats(ec_master_t *);
 #ifdef EC_EOE
 void ec_master_clear_eoe_handlers(ec_master_t *);
--- a/master/module.c	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/module.c	Tue Feb 19 08:22:20 2008 +0000
@@ -31,10 +31,9 @@
  *
  *****************************************************************************/
 
-/**
-   \file
-   EtherCAT master driver module.
-*/
+/** \file
+ * EtherCAT master driver module.
+ */
 
 /*****************************************************************************/
 
@@ -49,7 +48,7 @@
 
 /*****************************************************************************/
 
-#define MAX_MASTERS 5 /**< maximum number of masters */
+#define MAX_MASTERS 5 /**< Maximum number of masters. */
 
 /*****************************************************************************/
 
@@ -541,28 +540,7 @@
  *  Realtime interface
  *****************************************************************************/
 
-/**
- * Returns the version magic of the realtime interface.
- * \return ECRT version magic.
- * \ingroup RealtimeInterface
- */
-
-unsigned int ecrt_version_magic(void)
-{
-    return ECRT_VERSION_MAGIC;
-}
-
-/*****************************************************************************/
-
-/**
-   Reserves an EtherCAT master for realtime operation.
-   \return pointer to reserved master, or NULL on error
-   \ingroup RealtimeInterface
-*/
-
-ec_master_t *ecrt_request_master(unsigned int master_index
-                                 /**< master index */
-                                 )
+ec_master_t *ecrt_request_master(unsigned int master_index)
 {
     ec_master_t *master;
 
@@ -622,12 +600,7 @@
 
 /*****************************************************************************/
 
-/**
-   Releases a reserved EtherCAT master.
-   \ingroup RealtimeInterface
-*/
-
-void ecrt_release_master(ec_master_t *master /**< EtherCAT master */)
+void ecrt_release_master(ec_master_t *master)
 {
     EC_INFO("Releasing master %u...\n", master->index);
 
@@ -646,6 +619,13 @@
 
 /*****************************************************************************/
 
+unsigned int ecrt_version_magic(void)
+{
+    return ECRT_VERSION_MAGIC;
+}
+
+/*****************************************************************************/
+
 /** \cond */
 
 module_init(ec_init_module);
--- a/master/pdo.c	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/pdo.c	Tue Feb 19 08:22:20 2008 +0000
@@ -44,66 +44,196 @@
 
 /*****************************************************************************/
 
-/**
- * PDO constructor.
- */
-
-void ec_pdo_init(ec_pdo_t *pdo /**< EtherCAT PDO */)
-{
+void ec_pdo_clear_entries(ec_pdo_t *);
+
+/*****************************************************************************/
+
+/** PDO constructor.
+ */
+void ec_pdo_init(
+        ec_pdo_t *pdo /**< EtherCAT PDO */
+        )
+{
+    pdo->sync_index = -1; // not assigned 
     pdo->name = NULL;
     INIT_LIST_HEAD(&pdo->entries);
 }
 
 /*****************************************************************************/
 
-/**
- * PDO destructor.
- */
-
+/** Pdo copy constructor.
+ */
+int ec_pdo_init_copy(ec_pdo_t *pdo, const ec_pdo_t *other_pdo)
+{
+    pdo->dir = other_pdo->dir;
+    pdo->index = other_pdo->index;
+    pdo->sync_index = other_pdo->sync_index;
+    pdo->name = NULL;
+    INIT_LIST_HEAD(&pdo->entries);
+
+    if (ec_pdo_set_name(pdo, other_pdo->name))
+        goto out_return;
+
+    if (ec_pdo_copy_entries(pdo, other_pdo))
+        goto out_clear;
+
+    return 0;
+
+out_clear:
+    ec_pdo_clear(pdo);
+out_return:
+    return -1;
+}
+
+/*****************************************************************************/
+
+/** PDO destructor.
+ */
 void ec_pdo_clear(ec_pdo_t *pdo /**< EtherCAT PDO */)
 {
+    if (pdo->name)
+        kfree(pdo->name);
+
+    ec_pdo_clear_entries(pdo);
+}
+
+/*****************************************************************************/
+
+/** Clear Pdo entry list.
+ */
+void ec_pdo_clear_entries(ec_pdo_t *pdo /**< EtherCAT PDO */)
+{
     ec_pdo_entry_t *entry, *next;
 
     // free all PDO entries
     list_for_each_entry_safe(entry, next, &pdo->entries, list) {
         list_del(&entry->list);
+        ec_pdo_entry_clear(entry);
         kfree(entry);
     }
 }
 
 /*****************************************************************************/
 
-/**
- * Makes a deep copy of a PDO.
- */
-
-int ec_pdo_copy(ec_pdo_t *pdo, const ec_pdo_t *other_pdo)
-{
-    ec_pdo_entry_t *entry, *other_entry, *next;
-
-    // make flat copy
-    *pdo = *other_pdo;
-
-    INIT_LIST_HEAD(&pdo->entries);
-    list_for_each_entry(other_entry, &other_pdo->entries, list) {
+/** Set Pdo name.
+ */
+int ec_pdo_set_name(
+        ec_pdo_t *pdo, /**< Pdo. */
+        const char *name /**< New name. */
+        )
+{
+    unsigned int len;
+
+    if (pdo->name)
+        kfree(pdo->name);
+
+    if (name && (len = strlen(name))) {
+        if (!(pdo->name = (char *) kmalloc(len + 1, GFP_KERNEL))) {
+            EC_ERR("Failed to allocate PDO name.\n");
+            return -1;
+        }
+        memcpy(pdo->name, name, len + 1);
+    } else {
+        pdo->name = NULL;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** Copy Pdo entries from another Pdo.
+ */
+int ec_pdo_copy_entries(ec_pdo_t *pdo, const ec_pdo_t *other)
+{
+    ec_pdo_entry_t *entry, *other_entry;
+
+    ec_pdo_clear_entries(pdo);
+
+    list_for_each_entry(other_entry, &other->entries, list) {
         if (!(entry = (ec_pdo_entry_t *)
                     kmalloc(sizeof(ec_pdo_entry_t), GFP_KERNEL))) {
             EC_ERR("Failed to allocate memory for PDO entry copy.\n");
-            goto out_free;
-        }
-
-        *entry = *other_entry; // flat copy is sufficient
+            return -1;
+        }
+
+        if (ec_pdo_entry_init_copy(entry, other_entry)) {
+            kfree(entry);
+            return -1;
+        }
+
         list_add_tail(&entry->list, &pdo->entries);
     }
 
     return 0;
-
-out_free:
-    list_for_each_entry_safe(entry, next, &pdo->entries, list) {
-        list_del(&entry->list);
-        kfree(entry);
-    }
-    return -1;
-}
-
-/*****************************************************************************/
+}
+
+/*****************************************************************************/
+
+/** Pdo entry constructor.
+ */
+void ec_pdo_entry_init(
+        ec_pdo_entry_t *entry /**< Pdo entry. */
+        )
+{
+    entry->name = NULL;
+}
+
+/*****************************************************************************/
+
+/** Pdo entry copy constructor.
+ */
+int ec_pdo_entry_init_copy(
+        ec_pdo_entry_t *entry, /**< Pdo entry. */
+        const ec_pdo_entry_t *other /**< Pdo entry to copy from. */
+        )
+{
+    entry->index = other->index;
+    entry->subindex = other->subindex;
+    entry->name = NULL;
+    entry->bit_length = other->bit_length;
+
+    if (ec_pdo_entry_set_name(entry, other->name))
+        return -1;
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** Pdo entry destructor.
+ */
+void ec_pdo_entry_clear(ec_pdo_entry_t *entry /**< Pdo entry. */)
+{
+    if (entry->name)
+        kfree(entry->name);
+}
+
+/*****************************************************************************/
+
+/** Set Pdo entry name.
+ */
+int ec_pdo_entry_set_name(
+        ec_pdo_entry_t *entry, /**< Pdo entry. */
+        const char *name /**< New name. */
+        )
+{
+    unsigned int len;
+
+    if (entry->name)
+        kfree(entry->name);
+
+    if (name && (len = strlen(name))) {
+        if (!(entry->name = (char *) kmalloc(len + 1, GFP_KERNEL))) {
+            EC_ERR("Failed to allocate PDO entry name.\n");
+            return -1;
+        }
+        memcpy(entry->name, name, len + 1);
+    } else {
+        entry->name = NULL;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
--- a/master/pdo.h	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/pdo.h	Tue Feb 19 08:22:20 2008 +0000
@@ -43,59 +43,47 @@
 
 #include <linux/list.h>
 
+#include "../include/ecrt.h"
+
 #include "globals.h"
 
 /*****************************************************************************/
 
-/**
- * PDO type.
+/** PDO description.
  */
-
-typedef enum
-{
-    EC_RX_PDO, /**< Reveive PDO */
-    EC_TX_PDO /**< Transmit PDO */
-}
-ec_pdo_type_t;
+typedef struct {
+    struct list_head list; /**< List item. */
+    ec_direction_t dir; /**< PDO direction. */
+    uint16_t index; /**< PDO index. */
+    int8_t sync_index; /**< Assigned sync manager. */
+    char *name; /**< PDO name. */
+    struct list_head entries; /**< List of PDO entries. */
+} ec_pdo_t;
 
 /*****************************************************************************/
 
-/**
- * PDO description.
+/** PDO entry description.
  */
-
-typedef struct
-{
-    struct list_head list; /**< list item */
-    ec_pdo_type_t type; /**< PDO type */
-    uint16_t index; /**< PDO index */
-    int8_t sync_index; /**< assigned sync manager */
-    char *name; /**< PDO name */
-    struct list_head entries; /**< entry list */
-}
-ec_pdo_t;
-
-/*****************************************************************************/
-
-/**
- * PDO entry description.
- */
-
-typedef struct
-{
+typedef struct {
     struct list_head list; /**< list item */
     uint16_t index; /**< PDO entry index */
     uint8_t subindex; /**< PDO entry subindex */
     char *name; /**< entry name */
     uint8_t bit_length; /**< entry length in bit */
-}
-ec_pdo_entry_t;
+} ec_pdo_entry_t;
 
 /*****************************************************************************/
 
 void ec_pdo_init(ec_pdo_t *);
+int ec_pdo_init_copy(ec_pdo_t *, const ec_pdo_t *);
 void ec_pdo_clear(ec_pdo_t *);
-int ec_pdo_copy(ec_pdo_t *, const ec_pdo_t *);
+int ec_pdo_set_name(ec_pdo_t *, const char *);
+int ec_pdo_copy_entries(ec_pdo_t *, const ec_pdo_t *);
+
+void ec_pdo_entry_init(ec_pdo_entry_t *);
+int ec_pdo_entry_init_copy(ec_pdo_entry_t *, const ec_pdo_entry_t *);
+void ec_pdo_entry_clear(ec_pdo_entry_t *);
+int ec_pdo_entry_set_name(ec_pdo_entry_t *, const char *);
 
 /*****************************************************************************/
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/pdo_mapping.c	Tue Feb 19 08:22:20 2008 +0000
@@ -0,0 +1,319 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU General Public License
+ *  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
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  The 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.
+ *
+ *****************************************************************************/
+
+/**
+   \file
+   EtherCAT Pdo mapping methods.
+*/
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+
+#include "globals.h"
+#include "pdo.h"
+#include "slave_config.h"
+#include "master.h"
+
+#include "pdo_mapping.h"
+
+/*****************************************************************************/
+
+/** Pdo mapping constructor.
+ */
+void ec_pdo_mapping_init(
+        ec_pdo_mapping_t *pm /**< Pdo mapping. */
+        )
+{
+    INIT_LIST_HEAD(&pm->pdos);
+    pm->default_mapping = 1;
+}
+
+/*****************************************************************************/
+
+/** Pdo mapping destructor.
+ */
+void ec_pdo_mapping_clear(ec_pdo_mapping_t *pm /**< Pdo mapping. */)
+{
+    ec_pdo_mapping_clear_pdos(pm);
+}
+
+/*****************************************************************************/
+
+/** Clears the list of mapped Pdos.
+ */
+void ec_pdo_mapping_clear_pdos(ec_pdo_mapping_t *pm /**< Pdo mapping. */)
+{
+    ec_pdo_t *pdo, *next;
+
+    list_for_each_entry_safe(pdo, next, &pm->pdos, list) {
+        list_del_init(&pdo->list);
+        ec_pdo_clear(pdo);
+        kfree(pdo);
+    }
+}
+
+/*****************************************************************************/
+
+/** Calculates the total size of the mapped PDO entries.
+ *
+ * \retval Data size in byte.
+ */
+uint16_t ec_pdo_mapping_total_size(
+        const ec_pdo_mapping_t *pm /**< Pdo mapping. */
+        )
+{
+    unsigned int bit_size;
+    const ec_pdo_t *pdo;
+    const ec_pdo_entry_t *pdo_entry;
+    uint16_t byte_size;
+
+    bit_size = 0;
+    list_for_each_entry(pdo, &pm->pdos, list) {
+        list_for_each_entry(pdo_entry, &pdo->entries, list) {
+            bit_size += pdo_entry->bit_length;
+        }
+    }
+
+    if (bit_size % 8) // round up to full bytes
+        byte_size = bit_size / 8 + 1;
+    else
+        byte_size = bit_size / 8;
+
+    return byte_size;
+}
+
+/*****************************************************************************/
+
+/** Adds a Pdo to the mapping.
+ *
+ * \return 0 on success, else < 0
+ */
+int ec_pdo_mapping_add_pdo(
+        ec_pdo_mapping_t *pm, /**< Pdo mapping. */
+        const ec_pdo_t *pdo /**< PDO to add. */
+        )
+{
+    ec_pdo_t *mapped_pdo;
+
+    // PDO already mapped?
+    list_for_each_entry(mapped_pdo, &pm->pdos, list) {
+        if (mapped_pdo->index != pdo->index) continue;
+        EC_ERR("PDO 0x%04X is already mapped!\n", pdo->index);
+        return -1;
+    }
+    
+    if (!(mapped_pdo = kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
+        EC_ERR("Failed to allocate memory for PDO mapping.\n");
+        return -1;
+    }
+
+    if (ec_pdo_init_copy(mapped_pdo, pdo)) {
+        kfree(mapped_pdo);
+        return -1;
+    }
+
+    list_add_tail(&mapped_pdo->list, &pm->pdos);
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** Add a Pdo to the mapping.
+ *
+ * The first call of this method will clear the default mapping.
+ *
+ * \retval 0 Success.
+ * \retval -1 Error.
+ */
+int ec_pdo_mapping_add_pdo_info(
+        ec_pdo_mapping_t *pm, /**< Pdo mapping. */
+        const ec_pdo_info_t *pdo_info, /**< Pdo information. */
+        const ec_slave_config_t *config /**< Slave configuration, to load
+                                          default entries. */
+        )
+{
+    unsigned int i;
+    ec_pdo_t *pdo;
+    ec_pdo_entry_t *entry;
+    const ec_pdo_entry_info_t *entry_info;
+
+    if (pm->default_mapping) {
+        pm->default_mapping = 0;
+        ec_pdo_mapping_clear_pdos(pm);
+    }
+
+    if (!(pdo = (ec_pdo_t *) kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
+        EC_ERR("Failed to allocate memory for Pdo.\n");
+        goto out_return;
+    }
+
+    ec_pdo_init(pdo);
+    pdo->dir = pdo_info->dir;
+    pdo->index = pdo_info->index;
+
+    if (config->master->debug_level)
+        EC_INFO("Adding Pdo 0x%04X to mapping.\n", pdo->index);
+
+    if (pdo_info->n_entries) { // Pdo configuration provided
+        if (config->master->debug_level)
+            EC_INFO("  Pdo configuration provided.\n");
+
+        for (i = 0; i < pdo_info->n_entries; i++) {
+            entry_info = &pdo_info->entries[i];
+
+            if (!(entry = kmalloc(sizeof(ec_pdo_entry_t), GFP_KERNEL))) {
+                EC_ERR("Failed to allocate memory for PDO entry.\n");
+                goto out_free;
+            }
+
+            ec_pdo_entry_init(entry);
+            entry->index = entry_info->index;
+            entry->subindex = entry_info->subindex;
+            entry->bit_length = entry_info->bit_length;
+            list_add_tail(&entry->list, &pdo->entries);
+        }
+    } else { // use default Pdo configuration
+        if (config->master->debug_level)
+            EC_INFO("  Using default Pdo configuration.\n");
+
+        if (config->slave) {
+            ec_sync_t *sync;
+            ec_pdo_t *default_pdo;
+
+            if ((sync = ec_slave_get_pdo_sync(config->slave, pdo->dir))) {
+                list_for_each_entry(default_pdo, &sync->mapping.pdos, list) {
+                    if (default_pdo->index != pdo->index)
+                        continue;
+                    if (config->master->debug_level)
+                        EC_INFO("  Found Pdo name \"%s\".\n",
+                                default_pdo->name);
+                    // try to take Pdo name from mapped one
+                    if (ec_pdo_set_name(pdo, default_pdo->name))
+                        goto out_free;
+                    // copy entries (= default Pdo configuration)
+                    if (ec_pdo_copy_entries(pdo, default_pdo))
+                        goto out_free;
+                    if (config->master->debug_level) {
+                        const ec_pdo_entry_t *entry;
+                        list_for_each_entry(entry, &pdo->entries, list) {
+                            EC_INFO("    Entry 0x%04X:%u.\n",
+                                    entry->index, entry->subindex);
+                        }
+                    }
+                }
+            } else {
+                EC_WARN("Slave %u does not provide a default Pdo"
+                        " configuration!\n", config->slave->ring_position);
+            }
+        } else {
+            EC_WARN("Failed to load default Pdo configuration for %u:%u:"
+                    " Slave not found.\n", config->alias, config->position);
+        }
+    }
+
+    list_add_tail(&pdo->list, &pm->pdos);
+    return 0;
+
+out_free:
+    ec_pdo_clear(pdo);
+    kfree(pdo);
+out_return:
+    return -1;
+}
+
+/*****************************************************************************/
+
+/** Makes a deep copy of another Pdo mapping.
+ *
+ * \return 0 on success, else < 0
+ */
+int ec_pdo_mapping_copy(
+        ec_pdo_mapping_t *pm, /**< Pdo mapping. */
+        const ec_pdo_mapping_t *other /**< PDO mapping to copy from. */
+        )
+{
+    ec_pdo_t *other_pdo;
+
+    ec_pdo_mapping_clear_pdos(pm);
+
+    // PDO already mapped?
+    list_for_each_entry(other_pdo, &other->pdos, list) {
+        if (ec_pdo_mapping_add_pdo(pm, other_pdo))
+            return -1;
+    }
+    
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** Compares two Pdo mappings.
+ *
+ * Only the mapping is compared, not the Pdo entries (i. e. the Pdo
+ * configuration).
+ *
+ * \retval 1 The given Pdo mappings are equal.
+ * \retval 0 The given Pdo mappings differ.
+ */
+int ec_pdo_mapping_equal(
+        const ec_pdo_mapping_t *pm1, /**< First mapping. */
+        const ec_pdo_mapping_t *pm2 /**< Second mapping. */
+        )
+{
+    const struct list_head *h1, *h2, *l1, *l2;
+    const ec_pdo_t *p1, *p2;
+
+    h1 = l1 = &pm1->pdos;
+    h2 = l2 = &pm2->pdos;
+
+    while (1) {
+        l1 = l1->next;
+        l2 = l2->next;
+
+        if ((l1 == h1) ^ (l2 == h2)) // unequal lengths
+            return 0;
+        if (l1 == h1 && l2 == h2) // both finished
+            break;
+
+        p1 = list_entry(l1, ec_pdo_t, list);
+        p2 = list_entry(l2, ec_pdo_t, list);
+
+        if (p1->index != p2->index)
+            return 0;
+    }
+
+    return 1;
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/pdo_mapping.h	Tue Feb 19 08:22:20 2008 +0000
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU General Public License
+ *  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
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  The 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.
+ *
+ *****************************************************************************/
+
+/**
+   \file
+   EtherCAT Pdo mapping structure.
+*/
+
+/*****************************************************************************/
+
+#ifndef _EC_PDO_MAPPING_H_
+#define _EC_PDO_MAPPING_H_
+
+#include <linux/list.h>
+
+#include "../include/ecrt.h"
+
+#include "globals.h"
+
+/*****************************************************************************/
+
+/** EtherCAT PDO mapping.
+ */
+typedef struct {
+    struct list_head pdos; /**< List of Pdos. */
+    unsigned int default_mapping; /**< This is the default mapping. */
+} ec_pdo_mapping_t;
+
+/*****************************************************************************/
+
+void ec_pdo_mapping_init(ec_pdo_mapping_t *);
+void ec_pdo_mapping_clear(ec_pdo_mapping_t *);
+
+void ec_pdo_mapping_clear_pdos(ec_pdo_mapping_t *);
+
+int ec_pdo_mapping_add_pdo(ec_pdo_mapping_t *, const ec_pdo_t *);
+int ec_pdo_mapping_add_pdo_info(ec_pdo_mapping_t *, const ec_pdo_info_t *,
+        const ec_slave_config_t *);
+
+int ec_pdo_mapping_copy(ec_pdo_mapping_t *, const ec_pdo_mapping_t *);
+
+uint16_t ec_pdo_mapping_total_size(const ec_pdo_mapping_t *);
+int ec_pdo_mapping_equal(const ec_pdo_mapping_t *, const ec_pdo_mapping_t *);
+
+/*****************************************************************************/
+
+#endif
--- a/master/slave.c	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/slave.c	Tue Feb 19 08:22:20 2008 +0000
@@ -42,9 +42,11 @@
 #include <linux/delay.h>
 
 #include "globals.h"
-#include "slave.h"
 #include "datagram.h"
 #include "master.h"
+#include "slave_config.h"
+
+#include "slave.h"
 
 /*****************************************************************************/
 
@@ -113,13 +115,12 @@
 
     slave->master = master;
 
+    slave->config = NULL;
     slave->requested_state = EC_SLAVE_STATE_PREOP;
     slave->current_state = EC_SLAVE_STATE_UNKNOWN;
+    slave->online_state = EC_SLAVE_ONLINE;
     slave->self_configured = 0;
     slave->error_flag = 0;
-    slave->online_state = EC_SLAVE_ONLINE;
-    slave->fmmu_count = 0;
-    slave->pdos_registered = 0;
 
     slave->base_type = 0;
     slave->base_revision = 0;
@@ -151,7 +152,6 @@
     slave->sii_sync_count = 0;
     INIT_LIST_HEAD(&slave->sii_pdos);
     INIT_LIST_HEAD(&slave->sdo_dictionary);
-    INIT_LIST_HEAD(&slave->sdo_confs);
 
     slave->sdo_dictionary_fetched = 0;
     slave->pdo_mapping_fetched = 0;
@@ -213,6 +213,9 @@
 {
     ec_sdo_t *sdo, *next_sdo;
 
+    if (slave->config)
+        ec_slave_config_detach(slave->config);
+
     // free all SDOs
     list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) {
         list_del(&sdo->list);
@@ -240,7 +243,6 @@
 {
     ec_slave_t *slave;
     ec_pdo_t *pdo, *next_pdo;
-    ec_sdo_data_t *sdodata, *next_sdodata;
     unsigned int i;
 
     slave = container_of(kobj, ec_slave_t, kobj);
@@ -267,13 +269,6 @@
         kfree(pdo);
     }
 
-    // free all SDO configurations
-    list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) {
-        list_del(&sdodata->list);
-        kfree(sdodata->data);
-        kfree(sdodata);
-    }
-
     if (slave->eeprom_data) kfree(slave->eeprom_data);
 
     kfree(slave);
@@ -292,33 +287,6 @@
 /*****************************************************************************/
 
 /**
-   Reset slave from operation mode.
-*/
-
-void ec_slave_reset(ec_slave_t *slave /**< EtherCAT slave */)
-{
-    ec_sdo_data_t *sdodata, *next_sdodata;
-    unsigned int i;
-
-    slave->fmmu_count = 0;
-    slave->pdos_registered = 0;
-
-    // free all SDO configurations
-    list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) {
-        list_del(&sdodata->list);
-        kfree(sdodata->data);
-        kfree(sdodata);
-    }
-
-    // remove estimated sync manager sizes
-    for (i = 0; i < slave->sii_sync_count; i++) {
-        slave->sii_syncs[i].est_length = 0;
-    }
-}
-
-/*****************************************************************************/
-
-/**
  * Sets the application state of a slave.
  */
 
@@ -351,16 +319,12 @@
 {
     if (new_state == EC_SLAVE_OFFLINE &&
             slave->online_state == EC_SLAVE_ONLINE) {
-        if (slave->pdos_registered)
-            slave->master->pdo_slaves_offline++;
         if (slave->master->debug_level)
             EC_DBG("Slave %u: offline.\n", slave->ring_position);
     }
     else if (new_state == EC_SLAVE_ONLINE &&
             slave->online_state == EC_SLAVE_OFFLINE) {
         slave->error_flag = 0; // clear error flag
-        if (slave->pdos_registered)
-            slave->master->pdo_slaves_offline--;
         if (slave->master->debug_level) {
             char cur_state[EC_STATE_STRING_SIZE];
             ec_state_string(slave->current_state, cur_state);
@@ -534,7 +498,7 @@
         ec_slave_t *slave, /**< EtherCAT slave */
         const uint8_t *data, /**< category data */
         size_t data_size, /**< number of bytes */
-        ec_pdo_type_t pdo_type /**< PDO type */
+        ec_direction_t dir /**< PDO direction. */
         )
 {
     ec_pdo_t *pdo;
@@ -548,11 +512,16 @@
         }
 
         ec_pdo_init(pdo);
-        pdo->type = pdo_type;
+        pdo->dir = dir;
         pdo->index = EC_READ_U16(data);
         entry_count = EC_READ_U8(data + 2);
         pdo->sync_index = EC_READ_U8(data + 3);
-        pdo->name = ec_slave_sii_string(slave, EC_READ_U8(data + 5));
+        if (ec_pdo_set_name(pdo,
+                ec_slave_sii_string(slave, EC_READ_U8(data + 5)))) {
+            ec_pdo_clear(pdo);
+            kfree(pdo);
+            return -1;
+        }
         list_add_tail(&pdo->list, &slave->sii_pdos);
 
         data_size -= 8;
@@ -564,9 +533,15 @@
                 return -1;
             }
 
+            ec_pdo_entry_init(entry);
             entry->index = EC_READ_U16(data);
             entry->subindex = EC_READ_U8(data + 2);
-            entry->name = ec_slave_sii_string(slave, EC_READ_U8(data + 3));
+            if (ec_pdo_entry_set_name(entry,
+                    ec_slave_sii_string(slave, EC_READ_U8(data + 3)))) {
+                ec_pdo_entry_clear(entry);
+                kfree(entry);
+                return -1;
+            }
             entry->bit_length = EC_READ_U8(data + 5);
             list_add_tail(&entry->list, &pdo->entries);
 
@@ -577,7 +552,6 @@
         // if sync manager index is positive, the PDO is mapped by default
         if (pdo->sync_index >= 0) {
             ec_sync_t *sync;
-            ec_pdo_t *mapped_pdo;
 
             if (pdo->sync_index >= slave->sii_sync_count) {
                 EC_ERR("Invalid SM index %i for PDO 0x%04X in slave %u.",
@@ -586,18 +560,9 @@
             }
             sync = &slave->sii_syncs[pdo->sync_index];
 
-            if (!(mapped_pdo = kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
-                EC_ERR("Failed to allocate PDO memory.\n");
+            if (ec_pdo_mapping_add_pdo(&sync->mapping, pdo))
                 return -1;
-            }
-
-            if (ec_pdo_copy(mapped_pdo, pdo)) {
-                EC_ERR("Failed to copy PDO.\n");
-                kfree(mapped_pdo);
-                return -1;
-            }
-
-            list_add_tail(&mapped_pdo->list, &sync->pdos);
+
             sync->mapping_source = EC_SYNC_MAPPING_SII;
         }
     }
@@ -632,61 +597,8 @@
 
 /*****************************************************************************/
 
-/**
- * Prepares an FMMU configuration.
- * Configuration data for the FMMU is saved in the slave structure and is
- * written to the slave in ecrt_master_activate().
- * The FMMU configuration is done in a way, that the complete data range
- * of the corresponding sync manager is covered. Seperate FMMUs are configured
- * for each domain.
- * If the FMMU configuration is already prepared, the function returns with
- * success.
- * \return 0 in case of success, else < 0
+/** Outputs all information about a certain slave.
  */
-
-int ec_slave_prepare_fmmu(
-        ec_slave_t *slave, /**< EtherCAT slave */
-        const ec_domain_t *domain, /**< domain */
-        const ec_sync_t *sync  /**< sync manager */
-        )
-{
-    unsigned int i;
-    ec_fmmu_t *fmmu;
-
-    // FMMU configuration already prepared?
-    for (i = 0; i < slave->fmmu_count; i++) {
-        fmmu = &slave->fmmus[i];
-        if (fmmu->domain == domain && fmmu->sync == sync)
-            return 0;
-    }
-
-    // reserve new FMMU...
-
-    if (slave->fmmu_count >= slave->base_fmmu_count) {
-        EC_ERR("Slave %u FMMU limit reached!\n", slave->ring_position);
-        return -1;
-    }
-
-    fmmu = &slave->fmmus[slave->fmmu_count];
-
-    ec_fmmu_init(fmmu, slave, slave->fmmu_count++);
-    fmmu->domain = domain;
-    fmmu->sync = sync;
-    fmmu->logical_start_address = 0;
-
-    slave->pdos_registered = 1;
-    
-    ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
-
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
-   Outputs all information about a certain slave.
-*/
-
 ssize_t ec_slave_info(const ec_slave_t *slave, /**< EtherCAT slave */
         char *buffer /**< Output buffer */
         )
@@ -695,8 +607,6 @@
     ec_pdo_t *pdo;
     ec_pdo_entry_t *pdo_entry;
     int first, i;
-    ec_sdo_data_t *sdodata;
-    char str[20];
     char *large_buffer, *buf;
     unsigned int size;
 
@@ -713,9 +623,7 @@
     buf += sprintf(buf, " (");
     buf += ec_state_string(slave->requested_state, buf);
     buf += sprintf(buf, ")\n");
-    buf += sprintf(buf, "Flags: %s, %s\n\n",
-            slave->online_state == EC_SLAVE_ONLINE ? "online" : "OFFLINE",
-            slave->error_flag ? "ERROR" : "ok");
+    buf += sprintf(buf, "Flags: %s\n\n", slave->error_flag ? "ERROR" : "ok");
 
     buf += sprintf(buf, "Data link status:\n");
     for (i = 0; i < 4; i++) {
@@ -821,10 +729,10 @@
             buf += sprintf(buf,
                     "  SM%u: addr 0x%04X, size %u, control 0x%02X, %s\n",
                     sync->index, sync->physical_start_address,
-                    ec_sync_size(sync), sync->control_register,
+                    sync->length, sync->control_register,
                     sync->enable ? "enable" : "disable");
 
-            if (list_empty(&sync->pdos)) {
+            if (list_empty(&sync->mapping.pdos)) {
                 buf += sprintf(buf, "    No PDOs mapped.\n");
             } else if (sync->mapping_source != EC_SYNC_MAPPING_NONE) {
                 buf += sprintf(buf,
@@ -833,9 +741,9 @@
                         ? "SII" : "CoE");
             }
 
-            list_for_each_entry(pdo, &sync->pdos, list) {
+            list_for_each_entry(pdo, &sync->mapping.pdos, list) {
                 buf += sprintf(buf, "    %s 0x%04X \"%s\"\n",
-                        pdo->type == EC_RX_PDO ? "RxPdo" : "TxPdo",
+                        pdo->dir == EC_DIR_OUTPUT ? "RxPdo" : "TxPdo",
                         pdo->index, pdo->name ? pdo->name : "???");
 
                 list_for_each_entry(pdo_entry, &pdo->entries, list) {
@@ -856,7 +764,7 @@
 
         list_for_each_entry(pdo, &slave->sii_pdos, list) {
             buf += sprintf(buf, "  %s 0x%04X \"%s\"",
-                    pdo->type == EC_RX_PDO ? "RxPdo" : "TxPdo",
+                    pdo->dir == EC_DIR_OUTPUT ? "RxPdo" : "TxPdo",
                     pdo->index, pdo->name ? pdo->name : "???");
             if (pdo->sync_index >= 0)
                 buf += sprintf(buf, ", default mapping: SM%u.\n",
@@ -874,23 +782,6 @@
         buf += sprintf(buf, "\n");
     }
 
-    // type-cast to avoid warnings on some compilers
-    if (!list_empty((struct list_head *) &slave->sdo_confs)) {
-        buf += sprintf(buf, "SDO configurations:\n");
-
-        list_for_each_entry(sdodata, &slave->sdo_confs, list) {
-            switch (sdodata->size) {
-                case 1: sprintf(str, "%u", EC_READ_U8(sdodata->data)); break;
-                case 2: sprintf(str, "%u", EC_READ_U16(sdodata->data)); break;
-                case 4: sprintf(str, "%u", EC_READ_U32(sdodata->data)); break;
-                default: sprintf(str, "(invalid size)"); break;
-            }
-            buf += sprintf(buf, "  0x%04X:%-3i -> %s\n",
-                    sdodata->index, sdodata->subindex, str);
-        }
-        buf += sprintf(buf, "\n");
-    }
-
     size = buf - large_buffer;
     if (size >= PAGE_SIZE) {
         const char trunc[] = "\n---TRUNCATED---\n";
@@ -1251,47 +1142,6 @@
    \return 0 in case of success, else < 0
 */
 
-int ec_slave_conf_sdo(ec_slave_t *slave, /**< EtherCAT slave */
-                      uint16_t sdo_index, /**< SDO index */
-                      uint8_t sdo_subindex, /**< SDO subindex */
-                      const uint8_t *data, /**< SDO data */
-                      size_t size /**< SDO size in bytes */
-                      )
-{
-    ec_sdo_data_t *sdodata;
-
-    if (!(slave->sii_mailbox_protocols & EC_MBOX_COE)) {
-        EC_ERR("Slave %u does not support CoE!\n", slave->ring_position);
-        return -1;
-    }
-
-    if (!(sdodata = (ec_sdo_data_t *)
-          kmalloc(sizeof(ec_sdo_data_t), GFP_KERNEL))) {
-        EC_ERR("Failed to allocate memory for SDO configuration object!\n");
-        return -1;
-    }
-
-    if (!(sdodata->data = (uint8_t *) kmalloc(size, GFP_KERNEL))) {
-        EC_ERR("Failed to allocate memory for SDO configuration data!\n");
-        kfree(sdodata);
-        return -1;
-    }
-
-    sdodata->index = sdo_index;
-    sdodata->subindex = sdo_subindex;
-    memcpy(sdodata->data, data, size);
-    sdodata->size = size;
-
-    list_add_tail(&sdodata->list, &slave->sdo_confs);
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
-   \return 0 in case of success, else < 0
-*/
-
 int ec_slave_validate(const ec_slave_t *slave, /**< EtherCAT slave */
                       uint32_t vendor_id, /**< vendor ID */
                       uint32_t product_code /**< product code */
@@ -1357,184 +1207,4 @@
     return NULL;
 }
 
-/******************************************************************************
- *  Realtime interface
- *****************************************************************************/
-
-/**
-   \return 0 in case of success, else < 0
-   \ingroup RealtimeInterface
-*/
-
-int ecrt_slave_conf_sdo8(ec_slave_t *slave, /**< EtherCAT slave */
-                         uint16_t sdo_index, /**< SDO index */
-                         uint8_t sdo_subindex, /**< SDO subindex */
-                         uint8_t value /**< new SDO value */
-                         )
-{
-    uint8_t data[1];
-    EC_WRITE_U8(data, value);
-    return ec_slave_conf_sdo(slave, sdo_index, sdo_subindex, data, 1);
-}
-
-/*****************************************************************************/
-
-/**
-   \return 0 in case of success, else < 0
-   \ingroup RealtimeInterface
-*/
-
-int ecrt_slave_conf_sdo16(ec_slave_t *slave, /**< EtherCAT slave */
-                          uint16_t sdo_index, /**< SDO index */
-                          uint8_t sdo_subindex, /**< SDO subindex */
-                          uint16_t value /**< new SDO value */
-                          )
-{
-    uint8_t data[2];
-    EC_WRITE_U16(data, value);
-    return ec_slave_conf_sdo(slave, sdo_index, sdo_subindex, data, 2);
-}
-
-/*****************************************************************************/
-
-/**
-   \return 0 in case of success, else < 0
-   \ingroup RealtimeInterface
-*/
-
-int ecrt_slave_conf_sdo32(ec_slave_t *slave, /**< EtherCAT slave */
-                          uint16_t sdo_index, /**< SDO index */
-                          uint8_t sdo_subindex, /**< SDO subindex */
-                          uint32_t value /**< new SDO value */
-                          )
-{
-    uint8_t data[4];
-    EC_WRITE_U32(data, value);
-    return ec_slave_conf_sdo(slave, sdo_index, sdo_subindex, data, 4);
-}
-
-/*****************************************************************************/
-
-/**
- * Clear slave's PDO mapping.
- */
-
-void ecrt_slave_pdo_mapping_clear(
-        ec_slave_t *slave, /**< EtherCAT slave */
-        ec_direction_t dir /**< output/input */
-        )
-{
-    ec_sync_t *sync;
-
-    if (!(slave->sii_mailbox_protocols & EC_MBOX_COE)) {
-        EC_ERR("Slave %u does not support CoE!\n", slave->ring_position);
-        return;
-    }
-
-    if (!(sync = ec_slave_get_pdo_sync(slave, dir)))
-        return;
-
-    ec_sync_clear_pdos(sync);
-    sync->alt_mapping = 1;
-}
-
-/*****************************************************************************/
-
-/**
- * Add a PDO to the list of known mapped PDOs.
- */
-
-int ecrt_slave_pdo_mapping_add(
-        ec_slave_t *slave, /**< EtherCAT slave */
-        ec_direction_t dir, /**< input/output */
-        uint16_t pdo_index /**< Index of mapped PDO */)
-{
-    ec_pdo_t *pdo;
-    ec_sync_t *sync;
-    unsigned int not_found = 1;
-
-    if (!(slave->sii_mailbox_protocols & EC_MBOX_COE)) {
-        EC_ERR("Slave %u does not support CoE!\n", slave->ring_position);
-        return -1;
-    }
-
-    // does the slave provide the PDO? FIXME
-    list_for_each_entry(pdo, &slave->sii_pdos, list) {
-        if (pdo->index == pdo_index) {
-            not_found = 0;
-            break;
-        }
-    }
-
-    if (not_found) {
-        EC_ERR("Slave %u does not provide PDO 0x%04X!\n",
-                slave->ring_position, pdo_index);
-        return -1;
-    }
-
-    // check direction
-    if ((pdo->type == EC_TX_PDO && dir == EC_DIR_OUTPUT) ||
-            (pdo->type == EC_RX_PDO && dir == EC_DIR_INPUT)) {
-        EC_ERR("Invalid direction for PDO 0x%04X.\n", pdo_index);
-        return -1;
-    }
-
-
-    if (!(sync = ec_slave_get_pdo_sync(slave, dir))) {
-        EC_ERR("Failed to obtain sync manager for PDO mapping of slave %u!\n",
-                slave->ring_position);
-        return -1;
-    }
-
-    if (ec_sync_add_pdo(sync, pdo))
-        return -1;
-
-    sync->alt_mapping = 1;
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
- * Convenience function for ecrt_slave_pdo_mapping_clear() and
- * ecrt_slave_pdo_mapping_add().
- */
-
-int ecrt_slave_pdo_mapping(ec_slave_t *slave, /**< EtherCAT slave */
-        ec_direction_t dir, /**< input/output */
-        unsigned int num_args, /**< Number of following arguments */
-        ... /**< PDO indices to map */
-        )
-{
-    va_list ap;
-
-    ecrt_slave_pdo_mapping_clear(slave, dir);
-
-    va_start(ap, num_args);
-
-    for (; num_args; num_args--) {
-        if (ecrt_slave_pdo_mapping_add(
-                    slave, dir, (uint16_t) va_arg(ap, int))) {
-            return -1;
-        }
-    }
-
-    va_end(ap);
-    return 0;
-}
-
-
-/*****************************************************************************/
-
-/** \cond */
-
-EXPORT_SYMBOL(ecrt_slave_conf_sdo8);
-EXPORT_SYMBOL(ecrt_slave_conf_sdo16);
-EXPORT_SYMBOL(ecrt_slave_conf_sdo32);
-EXPORT_SYMBOL(ecrt_slave_pdo_mapping_clear);
-EXPORT_SYMBOL(ecrt_slave_pdo_mapping_add);
-EXPORT_SYMBOL(ecrt_slave_pdo_mapping);
-
-/** \endcond */
-
-/*****************************************************************************/
+/*****************************************************************************/
--- a/master/slave.h	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/slave.h	Tue Feb 19 08:22:20 2008 +0000
@@ -50,21 +50,12 @@
 #include "datagram.h"
 #include "pdo.h"
 #include "sync.h"
-#include "fmmu.h"
 
 /*****************************************************************************/
 
-/** maximum number of FMMUs per slave */
-#define EC_MAX_FMMUS 16
-
-/*****************************************************************************/
-
-/**
- * State of an EtherCAT slave.
+/** State of an EtherCAT slave.
  */
-
-typedef enum
-{
+typedef enum {
     EC_SLAVE_STATE_UNKNOWN = 0x00,
     /**< unknown state */
     EC_SLAVE_STATE_INIT = 0x01,
@@ -77,29 +68,22 @@
     /**< OP (mailbox communication and input/output update) */
     EC_SLAVE_STATE_ACK_ERR = 0x10
     /**< Acknowledge/Error bit (no actual state) */
-}
-ec_slave_state_t;
+} ec_slave_state_t;
 
 /*****************************************************************************/
 
-/**
- * EtherCAT slave online state.
+/** EtherCAT slave online state.
  */
-
 typedef enum {
     EC_SLAVE_OFFLINE,
     EC_SLAVE_ONLINE
-}
-ec_slave_online_state_t;
+} ec_slave_online_state_t;
 
 /*****************************************************************************/
 
-/**
- * Supported mailbox protocols.
+/** Supported mailbox protocols.
  */
-
-enum
-{
+enum {
     EC_MBOX_AOE = 0x01, /**< ADS-over-EtherCAT */
     EC_MBOX_EOE = 0x02, /**< Ethernet-over-EtherCAT */
     EC_MBOX_COE = 0x04, /**< CANopen-over-EtherCAT */
@@ -110,27 +94,26 @@
 
 /*****************************************************************************/
 
-/**
- * EtherCAT slave.
+/** EtherCAT slave.
  */
-
 struct ec_slave
 {
     struct list_head list; /**< list item */
     struct kobject kobj; /**< kobject */
     ec_master_t *master; /**< master owning the slave */
 
-    ec_slave_state_t requested_state; /**< requested application state */
-    ec_slave_state_t current_state; /**< current application state */
-    ec_slave_online_state_t online_state; /**< online state */
-    unsigned int self_configured; /**< slave was configured by this master */
-    unsigned int error_flag; /**< stop processing after an error */
-    unsigned int pdos_registered; /**< non-zero, if PDOs were registered */
-
     // addresses
     uint16_t ring_position; /**< ring position */
     uint16_t station_address; /**< configured station address */
 
+    // configuration
+    ec_slave_config_t *config; /**< Current configuration. */
+    ec_slave_state_t requested_state; /**< Requested application state. */
+    ec_slave_state_t current_state; /**< Current application state. */
+    ec_slave_online_state_t online_state; /**< online state */
+    unsigned int self_configured; /**< Slave was configured by this master. */
+    unsigned int error_flag; /**< Stop processing after an error. */
+
     // base data
     uint8_t base_type; /**< slave type */
     uint8_t base_revision; /**< revision */
@@ -169,12 +152,8 @@
     char *sii_name; /**< slave name acc. to EEPROM */
     int16_t sii_current_on_ebus; /**< power consumption */
 
-    ec_fmmu_t fmmus[EC_MAX_FMMUS]; /**< FMMU configurations */
-    uint8_t fmmu_count; /**< number of FMMUs used */
-
     struct kobject sdo_kobj; /**< kobject for SDOs */
     struct list_head sdo_dictionary; /**< SDO dictionary list */
-    struct list_head sdo_confs; /**< list of SDO configurations */
     uint8_t sdo_dictionary_fetched; /**< dictionary has been fetched */
     unsigned long jiffies_preop; /**< time, the slave went to PREOP */
 
@@ -187,11 +166,6 @@
 int ec_slave_init(ec_slave_t *, ec_master_t *, uint16_t, uint16_t);
 void ec_slave_destroy(ec_slave_t *);
 
-void ec_slave_reset(ec_slave_t *);
-
-int ec_slave_prepare_fmmu(ec_slave_t *, const ec_domain_t *,
-        const ec_sync_t *);
-
 void ec_slave_request_state(ec_slave_t *, ec_slave_state_t);
 void ec_slave_set_state(ec_slave_t *, ec_slave_state_t);
 void ec_slave_set_online_state(ec_slave_t *, ec_slave_online_state_t);
@@ -201,7 +175,7 @@
 int ec_slave_fetch_sii_general(ec_slave_t *, const uint8_t *, size_t);
 int ec_slave_fetch_sii_syncs(ec_slave_t *, const uint8_t *, size_t);
 int ec_slave_fetch_sii_pdos(ec_slave_t *, const uint8_t *, size_t,
-        ec_pdo_type_t);
+        ec_direction_t);
 
 // misc.
 ec_sync_t *ec_slave_get_pdo_sync(ec_slave_t *, ec_direction_t); 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/slave_config.c	Tue Feb 19 08:22:20 2008 +0000
@@ -0,0 +1,546 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU General Public License
+ *  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
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  The 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.
+ *
+ *****************************************************************************/
+
+/**
+   \file
+   EtherCAT slave configuration methods.
+*/
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+
+#include "globals.h"
+#include "master.h"
+
+#include "slave_config.h"
+
+/*****************************************************************************/
+
+void ec_slave_config_clear(struct kobject *);
+ssize_t ec_show_slave_config_attribute(struct kobject *, struct attribute *,
+        char *);
+
+/*****************************************************************************/
+
+/** \cond */
+
+EC_SYSFS_READ_ATTR(info);
+
+static struct attribute *def_attrs[] = {
+    &attr_info,
+    NULL,
+};
+
+static struct sysfs_ops sysfs_ops = {
+    .show = ec_show_slave_config_attribute
+};
+
+static struct kobj_type ktype_ec_slave_config = {
+    .release = ec_slave_config_clear,
+    .sysfs_ops = &sysfs_ops,
+    .default_attrs = def_attrs
+};
+
+/** \endcond */
+
+/*****************************************************************************/
+
+/** Slave configuration constructor.
+ *
+ * See ecrt_master_slave_config() for the usage of the \a alias and \a
+ * position parameters.
+ *
+ * \retval 0 Success.
+ * \retval <0 Failure.
+ */
+int ec_slave_config_init(ec_slave_config_t *sc, /**< Slave configuration. */
+        ec_master_t *master, /**< EtherCAT master. */
+        uint16_t alias, /**< Slave alias. */
+        uint16_t position, /**< Slave position. */
+        uint32_t vendor_id, /**< Expected vendor ID. */
+        uint32_t product_code /**< Expected product code. */
+        )
+{
+    ec_direction_t dir;
+
+    sc->master = master;
+    sc->alias = alias;
+    sc->position = position;
+    sc->vendor_id = vendor_id;
+    sc->product_code = product_code;
+    sc->slave = NULL;
+
+    for (dir = EC_DIR_OUTPUT; dir <= EC_DIR_INPUT; dir++)
+        ec_pdo_mapping_init(&sc->mapping[dir]);
+
+    INIT_LIST_HEAD(&sc->sdo_configs);
+
+    sc->used_fmmus = 0;
+
+    // init kobject and add it to the hierarchy
+    memset(&sc->kobj, 0x00, sizeof(struct kobject));
+    kobject_init(&sc->kobj);
+    sc->kobj.ktype = &ktype_ec_slave_config;
+    sc->kobj.parent = &master->kobj;
+    if (kobject_set_name(&sc->kobj, "config-%u-%u", sc->alias, sc->position)) {
+        EC_ERR("Failed to set kobject name for slave config %u:%u.\n",
+                sc->alias, sc->position);
+        goto out_put;
+    }
+    if (kobject_add(&sc->kobj)) {
+        EC_ERR("Failed to add kobject for slave config %u:%u.\n",
+                sc->alias, sc->position);
+        goto out_put;
+    }
+
+    return 0;
+
+ out_put:
+    kobject_put(&sc->kobj);
+    return -1;
+}
+
+/*****************************************************************************/
+
+/** Slave configuration destructor.
+ *
+ * Clears and frees a slave configuration object.
+ */
+void ec_slave_config_destroy(
+        ec_slave_config_t *sc /**< Slave configuration. */
+        )
+{
+    ec_slave_config_detach(sc);
+
+    // destroy self
+    kobject_del(&sc->kobj);
+    kobject_put(&sc->kobj);
+}
+
+/*****************************************************************************/
+
+/** Clear and free the slave configuration.
+ * 
+ * This method is called by the kobject, once there are no more references to
+ * it.
+ */
+void ec_slave_config_clear(struct kobject *kobj /**< kobject of the config. */)
+{
+    ec_slave_config_t *sc;
+    ec_direction_t dir;
+    ec_sdo_data_t *sdodata, *next_sdodata;
+
+    sc = container_of(kobj, ec_slave_config_t, kobj);
+
+    // Free Pdo mappings
+    for (dir = EC_DIR_OUTPUT; dir <= EC_DIR_INPUT; dir++)
+        ec_pdo_mapping_clear(&sc->mapping[dir]);
+
+    // free all SDO configurations
+    list_for_each_entry_safe(sdodata, next_sdodata, &sc->sdo_configs, list) {
+        list_del(&sdodata->list);
+        kfree(sdodata->data);
+        kfree(sdodata);
+    }
+
+    /** \todo */
+
+    kfree(sc);
+}
+
+/*****************************************************************************/
+
+/** Prepares an FMMU configuration.
+ *
+ * Configuration data for the FMMU is saved in the slave config structure and
+ * is written to the slave during the configuration. The FMMU configuration
+ * is done in a way, that the complete data range of the corresponding sync
+ * manager is covered. Seperate FMMUs are configured for each domain. If the
+ * FMMU configuration is already prepared, the function returns with success.
+ *
+ * \retval >=0 Logical offset address.
+ * \retval -1  FMMU limit reached.
+ */
+int ec_slave_config_prepare_fmmu(
+        ec_slave_config_t *sc, /**< Slave configuration. */
+        ec_domain_t *domain, /**< Domain. */
+        ec_direction_t dir /**< PDO direction. */
+        )
+{
+    unsigned int i;
+    ec_fmmu_config_t *fmmu;
+
+    // FMMU configuration already prepared?
+    for (i = 0; i < sc->used_fmmus; i++) {
+        fmmu = &sc->fmmu_configs[i];
+        if (fmmu->domain == domain && fmmu->dir == dir)
+            return fmmu->logical_start_address;
+    }
+
+    if (sc->used_fmmus == EC_MAX_FMMUS) {
+        EC_ERR("FMMU limit reached for slave configuration %u:%u!\n",
+                sc->alias, sc->position);
+        return -1;
+    }
+
+    fmmu = &sc->fmmu_configs[sc->used_fmmus++];
+    ec_fmmu_config_init(fmmu, sc, domain, dir);
+    return fmmu->logical_start_address;
+}
+
+/*****************************************************************************/
+
+/** Registers a Pdo entry.
+ *
+ * Searches the mapping and the Pdo configurations for the given Pdo entry. If
+ * found, the curresponding sync manager/FMMU is added to the domain and the
+ * offset of the Pdo entry's data in the domain process data is returned.
+ *
+ * \retval >=0 Offset of the Pdo entry's process data.
+ * \retval -1  Pdo entry not found.
+ * \retval -2  Failed to register Pdo entry.
+ */
+int ec_slave_config_reg_pdo_entry(
+        ec_slave_config_t *sc, /**< Slave configuration. */
+        ec_domain_t *domain, /**< Domain. */
+        uint16_t index, /**< Index of Pdo entry to register. */
+        uint8_t subindex /**< Subindex of Pdo entry to register. */
+        )
+{
+    ec_direction_t dir;
+    ec_pdo_mapping_t *map;
+    unsigned int bit_offset, byte_offset;
+    ec_pdo_t *pdo;
+    ec_pdo_entry_t *entry;
+    int ret;
+
+    for (dir = EC_DIR_OUTPUT; dir <= EC_DIR_INPUT; dir++) {
+        map = &sc->mapping[dir];
+        bit_offset = 0;
+        list_for_each_entry(pdo, &map->pdos, list) {
+            list_for_each_entry(entry, &pdo->entries, list) {
+                if (entry->index != index || entry->subindex != subindex) {
+                    bit_offset += entry->bit_length;
+                } else {
+                    goto found;
+                }
+            }
+        }
+    }
+
+    EC_ERR("PDO entry 0x%04X:%u is not mapped in slave config %u:%u.\n",
+           index, subindex, sc->alias, sc->position);
+    return -1;
+
+found:
+    byte_offset = bit_offset / 8;
+    if ((ret = ec_slave_config_prepare_fmmu(sc, domain, dir)) < 0)
+        return -2;
+    return ret + byte_offset;
+}
+
+/*****************************************************************************/
+
+/** Outputs all information about a certain slave configuration.
+*/
+ssize_t ec_slave_config_info(
+        const ec_slave_config_t *sc, /**< Slave configuration. */
+        char *buffer /**< Output buffer */
+        )
+{
+    char *buf = buffer;
+    ec_direction_t dir;
+    const ec_pdo_mapping_t *map;
+    const ec_pdo_t *pdo;
+    const ec_pdo_entry_t *entry;
+    char str[20];
+    ec_sdo_data_t *sdodata;
+
+    buf += sprintf(buf, "Alias: 0x%04X (%u)\n", sc->alias, sc->alias);
+    buf += sprintf(buf, "Position: %u\n", sc->position);
+
+    for (dir = EC_DIR_OUTPUT; dir <= EC_DIR_INPUT; dir++) {
+        map = &sc->mapping[dir];
+        
+        if (!list_empty(&map->pdos)) {
+            buf += sprintf(buf, "%s mapping:\n",
+                    dir == EC_DIR_OUTPUT ? "Output" : "Input");
+
+            list_for_each_entry(pdo, &map->pdos, list) {
+                buf += sprintf(buf, "  %s 0x%04X \"%s\"\n",
+                        pdo->dir == EC_DIR_OUTPUT ? "RxPdo" : "TxPdo",
+                        pdo->index, pdo->name ? pdo->name : "???");
+
+                list_for_each_entry(entry, &pdo->entries, list) {
+                    buf += sprintf(buf, "    0x%04X:%X \"%s\", %u bit\n",
+                            entry->index, entry->subindex,
+                            entry->name ? entry->name : "???",
+                            entry->bit_length);
+                }
+            }
+        }
+    }
+    
+    // type-cast to avoid warnings on some compilers
+    if (!list_empty((struct list_head *) &sc->sdo_configs)) {
+        buf += sprintf(buf, "\nSDO configurations:\n");
+
+        list_for_each_entry(sdodata, &sc->sdo_configs, list) {
+            switch (sdodata->size) {
+                case 1: sprintf(str, "%u", EC_READ_U8(sdodata->data)); break;
+                case 2: sprintf(str, "%u", EC_READ_U16(sdodata->data)); break;
+                case 4: sprintf(str, "%u", EC_READ_U32(sdodata->data)); break;
+                default: sprintf(str, "(invalid size)"); break;
+            }
+            buf += sprintf(buf, "  0x%04X:%-3i -> %s\n",
+                    sdodata->index, sdodata->subindex, str);
+        }
+        buf += sprintf(buf, "\n");
+    }
+
+    return buf - buffer;
+}
+
+/*****************************************************************************/
+
+/** Formats attribute data for SysFS read access.
+ *
+ * \return number of bytes to read
+ */
+ssize_t ec_show_slave_config_attribute(
+        struct kobject *kobj, /**< Slave configuration's kobject */
+        struct attribute *attr, /**< Requested attribute. */
+        char *buffer /**< Memory to store data. */
+        )
+{
+    ec_slave_config_t *sc = container_of(kobj, ec_slave_config_t, kobj);
+
+    if (attr == &attr_info) {
+        return ec_slave_config_info(sc, buffer);
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** Adds an SDO configuration.
+ */
+int ec_slave_config_sdo(ec_slave_config_t *sc, uint16_t index,
+        uint8_t subindex, const uint8_t *data, size_t size)
+{
+    ec_slave_t *slave = sc->slave;
+    ec_sdo_data_t *sdodata;
+
+    if (slave && !(slave->sii_mailbox_protocols & EC_MBOX_COE)) {
+        EC_ERR("Slave %u does not support CoE!\n", slave->ring_position);
+        return -1;
+    }
+
+    if (!(sdodata = (ec_sdo_data_t *)
+          kmalloc(sizeof(ec_sdo_data_t), GFP_KERNEL))) {
+        EC_ERR("Failed to allocate memory for SDO configuration object!\n");
+        return -1;
+    }
+
+    if (!(sdodata->data = (uint8_t *) kmalloc(size, GFP_KERNEL))) {
+        EC_ERR("Failed to allocate memory for SDO configuration data!\n");
+        kfree(sdodata);
+        return -1;
+    }
+
+    sdodata->index = index;
+    sdodata->subindex = subindex;
+    memcpy(sdodata->data, data, size);
+    sdodata->size = size;
+
+    list_add_tail(&sdodata->list, &sc->sdo_configs);
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** Attaches the configuration to the addressed slave object.
+ *
+ * \retval 0 Success.
+ * \retval -1 Slave not found.
+ * \retval -2 Slave already configured.
+ * \retval -3 Invalid slave type found at the given position.
+ */
+int ec_slave_config_attach(
+        ec_slave_config_t *sc /**< Slave configuration. */
+        )
+{
+	ec_slave_t *slave;
+	unsigned int alias_found = 0, relative_position = 0;
+
+	if (sc->slave)
+		return 0; // already attached
+
+	list_for_each_entry(slave, &sc->master->slaves, list) {
+		if (!alias_found) {
+			if (sc->alias && slave->sii_alias != sc->alias)
+				continue;
+			alias_found = 1;
+			relative_position = 0;
+		}
+		if (relative_position == sc->position)
+			goto found;
+		relative_position++;
+	}
+
+	EC_ERR("Failed to find slave for configuration %u:%u.\n",
+			sc->alias, sc->position);
+	return -1;
+
+found:
+	if (slave->config) {
+		EC_ERR("Failed to attach slave configuration %u:%u. Slave %u"
+				" already has a configuration!\n", sc->alias,
+				sc->position, slave->ring_position);
+		return -2;
+	}
+	if (slave->sii_vendor_id != sc->vendor_id
+			|| slave->sii_product_code != sc->product_code) {
+		EC_ERR("Slave %u has an invalid type (0x%08X/0x%08X) for"
+				" configuration %u:%u (0x%08X/0x%08X).\n",
+				slave->ring_position, slave->sii_vendor_id,
+				slave->sii_product_code, sc->alias, sc->position,
+				sc->vendor_id, sc->product_code);
+		return -3;
+	}
+
+	// attach slave
+	slave->config = sc;
+	sc->slave = slave;
+
+    ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
+
+	return 0;
+}
+
+/*****************************************************************************/
+
+/** Detaches the configuration from a slave object.
+ */
+void ec_slave_config_detach(
+        ec_slave_config_t *sc /**< Slave configuration. */
+        )
+{
+    if (sc->slave) {
+        sc->slave->config = NULL;
+        sc->slave = NULL;
+    }
+}
+
+/*****************************************************************************/
+
+/** Loads the default mapping from the slave object.
+ */
+void ec_slave_config_load_default_mapping(ec_slave_config_t *sc)
+{
+    ec_direction_t dir;
+    ec_pdo_mapping_t *map;
+    ec_sync_t *sync;
+
+    if (!sc->slave)
+        return;
+    
+    for (dir = EC_DIR_OUTPUT; dir <= EC_DIR_INPUT; dir++) {
+        map = &sc->mapping[dir];
+        if (!(sync = ec_slave_get_pdo_sync(sc->slave, dir)))
+            continue;
+        ec_pdo_mapping_copy(map, &sync->mapping);
+    }
+}
+
+/******************************************************************************
+ *  Realtime interface
+ *****************************************************************************/
+
+int ecrt_slave_config_mapping(ec_slave_config_t *sc, unsigned int n_entries,
+        const ec_pdo_info_t pdo_infos[])
+{
+    unsigned int i;
+
+    for (i = 0; i < n_entries; i++)
+        if (ec_pdo_mapping_add_pdo_info(&sc->mapping[pdo_infos[i].dir],
+                    &pdo_infos[i], sc))
+            return -1;
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_sdo8(ec_slave_config_t *slave, uint16_t index,
+        uint8_t subindex, uint8_t value)
+{
+    uint8_t data[1];
+    EC_WRITE_U8(data, value);
+    return ec_slave_config_sdo(slave, index, subindex, data, 1);
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_sdo16(ec_slave_config_t *slave, uint16_t index,
+        uint8_t subindex, uint16_t value)
+{
+    uint8_t data[2];
+    EC_WRITE_U16(data, value);
+    return ec_slave_config_sdo(slave, index, subindex, data, 2);
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_sdo32(ec_slave_config_t *slave, uint16_t index,
+        uint8_t subindex, uint32_t value)
+{
+    uint8_t data[4];
+    EC_WRITE_U32(data, value);
+    return ec_slave_config_sdo(slave, index, subindex, data, 4);
+}
+
+/*****************************************************************************/
+
+/** \cond */
+
+EXPORT_SYMBOL(ecrt_slave_config_mapping);
+EXPORT_SYMBOL(ecrt_slave_config_sdo8);
+EXPORT_SYMBOL(ecrt_slave_config_sdo16);
+EXPORT_SYMBOL(ecrt_slave_config_sdo32);
+
+/** \endcond */
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/slave_config.h	Tue Feb 19 08:22:20 2008 +0000
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it
+ *  and/or modify it under the terms of the GNU General Public License
+ *  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
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  The 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.
+ *
+ *****************************************************************************/
+
+/**
+   \file
+   EtherCAT slave configuration structure.
+*/
+
+/*****************************************************************************/
+
+#ifndef _EC_SLAVE_CONFIG_H_
+#define _EC_SLAVE_CONFIG_H_
+
+#include <linux/list.h>
+#include <linux/kobject.h>
+
+#include "../include/ecrt.h"
+
+#include "globals.h"
+#include "slave.h"
+#include "fmmu_config.h"
+#include "pdo_mapping.h"
+
+/*****************************************************************************/
+
+/** EtherCAT slave configuration.
+ */
+struct ec_slave_config {
+    struct list_head list; /**< List item. */
+    struct kobject kobj; /**< kobject. */
+    ec_master_t *master; /**< Master owning the slave configuration. */
+
+    uint16_t alias; /**< Slave alias. */
+    uint16_t position; /**< Index after alias. If alias is zero, this is the
+                         ring position. */
+    uint32_t vendor_id; /**< Slave vendor ID. */
+    uint32_t product_code; /**< Slave product code. */
+
+    ec_slave_t *slave; /**< Slave pointer. This is \a NULL, if the slave is
+                         offline. */
+
+    ec_pdo_mapping_t mapping[2]; /**< Output and input PDO mapping. */
+
+    struct list_head sdo_configs; /**< SDO configurations. */
+
+    ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]; /**< FMMU configurations. */
+    uint8_t used_fmmus; /**< Number of FMMUs used. */
+};
+
+/*****************************************************************************/
+
+int ec_slave_config_init(ec_slave_config_t *, ec_master_t *, uint16_t,
+        uint16_t, uint32_t, uint32_t);
+void ec_slave_config_destroy(ec_slave_config_t *);
+
+int ec_slave_config_reg_pdo_entry(ec_slave_config_t *, ec_domain_t *,
+        uint16_t, uint8_t);
+
+int ec_slave_config_attach(ec_slave_config_t *);
+void ec_slave_config_detach(ec_slave_config_t *);
+
+void ec_slave_config_load_default_mapping(ec_slave_config_t *);
+
+/*****************************************************************************/
+
+#endif
--- a/master/sync.c	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/sync.c	Tue Feb 19 08:22:20 2008 +0000
@@ -31,10 +31,9 @@
  *
  *****************************************************************************/
 
-/**
-   \file
-   EtherCAT sync manager methods.
-*/
+/** \file
+ * EtherCAT sync manager methods.
+ */
 
 /*****************************************************************************/
 
@@ -46,93 +45,52 @@
 
 /*****************************************************************************/
 
-/**
- * Constructor.
+/** Constructor.
  */
-
 void ec_sync_init(
-        ec_sync_t *sync, /**< EtherCAT sync manager */
-        ec_slave_t *slave, /**< EtherCAT slave */
-        unsigned int index /**< sync manager index */
+        ec_sync_t *sync, /**< EtherCAT sync manager. */
+        ec_slave_t *slave, /**< EtherCAT slave. */
+        unsigned int index /**< Sync manager index. */
         )
 {
     sync->slave = slave;
     sync->index = index;    
 
-    sync->est_length = 0;
-    INIT_LIST_HEAD(&sync->pdos);
-    sync->alt_mapping = 0;
+    ec_pdo_mapping_init(&sync->mapping);
     sync->mapping_source = EC_SYNC_MAPPING_NONE;
 }
 
 /*****************************************************************************/
 
-/**
- * Destructor.
+/** Destructor.
  */
-
 void ec_sync_clear(
-        ec_sync_t *sync /**< EtherCAT sync manager */
+        ec_sync_t *sync /**< EtherCAT sync manager. */
         )
 {
-    ec_sync_clear_pdos(sync);
+    ec_pdo_mapping_clear(&sync->mapping);
 }
 
 /*****************************************************************************/
 
-/**
- * Calculates the size of a sync manager by evaluating PDO sizes.
- * \return sync manager size
+/** Initializes a sync manager configuration page with EEPROM data.
+ *
+ * The referenced memory (\a data) must be at least \a EC_SYNC_SIZE bytes.
  */
-
-uint16_t ec_sync_size(
-        const ec_sync_t *sync /**< sync manager */
+void ec_sync_config(
+        const ec_sync_t *sync, /**< Sync manager. */
+        uint16_t data_size, /**< Data size. */
+        uint8_t *data /**> Configuration memory. */
         )
 {
-    const ec_pdo_t *pdo;
-    const ec_pdo_entry_t *pdo_entry;
-    unsigned int bit_size, byte_size;
-
-    if (sync->length) return sync->length;
-    if (sync->est_length) return sync->est_length;
-
-    bit_size = 0;
-    list_for_each_entry(pdo, &sync->pdos, list) {
-        list_for_each_entry(pdo_entry, &pdo->entries, list) {
-            bit_size += pdo_entry->bit_length;
-        }
-    }
-
-    if (bit_size % 8) // round up to full bytes
-        byte_size = bit_size / 8 + 1;
-    else
-        byte_size = bit_size / 8;
-
-    return byte_size;
-}
-
-/*****************************************************************************/
-
-/**
-   Initializes a sync manager configuration page with EEPROM data.
-   The referenced memory (\a data) must be at least EC_SYNC_SIZE bytes.
-*/
-
-void ec_sync_config(
-        const ec_sync_t *sync, /**< sync manager */
-        uint8_t *data /**> configuration memory */
-        )
-{
-    size_t sync_size = ec_sync_size(sync);
-
     if (sync->slave->master->debug_level) {
         EC_DBG("SM%i: Addr 0x%04X, Size %3i, Ctrl 0x%02X, En %i\n",
                sync->index, sync->physical_start_address,
-               sync_size, sync->control_register, sync->enable);
+               data_size, sync->control_register, sync->enable);
     }
 
     EC_WRITE_U16(data,     sync->physical_start_address);
-    EC_WRITE_U16(data + 2, sync_size);
+    EC_WRITE_U16(data + 2, data_size);
     EC_WRITE_U8 (data + 4, sync->control_register);
     EC_WRITE_U8 (data + 5, 0x00); // status byte (read only)
     EC_WRITE_U16(data + 6, sync->enable ? 0x0001 : 0x0000); // enable
@@ -140,72 +98,26 @@
 
 /*****************************************************************************/
 
-/**
- * Adds a PDO to the list of known mapped PDOs.
+/** Adds a PDO to the list of known mapped PDOs.
+ *
  * \return 0 on success, else < 0
  */
-
 int ec_sync_add_pdo(
-        ec_sync_t *sync, /**< EtherCAT sync manager */
-        const ec_pdo_t *pdo /**< PDO to map */
+        ec_sync_t *sync, /**< EtherCAT sync manager. */
+        const ec_pdo_t *pdo /**< PDO to map. */
         )
 {
-    ec_pdo_t *mapped_pdo;
-
-    // PDO already mapped?
-    list_for_each_entry(mapped_pdo, &sync->pdos, list) {
-        if (mapped_pdo->index != pdo->index) continue;
-        EC_ERR("PDO 0x%04X is already mapped!\n", pdo->index);
-        return -1;
-    }
-    
-    if (!(mapped_pdo = kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
-        EC_ERR("Failed to allocate memory for PDO mapping.\n");
-        return -1;
-    }
-
-    ec_pdo_init(mapped_pdo);
-    if (ec_pdo_copy(mapped_pdo, pdo)) {
-        ec_pdo_clear(mapped_pdo);
-        kfree(mapped_pdo);
-        return -1;
-    }
-
-    // set appropriate sync manager index
-    mapped_pdo->sync_index = sync->index;
-
-    list_add_tail(&mapped_pdo->list, &sync->pdos);
-    return 0;
+    return ec_pdo_mapping_add_pdo(&sync->mapping, pdo);
 }
 
 /*****************************************************************************/
 
-/**
- * Clears the list of known mapped PDOs.
+/** Get direction covered by sync manager.
+ *
+ * \return Direction covered by the given sync manager.
  */
-
-void ec_sync_clear_pdos(
-        ec_sync_t *sync /**< EtherCAT sync manager */
-        )
-{
-    ec_pdo_t *pdo, *next;
-
-    // free all mapped PDOs
-    list_for_each_entry_safe(pdo, next, &sync->pdos, list) {
-        list_del(&pdo->list);
-        ec_pdo_clear(pdo);
-        kfree(pdo);
-    }
-}
-
-/*****************************************************************************/
-
-/**
- * \return Type of PDOs covered by the given sync manager.
- */
-
-ec_pdo_type_t ec_sync_get_pdo_type(
-        const ec_sync_t *sync /**< EtherCAT sync manager */
+ec_direction_t ec_sync_direction(
+        const ec_sync_t *sync /**< EtherCAT sync manager. */
         )
 {
     int index = sync->index;
@@ -215,11 +127,11 @@
     }
 
     if (index < 0 || index > 1) {
-        EC_WARN("ec_sync_get_pdo_type(): invalid sync manager index.\n");
-        return EC_RX_PDO;
+        EC_WARN("ec_sync_get_direction(): invalid sync manager index.\n");
+        return EC_DIR_OUTPUT;
     }
 
-    return (ec_pdo_type_t) index;
+    return (ec_direction_t) index;
 }
 
 /*****************************************************************************/
--- a/master/sync.h	Thu Feb 14 09:18:55 2008 +0000
+++ b/master/sync.h	Tue Feb 19 08:22:20 2008 +0000
@@ -31,10 +31,9 @@
  *
  *****************************************************************************/
 
-/**
-   \file
-   EtherCAT sync manager.
-*/
+/** \file
+ * EtherCAT sync manager.
+ */
 
 /*****************************************************************************/
 
@@ -44,60 +43,46 @@
 #include <linux/list.h>
 
 #include "../include/ecrt.h"
+
 #include "globals.h"
+#include "pdo_mapping.h"
 
 /*****************************************************************************/
 
-/** size of a sync manager configuration page */
-#define EC_SYNC_SIZE 8
+/** EtherCAT sync manager PDO mapping information source.
+ */
+typedef enum {
+    EC_SYNC_MAPPING_NONE, /**< No PDO mapping information. */
+    EC_SYNC_MAPPING_SII, /**< PDO mapping information from SII. */
+    EC_SYNC_MAPPING_COE, /**< PDO mapping information from CoE dictionary. */
+    EC_SYNC_MAPPING_CUSTOM, /**< PDO mapping configured externally. */
+} ec_sync_mapping_source_t;
 
 /*****************************************************************************/
 
-/**
- * EtherCAT sync manager PDO mapping information source.
+/** Sync manager.
  */
-
-typedef enum {
-    EC_SYNC_MAPPING_NONE, /**< No PDO mapping information */
-    EC_SYNC_MAPPING_SII, /**< PDO mapping information from SII */
-    EC_SYNC_MAPPING_COE /**< PDO mapping information from CoE dictionary */
-}
-ec_sync_mapping_source_t;
-
-/*****************************************************************************/
-
-/**
- * Sync manager.
- */
-
-typedef struct
-{
-    ec_slave_t *slave; /**< slave, the sync manager belongs to */
-    unsigned int index; /**< sync manager index */
-    uint16_t physical_start_address; /**< physical start address */
-    uint16_t length; /**< data length in bytes */
-    uint8_t control_register; /**< control register value */
-    uint8_t enable; /**< enable bit */
-
-    uint16_t est_length; /**< used to calculate the length via PDO ranges */
-    struct list_head pdos; /**< list of mapped PDOs */
-    unsigned int alt_mapping; /**< alternative mapping configured */
-    ec_sync_mapping_source_t mapping_source; /**< pdo mapping source */
-}
-ec_sync_t;
+typedef struct {
+    ec_slave_t *slave; /**< Slave, the sync manager belongs to. */
+    unsigned int index; /**< Sync manager index. */
+    uint16_t physical_start_address; /**< Physical start address. */
+    uint16_t length; /**< Data length in bytes. */
+    uint8_t control_register; /**< Control register value. */
+    uint8_t enable; /**< Enable bit. */
+    ec_pdo_mapping_t mapping; /**< Current Pdo mapping. */
+    ec_sync_mapping_source_t mapping_source; /**< Pdo mapping source. */
+} ec_sync_t;
 
 /*****************************************************************************/
 
 void ec_sync_init(ec_sync_t *, ec_slave_t *, unsigned int);
 void ec_sync_clear(ec_sync_t *);
 
-uint16_t ec_sync_size(const ec_sync_t *);
-void ec_sync_config(const ec_sync_t *, uint8_t *);
+void ec_sync_config(const ec_sync_t *, uint16_t, uint8_t *);
 
 int ec_sync_add_pdo(ec_sync_t *, const ec_pdo_t *);
-void ec_sync_clear_pdos(ec_sync_t *);
 
-ec_pdo_type_t ec_sync_get_pdo_type(const ec_sync_t *);
+ec_direction_t ec_sync_direction(const ec_sync_t *);
 
 /*****************************************************************************/