Newer
Older
if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
EC_ERR("Writing to EEPROM is only allowed in idle mode!\n");
alias = simple_strtoul(data, &remainder, 0);
if (remainder == (char *) data || (*remainder && *remainder != '\n')) {
EC_ERR("Invalid alias value! Dropping.\n");
return -EINVAL;
}
if (!slave->eeprom_data || slave->eeprom_size < 16) {
EC_ERR("Failed to read EEPROM contents from slave %u.\n",
slave->ring_position);
return -EINVAL;
}
// copy first 7 words of recent EEPROM contents
memcpy(eeprom_data, slave->eeprom_data, 14);
// write new alias address in word 4
EC_WRITE_U16(eeprom_data + 8, alias);
// calculate new checksum over words 0 to 6
crc = ec_slave_eeprom_crc(eeprom_data, 14);
EC_WRITE_U16(eeprom_data + 14, crc);
// init EEPROM write request
INIT_LIST_HEAD(&request.list);
request.slave = slave;
request.data = eeprom_data;
request.word_offset = 0x0000;
request.word_size = 8;
if ((ret = ec_slave_schedule_eeprom_writing(&request)))
return ret; // error code
slave->sii.alias = alias; // FIXME: do this in state machine
return size; // success
/*****************************************************************************/
Formats attribute data for SysFS read access.
\return number of bytes to read
ssize_t ec_show_slave_attribute(struct kobject *kobj, /**< slave's kobject */
struct attribute *attr, /**< attribute */
char *buffer /**< memory to store data */
)
{
ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj);
if (attr == &attr_info) {
return ec_slave_info(slave, buffer);
else if (attr == &attr_state) {
switch (slave->current_state) {
case EC_SLAVE_STATE_INIT:
return sprintf(buffer, "INIT\n");
case EC_SLAVE_STATE_PREOP:
return sprintf(buffer, "PREOP\n");
case EC_SLAVE_STATE_SAFEOP:
return sprintf(buffer, "SAFEOP\n");
case EC_SLAVE_STATE_OP:
return sprintf(buffer, "OP\n");
default:
return sprintf(buffer, "UNKNOWN\n");
}
}
else if (attr == &attr_eeprom) {
if (slave->eeprom_data) {
if (slave->eeprom_size > PAGE_SIZE) {
EC_ERR("EEPROM contents of slave %u exceed 1 page (%u/%u).\n",
slave->ring_position, slave->eeprom_size,
(int) PAGE_SIZE);
}
else {
memcpy(buffer, slave->eeprom_data, slave->eeprom_size);
return slave->eeprom_size;
}
}
}
else if (attr == &attr_alias) {
return sprintf(buffer, "%u\n", slave->sii.alias);
/*****************************************************************************/
/**
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_state) {
Florian Pose
committed
char state[EC_STATE_STRING_SIZE];
ec_slave_request_state(slave, EC_SLAVE_STATE_INIT);
ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
else if (!strcmp(buffer, "SAFEOP\n"))
ec_slave_request_state(slave, EC_SLAVE_STATE_SAFEOP);
ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
else {
EC_ERR("Invalid slave state \"%s\"!\n", buffer);
return -EINVAL;
ec_state_string(slave->requested_state, state);
EC_INFO("Accepted new state %s for slave %u.\n",
state, slave->ring_position);
return ec_slave_write_eeprom(slave, buffer, size);
else if (attr == &attr_alias) {
return ec_slave_write_alias(slave, buffer, size);
}
/*****************************************************************************/
* Get the sync manager for either Rx- or Tx-Pdos.
* \return pointer to sync manager, or NULL.
ec_slave_t *slave, /**< EtherCAT slave */
ec_direction_t dir /**< input or output */
)
{
unsigned int sync_index;
if (dir != EC_DIR_INPUT && dir != EC_DIR_OUTPUT) {
EC_ERR("Invalid direction!\n");
return NULL;
sync_index = (unsigned int) dir;
if (slave->sii.mailbox_protocols) sync_index += 2;
}
/*****************************************************************************/
/**
\return 0 in case of success, else < 0
*/
int ec_slave_validate(const ec_slave_t *slave, /**< EtherCAT slave */
uint32_t vendor_id, /**< vendor ID */
uint32_t product_code /**< product code */
)
{
if (vendor_id != slave->sii.vendor_id ||
product_code != slave->sii.product_code) {
EC_ERR("Invalid slave type at position %u:\n", slave->ring_position);
EC_ERR(" Requested: 0x%08X 0x%08X\n", vendor_id, product_code);
EC_ERR(" Found: 0x%08X 0x%08X\n",
slave->sii.vendor_id, slave->sii.product_code);
/*****************************************************************************/
/**
Counts the total number of Sdos and entries in the dictionary.
*/
void ec_slave_sdo_dict_info(const ec_slave_t *slave, /**< EtherCAT slave */
unsigned int *sdo_count, /**< number of Sdos */
unsigned int *entry_count /**< total number of
entries */
)
{
unsigned int sdos = 0, entries = 0;
ec_sdo_t *sdo;
ec_sdo_entry_t *entry;
list_for_each_entry(sdo, &slave->sdo_dictionary, list) {
sdos++;
list_for_each_entry(entry, &sdo->entries, list) {
entries++;
}
}
*sdo_count = sdos;
*entry_count = entries;
}
/*****************************************************************************/
/**
* Get an Sdo from the dictionary.
* \returns The desired Sdo, or NULL.
*/
ec_sdo_t *ec_slave_get_sdo(
ec_slave_t *slave /**< EtherCAT slave */,
)
{
ec_sdo_t *sdo;
list_for_each_entry(sdo, &slave->sdo_dictionary, list) {
if (sdo->index != index) continue;
return sdo;
}
return NULL;
}
/*****************************************************************************/
/** Finds a mapped Pdo.
* \returns The desired Pdo object, or NULL.
*/
const ec_pdo_t *ec_slave_find_pdo(
const ec_slave_t *slave, /**< Slave. */
uint16_t index /**< Pdo index to find. */
)
{
unsigned int i;
const ec_sync_t *sync;
const ec_pdo_t *pdo;
for (i = 0; i < slave->sii.sync_count; i++) {
sync = &slave->sii.syncs[i];