fp@39: /****************************************************************************** fp@0: * fp@39: * $Id$ fp@0: * fp@197: * Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH fp@197: * fp@197: * This file is part of the IgH EtherCAT Master. fp@197: * fp@197: * The IgH EtherCAT Master is free software; you can redistribute it fp@197: * and/or modify it under the terms of the GNU General Public License fp@246: * as published by the Free Software Foundation; either version 2 of the fp@246: * License, or (at your option) any later version. fp@197: * fp@197: * The IgH EtherCAT Master is distributed in the hope that it will be fp@197: * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of fp@197: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the fp@197: * GNU General Public License for more details. fp@197: * fp@197: * You should have received a copy of the GNU General Public License fp@197: * along with the IgH EtherCAT Master; if not, write to the Free Software fp@197: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@197: * fp@246: * The right to use EtherCAT Technology is granted and comes free of fp@246: * charge under condition of compatibility of product made by fp@246: * Licensee. People intending to distribute/sell products based on the fp@246: * code, have to sign an agreement to guarantee that products using fp@246: * software based on IgH EtherCAT master stay compatible with the actual fp@246: * EtherCAT specification (which are released themselves as an open fp@246: * standard) as the (only) precondition to have the right to use EtherCAT fp@246: * Technology, IP and trade marks. fp@246: * fp@39: *****************************************************************************/ fp@0: fp@199: /** fp@199: \file fp@199: EtherCAT slave methods. fp@199: */ fp@199: fp@199: /*****************************************************************************/ fp@199: fp@24: #include fp@73: #include fp@0: fp@54: #include "globals.h" fp@54: #include "slave.h" fp@293: #include "datagram.h" fp@98: #include "master.h" fp@0: fp@39: /*****************************************************************************/ fp@0: fp@251: extern const ec_code_msg_t al_status_messages[]; fp@251: fp@251: /*****************************************************************************/ fp@251: fp@118: int ec_slave_fetch_categories(ec_slave_t *); fp@182: ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *); fp@256: ssize_t ec_store_slave_attribute(struct kobject *, struct attribute *, fp@256: const char *, size_t); fp@182: fp@182: /*****************************************************************************/ fp@182: fp@199: /** \cond */ fp@199: fp@184: EC_SYSFS_READ_ATTR(ring_position); fp@188: EC_SYSFS_READ_ATTR(coupler_address); fp@184: EC_SYSFS_READ_ATTR(vendor_name); fp@184: EC_SYSFS_READ_ATTR(product_name); fp@184: EC_SYSFS_READ_ATTR(product_desc); fp@264: EC_SYSFS_READ_ATTR(sii_name); fp@185: EC_SYSFS_READ_ATTR(type); fp@256: EC_SYSFS_READ_WRITE_ATTR(state); fp@269: EC_SYSFS_READ_WRITE_ATTR(eeprom); fp@182: fp@182: static struct attribute *def_attrs[] = { fp@182: &attr_ring_position, fp@188: &attr_coupler_address, fp@183: &attr_vendor_name, fp@183: &attr_product_name, fp@183: &attr_product_desc, fp@264: &attr_sii_name, fp@185: &attr_type, fp@256: &attr_state, fp@266: &attr_eeprom, fp@182: NULL, fp@182: }; fp@182: fp@182: static struct sysfs_ops sysfs_ops = { fp@256: .show = ec_show_slave_attribute, fp@256: .store = ec_store_slave_attribute fp@182: }; fp@182: fp@182: static struct kobj_type ktype_ec_slave = { fp@182: .release = ec_slave_clear, fp@182: .sysfs_ops = &sysfs_ops, fp@182: .default_attrs = def_attrs fp@182: }; fp@118: fp@199: /** \endcond */ fp@199: fp@118: /*****************************************************************************/ fp@118: fp@0: /** fp@195: Slave constructor. fp@195: \return 0 in case of success, else < 0 fp@195: */ fp@195: fp@195: int ec_slave_init(ec_slave_t *slave, /**< EtherCAT slave */ fp@195: ec_master_t *master, /**< EtherCAT master */ fp@195: uint16_t ring_position, /**< ring position */ fp@195: uint16_t station_address /**< station address to configure */ fp@182: ) fp@73: { fp@142: unsigned int i; fp@142: fp@182: slave->ring_position = ring_position; fp@182: slave->station_address = station_address; fp@182: fp@195: // init kobject and add it to the hierarchy fp@182: memset(&slave->kobj, 0x00, sizeof(struct kobject)); fp@182: kobject_init(&slave->kobj); fp@182: slave->kobj.ktype = &ktype_ec_slave; fp@182: slave->kobj.parent = &master->kobj; fp@182: if (kobject_set_name(&slave->kobj, "slave%03i", slave->ring_position)) { fp@182: EC_ERR("Failed to set kobject name.\n"); fp@182: kobject_put(&slave->kobj); fp@182: return -1; fp@182: } fp@182: fp@73: slave->master = master; fp@188: slave->coupler_index = 0; fp@188: slave->coupler_subindex = 0xFFFF; fp@73: slave->base_type = 0; fp@73: slave->base_revision = 0; fp@73: slave->base_build = 0; fp@73: slave->base_fmmu_count = 0; fp@73: slave->base_sync_count = 0; fp@114: slave->sii_alias = 0; fp@73: slave->sii_vendor_id = 0; fp@73: slave->sii_product_code = 0; fp@73: slave->sii_revision_number = 0; fp@73: slave->sii_serial_number = 0; fp@136: slave->sii_rx_mailbox_offset = 0; fp@136: slave->sii_rx_mailbox_size = 0; fp@136: slave->sii_tx_mailbox_offset = 0; fp@136: slave->sii_tx_mailbox_size = 0; fp@133: slave->sii_mailbox_protocols = 0; fp@73: slave->type = NULL; fp@73: slave->registered = 0; fp@73: slave->fmmu_count = 0; fp@266: slave->eeprom_data = NULL; fp@266: slave->eeprom_size = 0; fp@264: slave->eeprom_group = NULL; fp@264: slave->eeprom_image = NULL; fp@264: slave->eeprom_order = NULL; fp@121: slave->eeprom_name = NULL; fp@251: slave->requested_state = EC_SLAVE_STATE_UNKNOWN; fp@251: slave->current_state = EC_SLAVE_STATE_UNKNOWN; fp@291: slave->error_flag = 0; fp@260: slave->online = 1; fp@269: slave->new_eeprom_data = NULL; fp@269: slave->new_eeprom_size = 0; fp@145: fp@126: INIT_LIST_HEAD(&slave->eeprom_strings); fp@126: INIT_LIST_HEAD(&slave->eeprom_syncs); fp@126: INIT_LIST_HEAD(&slave->eeprom_pdos); fp@135: INIT_LIST_HEAD(&slave->sdo_dictionary); fp@275: INIT_LIST_HEAD(&slave->varsize_fields); fp@145: fp@183: for (i = 0; i < 4; i++) { fp@183: slave->dl_link[i] = 0; fp@183: slave->dl_loop[i] = 0; fp@183: slave->dl_signal[i] = 0; fp@190: slave->sii_physical_layer[i] = 0xFF; fp@145: } fp@182: fp@182: return 0; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@195: Slave destructor. fp@195: */ fp@195: fp@195: void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */) fp@182: { fp@182: ec_slave_t *slave; fp@126: ec_eeprom_string_t *string, *next_str; fp@126: ec_eeprom_sync_t *sync, *next_sync; fp@126: ec_eeprom_pdo_t *pdo, *next_pdo; fp@126: ec_eeprom_pdo_entry_t *entry, *next_ent; fp@157: ec_sdo_t *sdo, *next_sdo; fp@157: ec_sdo_entry_t *en, *next_en; fp@275: ec_varsize_t *var, *next_var; fp@118: fp@182: slave = container_of(kobj, ec_slave_t, kobj); fp@182: fp@195: // free all string objects fp@126: list_for_each_entry_safe(string, next_str, &slave->eeprom_strings, list) { fp@118: list_del(&string->list); fp@118: kfree(string); fp@118: } fp@121: fp@195: // free all sync managers fp@126: list_for_each_entry_safe(sync, next_sync, &slave->eeprom_syncs, list) { fp@126: list_del(&sync->list); fp@126: kfree(sync); fp@126: } fp@126: fp@195: // free all PDOs fp@126: list_for_each_entry_safe(pdo, next_pdo, &slave->eeprom_pdos, list) { fp@126: list_del(&pdo->list); fp@126: if (pdo->name) kfree(pdo->name); fp@126: fp@195: // free all PDO entries fp@126: list_for_each_entry_safe(entry, next_ent, &pdo->entries, list) { fp@126: list_del(&entry->list); fp@126: if (entry->name) kfree(entry->name); fp@126: kfree(entry); fp@126: } fp@126: fp@126: kfree(pdo); fp@126: } fp@126: fp@264: if (slave->eeprom_group) kfree(slave->eeprom_group); fp@264: if (slave->eeprom_image) kfree(slave->eeprom_image); fp@264: if (slave->eeprom_order) kfree(slave->eeprom_order); fp@121: if (slave->eeprom_name) kfree(slave->eeprom_name); fp@135: fp@195: // free all SDOs fp@135: list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) { fp@135: list_del(&sdo->list); fp@135: if (sdo->name) kfree(sdo->name); fp@161: fp@195: // free all SDO entries fp@139: list_for_each_entry_safe(en, next_en, &sdo->entries, list) { fp@139: list_del(&en->list); fp@139: kfree(en); fp@139: } fp@135: kfree(sdo); fp@135: } fp@145: fp@275: // free information about variable sized data fields fp@275: list_for_each_entry_safe(var, next_var, &slave->varsize_fields, list) { fp@275: list_del(&var->list); fp@275: kfree(var); fp@275: } fp@275: fp@266: if (slave->eeprom_data) kfree(slave->eeprom_data); fp@269: if (slave->new_eeprom_data) kfree(slave->new_eeprom_data); fp@121: } fp@121: fp@121: /*****************************************************************************/ fp@121: fp@121: /** fp@195: Reads all necessary information from a slave. fp@195: \return 0 in case of success, else < 0 fp@195: */ fp@195: fp@195: int ec_slave_fetch(ec_slave_t *slave /**< EtherCAT slave */) fp@73: { fp@293: ec_datagram_t *datagram; fp@142: unsigned int i; fp@142: uint16_t dl_status; fp@73: fp@293: datagram = &slave->master->simple_datagram; fp@144: fp@195: // read base data fp@293: if (ec_datagram_nprd(datagram, slave->station_address, 0x0000, 6)) fp@293: return -1; fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@142: EC_ERR("Reading base data from slave %i failed!\n", fp@84: slave->ring_position); fp@73: return -1; fp@73: } fp@73: fp@293: slave->base_type = EC_READ_U8 (datagram->data); fp@293: slave->base_revision = EC_READ_U8 (datagram->data + 1); fp@293: slave->base_build = EC_READ_U16(datagram->data + 2); fp@293: slave->base_fmmu_count = EC_READ_U8 (datagram->data + 4); fp@293: slave->base_sync_count = EC_READ_U8 (datagram->data + 5); fp@73: fp@73: if (slave->base_fmmu_count > EC_MAX_FMMUS) fp@73: slave->base_fmmu_count = EC_MAX_FMMUS; fp@73: fp@195: // read data link status fp@293: if (ec_datagram_nprd(datagram, slave->station_address, 0x0110, 2)) fp@293: return -1; fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@142: EC_ERR("Reading DL status from slave %i failed!\n", fp@142: slave->ring_position); fp@142: return -1; fp@142: } fp@142: fp@293: dl_status = EC_READ_U16(datagram->data); fp@183: for (i = 0; i < 4; i++) { fp@183: slave->dl_link[i] = dl_status & (1 << (4 + i)) ? 1 : 0; fp@183: slave->dl_loop[i] = dl_status & (1 << (8 + i * 2)) ? 1 : 0; fp@183: slave->dl_signal[i] = dl_status & (1 << (9 + i * 2)) ? 1 : 0; fp@142: } fp@142: fp@195: // read EEPROM data fp@136: if (ec_slave_sii_read16(slave, 0x0004, &slave->sii_alias)) fp@136: return -1; fp@136: if (ec_slave_sii_read32(slave, 0x0008, &slave->sii_vendor_id)) fp@136: return -1; fp@136: if (ec_slave_sii_read32(slave, 0x000A, &slave->sii_product_code)) fp@136: return -1; fp@136: if (ec_slave_sii_read32(slave, 0x000C, &slave->sii_revision_number)) fp@136: return -1; fp@136: if (ec_slave_sii_read32(slave, 0x000E, &slave->sii_serial_number)) fp@136: return -1; fp@136: if (ec_slave_sii_read16(slave, 0x0018, &slave->sii_rx_mailbox_offset)) fp@136: return -1; fp@136: if (ec_slave_sii_read16(slave, 0x0019, &slave->sii_rx_mailbox_size)) fp@136: return -1; fp@136: if (ec_slave_sii_read16(slave, 0x001A, &slave->sii_tx_mailbox_offset)) fp@136: return -1; fp@136: if (ec_slave_sii_read16(slave, 0x001B, &slave->sii_tx_mailbox_size)) fp@136: return -1; fp@136: if (ec_slave_sii_read16(slave, 0x001C, &slave->sii_mailbox_protocols)) fp@136: return -1; fp@133: fp@118: if (unlikely(ec_slave_fetch_categories(slave))) { fp@136: EC_ERR("Failed to fetch category data!\n"); fp@118: return -1; fp@118: } fp@118: fp@73: return 0; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@195: Reads 16 bit from the slave information interface (SII). fp@195: \return 0 in case of success, else < 0 fp@73: */ fp@73: fp@136: int ec_slave_sii_read16(ec_slave_t *slave, fp@195: /**< EtherCAT slave */ fp@136: uint16_t offset, fp@195: /**< address of the SII register to read */ fp@136: uint16_t *target fp@195: /**< target memory */ fp@136: ) fp@73: { fp@293: ec_datagram_t *datagram; fp@98: cycles_t start, end, timeout; fp@73: fp@293: datagram = &slave->master->simple_datagram; fp@144: fp@195: // initiate read operation fp@293: if (ec_datagram_npwr(datagram, slave->station_address, 0x502, 6)) fp@293: return -1; fp@293: EC_WRITE_U8 (datagram->data, 0x00); // read-only access fp@293: EC_WRITE_U8 (datagram->data + 1, 0x01); // request read operation fp@293: EC_WRITE_U32(datagram->data + 2, offset); fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@89: EC_ERR("SII-read failed on slave %i!\n", slave->ring_position); fp@73: return -1; fp@73: } fp@73: fp@98: start = get_cycles(); fp@119: timeout = (cycles_t) 100 * cpu_khz; // 100ms fp@98: fp@113: while (1) fp@73: { fp@113: udelay(10); fp@113: fp@293: if (ec_datagram_nprd(datagram, slave->station_address, 0x502, 10)) fp@293: return -1; fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@89: EC_ERR("Getting SII-read status failed on slave %i!\n", fp@84: slave->ring_position); fp@73: return -1; fp@73: } fp@73: fp@98: end = get_cycles(); fp@98: fp@195: // check for "busy bit" fp@293: if (likely((EC_READ_U8(datagram->data + 1) & 0x81) == 0)) { fp@293: *target = EC_READ_U16(datagram->data + 6); fp@136: return 0; fp@136: } fp@136: fp@136: if (unlikely((end - start) >= timeout)) { fp@136: EC_ERR("SII-read. Slave %i timed out!\n", slave->ring_position); fp@136: return -1; fp@136: } fp@136: } fp@136: } fp@136: fp@136: /*****************************************************************************/ fp@136: fp@136: /** fp@195: Reads 32 bit from the slave information interface (SII). fp@195: \return 0 in case of success, else < 0 fp@136: */ fp@136: fp@136: int ec_slave_sii_read32(ec_slave_t *slave, fp@195: /**< EtherCAT slave */ fp@136: uint16_t offset, fp@195: /**< address of the SII register to read */ fp@136: uint32_t *target fp@195: /**< target memory */ fp@136: ) fp@136: { fp@293: ec_datagram_t *datagram; fp@136: cycles_t start, end, timeout; fp@136: fp@293: datagram = &slave->master->simple_datagram; fp@144: fp@195: // initiate read operation fp@293: if (ec_datagram_npwr(datagram, slave->station_address, 0x502, 6)) fp@293: return -1; fp@293: EC_WRITE_U8 (datagram->data, 0x00); // read-only access fp@293: EC_WRITE_U8 (datagram->data + 1, 0x01); // request read operation fp@293: EC_WRITE_U32(datagram->data + 2, offset); fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@136: EC_ERR("SII-read failed on slave %i!\n", slave->ring_position); fp@136: return -1; fp@136: } fp@136: fp@136: start = get_cycles(); fp@136: timeout = (cycles_t) 100 * cpu_khz; // 100ms fp@136: fp@136: while (1) fp@136: { fp@136: udelay(10); fp@136: fp@293: if (ec_datagram_nprd(datagram, slave->station_address, 0x502, 10)) fp@293: return -1; fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@136: EC_ERR("Getting SII-read status failed on slave %i!\n", fp@136: slave->ring_position); fp@136: return -1; fp@136: } fp@136: fp@136: end = get_cycles(); fp@136: fp@195: // check "busy bit" fp@293: if (likely((EC_READ_U8(datagram->data + 1) & 0x81) == 0)) { fp@293: *target = EC_READ_U32(datagram->data + 6); fp@113: return 0; fp@113: } fp@113: fp@113: if (unlikely((end - start) >= timeout)) { fp@118: EC_ERR("SII-read. Slave %i timed out!\n", slave->ring_position); fp@113: return -1; fp@113: } fp@113: } fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@195: Writes 16 bit of data to the slave information interface (SII). fp@195: \return 0 in case of success, else < 0 fp@114: */ fp@114: fp@136: int ec_slave_sii_write16(ec_slave_t *slave, fp@195: /**< EtherCAT slave */ fp@136: uint16_t offset, fp@195: /**< address of the SII register to write */ fp@136: uint16_t value fp@195: /**< new value */ fp@136: ) fp@114: { fp@293: ec_datagram_t *datagram; fp@114: cycles_t start, end, timeout; fp@114: fp@293: datagram = &slave->master->simple_datagram; fp@144: fp@114: EC_INFO("SII-write (slave %i, offset 0x%04X, value 0x%04X)\n", fp@114: slave->ring_position, offset, value); fp@114: fp@195: // initiate write operation fp@293: if (ec_datagram_npwr(datagram, slave->station_address, 0x502, 8)) fp@293: return -1; fp@293: EC_WRITE_U8 (datagram->data, 0x01); // enable write access fp@293: EC_WRITE_U8 (datagram->data + 1, 0x02); // request write operation fp@293: EC_WRITE_U32(datagram->data + 2, offset); fp@293: EC_WRITE_U16(datagram->data + 6, value); fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@114: EC_ERR("SII-write failed on slave %i!\n", slave->ring_position); fp@114: return -1; fp@114: } fp@114: fp@114: start = get_cycles(); fp@119: timeout = (cycles_t) 100 * cpu_khz; // 100ms fp@114: fp@114: while (1) fp@114: { fp@114: udelay(10); fp@114: fp@293: if (ec_datagram_nprd(datagram, slave->station_address, 0x502, 2)) fp@293: return -1; fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@114: EC_ERR("Getting SII-write status failed on slave %i!\n", fp@114: slave->ring_position); fp@114: return -1; fp@114: } fp@114: fp@114: end = get_cycles(); fp@114: fp@195: // check "busy bit" fp@293: if (likely((EC_READ_U8(datagram->data + 1) & 0x82) == 0)) { fp@293: if (EC_READ_U8(datagram->data + 1) & 0x40) { fp@114: EC_ERR("SII-write failed!\n"); fp@114: return -1; fp@114: } fp@114: else { fp@114: EC_INFO("SII-write succeeded!\n"); fp@114: return 0; fp@114: } fp@114: } fp@114: fp@114: if (unlikely((end - start) >= timeout)) { fp@118: EC_ERR("SII-write: Slave %i timed out!\n", slave->ring_position); fp@118: return -1; fp@118: } fp@118: } fp@118: } fp@118: fp@118: /*****************************************************************************/ fp@118: fp@118: /** fp@195: Fetches data from slave's EEPROM. fp@195: \return 0 in case of success, else < 0 fp@238: \todo memory allocation fp@195: */ fp@195: fp@195: int ec_slave_fetch_categories(ec_slave_t *slave /**< EtherCAT slave */) fp@118: { fp@126: uint16_t word_offset, cat_type, word_count; fp@118: uint32_t value; fp@118: uint8_t *cat_data; fp@118: unsigned int i; fp@118: fp@118: word_offset = 0x0040; fp@118: fp@296: if (!(cat_data = (uint8_t *) kmalloc(0x10000, GFP_ATOMIC))) { fp@118: EC_ERR("Failed to allocate 64k bytes for category data.\n"); fp@118: return -1; fp@118: } fp@118: fp@118: while (1) { fp@126: // read category type fp@136: if (ec_slave_sii_read32(slave, word_offset, &value)) { fp@126: EC_ERR("Unable to read category header.\n"); fp@123: goto out_free; fp@118: } fp@118: fp@195: // last category? fp@118: if ((value & 0xFFFF) == 0xFFFF) break; fp@118: fp@126: cat_type = value & 0x7FFF; fp@118: word_count = (value >> 16) & 0xFFFF; fp@118: fp@195: // fetch category data fp@118: for (i = 0; i < word_count; i++) { fp@136: if (ec_slave_sii_read32(slave, word_offset + 2 + i, &value)) { fp@118: EC_ERR("Unable to read category data word %i.\n", i); fp@123: goto out_free; fp@118: } fp@118: fp@118: cat_data[i * 2] = (value >> 0) & 0xFF; fp@118: cat_data[i * 2 + 1] = (value >> 8) & 0xFF; fp@118: fp@118: // read second word "on the fly" fp@118: if (i + 1 < word_count) { fp@118: i++; fp@118: cat_data[i * 2] = (value >> 16) & 0xFF; fp@118: cat_data[i * 2 + 1] = (value >> 24) & 0xFF; fp@118: } fp@118: } fp@118: fp@126: switch (cat_type) fp@118: { fp@118: case 0x000A: fp@123: if (ec_slave_fetch_strings(slave, cat_data)) fp@123: goto out_free; fp@118: break; fp@118: case 0x001E: fp@123: if (ec_slave_fetch_general(slave, cat_data)) fp@123: goto out_free; fp@118: break; fp@118: case 0x0028: fp@118: break; fp@118: case 0x0029: fp@126: if (ec_slave_fetch_sync(slave, cat_data, word_count)) fp@126: goto out_free; fp@118: break; fp@118: case 0x0032: fp@126: if (ec_slave_fetch_pdo(slave, cat_data, word_count, EC_TX_PDO)) fp@126: goto out_free; fp@118: break; fp@118: case 0x0033: fp@126: if (ec_slave_fetch_pdo(slave, cat_data, word_count, EC_RX_PDO)) fp@126: goto out_free; fp@118: break; fp@118: default: fp@126: EC_WARN("Unknown category type 0x%04X in slave %i.\n", fp@126: cat_type, slave->ring_position); fp@118: } fp@118: fp@118: word_offset += 2 + word_count; fp@118: } fp@118: fp@118: kfree(cat_data); fp@118: return 0; fp@123: fp@123: out_free: fp@123: kfree(cat_data); fp@123: return -1; fp@118: } fp@118: fp@118: /*****************************************************************************/ fp@118: fp@118: /** fp@195: Fetches data from a STRING category. fp@195: \return 0 in case of success, else < 0 fp@195: */ fp@195: fp@195: int ec_slave_fetch_strings(ec_slave_t *slave, /**< EtherCAT slave */ fp@195: const uint8_t *data /**< category data */ fp@118: ) fp@118: { fp@118: unsigned int string_count, i; fp@118: size_t size; fp@118: off_t offset; fp@126: ec_eeprom_string_t *string; fp@118: fp@118: string_count = data[0]; fp@118: offset = 1; fp@118: for (i = 0; i < string_count; i++) { fp@118: size = data[offset]; fp@195: // allocate memory for string structure and data at a single blow fp@126: if (!(string = (ec_eeprom_string_t *) fp@296: kmalloc(sizeof(ec_eeprom_string_t) + size + 1, GFP_ATOMIC))) { fp@118: EC_ERR("Failed to allocate string memory.\n"); fp@118: return -1; fp@118: } fp@121: string->size = size; fp@161: // string memory appended to string structure fp@126: string->data = (char *) string + sizeof(ec_eeprom_string_t); fp@118: memcpy(string->data, data + offset + 1, size); fp@118: string->data[size] = 0x00; fp@121: list_add_tail(&string->list, &slave->eeprom_strings); fp@118: offset += 1 + size; fp@118: } fp@118: fp@118: return 0; fp@118: } fp@118: fp@118: /*****************************************************************************/ fp@118: fp@118: /** fp@195: Fetches data from a GENERAL category. fp@195: \return 0 in case of success, else < 0 fp@195: */ fp@195: fp@195: int ec_slave_fetch_general(ec_slave_t *slave, /**< EtherCAT slave */ fp@195: const uint8_t *data /**< category data */ fp@123: ) fp@123: { fp@190: unsigned int i; fp@190: fp@123: if (ec_slave_locate_string(slave, data[0], &slave->eeprom_group)) fp@123: return -1; fp@264: if (ec_slave_locate_string(slave, data[1], &slave->eeprom_image)) fp@264: return -1; fp@264: if (ec_slave_locate_string(slave, data[2], &slave->eeprom_order)) fp@264: return -1; fp@264: if (ec_slave_locate_string(slave, data[3], &slave->eeprom_name)) fp@123: return -1; fp@123: fp@190: for (i = 0; i < 4; i++) fp@195: slave->sii_physical_layer[i] = fp@195: (data[4] & (0x03 << (i * 2))) >> (i * 2); fp@190: fp@123: return 0; fp@118: } fp@118: fp@118: /*****************************************************************************/ fp@118: fp@118: /** fp@195: Fetches data from a SYNC MANAGER category. fp@195: \return 0 in case of success, else < 0 fp@195: */ fp@195: fp@195: int ec_slave_fetch_sync(ec_slave_t *slave, /**< EtherCAT slave */ fp@195: const uint8_t *data, /**< category data */ fp@195: size_t word_count /**< number of words */ fp@126: ) fp@126: { fp@126: unsigned int sync_count, i; fp@126: ec_eeprom_sync_t *sync; fp@126: fp@195: sync_count = word_count / 4; // sync manager struct is 4 words long fp@126: fp@126: for (i = 0; i < sync_count; i++, data += 8) { fp@127: if (!(sync = (ec_eeprom_sync_t *) fp@296: kmalloc(sizeof(ec_eeprom_sync_t), GFP_ATOMIC))) { fp@126: EC_ERR("Failed to allocate Sync-Manager memory.\n"); fp@126: return -1; fp@126: } fp@126: fp@126: sync->index = i; fp@126: sync->physical_start_address = *((uint16_t *) (data + 0)); fp@126: sync->length = *((uint16_t *) (data + 2)); fp@126: sync->control_register = data[4]; fp@126: sync->enable = data[6]; fp@126: fp@126: list_add_tail(&sync->list, &slave->eeprom_syncs); fp@126: } fp@126: fp@126: return 0; fp@118: } fp@118: fp@118: /*****************************************************************************/ fp@118: fp@118: /** fp@195: Fetches data from a [RT]XPDO category. fp@195: \return 0 in case of success, else < 0 fp@195: */ fp@195: fp@195: int ec_slave_fetch_pdo(ec_slave_t *slave, /**< EtherCAT slave */ fp@195: const uint8_t *data, /**< category data */ fp@195: size_t word_count, /**< number of words */ fp@195: ec_pdo_type_t pdo_type /**< PDO type */ fp@126: ) fp@126: { fp@126: ec_eeprom_pdo_t *pdo; fp@126: ec_eeprom_pdo_entry_t *entry; fp@126: unsigned int entry_count, i; fp@126: fp@126: while (word_count >= 4) { fp@127: if (!(pdo = (ec_eeprom_pdo_t *) fp@296: kmalloc(sizeof(ec_eeprom_pdo_t), GFP_ATOMIC))) { fp@126: EC_ERR("Failed to allocate PDO memory.\n"); fp@126: return -1; fp@126: } fp@126: fp@126: INIT_LIST_HEAD(&pdo->entries); fp@126: pdo->type = pdo_type; fp@126: fp@126: pdo->index = *((uint16_t *) data); fp@126: entry_count = data[2]; fp@126: pdo->sync_manager = data[3]; fp@126: pdo->name = NULL; fp@126: ec_slave_locate_string(slave, data[5], &pdo->name); fp@126: fp@126: list_add_tail(&pdo->list, &slave->eeprom_pdos); fp@126: fp@126: word_count -= 4; fp@126: data += 8; fp@126: fp@126: for (i = 0; i < entry_count; i++) { fp@126: if (!(entry = (ec_eeprom_pdo_entry_t *) fp@296: kmalloc(sizeof(ec_eeprom_pdo_entry_t), GFP_ATOMIC))) { fp@126: EC_ERR("Failed to allocate PDO entry memory.\n"); fp@126: return -1; fp@126: } fp@126: fp@126: entry->index = *((uint16_t *) data); fp@126: entry->subindex = data[2]; fp@126: entry->name = NULL; fp@126: ec_slave_locate_string(slave, data[3], &entry->name); fp@126: entry->bit_length = data[5]; fp@126: fp@126: list_add_tail(&entry->list, &pdo->entries); fp@126: fp@126: word_count -= 4; fp@126: data += 8; fp@126: } fp@126: } fp@126: fp@126: return 0; fp@114: } fp@114: fp@114: /*****************************************************************************/ fp@114: fp@114: /** fp@195: Searches the string list for an index and allocates a new string. fp@195: \return 0 in case of success, else < 0 fp@197: \todo documentation fp@197: */ fp@197: fp@197: int ec_slave_locate_string(ec_slave_t *slave, /**< EtherCAT slave */ fp@197: unsigned int index, /**< string index */ fp@197: char **ptr /**< Address of the string pointer */ fp@197: ) fp@123: { fp@126: ec_eeprom_string_t *string; fp@126: char *err_string; fp@126: fp@126: // Erst alten Speicher freigeben fp@123: if (*ptr) { fp@123: kfree(*ptr); fp@123: *ptr = NULL; fp@123: } fp@123: fp@126: // Index 0 bedeutet "nicht belegt" fp@123: if (!index) return 0; fp@123: fp@126: // EEPROM-String mit Index finden und kopieren fp@123: list_for_each_entry(string, &slave->eeprom_strings, list) { fp@126: if (--index) continue; fp@126: fp@296: if (!(*ptr = (char *) kmalloc(string->size + 1, GFP_ATOMIC))) { fp@126: EC_ERR("Unable to allocate string memory.\n"); fp@126: return -1; fp@126: } fp@126: memcpy(*ptr, string->data, string->size + 1); fp@126: return 0; fp@126: } fp@126: fp@126: EC_WARN("String %i not found in slave %i.\n", index, slave->ring_position); fp@126: fp@126: err_string = "(string not found)"; fp@126: fp@296: if (!(*ptr = (char *) kmalloc(strlen(err_string) + 1, GFP_ATOMIC))) { fp@126: EC_ERR("Unable to allocate string memory.\n"); fp@126: return -1; fp@126: } fp@126: fp@126: memcpy(*ptr, err_string, strlen(err_string) + 1); fp@123: return 0; fp@123: } fp@123: fp@123: /*****************************************************************************/ fp@123: fp@123: /** fp@195: Acknowledges an error after a state transition. fp@195: */ fp@195: fp@195: void ec_slave_state_ack(ec_slave_t *slave, /**< EtherCAT slave */ fp@195: uint8_t state /**< previous state */ fp@73: ) fp@73: { fp@293: ec_datagram_t *datagram; fp@98: cycles_t start, end, timeout; fp@73: fp@293: datagram = &slave->master->simple_datagram; fp@293: fp@293: if (ec_datagram_npwr(datagram, slave->station_address, 0x0120, 2)) return; fp@293: EC_WRITE_U16(datagram->data, state | EC_ACK); fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@163: EC_WARN("Acknowledge sending failed on slave %i!\n", fp@163: slave->ring_position); fp@73: return; fp@73: } fp@73: fp@98: start = get_cycles(); fp@119: timeout = (cycles_t) 10 * cpu_khz; // 10ms fp@98: fp@113: while (1) fp@73: { fp@195: udelay(100); // wait a little bit... fp@113: fp@293: if (ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2)) fp@144: return; fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@260: slave->current_state = EC_SLAVE_STATE_UNKNOWN; fp@163: EC_WARN("Acknowledge checking failed on slave %i!\n", fp@84: slave->ring_position); fp@73: return; fp@73: } fp@113: fp@163: end = get_cycles(); fp@163: fp@293: if (likely(EC_READ_U8(datagram->data) == state)) { fp@260: slave->current_state = state; fp@163: EC_INFO("Acknowleged state 0x%02X on slave %i.\n", state, fp@163: slave->ring_position); fp@163: return; fp@163: } fp@163: fp@113: if (unlikely((end - start) >= timeout)) { fp@260: slave->current_state = EC_SLAVE_STATE_UNKNOWN; fp@164: EC_WARN("Failed to acknowledge state 0x%02X on slave %i" fp@164: " - Timeout!\n", state, slave->ring_position); fp@113: return; fp@113: } fp@73: } fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@164: Reads the AL status code of a slave and displays it. fp@164: If the AL status code is not supported, or if no error occurred (both fp@197: resulting in code = 0), nothing is displayed. fp@164: */ fp@164: fp@195: void ec_slave_read_al_status_code(ec_slave_t *slave /**< EtherCAT slave */) fp@164: { fp@293: ec_datagram_t *datagram; fp@164: uint16_t code; fp@164: const ec_code_msg_t *al_msg; fp@164: fp@293: datagram = &slave->master->simple_datagram; fp@293: fp@293: if (ec_datagram_nprd(datagram, slave->station_address, 0x0134, 2)) return; fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@164: EC_WARN("Failed to read AL status code on slave %i!\n", fp@164: slave->ring_position); fp@164: return; fp@164: } fp@164: fp@293: if (!(code = EC_READ_U16(datagram->data))) return; fp@164: fp@164: for (al_msg = al_status_messages; al_msg->code; al_msg++) { fp@164: if (al_msg->code == code) { fp@164: EC_ERR("AL status message 0x%04X: \"%s\".\n", fp@164: al_msg->code, al_msg->message); fp@164: return; fp@164: } fp@164: } fp@164: fp@164: EC_ERR("Unknown AL status code 0x%04X.\n", code); fp@164: } fp@164: fp@164: /*****************************************************************************/ fp@164: fp@164: /** fp@195: Does a state transition. fp@195: \return 0 in case of success, else < 0 fp@195: */ fp@195: fp@195: int ec_slave_state_change(ec_slave_t *slave, /**< EtherCAT slave */ fp@195: uint8_t state /**< new state */ fp@73: ) fp@73: { fp@293: ec_datagram_t *datagram; fp@98: cycles_t start, end, timeout; fp@73: fp@293: datagram = &slave->master->simple_datagram; fp@144: fp@260: slave->requested_state = state; fp@260: fp@293: if (ec_datagram_npwr(datagram, slave->station_address, 0x0120, 2)) fp@293: return -1; fp@293: EC_WRITE_U16(datagram->data, state); fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@164: EC_ERR("Failed to set state 0x%02X on slave %i!\n", fp@89: state, slave->ring_position); fp@73: return -1; fp@73: } fp@73: fp@98: start = get_cycles(); fp@119: timeout = (cycles_t) 10 * cpu_khz; // 10ms fp@98: fp@113: while (1) fp@73: { fp@195: udelay(100); // wait a little bit fp@98: fp@293: if (ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2)) fp@293: return -1; fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@260: slave->current_state = EC_SLAVE_STATE_UNKNOWN; fp@164: EC_ERR("Failed to check state 0x%02X on slave %i!\n", fp@84: state, slave->ring_position); fp@73: return -1; fp@73: } fp@73: fp@98: end = get_cycles(); fp@98: fp@293: if (unlikely(EC_READ_U8(datagram->data) & 0x10)) { fp@293: // state change error fp@164: EC_ERR("Failed to set state 0x%02X - Slave %i refused state change" fp@164: " (code 0x%02X)!\n", state, slave->ring_position, fp@293: EC_READ_U8(datagram->data)); fp@293: slave->current_state = EC_READ_U8(datagram->data); fp@260: state = slave->current_state & 0x0F; fp@164: ec_slave_read_al_status_code(slave); fp@164: ec_slave_state_ack(slave, state); fp@144: return -1; fp@144: } fp@144: fp@293: if (likely(EC_READ_U8(datagram->data) == (state & 0x0F))) { fp@260: slave->current_state = state; fp@195: return 0; // state change successful fp@260: } fp@113: fp@113: if (unlikely((end - start) >= timeout)) { fp@260: slave->current_state = EC_SLAVE_STATE_UNKNOWN; fp@164: EC_ERR("Failed to check state 0x%02X of slave %i - Timeout!\n", fp@113: state, slave->ring_position); fp@113: return -1; fp@113: } fp@113: } fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@195: Prepares an FMMU configuration. fp@195: Configuration data for the FMMU is saved in the slave structure and is fp@195: written to the slave in ecrt_master_activate(). fp@195: The FMMU configuration is done in a way, that the complete data range fp@195: of the corresponding sync manager is covered. Seperate FMMUs arce configured fp@195: for each domain. fp@195: If the FMMU configuration is already prepared, the function returns with fp@195: success. fp@195: \return 0 in case of success, else < 0 fp@195: */ fp@195: fp@195: int ec_slave_prepare_fmmu(ec_slave_t *slave, /**< EtherCAT slave */ fp@195: const ec_domain_t *domain, /**< domain */ fp@195: const ec_sync_t *sync /**< sync manager */ fp@160: ) fp@73: { fp@73: unsigned int i; fp@73: fp@195: // FMMU configuration already prepared? fp@73: for (i = 0; i < slave->fmmu_count; i++) fp@73: if (slave->fmmus[i].domain == domain && slave->fmmus[i].sync == sync) fp@73: return 0; fp@73: fp@195: // reserve new FMMU... fp@91: fp@73: if (slave->fmmu_count >= slave->base_fmmu_count) { fp@84: EC_ERR("Slave %i FMMU limit reached!\n", slave->ring_position); fp@73: return -1; fp@73: } fp@73: fp@73: slave->fmmus[slave->fmmu_count].domain = domain; fp@73: slave->fmmus[slave->fmmu_count].sync = sync; fp@73: slave->fmmus[slave->fmmu_count].logical_start_address = 0; fp@73: slave->fmmu_count++; fp@73: slave->registered = 1; fp@73: fp@73: return 0; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@195: Outputs all information about a certain slave. fp@140: Verbosity: fp@195: - 0: Only slave types and addresses fp@195: - 1: with EEPROM information fp@195: - >1: with SDO dictionaries fp@195: */ fp@195: fp@195: void ec_slave_print(const ec_slave_t *slave, /**< EtherCAT slave */ fp@195: unsigned int verbosity /**< verbosity level */ fp@140: ) fp@73: { fp@126: ec_eeprom_sync_t *sync; fp@126: ec_eeprom_pdo_t *pdo; fp@139: ec_eeprom_pdo_entry_t *pdo_entry; fp@135: ec_sdo_t *sdo; fp@139: ec_sdo_entry_t *sdo_entry; fp@142: int first, i; fp@126: fp@73: if (slave->type) { fp@157: EC_INFO("%i) %s %s: %s\n", slave->ring_position, fp@84: slave->type->vendor_name, slave->type->product_name, fp@84: slave->type->description); fp@73: } fp@73: else { fp@157: EC_INFO("%i) UNKNOWN SLAVE: vendor 0x%08X, product 0x%08X\n", fp@157: slave->ring_position, slave->sii_vendor_id, fp@157: slave->sii_product_code); fp@157: } fp@157: fp@157: if (!verbosity) return; fp@157: fp@157: EC_INFO(" Station address: 0x%04X\n", slave->station_address); fp@157: fp@157: EC_INFO(" Data link status:\n"); fp@183: for (i = 0; i < 4; i++) { fp@190: EC_INFO(" Port %i (", i); fp@190: switch (slave->sii_physical_layer[i]) { fp@190: case 0x00: fp@190: printk("EBUS"); fp@190: break; fp@190: case 0x01: fp@190: printk("100BASE-TX"); fp@190: break; fp@190: case 0x02: fp@190: printk("100BASE-FX"); fp@190: break; fp@190: default: fp@190: printk("unknown"); fp@190: } fp@190: printk(")\n"); fp@190: EC_INFO(" link %s, loop %s, %s\n", fp@183: slave->dl_link[i] ? "up" : "down", fp@183: slave->dl_loop[i] ? "closed" : "open", fp@183: slave->dl_signal[i] ? "signal detected" : "no signal"); fp@157: } fp@157: fp@157: EC_INFO(" Base information:\n"); fp@157: EC_INFO(" Type %u, revision %i, build %i\n", fp@147: slave->base_type, slave->base_revision, slave->base_build); fp@157: EC_INFO(" Supported FMMUs: %i, sync managers: %i\n", fp@147: slave->base_fmmu_count, slave->base_sync_count); fp@147: fp@147: if (slave->sii_mailbox_protocols) { fp@157: EC_INFO(" Mailbox communication:\n"); fp@157: EC_INFO(" RX mailbox: 0x%04X/%i, TX mailbox: 0x%04X/%i\n", fp@147: slave->sii_rx_mailbox_offset, slave->sii_rx_mailbox_size, fp@147: slave->sii_tx_mailbox_offset, slave->sii_tx_mailbox_size); fp@157: EC_INFO(" Supported protocols: "); fp@147: fp@147: first = 1; fp@147: if (slave->sii_mailbox_protocols & EC_MBOX_AOE) { fp@147: printk("AoE"); fp@147: first = 0; fp@147: } fp@147: if (slave->sii_mailbox_protocols & EC_MBOX_EOE) { fp@147: if (!first) printk(", "); fp@147: printk("EoE"); fp@147: first = 0; fp@147: } fp@147: if (slave->sii_mailbox_protocols & EC_MBOX_COE) { fp@147: if (!first) printk(", "); fp@147: printk("CoE"); fp@147: first = 0; fp@147: } fp@147: if (slave->sii_mailbox_protocols & EC_MBOX_FOE) { fp@147: if (!first) printk(", "); fp@147: printk("FoE"); fp@147: first = 0; fp@147: } fp@147: if (slave->sii_mailbox_protocols & EC_MBOX_SOE) { fp@147: if (!first) printk(", "); fp@147: printk("SoE"); fp@147: first = 0; fp@147: } fp@147: if (slave->sii_mailbox_protocols & EC_MBOX_VOE) { fp@147: if (!first) printk(", "); fp@147: printk("VoE"); fp@147: } fp@147: printk("\n"); fp@147: } fp@147: fp@157: EC_INFO(" EEPROM data:\n"); fp@147: fp@266: EC_INFO(" EEPROM content size: %i Bytes\n", slave->eeprom_size); fp@266: fp@147: if (slave->sii_alias) fp@157: EC_INFO(" Configured station alias: 0x%04X (%i)\n", fp@147: slave->sii_alias, slave->sii_alias); fp@147: fp@157: EC_INFO(" Vendor-ID: 0x%08X, Product code: 0x%08X\n", fp@147: slave->sii_vendor_id, slave->sii_product_code); fp@157: EC_INFO(" Revision number: 0x%08X, Serial number: 0x%08X\n", fp@147: slave->sii_revision_number, slave->sii_serial_number); fp@147: fp@264: if (slave->eeprom_group) fp@264: EC_INFO(" Group: %s\n", slave->eeprom_group); fp@264: if (slave->eeprom_image) fp@264: EC_INFO(" Image: %s\n", slave->eeprom_image); fp@264: if (slave->eeprom_order) fp@264: EC_INFO(" Order#: %s\n", slave->eeprom_order); fp@147: if (slave->eeprom_name) fp@157: EC_INFO(" Name: %s\n", slave->eeprom_name); fp@147: fp@147: if (!list_empty(&slave->eeprom_syncs)) { fp@157: EC_INFO(" Sync-Managers:\n"); fp@147: list_for_each_entry(sync, &slave->eeprom_syncs, list) { fp@157: EC_INFO(" %i: 0x%04X, length %i, control 0x%02X, %s\n", fp@147: sync->index, sync->physical_start_address, fp@147: sync->length, sync->control_register, fp@147: sync->enable ? "enable" : "disable"); fp@147: } fp@147: } fp@147: fp@147: list_for_each_entry(pdo, &slave->eeprom_pdos, list) { fp@157: EC_INFO(" %s \"%s\" (0x%04X), -> Sync-Manager %i\n", fp@147: pdo->type == EC_RX_PDO ? "RXPDO" : "TXPDO", fp@147: pdo->name ? pdo->name : "???", fp@147: pdo->index, pdo->sync_manager); fp@147: fp@147: list_for_each_entry(pdo_entry, &pdo->entries, list) { fp@157: EC_INFO(" \"%s\" 0x%04X:%X, %i Bit\n", fp@147: pdo_entry->name ? pdo_entry->name : "???", fp@147: pdo_entry->index, pdo_entry->subindex, fp@147: pdo_entry->bit_length); fp@140: } fp@140: } fp@140: fp@157: if (verbosity < 2) return; fp@157: fp@157: if (!list_empty(&slave->sdo_dictionary)) { fp@157: EC_INFO(" SDO-Dictionary:\n"); fp@157: list_for_each_entry(sdo, &slave->sdo_dictionary, list) { fp@157: EC_INFO(" 0x%04X \"%s\"\n", sdo->index, fp@157: sdo->name ? sdo->name : ""); fp@175: EC_INFO(" Object code: 0x%02X\n", sdo->object_code); fp@157: list_for_each_entry(sdo_entry, &sdo->entries, list) { fp@157: EC_INFO(" 0x%04X:%i \"%s\", type 0x%04X, %i bits\n", fp@157: sdo->index, sdo_entry->subindex, fp@157: sdo_entry->name ? sdo_entry->name : "", fp@157: sdo_entry->data_type, sdo_entry->bit_length); fp@139: } fp@135: } fp@135: } fp@123: } fp@123: fp@123: /*****************************************************************************/ fp@123: fp@123: /** fp@195: Outputs the values of the CRC faoult counters and resets them. fp@195: \return 0 in case of success, else < 0 fp@195: */ fp@195: fp@195: int ec_slave_check_crc(ec_slave_t *slave /**< EtherCAT slave */) fp@74: { fp@293: ec_datagram_t *datagram; fp@293: fp@293: datagram = &slave->master->simple_datagram; fp@293: fp@293: if (ec_datagram_nprd(datagram, slave->station_address, 0x0300, 4)) fp@293: return -1; fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@89: EC_WARN("Reading CRC fault counters failed on slave %i!\n", fp@84: slave->ring_position); fp@74: return -1; fp@74: } fp@74: fp@293: if (!EC_READ_U32(datagram->data)) return 0; // no CRC faults fp@293: fp@293: if (EC_READ_U8(datagram->data)) fp@132: EC_WARN("%3i RX-error%s on slave %i, channel A.\n", fp@293: EC_READ_U8(datagram->data), fp@293: EC_READ_U8(datagram->data) == 1 ? "" : "s", fp@132: slave->ring_position); fp@293: if (EC_READ_U8(datagram->data + 1)) fp@132: EC_WARN("%3i invalid frame%s on slave %i, channel A.\n", fp@293: EC_READ_U8(datagram->data + 1), fp@293: EC_READ_U8(datagram->data + 1) == 1 ? "" : "s", fp@132: slave->ring_position); fp@293: if (EC_READ_U8(datagram->data + 2)) fp@132: EC_WARN("%3i RX-error%s on slave %i, channel B.\n", fp@293: EC_READ_U8(datagram->data + 2), fp@293: EC_READ_U8(datagram->data + 2) == 1 ? "" : "s", fp@132: slave->ring_position); fp@293: if (EC_READ_U8(datagram->data + 3)) fp@132: EC_WARN("%3i invalid frame%s on slave %i, channel B.\n", fp@293: EC_READ_U8(datagram->data + 3), fp@293: EC_READ_U8(datagram->data + 3) == 1 ? "" : "s", fp@132: slave->ring_position); fp@74: fp@195: // reset CRC counters fp@293: if (ec_datagram_npwr(datagram, slave->station_address, 0x0300, 4)) fp@293: return -1; fp@293: EC_WRITE_U32(datagram->data, 0x00000000); fp@293: if (unlikely(ec_master_simple_io(slave->master, datagram))) { fp@89: EC_WARN("Resetting CRC fault counters failed on slave %i!\n", fp@84: slave->ring_position); fp@74: return -1; fp@74: } fp@74: fp@74: return 0; fp@74: } fp@74: fp@74: /*****************************************************************************/ fp@74: fp@133: /** fp@269: Schedules an EEPROM write operation. fp@269: \return 0 in case of success, else < 0 fp@269: */ fp@269: fp@269: ssize_t ec_slave_write_eeprom(ec_slave_t *slave, /**< EtherCAT slave */ fp@269: const uint8_t *data, /**< new EEPROM data */ fp@269: size_t size /**< size of data in bytes */ fp@269: ) fp@269: { fp@269: uint16_t word_size, cat_type, cat_size; fp@269: const uint16_t *data_words, *next_header; fp@269: uint16_t *new_data; fp@269: fp@269: if (!slave->master->eeprom_write_enable) { fp@269: EC_ERR("Writing EEPROMs not allowed! Enable via" fp@269: " eeprom_write_enable SysFS entry.\n"); fp@269: return -1; fp@269: } fp@269: fp@269: if (slave->master->mode != EC_MASTER_MODE_FREERUN) { fp@269: EC_ERR("Writing EEPROMs only allowed in freerun mode!\n"); fp@269: return -1; fp@269: } fp@269: fp@269: if (slave->new_eeprom_data) { fp@269: EC_ERR("Slave %i already has a pending EEPROM write operation!\n", fp@269: slave->ring_position); fp@269: return -1; fp@269: } fp@269: fp@269: // coarse check of the data fp@269: fp@269: if (size % 2) { fp@269: EC_ERR("EEPROM size is odd! Dropping.\n"); fp@269: return -1; fp@269: } fp@269: fp@269: data_words = (const uint16_t *) data; fp@269: word_size = size / 2; fp@269: fp@269: if (word_size < 0x0041) { fp@269: EC_ERR("EEPROM data too short! Dropping.\n"); fp@269: return -1; fp@269: } fp@269: fp@269: next_header = data_words + 0x0040; fp@269: cat_type = EC_READ_U16(next_header); fp@269: while (cat_type != 0xFFFF) { fp@269: cat_type = EC_READ_U16(next_header); fp@269: cat_size = EC_READ_U16(next_header + 1); fp@269: if ((next_header + cat_size + 2) - data_words >= word_size) { fp@269: EC_ERR("EEPROM data seems to be corrupted! Dropping.\n"); fp@269: return -1; fp@269: } fp@269: next_header += cat_size + 2; fp@269: cat_type = EC_READ_U16(next_header); fp@269: } fp@269: fp@269: // data ok! fp@269: fp@269: if (!(new_data = (uint16_t *) kmalloc(word_size * 2, GFP_KERNEL))) { fp@269: EC_ERR("Unable to allocate memory for new EEPROM data!\n"); fp@269: return -1; fp@269: } fp@269: memcpy(new_data, data, size); fp@269: fp@269: slave->new_eeprom_size = word_size; fp@269: slave->new_eeprom_data = new_data; fp@269: fp@269: EC_INFO("EEPROM writing scheduled for slave %i, %i words.\n", fp@269: slave->ring_position, word_size); fp@269: return 0; fp@269: } fp@269: fp@269: /*****************************************************************************/ fp@269: fp@269: /** fp@195: Formats attribute data for SysFS read access. fp@195: \return number of bytes to read fp@195: */ fp@195: fp@195: ssize_t ec_show_slave_attribute(struct kobject *kobj, /**< slave's kobject */ fp@195: struct attribute *attr, /**< attribute */ fp@195: char *buffer /**< memory to store data */ fp@182: ) fp@182: { fp@182: ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj); fp@182: fp@182: if (attr == &attr_ring_position) { fp@182: return sprintf(buffer, "%i\n", slave->ring_position); fp@182: } fp@188: else if (attr == &attr_coupler_address) { fp@188: return sprintf(buffer, "%i:%i\n", slave->coupler_index, fp@188: slave->coupler_subindex); fp@183: } fp@183: else if (attr == &attr_vendor_name) { fp@183: if (slave->type) fp@183: return sprintf(buffer, "%s\n", slave->type->vendor_name); fp@183: } fp@183: else if (attr == &attr_product_name) { fp@183: if (slave->type) fp@183: return sprintf(buffer, "%s\n", slave->type->product_name); fp@183: } fp@183: else if (attr == &attr_product_desc) { fp@183: if (slave->type) fp@183: return sprintf(buffer, "%s\n", slave->type->description); fp@183: } fp@264: else if (attr == &attr_sii_name) { fp@264: if (slave->eeprom_name) fp@264: return sprintf(buffer, "%s\n", slave->eeprom_name); fp@238: } fp@185: else if (attr == &attr_type) { fp@185: if (slave->type) { fp@185: if (slave->type->special == EC_TYPE_BUS_COUPLER) fp@185: return sprintf(buffer, "coupler\n"); fp@290: else if (slave->type->special == EC_TYPE_INFRA) fp@290: return sprintf(buffer, "infrastructure\n"); fp@185: else fp@185: return sprintf(buffer, "normal\n"); fp@185: } fp@185: } fp@256: else if (attr == &attr_state) { fp@256: switch (slave->current_state) { fp@256: case EC_SLAVE_STATE_INIT: fp@256: return sprintf(buffer, "INIT\n"); fp@256: case EC_SLAVE_STATE_PREOP: fp@256: return sprintf(buffer, "PREOP\n"); fp@256: case EC_SLAVE_STATE_SAVEOP: fp@256: return sprintf(buffer, "SAVEOP\n"); fp@256: case EC_SLAVE_STATE_OP: fp@256: return sprintf(buffer, "OP\n"); fp@256: default: fp@256: return sprintf(buffer, "UNKNOWN\n"); fp@256: } fp@256: } fp@266: else if (attr == &attr_eeprom) { fp@266: if (slave->eeprom_data) { fp@266: if (slave->eeprom_size > PAGE_SIZE) { fp@266: EC_ERR("EEPROM contents of slave %i exceed 1 page (%i/%i).\n", fp@266: slave->ring_position, slave->eeprom_size, fp@266: (int) PAGE_SIZE); fp@266: } fp@266: else { fp@266: memcpy(buffer, slave->eeprom_data, slave->eeprom_size); fp@266: return slave->eeprom_size; fp@266: } fp@266: } fp@266: } fp@182: fp@182: return 0; fp@182: } fp@182: fp@256: /*****************************************************************************/ fp@256: fp@256: /** fp@256: Formats attribute data for SysFS write access. fp@256: \return number of bytes processed, or negative error code fp@256: */ fp@256: fp@256: ssize_t ec_store_slave_attribute(struct kobject *kobj, /**< slave's kobject */ fp@256: struct attribute *attr, /**< attribute */ fp@256: const char *buffer, /**< memory with data */ fp@256: size_t size /**< size of data to store */ fp@256: ) fp@256: { fp@256: ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj); fp@256: fp@256: if (attr == &attr_state) { fp@292: if (!strcmp(buffer, "INIT\n")) fp@256: slave->requested_state = EC_SLAVE_STATE_INIT; fp@292: else if (!strcmp(buffer, "PREOP\n")) fp@256: slave->requested_state = EC_SLAVE_STATE_PREOP; fp@292: else if (!strcmp(buffer, "SAVEOP\n")) fp@256: slave->requested_state = EC_SLAVE_STATE_SAVEOP; fp@292: else if (!strcmp(buffer, "OP\n")) fp@256: slave->requested_state = EC_SLAVE_STATE_OP; fp@292: else { fp@292: EC_ERR("Invalid slave state \"%s\"!\n", buffer); fp@292: return -EINVAL; fp@292: } fp@292: fp@292: EC_INFO("Accepted new state %s for slave %i.\n", fp@292: buffer, slave->ring_position); fp@292: slave->error_flag = 0; fp@292: return size; fp@256: } fp@269: else if (attr == &attr_eeprom) { fp@269: if (!ec_slave_write_eeprom(slave, buffer, size)) fp@269: return size; fp@269: } fp@256: fp@256: return -EINVAL; fp@256: } fp@256: fp@275: /*****************************************************************************/ fp@275: fp@275: /** fp@275: \return size of sync manager contents fp@275: */ fp@275: fp@275: size_t ec_slave_calc_sync_size(const ec_slave_t *slave, /**< EtherCAT slave */ fp@275: const ec_sync_t *sync /**< sync manager */ fp@275: ) fp@275: { fp@275: unsigned int i, found; fp@275: const ec_field_t *field; fp@275: const ec_varsize_t *var; fp@275: size_t size; fp@275: fp@275: // if size is specified, return size fp@275: if (sync->size) return sync->size; fp@275: fp@275: // sync manager has variable size (size == 0). fp@275: fp@275: size = 0; fp@275: for (i = 0; (field = sync->fields[i]); i++) { fp@275: found = 0; fp@275: list_for_each_entry(var, &slave->varsize_fields, list) { fp@275: if (var->field != field) continue; fp@275: size += var->size; fp@275: found = 1; fp@275: } fp@275: fp@275: if (!found) { fp@275: EC_WARN("Variable data field \"%s\" of slave %i has no size" fp@275: " information!\n", field->name, slave->ring_position); fp@275: } fp@275: } fp@275: return size; fp@275: } fp@275: fp@199: /****************************************************************************** fp@199: * Realtime interface fp@199: *****************************************************************************/ fp@199: fp@199: /** fp@199: Writes the "configured station alias" to the slave's EEPROM. fp@199: \return 0 in case of success, else < 0 fp@199: \ingroup RealtimeInterface fp@199: */ fp@199: fp@199: int ecrt_slave_write_alias(ec_slave_t *slave, /**< EtherCAT slave */ fp@199: uint16_t alias /**< new alias */ fp@199: ) fp@199: { fp@199: return ec_slave_sii_write16(slave, 0x0004, alias); fp@199: } fp@199: fp@199: /*****************************************************************************/ fp@199: fp@275: /** fp@275: \return 0 in case of success, else < 0 fp@275: \ingroup RealtimeInterface fp@275: */ fp@275: fp@275: int ecrt_slave_field_size(ec_slave_t *slave, /**< EtherCAT slave */ fp@275: const char *field_name, /**< data field name */ fp@275: unsigned int field_index, /**< data field index */ fp@275: size_t size /**< new data field size */ fp@275: ) fp@275: { fp@275: unsigned int i, j, field_counter; fp@275: const ec_sync_t *sync; fp@275: const ec_field_t *field; fp@275: ec_varsize_t *var; fp@275: fp@275: if (!slave->type) { fp@275: EC_ERR("Slave %i has no type information!\n", slave->ring_position); fp@275: return -1; fp@275: } fp@275: fp@275: field_counter = 0; fp@275: for (i = 0; (sync = slave->type->sync_managers[i]); i++) { fp@275: for (j = 0; (field = sync->fields[j]); j++) { fp@275: if (!strcmp(field->name, field_name)) { fp@275: if (field_counter++ == field_index) { fp@275: // is the size of this field variable? fp@275: if (field->size) { fp@275: EC_ERR("Field \"%s\"[%i] of slave %i has no variable" fp@275: " size!\n", field->name, field_index, fp@275: slave->ring_position); fp@275: return -1; fp@275: } fp@275: // does a size specification already exist? fp@275: list_for_each_entry(var, &slave->varsize_fields, list) { fp@275: if (var->field == field) { fp@275: EC_WARN("Resizing field \"%s\"[%i] of slave %i.\n", fp@275: field->name, field_index, fp@275: slave->ring_position); fp@275: var->size = size; fp@275: return 0; fp@275: } fp@275: } fp@275: // create a new size specification... fp@275: if (!(var = kmalloc(sizeof(ec_varsize_t), GFP_KERNEL))) { fp@275: EC_ERR("Failed to allocate memory for varsize_t!\n"); fp@275: return -1; fp@275: } fp@275: var->field = field; fp@275: var->size = size; fp@275: list_add_tail(&var->list, &slave->varsize_fields); fp@275: return 0; fp@275: } fp@275: } fp@275: } fp@275: } fp@275: fp@275: EC_ERR("Slave %i (\"%s %s\") has no field \"%s\"[%i]!\n", fp@275: slave->ring_position, slave->type->vendor_name, fp@275: slave->type->product_name, field_name, field_index); fp@275: return -1; fp@275: } fp@275: fp@275: /*****************************************************************************/ fp@275: fp@199: /**< \cond */ fp@164: fp@138: EXPORT_SYMBOL(ecrt_slave_write_alias); fp@275: EXPORT_SYMBOL(ecrt_slave_field_size); fp@138: fp@199: /**< \endcond */ fp@199: fp@199: /*****************************************************************************/