diff -r 60b2aad9d40b -r 1cc865ba17c2 master/slave.c --- a/master/slave.c Fri Oct 13 10:07:10 2006 +0000 +++ b/master/slave.c Tue Nov 07 12:13:30 2006 +0000 @@ -52,6 +52,8 @@ /*****************************************************************************/ +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); @@ -82,6 +84,10 @@ .default_attrs = def_attrs }; +static struct kobj_type ktype_ec_slave_sdos = { + .release = ec_slave_sdos_clear +}; + /** \endcond */ /*****************************************************************************/ @@ -102,25 +108,14 @@ slave->ring_position = ring_position; slave->station_address = station_address; - // init kobject and add it to the hierarchy - memset(&slave->kobj, 0x00, sizeof(struct kobject)); - kobject_init(&slave->kobj); - slave->kobj.ktype = &ktype_ec_slave; - slave->kobj.parent = &master->kobj; - if (kobject_set_name(&slave->kobj, "slave%03i", slave->ring_position)) { - EC_ERR("Failed to set kobject name.\n"); - kobject_put(&slave->kobj); - return -1; - } - slave->master = master; slave->requested_state = EC_SLAVE_STATE_UNKNOWN; slave->current_state = EC_SLAVE_STATE_UNKNOWN; + slave->configured = 0; slave->error_flag = 0; slave->online = 1; slave->fmmu_count = 0; - slave->registered = 0; slave->coupler_index = 0; slave->coupler_subindex = 0xFFFF; @@ -156,7 +151,9 @@ INIT_LIST_HEAD(&slave->sii_pdos); INIT_LIST_HEAD(&slave->sdo_dictionary); INIT_LIST_HEAD(&slave->sdo_confs); - INIT_LIST_HEAD(&slave->varsize_fields); + + slave->sdo_dictionary_fetched = 0; + slave->jiffies_preop = 0; for (i = 0; i < 4; i++) { slave->dl_link[i] = 0; @@ -165,13 +162,76 @@ slave->sii_physical_layer[i] = 0xFF; } + // init kobject and add it to the hierarchy + memset(&slave->kobj, 0x00, sizeof(struct kobject)); + kobject_init(&slave->kobj); + slave->kobj.ktype = &ktype_ec_slave; + slave->kobj.parent = &master->kobj; + if (kobject_set_name(&slave->kobj, "slave%03i", slave->ring_position)) { + EC_ERR("Failed to set kobject name.\n"); + goto out_slave_put; + } + if (kobject_add(&slave->kobj)) { + EC_ERR("Failed to add slave's kobject.\n"); + goto out_slave_put; + } + + // init SDO kobject and add it to the hierarchy + memset(&slave->sdo_kobj, 0x00, sizeof(struct kobject)); + kobject_init(&slave->sdo_kobj); + slave->sdo_kobj.ktype = &ktype_ec_slave_sdos; + slave->sdo_kobj.parent = &slave->kobj; + if (kobject_set_name(&slave->sdo_kobj, "sdos")) { + EC_ERR("Failed to set kobject name.\n"); + goto out_sdo_put; + } + if (kobject_add(&slave->sdo_kobj)) { + EC_ERR("Failed to add SDOs kobject.\n"); + goto out_sdo_put; + } + return 0; + + out_sdo_put: + kobject_put(&slave->sdo_kobj); + kobject_del(&slave->kobj); + out_slave_put: + kobject_put(&slave->kobj); + return -1; } /*****************************************************************************/ /** Slave destructor. + Clears and frees a slave object. +*/ + +void ec_slave_destroy(ec_slave_t *slave /**< EtherCAT slave */) +{ + ec_sdo_t *sdo, *next_sdo; + + // free all SDOs + list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) { + list_del(&sdo->list); + ec_sdo_destroy(sdo); + } + + // free SDO kobject + kobject_del(&slave->sdo_kobj); + kobject_put(&slave->sdo_kobj); + + // destroy self + kobject_del(&slave->kobj); + kobject_put(&slave->kobj); +} + +/*****************************************************************************/ + +/** + Clear and free slave. + This method is called by the kobject, + once there are no more references to it. */ void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */) @@ -181,10 +241,7 @@ ec_sii_sync_t *sync, *next_sync; ec_sii_pdo_t *pdo, *next_pdo; ec_sii_pdo_entry_t *entry, *next_ent; - ec_sdo_t *sdo, *next_sdo; - ec_sdo_entry_t *en, *next_en; ec_sdo_data_t *sdodata, *next_sdodata; - ec_varsize_t *var, *next_var; slave = container_of(kobj, ec_slave_t, kobj); @@ -220,19 +277,6 @@ if (slave->sii_order) kfree(slave->sii_order); if (slave->sii_name) kfree(slave->sii_name); - // free all SDOs - list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) { - list_del(&sdo->list); - if (sdo->name) kfree(sdo->name); - - // free all SDO entries - list_for_each_entry_safe(en, next_en, &sdo->entries, list) { - list_del(&en->list); - kfree(en); - } - kfree(sdo); - } - // free all SDO configurations list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) { list_del(&sdodata->list); @@ -240,14 +284,59 @@ kfree(sdodata); } - // free information about variable sized data fields - list_for_each_entry_safe(var, next_var, &slave->varsize_fields, list) { - list_del(&var->list); - kfree(var); - } - if (slave->eeprom_data) kfree(slave->eeprom_data); if (slave->new_eeprom_data) kfree(slave->new_eeprom_data); + + kfree(slave); +} + +/*****************************************************************************/ + +/** +*/ + +void ec_slave_sdos_clear(struct kobject *kobj /**< kobject for SDOs */) +{ +} + +/*****************************************************************************/ + +/** + Reset slave from operation mode. +*/ + +void ec_slave_reset(ec_slave_t *slave /**< EtherCAT slave */) +{ + ec_sdo_data_t *sdodata, *next_sdodata; + ec_sii_sync_t *sync; + + // remove FMMU configurations + slave->fmmu_count = 0; + + // free all SDO configurations + list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) { + list_del(&sdodata->list); + kfree(sdodata->data); + kfree(sdodata); + } + + // remove estimated sync manager sizes + list_for_each_entry(sync, &slave->sii_syncs, list) { + sync->est_length = 0; + } +} + +/*****************************************************************************/ + +/** + */ + +void ec_slave_request_state(ec_slave_t *slave, /**< ETherCAT slave */ + ec_slave_state_t state /**< new state */ + ) +{ + slave->requested_state = state; + slave->error_flag = 0; } /*****************************************************************************/ @@ -341,6 +430,8 @@ sync->control_register = EC_READ_U8 (data + 4); sync->enable = EC_READ_U8 (data + 6); + sync->est_length = 0; + list_add_tail(&sync->list, &slave->sii_syncs); } @@ -445,7 +536,9 @@ return 0; } - EC_WARN("String %i not found in slave %i.\n", index, slave->ring_position); + if (slave->master->debug_level) + EC_WARN("String %i not found in slave %i.\n", + index, slave->ring_position); err_string = "(string not found)"; @@ -478,11 +571,14 @@ ) { unsigned int i; + ec_fmmu_t *fmmu; // FMMU configuration already prepared? - for (i = 0; i < slave->fmmu_count; i++) - if (slave->fmmus[i].domain == domain && slave->fmmus[i].sync == sync) + for (i = 0; i < slave->fmmu_count; i++) { + fmmu = &slave->fmmus[i]; + if (fmmu->domain == domain && fmmu->sync == sync) return 0; + } // reserve new FMMU... @@ -491,11 +587,14 @@ return -1; } - slave->fmmus[slave->fmmu_count].domain = domain; - slave->fmmus[slave->fmmu_count].sync = sync; - slave->fmmus[slave->fmmu_count].logical_start_address = 0; + fmmu = &slave->fmmus[slave->fmmu_count]; + + fmmu->index = slave->fmmu_count; + fmmu->domain = domain; + fmmu->sync = sync; + fmmu->logical_start_address = 0; + slave->fmmu_count++; - slave->registered = 1; return 0; } @@ -515,6 +614,8 @@ ec_sii_pdo_t *pdo; ec_sii_pdo_entry_t *pdo_entry; int first, i; + ec_sdo_data_t *sdodata; + char str[20]; off += sprintf(buffer + off, "\nName: "); @@ -528,7 +629,10 @@ off += sprintf(buffer + off, "State: "); off += ec_state_string(slave->current_state, buffer + off); - off += sprintf(buffer + off, "\nRing position: %i\n", + off += sprintf(buffer + off, "\nFlags: %s, %s\n", + slave->online ? "online" : "OFFLINE", + slave->error_flag ? "ERROR" : "ok"); + off += sprintf(buffer + off, "Ring position: %i\n", slave->ring_position); off += sprintf(buffer + off, "Advanced position: %i:%i\n", slave->coupler_index, slave->coupler_subindex); @@ -643,6 +747,20 @@ } } + if (!list_empty(&slave->sdo_confs)) + off += sprintf(buffer + off, "\nSDO configurations:\n"); + + list_for_each_entry(sdodata, &slave->sdo_confs, list) { + switch (sdodata->size) { + case 1: sprintf(str, "%i", EC_READ_U8(sdodata->data)); break; + case 2: sprintf(str, "%i", EC_READ_U16(sdodata->data)); break; + case 4: sprintf(str, "%i", EC_READ_U32(sdodata->data)); break; + default: sprintf(str, "(invalid size)"); break; + } + off += sprintf(buffer + off, " 0x%04X:%-3i -> %s\n", + sdodata->index, sdodata->subindex, str); + } + off += sprintf(buffer + off, "\n"); return off; @@ -789,15 +907,15 @@ ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj); if (attr == &attr_state) { - char state[25]; + char state[EC_STATE_STRING_SIZE]; if (!strcmp(buffer, "INIT\n")) - slave->requested_state = EC_SLAVE_STATE_INIT; + ec_slave_request_state(slave, EC_SLAVE_STATE_INIT); else if (!strcmp(buffer, "PREOP\n")) - slave->requested_state = EC_SLAVE_STATE_PREOP; + ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP); else if (!strcmp(buffer, "SAVEOP\n")) - slave->requested_state = EC_SLAVE_STATE_SAVEOP; + ec_slave_request_state(slave, EC_SLAVE_STATE_SAVEOP); else if (!strcmp(buffer, "OP\n")) - slave->requested_state = EC_SLAVE_STATE_OP; + ec_slave_request_state(slave, EC_SLAVE_STATE_OP); else { EC_ERR("Invalid slave state \"%s\"!\n", buffer); return -EINVAL; @@ -806,7 +924,6 @@ ec_state_string(slave->requested_state, state); EC_INFO("Accepted new state %s for slave %i.\n", state, slave->ring_position); - slave->error_flag = 0; return size; } else if (attr == &attr_eeprom) { @@ -832,9 +949,10 @@ { ec_sii_pdo_t *pdo; ec_sii_pdo_entry_t *pdo_entry; - unsigned int bit_size; + unsigned int bit_size, byte_size; if (sync->length) return sync->length; + if (sync->est_length) return sync->est_length; bit_size = 0; list_for_each_entry(pdo, &slave->sii_pdos, list) { @@ -846,9 +964,11 @@ } if (bit_size % 8) // round up to full bytes - return bit_size / 8 + 1; + byte_size = bit_size / 8 + 1; else - return bit_size / 8; + byte_size = bit_size / 8; + + return byte_size; } /*****************************************************************************/ @@ -873,7 +993,7 @@ int ec_slave_has_subbus(const ec_slave_t *slave /**< EtherCAT slave */) { return slave->sii_vendor_id == 0x00000002 - && slave->sii_product_code == 0x13ED3052; + && slave->sii_product_code == 0x04602c22; } /*****************************************************************************/ @@ -917,6 +1037,54 @@ return 0; } +/*****************************************************************************/ + +/** + \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 %i - Requested: 0x%08X 0x%08X," + " found: 0x%08X 0x%08X\".\n", slave->ring_position, vendor_id, + product_code, slave->sii_vendor_id, slave->sii_product_code); + return -1; + } + return 0; +} + +/*****************************************************************************/ + +/** + 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; +} + /****************************************************************************** * Realtime interface *****************************************************************************/