diff -r 3702f0d6693b -r 370aa8c2d1b1 master/fsm_master.c --- 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; } /*****************************************************************************/