Slaves stored in list, slaves in SysFS

This commit is contained in:
Florian Pose 2006-04-11 09:12:00 +00:00
parent 9cfb580cba
commit 849e02da7c
5 changed files with 161 additions and 81 deletions

View File

@ -213,8 +213,7 @@ int ec_domain_alloc(ec_domain_t *domain, /**< Dom
cmd_offset = base_address;
cmd_data_size = 0;
cmd_count = 0;
for (i = 0; i < domain->master->slave_count; i++) {
slave = &domain->master->slaves[i];
list_for_each_entry(slave, &domain->master->slaves, list) {
for (j = 0; j < slave->fmmu_count; j++) {
fmmu = &slave->fmmus[j];
if (fmmu->domain == domain) {

View File

@ -64,10 +64,10 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT-Master */
EC_INFO("Initializing master %i.\n", index);
master->index = index;
master->slaves = NULL;
master->device = NULL;
master->reserved = 0;
INIT_LIST_HEAD(&master->slaves);
INIT_LIST_HEAD(&master->command_queue);
INIT_LIST_HEAD(&master->domains);
INIT_LIST_HEAD(&master->eoe_slaves);
@ -130,24 +130,23 @@ void ec_master_reset(ec_master_t *master
/**< Zeiger auf den zurückzusetzenden Master */
)
{
unsigned int i;
ec_slave_t *slave, *next_s;
ec_command_t *command, *next_c;
ec_domain_t *domain, *next_d;
ec_eoe_t *eoe, *next_eoe;
// Alle Slaves entfernen
if (master->slaves) {
for (i = 0; i < master->slave_count; i++)
ec_slave_clear(master->slaves + i);
kfree(master->slaves);
master->slaves = NULL;
list_for_each_entry_safe(slave, next_s, &master->slaves, list) {
list_del(&slave->list);
kobject_del(&slave->kobj);
kobject_put(&slave->kobj);
}
master->slave_count = 0;
// Kommando-Warteschlange leeren
list_for_each_entry_safe(command, next_c, &master->command_queue, queue) {
command->state = EC_CMD_ERROR;
list_del_init(&command->queue);
command->state = EC_CMD_ERROR;
}
// Domain-Liste leeren
@ -455,13 +454,14 @@ int ec_master_simple_io(ec_master_t *master, /**< EtherCAT-Master */
int ec_master_bus_scan(ec_master_t *master /**< EtherCAT-Master */)
{
ec_slave_t *slave;
ec_slave_t *slave, *next;
ec_slave_ident_t *ident;
unsigned int i;
ec_command_t *command;
ec_eoe_t *eoe;
uint16_t buscoupler_index, index_after_buscoupler;
if (master->slaves || master->slave_count) {
if (!list_empty(&master->slaves)) {
EC_ERR("Slave scan already done!\n");
return -1;
}
@ -476,35 +476,42 @@ int ec_master_bus_scan(ec_master_t *master /**< EtherCAT-Master */)
if (!master->slave_count) return 0;
if (!(master->slaves = (ec_slave_t *)
kmalloc(master->slave_count * sizeof(ec_slave_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate slaves!\n");
return -1;
}
// Init slaves
for (i = 0; i < master->slave_count; i++) {
slave = master->slaves + i;
ec_slave_init(slave, master);
slave->ring_position = i;
slave->station_address = i + 1;
if (!(slave = (ec_slave_t *) kmalloc(sizeof(ec_slave_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate slave %i!\n", i);
goto out_free;
}
if (ec_slave_init(slave, master, i, i + 1)) goto out_free;
if (kobject_add(&slave->kobj)) {
EC_ERR("Failed to add kobject.\n");
kobject_put(&slave->kobj); // free
goto out_free;
}
list_add_tail(&slave->list, &master->slaves);
}
buscoupler_index = 0xFFFF;
index_after_buscoupler = 0;
// For every slave on the bus
for (i = 0; i < master->slave_count; i++) {
slave = master->slaves + i;
list_for_each_entry(slave, &master->slaves, list) {
// Write station address
if (ec_command_apwr(command, slave->ring_position,
0x0010, sizeof(uint16_t))) return -1;
if (ec_command_apwr(command, slave->ring_position, 0x0010,
sizeof(uint16_t))) goto out_free;
EC_WRITE_U16(command->data, slave->station_address);
if (unlikely(ec_master_simple_io(master, command))) {
EC_ERR("Writing station address failed on slave %i!\n", i);
return -1;
EC_ERR("Writing station address failed on slave %i!\n",
slave->ring_position);
goto out_free;
}
// Fetch all slave information
if (ec_slave_fetch(slave)) return -1;
if (ec_slave_fetch(slave)) goto out_free;
// Search for identification in "database"
ident = slave_idents;
@ -521,12 +528,22 @@ int ec_master_bus_scan(ec_master_t *master /**< EtherCAT-Master */)
EC_WARN("Unknown slave device (vendor 0x%08X, code 0x%08X) at"
" position %i.\n", slave->sii_vendor_id,
slave->sii_product_code, i);
else {
if (slave->type->special == EC_TYPE_BUS_COUPLER) {
buscoupler_index++;
index_after_buscoupler = 0;
}
}
slave->buscoupler_index = buscoupler_index;
slave->index_after_buscoupler = index_after_buscoupler;
index_after_buscoupler++;
// Does the slave support EoE?
if (slave->sii_mailbox_protocols & EC_MBOX_EOE) {
if (!(eoe = (ec_eoe_t *) kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate EoE-Object.\n");
return -1;
goto out_free;
}
ec_eoe_init(eoe, slave);
@ -535,6 +552,14 @@ int ec_master_bus_scan(ec_master_t *master /**< EtherCAT-Master */)
}
return 0;
out_free:
list_for_each_entry_safe(slave, next, &master->slaves, list) {
list_del(&slave->list);
kobject_del(&slave->kobj);
kobject_put(&slave->kobj);
}
return -1;
}
/*****************************************************************************/
@ -600,14 +625,12 @@ ec_slave_t *ecrt_master_get_slave(const ec_master_t *master, /**< Master */
{
unsigned long first, second;
char *remainder, *remainder2;
unsigned int i, alias_requested, alias_slave_index, alias_found;
int coupler_idx, slave_idx;
ec_slave_t *slave;
unsigned int alias_requested, alias_found;
ec_slave_t *alias_slave = NULL, *slave;
if (!address || address[0] == 0) return NULL;
alias_requested = 0;
alias_slave_index = 0;
if (address[0] == '#') {
alias_requested = 1;
address++;
@ -621,9 +644,8 @@ ec_slave_t *ecrt_master_get_slave(const ec_master_t *master, /**< Master */
if (alias_requested) {
alias_found = 0;
for (i = 0; i < master->slave_count; i++) {
if (master->slaves[i].sii_alias == first) {
alias_slave_index = i;
list_for_each_entry(alias_slave, &master->slaves, list) {
if (alias_slave->sii_alias == first) {
alias_found = 1;
break;
}
@ -636,11 +658,11 @@ ec_slave_t *ecrt_master_get_slave(const ec_master_t *master, /**< Master */
if (!remainder[0]) { // absolute position
if (alias_requested) {
return master->slaves + alias_slave_index;
return alias_slave;
}
else {
if (first < master->slave_count) {
return master->slaves + first;
list_for_each_entry(slave, &master->slaves, list) {
if (slave->ring_position == first) return slave;
}
EC_ERR("Slave address \"%s\" - Absolute position invalid!\n",
address);
@ -661,29 +683,21 @@ ec_slave_t *ecrt_master_get_slave(const ec_master_t *master, /**< Master */
}
if (alias_requested) {
for (i = alias_slave_index + 1; i < master->slave_count; i++) {
slave = master->slaves + i;
if (!slave->type ||
slave->type->special == EC_TYPE_BUS_COUPLER) break;
if (i - alias_slave_index == second) return slave;
list_for_each_entry(slave, &master->slaves, list) {
if (slave->buscoupler_index == alias_slave->buscoupler_index
&& alias_slave->index_after_buscoupler == 0
&& slave->index_after_buscoupler == second)
return slave;
}
EC_ERR("Slave address \"%s\" - Bus coupler %i has no %lu. slave"
" following!\n", address,
(master->slaves + alias_slave_index)->ring_position,
" following!\n", address, alias_slave->ring_position,
second);
return NULL;
}
else {
coupler_idx = -1;
slave_idx = 0;
for (i = 0; i < master->slave_count; i++, slave_idx++) {
slave = master->slaves + i;
if (!slave->type) continue;
if (slave->type->special == EC_TYPE_BUS_COUPLER) {
coupler_idx++;
slave_idx = 0;
}
if (coupler_idx == first && slave_idx == second) return slave;
list_for_each_entry(slave, &master->slaves, list) {
if (slave->buscoupler_index == first
&& slave->index_after_buscoupler == second) return slave;
}
}
}
@ -887,7 +901,7 @@ ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< Master */)
int ecrt_master_activate(ec_master_t *master /**< EtherCAT-Master */)
{
unsigned int i, j;
unsigned int j;
ec_slave_t *slave;
ec_command_t *command;
const ec_sync_t *sync;
@ -915,8 +929,7 @@ int ecrt_master_activate(ec_master_t *master /**< EtherCAT-Master */)
}
// Slaves aktivieren
for (i = 0; i < master->slave_count; i++) {
slave = master->slaves + i;
list_for_each_entry(slave, &master->slaves, list) {
// Change state to INIT
if (unlikely(ec_slave_state_change(slave, EC_SLAVE_STATE_INIT)))
@ -924,7 +937,8 @@ int ecrt_master_activate(ec_master_t *master /**< EtherCAT-Master */)
// Check if slave was registered...
type = slave->type;
if (!type) EC_WARN("Slave %i has unknown type!\n", i);
if (!type)
EC_WARN("Slave %i has unknown type!\n", slave->ring_position);
// Check and reset CRC fault counters
ec_slave_check_crc(slave);
@ -1079,11 +1093,8 @@ int ecrt_master_activate(ec_master_t *master /**< EtherCAT-Master */)
void ecrt_master_deactivate(ec_master_t *master /**< EtherCAT-Master */)
{
ec_slave_t *slave;
unsigned int i;
for (i = 0; i < master->slave_count; i++)
{
slave = master->slaves + i;
list_for_each_entry(slave, &master->slaves, list) {
ec_slave_check_crc(slave);
ec_slave_state_change(slave, EC_SLAVE_STATE_INIT);
}
@ -1103,10 +1114,8 @@ void ecrt_master_deactivate(ec_master_t *master /**< EtherCAT-Master */)
int ecrt_master_fetch_sdo_lists(ec_master_t *master /**< EtherCAT-Master */)
{
ec_slave_t *slave;
unsigned int i;
for (i = 0; i < master->slave_count; i++) {
slave = master->slaves + i;
list_for_each_entry(slave, &master->slaves, list) {
if (slave->sii_mailbox_protocols & EC_MBOX_COE) {
if (unlikely(ec_slave_fetch_sdo_list(slave))) {
EC_ERR("Failed to fetch SDO list on slave %i!\n",
@ -1319,14 +1328,14 @@ void ecrt_master_print(const ec_master_t *master, /**< EtherCAT-Master */
unsigned int verbosity /**< Geschwätzigkeit */
)
{
unsigned int i;
ec_slave_t *slave;
ec_eoe_t *eoe;
EC_INFO("*** Begin master information ***\n");
if (master->slave_count) {
EC_INFO("Slave list:\n");
for (i = 0; i < master->slave_count; i++)
ec_slave_print(&master->slaves[i], verbosity);
list_for_each_entry(slave, &master->slaves, list)
ec_slave_print(slave, verbosity);
}
if (!list_empty(&master->eoe_slaves)) {
EC_INFO("Ethernet-over-EtherCAT (EoE) objects:\n");

View File

@ -15,7 +15,6 @@
#include <linux/sysfs.h>
#include "device.h"
#include "slave.h"
#include "domain.h"
/*****************************************************************************/
@ -49,7 +48,7 @@ struct ec_master
struct list_head list; /**< Noetig fuer Master-Liste */
struct kobject kobj; /**< Kernel-Object */
unsigned int index; /**< Master-Index */
ec_slave_t *slaves; /**< Array von Slaves auf dem Bus */
struct list_head slaves; /**< Liste der Slaves auf dem Bus */
unsigned int slave_count; /**< Anzahl Slaves auf dem Bus */
ec_device_t *device; /**< EtherCAT-Gerät */
struct list_head command_queue; /**< Kommando-Warteschlange */

View File

@ -24,6 +24,31 @@ int ec_slave_fetch_general(ec_slave_t *, const uint8_t *);
int ec_slave_fetch_sync(ec_slave_t *, const uint8_t *, size_t);
int ec_slave_fetch_pdo(ec_slave_t *, const uint8_t *, size_t, ec_pdo_type_t);
int ec_slave_locate_string(ec_slave_t *, unsigned int, char **);
ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *);
/*****************************************************************************/
static struct attribute attr_ring_position = {
.name = "ring_position",
.owner = THIS_MODULE,
.mode = S_IRUGO
};
static struct attribute *def_attrs[] = {
&attr_ring_position,
NULL,
};
static struct sysfs_ops sysfs_ops = {
.show = &ec_show_slave_attribute,
.store = NULL
};
static struct kobj_type ktype_ec_slave = {
.release = ec_slave_clear,
.sysfs_ops = &sysfs_ops,
.default_attrs = def_attrs
};
/*****************************************************************************/
@ -35,20 +60,36 @@ const ec_code_msg_t al_status_messages[];
EtherCAT-Slave-Konstruktor.
*/
void ec_slave_init(ec_slave_t *slave, /**< EtherCAT-Slave */
ec_master_t *master /**< EtherCAT-Master */
)
int ec_slave_init(ec_slave_t *slave, /**< EtherCAT-Slave */
ec_master_t *master, /**< EtherCAT-Master */
uint16_t ring_position, /**< Ringposition */
uint16_t station_address /**< Programmierte Adresse */
)
{
unsigned int i;
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->buscoupler_index = 0;
slave->index_after_buscoupler = 0xFFFF;
slave->base_type = 0;
slave->base_revision = 0;
slave->base_build = 0;
slave->base_fmmu_count = 0;
slave->base_sync_count = 0;
slave->ring_position = 0;
slave->station_address = 0;
slave->sii_alias = 0;
slave->sii_vendor_id = 0;
slave->sii_product_code = 0;
@ -78,6 +119,8 @@ void ec_slave_init(ec_slave_t *slave, /**< EtherCAT-Slave */
slave->dl_status_loop[i] = 0;
slave->dl_status_comm[i] = 0;
}
return 0;
}
/*****************************************************************************/
@ -86,8 +129,9 @@ void ec_slave_init(ec_slave_t *slave, /**< EtherCAT-Slave */
EtherCAT-Slave-Destruktor.
*/
void ec_slave_clear(ec_slave_t *slave /**< EtherCAT-Slave */)
void ec_slave_clear(struct kobject *kobj /**< KObject des Slaves */)
{
ec_slave_t *slave;
ec_eeprom_string_t *string, *next_str;
ec_eeprom_sync_t *sync, *next_sync;
ec_eeprom_pdo_t *pdo, *next_pdo;
@ -95,6 +139,8 @@ void ec_slave_clear(ec_slave_t *slave /**< EtherCAT-Slave */)
ec_sdo_t *sdo, *next_sdo;
ec_sdo_entry_t *en, *next_en;
slave = container_of(kobj, ec_slave_t, kobj);
// Alle Strings freigeben
list_for_each_entry_safe(string, next_str, &slave->eeprom_strings, list) {
list_del(&string->list);
@ -1143,6 +1189,28 @@ int ecrt_slave_write_alias(ec_slave_t *slave, /** EtherCAT-Slave */
/*****************************************************************************/
/**
Formatiert Attribut-Daten für lesenden Zugriff im SysFS
\return Anzahl Bytes im Speicher
*/
ssize_t ec_show_slave_attribute(struct kobject *kobj, /**< KObject */
struct attribute *attr, /**< Attribut */
char *buffer /**< Speicher für die Daten */
)
{
ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj);
if (attr == &attr_ring_position) {
return sprintf(buffer, "%i\n", slave->ring_position);
}
return 0;
}
/*****************************************************************************/
const ec_code_msg_t al_status_messages[] = {
{0x0001, "Unspecified error"},
{0x0011, "Invalud requested state change"},

View File

@ -12,6 +12,7 @@
#define _EC_SLAVE_H_
#include <linux/list.h>
#include <linux/kobject.h>
#include "globals.h"
#include "command.h"
@ -188,11 +189,15 @@ ec_sdo_entry_t;
struct ec_slave
{
struct list_head list; /**< Noetig fuer Slave-Liste im Master */
struct kobject kobj; /**< Kernel-Object */
ec_master_t *master; /**< EtherCAT-Master, zu dem der Slave gehört. */
// Addresses
uint16_t ring_position; /**< Position des Slaves im Bus */
uint16_t station_address; /**< Konfigurierte Slave-Adresse */
uint16_t buscoupler_index; /**< Letzter Buskoppler */
uint16_t index_after_buscoupler; /**< Index hinter letztem Buskoppler */
// Base data
uint8_t base_type; /**< Slave-Typ */
@ -242,8 +247,8 @@ struct ec_slave
/*****************************************************************************/
// Slave construction/destruction
void ec_slave_init(ec_slave_t *, ec_master_t *);
void ec_slave_clear(ec_slave_t *);
int ec_slave_init(ec_slave_t *, ec_master_t *, uint16_t, uint16_t);
void ec_slave_clear(struct kobject *);
// Slave control
int ec_slave_fetch(ec_slave_t *);