From 5ae68fa1db8bcda99397c103ea38f07d7e8e0c2e Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Tue, 24 Oct 2006 15:14:25 +0000 Subject: [PATCH] SDO uploading via Sysfs without master FSM calling wake_up(). --- master/canopen.c | 25 +++++++++++++++++++------ master/fsm.c | 42 ++++++++++++++++++++---------------------- master/master.c | 41 +++++++++++++++++++++++++++++++---------- master/master.h | 9 ++++++--- 4 files changed, 76 insertions(+), 41 deletions(-) diff --git a/master/canopen.c b/master/canopen.c index 70932679..6c726c22 100644 --- a/master/canopen.c +++ b/master/canopen.c @@ -295,18 +295,31 @@ ssize_t ec_sdo_entry_read_value(ec_sdo_entry_t *entry, /**< SDO entry */ off_t off = 0; ec_sdo_request_t request; - ec_sdo_request_init_read(&request, sdo, entry); - list_add_tail(&request.queue, &master->sdo_requests); - if (wait_event_interruptible(master->sdo_wait_queue, - request.return_code)) { + if (down_interruptible(&master->sdo_sem)) { // interrupted by signal - list_del_init(&request.queue); + return -ERESTARTSYS; } + ec_sdo_request_init_read(&request, sdo, entry); + + // this is necessary, because the completion object + // is completed by the ec_master_flush_sdo_requests() function. + INIT_COMPLETION(master->sdo_complete); + + master->sdo_request = &request; + master->sdo_seq_user++; + master->sdo_timer.expires = jiffies + 10; + add_timer(&master->sdo_timer); + + wait_for_completion(&master->sdo_complete); + + master->sdo_request = NULL; + up(&master->sdo_sem); + if (request.return_code == 1 && request.data) { off += ec_sdo_entry_format_data(entry, &request, buffer); } - else if (request.return_code < 0) { + else { off = -EINVAL; } diff --git a/master/fsm.c b/master/fsm.c index daedf2e7..24cdf6c9 100644 --- a/master/fsm.c +++ b/master/fsm.c @@ -523,7 +523,6 @@ void ec_fsm_master_action_process_states(ec_fsm_t *fsm ec_master_t *master = fsm->master; ec_slave_t *slave; char old_state[EC_STATE_STRING_SIZE], new_state[EC_STATE_STRING_SIZE]; - ec_sdo_request_t *request, *next_request; // check if any slaves are not in the state, they're supposed to be list_for_each_entry(slave, &master->slaves, list) { @@ -558,29 +557,28 @@ void ec_fsm_master_action_process_states(ec_fsm_t *fsm // Check, if EoE processing has to be started ec_master_eoe_start(master); - // check, if there are pending SDO requests - list_for_each_entry_safe(request, next_request, - &master->sdo_requests, queue) { - // TODO: critical section! - list_del_init(&request->queue); - - slave = request->sdo->slave; - + // Check for a pending SDO request + if (master->sdo_seq_master != master->sdo_seq_user) { + if (master->debug_level) + EC_DBG("Processing SDO request...\n"); + slave = master->sdo_request->sdo->slave; if (slave->current_state == EC_SLAVE_STATE_INIT || !slave->online || slave->error_flag) { - request->return_code = -1; - wake_up_interruptible(&master->sdo_wait_queue); - continue; + EC_ERR("Failed to process SDO request, slave %i not ready.\n", + slave->ring_position); + master->sdo_request->return_code = -1; + master->sdo_seq_master++; + } + else { + // start uploading SDO + fsm->slave = slave; + fsm->master_state = ec_fsm_master_sdo_request; + fsm->sdo_request = master->sdo_request; + ec_fsm_coe_upload(&fsm->fsm_coe, slave, fsm->sdo_request); + ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately + return; } - - // start uploading SDO - fsm->slave = slave; - fsm->master_state = ec_fsm_master_sdo_request; - fsm->sdo_request = request; - ec_fsm_coe_upload(&fsm->fsm_coe, slave, request); - ec_fsm_coe_exec(&fsm->fsm_coe); // execute immediately - return; } // check, if slaves have an SDO dictionary to read out. @@ -1034,7 +1032,7 @@ void ec_fsm_master_sdo_request(ec_fsm_t *fsm /**< finite state machine */) if (!ec_fsm_coe_success(&fsm->fsm_coe)) { request->return_code = -1; - wake_up_interruptible(&master->sdo_wait_queue); + master->sdo_seq_master++; fsm->master_state = ec_fsm_master_start; fsm->master_state(fsm); // execute immediately return; @@ -1043,7 +1041,7 @@ void ec_fsm_master_sdo_request(ec_fsm_t *fsm /**< finite state machine */) // SDO dictionary fetching finished request->return_code = 1; - wake_up_interruptible(&master->sdo_wait_queue); + master->sdo_seq_master++; // restart master state machine. fsm->master_state = ec_fsm_master_start; diff --git a/master/master.c b/master/master.c index f91dbc74..493b0a13 100644 --- a/master/master.c +++ b/master/master.c @@ -58,6 +58,7 @@ void ec_master_clear(struct kobject *); void ec_master_sync_io(ec_master_t *); void ec_master_idle_run(void *); void ec_master_eoe_run(unsigned long); +void ec_master_check_sdo(unsigned long); 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); @@ -130,8 +131,11 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */ master->idle_cycle_time_pos = 0; master->eoe_cycle_time_pos = 0; master->debug_level = 0; - INIT_LIST_HEAD(&master->sdo_requests); - init_waitqueue_head(&master->sdo_wait_queue); + init_MUTEX(&master->sdo_sem); + init_timer(&master->sdo_timer); + master->sdo_timer.function = ec_master_check_sdo; + master->sdo_timer.data = (unsigned long) master; + init_completion(&master->sdo_complete); // create workqueue if (!(master->workqueue = create_singlethread_workqueue("EtherCAT"))) { @@ -301,14 +305,11 @@ void ec_master_clear_slaves(ec_master_t *master) void ec_master_flush_sdo_requests(ec_master_t *master) { - ec_sdo_request_t *req, *next_req; - - list_for_each_entry_safe(req, next_req, &master->sdo_requests, queue) { - list_del_init(&req->queue); - req->return_code = -1; - } - - wake_up_interruptible(&master->sdo_wait_queue); + del_timer_sync(&master->sdo_timer); + complete(&master->sdo_complete); + master->sdo_request = NULL; + master->sdo_seq_user = 0; + master->sdo_seq_master = 0; } /*****************************************************************************/ @@ -1004,6 +1005,7 @@ void ec_master_eoe_stop(ec_master_t *master /**< EtherCAT master */) } /*****************************************************************************/ + /** Does the Ethernet-over-EtherCAT processing. */ @@ -1066,6 +1068,25 @@ void ec_master_eoe_run(unsigned long data /**< master pointer */) /*****************************************************************************/ +/** +*/ + +void ec_master_check_sdo(unsigned long data /**< master pointer */) +{ + ec_master_t *master = (ec_master_t *) data; + + if (master->sdo_seq_master != master->sdo_seq_user) { + master->sdo_timer.expires = jiffies + 10; + add_timer(&master->sdo_timer); + return; + } + + // master has processed the request + complete(&master->sdo_complete); +} + +/*****************************************************************************/ + /** Calculates Advanced Position Adresses. */ diff --git a/master/master.h b/master/master.h index d5d59c4e..6fbbed60 100644 --- a/master/master.h +++ b/master/master.h @@ -44,7 +44,6 @@ #include #include #include -#include #include #include @@ -139,8 +138,12 @@ struct ec_master uint8_t eeprom_write_enable; /**< allow write operations to EEPROMs */ - struct list_head sdo_requests; /**< list of SDO read/write requests */ - wait_queue_head_t sdo_wait_queue; /**< wait queue for SDO access */ + ec_sdo_request_t *sdo_request; /**< pointer to the current SDO request */ + unsigned int sdo_seq_user; /**< sequence number for user space */ + unsigned int sdo_seq_master; /**< sequence number for master */ + struct semaphore sdo_sem; /**< SDO semaphore */ + struct timer_list sdo_timer; /**< timer for polling sdo processing */ + struct completion sdo_complete; /**< SDO request completion object */ }; /*****************************************************************************/