SDO uploading via Sysfs without master FSM calling wake_up().
authorFlorian Pose <fp@igh-essen.com>
Tue, 24 Oct 2006 15:14:25 +0000
changeset 441 ffa13db95e10
parent 440 16fddae16c94
child 442 6607875255d9
SDO uploading via Sysfs without master FSM calling wake_up().
master/canopen.c
master/fsm.c
master/master.c
master/master.h
--- a/master/canopen.c	Tue Oct 24 12:06:59 2006 +0000
+++ b/master/canopen.c	Tue Oct 24 15:14:25 2006 +0000
@@ -295,18 +295,31 @@
     off_t off = 0;
     ec_sdo_request_t request;
 
+    if (down_interruptible(&master->sdo_sem)) {
+        // interrupted by signal
+        return -ERESTARTSYS;
+    }
+
     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)) {
-        // interrupted by signal
-        list_del_init(&request.queue);
-    }
+
+    // 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;
     }
 
--- a/master/fsm.c	Tue Oct 24 12:06:59 2006 +0000
+++ b/master/fsm.c	Tue Oct 24 15:14:25 2006 +0000
@@ -523,7 +523,6 @@
     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 @@
     // 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;
-        }
-
-        // 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;
+            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;
+        }
     }
 
     // check, if slaves have an SDO dictionary to read out.
@@ -1034,7 +1032,7 @@
 
     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 @@
     // 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;
--- a/master/master.c	Tue Oct 24 12:06:59 2006 +0000
+++ b/master/master.c	Tue Oct 24 15:14:25 2006 +0000
@@ -58,6 +58,7 @@
 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 @@
     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_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 @@
 }
 
 /*****************************************************************************/
+
 /**
    Does the Ethernet-over-EtherCAT processing.
 */
@@ -1067,6 +1069,25 @@
 /*****************************************************************************/
 
 /**
+*/
+
+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.
 */
 
--- a/master/master.h	Tue Oct 24 12:06:59 2006 +0000
+++ b/master/master.h	Tue Oct 24 15:14:25 2006 +0000
@@ -44,7 +44,6 @@
 #include <linux/list.h>
 #include <linux/sysfs.h>
 #include <linux/timer.h>
-#include <linux/wait.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
 
@@ -139,8 +138,12 @@
 
     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 */
 };
 
 /*****************************************************************************/