# HG changeset patch # User Florian Pose # Date 1149258345 0 # Node ID a03be9a6fed6a9eaa1c920f16241f21652ada0e7 # Parent 4f9c149fb71fd74e8211b090f8c28f7395f4818e EEPROM writing via SysFS. diff -r 4f9c149fb71f -r a03be9a6fed6 master/fsm.c --- a/master/fsm.c Fri Jun 02 12:01:47 2006 +0000 +++ b/master/fsm.c Fri Jun 02 14:25:45 2006 +0000 @@ -58,6 +58,7 @@ void ec_fsm_master_reconfigure(ec_fsm_t *); void ec_fsm_master_address(ec_fsm_t *); void ec_fsm_master_conf(ec_fsm_t *); +void ec_fsm_master_eeprom(ec_fsm_t *); void ec_fsm_slave_start_reading(ec_fsm_t *); void ec_fsm_slave_read_status(ec_fsm_t *); @@ -77,8 +78,11 @@ void ec_fsm_slave_op2(ec_fsm_t *); void ec_fsm_sii_start_reading(ec_fsm_t *); -void ec_fsm_sii_check(ec_fsm_t *); -void ec_fsm_sii_fetch(ec_fsm_t *); +void ec_fsm_sii_read_check(ec_fsm_t *); +void ec_fsm_sii_read_fetch(ec_fsm_t *); +void ec_fsm_sii_start_writing(ec_fsm_t *); +void ec_fsm_sii_write_check(ec_fsm_t *); +void ec_fsm_sii_write_check2(ec_fsm_t *); void ec_fsm_sii_end(ec_fsm_t *); void ec_fsm_sii_error(ec_fsm_t *); @@ -406,7 +410,25 @@ return; } - // nothing to configure. restart master state machine. + if (master->mode == EC_MASTER_MODE_FREERUN) { + // nothing to configure. check for pending EEPROM write operations. + list_for_each_entry(slave, &master->slaves, list) { + if (!slave->new_eeprom_data) continue; + + // found pending EEPROM write operation. execute it! + EC_INFO("Writing EEPROM of slave %i...\n", slave->ring_position); + fsm->sii_offset = 0x0000; + memcpy(fsm->sii_value, slave->new_eeprom_data, 2); + fsm->sii_mode = 1; + fsm->sii_state = ec_fsm_sii_start_writing; + fsm->slave = slave; + fsm->master_state = ec_fsm_master_eeprom; + fsm->master_state(fsm); // execute immediately + return; + } + } + + // nothing to do. restart master state machine. fsm->master_state = ec_fsm_master_start; fsm->master_state(fsm); // execute immediately } @@ -434,7 +456,7 @@ if (fsm->sii_state != ec_fsm_sii_end) return; - if (EC_READ_U32(fsm->sii_result) != slave->sii_vendor_id) { + if (EC_READ_U32(fsm->sii_value) != 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 @@ -472,10 +494,10 @@ if (fsm->sii_state != ec_fsm_sii_end) return; - if (EC_READ_U32(fsm->sii_result) != slave->sii_product_code) { + if (EC_READ_U32(fsm->sii_value) != 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, - EC_READ_U32(fsm->sii_result)); + EC_READ_U32(fsm->sii_value)); fsm->master_state = ec_fsm_master_start; fsm->master_state(fsm); // execute immediately return; @@ -666,6 +688,49 @@ fsm->master_state(fsm); // execute immediately } +/*****************************************************************************/ + +/** + Master state: EEPROM. +*/ + +void ec_fsm_master_eeprom(ec_fsm_t *fsm /**< finite state machine */) +{ + ec_slave_t *slave = fsm->slave; + + fsm->sii_state(fsm); // execute SII state machine + + if (fsm->sii_state == ec_fsm_sii_error) { + EC_ERR("Failed to write EEPROM contents to slave %i.\n", + slave->ring_position); + kfree(slave->new_eeprom_data); + slave->new_eeprom_data = NULL; + fsm->master_state = ec_fsm_master_start; + fsm->master_state(fsm); // execute immediately + return; + } + + if (fsm->sii_state != ec_fsm_sii_end) return; + + fsm->sii_offset++; + if (fsm->sii_offset < slave->new_eeprom_size) { + memcpy(fsm->sii_value, slave->new_eeprom_data + fsm->sii_offset, 2); + fsm->sii_state = ec_fsm_sii_start_writing; + fsm->sii_state(fsm); // execute immediately + return; + } + + // finished writing EEPROM + EC_INFO("Finished writing EEPROM of slave %i.\n", slave->ring_position); + kfree(slave->new_eeprom_data); + slave->new_eeprom_data = NULL; + + // restart master state machine. + fsm->master_state = ec_fsm_master_start; + fsm->master_state(fsm); // execute immediately + return; +} + /****************************************************************************** * slave state machine *****************************************************************************/ @@ -834,8 +899,8 @@ if (fsm->sii_state != ec_fsm_sii_end) return; - cat_type = EC_READ_U16(fsm->sii_result); - cat_size = EC_READ_U16(fsm->sii_result + 2); + cat_type = EC_READ_U16(fsm->sii_value); + cat_size = EC_READ_U16(fsm->sii_value + 2); if (cat_type != 0xFFFF) { // not the last category fsm->sii_offset += cat_size + 2; @@ -895,10 +960,10 @@ // 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); + memcpy(slave->eeprom_data + fsm->sii_offset * 2, fsm->sii_value, 4); } else { // copy the last word - memcpy(slave->eeprom_data + fsm->sii_offset * 2, fsm->sii_result, 2); + memcpy(slave->eeprom_data + fsm->sii_offset * 2, fsm->sii_value, 2); } if (fsm->sii_offset + 2 < slave->eeprom_size / 2) { @@ -1305,17 +1370,17 @@ EC_WRITE_U8 (command->data + 1, 0x01); // request read operation EC_WRITE_U16(command->data + 2, fsm->sii_offset); ec_master_queue_command(fsm->master, command); - fsm->sii_state = ec_fsm_sii_check; -} - -/*****************************************************************************/ - -/** - SII state: CHECK. + fsm->sii_state = ec_fsm_sii_read_check; +} + +/*****************************************************************************/ + +/** + SII state: READ_CHECK. Checks, if the SII-read-command has been sent and issues a fetch command. */ -void ec_fsm_sii_check(ec_fsm_t *fsm /**< finite state machine */) +void ec_fsm_sii_read_check(ec_fsm_t *fsm /**< finite state machine */) { ec_command_t *command = &fsm->command; @@ -1336,17 +1401,17 @@ } ec_master_queue_command(fsm->master, command); - fsm->sii_state = ec_fsm_sii_fetch; -} - -/*****************************************************************************/ - -/** - SII state: FETCH. + fsm->sii_state = ec_fsm_sii_read_fetch; +} + +/*****************************************************************************/ + +/** + SII state: READ_FETCH. Fetches the result of an SII-read command. */ -void ec_fsm_sii_fetch(ec_fsm_t *fsm /**< finite state machine */) +void ec_fsm_sii_read_fetch(ec_fsm_t *fsm /**< finite state machine */) { ec_command_t *command = &fsm->command; @@ -1391,13 +1456,93 @@ #endif // SII value received. - memcpy(fsm->sii_result, command->data + 6, 4); + memcpy(fsm->sii_value, command->data + 6, 4); fsm->sii_state = ec_fsm_sii_end; } /*****************************************************************************/ /** + SII state: START_WRITING. + Starts reading the slave information interface. +*/ + +void ec_fsm_sii_start_writing(ec_fsm_t *fsm /**< finite state machine */) +{ + ec_command_t *command = &fsm->command; + + // initiate write operation + ec_command_npwr(command, fsm->slave->station_address, 0x502, 8); + EC_WRITE_U8 (command->data, 0x01); // enable write access + EC_WRITE_U8 (command->data + 1, 0x02); // request write operation + EC_WRITE_U32(command->data + 2, fsm->sii_offset); + memcpy(command->data + 6, fsm->sii_value, 2); + ec_master_queue_command(fsm->master, command); + fsm->sii_state = ec_fsm_sii_write_check; +} + +/*****************************************************************************/ + +/** + SII state: WRITE_CHECK. +*/ + +void ec_fsm_sii_write_check(ec_fsm_t *fsm /**< finite state machine */) +{ + ec_command_t *command = &fsm->command; + + if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { + EC_ERR("SII: Reception of write command failed.\n"); + fsm->sii_state = ec_fsm_sii_error; + return; + } + + fsm->sii_start = get_cycles(); + + // issue check/fetch command + ec_command_nprd(command, fsm->slave->station_address, 0x502, 2); + ec_master_queue_command(fsm->master, command); + fsm->sii_state = ec_fsm_sii_write_check2; +} + +/*****************************************************************************/ + +/** + SII state: WRITE_CHECK2. +*/ + +void ec_fsm_sii_write_check2(ec_fsm_t *fsm /**< finite state machine */) +{ + ec_command_t *command = &fsm->command; + + if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { + EC_ERR("SII: Reception of write check command failed.\n"); + fsm->sii_state = ec_fsm_sii_error; + return; + } + + if (EC_READ_U8(command->data + 1) & 0x82) { + // still busy... timeout? + if (get_cycles() - fsm->sii_start >= (cycles_t) 10 * cpu_khz) { + EC_ERR("SII: Write timeout.\n"); + fsm->sii_state = ec_fsm_sii_error; + } + + // issue check/fetch command again + ec_master_queue_command(fsm->master, command); + } + else if (EC_READ_U8(command->data + 1) & 0x40) { + EC_ERR("SII: Write operation failed!\n"); + fsm->sii_state = ec_fsm_sii_error; + } + else { // success + fsm->sii_state = ec_fsm_sii_end; + } +} + +/*****************************************************************************/ + +/** SII state: END. End state of the slave SII state machine. */ diff -r 4f9c149fb71f -r a03be9a6fed6 master/fsm.h --- a/master/fsm.h Fri Jun 02 12:01:47 2006 +0000 +++ b/master/fsm.h Fri Jun 02 14:25:45 2006 +0000 @@ -71,7 +71,7 @@ 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) */ - uint8_t sii_result[4]; /**< output: raw SII value (32bit) */ + uint8_t sii_value[4]; /**< raw SII value (32bit) */ cycles_t sii_start; /**< sii start */ void (*change_state)(ec_fsm_t *); /**< slave state change state function */ diff -r 4f9c149fb71f -r a03be9a6fed6 master/slave.c --- a/master/slave.c Fri Jun 02 12:01:47 2006 +0000 +++ b/master/slave.c Fri Jun 02 14:25:45 2006 +0000 @@ -69,7 +69,7 @@ EC_SYSFS_READ_ATTR(sii_name); EC_SYSFS_READ_ATTR(type); EC_SYSFS_READ_WRITE_ATTR(state); -EC_SYSFS_READ_ATTR(eeprom); +EC_SYSFS_READ_WRITE_ATTR(eeprom); static struct attribute *def_attrs[] = { &attr_ring_position, @@ -157,6 +157,8 @@ slave->current_state = EC_SLAVE_STATE_UNKNOWN; slave->state_error = 0; slave->online = 1; + slave->new_eeprom_data = NULL; + slave->new_eeprom_size = 0; ec_command_init(&slave->mbox_command); @@ -239,6 +241,7 @@ } if (slave->eeprom_data) kfree(slave->eeprom_data); + if (slave->new_eeprom_data) kfree(slave->new_eeprom_data); ec_command_clear(&slave->mbox_command); } @@ -1247,6 +1250,83 @@ /*****************************************************************************/ /** + Schedules an EEPROM write operation. + \return 0 in case of success, else < 0 +*/ + +ssize_t ec_slave_write_eeprom(ec_slave_t *slave, /**< EtherCAT slave */ + const uint8_t *data, /**< new EEPROM data */ + size_t size /**< size of data in bytes */ + ) +{ + uint16_t word_size, cat_type, cat_size; + const uint16_t *data_words, *next_header; + uint16_t *new_data; + + if (!slave->master->eeprom_write_enable) { + EC_ERR("Writing EEPROMs not allowed! Enable via" + " eeprom_write_enable SysFS entry.\n"); + return -1; + } + + if (slave->master->mode != EC_MASTER_MODE_FREERUN) { + EC_ERR("Writing EEPROMs only allowed in freerun mode!\n"); + return -1; + } + + if (slave->new_eeprom_data) { + EC_ERR("Slave %i already has a pending EEPROM write operation!\n", + slave->ring_position); + return -1; + } + + // coarse check of the data + + if (size % 2) { + EC_ERR("EEPROM size is odd! Dropping.\n"); + return -1; + } + + data_words = (const uint16_t *) data; + word_size = size / 2; + + if (word_size < 0x0041) { + EC_ERR("EEPROM data too short! Dropping.\n"); + return -1; + } + + next_header = data_words + 0x0040; + cat_type = EC_READ_U16(next_header); + while (cat_type != 0xFFFF) { + cat_type = EC_READ_U16(next_header); + cat_size = EC_READ_U16(next_header + 1); + if ((next_header + cat_size + 2) - data_words >= word_size) { + EC_ERR("EEPROM data seems to be corrupted! Dropping.\n"); + return -1; + } + next_header += cat_size + 2; + cat_type = EC_READ_U16(next_header); + } + + // data ok! + + if (!(new_data = (uint16_t *) kmalloc(word_size * 2, GFP_KERNEL))) { + EC_ERR("Unable to allocate memory for new EEPROM data!\n"); + return -1; + } + memcpy(new_data, data, size); + + slave->new_eeprom_size = word_size; + slave->new_eeprom_data = new_data; + + EC_INFO("EEPROM writing scheduled for slave %i, %i words.\n", + slave->ring_position, word_size); + return 0; +} + +/*****************************************************************************/ + +/** Formats attribute data for SysFS read access. \return number of bytes to read */ @@ -1359,6 +1439,10 @@ EC_ERR("Failed to set slave state!\n"); } + else if (attr == &attr_eeprom) { + if (!ec_slave_write_eeprom(slave, buffer, size)) + return size; + } return -EINVAL; } diff -r 4f9c149fb71f -r a03be9a6fed6 master/slave.h --- a/master/slave.h Fri Jun 02 12:01:47 2006 +0000 +++ b/master/slave.h Fri Jun 02 14:25:45 2006 +0000 @@ -271,6 +271,9 @@ char *eeprom_order; /**< slave order number acc. to EEPROM */ char *eeprom_name; /**< slave name acc. to EEPROM */ + uint16_t *new_eeprom_data; /**< new EEPROM data to write */ + size_t new_eeprom_size; /**< size of new EEPROM data in words */ + struct list_head sdo_dictionary; /**< SDO directory list */ ec_command_t mbox_command; /**< mailbox command */