master/slave.c
changeset 980 c07dd38243ba
parent 979 405cc2d033e0
child 992 50a44cbd30af
--- a/master/slave.c	Mon Jun 09 14:32:16 2008 +0000
+++ b/master/slave.c	Tue Jun 10 08:48:50 2008 +0000
@@ -57,8 +57,6 @@
 void ec_slave_clear(struct kobject *);
 void ec_slave_sdos_clear(struct kobject *);
 ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *);
-ssize_t ec_store_slave_attribute(struct kobject *, struct attribute *,
-                                 const char *, size_t);
 char *ec_slave_sii_string(ec_slave_t *, unsigned int);
 
 /*****************************************************************************/
@@ -66,19 +64,14 @@
 /** \cond */
 
 EC_SYSFS_READ_ATTR(info);
-EC_SYSFS_READ_WRITE_ATTR(sii);
-EC_SYSFS_READ_WRITE_ATTR(alias);
 
 static struct attribute *def_attrs[] = {
     &attr_info,
-    &attr_sii,
-    &attr_alias,
     NULL,
 };
 
 static struct sysfs_ops sysfs_ops = {
     .show = ec_show_slave_attribute,
-    .store = ec_store_slave_attribute
 };
 
 static struct kobj_type ktype_ec_slave = {
@@ -848,217 +841,59 @@
 /*****************************************************************************/
 
 /**
- * Schedules an SII write request.
- * \return 0 case of success, otherwise error code.
- */
-
-int ec_slave_schedule_sii_writing(
-        ec_sii_write_request_t *request /**< SII write request */
-        )
-{
-    ec_master_t *master = request->slave->master;
-
-    request->state = EC_REQUEST_QUEUED;
-
-    // schedule SII write request.
-    down(&master->sii_sem);
-    list_add_tail(&request->list, &master->sii_requests);
-    up(&master->sii_sem);
-
-    // wait for processing through FSM
-    if (wait_event_interruptible(master->sii_queue,
-                request->state != EC_REQUEST_QUEUED)) {
-        // interrupted by signal
-        down(&master->sii_sem);
-        if (request->state == EC_REQUEST_QUEUED) {
-            list_del(&request->list);
-            up(&master->sii_sem);
-            return -EINTR;
-        }
-        // request already processing: interrupt not possible.
-        up(&master->sii_sem);
-    }
-
-    // wait until master FSM has finished processing
-    wait_event(master->sii_queue,
-            request->state != EC_REQUEST_BUSY);
-
-    return request->state == EC_REQUEST_SUCCESS ? 0 : -EIO;
-}
-
-/*****************************************************************************/
-
-/**
- * Calculates the SII checksum field.
- *
- * The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an
- * initial value of 0xff (see IEC 61158-6-12 ch. 5.4).
- *
- * The below code was originally generated with PYCRC
- * http://www.tty1.net/pycrc
- *
- * ./pycrc.py --width=8 --poly=0x07 --reflect-in=0 --xor-in=0xff
- *   --reflect-out=0 --xor-out=0 --generate c --algorithm=bit-by-bit
- *
- * \return CRC8
- */
-
-uint8_t ec_slave_sii_crc(
-        const uint8_t *data, /**< pointer to data */
-        size_t length /**< number of bytes in \a data */
-        )
-{
-    unsigned int i;
-    uint8_t bit, byte, crc = 0x48;
-
-    while (length--) {
-        byte = *data++;
-        for (i = 0; i < 8; i++) {
-            bit = crc & 0x80;
-            crc = (crc << 1) | ((byte >> (7 - i)) & 0x01);
-            if (bit) crc ^= 0x07;
-        }
-    }
-
-    for (i = 0; i < 8; i++) {
-        bit = crc & 0x80;
-        crc <<= 1;
-        if (bit) crc ^= 0x07;
-    }
-
-    return crc;
-}
-
-/*****************************************************************************/
-
-/**
- * Writes complete SII contents to a slave.
- * \return data size written in case of success, otherwise error code.
- */
-
-ssize_t ec_slave_write_sii(ec_slave_t *slave, /**< EtherCAT slave */
-        const uint8_t *data, /**< new SII data */
-        size_t size /**< size of data in bytes */
-        )
-{
+ * Writes SII contents to a slave.
+ * \return Zero on success, otherwise error code.
+ */
+
+int ec_slave_write_sii(
+        ec_slave_t *slave, /**< EtherCAT slave */
+        uint16_t offset, /**< SII word offset. */
+        unsigned int nwords, /**< Number of words. */
+        const uint16_t *words /**< New SII data. */
+        )
+{
+    ec_master_t *master = slave->master;
     ec_sii_write_request_t request;
-    const uint16_t *cat_header;
-    uint16_t cat_type, cat_size;
-    int ret;
-    uint8_t crc;
-
-    if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
-        EC_ERR("Writing SIIs only allowed in idle mode!\n");
-        return -EBUSY;
-    }
-
-    if (size % 2) {
-        EC_ERR("SII data size is odd (%u bytes)! SII data must be"
-                " word-aligned. Dropping.\n", size);
-        return -EINVAL;
-    }
 
     // init SII write request
     INIT_LIST_HEAD(&request.list);
     request.slave = slave;
-    request.words = (const uint16_t *) data;
-    request.offset = 0;
-    request.nwords = size / 2;
-
-    if (request.nwords < 0x0041) {
-        EC_ERR("SII data too short (%u words)! Mimimum is"
-                " 40 fixed words + 1 delimiter. Dropping.\n",
-                request.nwords);
-        return -EINVAL;
-    }
-
-    // calculate checksum
-    crc = ec_slave_sii_crc(data, 14); // CRC over words 0 to 6
-    if (crc != data[14]) {
-        EC_WARN("SII CRC incorrect. Must be 0x%02x.\n", crc);
-    }
-
-    cat_header = request.words + EC_FIRST_SII_CATEGORY_OFFSET;
-    cat_type = EC_READ_U16(cat_header);
-    while (cat_type != 0xFFFF) { // cycle through categories
-        if (cat_header + 1 > request.words + request.nwords) {
-            EC_ERR("SII data corrupted! Dropping.\n");
-            return -EINVAL;
-        }
-        cat_size = EC_READ_U16(cat_header + 1);
-        if (cat_header + cat_size + 2 > request.words + request.nwords) {
-            EC_ERR("SII data corrupted! Dropping.\n");
-            return -EINVAL;
-        }
-        cat_header += cat_size + 2;
-        cat_type = EC_READ_U16(cat_header);
-    }
-
-    // SII data ok. schedule writing.
-    if ((ret = ec_slave_schedule_sii_writing(&request)))
-        return ret; // error code
-
-    return size; // success
-}
-
-/*****************************************************************************/
-
-/**
- * Writes the Secondary slave address (alias) to the slave's SII.
- * \return data size written in case of success, otherwise error code.
- */
-
-ssize_t ec_slave_write_alias(ec_slave_t *slave, /**< EtherCAT slave */
-        const uint8_t *data, /**< alias string */
-        size_t size /**< size of data in bytes */
-        )
-{
-    ec_sii_write_request_t request;
-    char *remainder;
-    uint16_t alias;
-    int ret;
-    uint8_t sii_data[16], crc;
-
-    if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
-        EC_ERR("Writing to SII is only allowed in idle mode!\n");
-        return -EBUSY;
-    }
-
-    alias = simple_strtoul(data, &remainder, 0);
-    if (remainder == (char *) data || (*remainder && *remainder != '\n')) {
-        EC_ERR("Invalid alias value! Dropping.\n");
-        return -EINVAL;
-    }
-
-    if (!slave->sii_words || slave->sii_nwords < 8) {
-        EC_ERR("Failed to read SII contents from slave %u.\n",
-                slave->ring_position);
-        return -EINVAL;
-    }
-
-    // copy first 7 words of recent SII contents
-    memcpy(sii_data, (uint8_t *) slave->sii_words, 14);
-    
-    // write new alias address in word 4
-    EC_WRITE_U16(sii_data + 8, alias);
-
-    // calculate new checksum over words 0 to 6
-    crc = ec_slave_sii_crc(sii_data, 14);
-    EC_WRITE_U16(sii_data + 14, crc);
-
-    // init SII write request
-    INIT_LIST_HEAD(&request.list);
-    request.slave = slave;
-    request.words = (const uint16_t *) sii_data;
-    request.offset = 0x0000;
-    request.nwords = 8;
-
-    if ((ret = ec_slave_schedule_sii_writing(&request)))
-        return ret; // error code
-
-    slave->sii.alias = alias; // FIXME: do this in state machine
-
-    return size; // success
+    request.words = words;
+    request.offset = offset;
+    request.nwords = nwords;
+    request.state = EC_REQUEST_QUEUED;
+
+    // schedule SII write request.
+    down(&master->sii_sem);
+    list_add_tail(&request.list, &master->sii_requests);
+    up(&master->sii_sem);
+
+    // wait for processing through FSM
+    if (wait_event_interruptible(master->sii_queue,
+                request.state != EC_REQUEST_QUEUED)) {
+        // interrupted by signal
+        down(&master->sii_sem);
+        if (request.state == EC_REQUEST_QUEUED) {
+            list_del(&request.list);
+            up(&master->sii_sem);
+            return -EINTR;
+        }
+        // request already processing: interrupt not possible.
+        up(&master->sii_sem);
+    }
+
+    // wait until master FSM has finished processing
+    wait_event(master->sii_queue,
+            request.state != EC_REQUEST_BUSY);
+
+    if (request.state == EC_REQUEST_SUCCESS) {
+        if (offset <= 4 && offset + nwords > 4) { // alias was written
+            slave->sii.alias = EC_READ_U16(words + 4);
+        }
+        return 0;
+    } else {
+        return -EIO;
+    }
 }
 
 /*****************************************************************************/
@@ -1074,25 +909,9 @@
                                 )
 {
     ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj);
-    unsigned int sii_size;
 
     if (attr == &attr_info) {
         return ec_slave_info(slave, buffer);
-    } else if (attr == &attr_sii) {
-        if (slave->sii_words) {
-            sii_size = slave->sii_nwords * 2;
-            if (sii_size > PAGE_SIZE) {
-                EC_ERR("SII contents of slave %u exceed 1 page (%u/%u).\n",
-                       slave->ring_position, sii_size,
-                       (int) PAGE_SIZE);
-            }
-            else {
-                memcpy(buffer, (uint8_t *) slave->sii_words, sii_size);
-                return sii_size;
-            }
-        }
-    } else if (attr == &attr_alias) {
-        return sprintf(buffer, "%u\n", slave->sii.alias);
     }
 
     return 0;
@@ -1100,30 +919,6 @@
 
 /*****************************************************************************/
 
-/**
-   Formats attribute data for SysFS write access.
-   \return number of bytes processed, or negative error code
-*/
-
-ssize_t ec_store_slave_attribute(struct kobject *kobj, /**< slave's kobject */
-                                 struct attribute *attr, /**< attribute */
-                                 const char *buffer, /**< memory with data */
-                                 size_t size /**< size of data to store */
-                                 )
-{
-    ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj);
-
-    if (attr == &attr_sii) {
-        return ec_slave_write_sii(slave, buffer, size);
-    } else if (attr == &attr_alias) {
-        return ec_slave_write_alias(slave, buffer, size);
-    }
-
-    return -EIO;
-}
-
-/*****************************************************************************/
-
 /** Get the sync manager for either Rx- or Tx-Pdos.
  *
  * \todo This seems not to be correct in every case...