Persistent slave lists.
authorFlorian Pose <fp@igh-essen.com>
Thu, 26 Oct 2006 16:29:26 +0000
changeset 446 8fede404c01f
parent 445 3b7eec329112
child 447 ee53be7e18ee
Persistent slave lists.
examples/mini/mini.c
master/datagram.c
master/domain.c
master/domain.h
master/ethernet.c
master/fsm.c
master/fsm.h
master/fsm_coe.c
master/master.c
master/master.h
master/module.c
master/slave.c
master/slave.h
--- a/examples/mini/mini.c	Wed Oct 25 16:53:17 2006 +0000
+++ b/examples/mini/mini.c	Thu Oct 26 16:29:26 2006 +0000
@@ -56,13 +56,16 @@
 spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
 
 // data fields
+#if 0
 void *r_inputs;
 void *r_outputs;
-
-#if 0
+#endif
+
+void *r_ana_in;
+
+#if 1
 ec_pdo_reg_t domain1_pdos[] = {
-    {"2", Beckhoff_EL4132_Output1, &r_ana_out},
-    {"3", Beckhoff_EL5001_Value, NULL},
+    {"2", Beckhoff_EL3102_Input1, &r_ana_in},
     {}
 };
 #endif
@@ -82,8 +85,7 @@
 
     // process data
     //k_pos = EC_READ_U32(r_ssi);
-    EC_WRITE_U8(r_outputs + 2, einaus ? 0xFF : 0x00);
-
+    //EC_WRITE_U8(r_outputs + 2, einaus ? 0xFF : 0x00);
 
     // send
     ecrt_master_run(master);
@@ -142,12 +144,14 @@
     }
 
     printk(KERN_INFO "Registering PDOs...\n");
-#if 0
+#if 1
     if (ecrt_domain_register_pdo_list(domain1, domain1_pdos)) {
         printk(KERN_ERR "PDO registration failed!\n");
         goto out_release_master;
     }
 #endif
+
+#if 0
     if (!ecrt_domain_register_pdo_range(domain1, "0", Beckhoff_BK1120,
                                         EC_DIR_OUTPUT, 0, 4, &r_outputs)) {
         printk(KERN_ERR "PDO registration failed!\n");
@@ -158,6 +162,7 @@
         printk(KERN_ERR "PDO registration failed!\n");
         goto out_release_master;
     }
+#endif
 
 #if 0
     if (!(slave = ecrt_master_get_slave(master, "3")))
--- a/master/datagram.c	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/datagram.c	Thu Oct 26 16:29:26 2006 +0000
@@ -69,6 +69,7 @@
 
 void ec_datagram_init(ec_datagram_t *datagram /**< EtherCAT datagram */)
 {
+    INIT_LIST_HEAD(&datagram->queue); // mark as unqueued
     datagram->type = EC_DATAGRAM_NONE;
     datagram->address.logical = 0x00000000;
     datagram->data = NULL;
--- a/master/domain.c	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/domain.c	Thu Oct 26 16:29:26 2006 +0000
@@ -139,8 +139,6 @@
 
     domain = container_of(kobj, ec_domain_t, kobj);
 
-    EC_INFO("Clearing domain %i.\n", domain->index);
-
     list_for_each_entry_safe(datagram, next, &domain->datagrams, list) {
         ec_datagram_clear(datagram);
         kfree(datagram);
@@ -222,6 +220,9 @@
     data_reg->data_ptr = data_ptr;
 
     list_add_tail(&data_reg->list, &domain->data_regs);
+
+    ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
+
     return 0;
 }
 
@@ -297,6 +298,9 @@
     }
 
     list_add_tail(&data_reg->list, &domain->data_regs);
+
+    ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
+
     return 0;
 }
 
@@ -448,7 +452,7 @@
    Places all process data datagrams in the masters datagram queue.
 */
 
-void ec_domain_queue(ec_domain_t *domain /**< EtherCAT domain */)
+void ec_domain_queue_datagrams(ec_domain_t *domain /**< EtherCAT domain */)
 {
     ec_datagram_t *datagram;
 
@@ -460,6 +464,22 @@
 /*****************************************************************************/
 
 /**
+   Dequeues all datagrams from the masters datagram queue.
+*/
+
+void ec_domain_dequeue_datagrams(ec_domain_t *domain /**< EtherCAT domain */)
+{
+    ec_datagram_t *datagram;
+
+    list_for_each_entry(datagram, &domain->datagrams, list) {
+        if (!list_empty(&datagram->queue)) // datagram queued?
+            list_del_init(&datagram->queue);
+    }
+}
+
+/*****************************************************************************/
+
+/**
    Formats attribute data for SysFS reading.
    \return number of bytes to read
 */
@@ -518,18 +538,15 @@
     if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
     if (ec_slave_validate(slave, vendor_id, product_code)) return NULL;
 
-    if (!data_ptr) {
-        // data_ptr is NULL => mark slave as "registered" (do not warn)
-        slave->registered = 1;
-    }
+    if (!data_ptr) return slave;
 
     list_for_each_entry(pdo, &slave->sii_pdos, list) {
         list_for_each_entry(entry, &pdo->entries, list) {
             if (entry->index != pdo_index
                 || entry->subindex != pdo_subindex) continue;
 
-            if (data_ptr) {
-                ec_domain_reg_pdo_entry(domain, slave, pdo, entry, data_ptr);
+            if (ec_domain_reg_pdo_entry(domain, slave, pdo, entry, data_ptr)) {
+                return NULL;
             }
 
             return slave;
@@ -538,7 +555,6 @@
 
     EC_ERR("Slave %i does not provide PDO 0x%04X:%i.\n",
            slave->ring_position, pdo_index, pdo_subindex);
-    slave->registered = 0;
     return NULL;
 }
 
@@ -609,11 +625,7 @@
     if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
     if (ec_slave_validate(slave, vendor_id, product_code)) return NULL;
 
-    if (!data_ptr) {
-        // data_ptr is NULL => mark slave as "registered" (do not warn)
-        slave->registered = 1;
-        return slave;
-    }
+    if (!data_ptr) return slave;
 
     if (ec_domain_reg_pdo_range(domain, slave,
                                 direction, offset, length, data_ptr)) {
@@ -666,7 +678,7 @@
         domain->working_counter_changes = 0;
     }
 
-    ec_domain_queue(domain);
+    ec_domain_queue_datagrams(domain);
 }
 
 /*****************************************************************************/
--- a/master/domain.h	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/domain.h	Thu Oct 26 16:29:26 2006 +0000
@@ -76,8 +76,11 @@
 /*****************************************************************************/
 
 int ec_domain_init(ec_domain_t *, ec_master_t *, unsigned int);
+
 int ec_domain_alloc(ec_domain_t *, uint32_t);
-void ec_domain_queue(ec_domain_t *);
+
+void ec_domain_queue_datagrams(ec_domain_t *);
+void ec_domain_dequeue_datagrams(ec_domain_t *);
 
 /*****************************************************************************/
 
--- a/master/ethernet.c	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/ethernet.c	Thu Oct 26 16:29:26 2006 +0000
@@ -629,8 +629,7 @@
     if (!eoe->slave)
         EC_WARN("device %s is not coupled to any EoE slave!\n", dev->name);
     else {
-        eoe->slave->requested_state = EC_SLAVE_STATE_OP;
-        eoe->slave->error_flag = 0;
+        ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_OP);
     }
     return 0;
 }
@@ -652,8 +651,7 @@
     if (!eoe->slave)
         EC_WARN("device %s is not coupled to any EoE slave!\n", dev->name);
     else {
-        eoe->slave->requested_state = EC_SLAVE_STATE_INIT;
-        eoe->slave->error_flag = 0;
+        ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_PREOP);
     }
     return 0;
 }
--- a/master/fsm.c	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/fsm.c	Thu Oct 26 16:29:26 2006 +0000
@@ -56,13 +56,8 @@
 void ec_fsm_master_write_eeprom(ec_fsm_t *);
 void ec_fsm_master_sdodict(ec_fsm_t *);
 void ec_fsm_master_sdo_request(ec_fsm_t *);
-
-void ec_fsm_startup_start(ec_fsm_t *);
-void ec_fsm_startup_broadcast(ec_fsm_t *);
-void ec_fsm_startup_scan(ec_fsm_t *);
-
-void ec_fsm_configuration_start(ec_fsm_t *);
-void ec_fsm_configuration_conf(ec_fsm_t *);
+void ec_fsm_master_end(ec_fsm_t *);
+void ec_fsm_master_error(ec_fsm_t *);
 
 void ec_fsm_slavescan_start(ec_fsm_t *);
 void ec_fsm_slavescan_address(ec_fsm_t *);
@@ -80,8 +75,8 @@
 void ec_fsm_slaveconf_saveop(ec_fsm_t *);
 void ec_fsm_slaveconf_op(ec_fsm_t *);
 
-void ec_fsm_end(ec_fsm_t *);
-void ec_fsm_error(ec_fsm_t *);
+void ec_fsm_slave_end(ec_fsm_t *);
+void ec_fsm_slave_error(ec_fsm_t *);
 
 /*****************************************************************************/
 
@@ -132,19 +127,6 @@
 /*****************************************************************************/
 
 /**
-   Resets the state machine.
-*/
-
-void ec_fsm_reset(ec_fsm_t *fsm /**< finite state machine */)
-{
-    fsm->master_state = ec_fsm_master_start;
-    fsm->master_slaves_responding = 0;
-    fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN;
-}
-
-/*****************************************************************************/
-
-/**
    Executes the current state of the state machine.
    \return false, if state machine has terminated
 */
@@ -153,232 +135,23 @@
 {
     fsm->master_state(fsm);
 
-    return fsm->master_state != ec_fsm_end &&
-        fsm->master_state != ec_fsm_error;
-}
-
-/*****************************************************************************/
-
-/**
-   Initializes the master startup state machine.
-*/
-
-void ec_fsm_startup(ec_fsm_t *fsm)
-{
-    fsm->master_state = ec_fsm_startup_start;
-}
-
-/*****************************************************************************/
-
-/**
-   Returns, if the master startup state machine terminated with success.
-   \return non-zero if successful.
-*/
-
-int ec_fsm_startup_success(ec_fsm_t *fsm /**< Finite state machine */)
-{
-    return fsm->master_state == ec_fsm_end;
-}
-
-/*****************************************************************************/
-
-/**
-   Initializes the master configuration state machine.
-*/
-
-void ec_fsm_configuration(ec_fsm_t *fsm)
-{
-    fsm->master_state = ec_fsm_configuration_start;
-}
-
-/*****************************************************************************/
-
-/**
-   Returns, if the master confuguration state machine terminated with success.
-   \return non-zero if successful.
-*/
-
-int ec_fsm_configuration_success(ec_fsm_t *fsm /**< Finite state machine */)
-{
-    return fsm->master_state == ec_fsm_end;
+    return fsm->master_state != ec_fsm_master_end
+        && fsm->master_state != ec_fsm_master_error;
+}
+
+/*****************************************************************************/
+
+/**
+   \return true, if the master state machine terminated gracefully
+*/
+
+int ec_fsm_success(ec_fsm_t *fsm /**< finite state machine */)
+{
+    return fsm->master_state == ec_fsm_master_end;
 }
 
 /******************************************************************************
- *  master startup state machine
- *****************************************************************************/
-
-/**
-   Master state: START.
-   Starts with getting slave count and slave states.
-*/
-
-void ec_fsm_startup_start(ec_fsm_t *fsm)
-{
-    ec_datagram_brd(&fsm->datagram, 0x0130, 2);
-    ec_master_queue_datagram(fsm->master, &fsm->datagram);
-    fsm->master_state = ec_fsm_startup_broadcast;
-}
-
-/*****************************************************************************/
-
-/**
-   Master state: BROADCAST.
-   Processes the broadcast read slave count and slaves states.
-*/
-
-void ec_fsm_startup_broadcast(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_datagram_t *datagram = &fsm->datagram;
-    unsigned int i;
-    ec_slave_t *slave;
-    ec_master_t *master = fsm->master;
-
-    if (datagram->state != EC_DATAGRAM_RECEIVED) {
-        EC_ERR("Failed to receive broadcast datagram.\n");
-        fsm->master_state = ec_fsm_error;
-        return;
-    }
-
-    EC_INFO("Scanning bus.\n");
-
-    ec_master_clear_slaves(master);
-
-    master->slave_count = datagram->working_counter;
-
-    if (!master->slave_count) {
-        // no slaves present -> finish state machine.
-        fsm->master_state = ec_fsm_end;
-        return;
-    }
-
-    // init slaves
-    for (i = 0; i < master->slave_count; i++) {
-        if (!(slave = (ec_slave_t *) kmalloc(sizeof(ec_slave_t),
-                                             GFP_KERNEL))) {
-            EC_ERR("Failed to allocate slave %i!\n", i);
-            fsm->master_state = ec_fsm_error;
-            return;
-        }
-
-        if (ec_slave_init(slave, master, i, i + 1)) {
-            fsm->master_state = ec_fsm_error;
-            return;
-        }
-
-        if (kobject_add(&slave->kobj)) {
-            EC_ERR("Failed to add kobject.\n");
-            kobject_put(&slave->kobj); // free
-            fsm->master_state = ec_fsm_error;
-            return;
-        }
-
-        list_add_tail(&slave->list, &master->slaves);
-    }
-
-    // begin scanning of slaves
-    fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
-    fsm->slave_state = ec_fsm_slavescan_start;
-    fsm->master_state = ec_fsm_startup_scan;
-    fsm->master_state(fsm); // execute immediately
-    return;
-}
-
-/*****************************************************************************/
-
-/**
-   Master state: SCAN.
-   Executes the sub-statemachine for the scanning of a slave.
-*/
-
-void ec_fsm_startup_scan(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_master_t *master = fsm->master;
-    ec_slave_t *slave = fsm->slave;
-
-    fsm->slave_state(fsm); // execute slave state machine
-
-    if (fsm->slave_state == ec_fsm_error) {
-        EC_ERR("Slave scanning failed.\n");
-        fsm->master_state = ec_fsm_error;
-        return;
-    }
-
-    if (fsm->slave_state != ec_fsm_end) return;
-
-    // another slave to scan?
-    if (slave->list.next != &master->slaves) {
-        fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
-        fsm->slave_state = ec_fsm_slavescan_start;
-        fsm->slave_state(fsm); // execute immediately
-        return;
-    }
-
-    EC_INFO("Bus scanning completed.\n");
-
-    ec_master_calc_addressing(master);
-
-    fsm->master_state = ec_fsm_end;
-}
-
-/******************************************************************************
- *  master configuration state machine
- *****************************************************************************/
-
-/**
-   Master configuration state machine: START.
-*/
-
-void ec_fsm_configuration_start(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_master_t *master = fsm->master;
-
-    if (list_empty(&master->slaves)) {
-        fsm->master_state = ec_fsm_end;
-        return;
-    }
-
-    // begin configuring slaves
-    fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
-    fsm->slave_state = ec_fsm_slaveconf_init;
-    ec_fsm_change(&fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_INIT);
-    fsm->master_state = ec_fsm_configuration_conf;
-    fsm->master_state(fsm); // execute immediately
-}
-
-/*****************************************************************************/
-
-/**
-   Master state: CONF.
-*/
-
-void ec_fsm_configuration_conf(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_master_t *master = fsm->master;
-    ec_slave_t *slave = fsm->slave;
-
-    fsm->slave_state(fsm); // execute slave's state machine
-
-    if (fsm->slave_state == ec_fsm_error) {
-        fsm->master_state = ec_fsm_error;
-        return;
-    }
-
-    if (fsm->slave_state != ec_fsm_end) return;
-
-    // another slave to configure?
-    if (slave->list.next != &master->slaves) {
-        fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
-        fsm->slave_state = ec_fsm_slaveconf_init;
-        ec_fsm_change(&fsm->fsm_change, fsm->slave, EC_SLAVE_STATE_INIT);
-        fsm->master_state(fsm); // execute immediately
-        return;
-    }
-
-    fsm->master_state = ec_fsm_end;
-}
-
-/******************************************************************************
- *  operation / idle state machine
+ *  operation/idle state machine
  *****************************************************************************/
 
 /**
@@ -414,8 +187,10 @@
                 slave->online = 0;
             }
         }
-        fsm->master_state = ec_fsm_master_start;
-        fsm->master_state(fsm); // execute immediately
+        else {
+            EC_ERR("Failed to receive broadcast datagram.\n");
+        }
+        fsm->master_state = ec_fsm_master_error;
         return;
     }
 
@@ -449,7 +224,6 @@
 
     // topology change in idle mode: clear all slaves and scan the bus
     if (topology_change && master->mode == EC_MASTER_MODE_IDLE) {
-        EC_INFO("Scanning bus.\n");
 
         ec_master_eoe_stop(master);
         ec_master_clear_slaves(master);
@@ -458,8 +232,7 @@
 
         if (!master->slave_count) {
             // no slaves present -> finish state machine.
-            fsm->master_state = ec_fsm_master_start;
-            fsm->master_state(fsm); // execute immediately
+            fsm->master_state = ec_fsm_master_end;
             return;
         }
 
@@ -469,16 +242,14 @@
                                                  GFP_ATOMIC))) {
                 EC_ERR("Failed to allocate slave %i!\n", i);
                 ec_master_clear_slaves(master);
-                fsm->master_state = ec_fsm_master_start;
-                fsm->master_state(fsm); // execute immediately
+                fsm->master_state = ec_fsm_master_error;
                 return;
             }
 
             if (ec_slave_init(slave, master, i, i + 1)) {
                 // freeing of "slave" already done
                 ec_master_clear_slaves(master);
-                fsm->master_state = ec_fsm_master_start;
-                fsm->master_state(fsm); // execute immediately
+                fsm->master_state = ec_fsm_master_error;
                 return;
             }
 
@@ -486,14 +257,15 @@
                 EC_ERR("Failed to add kobject.\n");
                 kobject_put(&slave->kobj); // free
                 ec_master_clear_slaves(master);
-                fsm->master_state = ec_fsm_master_start;
-                fsm->master_state(fsm); // execute immediately
+                fsm->master_state = ec_fsm_master_error;
                 return;
             }
 
             list_add_tail(&slave->list, &master->slaves);
         }
 
+        EC_INFO("Scanning bus.\n");
+
         // begin scanning of slaves
         fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
         fsm->slave_state = ec_fsm_slavescan_start;
@@ -533,17 +305,18 @@
                 && (slave->configured
                     || slave->current_state == EC_SLAVE_STATE_INIT))) continue;
 
-        ec_state_string(slave->current_state, old_state);
-        ec_state_string(slave->requested_state, new_state);
-
-        if (!slave->configured
-            && slave->current_state != EC_SLAVE_STATE_INIT) {
-            EC_INFO("Reconfiguring slave %i (%s -> %s).\n",
-                    slave->ring_position, old_state, new_state);
-        }
-        else if (slave->current_state != slave->requested_state) {
-            EC_INFO("Changing state of slave %i (%s -> %s).\n",
-                    slave->ring_position, old_state, new_state);
+        if (master->debug_level) {
+            ec_state_string(slave->current_state, old_state);
+            if (!slave->configured
+                && slave->current_state != EC_SLAVE_STATE_INIT) {
+                EC_INFO("Reconfiguring slave %i (%s).\n",
+                        slave->ring_position, old_state);
+            }
+            else if (slave->current_state != slave->requested_state) {
+                ec_state_string(slave->requested_state, new_state);
+                EC_INFO("Changing state of slave %i (%s -> %s).\n",
+                        slave->ring_position, old_state, new_state);
+            }
         }
 
         fsm->slave = slave;
@@ -601,8 +374,7 @@
                 EC_ERR("Failed to add SDO kobj of slave %i.\n",
                        slave->ring_position);
                 slave->error_flag = 1;
-                fsm->master_state = ec_fsm_master_start;
-                fsm->master_state(fsm); // execute immediately
+                fsm->master_state = ec_fsm_master_error;
                 return;
             }
 
@@ -639,9 +411,7 @@
         }
     }
 
-    // nothing to do. restart master state machine.
-    fsm->master_state = ec_fsm_master_start;
-    fsm->master_state(fsm); // execute immediately
+    fsm->master_state = ec_fsm_master_end;
 }
 
 /*****************************************************************************/
@@ -702,8 +472,9 @@
     uint8_t new_state;
 
     if (datagram->state != EC_DATAGRAM_RECEIVED) {
-        fsm->master_state = ec_fsm_master_start;
-        fsm->master_state(fsm); // execute immediately
+        EC_ERR("Failed to receive AL state datagram for slave %i!\n",
+               slave->ring_position);
+        fsm->master_state = ec_fsm_master_error;
         return;
     }
 
@@ -756,15 +527,13 @@
         fsm->slave->error_flag = 1;
         EC_ERR("Failed to validate vendor ID of slave %i.\n",
                slave->ring_position);
-        fsm->master_state = ec_fsm_master_start;
-        fsm->master_state(fsm); // execute immediately
+        fsm->master_state = ec_fsm_master_error;
         return;
     }
 
     if (EC_READ_U32(fsm->fsm_sii.value) != slave->sii_vendor_id) {
-        EC_ERR("Slave %i: invalid vendor ID!\n", slave->ring_position);
-        fsm->master_state = ec_fsm_master_start;
-        fsm->master_state(fsm); // execute immediately
+        EC_ERR("Slave %i has an invalid vendor ID!\n", slave->ring_position);
+        fsm->master_state = ec_fsm_master_error;
         return;
     }
 
@@ -796,7 +565,8 @@
         fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
     }
 
-    EC_INFO("Reinitializing slave %i.\n", fsm->slave->ring_position);
+    if (fsm->master->debug_level)
+        EC_DBG("Reinitializing slave %i.\n", fsm->slave->ring_position);
 
     // write station address
     ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x0010, 2);
@@ -822,8 +592,7 @@
         fsm->slave->error_flag = 1;
         EC_ERR("Failed to validate product code of slave %i.\n",
                slave->ring_position);
-        fsm->master_state = ec_fsm_master_start;
-        fsm->master_state(fsm); // execute immediately
+        fsm->master_state = ec_fsm_master_error;
         return;
     }
 
@@ -831,8 +600,7 @@
         EC_ERR("Slave %i: invalid product code!\n", slave->ring_position);
         EC_ERR("expected 0x%08X, got 0x%08X.\n", slave->sii_product_code,
                EC_READ_U32(fsm->fsm_sii.value));
-        fsm->master_state = ec_fsm_master_start;
-        fsm->master_state(fsm); // execute immediately
+        fsm->master_state = ec_fsm_master_error;
         return;
     }
 
@@ -897,8 +665,8 @@
 
     fsm->slave_state(fsm); // execute slave state machine
 
-    if (fsm->slave_state != ec_fsm_end
-        && fsm->slave_state != ec_fsm_error) return;
+    if (fsm->slave_state != ec_fsm_slave_end
+        && fsm->slave_state != ec_fsm_slave_error) return;
 
     // another slave to fetch?
     if (slave->list.next != &master->slaves) {
@@ -915,11 +683,10 @@
     // set initial states of all slaves to PREOP to make mailbox
     // communication possible
     list_for_each_entry(slave, &master->slaves, list) {
-        slave->requested_state = EC_SLAVE_STATE_PREOP;
-    }
-
-    fsm->master_state = ec_fsm_master_start;
-    fsm->master_state(fsm); // execute immediately
+        ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
+    }
+
+    fsm->master_state = ec_fsm_master_end;
 }
 
 /*****************************************************************************/
@@ -935,8 +702,8 @@
 {
     fsm->slave_state(fsm); // execute slave's state machine
 
-    if (fsm->slave_state != ec_fsm_end
-        && fsm->slave_state != ec_fsm_error) return;
+    if (fsm->slave_state != ec_fsm_slave_end
+        && fsm->slave_state != ec_fsm_slave_error) return;
 
     ec_fsm_master_action_process_states(fsm);
 }
@@ -959,8 +726,7 @@
                slave->ring_position);
         kfree(slave->new_eeprom_data);
         slave->new_eeprom_data = NULL;
-        fsm->master_state = ec_fsm_master_start;
-        fsm->master_state(fsm); // execute immediately
+        fsm->master_state = ec_fsm_master_error;
         return;
     }
 
@@ -999,8 +765,7 @@
     if (ec_fsm_coe_exec(&fsm->fsm_coe)) return;
 
     if (!ec_fsm_coe_success(&fsm->fsm_coe)) {
-        fsm->master_state = ec_fsm_master_start;
-        fsm->master_state(fsm); // execute immediately
+        fsm->master_state = ec_fsm_master_error;
         return;
     }
 
@@ -1034,8 +799,7 @@
     if (!ec_fsm_coe_success(&fsm->fsm_coe)) {
         request->return_code = -1;
         master->sdo_seq_master++;
-        fsm->master_state = ec_fsm_master_start;
-        fsm->master_state(fsm); // execute immediately
+        fsm->master_state = ec_fsm_master_error;
         return;
     }
 
@@ -1049,6 +813,28 @@
     fsm->master_state(fsm); // execute immediately
 }
 
+/*****************************************************************************/
+
+/**
+   State: ERROR.
+*/
+
+void ec_fsm_master_error(ec_fsm_t *fsm /**< finite state machine */)
+{
+    fsm->master_state = ec_fsm_master_start;
+}
+
+/*****************************************************************************/
+
+/**
+   State: END.
+*/
+
+void ec_fsm_master_end(ec_fsm_t *fsm /**< finite state machine */)
+{
+    fsm->master_state = ec_fsm_master_start;
+}
+
 /******************************************************************************
  *  slave scan state machine
  *****************************************************************************/
@@ -1083,7 +869,7 @@
     if (datagram->state != EC_DATAGRAM_RECEIVED
         || datagram->working_counter != 1) {
         fsm->slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         EC_ERR("Failed to write station address of slave %i.\n",
                fsm->slave->ring_position);
         return;
@@ -1109,7 +895,7 @@
     if (datagram->state != EC_DATAGRAM_RECEIVED
         || datagram->working_counter != 1) {
         fsm->slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         EC_ERR("Failed to read AL state of slave %i.\n",
                fsm->slave->ring_position);
         return;
@@ -1141,7 +927,7 @@
     if (datagram->state != EC_DATAGRAM_RECEIVED
         || datagram->working_counter != 1) {
         fsm->slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         EC_ERR("Failed to read base data of slave %i.\n",
                slave->ring_position);
         return;
@@ -1178,7 +964,7 @@
     if (datagram->state != EC_DATAGRAM_RECEIVED
         || datagram->working_counter != 1) {
         fsm->slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         EC_ERR("Failed to read DL status of slave %i.\n",
                slave->ring_position);
         return;
@@ -1214,7 +1000,7 @@
 
     if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
         fsm->slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         EC_ERR("Failed to read EEPROM size of slave %i.\n",
                slave->ring_position);
         return;
@@ -1242,7 +1028,7 @@
     if (!(slave->eeprom_data =
           (uint8_t *) kmalloc(slave->eeprom_size, GFP_ATOMIC))) {
         fsm->slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         EC_ERR("Failed to allocate EEPROM data on slave %i.\n",
                slave->ring_position);
         return;
@@ -1271,7 +1057,7 @@
 
     if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
         fsm->slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         EC_ERR("Failed to fetch EEPROM contents of slave %i.\n",
                slave->ring_position);
         return;
@@ -1359,13 +1145,13 @@
         cat_word += cat_size + 2;
     }
 
-    fsm->slave_state = ec_fsm_end;
+    fsm->slave_state = ec_fsm_slave_end;
     return;
 
 end:
     EC_ERR("Failed to analyze category data.\n");
     fsm->slave->error_flag = 1;
-    fsm->slave_state = ec_fsm_error;
+    fsm->slave_state = ec_fsm_slave_error;
 }
 
 /******************************************************************************
@@ -1388,7 +1174,7 @@
 
     if (!ec_fsm_change_success(&fsm->fsm_change)) {
         slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         return;
     }
 
@@ -1400,7 +1186,7 @@
 
     // slave is now in INIT
     if (slave->current_state == slave->requested_state) {
-        fsm->slave_state = ec_fsm_end; // successful
+        fsm->slave_state = ec_fsm_slave_end; // successful
         if (master->debug_level) {
             EC_DBG("Finished configuration of slave %i.\n",
                    slave->ring_position);
@@ -1457,7 +1243,7 @@
             if (sync->index >= slave->base_sync_count) {
                 EC_ERR("Invalid sync manager configuration found!");
                 fsm->slave->error_flag = 1;
-                fsm->slave_state = ec_fsm_error;
+                fsm->slave_state = ec_fsm_slave_error;
                 return;
             }
             ec_sync_config(sync, slave,
@@ -1483,7 +1269,7 @@
     if (datagram->state != EC_DATAGRAM_RECEIVED
         || datagram->working_counter != 1) {
         slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         EC_ERR("Failed to set sync managers on slave %i.\n",
                slave->ring_position);
         return;
@@ -1511,7 +1297,7 @@
 
     if (!ec_fsm_change_success(&fsm->fsm_change)) {
         slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         return;
     }
 
@@ -1523,7 +1309,7 @@
     }
 
     if (slave->current_state == slave->requested_state) {
-        fsm->slave_state = ec_fsm_end; // successful
+        fsm->slave_state = ec_fsm_slave_end; // successful
         if (master->debug_level) {
             EC_DBG("Finished configuration of slave %i.\n",
                    slave->ring_position);
@@ -1574,7 +1360,7 @@
     if (datagram->state != EC_DATAGRAM_RECEIVED
         || datagram->working_counter != 1) {
         fsm->slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         EC_ERR("Failed to set FMMUs on slave %i.\n",
                fsm->slave->ring_position);
         return;
@@ -1608,7 +1394,7 @@
 
     if (!ec_fsm_coe_success(&fsm->fsm_coe)) {
         fsm->slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         return;
     }
 
@@ -1644,7 +1430,7 @@
 
     if (!ec_fsm_change_success(&fsm->fsm_change)) {
         fsm->slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         return;
     }
 
@@ -1655,7 +1441,7 @@
     }
 
     if (fsm->slave->current_state == fsm->slave->requested_state) {
-        fsm->slave_state = ec_fsm_end; // successful
+        fsm->slave_state = ec_fsm_slave_end; // successful
         if (master->debug_level) {
             EC_DBG("Finished configuration of slave %i.\n",
                    slave->ring_position);
@@ -1684,7 +1470,7 @@
 
     if (!ec_fsm_change_success(&fsm->fsm_change)) {
         slave->error_flag = 1;
-        fsm->slave_state = ec_fsm_error;
+        fsm->slave_state = ec_fsm_slave_error;
         return;
     }
 
@@ -1695,7 +1481,7 @@
         EC_DBG("Finished configuration of slave %i.\n", slave->ring_position);
     }
 
-    fsm->slave_state = ec_fsm_end; // successful
+    fsm->slave_state = ec_fsm_slave_end; // successful
 }
 
 /******************************************************************************
@@ -1706,7 +1492,7 @@
    State: ERROR.
 */
 
-void ec_fsm_error(ec_fsm_t *fsm /**< finite state machine */)
+void ec_fsm_slave_error(ec_fsm_t *fsm /**< finite state machine */)
 {
 }
 
@@ -1716,8 +1502,8 @@
    State: END.
 */
 
-void ec_fsm_end(ec_fsm_t *fsm /**< finite state machine */)
-{
-}
-
-/*****************************************************************************/
+void ec_fsm_slave_end(ec_fsm_t *fsm /**< finite state machine */)
+{
+}
+
+/*****************************************************************************/
--- a/master/fsm.h	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/fsm.h	Thu Oct 26 16:29:26 2006 +0000
@@ -84,14 +84,9 @@
 
 int ec_fsm_init(ec_fsm_t *, ec_master_t *);
 void ec_fsm_clear(ec_fsm_t *);
-void ec_fsm_reset(ec_fsm_t *);
+
 int ec_fsm_exec(ec_fsm_t *);
-
-void ec_fsm_startup(ec_fsm_t *);
-int ec_fsm_startup_success(ec_fsm_t *);
-
-void ec_fsm_configuration(ec_fsm_t *);
-int ec_fsm_configuration_success(ec_fsm_t *);
+int ec_fsm_success(ec_fsm_t *);
 
 /*****************************************************************************/
 
--- a/master/fsm_coe.c	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/fsm_coe.c	Thu Oct 26 16:29:26 2006 +0000
@@ -360,7 +360,7 @@
     }
 
     if (mbox_prot != 0x03) { // CoE
-        EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
+        EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
         fsm->state = ec_fsm_coe_error;
 	return;
     }
@@ -549,7 +549,7 @@
     }
 
     if (mbox_prot != 0x03) { // CoE
-        EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
+        EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
         fsm->state = ec_fsm_coe_error;
 	return;
     }
@@ -722,7 +722,7 @@
     }
 
     if (mbox_prot != 0x03) { // CoE
-        EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
+        EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
         fsm->state = ec_fsm_coe_error;
 	return;
     }
@@ -970,7 +970,7 @@
     }
 
     if (mbox_prot != 0x03) { // CoE
-        EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
+        EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
         fsm->state = ec_fsm_coe_error;
 	return;
     }
@@ -1210,8 +1210,10 @@
     request->size = 0;
 
     if (complete_size) {
-        if (!(request->data = (uint8_t *) kmalloc(complete_size + 1, GFP_ATOMIC))) {
-            EC_ERR("Failed to allocate %i bytes of SDO data!\n", complete_size);
+        if (!(request->data = (uint8_t *)
+              kmalloc(complete_size + 1, GFP_ATOMIC))) {
+            EC_ERR("Failed to allocate %i bytes of SDO data!\n",
+                   complete_size);
             fsm->state = ec_fsm_coe_error;
             return;
         }
@@ -1228,9 +1230,11 @@
         fsm->toggle = 0;
 
         if (data_size < complete_size) {
-            EC_WARN("SDO data incomplete (%i / %i).\n", data_size, complete_size);
-
-            if (!(data = ec_slave_mbox_prepare_send(slave, datagram, 0x03, 3))) {
+            EC_WARN("SDO data incomplete (%i / %i).\n",
+                    data_size, complete_size);
+
+            if (!(data = ec_slave_mbox_prepare_send(slave, datagram,
+                                                    0x03, 3))) {
                 fsm->state = ec_fsm_coe_error;
                 return;
             }
@@ -1354,7 +1358,7 @@
     }
 
     if (mbox_prot != 0x03) { // CoE
-        EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
+        EC_ERR("Received mailbox protocol 0x%02X as response.\n", mbox_prot);
         fsm->state = ec_fsm_coe_error;
 	return;
     }
--- a/master/master.c	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/master.c	Thu Oct 26 16:29:26 2006 +0000
@@ -59,6 +59,7 @@
 void ec_master_idle_run(void *);
 void ec_master_eoe_run(unsigned long);
 void ec_master_check_sdo(unsigned long);
+int ec_master_measure_bus_time(ec_master_t *);
 ssize_t ec_show_master_attribute(struct kobject *, struct attribute *, char *);
 ssize_t ec_store_master_attribute(struct kobject *, struct attribute *,
                                   const char *, size_t);
@@ -109,28 +110,55 @@
 
     EC_INFO("Initializing master %i.\n", index);
 
+    atomic_set(&master->available, 1);
     master->index = index;
+
     master->device = NULL;
     init_MUTEX(&master->device_sem);
-    atomic_set(&master->available, 1);
+
+    master->mode = EC_MASTER_MODE_ORPHANED;
+
     INIT_LIST_HEAD(&master->slaves);
+    master->slave_count = 0;
+
     INIT_LIST_HEAD(&master->datagram_queue);
+    master->datagram_index = 0;
+
     INIT_LIST_HEAD(&master->domains);
-    INIT_LIST_HEAD(&master->eoe_handlers);
+    master->debug_level = 0;
+
+    master->stats.timeouts = 0;
+    master->stats.corrupted = 0;
+    master->stats.skipped = 0;
+    master->stats.unmatched = 0;
+    master->stats.output_jiffies = 0;
+
     INIT_WORK(&master->idle_work, ec_master_idle_run, (void *) master);
+
+    for (i = 0; i < HZ; i++) {
+        master->idle_cycle_times[i] = 0;
+        master->eoe_cycle_times[i] = 0;
+    }
+    master->idle_cycle_time_pos = 0;
+    master->eoe_cycle_time_pos = 0;
+
     init_timer(&master->eoe_timer);
     master->eoe_timer.function = ec_master_eoe_run;
     master->eoe_timer.data = (unsigned long) master;
-    master->internal_lock = SPIN_LOCK_UNLOCKED;
     master->eoe_running = 0;
     master->eoe_checked = 0;
-    for (i = 0; i < HZ; i++) {
-        master->idle_cycle_times[i] = 0;
-        master->eoe_cycle_times[i] = 0;
-    }
-    master->idle_cycle_time_pos = 0;
-    master->eoe_cycle_time_pos = 0;
-    master->debug_level = 0;
+    INIT_LIST_HEAD(&master->eoe_handlers);
+
+    master->internal_lock = SPIN_LOCK_UNLOCKED;
+    master->request_cb = NULL;
+    master->release_cb = NULL;
+    master->cb_data = NULL;
+
+    master->eeprom_write_enable = 0;
+
+    master->sdo_request = NULL;
+    master->sdo_seq_user = 0;
+    master->sdo_seq_master = 0;
     init_MUTEX(&master->sdo_sem);
     init_timer(&master->sdo_timer);
     master->sdo_timer.function = ec_master_check_sdo;
@@ -175,7 +203,6 @@
         return -1;
     }
 
-    ec_master_reset(master);
     return 0;
 
  out_clear_eoe:
@@ -203,10 +230,17 @@
 {
     ec_master_t *master = container_of(kobj, ec_master_t, kobj);
     ec_eoe_t *eoe, *next_eoe;
-
-    EC_INFO("Clearing master %i...\n", master->index);
-
-    ec_master_reset(master);
+    ec_datagram_t *datagram, *next_c;
+
+    ec_master_clear_slaves(master);
+
+    // empty datagram queue
+    list_for_each_entry_safe(datagram, next_c,
+                             &master->datagram_queue, queue) {
+        datagram->state = EC_DATAGRAM_ERROR;
+        list_del_init(&datagram->queue);
+    }
+
     ec_fsm_clear(&master->fsm);
     destroy_workqueue(master->workqueue);
     ec_xmldev_clear(&master->xmldev);
@@ -218,11 +252,6 @@
         kfree(eoe);
     }
 
-    if (master->device) {
-        ec_device_clear(master->device);
-        kfree(master->device);
-    }
-
     EC_INFO("Master %i cleared.\n", master->index);
 
     kfree(master);
@@ -231,57 +260,6 @@
 /*****************************************************************************/
 
 /**
-   Resets the master.
-   Note: This function has to be called, everytime ec_master_release() is
-   called, to free the slave list, domains etc.
-*/
-
-void ec_master_reset(ec_master_t *master /**< EtherCAT master */)
-{
-    ec_datagram_t *datagram, *next_c;
-    ec_domain_t *domain, *next_d;
-
-    ec_master_eoe_stop(master);
-    ec_master_idle_stop(master);
-    ec_master_flush_sdo_requests(master);
-    ec_master_clear_slaves(master);
-
-    // empty datagram queue
-    list_for_each_entry_safe(datagram, next_c,
-                             &master->datagram_queue, queue) {
-        datagram->state = EC_DATAGRAM_ERROR;
-        list_del_init(&datagram->queue);
-    }
-
-    // clear domains
-    list_for_each_entry_safe(domain, next_d, &master->domains, list) {
-        list_del(&domain->list);
-        kobject_del(&domain->kobj);
-        kobject_put(&domain->kobj);
-    }
-
-    master->datagram_index = 0;
-
-    master->stats.timeouts = 0;
-    master->stats.corrupted = 0;
-    master->stats.skipped = 0;
-    master->stats.unmatched = 0;
-    master->stats.output_jiffies = 0;
-
-    master->mode = EC_MASTER_MODE_ORPHANED;
-
-    master->request_cb = NULL;
-    master->release_cb = NULL;
-    master->cb_data = NULL;
-
-    master->eeprom_write_enable = 0;
-
-    ec_fsm_reset(&master->fsm);
-}
-
-/*****************************************************************************/
-
-/**
    Clears all slaves.
 */
 
@@ -294,6 +272,7 @@
         kobject_del(&slave->kobj);
         kobject_put(&slave->kobj);
     }
+
     master->slave_count = 0;
 }
 
@@ -315,6 +294,123 @@
 /*****************************************************************************/
 
 /**
+*/
+
+int ec_master_enter_idle_mode(ec_master_t *master /**< EtherCAT master */)
+{
+    master->mode = EC_MASTER_MODE_IDLE;
+    queue_delayed_work(master->workqueue, &master->idle_work, 1);
+    return 0;
+}
+
+/*****************************************************************************/
+
+/**
+*/
+
+void ec_master_leave_idle_mode(ec_master_t *master /**< EtherCAT master */)
+{
+    ec_master_eoe_stop(master);
+
+    master->mode = EC_MASTER_MODE_ORPHANED;
+    if (!cancel_delayed_work(&master->idle_work)) {
+        flush_workqueue(master->workqueue);
+    }
+
+    ec_master_flush_sdo_requests(master);
+}
+
+/*****************************************************************************/
+
+/**
+*/
+
+int ec_master_enter_operation_mode(ec_master_t *master /**< EtherCAT master */)
+{
+    ec_slave_t *slave;
+    ec_datagram_t *datagram = &master->fsm.datagram;
+
+    master->mode = EC_MASTER_MODE_OPERATION;
+    if (!cancel_delayed_work(&master->idle_work)) {
+        flush_workqueue(master->workqueue);
+    }
+
+    // wait for FSM datagram
+    if (datagram->state == EC_DATAGRAM_SENT) {;
+        while (get_cycles() - datagram->cycles_sent
+               < (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000)) {}
+        ecrt_master_receive(master);
+    }
+
+    // finish running FSM
+    while (ec_fsm_exec(&master->fsm)) {
+        ec_master_sync_io(master);
+    }
+
+    if (!ec_fsm_success(&master->fsm)) {
+        EC_ERR("Master state machine failure!\n");
+        goto out_idle;
+    }
+
+    if (master->debug_level) {
+        if (ec_master_measure_bus_time(master)) {
+            EC_ERR("Bus time measuring failed!\n");
+            goto out_idle;
+        }
+    }
+
+    // set initial slave states
+    list_for_each_entry(slave, &master->slaves, list) {
+        if (ec_slave_is_coupler(slave)) {
+            ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
+        }
+        else {
+            ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
+        }
+    }
+
+    return 0;
+
+ out_idle:
+    master->mode = EC_MASTER_MODE_IDLE;
+    queue_delayed_work(master->workqueue, &master->idle_work, 1);
+    return -1;
+}
+
+/*****************************************************************************/
+
+/**
+*/
+
+void ec_master_leave_operation_mode(ec_master_t *master
+                                    /**< EtherCAT master */)
+{
+    ec_slave_t *slave;
+    ec_domain_t *domain, *next_d;
+
+    // clear domains
+    list_for_each_entry_safe(domain, next_d, &master->domains, list) {
+        ec_domain_dequeue_datagrams(domain);
+        list_del(&domain->list);
+        kobject_del(&domain->kobj);
+        kobject_put(&domain->kobj);
+    }
+
+    master->request_cb = NULL;
+    master->release_cb = NULL;
+    master->cb_data = NULL;
+
+    list_for_each_entry(slave, &master->slaves, list) {
+        ec_slave_reset(slave);
+    }
+
+    master->mode = EC_MASTER_MODE_IDLE;
+    queue_delayed_work(master->workqueue, &master->idle_work, 1);
+}
+
+/*****************************************************************************/
+
+/**
    Places a datagram in the datagram queue.
 */
 
@@ -545,32 +641,6 @@
 /*****************************************************************************/
 
 /**
-   Scans the EtherCAT bus for slaves.
-   Creates a list of slave structures for further processing.
-   \return 0 in case of success, else < 0
-*/
-
-int ec_master_bus_scan(ec_master_t *master /**< EtherCAT master */)
-{
-    ec_fsm_t *fsm = &master->fsm;
-
-    ec_fsm_startup(fsm); // init startup state machine
-
-    while (ec_fsm_exec(fsm)) {
-        ec_master_sync_io(master);
-    }
-
-    if (!ec_fsm_startup_success(fsm)) {
-        ec_master_clear_slaves(master);
-        return -1;
-    }
-
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
    Output statistics in cyclic mode.
    This function outputs statistical data on demand, but not more often than
    necessary. The output happens at most once a second.
@@ -607,52 +677,6 @@
 /*****************************************************************************/
 
 /**
-   Starts the Idle mode.
-*/
-
-void ec_master_idle_start(ec_master_t *master /**< EtherCAT master */)
-{
-    if (master->mode == EC_MASTER_MODE_IDLE) return;
-
-    if (master->mode == EC_MASTER_MODE_OPERATION) {
-        EC_ERR("ec_master_idle_start: Master already running!\n");
-        return;
-    }
-
-    EC_INFO("Starting Idle mode.\n");
-
-    master->mode = EC_MASTER_MODE_IDLE;
-    ec_fsm_reset(&master->fsm);
-    queue_delayed_work(master->workqueue, &master->idle_work, 1);
-}
-
-/*****************************************************************************/
-
-/**
-   Stops the Idle mode.
-*/
-
-void ec_master_idle_stop(ec_master_t *master /**< EtherCAT master */)
-{
-    if (master->mode != EC_MASTER_MODE_IDLE) return;
-
-    ec_master_eoe_stop(master);
-
-    EC_INFO("Stopping Idle mode.\n");
-    master->mode = EC_MASTER_MODE_ORPHANED; // this is important for the
-                                            // IDLE work function to not
-                                            // queue itself again
-
-    if (!cancel_delayed_work(&master->idle_work)) {
-        flush_workqueue(master->workqueue);
-    }
-
-    ec_master_clear_slaves(master);
-}
-
-/*****************************************************************************/
-
-/**
    Idle mode function.
 */
 
@@ -947,16 +971,16 @@
             coupled++;
             EC_INFO("Coupling device %s to slave %i.\n",
                     eoe->dev->name, slave->ring_position);
-            if (eoe->opened) slave->requested_state = EC_SLAVE_STATE_OP;
-            else slave->requested_state = EC_SLAVE_STATE_INIT;
-            slave->error_flag = 0;
+            if (eoe->opened)
+                ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
+            else
+                ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
             break;
         }
 
         if (!found) {
             EC_WARN("No EoE handler for slave %i!\n", slave->ring_position);
-            slave->requested_state = EC_SLAVE_STATE_INIT;
-            slave->error_flag = 0;
+            ec_slave_request_state(slave, EC_SLAVE_STATE_INIT);
         }
     }
 
@@ -995,8 +1019,7 @@
     // decouple all EoE handlers
     list_for_each_entry(eoe, &master->eoe_handlers, list) {
         if (eoe->slave) {
-            eoe->slave->requested_state = EC_SLAVE_STATE_INIT;
-            eoe->slave->error_flag = 0;
+            ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_PREOP);
             eoe->slave = NULL;
         }
     }
@@ -1253,27 +1276,23 @@
         domain_offset += domain->data_size;
     }
 
-    // determine initial states.
-    list_for_each_entry(slave, &master->slaves, list) {
-        if (ec_slave_is_coupler(slave) || slave->registered) {
-            slave->requested_state = EC_SLAVE_STATE_OP;
-        }
-        else {
-            slave->requested_state = EC_SLAVE_STATE_PREOP;
-        }
-    }
-
-    ec_fsm_configuration(fsm); // init configuration state machine
-
+    // execute master FSM until termination
     while (ec_fsm_exec(fsm)) {
         ec_master_sync_io(master);
     }
 
-    if (!ec_fsm_configuration_success(fsm)) {
+    if (!ec_fsm_success(fsm)) {
+        EC_ERR("Error in master state machine.\n");
         return -1;
     }
 
-    ec_fsm_reset(&master->fsm); // prepare for operation state machine
+    // check, if all slaves have been configured
+    list_for_each_entry(slave, &master->slaves, list) {
+        if (slave->error_flag || !slave->online) {
+            EC_ERR("Failed to configure slave %i!\n", slave->ring_position);
+            return -1;
+        }
+    }
 
     return 0;
 }
@@ -1289,13 +1308,21 @@
 {
     ec_fsm_t *fsm = &master->fsm;
     ec_slave_t *slave;
-
+    ec_datagram_t *datagram = &master->fsm.datagram;
+
+    // wait for FSM datagram
+    if (datagram->state == EC_DATAGRAM_SENT) {
+        while (get_cycles() - datagram->cycles_sent
+               < (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000)) {}
+        ecrt_master_receive(master);
+    }
+
+    // set states for all slaves
     list_for_each_entry(slave, &master->slaves, list) {
-        slave->requested_state = EC_SLAVE_STATE_INIT;
-    }
-
-    ec_fsm_configuration(fsm); // init configuration state machine
-
+        ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
+    }
+
+    // execute master FSM to deactivate slaves
     while (ec_fsm_exec(fsm)) {
         ec_master_sync_io(master);
     }
@@ -1416,7 +1443,7 @@
 
     // queue datagrams of all domains
     list_for_each_entry(domain, &master->domains, list)
-        ec_domain_queue(domain);
+        ec_domain_queue_datagrams(domain);
 
     ecrt_master_send(master);
 
@@ -1443,7 +1470,7 @@
     // output statistics
     ec_master_output_stats(master);
 
-    // execute master state machine
+    // execute master state machine in a loop
     ec_fsm_exec(&master->fsm);
 }
 
--- a/master/master.h	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/master.h	Thu Oct 26 16:29:26 2006 +0000
@@ -148,35 +148,31 @@
 
 /*****************************************************************************/
 
-// master creation and deletion
+// master creation
 int ec_master_init(ec_master_t *, unsigned int, unsigned int, dev_t);
-void ec_master_reset(ec_master_t *);
 
-// free run
-void ec_master_idle_start(ec_master_t *);
-void ec_master_idle_stop(ec_master_t *);
+// mode transitions
+int ec_master_enter_idle_mode(ec_master_t *);
+void ec_master_leave_idle_mode(ec_master_t *);
+int ec_master_enter_operation_mode(ec_master_t *);
+void ec_master_leave_operation_mode(ec_master_t *);
 
 // EoE
 void ec_master_eoe_start(ec_master_t *);
 void ec_master_eoe_stop(ec_master_t *);
 
-// IO
+// datagram IO
 void ec_master_receive_datagrams(ec_master_t *, const uint8_t *, size_t);
 void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *);
 
-// slave management
-int ec_master_bus_scan(ec_master_t *);
-
 // misc.
 void ec_master_output_stats(ec_master_t *);
 void ec_master_clear_slaves(ec_master_t *);
-int ec_master_measure_bus_time(ec_master_t *);
+void ec_master_calc_addressing(ec_master_t *);
 
-// other methods
+// helper functions
 void ec_sync_config(const ec_sii_sync_t *, const ec_slave_t *, uint8_t *);
 void ec_fmmu_config(const ec_fmmu_t *, const ec_slave_t *, uint8_t *);
-void ec_master_calc_addressing(ec_master_t *);
-void ec_master_flush_sdo_requests(ec_master_t *);
 
 /*****************************************************************************/
 
--- a/master/module.c	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/module.c	Thu Oct 26 16:29:26 2006 +0000
@@ -384,7 +384,8 @@
         return -1;
     }
 
-    ec_master_idle_start(master);
+    ec_master_enter_idle_mode(master);
+
     return 0;
 }
 
@@ -402,8 +403,7 @@
     ec_master_t *master;
     if (!(master = ec_find_master(master_index))) return;
 
-    ec_master_idle_stop(master);
-    ec_master_flush_sdo_requests(master);
+    ec_master_leave_idle_mode(master);
 
     if (ec_device_close(master->device))
         EC_WARN("Failed to close device!\n");
@@ -459,31 +459,19 @@
         goto out_module_put;
     }
 
-    ec_master_reset(master); // also stops idle mode
-    master->mode = EC_MASTER_MODE_OPERATION;
-
-    if (ec_master_measure_bus_time(master)) {
-        EC_ERR("Bus time measuring failed!\n");
-        goto out_reset;
-    }
-
-    if (ec_master_bus_scan(master)) {
-        EC_ERR("Bus scan failed!\n");
-        goto out_reset;
+    if (ec_master_enter_operation_mode(master)) {
+        EC_ERR("Failed to enter OPERATION mode!\n");
+        goto out_module_put;
     }
 
     EC_INFO("Successfully requested master %i.\n", master_index);
     return master;
 
- out_reset:
-    ec_master_reset(master);
-    ec_master_idle_start(master);
  out_module_put:
     module_put(master->device->module);
  out_release:
     atomic_inc(&master->available);
  out_return:
-    EC_ERR("Failed to request master %i.\n", master_index);
     return NULL;
 }
 
@@ -496,20 +484,12 @@
 
 void ecrt_release_master(ec_master_t *master /**< EtherCAT master */)
 {
-    EC_INFO("Releasing master %i...\n", master->index);
-
-    if (atomic_read(&master->available)) {
-        EC_ERR("Master %i was never requested!\n", master->index);
-        return;
-    }
-
-    ec_master_reset(master);
-    ec_master_idle_start(master);
+    ec_master_leave_operation_mode(master);
 
     module_put(master->device->module);
     atomic_inc(&master->available);
 
-    EC_INFO("Successfully released master %i.\n", master->index);
+    EC_INFO("Released master %i.\n", master->index);
     return;
 }
 
--- a/master/slave.c	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/slave.c	Thu Oct 26 16:29:26 2006 +0000
@@ -136,7 +136,6 @@
     slave->error_flag = 0;
     slave->online = 1;
     slave->fmmu_count = 0;
-    slave->registered = 0;
 
     slave->coupler_index = 0;
     slave->coupler_subindex = 0xFFFF;
@@ -243,7 +242,7 @@
         kobject_put(&sdo->kobj);
     }
 
-    // free SDO kobject
+    // free SDO kobject FIXME
     if (slave->sdo_dictionary_fetched) kobject_del(&slave->sdo_kobj);
     kobject_put(&slave->sdo_kobj);
 
@@ -263,6 +262,30 @@
 /*****************************************************************************/
 
 /**
+   Reset slave from operation mode.
+*/
+
+void ec_slave_reset(ec_slave_t *slave /**< EtherCAT slave */)
+{
+    slave->fmmu_count = 0;
+}
+
+/*****************************************************************************/
+
+/**
+ */
+
+void ec_slave_request_state(ec_slave_t *slave, /**< ETherCAT slave */
+                            ec_slave_state_t state /**< new state */
+                            )
+{
+    slave->requested_state = state;
+    slave->error_flag = 0;
+}
+
+/*****************************************************************************/
+
+/**
    Fetches data from a STRING category.
    \return 0 in case of success, else < 0
 */
@@ -514,7 +537,6 @@
     fmmu->logical_start_address = 0;
 
     slave->fmmu_count++;
-    slave->registered = 1;
 
     return 0;
 }
@@ -810,13 +832,13 @@
     if (attr == &attr_state) {
         char state[EC_STATE_STRING_SIZE];
         if (!strcmp(buffer, "INIT\n"))
-            slave->requested_state = EC_SLAVE_STATE_INIT;
+            ec_slave_request_state(slave, EC_SLAVE_STATE_INIT);
         else if (!strcmp(buffer, "PREOP\n"))
-            slave->requested_state = EC_SLAVE_STATE_PREOP;
+            ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
         else if (!strcmp(buffer, "SAVEOP\n"))
-            slave->requested_state = EC_SLAVE_STATE_SAVEOP;
+            ec_slave_request_state(slave, EC_SLAVE_STATE_SAVEOP);
         else if (!strcmp(buffer, "OP\n"))
-            slave->requested_state = EC_SLAVE_STATE_OP;
+            ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
         else {
             EC_ERR("Invalid slave state \"%s\"!\n", buffer);
             return -EINVAL;
@@ -825,7 +847,6 @@
         ec_state_string(slave->requested_state, state);
         EC_INFO("Accepted new state %s for slave %i.\n",
                 state, slave->ring_position);
-        slave->error_flag = 0;
         return size;
     }
     else if (attr == &attr_eeprom) {
--- a/master/slave.h	Wed Oct 25 16:53:17 2006 +0000
+++ b/master/slave.h	Thu Oct 26 16:29:26 2006 +0000
@@ -197,10 +197,9 @@
 
     ec_slave_state_t requested_state; /**< requested slave state */
     ec_slave_state_t current_state; /**< current slave state */
-    unsigned int configured; /**< the slave is configured by this master */
+    unsigned int configured; /**< the slave was configured by this master */
     unsigned int error_flag; /**< stop processing after an error */
     unsigned int online; /**< non-zero, if the slave responds. */
-    uint8_t registered; /**< true, if slave has been registered */
 
     // addresses
     uint16_t ring_position; /**< ring position */
@@ -261,9 +260,13 @@
 // slave construction/destruction
 int ec_slave_init(ec_slave_t *, ec_master_t *, uint16_t, uint16_t);
 
+void ec_slave_reset(ec_slave_t *);
+
 int ec_slave_prepare_fmmu(ec_slave_t *, const ec_domain_t *,
                           const ec_sii_sync_t *);
 
+void ec_slave_request_state(ec_slave_t *, ec_slave_state_t);
+
 // SII categories
 int ec_slave_fetch_strings(ec_slave_t *, const uint8_t *);
 void ec_slave_fetch_general(ec_slave_t *, const uint8_t *);