Read complete eeprom data from slave and map it into SysFS.

This commit is contained in:
Florian Pose 2006-06-02 08:38:04 +00:00
parent 430c24a086
commit 429c0b26cb
4 changed files with 172 additions and 242 deletions

View File

@ -44,14 +44,6 @@
/*****************************************************************************/
/**
Size of memory to allocate while reading categories.
*/
#define EC_CAT_MEM 0x100
/*****************************************************************************/
const ec_code_msg_t al_status_messages[];
/*****************************************************************************/
@ -71,10 +63,9 @@ void ec_fsm_slave_start_reading(ec_fsm_t *);
void ec_fsm_slave_read_status(ec_fsm_t *);
void ec_fsm_slave_read_base(ec_fsm_t *);
void ec_fsm_slave_read_dl(ec_fsm_t *);
void ec_fsm_slave_prepare_sii(ec_fsm_t *);
void ec_fsm_slave_read_sii(ec_fsm_t *);
void ec_fsm_slave_category_header(ec_fsm_t *);
void ec_fsm_slave_category_data(ec_fsm_t *);
void ec_fsm_slave_eeprom_size(ec_fsm_t *);
void ec_fsm_slave_fetch_eeprom(ec_fsm_t *);
void ec_fsm_slave_fetch_eeprom2(ec_fsm_t *);
void ec_fsm_slave_end(ec_fsm_t *);
void ec_fsm_slave_conf(ec_fsm_t *);
@ -115,7 +106,6 @@ int ec_fsm_init(ec_fsm_t *fsm, /**< finite state machine */
fsm->master_slaves_responding = 0;
fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN;
fsm->master_validation = 0;
fsm->slave_cat_data = NULL;
ec_command_init(&fsm->command);
if (ec_command_prealloc(&fsm->command, EC_MAX_DATA_SIZE)) {
@ -134,7 +124,6 @@ int ec_fsm_init(ec_fsm_t *fsm, /**< finite state machine */
void ec_fsm_clear(ec_fsm_t *fsm /**< finite state machine */)
{
if (fsm->slave_cat_data) kfree(fsm->slave_cat_data);
ec_command_clear(&fsm->command);
}
@ -149,11 +138,6 @@ void ec_fsm_reset(ec_fsm_t *fsm /**< finite state machine */)
fsm->master_state = ec_fsm_master_start;
fsm->master_slaves_responding = 0;
fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN;
if (fsm->slave_cat_data) {
kfree(fsm->slave_cat_data);
fsm->slave_cat_data = NULL;
}
}
/*****************************************************************************/
@ -450,7 +434,7 @@ void ec_fsm_master_validate_vendor(ec_fsm_t *fsm /**< finite state machine */)
if (fsm->sii_state != ec_fsm_sii_end) return;
if (fsm->sii_result != slave->sii_vendor_id) {
if (EC_READ_U32(fsm->sii_result) != slave->sii_vendor_id) {
EC_ERR("Slave %i: invalid vendor ID!\n", slave->ring_position);
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
@ -488,10 +472,10 @@ void ec_fsm_master_validate_product(ec_fsm_t *fsm /**< finite state machine */)
if (fsm->sii_state != ec_fsm_sii_end) return;
if (fsm->sii_result != slave->sii_product_code) {
if (EC_READ_U32(fsm->sii_result) != slave->sii_product_code) {
EC_ERR("Slave %i: invalid product code!\n", slave->ring_position);
EC_ERR("expected 0x%08X, got 0x%08X.\n", slave->sii_product_code,
fsm->sii_result);
EC_READ_U32(fsm->sii_result));
fsm->master_state = ec_fsm_master_start;
fsm->master_state(fsm); // execute immediately
return;
@ -787,16 +771,17 @@ void ec_fsm_slave_read_dl(ec_fsm_t *fsm /**< finite state machine */)
// read data link status
ec_command_nprd(command, slave->station_address, 0x0110, 2);
ec_master_queue_command(slave->master, command);
fsm->slave_state = ec_fsm_slave_prepare_sii;
fsm->slave_state = ec_fsm_slave_eeprom_size;
}
/*****************************************************************************/
/**
Slave state: PREPARE_SII.
Slave state: EEPROM_SIZE.
Read the actual size of the EEPROM to allocate the EEPROM image.
*/
void ec_fsm_slave_prepare_sii(ec_fsm_t *fsm /**< finite state machine */)
void ec_fsm_slave_eeprom_size(ec_fsm_t *fsm /**< finite state machine */)
{
ec_command_t *command = &fsm->command;
ec_slave_t *slave = fsm->slave;
@ -811,254 +796,183 @@ void ec_fsm_slave_prepare_sii(ec_fsm_t *fsm /**< finite state machine */)
}
dl_status = EC_READ_U16(command->data);
for (i = 0; i < 4; i++) {
slave->dl_link[i] = dl_status & (1 << (4 + i)) ? 1 : 0;
slave->dl_loop[i] = dl_status & (1 << (8 + i * 2)) ? 1 : 0;
slave->dl_signal[i] = dl_status & (1 << (9 + i * 2)) ? 1 : 0;
}
fsm->sii_offset = 0x0004;
// Start fetching EEPROM size
fsm->sii_offset = 0x0040; // first category header
fsm->sii_mode = 1;
fsm->sii_state = ec_fsm_sii_start_reading;
fsm->slave_sii_num = 0;
fsm->slave_state = ec_fsm_slave_read_sii;
fsm->slave_state = ec_fsm_slave_fetch_eeprom;
fsm->slave_state(fsm); // execute state immediately
}
/*****************************************************************************/
/**
Slave state: READ_SII.
Slave state: FETCH_EEPROM.
*/
void ec_fsm_slave_read_sii(ec_fsm_t *fsm /**< finite state machine */)
void ec_fsm_slave_fetch_eeprom(ec_fsm_t *fsm /**< finite state machine */)
{
ec_slave_t *slave = fsm->slave;
uint16_t cat_type, cat_size;
// execute SII state machine
fsm->sii_state(fsm);
if (fsm->sii_state == ec_fsm_sii_error) {
fsm->slave_state = ec_fsm_slave_end;
EC_ERR("FSM failed to read SII data at 0x%04X on slave %i.\n",
fsm->sii_offset, slave->ring_position);
EC_ERR("Failed to read EEPROM size of slave %i.\n",
slave->ring_position);
return;
}
if (fsm->sii_state != ec_fsm_sii_end) return;
switch (fsm->slave_sii_num) {
case 0:
slave->sii_alias = fsm->sii_result & 0xFFFF;
fsm->sii_offset = 0x0008;
break;
case 1:
slave->sii_vendor_id = fsm->sii_result;
fsm->sii_offset = 0x000A;
break;
case 2:
slave->sii_product_code = fsm->sii_result;
fsm->sii_offset = 0x000C;
break;
case 3:
slave->sii_revision_number = fsm->sii_result;
fsm->sii_offset = 0x000E;
break;
case 4:
slave->sii_serial_number = fsm->sii_result;
fsm->sii_offset = 0x0018;
break;
case 5:
slave->sii_rx_mailbox_offset = fsm->sii_result & 0xFFFF;
slave->sii_rx_mailbox_size = fsm->sii_result >> 16;
fsm->sii_offset = 0x001A;
break;
case 6:
slave->sii_tx_mailbox_offset = fsm->sii_result & 0xFFFF;
slave->sii_tx_mailbox_size = fsm->sii_result >> 16;
fsm->sii_offset = 0x001C;
break;
case 7:
slave->sii_mailbox_protocols = fsm->sii_result & 0xFFFF;
cat_type = EC_READ_U16(fsm->sii_result);
cat_size = EC_READ_U16(fsm->sii_result + 2);
fsm->slave_cat_offset = 0x0040;
if (fsm->slave_cat_data) {
EC_INFO("FSM freeing old category data on slave %i...\n",
fsm->slave->ring_position);
kfree(fsm->slave_cat_data);
}
if (!(fsm->slave_cat_data =
(uint8_t *) kmalloc(EC_CAT_MEM, GFP_ATOMIC))) {
EC_ERR("FSM Failed to allocate category data.\n");
fsm->slave_state = ec_fsm_slave_end;
return;
}
// start reading first category header
fsm->sii_offset = fsm->slave_cat_offset;
fsm->sii_state = ec_fsm_sii_start_reading;
fsm->slave_state = ec_fsm_slave_category_header;
fsm->slave_state(fsm); // execute state immediately
return;
}
fsm->slave_sii_num++;
fsm->sii_state = ec_fsm_sii_start_reading;
fsm->slave_state(fsm); // execute state immediately
}
/*****************************************************************************/
/**
Slave state: CATEGORY_HEADER.
Start reading categories.
*/
void ec_fsm_slave_category_header(ec_fsm_t *fsm /**< finite state machine */)
{
// execute SII state machine
fsm->sii_state(fsm);
if (fsm->sii_state == ec_fsm_sii_error) {
kfree(fsm->slave_cat_data);
fsm->slave_cat_data = NULL;
fsm->slave_state = ec_fsm_slave_end;
EC_ERR("FSM failed to read category header at 0x%04X on slave %i.\n",
fsm->slave_cat_offset, fsm->slave->ring_position);
return;
}
if (fsm->sii_state != ec_fsm_sii_end) return;
// last category?
if ((fsm->sii_result & 0xFFFF) == 0xFFFF) {
kfree(fsm->slave_cat_data);
fsm->slave_cat_data = NULL;
fsm->slave_state = ec_fsm_slave_end;
return;
}
fsm->slave_cat_type = fsm->sii_result & 0x7FFF;
fsm->slave_cat_words = (fsm->sii_result >> 16) & 0xFFFF;
if (fsm->slave_cat_words > EC_CAT_MEM * 2) {
EC_ERR("FSM category memory too small! %i words needed.\n",
fsm->slave_cat_words);
fsm->slave_state = ec_fsm_slave_end;
return;
}
// start reading category data
fsm->slave_cat_data_offset = 0;
fsm->sii_offset = (fsm->slave_cat_offset + 2 +
fsm->slave_cat_data_offset);
fsm->sii_mode = 1;
fsm->sii_state = ec_fsm_sii_start_reading;
fsm->slave_state = ec_fsm_slave_category_data;
fsm->slave_state(fsm); // execute state immediately
}
/*****************************************************************************/
/**
Slave state: CATEGORY_DATA.
Reads category data.
*/
void ec_fsm_slave_category_data(ec_fsm_t *fsm /**< finite state machine */)
{
// execute SII state machine
fsm->sii_state(fsm);
if (fsm->sii_state == ec_fsm_sii_error) {
kfree(fsm->slave_cat_data);
fsm->slave_cat_data = NULL;
fsm->slave_state = ec_fsm_slave_end;
EC_ERR("FSM failed to read category 0x%02X data at 0x%04X"
" on slave %i.\n", fsm->slave_cat_type, fsm->sii_offset,
fsm->slave->ring_position);
return;
}
if (fsm->sii_state != ec_fsm_sii_end) return;
fsm->slave_cat_data[fsm->slave_cat_data_offset * 2] =
fsm->sii_result & 0xFF;
fsm->slave_cat_data[fsm->slave_cat_data_offset * 2 + 1] =
(fsm->sii_result >> 8) & 0xFF;
// read second word "on the fly"
if (fsm->slave_cat_data_offset + 1 < fsm->slave_cat_words) {
fsm->slave_cat_data_offset++;
fsm->slave_cat_data[fsm->slave_cat_data_offset * 2] =
(fsm->sii_result >> 16) & 0xFF;
fsm->slave_cat_data[fsm->slave_cat_data_offset * 2 + 1] =
(fsm->sii_result >> 24) & 0xFF;
}
fsm->slave_cat_data_offset++;
if (fsm->slave_cat_data_offset < fsm->slave_cat_words) {
fsm->sii_offset = (fsm->slave_cat_offset + 2 +
fsm->slave_cat_data_offset);
fsm->sii_mode = 1;
if (cat_type != 0xFFFF) { // not the last category
fsm->sii_offset += cat_size + 2;
fsm->sii_state = ec_fsm_sii_start_reading;
fsm->slave_state = ec_fsm_slave_category_data;
fsm->slave_state(fsm); // execute state immediately
fsm->sii_state(fsm); // execute state immediately
return;
}
// category data complete
switch (fsm->slave_cat_type)
{
case 0x000A:
if (ec_slave_fetch_strings(fsm->slave, fsm->slave_cat_data))
goto out_free;
break;
case 0x001E:
if (ec_slave_fetch_general(fsm->slave, fsm->slave_cat_data))
goto out_free;
break;
case 0x0028:
break;
case 0x0029:
if (ec_slave_fetch_sync(fsm->slave, fsm->slave_cat_data,
fsm->slave_cat_words))
goto out_free;
break;
case 0x0032:
if (ec_slave_fetch_pdo(fsm->slave, fsm->slave_cat_data,
fsm->slave_cat_words,
EC_TX_PDO))
goto out_free;
break;
case 0x0033:
if (ec_slave_fetch_pdo(fsm->slave, fsm->slave_cat_data,
fsm->slave_cat_words,
EC_RX_PDO))
goto out_free;
break;
default:
EC_WARN("FSM: Unknown category type 0x%04X in slave %i.\n",
fsm->slave_cat_type, fsm->slave->ring_position);
slave->eeprom_size = (fsm->sii_offset + 1) * 2;
if (slave->eeprom_data) {
EC_INFO("Freeing old EEPROM data on slave %i...\n",
slave->ring_position);
kfree(slave->eeprom_data);
}
// start reading next category header
fsm->slave_cat_offset += 2 + fsm->slave_cat_words;
fsm->sii_offset = fsm->slave_cat_offset;
if (!(slave->eeprom_data =
(uint8_t *) kmalloc(slave->eeprom_size, GFP_ATOMIC))) {
EC_ERR("Failed to allocate EEPROM data on slave %i.\n",
slave->ring_position);
fsm->slave_state = ec_fsm_slave_end;
return;
}
// Start fetching EEPROM contents
fsm->sii_offset = 0x0000;
fsm->sii_mode = 1;
fsm->sii_state = ec_fsm_sii_start_reading;
fsm->slave_state = ec_fsm_slave_category_header;
fsm->slave_state = ec_fsm_slave_fetch_eeprom2;
fsm->slave_state(fsm); // execute state immediately
return;
}
out_free:
kfree(fsm->slave_cat_data);
fsm->slave_cat_data = NULL;
/*****************************************************************************/
/**
Slave state: FETCH_EEPROM2.
*/
void ec_fsm_slave_fetch_eeprom2(ec_fsm_t *fsm /**< finite state machine */)
{
ec_slave_t *slave = fsm->slave;
uint16_t *cat_word, cat_type, cat_size;
// execute SII state machine
fsm->sii_state(fsm);
if (fsm->sii_state == ec_fsm_sii_error) {
fsm->slave_state = ec_fsm_slave_end;
EC_ERR("Failed to fetch EEPROM contents of slave %i.\n",
slave->ring_position);
return;
}
if (fsm->sii_state != ec_fsm_sii_end) return;
// 2 words fetched
if (fsm->sii_offset + 2 <= slave->eeprom_size / 2) { // 2 words fit
memcpy(slave->eeprom_data + fsm->sii_offset * 2, fsm->sii_result, 4);
}
else { // copy the last word
memcpy(slave->eeprom_data + fsm->sii_offset * 2, fsm->sii_result, 2);
}
if (fsm->sii_offset + 2 < slave->eeprom_size / 2) {
// fetch the next 2 words
fsm->sii_offset += 2;
fsm->sii_state = ec_fsm_sii_start_reading;
fsm->sii_state(fsm); // execute state immediately
return;
}
// Evaluate EEPROM contents
slave->sii_alias =
EC_READ_U16(slave->eeprom_data + 2 * 0x0004);
slave->sii_vendor_id =
EC_READ_U32(slave->eeprom_data + 2 * 0x0008);
slave->sii_product_code =
EC_READ_U32(slave->eeprom_data + 2 * 0x000A);
slave->sii_revision_number =
EC_READ_U32(slave->eeprom_data + 2 * 0x000C);
slave->sii_serial_number =
EC_READ_U32(slave->eeprom_data + 2 * 0x000E);
slave->sii_rx_mailbox_offset =
EC_READ_U16(slave->eeprom_data + 2 * 0x0018);
slave->sii_rx_mailbox_size =
EC_READ_U16(slave->eeprom_data + 2 * 0x0019);
slave->sii_tx_mailbox_offset =
EC_READ_U16(slave->eeprom_data + 2 * 0x001A);
slave->sii_tx_mailbox_size =
EC_READ_U16(slave->eeprom_data + 2 * 0x001B);
slave->sii_mailbox_protocols =
EC_READ_U16(slave->eeprom_data + 2 * 0x001C);
// evaluate category data
cat_word = (uint16_t *) slave->eeprom_data + 0x0040;
while (EC_READ_U16(cat_word) != 0xFFFF) {
cat_type = EC_READ_U16(cat_word) & 0x7FFF;
cat_size = EC_READ_U16(cat_word + 1);
switch (cat_type) {
case 0x000A:
if (ec_slave_fetch_strings(slave, (uint8_t *) (cat_word + 2)))
goto end;
break;
case 0x001E:
if (ec_slave_fetch_general(slave, (uint8_t *) (cat_word + 2)))
goto end;
break;
case 0x0028:
break;
case 0x0029:
if (ec_slave_fetch_sync(slave, (uint8_t *) (cat_word + 2),
cat_size))
goto end;
break;
case 0x0032:
if (ec_slave_fetch_pdo(slave, (uint8_t *) (cat_word + 2),
cat_size, EC_TX_PDO))
goto end;
break;
case 0x0033:
if (ec_slave_fetch_pdo(slave, (uint8_t *) (cat_word + 2),
cat_size, EC_RX_PDO))
goto end;
break;
default:
EC_WARN("Unknown category type 0x%04X in slave %i.\n",
cat_type, slave->ring_position);
}
cat_word += cat_size + 2;
}
end:
fsm->slave_state = ec_fsm_slave_end;
}
@ -1477,7 +1391,7 @@ void ec_fsm_sii_fetch(ec_fsm_t *fsm /**< finite state machine */)
#endif
// SII value received.
fsm->sii_result = EC_READ_U32(command->data + 6);
memcpy(fsm->sii_result, command->data + 6, 4);
fsm->sii_state = ec_fsm_sii_end;
}

View File

@ -67,17 +67,11 @@ struct ec_fsm
unsigned int master_validation; /**< non-zero, if validation to do */
void (*slave_state)(ec_fsm_t *); /**< slave state function */
uint8_t slave_sii_num; /**< SII value iteration counter */
uint8_t *slave_cat_data; /**< temporary memory for category data */
uint16_t slave_cat_offset; /**< current category word offset in EEPROM */
uint16_t slave_cat_data_offset; /**< current offset in category data */
uint16_t slave_cat_type; /**< type of current category */
uint16_t slave_cat_words; /**< number of words of current category */
void (*sii_state)(ec_fsm_t *); /**< SII state function */
uint16_t sii_offset; /**< input: offset in SII */
unsigned int sii_mode; /**< SII reading done by APRD (0) or NPRD (1) */
uint32_t sii_result; /**< output: read SII value (32bit) */
uint8_t sii_result[4]; /**< output: raw SII value (32bit) */
cycles_t sii_start; /**< sii start */
void (*change_state)(ec_fsm_t *); /**< slave state change state function */

View File

@ -69,6 +69,7 @@ EC_SYSFS_READ_ATTR(product_desc);
EC_SYSFS_READ_ATTR(sii_name);
EC_SYSFS_READ_ATTR(type);
EC_SYSFS_READ_WRITE_ATTR(state);
EC_SYSFS_READ_ATTR(eeprom);
static struct attribute *def_attrs[] = {
&attr_ring_position,
@ -79,6 +80,7 @@ static struct attribute *def_attrs[] = {
&attr_sii_name,
&attr_type,
&attr_state,
&attr_eeprom,
NULL,
};
@ -145,6 +147,8 @@ int ec_slave_init(ec_slave_t *slave, /**< EtherCAT slave */
slave->type = NULL;
slave->registered = 0;
slave->fmmu_count = 0;
slave->eeprom_data = NULL;
slave->eeprom_size = 0;
slave->eeprom_group = NULL;
slave->eeprom_image = NULL;
slave->eeprom_order = NULL;
@ -234,6 +238,8 @@ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */)
kfree(sdo);
}
if (slave->eeprom_data) kfree(slave->eeprom_data);
ec_command_clear(&slave->mbox_command);
}
@ -1121,6 +1127,8 @@ void ec_slave_print(const ec_slave_t *slave, /**< EtherCAT slave */
EC_INFO(" EEPROM data:\n");
EC_INFO(" EEPROM content size: %i Bytes\n", slave->eeprom_size);
if (slave->sii_alias)
EC_INFO(" Configured station alias: 0x%04X (%i)\n",
slave->sii_alias, slave->sii_alias);
@ -1295,6 +1303,19 @@ ssize_t ec_show_slave_attribute(struct kobject *kobj, /**< slave's kobject */
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 %i exceed 1 page (%i/%i).\n",
slave->ring_position, slave->eeprom_size,
(int) PAGE_SIZE);
}
else {
memcpy(buffer, slave->eeprom_data, slave->eeprom_size);
return slave->eeprom_size;
}
}
}
return 0;
}

View File

@ -261,10 +261,11 @@ struct ec_slave
ec_fmmu_t fmmus[EC_MAX_FMMUS]; /**< FMMU configurations */
uint8_t fmmu_count; /**< number of FMMUs used */
uint8_t *eeprom_data; /**< Complete EEPROM image */
uint16_t eeprom_size; /**< size of the EEPROM contents in byte */
struct list_head eeprom_strings; /**< EEPROM STRING categories */
struct list_head eeprom_syncs; /**< EEPROM SYNC MANAGER categories */
struct list_head eeprom_pdos; /**< EEPROM [RT]XPDO categories */
char *eeprom_group; /**< slave group acc. to EEPROM */
char *eeprom_image; /**< slave image name acc. to EEPROM */
char *eeprom_order; /**< slave order number acc. to EEPROM */