fp@238: /****************************************************************************** fp@238: * fp@238: * $Id$ fp@238: * fp@1326: * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH fp@238: * fp@238: * This file is part of the IgH EtherCAT Master. fp@238: * fp@1326: * The IgH EtherCAT Master is free software; you can redistribute it and/or fp@1326: * modify it under the terms of the GNU General Public License version 2, as fp@1326: * published by the Free Software Foundation. fp@1326: * fp@1326: * The IgH EtherCAT Master is distributed in the hope that it will be useful, fp@1326: * but WITHOUT ANY WARRANTY; without even the implied warranty of fp@1326: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General fp@1326: * Public License for more details. fp@1326: * fp@1326: * You should have received a copy of the GNU General Public License along fp@1326: * with the IgH EtherCAT Master; if not, write to the Free Software fp@238: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@238: * fp@1363: * --- fp@1363: * fp@1363: * The license mentioned above concerns the source code only. Using the fp@1363: * EtherCAT technology and brand is only permitted in compliance with the fp@1363: * industrial property and similar rights of Beckhoff Automation GmbH. fp@246: * fp@238: *****************************************************************************/ fp@238: fp@907: /** \file fp@907: * EtherCAT master state machine. fp@907: */ fp@238: fp@238: /*****************************************************************************/ fp@238: fp@238: #include "globals.h" fp@238: #include "master.h" fp@329: #include "mailbox.h" fp@858: #include "slave_config.h" fp@715: #ifdef EC_EOE fp@661: #include "ethernet.h" fp@715: #endif fp@849: fp@528: #include "fsm_master.h" fp@1335: #include "fsm_foe.h" fp@528: fp@528: /*****************************************************************************/ fp@528: fp@1925: /** Time difference [ns] to tolerate without setting a new system time offset. fp@1925: */ ch1010277@1998: #ifdef EC_HAVE_CYCLES ch1010277@1998: #define EC_SYSTEM_TIME_TOLERANCE_NS 10000 ch1010277@1998: #else fp@1925: #define EC_SYSTEM_TIME_TOLERANCE_NS 100000000 ch1010277@1998: #endif fp@1925: fp@1925: /*****************************************************************************/ fp@1925: fp@528: void ec_fsm_master_state_start(ec_fsm_master_t *); fp@528: void ec_fsm_master_state_broadcast(ec_fsm_master_t *); fp@907: void ec_fsm_master_state_read_state(ec_fsm_master_t *); fp@528: void ec_fsm_master_state_acknowledge(ec_fsm_master_t *); fp@528: void ec_fsm_master_state_configure_slave(ec_fsm_master_t *); fp@717: void ec_fsm_master_state_clear_addresses(ec_fsm_master_t *); fp@1420: void ec_fsm_master_state_dc_measure_delays(ec_fsm_master_t *); fp@907: void ec_fsm_master_state_scan_slave(ec_fsm_master_t *); fp@1925: void ec_fsm_master_state_dc_read_offset(ec_fsm_master_t *); fp@1925: void ec_fsm_master_state_dc_write_offset(ec_fsm_master_t *); fp@872: void ec_fsm_master_state_write_sii(ec_fsm_master_t *); fp@905: void ec_fsm_master_state_sdo_dictionary(ec_fsm_master_t *); fp@528: void ec_fsm_master_state_sdo_request(ec_fsm_master_t *); fp@1388: void ec_fsm_master_state_reg_request(ec_fsm_master_t *); fp@251: fp@1925: void ec_fsm_master_enter_write_system_times(ec_fsm_master_t *); martin@1583: fp@238: /*****************************************************************************/ fp@238: fp@907: /** Constructor. fp@907: */ fp@907: void ec_fsm_master_init( fp@907: ec_fsm_master_t *fsm, /**< Master state machine. */ fp@907: ec_master_t *master, /**< EtherCAT master. */ fp@907: ec_datagram_t *datagram /**< Datagram object to use. */ fp@528: ) fp@238: { fp@238: fsm->master = master; fp@528: fsm->datagram = datagram; fp@528: fsm->state = ec_fsm_master_state_start; fp@650: fsm->idle = 0; fp@1400: fsm->link_state = 0; fp@528: fsm->slaves_responding = 0; fp@1961: fsm->rescan_required = 0; fp@528: fsm->slave_states = EC_SLAVE_STATE_UNKNOWN; fp@238: fp@436: // init sub-state-machines fp@1174: ec_fsm_coe_init(&fsm->fsm_coe, fsm->datagram); fp@1174: ec_fsm_pdo_init(&fsm->fsm_pdo, &fsm->fsm_coe); fp@1174: ec_fsm_change_init(&fsm->fsm_change, fsm->datagram); fp@1174: ec_fsm_slave_config_init(&fsm->fsm_slave_config, fsm->datagram, fp@1174: &fsm->fsm_change, &fsm->fsm_coe, &fsm->fsm_pdo); fp@831: ec_fsm_slave_scan_init(&fsm->fsm_slave_scan, fsm->datagram, fp@1174: &fsm->fsm_slave_config, &fsm->fsm_pdo); fp@528: ec_fsm_sii_init(&fsm->fsm_sii, fsm->datagram); fp@238: } fp@238: fp@238: /*****************************************************************************/ fp@238: fp@907: /** Destructor. fp@907: */ fp@907: void ec_fsm_master_clear( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@907: ) fp@238: { fp@436: // clear sub-state machines fp@1174: ec_fsm_coe_clear(&fsm->fsm_coe); fp@1174: ec_fsm_pdo_clear(&fsm->fsm_pdo); fp@1174: ec_fsm_change_clear(&fsm->fsm_change); fp@830: ec_fsm_slave_config_clear(&fsm->fsm_slave_config); fp@830: ec_fsm_slave_scan_clear(&fsm->fsm_slave_scan); fp@433: ec_fsm_sii_clear(&fsm->fsm_sii); fp@238: } fp@238: fp@238: /*****************************************************************************/ fp@238: fp@907: /** Executes the current state of the state machine. fp@907: * fp@907: * If the state machine's datagram is not sent or received yet, the execution fp@907: * of the state machine is delayed to the next cycle. martin@1583: * martin@1583: * \return true, if the state machine was executed martin@1583: */ martin@1583: int ec_fsm_master_exec( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@907: ) fp@528: { fp@528: if (fsm->datagram->state == EC_DATAGRAM_SENT fp@528: || fsm->datagram->state == EC_DATAGRAM_QUEUED) { fp@505: // datagram was not sent or received yet. martin@1583: return 0; fp@528: } fp@528: fp@528: fsm->state(fsm); martin@1583: return 1; fp@446: } fp@446: fp@650: /*****************************************************************************/ fp@650: fp@650: /** fp@650: * \return true, if the state machine is in an idle phase fp@650: */ fp@650: int ec_fsm_master_idle( fp@907: const ec_fsm_master_t *fsm /**< Master state machine. */ fp@650: ) fp@650: { fp@650: return fsm->idle; fp@650: } fp@650: fp@1031: /*****************************************************************************/ fp@1031: fp@1031: /** Restarts the master state machine. fp@1031: */ fp@1031: void ec_fsm_master_restart( fp@1031: ec_fsm_master_t *fsm /**< Master state machine. */ fp@1031: ) fp@1031: { fp@1031: fsm->state = ec_fsm_master_state_start; fp@1031: fsm->state(fsm); // execute immediately fp@1031: } fp@1031: fp@238: /****************************************************************************** fp@907: * Master state machine fp@238: *****************************************************************************/ fp@238: fp@907: /** Master state: START. fp@907: * fp@907: * Starts with getting slave count and slave states. fp@907: */ fp@907: void ec_fsm_master_state_start( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@907: ) fp@528: { fp@650: fsm->idle = 1; fp@528: ec_datagram_brd(fsm->datagram, 0x0130, 2); fp@1225: ec_datagram_zero(fsm->datagram); fp@528: fsm->state = ec_fsm_master_state_broadcast; fp@260: } fp@260: fp@260: /*****************************************************************************/ fp@260: fp@907: /** Master state: BROADCAST. fp@907: * fp@907: * Processes the broadcast read slave count and slaves states. fp@907: */ fp@907: void ec_fsm_master_state_broadcast( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@907: ) fp@528: { fp@528: ec_datagram_t *datagram = fsm->datagram; fp@1005: unsigned int i, size; fp@238: ec_slave_t *slave; fp@260: ec_master_t *master = fsm->master; fp@238: fp@637: if (datagram->state == EC_DATAGRAM_TIMED_OUT) fp@637: return; // always retry fp@505: fp@553: // bus topology change? fp@553: if (datagram->working_counter != fsm->slaves_responding) { fp@1961: fsm->rescan_required = 1; fp@553: fsm->slaves_responding = datagram->working_counter; fp@1921: EC_MASTER_INFO(master, "%u slave(s) responding.\n", fp@1921: fsm->slaves_responding); fp@906: } fp@906: fp@1400: if (fsm->link_state && !master->main_device.link_state) { // link went down fp@1921: EC_MASTER_DBG(master, 1, "Master state machine detected " fp@1921: "link down. Clearing slave list.\n"); fp@1402: fp@1400: #ifdef EC_EOE fp@1400: ec_master_eoe_stop(master); fp@1400: ec_master_clear_eoe_handlers(master); fp@1400: #endif fp@1400: ec_master_clear_slaves(master); fp@1830: fsm->slave_states = 0x00; fp@1400: } fp@1400: fsm->link_state = master->main_device.link_state; fp@1400: fp@1402: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1031: ec_fsm_master_restart(fsm); fp@906: return; fp@260: } fp@260: fp@1021: if (fsm->slaves_responding) { fp@1021: uint8_t states = EC_READ_U8(datagram->data); fp@1021: if (states != fsm->slave_states) { // slave states changed? fp@1021: char state_str[EC_STATE_STRING_SIZE]; fp@1021: fsm->slave_states = states; fp@1337: ec_state_string(fsm->slave_states, state_str, 1); fp@1921: EC_MASTER_INFO(master, "Slave states: %s.\n", state_str); fp@1021: } fp@1021: } else { fp@1021: fsm->slave_states = 0x00; fp@260: } fp@260: fp@1961: if (fsm->rescan_required) { fp@656: down(&master->scan_sem); fp@656: if (!master->allow_scan) { fp@656: up(&master->scan_sem); fp@900: } else { fp@900: master->scan_busy = 1; fp@656: up(&master->scan_sem); fp@1335: fp@656: // clear all slaves and scan the bus fp@1961: fsm->rescan_required = 0; fp@656: fsm->idle = 0; fp@656: fsm->scan_jiffies = jiffies; fp@656: fp@715: #ifdef EC_EOE fp@656: ec_master_eoe_stop(master); fp@661: ec_master_clear_eoe_handlers(master); fp@715: #endif fp@992: ec_master_clear_slaves(master); fp@656: fp@1003: master->slave_count = fsm->slaves_responding; fp@656: fp@656: if (!master->slave_count) { fp@656: // no slaves present -> finish state machine. fp@900: master->scan_busy = 0; fp@656: wake_up_interruptible(&master->scan_queue); fp@1031: ec_fsm_master_restart(fsm); fp@260: return; fp@260: } fp@260: fp@1005: size = sizeof(ec_slave_t) * master->slave_count; fp@1005: if (!(master->slaves = (ec_slave_t *) kmalloc(size, GFP_KERNEL))) { fp@1921: EC_MASTER_ERR(master, "Failed to allocate %u bytes" fp@1921: " of slave memory!\n", size); fp@1064: master->slave_count = 0; // TODO avoid retrying scan! fp@1000: master->scan_busy = 0; fp@1000: wake_up_interruptible(&master->scan_queue); fp@1031: ec_fsm_master_restart(fsm); fp@1000: return; fp@1000: } fp@1000: fp@656: // init slaves fp@656: for (i = 0; i < master->slave_count; i++) { fp@1000: slave = master->slaves + i; fp@992: ec_slave_init(slave, master, i, i + 1); fp@656: fp@1029: // do not force reconfiguration in operation phase to avoid fp@908: // unnecesssary process data interruptions fp@1029: if (master->phase != EC_OPERATION) fp@908: slave->force_config = 1; fp@260: } fp@260: fp@904: // broadcast clear all station addresses fp@717: ec_datagram_bwr(datagram, 0x0010, 2); fp@717: EC_WRITE_U16(datagram->data, 0x0000); fp@717: fsm->retries = EC_FSM_RETRIES; fp@717: fsm->state = ec_fsm_master_state_clear_addresses; fp@656: return; fp@656: } fp@260: } fp@260: fp@1000: if (master->slave_count) { fp@1925: fp@1925: // application applied configurations fp@1925: if (master->config_changed) { fp@1925: master->config_changed = 0; fp@1925: fp@1925: EC_MASTER_DBG(master, 1, "Configuration changed.\n"); fp@1925: fp@1925: fsm->slave = master->slaves; // begin with first slave fp@1925: ec_fsm_master_enter_write_system_times(fsm); fp@1925: fp@1925: } else { fp@1925: // fetch state from first slave fp@1925: fsm->slave = master->slaves; fp@1925: ec_datagram_fprd(fsm->datagram, fsm->slave->station_address, fp@1925: 0x0130, 2); fp@1925: ec_datagram_zero(datagram); fp@1925: fsm->retries = EC_FSM_RETRIES; fp@1925: fsm->state = ec_fsm_master_state_read_state; fp@1925: } fp@1000: } else { fp@1031: ec_fsm_master_restart(fsm); fp@907: } fp@907: } fp@907: fp@907: /*****************************************************************************/ fp@907: fp@907: /** Check for pending SII write requests and process one. fp@1335: * fp@872: * \return non-zero, if an SII write request is processed. fp@601: */ fp@872: int ec_fsm_master_action_process_sii( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@601: ) fp@601: { fp@601: ec_master_t *master = fsm->master; fp@872: ec_sii_write_request_t *request; fp@601: fp@604: // search the first request to be processed fp@604: while (1) { fp@1079: if (list_empty(&master->sii_requests)) fp@604: break; fp@1079: fp@604: // get first request fp@872: request = list_entry(master->sii_requests.next, fp@872: ec_sii_write_request_t, list); fp@601: list_del_init(&request->list); // dequeue fp@1209: request->state = EC_INT_REQUEST_BUSY; fp@601: fp@872: // found pending SII write operation. execute it! fp@1921: EC_SLAVE_DBG(request->slave, 1, "Writing SII data...\n"); fp@872: fsm->sii_request = request; fp@872: fsm->sii_index = 0; fp@979: ec_fsm_sii_write(&fsm->fsm_sii, request->slave, request->offset, fp@979: request->words, EC_FSM_SII_USE_CONFIGURED_ADDRESS); fp@872: fsm->state = ec_fsm_master_state_write_sii; fp@601: fsm->state(fsm); // execute immediately fp@601: return 1; fp@601: } fp@601: fp@601: return 0; fp@601: } fp@601: fp@601: /*****************************************************************************/ fp@601: fp@1388: /** Check for pending register requests and process one. martin@1579: * fp@1388: * \return non-zero, if a register request is processed. fp@1388: */ fp@1388: int ec_fsm_master_action_process_register( fp@1388: ec_fsm_master_t *fsm /**< Master state machine. */ fp@1388: ) fp@1388: { fp@1388: ec_master_t *master = fsm->master; fp@1388: ec_reg_request_t *request; fp@1200: fp@1200: // search the first request to be processed fp@1388: while (!list_empty(&master->reg_requests)) { fp@1200: fp@1200: // get first request fp@1388: request = list_entry(master->reg_requests.next, fp@1388: ec_reg_request_t, list); fp@1200: list_del_init(&request->list); // dequeue fp@1209: request->state = EC_INT_REQUEST_BUSY; fp@1200: fp@1200: // found pending request; process it! fp@1921: EC_SLAVE_DBG(request->slave, 1, "Processing register request, " fp@1921: "offset 0x%04x, length %zu...\n", fp@1921: request->offset, request->length); fp@1386: fp@1386: if (request->length > fsm->datagram->mem_size) { fp@1921: EC_MASTER_ERR(master, "Request length (%zu) exceeds maximum " fp@1543: "datagram size (%zu)!\n", request->length, fp@1386: fsm->datagram->mem_size); fp@1386: request->state = EC_INT_REQUEST_FAILURE; fp@1388: wake_up(&master->reg_queue); fp@1386: continue; fp@1386: } fp@1386: fp@1388: fsm->reg_request = request; fp@1200: fp@1200: if (request->dir == EC_DIR_INPUT) { fp@1200: ec_datagram_fprd(fsm->datagram, request->slave->station_address, fp@1200: request->offset, request->length); fp@1225: ec_datagram_zero(fsm->datagram); fp@1200: } else { fp@1200: ec_datagram_fpwr(fsm->datagram, request->slave->station_address, fp@1200: request->offset, request->length); fp@1200: memcpy(fsm->datagram->data, request->data, request->length); fp@1200: } fp@1200: fsm->retries = EC_FSM_RETRIES; fp@1388: fsm->state = ec_fsm_master_state_reg_request; fp@1200: return 1; fp@1200: } fp@1200: fp@1200: return 0; fp@1200: } fp@1200: fp@1200: /*****************************************************************************/ fp@1200: fp@1327: /** Check for pending SDO requests and process one. fp@1335: * fp@1327: * \return non-zero, if an SDO request is processed. fp@646: */ fp@646: int ec_fsm_master_action_process_sdo( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@646: ) fp@646: { fp@646: ec_master_t *master = fsm->master; fp@1000: ec_slave_t *slave; fp@1000: ec_sdo_request_t *req; fp@646: fp@858: // search for internal requests to be processed fp@1000: for (slave = master->slaves; fp@1000: slave < master->slaves + master->slave_count; fp@1000: slave++) { fp@858: if (!slave->config) fp@858: continue; fp@858: list_for_each_entry(req, &slave->config->sdo_requests, list) { fp@1209: if (req->state == EC_INT_REQUEST_QUEUED) { fp@880: fp@880: if (ec_sdo_request_timed_out(req)) { fp@1209: req->state = EC_INT_REQUEST_FAILURE; fp@1921: EC_SLAVE_DBG(slave, 1, "Internal SDO request" fp@1921: " timed out.\n"); fp@880: continue; fp@880: } fp@858: fp@987: if (slave->current_state == EC_SLAVE_STATE_INIT) { fp@1209: req->state = EC_INT_REQUEST_FAILURE; fp@858: continue; fp@858: } fp@858: fp@1209: req->state = EC_INT_REQUEST_BUSY; fp@1921: EC_SLAVE_DBG(slave, 1, "Processing internal" fp@1921: " SDO request...\n"); fp@858: fsm->idle = 0; fp@858: fsm->sdo_request = req; fp@858: fsm->slave = slave; fp@858: fsm->state = ec_fsm_master_state_sdo_request; fp@859: ec_fsm_coe_transfer(&fsm->fsm_coe, slave, req); fp@858: ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately fp@858: return 1; fp@858: } fp@858: } fp@858: } fp@646: return 0; fp@646: } fp@646: martin@1597: martin@1597: /*****************************************************************************/ martin@1597: martin@1597: /** Master action: IDLE. martin@1597: * martin@1597: * Does secondary work. martin@1597: */ martin@1597: void ec_fsm_master_action_idle( fp@1335: ec_fsm_master_t *fsm /**< Master state machine. */ fp@1335: ) fp@1335: { fp@1335: ec_master_t *master = fsm->master; fp@1335: ec_slave_t *slave; martin@1597: martin@1597: // Check for pending internal SDO requests fp@646: if (ec_fsm_master_action_process_sdo(fsm)) fp@646: return; fp@646: fp@1831: // enable processing of requests fp@1804: for (slave = master->slaves; fp@1804: slave < master->slaves + master->slave_count; fp@1804: slave++) { fp@1804: ec_fsm_slave_ready(&slave->fsm); fp@1804: } fp@1804: fp@1804: // check, if slaves have an SDO dictionary to read out. fp@1000: for (slave = master->slaves; fp@1000: slave < master->slaves + master->slave_count; fp@1000: slave++) { fp@910: if (!(slave->sii.mailbox_protocols & EC_MBOX_COE) fp@1219: || (slave->sii.has_general fp@1219: && !slave->sii.coe_details.enable_sdo_info) fp@442: || slave->sdo_dictionary_fetched fp@442: || slave->current_state == EC_SLAVE_STATE_INIT fp@1219: || slave->current_state == EC_SLAVE_STATE_UNKNOWN fp@442: || jiffies - slave->jiffies_preop < EC_WAIT_SDO_DICT * HZ fp@987: ) continue; fp@442: fp@1921: EC_SLAVE_DBG(slave, 1, "Fetching SDO dictionary.\n"); fp@442: fp@910: slave->sdo_dictionary_fetched = 1; fp@910: fp@1327: // start fetching SDO dictionary fp@910: fsm->idle = 0; fp@910: fsm->slave = slave; fp@910: fsm->state = ec_fsm_master_state_sdo_dictionary; fp@910: ec_fsm_coe_dictionary(&fsm->fsm_coe, slave); fp@910: ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately fp@910: return; fp@910: } fp@910: fp@910: // check for pending SII write operations. fp@910: if (ec_fsm_master_action_process_sii(fsm)) fp@910: return; // SII write request found fp@304: fp@1388: // check for pending register requests. fp@1388: if (ec_fsm_master_action_process_register(fsm)) fp@1388: return; // register request processing fp@1200: fp@1031: ec_fsm_master_restart(fsm); fp@260: } fp@260: fp@260: /*****************************************************************************/ fp@260: fp@907: /** Master action: Get state of next slave. fp@907: */ fp@907: void ec_fsm_master_action_next_slave_state( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@907: ) fp@260: { fp@260: ec_master_t *master = fsm->master; fp@260: fp@304: // is there another slave to query? fp@1000: fsm->slave++; fp@1000: if (fsm->slave < master->slaves + master->slave_count) { fp@907: // fetch state from next slave fp@650: fsm->idle = 1; fp@1000: ec_datagram_fprd(fsm->datagram, fp@1000: fsm->slave->station_address, 0x0130, 2); fp@1225: ec_datagram_zero(fsm->datagram); fp@505: fsm->retries = EC_FSM_RETRIES; fp@907: fsm->state = ec_fsm_master_state_read_state; fp@907: return; fp@907: } fp@907: fp@907: // all slaves processed fp@907: ec_fsm_master_action_idle(fsm); fp@907: } fp@907: fp@907: /*****************************************************************************/ fp@907: fp@907: /** Master action: Configure. fp@907: */ fp@907: void ec_fsm_master_action_configure( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@907: ) fp@907: { fp@907: ec_master_t *master = fsm->master; fp@907: ec_slave_t *slave = fsm->slave; fp@907: fp@907: // Does the slave have to be configured? fp@987: if ((slave->current_state != slave->requested_state fp@987: || slave->force_config) && !slave->error_flag) { fp@1177: fp@907: // Start slave configuration, if it is allowed. fp@907: down(&master->config_sem); fp@907: if (!master->allow_config) { fp@907: up(&master->config_sem); fp@907: } else { fp@907: master->config_busy = 1; fp@907: up(&master->config_sem); fp@907: fp@907: if (master->debug_level) { fp@908: char old_state[EC_STATE_STRING_SIZE], fp@908: new_state[EC_STATE_STRING_SIZE]; fp@1337: ec_state_string(slave->current_state, old_state, 0); fp@1337: ec_state_string(slave->requested_state, new_state, 0); fp@1921: EC_SLAVE_DBG(slave, 1, "Changing state from %s to %s%s.\n", fp@1921: old_state, new_state, fp@908: slave->force_config ? " (forced)" : ""); fp@907: } fp@907: fp@907: fsm->idle = 0; fp@907: fsm->state = ec_fsm_master_state_configure_slave; fp@907: ec_fsm_slave_config_start(&fsm->fsm_slave_config, slave); fp@907: fsm->state(fsm); // execute immediately fp@907: return; fp@907: } fp@907: } fp@907: fp@907: // slave has error flag set; process next one fp@907: ec_fsm_master_action_next_slave_state(fsm); fp@907: } fp@907: fp@907: /*****************************************************************************/ fp@907: fp@987: /** Master state: READ STATE. fp@987: * fp@987: * Fetches the AL state of a slave. fp@987: */ fp@987: void ec_fsm_master_state_read_state( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@907: ) fp@907: { fp@907: ec_slave_t *slave = fsm->slave; fp@987: ec_datagram_t *datagram = fsm->datagram; fp@987: fp@987: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@987: return; fp@987: fp@987: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1921: EC_SLAVE_ERR(slave, "Failed to receive AL state datagram: "); fp@1822: ec_datagram_print_state(datagram); fp@1031: ec_fsm_master_restart(fsm); fp@987: return; fp@987: } fp@987: fp@987: // did the slave not respond to its station address? fp@987: if (datagram->working_counter != 1) { fp@987: if (!slave->error_flag) { fp@987: slave->error_flag = 1; fp@1921: EC_SLAVE_DBG(slave, 1, "Slave did not respond to state query.\n"); fp@987: } fp@1961: fsm->rescan_required = 1; fp@1031: ec_fsm_master_restart(fsm); fp@987: return; fp@987: } fp@987: fp@987: // A single slave responded fp@987: ec_slave_set_state(slave, EC_READ_U8(datagram->data)); fp@907: fp@907: if (!slave->error_flag) { fp@907: // Check, if new slave state has to be acknowledged fp@907: if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) { fp@907: fsm->idle = 0; fp@907: fsm->state = ec_fsm_master_state_acknowledge; fp@907: ec_fsm_change_ack(&fsm->fsm_change, slave); fp@907: fsm->state(fsm); // execute immediately fp@907: return; fp@907: } fp@907: fp@907: // No acknowlegde necessary; check for configuration fp@907: ec_fsm_master_action_configure(fsm); fp@907: return; fp@907: } fp@907: fp@907: // slave has error flag set; process next one fp@907: ec_fsm_master_action_next_slave_state(fsm); fp@907: } fp@907: fp@907: /*****************************************************************************/ fp@907: fp@907: /** Master state: ACKNOWLEDGE. fp@907: */ fp@907: void ec_fsm_master_state_acknowledge( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@907: ) fp@454: { fp@454: ec_slave_t *slave = fsm->slave; fp@454: fp@907: if (ec_fsm_change_exec(&fsm->fsm_change)) fp@907: return; fp@454: fp@454: if (!ec_fsm_change_success(&fsm->fsm_change)) { fp@454: fsm->slave->error_flag = 1; fp@1921: EC_SLAVE_ERR(slave, "Failed to acknowledge state change.\n"); fp@907: } fp@907: fp@907: ec_fsm_master_action_configure(fsm); fp@907: } fp@907: fp@907: /*****************************************************************************/ fp@907: fp@907: /** Master state: CLEAR ADDRESSES. fp@907: */ fp@717: void ec_fsm_master_state_clear_addresses( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@717: ) fp@717: { fp@717: ec_master_t *master = fsm->master; fp@717: ec_datagram_t *datagram = fsm->datagram; fp@717: fp@717: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@717: return; fp@717: fp@717: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1921: EC_MASTER_ERR(master, "Failed to receive address" fp@1921: " clearing datagram: "); fp@1921: ec_datagram_print_state(datagram); fp@900: master->scan_busy = 0; fp@794: wake_up_interruptible(&master->scan_queue); fp@1031: ec_fsm_master_restart(fsm); fp@717: return; fp@717: } fp@717: fp@717: if (datagram->working_counter != master->slave_count) { fp@1921: EC_MASTER_WARN(master, "Failed to clear all station addresses:" fp@1921: " Cleared %u of %u", fp@717: datagram->working_counter, master->slave_count); fp@717: } fp@717: fp@1921: EC_MASTER_DBG(master, 1, "Sending broadcast-write" fp@1921: " to measure transmission delays.\n"); fp@1420: fp@1420: ec_datagram_bwr(datagram, 0x0900, 1); fp@1420: ec_datagram_zero(datagram); fp@1420: fsm->retries = EC_FSM_RETRIES; fp@1420: fsm->state = ec_fsm_master_state_dc_measure_delays; fp@1420: } fp@1420: fp@1420: /*****************************************************************************/ fp@1420: fp@1420: /** Master state: DC MEASURE DELAYS. fp@1420: */ fp@1420: void ec_fsm_master_state_dc_measure_delays( fp@1420: ec_fsm_master_t *fsm /**< Master state machine. */ fp@1420: ) fp@1420: { fp@1420: ec_master_t *master = fsm->master; fp@1420: ec_datagram_t *datagram = fsm->datagram; fp@1420: fp@1420: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@1420: return; fp@1420: fp@1420: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1921: EC_MASTER_ERR(master, "Failed to receive delay measuring datagram: "); fp@1921: ec_datagram_print_state(datagram); fp@1420: master->scan_busy = 0; fp@1420: wake_up_interruptible(&master->scan_queue); fp@1420: ec_fsm_master_restart(fsm); fp@1420: return; fp@1420: } fp@1420: fp@1921: EC_MASTER_DBG(master, 1, "%u slaves responded to delay measuring.\n", fp@1921: datagram->working_counter); fp@1921: fp@1921: EC_MASTER_INFO(master, "Scanning bus.\n"); fp@717: fp@717: // begin scanning of slaves fp@1000: fsm->slave = master->slaves; fp@907: fsm->state = ec_fsm_master_state_scan_slave; fp@830: ec_fsm_slave_scan_start(&fsm->fsm_slave_scan, fsm->slave); fp@830: ec_fsm_slave_scan_exec(&fsm->fsm_slave_scan); // execute immediately fp@717: } fp@717: fp@717: /*****************************************************************************/ fp@717: fp@907: /** Master state: SCAN SLAVE. fp@907: * fp@652: * Executes the sub-statemachine for the scanning of a slave. fp@652: */ fp@907: void ec_fsm_master_state_scan_slave( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@652: ) fp@238: { fp@238: ec_master_t *master = fsm->master; fp@1335: #ifdef EC_EOE fp@637: ec_slave_t *slave = fsm->slave; fp@1335: #endif fp@907: if (ec_fsm_slave_scan_exec(&fsm->fsm_slave_scan)) fp@528: return; fp@325: fp@715: #ifdef EC_EOE fp@834: if (slave->sii.mailbox_protocols & EC_MBOX_EOE) { fp@661: // create EoE handler for this slave fp@661: ec_eoe_t *eoe; fp@661: if (!(eoe = kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) { fp@1921: EC_SLAVE_ERR(slave, "Failed to allocate EoE handler memory!\n"); fp@900: } else if (ec_eoe_init(eoe, slave)) { fp@1921: EC_SLAVE_ERR(slave, "Failed to init EoE handler!\n"); fp@661: kfree(eoe); fp@900: } else { fp@661: list_add_tail(&eoe->list, &master->eoe_handlers); fp@661: } fp@661: } fp@715: #endif fp@661: fp@325: // another slave to fetch? fp@1000: fsm->slave++; fp@1002: if (fsm->slave < master->slaves + master->slave_count) { fp@830: ec_fsm_slave_scan_start(&fsm->fsm_slave_scan, fsm->slave); fp@830: ec_fsm_slave_scan_exec(&fsm->fsm_slave_scan); // execute immediately fp@325: return; fp@325: } fp@325: fp@1931: EC_MASTER_INFO(master, "Bus scanning completed in %lu ms.\n", fp@1931: (jiffies - fsm->scan_jiffies) * 1000 / HZ); fp@661: fp@900: master->scan_busy = 0; fp@900: wake_up_interruptible(&master->scan_queue); fp@900: fp@1425: ec_master_calc_dc(master); fp@1507: fp@792: // Attach slave configurations fp@792: ec_master_attach_slave_configs(master); fp@792: fp@716: #ifdef EC_EOE fp@661: // check if EoE processing has to be started fp@661: ec_master_eoe_start(master); fp@715: #endif fp@661: fp@1925: if (master->slave_count) { fp@1925: fsm->slave = master->slaves; // begin with first slave fp@1925: ec_fsm_master_enter_write_system_times(fsm); fp@1925: } else { fp@1925: ec_fsm_master_restart(fsm); fp@1925: } fp@238: } fp@238: fp@238: /*****************************************************************************/ fp@238: fp@907: /** Master state: CONFIGURE SLAVE. fp@907: * fp@907: * Starts configuring a slave. fp@907: */ fp@907: void ec_fsm_master_state_configure_slave( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@907: ) fp@907: { fp@907: ec_master_t *master = fsm->master; fp@907: fp@907: if (ec_fsm_slave_config_exec(&fsm->fsm_slave_config)) fp@907: return; fp@907: fp@1277: fsm->slave->force_config = 0; fp@1277: fp@907: // configuration finished fp@907: master->config_busy = 0; fp@907: wake_up_interruptible(&master->config_queue); fp@830: fp@900: if (!ec_fsm_slave_config_success(&fsm->fsm_slave_config)) { fp@900: // TODO: mark slave_config as failed. fp@900: } fp@656: fp@907: fsm->idle = 1; fp@907: ec_fsm_master_action_next_slave_state(fsm); fp@907: } fp@907: fp@907: /*****************************************************************************/ fp@907: fp@1925: /** Start writing DC system times. fp@1925: */ fp@1925: void ec_fsm_master_enter_write_system_times( fp@1925: ec_fsm_master_t *fsm /**< Master state machine. */ fp@1925: ) fp@1925: { fp@1925: ec_master_t *master = fsm->master; fp@1925: fp@1925: EC_MASTER_DBG(master, 1, "Writing system time offsets...\n"); fp@1925: fp@1925: if (master->has_app_time) { fp@1925: while (fsm->slave < master->slaves + master->slave_count) { fp@1925: if (!fsm->slave->base_dc_supported fp@1925: || !fsm->slave->has_dc_system_time) { fp@1925: fsm->slave++; fp@1925: continue; fp@1925: } fp@1925: fp@1925: // read DC system time (0x0910, 64 bit) fp@1925: // gap (64 bit) fp@1925: // and time offset (0x0920, 64 bit) fp@1925: ec_datagram_fprd(fsm->datagram, fsm->slave->station_address, fp@1925: 0x0910, 24); fp@1925: fsm->retries = EC_FSM_RETRIES; fp@1925: fsm->state = ec_fsm_master_state_dc_read_offset; fp@1925: return; fp@1925: } fp@1925: } else { fp@1925: EC_MASTER_DBG(master, 1, "No app_time received up to now.\n"); fp@1925: } fp@1925: fp@1925: ec_master_request_op(master); fp@1925: ec_fsm_master_restart(fsm); fp@1925: } fp@1925: fp@1925: /*****************************************************************************/ fp@1925: fp@1925: /** Configure 32 bit time offset. fp@1925: */ fp@1925: u64 ec_fsm_master_dc_offset32( fp@1925: ec_fsm_master_t *fsm, /**< Master state machine. */ fp@1925: u64 system_time, /**< System time register. */ fp@1925: u64 old_offset, /**< Time offset register. */ martin@1989: u64 correction /**< Correction. */ fp@1925: ) fp@1925: { fp@1925: ec_slave_t *slave = fsm->slave; martin@1989: u32 correction32, system_time32, old_offset32, new_offset; fp@1925: s32 time_diff; fp@1925: martin@1989: system_time32 = (u32) system_time; martin@1989: // correct read system time by elapsed time between read operation martin@1989: // and app_time set time martin@1989: correction32 = (u32)correction; martin@1989: system_time32 -= correction32; martin@1989: old_offset32 = (u32) old_offset; martin@1989: ch1010277@1999: time_diff = (u32) slave->master->app_start_time - system_time32; fp@1925: fp@1925: EC_SLAVE_DBG(slave, 1, "DC system time offset calculation:" fp@1925: " system_time=%u (corrected with %u)," ch1010277@1999: " app_start_time=%llu, diff=%i\n", martin@1989: system_time32, correction32, ch1010277@1999: slave->master->app_start_time, time_diff); fp@1925: fp@1925: if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) { fp@1925: new_offset = time_diff + old_offset32; fp@1925: EC_SLAVE_DBG(slave, 1, "Setting time offset to %u (was %u)\n", fp@1925: new_offset, old_offset32); fp@1925: return (u64) new_offset; fp@1925: } else { fp@1925: EC_SLAVE_DBG(slave, 1, "Not touching time offset.\n"); fp@1925: return old_offset; fp@1925: } fp@1925: } fp@1925: fp@1925: /*****************************************************************************/ fp@1925: fp@1925: /** Configure 64 bit time offset. fp@1925: */ fp@1925: u64 ec_fsm_master_dc_offset64( fp@1925: ec_fsm_master_t *fsm, /**< Master state machine. */ fp@1925: u64 system_time, /**< System time register. */ fp@1925: u64 old_offset, /**< Time offset register. */ martin@1989: u64 correction /**< Correction. */ fp@1925: ) fp@1925: { fp@1925: ec_slave_t *slave = fsm->slave; martin@1989: u64 new_offset; fp@1925: s64 time_diff; fp@1925: martin@1989: // correct read system time by elapsed time between read operation martin@1989: // and app_time set time martin@1989: system_time -= correction; ch1010277@1999: time_diff = fsm->slave->master->app_start_time - system_time; fp@1925: fp@1925: EC_SLAVE_DBG(slave, 1, "DC system time offset calculation:" fp@1925: " system_time=%llu (corrected with %llu)," ch1010277@1999: " app_start_time=%llu, diff=%lli\n", fp@1925: system_time, correction, ch1010277@1999: slave->master->app_start_time, time_diff); fp@1925: fp@1925: if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) { fp@1925: new_offset = time_diff + old_offset; fp@1925: EC_SLAVE_DBG(slave, 1, "Setting time offset to %llu (was %llu)\n", fp@1925: new_offset, old_offset); fp@1925: } else { fp@1925: new_offset = old_offset; fp@1925: EC_SLAVE_DBG(slave, 1, "Not touching time offset.\n"); fp@1925: } fp@1925: fp@1925: return new_offset; fp@1925: } fp@1925: fp@1925: /*****************************************************************************/ fp@1925: fp@1925: /** Master state: DC READ OFFSET. fp@1925: */ fp@1925: void ec_fsm_master_state_dc_read_offset( fp@1925: ec_fsm_master_t *fsm /**< Master state machine. */ fp@1925: ) fp@1925: { fp@1925: ec_datagram_t *datagram = fsm->datagram; fp@1925: ec_slave_t *slave = fsm->slave; martin@1989: u64 system_time, old_offset, new_offset, correction; fp@1925: fp@1925: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@1925: return; fp@1925: fp@1925: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1925: EC_SLAVE_ERR(slave, "Failed to receive DC times datagram: "); fp@1925: ec_datagram_print_state(datagram); fp@1925: fsm->slave++; fp@1925: ec_fsm_master_enter_write_system_times(fsm); fp@1925: return; fp@1925: } fp@1925: fp@1925: if (datagram->working_counter != 1) { fp@1925: EC_SLAVE_WARN(slave, "Failed to get DC times: "); fp@1925: ec_datagram_print_wc_error(datagram); fp@1925: fsm->slave++; fp@1925: ec_fsm_master_enter_write_system_times(fsm); fp@1925: return; fp@1925: } fp@1925: fp@1925: system_time = EC_READ_U64(datagram->data); // 0x0910 fp@1925: old_offset = EC_READ_U64(datagram->data + 16); // 0x0920 martin@1989: /* correct read system time by elapsed time since read operation martin@1989: and the app_time set time */ martin@1989: #ifdef EC_HAVE_CYCLES martin@1989: correction = martin@1989: (datagram->cycles_sent - slave->master->dc_cycles_app_time) martin@1989: * 1000000LL; martin@1989: do_div(correction,cpu_khz); martin@1989: #else martin@1989: correction = martin@1989: (u64) ((datagram->jiffies_sent-slave->master->dc_jiffies_app_time) * 1000 / HZ) martin@1989: * 1000000; martin@1989: #endif fp@1925: fp@1925: if (slave->base_dc_range == EC_DC_32) { fp@1925: new_offset = ec_fsm_master_dc_offset32(fsm, martin@1989: system_time, old_offset, correction); fp@1925: } else { fp@1925: new_offset = ec_fsm_master_dc_offset64(fsm, martin@1989: system_time, old_offset, correction); fp@1925: } fp@1925: fp@1925: // set DC system time offset and transmission delay fp@1925: ec_datagram_fpwr(datagram, slave->station_address, 0x0920, 12); fp@1925: EC_WRITE_U64(datagram->data, new_offset); fp@1925: EC_WRITE_U32(datagram->data + 8, slave->transmission_delay); fp@1925: fsm->retries = EC_FSM_RETRIES; fp@1925: fsm->state = ec_fsm_master_state_dc_write_offset; fp@1925: } fp@1925: fp@1925: /*****************************************************************************/ fp@1925: fp@1925: /** Master state: DC WRITE OFFSET. fp@1925: */ fp@1925: void ec_fsm_master_state_dc_write_offset( fp@1925: ec_fsm_master_t *fsm /**< Master state machine. */ fp@1925: ) fp@1925: { fp@1925: ec_datagram_t *datagram = fsm->datagram; fp@1925: ec_slave_t *slave = fsm->slave; fp@1925: fp@1925: if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) fp@1925: return; fp@1925: fp@1925: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1925: EC_SLAVE_ERR(slave, fp@1925: "Failed to receive DC system time offset datagram: "); fp@1925: ec_datagram_print_state(datagram); fp@1925: fsm->slave++; fp@1925: ec_fsm_master_enter_write_system_times(fsm); fp@1925: return; fp@1925: } fp@1925: fp@1925: if (datagram->working_counter != 1) { fp@1925: EC_SLAVE_ERR(slave, "Failed to set DC system time offset: "); fp@1925: ec_datagram_print_wc_error(datagram); fp@1925: fsm->slave++; fp@1925: ec_fsm_master_enter_write_system_times(fsm); fp@1925: return; fp@1925: } fp@1925: fp@1925: fsm->slave++; fp@1925: ec_fsm_master_enter_write_system_times(fsm); fp@1925: } fp@1925: fp@1925: /*****************************************************************************/ fp@1925: fp@907: /** Master state: WRITE SII. fp@907: */ fp@872: void ec_fsm_master_state_write_sii( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@907: ) fp@269: { fp@601: ec_master_t *master = fsm->master; fp@872: ec_sii_write_request_t *request = fsm->sii_request; fp@601: ec_slave_t *slave = request->slave; fp@269: fp@435: if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; fp@433: fp@433: if (!ec_fsm_sii_success(&fsm->fsm_sii)) { fp@1921: EC_SLAVE_ERR(slave, "Failed to write SII data.\n"); fp@1209: request->state = EC_INT_REQUEST_FAILURE; fp@872: wake_up(&master->sii_queue); fp@1031: ec_fsm_master_restart(fsm); fp@872: return; fp@872: } fp@872: fp@872: fsm->sii_index++; fp@979: if (fsm->sii_index < request->nwords) { fp@601: ec_fsm_sii_write(&fsm->fsm_sii, slave, fp@979: request->offset + fsm->sii_index, fp@979: request->words + fsm->sii_index, fp@815: EC_FSM_SII_USE_CONFIGURED_ADDRESS); fp@433: ec_fsm_sii_exec(&fsm->fsm_sii); // execute immediately fp@269: return; fp@269: } fp@269: fp@872: // finished writing SII fp@1921: EC_SLAVE_DBG(slave, 1, "Finished writing %zu words of SII data.\n", fp@1921: request->nwords); fp@1079: fp@1079: if (request->offset <= 4 && request->offset + request->nwords > 4) { fp@1079: // alias was written fp@1079: slave->sii.alias = EC_READ_U16(request->words + 4); martin@1579: // TODO: read alias from register 0x0012 fp@1909: slave->effective_alias = slave->sii.alias; fp@1079: } fp@1079: // TODO: Evaluate other SII contents! fp@1335: fp@1209: request->state = EC_INT_REQUEST_SUCCESS; fp@872: wake_up(&master->sii_queue); fp@872: fp@872: // check for another SII write request fp@872: if (ec_fsm_master_action_process_sii(fsm)) fp@601: return; // processing another request fp@601: fp@1031: ec_fsm_master_restart(fsm); fp@419: } fp@419: fp@419: /*****************************************************************************/ fp@419: fp@907: /** Master state: SDO DICTIONARY. fp@907: */ fp@905: void ec_fsm_master_state_sdo_dictionary( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@905: ) fp@419: { fp@419: ec_slave_t *slave = fsm->slave; fp@419: ec_master_t *master = fsm->master; fp@419: fp@436: if (ec_fsm_coe_exec(&fsm->fsm_coe)) return; fp@436: fp@436: if (!ec_fsm_coe_success(&fsm->fsm_coe)) { fp@1031: ec_fsm_master_restart(fsm); fp@419: return; fp@419: } fp@419: fp@1327: // SDO dictionary fetching finished fp@419: fp@419: if (master->debug_level) { fp@423: unsigned int sdo_count, entry_count; fp@423: ec_slave_sdo_dict_info(slave, &sdo_count, &entry_count); fp@1921: EC_SLAVE_DBG(slave, 1, "Fetched %u SDOs and %u entries.\n", fp@1921: sdo_count, entry_count); fp@419: } fp@419: fp@1186: // attach pdo names from dictionary fp@1186: ec_slave_attach_pdo_names(slave); fp@1186: fp@1031: ec_fsm_master_restart(fsm); fp@269: } fp@269: fp@430: /*****************************************************************************/ fp@430: fp@907: /** Master state: SDO REQUEST. fp@907: */ fp@907: void ec_fsm_master_state_sdo_request( fp@907: ec_fsm_master_t *fsm /**< Master state machine. */ fp@907: ) fp@430: { fp@858: ec_sdo_request_t *request = fsm->sdo_request; fp@436: fp@436: if (ec_fsm_coe_exec(&fsm->fsm_coe)) return; fp@436: fp@436: if (!ec_fsm_coe_success(&fsm->fsm_coe)) { fp@1921: EC_SLAVE_DBG(fsm->slave, 1, fp@1921: "Failed to process internal SDO request.\n"); fp@1209: request->state = EC_INT_REQUEST_FAILURE; martin@1596: wake_up(&fsm->slave->sdo_queue); fp@1031: ec_fsm_master_restart(fsm); fp@646: return; fp@646: } fp@646: fp@1335: // SDO request finished fp@1209: request->state = EC_INT_REQUEST_SUCCESS; martin@1596: wake_up(&fsm->slave->sdo_queue); fp@646: fp@1921: EC_SLAVE_DBG(fsm->slave, 1, "Finished internal SDO request.\n"); fp@646: fp@1327: // check for another SDO request fp@646: if (ec_fsm_master_action_process_sdo(fsm)) fp@646: return; // processing another request fp@430: fp@1031: ec_fsm_master_restart(fsm); fp@1031: } fp@1031: fp@1031: /*****************************************************************************/ fp@1200: fp@1388: /** Master state: REG REQUEST. fp@1388: */ fp@1388: void ec_fsm_master_state_reg_request( fp@1200: ec_fsm_master_t *fsm /**< Master state machine. */ fp@1200: ) fp@1200: { fp@1200: ec_master_t *master = fsm->master; fp@1200: ec_datagram_t *datagram = fsm->datagram; fp@1388: ec_reg_request_t *request = fsm->reg_request; fp@1200: fp@1200: if (datagram->state != EC_DATAGRAM_RECEIVED) { fp@1921: EC_MASTER_ERR(master, "Failed to receive register" fp@1921: " request datagram: "); fp@1921: ec_datagram_print_state(datagram); fp@1209: request->state = EC_INT_REQUEST_FAILURE; fp@1388: wake_up(&master->reg_queue); fp@1200: ec_fsm_master_restart(fsm); fp@1200: return; fp@1200: } martin@1579: fp@1385: if (datagram->working_counter == 1) { fp@1385: if (request->dir == EC_DIR_INPUT) { // read request fp@1385: if (request->data) fp@1385: kfree(request->data); fp@1385: request->data = kmalloc(request->length, GFP_KERNEL); fp@1385: if (!request->data) { fp@1921: EC_MASTER_ERR(master, "Failed to allocate %zu bytes" fp@1921: " of memory for register data.\n", request->length); fp@1385: request->state = EC_INT_REQUEST_FAILURE; fp@1388: wake_up(&master->reg_queue); fp@1385: ec_fsm_master_restart(fsm); fp@1385: return; fp@1385: } fp@1385: memcpy(request->data, datagram->data, request->length); fp@1200: } fp@1385: fp@1385: request->state = EC_INT_REQUEST_SUCCESS; fp@1927: EC_SLAVE_DBG(request->slave, 1, "Register request successful.\n"); fp@1385: } else { fp@1385: request->state = EC_INT_REQUEST_FAILURE; fp@1921: EC_MASTER_ERR(master, "Register request failed.\n"); fp@1385: } fp@1385: fp@1388: wake_up(&master->reg_queue); fp@1388: fp@1388: // check for another register request fp@1388: if (ec_fsm_master_action_process_register(fsm)) fp@1200: return; // processing another request fp@1200: fp@1200: ec_fsm_master_restart(fsm); fp@1200: } fp@1200: fp@1200: /*****************************************************************************/