master/fsm_master.c
changeset 656 370aa8c2d1b1
parent 652 15cff76b66c7
child 661 bc1de1362efb
--- a/master/fsm_master.c	Mon Mar 12 18:15:06 2007 +0000
+++ b/master/fsm_master.c	Mon Mar 12 18:21:42 2007 +0000
@@ -221,53 +221,68 @@
         EC_INFO("Slave states: %s.\n", states);
     }
 
-    // topology change in idle mode: clear all slaves and scan the bus
-    if (fsm->topology_change_pending &&
-            master->mode == EC_MASTER_MODE_IDLE) {
-        fsm->topology_change_pending = 0;
-        fsm->tainted = 0;
-        fsm->idle = 0;
-        fsm->scan_jiffies = jiffies;
-
-        ec_master_eoe_stop(master);
-        ec_master_destroy_slaves(master);
-
-        master->slave_count = datagram->working_counter;
-
-        if (!master->slave_count) {
-            // no slaves present -> finish state machine.
-            fsm->state = ec_fsm_master_state_end;
-            return;
-        }
-
-        // init slaves
-        for (i = 0; i < master->slave_count; i++) {
-            if (!(slave = (ec_slave_t *) kmalloc(sizeof(ec_slave_t),
-                                                 GFP_ATOMIC))) {
-                EC_ERR("Failed to allocate slave %i!\n", i);
-                ec_master_destroy_slaves(master);
-                fsm->state = ec_fsm_master_state_error;
+    if (fsm->topology_change_pending) {
+        down(&master->scan_sem);
+        if (!master->allow_scan) {
+            up(&master->scan_sem);
+        }
+        else {
+            master->scan_state = EC_REQUEST_IN_PROGRESS;
+            up(&master->scan_sem);
+            
+            // topology change when scan is allowed:
+            // clear all slaves and scan the bus
+            fsm->topology_change_pending = 0;
+            fsm->tainted = 0;
+            fsm->idle = 0;
+            fsm->scan_jiffies = jiffies;
+
+            ec_master_eoe_stop(master);
+            ec_master_destroy_slaves(master);
+
+            master->slave_count = datagram->working_counter;
+
+            if (!master->slave_count) {
+                // no slaves present -> finish state machine.
+                master->scan_state = EC_REQUEST_COMPLETE;
+                wake_up_interruptible(&master->scan_queue);
+                fsm->state = ec_fsm_master_state_end;
                 return;
             }
 
-            if (ec_slave_init(slave, master, i, i + 1)) {
-                // freeing of "slave" already done
-                ec_master_destroy_slaves(master);
-                fsm->state = ec_fsm_master_state_error;
-                return;
+            // init slaves
+            for (i = 0; i < master->slave_count; i++) {
+                if (!(slave = (ec_slave_t *) kmalloc(sizeof(ec_slave_t),
+                                GFP_ATOMIC))) {
+                    EC_ERR("Failed to allocate slave %i!\n", i);
+                    ec_master_destroy_slaves(master);
+                    master->scan_state = EC_REQUEST_FAILURE;
+                    wake_up_interruptible(&master->scan_queue);
+                    fsm->state = ec_fsm_master_state_error;
+                    return;
+                }
+
+                if (ec_slave_init(slave, master, i, i + 1)) {
+                    // freeing of "slave" already done
+                    ec_master_destroy_slaves(master);
+                    master->scan_state = EC_REQUEST_FAILURE;
+                    wake_up_interruptible(&master->scan_queue);
+                    fsm->state = ec_fsm_master_state_error;
+                    return;
+                }
+
+                list_add_tail(&slave->list, &master->slaves);
             }
 
-            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->state = ec_fsm_master_state_scan_slaves;
-        ec_fsm_slave_start_scan(&fsm->fsm_slave, fsm->slave);
-        ec_fsm_slave_exec(&fsm->fsm_slave); // execute immediately
-        return;
+            EC_INFO("Scanning bus.\n");
+
+            // begin scanning of slaves
+            fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
+            fsm->state = ec_fsm_master_state_scan_slaves;
+            ec_fsm_slave_start_scan(&fsm->fsm_slave, fsm->slave);
+            ec_fsm_slave_exec(&fsm->fsm_slave); // execute immediately
+            return;
+        }
     }
 
     // fetch state from each slave
@@ -392,36 +407,35 @@
 /*****************************************************************************/
 
 /**
-   Master action: PROC_STATES.
-   Processes the slave states.
-*/
-
-void ec_fsm_master_action_process_states(ec_fsm_master_t *fsm
-                                         /**< master state machine */
-                                         )
-{
+ */
+
+int ec_fsm_master_action_configure(
+        ec_fsm_master_t *fsm /**< master state machine */
+        )
+{
+    ec_slave_t *slave;
     ec_master_t *master = fsm->master;
-    ec_slave_t *slave;
     char old_state[EC_STATE_STRING_SIZE], new_state[EC_STATE_STRING_SIZE];
 
     // check if any slaves are not in the state, they're supposed to be
+    // FIXME do not check all slaves in every cycle...
     list_for_each_entry(slave, &master->slaves, list) {
         if (slave->error_flag
-            || slave->online_state == EC_SLAVE_OFFLINE
-            || slave->requested_state == EC_SLAVE_STATE_UNKNOWN
-            || (slave->current_state == slave->requested_state
-                && slave->self_configured)) continue;
+                || slave->online_state == EC_SLAVE_OFFLINE
+                || slave->requested_state == EC_SLAVE_STATE_UNKNOWN
+                || (slave->current_state == slave->requested_state
+                    && slave->self_configured)) continue;
 
         if (master->debug_level) {
             ec_state_string(slave->current_state, old_state);
             if (slave->current_state != slave->requested_state) {
                 ec_state_string(slave->requested_state, new_state);
                 EC_DBG("Changing state of slave %i (%s -> %s).\n",
-                       slave->ring_position, old_state, new_state);
+                        slave->ring_position, old_state, new_state);
             }
             else if (!slave->self_configured) {
                 EC_DBG("Reconfiguring slave %i (%s).\n",
-                       slave->ring_position, old_state);
+                        slave->ring_position, old_state);
             }
         }
 
@@ -430,7 +444,43 @@
         fsm->state = ec_fsm_master_state_configure_slave;
         ec_fsm_slave_start_conf(&fsm->fsm_slave, slave);
         ec_fsm_slave_exec(&fsm->fsm_slave); // execute immediately
-        return;
+        return 1;
+    }
+
+    if (fsm->config_error)
+        master->config_state = EC_REQUEST_FAILURE;
+    else
+        master->config_state = EC_REQUEST_COMPLETE;
+    wake_up_interruptible(&master->config_queue);
+    return 0;
+}
+
+/*****************************************************************************/
+
+/**
+   Master action: PROC_STATES.
+   Processes the slave states.
+*/
+
+void ec_fsm_master_action_process_states(ec_fsm_master_t *fsm
+                                         /**< master state machine */
+                                         )
+{
+    ec_master_t *master = fsm->master;
+    ec_slave_t *slave;
+
+    down(&master->config_sem);
+    if (!master->allow_config) {
+        up(&master->config_sem);
+    }
+    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;
     }
 
     // Check, if EoE processing has to be started
@@ -769,13 +819,8 @@
 
     EC_INFO("Bus scanning completed in %u ms.\n",
             (u32) (jiffies - fsm->scan_jiffies) * 1000 / HZ);
-
-    // set initial states of all slaves to PREOP to make mailbox
-    // communication possible
-    list_for_each_entry(slave, &master->slaves, list) {
-        if (slave->requested_state == EC_SLAVE_STATE_UNKNOWN)
-            ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
-    }
+    master->scan_state = EC_REQUEST_COMPLETE;
+    wake_up_interruptible(&master->scan_queue);
 
     fsm->state = ec_fsm_master_state_end;
 }
@@ -794,7 +839,14 @@
     if (ec_fsm_slave_exec(&fsm->fsm_slave)) // execute slave's state machine
         return;
 
-    ec_fsm_master_action_process_states(fsm);
+    if (!ec_fsm_slave_success(&fsm->fsm_slave))
+        fsm->config_error = 1;
+
+    // configure next slave, if necessary
+    if (ec_fsm_master_action_configure(fsm))
+        return;
+
+    fsm->state = ec_fsm_master_state_end;
 }
 
 /*****************************************************************************/