The patch I have is for the latest stable-1.5 tag. To use the patch, put the 
SII information (export using TwinCAT) in 

[FIRMWARE_LOCATION]/ethercat/ec_[VENDOR ID]_[PRODUCT CODE].bin

For my distro, OpenSuSE, the firmware location is 
/lib/firmware/[KERNEL_VERSION], but this can differ between distro's. 

Regards,

Jesper


Op dinsdag 1 november 2011 10:00:04 schreef Graeme Foot:
> Hi,
> 
> Yes, I'm interested in the patch.
> 
> Thanks,
> Graeme.
> 
> 
> -----Original Message-----
> From: [email protected]
> [mailto:[email protected]] On Behalf Of Jesper Smith
> Sent: Friday, 28 October 2011 04:02
> To: [email protected]
> Subject: Re: [etherlab-users] Problem reading SII configuration from
> slave
> 
> Hello,
> 
> Because the supplier of our slaves told us that their SII information
> will
> never fit in the slave (the SII binary is 3kb and the slave only has a
> 2kb
> memory location) and we're stuck with 14 of them I've cleaned up the
> hack to
> read the SII information from a binary file and made it work in
> combination
> with other slaves.  If someone is interested I can make a patch to the
> most
> recent master code.
> 
> I've adjusted the fsm_slave_scan state machine to works as follows
> 
> - Read vendor id + product code from slave
> - Use the kernels firmware_request to load
> ec_${vendor_id}_${product_code}.bin
> /lib/firmware/${uname -r}/ethercat (or whatever path your distribution
> uses)
> 
> If firmware is found,
>         use that to load the SII information
> else
>         read SII information from the slave
> 
> 
> I think this can be used as starting point for reading XML files. I'm
> thinking
> of the following solutions
> 
> - Make a separate user space program that compiles the XML files to SII
> binaries and stores them in /lib/firmware
> - Store the XML file in /lib/firmware and parse it in the master module
> - Create a separate communication between the kernel and user space that
> 
> requests slave information from a daemon/udev.
> 
> Maybe someone on this list can voice their opinion what would be the
> neatest
> way to do it.
> 
> 
> Regards,
> 
> Jesper
diff -rup ethercat-default.orig/master/fsm_master.c ethercat-default/master/fsm_master.c
--- ethercat-default.orig/master/fsm_master.c	2011-10-28 09:34:57.000000000 -0500
+++ ethercat-default/master/fsm_master.c	2011-10-27 10:45:40.000000000 -0500
@@ -100,7 +100,7 @@ void ec_fsm_master_init(
     ec_fsm_slave_config_init(&fsm->fsm_slave_config, fsm->datagram,
             &fsm->fsm_change, &fsm->fsm_coe, &fsm->fsm_pdo);
     ec_fsm_slave_scan_init(&fsm->fsm_slave_scan, fsm->datagram,
-            &fsm->fsm_slave_config, &fsm->fsm_pdo);
+            &fsm->fsm_slave_config, &fsm->fsm_pdo, &fsm->master->class_device);
     ec_fsm_sii_init(&fsm->fsm_sii, fsm->datagram);
 }
 
@@ -332,6 +332,7 @@ int ec_fsm_master_action_process_sii(
         ec_fsm_master_t *fsm /**< Master state machine. */
         )
 {
+
     ec_master_t *master = fsm->master;
     ec_sii_write_request_t *request;
 
diff -rup ethercat-default.orig/master/fsm_slave_scan.c ethercat-default/master/fsm_slave_scan.c
--- ethercat-default.orig/master/fsm_slave_scan.c	2011-10-28 09:34:57.000000000 -0500
+++ ethercat-default/master/fsm_slave_scan.c	2011-10-26 17:56:48.000000000 -0500
@@ -34,6 +34,7 @@
 
 /*****************************************************************************/
 
+#include <linux/firmware.h>
 #include "globals.h"
 #include "master.h"
 #include "mailbox.h"
@@ -50,8 +51,11 @@ void ec_fsm_slave_scan_state_base(ec_fsm
 void ec_fsm_slave_scan_state_dc_cap(ec_fsm_slave_scan_t *);
 void ec_fsm_slave_scan_state_dc_times(ec_fsm_slave_scan_t *);
 void ec_fsm_slave_scan_state_datalink(ec_fsm_slave_scan_t *);
+void ec_fsm_slave_scan_state_sii_device(ec_fsm_slave_scan_t *);
+void ec_fsm_slave_scan_state_sii_request(ec_fsm_slave_scan_t *);
 void ec_fsm_slave_scan_state_sii_size(ec_fsm_slave_scan_t *);
 void ec_fsm_slave_scan_state_sii_data(ec_fsm_slave_scan_t *);
+void ec_fsm_slave_scan_state_sii_parse(ec_fsm_slave_scan_t *);
 #ifdef EC_REGALIAS
 void ec_fsm_slave_scan_state_regalias(ec_fsm_slave_scan_t *);
 #endif
@@ -78,12 +82,18 @@ void ec_fsm_slave_scan_init(
         ec_datagram_t *datagram, /**< Datagram to use. */
         ec_fsm_slave_config_t *fsm_slave_config, /**< Slave configuration
                                                   state machine to use. */
-        ec_fsm_pdo_t *fsm_pdo /**< PDO configuration machine to use. */
+        ec_fsm_pdo_t *fsm_pdo, /**< PDO configuration machine to use. */
+        #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+			struct device **class_device /**< Master class device. */
+		#else
+			struct class_device **class_device /**< Master class device. */
+		#endif
         )
 {
     fsm->datagram = datagram;
     fsm->fsm_slave_config = fsm_slave_config;
     fsm->fsm_pdo = fsm_pdo;
+    fsm->class_device = class_device;
 
     // init sub state machines
     ec_fsm_sii_init(&fsm->fsm_sii, fsm->datagram);
@@ -480,16 +490,142 @@ void ec_fsm_slave_scan_state_datalink(ec
 
     // Start fetching SII size
 
-    fsm->sii_offset = EC_FIRST_SII_CATEGORY_OFFSET; // first category header
-    ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
-            EC_FSM_SII_USE_CONFIGURED_ADDRESS);
-    fsm->state = ec_fsm_slave_scan_state_sii_size;
+    if (slave->vendor_words) {
+		EC_SLAVE_WARN(slave, "Freeing old vendor data...\n");
+		kfree(slave->vendor_words);
+	}
+
+	if (!(slave->vendor_words =
+				(uint16_t *) kmalloc(32, GFP_KERNEL))) {
+		EC_SLAVE_ERR(slave, "Failed to allocate 16 words of SII data.\n");
+		slave->error_flag = 1;
+		fsm->state = ec_fsm_slave_scan_state_error;
+		return;
+	}
+	fsm->sii_offset = 0;
+	 ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
+	            EC_FSM_SII_USE_CONFIGURED_ADDRESS);
+	 fsm->state = ec_fsm_slave_scan_state_sii_device;
+
     fsm->state(fsm); // execute state immediately
 }
 
 /*****************************************************************************/
 
 /**
+ 	 Slave scan state: SII Device
+ */
+
+
+void ec_fsm_slave_scan_state_sii_device(ec_fsm_slave_scan_t *fsm /**< slave state machine */)
+{
+	ec_slave_t *slave = fsm->slave;
+	if (ec_fsm_sii_exec(&fsm->fsm_sii))
+		return;
+
+	if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
+		fsm->slave->error_flag = 1;
+		fsm->state = ec_fsm_slave_scan_state_error;
+		EC_SLAVE_ERR(slave, "Failed to determine product and vendor ID:"
+				" Reading word offset 0x%04x failed. \n",
+				fsm->sii_offset);
+		return;
+	}
+
+	memcpy(slave->vendor_words + fsm->sii_offset, fsm->fsm_sii.value, 4);
+
+	if (fsm->sii_offset + 2 < 16) {
+		// fetch the next 2 words
+		fsm->sii_offset += 2;
+        ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
+                        EC_FSM_SII_USE_CONFIGURED_ADDRESS);
+        ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
+
+		return;
+	}
+
+	// Evaluate SII contents
+	slave->sii.alias =
+		EC_READ_U16(slave->vendor_words + 0x0004);
+	slave->effective_alias = slave->sii.alias;
+	slave->sii.vendor_id =
+		EC_READ_U32(slave->vendor_words + 0x0008);
+	slave->sii.product_code =
+		EC_READ_U32(slave->vendor_words + 0x000A);
+	slave->sii.revision_number =
+	        EC_READ_U32(slave->vendor_words + 0x000C);
+	slave->sii.serial_number =
+		EC_READ_U32(slave->vendor_words + 0x000E);
+
+
+	fsm->state = ec_fsm_slave_scan_state_sii_request;
+
+}
+
+/*****************************************************************************/
+
+/**
+   Slave scan state: SII REQUEST.
+*/
+
+void ec_fsm_slave_scan_state_sii_request(ec_fsm_slave_scan_t *fsm /**< slave state machine */)
+{
+	ec_slave_t *slave = fsm->slave;
+	const struct firmware *firmware;
+
+	char buffer[48];
+	sprintf(buffer, "ethercat/ec_%08x_%08x.bin", slave->sii.vendor_id, slave->sii.product_code);
+
+	EC_SLAVE_DBG(slave, 1, "Trying to load SII firmware: %s", buffer);
+
+	if(!*(fsm->class_device))
+	{
+		EC_SLAVE_ERR(slave, "Cannot acces master device");
+		fsm->state = ec_fsm_slave_scan_state_error;
+		return;
+	}
+	if (request_firmware(&firmware, buffer, *(fsm->class_device)) == 0)
+	{
+		EC_SLAVE_DBG(slave, 1, "Firmware file found, reading %zu bytes.\n", firmware->size);
+		// Load firmware from file
+		slave->sii_nwords = firmware->size/2;
+
+
+		if (slave->sii_words) {
+			EC_SLAVE_WARN(slave, "Freeing old SII data...\n");
+			kfree(slave->sii_words);
+		}
+
+		if (!(slave->sii_words =
+					(uint16_t *) kmalloc(slave->sii_nwords * 2, GFP_KERNEL))) {
+			EC_SLAVE_ERR(slave, "Failed to allocate %zu words of SII data.\n",
+				   slave->sii_nwords);
+			slave->sii_nwords = 0;
+			slave->error_flag = 1;
+			fsm->state = ec_fsm_slave_scan_state_error;
+			return;
+		}
+
+		memcpy(slave->sii_words, firmware->data, slave->sii_nwords*2);
+		fsm->state = ec_fsm_slave_scan_state_sii_parse;
+
+		release_firmware(firmware);
+	}
+	else
+	{
+		EC_SLAVE_DBG(slave, 1, "SII firmware file not found, reading SII data from slave.\n");
+		// Read firmware from device
+		fsm->sii_offset = EC_FIRST_SII_CATEGORY_OFFSET; // first category header
+		ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
+					EC_FSM_SII_USE_CONFIGURED_ADDRESS);
+		fsm->state = ec_fsm_slave_scan_state_sii_size;
+	}
+}
+
+
+/*****************************************************************************/
+
+/**
    Slave scan state: SII SIZE.
 */
 
@@ -513,7 +649,6 @@ void ec_fsm_slave_scan_state_sii_size(ec
 
     cat_type = EC_READ_U16(fsm->fsm_sii.value);
     cat_size = EC_READ_U16(fsm->fsm_sii.value + 2);
-
     if (cat_type != 0xFFFF) { // not the last category
         off_t next_offset = 2UL + fsm->sii_offset + cat_size;
         if (next_offset >= EC_MAX_SII_SIZE) {
@@ -551,10 +686,15 @@ alloc_sii:
     // Start fetching SII contents
 
     fsm->state = ec_fsm_slave_scan_state_sii_data;
-    fsm->sii_offset = 0x0000;
+    fsm->sii_offset = 0x0016;
+
+    // Copy vendor data to sii_words
+    memcpy(slave->sii_words, slave->vendor_words, 32);
+
     ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
             EC_FSM_SII_USE_CONFIGURED_ADDRESS);
     ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
+
 }
 
 /*****************************************************************************/
@@ -566,10 +706,10 @@ alloc_sii:
 void ec_fsm_slave_scan_state_sii_data(ec_fsm_slave_scan_t *fsm /**< slave state machine */)
 {
     ec_slave_t *slave = fsm->slave;
-    uint16_t *cat_word, cat_type, cat_size;
 
     if (ec_fsm_sii_exec(&fsm->fsm_sii)) return;
 
+
     if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
         fsm->slave->error_flag = 1;
         fsm->state = ec_fsm_slave_scan_state_error;
@@ -591,24 +731,28 @@ void ec_fsm_slave_scan_state_sii_data(ec
         ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
                         EC_FSM_SII_USE_CONFIGURED_ADDRESS);
         ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
+
+
         return;
     }
 
+    fsm->state = ec_fsm_slave_scan_state_sii_parse;
+}
+/*****************************************************************************/
+
+/**
+   Slave scan state: SII PARSE.
+*/
+
+void ec_fsm_slave_scan_state_sii_parse(ec_fsm_slave_scan_t *fsm /**< slave state machine */)
+{
+	ec_slave_t *slave = fsm->slave;
+	uint16_t *cat_word, cat_type, cat_size;
+
     // Evaluate SII contents
 
     ec_slave_clear_sync_managers(slave);
 
-    slave->sii.alias =
-        EC_READ_U16(slave->sii_words + 0x0004);
-    slave->effective_alias = slave->sii.alias;
-    slave->sii.vendor_id =
-        EC_READ_U32(slave->sii_words + 0x0008);
-    slave->sii.product_code =
-        EC_READ_U32(slave->sii_words + 0x000A);
-    slave->sii.revision_number =
-        EC_READ_U32(slave->sii_words + 0x000C);
-    slave->sii.serial_number =
-        EC_READ_U32(slave->sii_words + 0x000E);
     slave->sii.boot_rx_mailbox_offset =
         EC_READ_U16(slave->sii_words + 0x0014);
     slave->sii.boot_rx_mailbox_size =
Only in ethercat-default/master: fsm_slave_scan.c.orig
diff -rup ethercat-default.orig/master/fsm_slave_scan.h ethercat-default/master/fsm_slave_scan.h
--- ethercat-default.orig/master/fsm_slave_scan.h	2011-10-28 09:34:57.000000000 -0500
+++ ethercat-default/master/fsm_slave_scan.h	2011-10-26 17:00:36.000000000 -0500
@@ -37,6 +37,7 @@
 #ifndef __EC_FSM_SLAVE_SCAN_H__
 #define __EC_FSM_SLAVE_SCAN_H__
 
+#include <linux/device.h>
 #include "globals.h"
 #include "datagram.h"
 #include "slave.h"
@@ -50,6 +51,7 @@
 /** \see ec_fsm_slave_scan */
 typedef struct ec_fsm_slave_scan ec_fsm_slave_scan_t;
 
+
 /** Finite state machine for scanning an EtherCAT slave.
  */
 struct ec_fsm_slave_scan
@@ -65,12 +67,24 @@ struct ec_fsm_slave_scan
     uint16_t sii_offset; /**< SII offset in words. */
 
     ec_fsm_sii_t fsm_sii; /**< SII state machine. */
+
+	#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+		struct device **class_device; /**< Master class device. */
+	#else
+		struct class_device **class_device; /**< Master class device. */
+	#endif
 };
 
 /*****************************************************************************/
 
 void ec_fsm_slave_scan_init(ec_fsm_slave_scan_t *, ec_datagram_t *,
-        ec_fsm_slave_config_t *, ec_fsm_pdo_t *);
+        ec_fsm_slave_config_t *, ec_fsm_pdo_t *,
+		#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+			struct device **
+		#else
+			struct class_device **
+		#endif
+        );
 void ec_fsm_slave_scan_clear(ec_fsm_slave_scan_t *);
 
 void ec_fsm_slave_scan_start(ec_fsm_slave_scan_t *, ec_slave_t *);
Only in ethercat-default/master: Makefile.in
diff -rup ethercat-default.orig/master/slave.c ethercat-default/master/slave.c
--- ethercat-default.orig/master/slave.c	2011-10-28 09:34:58.000000000 -0500
+++ ethercat-default/master/slave.c	2011-10-26 14:25:00.000000000 -0500
@@ -110,6 +110,7 @@ void ec_slave_init(
     slave->has_dc_system_time = 0;
     slave->transmission_delay = 0U;
 
+    slave->vendor_words = NULL;
     slave->sii_words = NULL;
     slave->sii_nwords = 0;
 
@@ -253,8 +254,12 @@ void ec_slave_clear(ec_slave_t *slave /*
         kfree(pdo);
     }
 
+    if (slave->vendor_words)
+    	kfree(slave->vendor_words);
+
     if (slave->sii_words)
         kfree(slave->sii_words);
+
     ec_fsm_slave_clear(&slave->fsm);
     ec_datagram_clear(&slave->fsm_datagram);
 }
diff -rup ethercat-default.orig/master/slave.h ethercat-default/master/slave.h
--- ethercat-default.orig/master/slave.h	2011-10-28 09:34:58.000000000 -0500
+++ ethercat-default/master/slave.h	2011-10-26 14:20:07.000000000 -0500
@@ -255,6 +255,7 @@ struct ec_slave
                                    (offset from reference clock). */
 
     // SII
+    uint16_t *vendor_words; /**< First 16 words of SII image. */
     uint16_t *sii_words; /**< Complete SII image. */
     size_t sii_nwords; /**< Size of the SII contents in words. */
 
Only in ethercat-default/master: .svn
_______________________________________________
etherlab-users mailing list
[email protected]
http://lists.etherlab.org/mailman/listinfo/etherlab-users

Reply via email to