diff -r 405cc2d033e0 -r c07dd38243ba master/slave.c --- 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...