Allow only MAC addresses as device identifiers; replaced master list by
master array; hand ober MAC addresses with array module parameters.
This commit is contained in:
parent
8c9abc407c
commit
8ac6516b4e
9
NEWS
9
NEWS
|
|
@ -9,12 +9,11 @@ Changes in version 1.3.0:
|
|||
* Added testing version of Intel PRO/100 ethernet driver (e100).
|
||||
* Added testing version of NVIDIA nForce ethernet driver (forcedeth).
|
||||
* Removed "ec_eoeif_count" master module parameter.
|
||||
* Introduced "Device IDs" to tell a master to wait for connection of certain
|
||||
ethernet devices.
|
||||
* Added "main" and "backup" parameters to master module to hand over
|
||||
device ID lists.
|
||||
* Added "main" and "backup" parameters to master module to hand over the
|
||||
MAC addresses of the devices to wait for. This made the ec_device_index
|
||||
parameter of the ethercat drivers obsolete.
|
||||
* Changed format of sysconfig file and accordingly adjusted functionality
|
||||
of the init script to handle device ID lists.
|
||||
of the init script to handle MAC address lists.
|
||||
* Realtime interface changes:
|
||||
- ecrt_master_run() became obsolete, because the master state machine is now
|
||||
run in process context.
|
||||
|
|
|
|||
1
TODO
1
TODO
|
|
@ -8,7 +8,6 @@ $Id$
|
|||
|
||||
* Release 1.3:
|
||||
- Remove addressing scheme "X:Y".
|
||||
- Allow only MAC address as device ID.
|
||||
- Remove ugly ec_slave_is_coupler().
|
||||
- Replace Vendor ID and product code arguments of ec_domain_register_pdo()
|
||||
by slave pointer.
|
||||
|
|
|
|||
|
|
@ -1069,8 +1069,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
|
|||
/* dev is fully set up and ready to use now */
|
||||
|
||||
// offer device to EtherCAT master module
|
||||
if (ecdev_offer(dev, &tp->ecdev, "8139too", board_idx,
|
||||
ec_poll, THIS_MODULE)) {
|
||||
if (ecdev_offer(dev, ec_poll, THIS_MODULE, &tp->ecdev)) {
|
||||
printk(KERN_ERR PFX "Failed to offer device.\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1073,8 +1073,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
|
|||
/* dev is fully set up and ready to use now */
|
||||
|
||||
// offer device to EtherCAT master module
|
||||
if (ecdev_offer(dev, &tp->ecdev, "8139too", board_idx,
|
||||
ec_poll, THIS_MODULE)) {
|
||||
if (ecdev_offer(dev, ec_poll, THIS_MODULE, &tp->ecdev)) {
|
||||
printk(KERN_ERR PFX "Failed to offer device.\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1074,8 +1074,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
|
|||
/* dev is fully set up and ready to use now */
|
||||
|
||||
// offer device to EtherCAT master module
|
||||
if (ecdev_offer(dev, &tp->ecdev, "8139too", board_idx,
|
||||
ec_poll, THIS_MODULE)) {
|
||||
if (ecdev_offer(dev, ec_poll, THIS_MODULE, &tp->ecdev)) {
|
||||
printk(KERN_ERR PFX "Failed to offer device.\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1073,8 +1073,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
|
|||
/* dev is fully set up and ready to use now */
|
||||
|
||||
// offer device to EtherCAT master module
|
||||
if (ecdev_offer(dev, &tp->ecdev, "8139too", board_idx,
|
||||
ec_poll, THIS_MODULE)) {
|
||||
if (ecdev_offer(dev, ec_poll, THIS_MODULE, &tp->ecdev)) {
|
||||
printk(KERN_ERR PFX "Failed to offer device.\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,9 +66,8 @@ typedef void (*ec_pollfunc_t)(struct net_device *);
|
|||
/*****************************************************************************/
|
||||
// Offering/withdrawal functions
|
||||
|
||||
int ecdev_offer(struct net_device *net_dev, ec_device_t **,
|
||||
const char *driver_name, unsigned int board_index,
|
||||
ec_pollfunc_t poll, struct module *module);
|
||||
int ecdev_offer(struct net_device *net_dev, ec_pollfunc_t poll,
|
||||
struct module *module, ec_device_t **);
|
||||
void ecdev_withdraw(ec_device_t *device);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -3336,8 +3336,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
|
|||
np->autoneg = 1;
|
||||
|
||||
// offer device to EtherCAT master module
|
||||
if (ecdev_offer(dev, &np->ecdev, "forcedeth", board_idx, ec_poll,
|
||||
THIS_MODULE)) {
|
||||
if (ecdev_offer(dev, ec_poll, THIS_MODULE, &np->ecdev)) {
|
||||
printk(KERN_ERR "forcedeth: Failed to offer device.\n");
|
||||
goto out_freering;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4628,8 +4628,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
|
|||
np->autoneg = 1;
|
||||
|
||||
// offer device to EtherCAT master module
|
||||
if (ecdev_offer(dev, &np->ecdev, "forcedeth", board_idx, ec_poll,
|
||||
THIS_MODULE)) {
|
||||
if (ecdev_offer(dev, ec_poll, THIS_MODULE, &np->ecdev)) {
|
||||
printk(KERN_ERR "forcedeth: Failed to offer device.\n");
|
||||
goto out_error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ include $(src)/../config.kbuild
|
|||
|
||||
obj-m := ec_master.o
|
||||
|
||||
ec_master-objs := module.o master.o device.o device_id.o pdo.o sync.o fmmu.o \
|
||||
slave.o datagram.o domain.o mailbox.o canopen.o ethernet.o fsm_sii.o \
|
||||
fsm_change.o fsm_coe.o fsm_mapping.o fsm_slave.o fsm_master.o xmldev.o
|
||||
ec_master-objs := module.o master.o device.o pdo.o sync.o fmmu.o slave.o \
|
||||
datagram.o domain.o mailbox.o canopen.o ethernet.o fsm_sii.o fsm_change.o \
|
||||
fsm_coe.o fsm_mapping.o fsm_slave.o fsm_master.o xmldev.o
|
||||
|
||||
ifeq ($(EC_DBG_IF),1)
|
||||
ec_master-objs += debug.o
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ EXTRA_DIST = \
|
|||
datagram.c datagram.h \
|
||||
debug.c debug.h \
|
||||
device.c device.h \
|
||||
device_id.c device_id.h \
|
||||
pdo.c pdo.h \
|
||||
sync.c sync.h \
|
||||
fmmu.c fmmu.h \
|
||||
|
|
|
|||
|
|
@ -1,222 +0,0 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The IgH EtherCAT Master is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* The right to use EtherCAT Technology is granted and comes free of
|
||||
* charge under condition of compatibility of product made by
|
||||
* Licensee. People intending to distribute/sell products based on the
|
||||
* code, have to sign an agreement to guarantee that products using
|
||||
* software based on IgH EtherCAT master stay compatible with the actual
|
||||
* EtherCAT specification (which are released themselves as an open
|
||||
* standard) as the (only) precondition to have the right to use EtherCAT
|
||||
* Technology, IP and trade marks.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT device ID.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "device_id.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int ec_device_id_parse_mac(ec_device_id_t *dev_id,
|
||||
const char *src, const char **remainder)
|
||||
{
|
||||
unsigned int i, value;
|
||||
char *rem;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++) {
|
||||
value = simple_strtoul(src, &rem, 16);
|
||||
if (rem != src + 2
|
||||
|| value > 0xFF
|
||||
|| (i < ETH_ALEN - 1 && *rem != ':')) {
|
||||
return -1;
|
||||
}
|
||||
dev_id->octets[i] = value;
|
||||
if (i < ETH_ALEN - 1)
|
||||
src = rem + 1;
|
||||
}
|
||||
|
||||
dev_id->type = ec_device_id_mac;
|
||||
*remainder = rem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_device_id_clear_list(struct list_head *ids)
|
||||
{
|
||||
ec_device_id_t *dev_id, *next_dev_id;
|
||||
|
||||
list_for_each_entry_safe(dev_id, next_dev_id, ids, list) {
|
||||
list_del(&dev_id->list);
|
||||
kfree(dev_id);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int ec_device_id_create_list(struct list_head *ids, const char *src)
|
||||
{
|
||||
const char *rem;
|
||||
ec_device_id_t *dev_id;
|
||||
unsigned int index = 0;
|
||||
|
||||
while (*src) {
|
||||
// allocate new device ID
|
||||
if (!(dev_id = kmalloc(sizeof(ec_device_id_t), GFP_KERNEL))) {
|
||||
EC_ERR("Out of memory!\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (*src == ';') { // empty device ID
|
||||
dev_id->type = ec_device_id_empty;
|
||||
}
|
||||
else if (*src == 'M') {
|
||||
src++;
|
||||
if (ec_device_id_parse_mac(dev_id, src, &rem)) {
|
||||
EC_ERR("Device ID %u: Invalid MAC syntax!\n", index);
|
||||
kfree(dev_id);
|
||||
goto out_free;
|
||||
}
|
||||
src = rem;
|
||||
}
|
||||
else {
|
||||
EC_ERR("Device ID %u: Unknown format \'%c\'!\n", index, *src);
|
||||
kfree(dev_id);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
list_add_tail(&dev_id->list, ids);
|
||||
|
||||
if (*src) {
|
||||
if (*src != ';') {
|
||||
EC_ERR("Invalid delimiter '%c' after device ID %i!\n",
|
||||
*src, index);
|
||||
goto out_free;
|
||||
}
|
||||
src++; // skip delimiter
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
ec_device_id_clear_list(ids);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ec_device_id_process_params(const char *main, const char *backup,
|
||||
struct list_head *main_ids, struct list_head *backup_ids)
|
||||
{
|
||||
ec_device_id_t *id;
|
||||
unsigned int main_count = 0, backup_count = 0;
|
||||
|
||||
if (ec_device_id_create_list(main_ids, main))
|
||||
return -1;
|
||||
|
||||
if (ec_device_id_create_list(backup_ids, backup))
|
||||
return -1;
|
||||
|
||||
// count main device IDs and check for empty ones
|
||||
list_for_each_entry(id, main_ids, list) {
|
||||
if (id->type == ec_device_id_empty) {
|
||||
EC_ERR("Main device IDs may not be empty!\n");
|
||||
return -1;
|
||||
}
|
||||
main_count++;
|
||||
}
|
||||
|
||||
// count backup device IDs
|
||||
list_for_each_entry(id, backup_ids, list) {
|
||||
backup_count++;
|
||||
}
|
||||
|
||||
// fill up backup device IDs
|
||||
while (backup_count < main_count) {
|
||||
if (!(id = kmalloc(sizeof(ec_device_id_t), GFP_KERNEL))) {
|
||||
EC_ERR("Out of memory!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
id->type = ec_device_id_empty;
|
||||
list_add_tail(&id->list, backup_ids);
|
||||
backup_count++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ec_device_id_check(const ec_device_id_t *dev_id,
|
||||
const struct net_device *dev, const char *driver_name,
|
||||
unsigned int device_index)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
switch (dev_id->type) {
|
||||
case ec_device_id_mac:
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
if (dev->dev_addr[i] != dev_id->octets[i])
|
||||
return 0;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
ssize_t ec_device_id_print(const ec_device_id_t *dev_id, char *buffer)
|
||||
{
|
||||
off_t off = 0;
|
||||
unsigned int i;
|
||||
|
||||
switch (dev_id->type) {
|
||||
case ec_device_id_empty:
|
||||
off += sprintf(buffer + off, "none");
|
||||
break;
|
||||
case ec_device_id_mac:
|
||||
off += sprintf(buffer + off, "MAC ");
|
||||
for (i = 0; i < ETH_ALEN; i++) {
|
||||
off += sprintf(buffer + off, "%02X", dev_id->octets[i]);
|
||||
if (i < ETH_ALEN - 1) off += sprintf(buffer + off, ":");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The IgH EtherCAT Master is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* The right to use EtherCAT Technology is granted and comes free of
|
||||
* charge under condition of compatibility of product made by
|
||||
* Licensee. People intending to distribute/sell products based on the
|
||||
* code, have to sign an agreement to guarantee that products using
|
||||
* software based on IgH EtherCAT master stay compatible with the actual
|
||||
* EtherCAT specification (which are released themselves as an open
|
||||
* standard) as the (only) precondition to have the right to use EtherCAT
|
||||
* Technology, IP and trade marks.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT device ID structure.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef _EC_DEVICE_ID_H_
|
||||
#define _EC_DEVICE_ID_H_
|
||||
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
ec_device_id_empty,
|
||||
ec_device_id_mac
|
||||
}
|
||||
ec_device_id_type_t;
|
||||
|
||||
typedef struct {
|
||||
struct list_head list;
|
||||
ec_device_id_type_t type;
|
||||
unsigned char octets[ETH_ALEN];
|
||||
}
|
||||
ec_device_id_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ec_device_id_process_params(const char *, const char *,
|
||||
struct list_head *, struct list_head *);
|
||||
void ec_device_id_clear_list(struct list_head *);
|
||||
int ec_device_id_check(const ec_device_id_t *, const struct net_device *,
|
||||
const char *, unsigned int);
|
||||
ssize_t ec_device_id_print(const ec_device_id_t *, char *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
|
@ -157,6 +157,8 @@ extern char *ec_master_version_str;
|
|||
void ec_print_data(const uint8_t *, size_t);
|
||||
void ec_print_data_diff(const uint8_t *, const uint8_t *, size_t);
|
||||
size_t ec_state_string(uint8_t, char *);
|
||||
ssize_t ec_mac_print(const uint8_t *, char *);
|
||||
int ec_mac_is_zero(const uint8_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
100
master/master.c
100
master/master.c
|
|
@ -54,7 +54,6 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_master_clear(struct kobject *);
|
||||
void ec_master_destroy_domains(ec_master_t *);
|
||||
void ec_master_sync_io(ec_master_t *);
|
||||
static int ec_master_idle_thread(ec_master_t *);
|
||||
|
|
@ -85,7 +84,7 @@ static struct sysfs_ops ec_sysfs_ops = {
|
|||
};
|
||||
|
||||
static struct kobj_type ktype_ec_master = {
|
||||
.release = ec_master_clear,
|
||||
.release = NULL,
|
||||
.sysfs_ops = &ec_sysfs_ops,
|
||||
.default_attrs = ec_def_attrs
|
||||
};
|
||||
|
|
@ -102,9 +101,8 @@ static struct kobj_type ktype_ec_master = {
|
|||
int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
||||
struct kobject *module_kobj, /**< kobject of the master module */
|
||||
unsigned int index, /**< master index */
|
||||
const ec_device_id_t *main_id, /**< ID of main device */
|
||||
const ec_device_id_t *backup_id, /**< ID of main device */
|
||||
unsigned int eoeif_count /**< number of EoE interfaces */
|
||||
const uint8_t *main_mac, /**< MAC address of main device */
|
||||
const uint8_t *backup_mac /**< MAC address of backup device */
|
||||
)
|
||||
{
|
||||
ec_eoe_t *eoe, *next_eoe;
|
||||
|
|
@ -113,8 +111,8 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
|||
atomic_set(&master->available, 1);
|
||||
master->index = index;
|
||||
|
||||
master->main_device_id = main_id;
|
||||
master->backup_device_id = backup_id;
|
||||
master->main_mac = main_mac;
|
||||
master->backup_mac = backup_mac;
|
||||
init_MUTEX(&master->device_sem);
|
||||
|
||||
master->mode = EC_MASTER_MODE_ORPHANED;
|
||||
|
|
@ -175,19 +173,6 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
|||
if (ec_device_init(&master->backup_device, master))
|
||||
goto out_clear_main;
|
||||
|
||||
// create EoE handlers
|
||||
for (i = 0; i < eoeif_count; i++) {
|
||||
if (!(eoe = (ec_eoe_t *) kmalloc(sizeof(ec_eoe_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate EoE-Object.\n");
|
||||
goto out_clear_eoe;
|
||||
}
|
||||
if (ec_eoe_init(eoe)) {
|
||||
kfree(eoe);
|
||||
goto out_clear_eoe;
|
||||
}
|
||||
list_add_tail(&eoe->list, &master->eoe_handlers);
|
||||
}
|
||||
|
||||
// init state machine datagram
|
||||
ec_datagram_init(&master->fsm_datagram);
|
||||
if (ec_datagram_prealloc(&master->fsm_datagram, EC_MAX_DATA_SIZE)) {
|
||||
|
|
@ -233,35 +218,22 @@ out_return:
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Master destructor.
|
||||
Clears the kobj-hierarchy bottom up and frees the master.
|
||||
*/
|
||||
|
||||
void ec_master_destroy(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
ec_master_destroy_slaves(master);
|
||||
ec_master_destroy_domains(master);
|
||||
|
||||
// destroy self
|
||||
kobject_del(&master->kobj);
|
||||
kobject_put(&master->kobj); // free master
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Clear and free master.
|
||||
This method is called by the kobject,
|
||||
once there are no more references to it.
|
||||
*/
|
||||
|
||||
void ec_master_clear(struct kobject *kobj /**< kobject of the master */)
|
||||
void ec_master_clear(
|
||||
ec_master_t *master /**< EtherCAT master */
|
||||
)
|
||||
{
|
||||
ec_master_t *master = container_of(kobj, ec_master_t, kobj);
|
||||
ec_eoe_t *eoe, *next_eoe;
|
||||
ec_datagram_t *datagram, *next_datagram;
|
||||
|
||||
ec_master_destroy_slaves(master);
|
||||
ec_master_destroy_domains(master);
|
||||
|
||||
// list of EEPROM requests is empty,
|
||||
// otherwise master could not be cleared.
|
||||
|
||||
|
|
@ -285,9 +257,11 @@ void ec_master_clear(struct kobject *kobj /**< kobject of the master */)
|
|||
ec_device_clear(&master->backup_device);
|
||||
ec_device_clear(&master->main_device);
|
||||
|
||||
EC_INFO("Master %i freed.\n", master->index);
|
||||
// destroy self
|
||||
kobject_del(&master->kobj);
|
||||
kobject_put(&master->kobj);
|
||||
|
||||
kfree(master);
|
||||
EC_INFO("Master %u freed.\n", master->index);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -945,30 +919,34 @@ schedule:
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
ssize_t ec_master_device_info(const ec_device_t *device,
|
||||
const ec_device_id_t *dev_id,
|
||||
char *buffer)
|
||||
ssize_t ec_master_device_info(
|
||||
const ec_device_t *device,
|
||||
const uint8_t *mac,
|
||||
char *buffer
|
||||
)
|
||||
{
|
||||
unsigned int frames_lost;
|
||||
off_t off = 0;
|
||||
|
||||
off += ec_device_id_print(dev_id, buffer + off);
|
||||
|
||||
if (device->dev) {
|
||||
off += sprintf(buffer + off, " (connected).\n");
|
||||
off += sprintf(buffer + off, " Frames sent: %u\n",
|
||||
device->tx_count);
|
||||
off += sprintf(buffer + off, " Frames received: %u\n",
|
||||
device->rx_count);
|
||||
frames_lost = device->tx_count - device->rx_count;
|
||||
if (frames_lost) frames_lost--;
|
||||
off += sprintf(buffer + off, " Frames lost: %u\n", frames_lost);
|
||||
}
|
||||
else if (dev_id->type != ec_device_id_empty) {
|
||||
off += sprintf(buffer + off, " (WAITING).\n");
|
||||
if (ec_mac_is_zero(mac)) {
|
||||
off += sprintf(buffer + off, "none.\n");
|
||||
}
|
||||
else {
|
||||
off += sprintf(buffer + off, ".\n");
|
||||
off += ec_mac_print(mac, buffer + off);
|
||||
|
||||
if (device->dev) {
|
||||
off += sprintf(buffer + off, " (connected).\n");
|
||||
off += sprintf(buffer + off, " Frames sent: %u\n",
|
||||
device->tx_count);
|
||||
off += sprintf(buffer + off, " Frames received: %u\n",
|
||||
device->rx_count);
|
||||
frames_lost = device->tx_count - device->rx_count;
|
||||
if (frames_lost) frames_lost--;
|
||||
off += sprintf(buffer + off, " Frames lost: %u\n", frames_lost);
|
||||
}
|
||||
else {
|
||||
off += sprintf(buffer + off, " (WAITING).\n");
|
||||
}
|
||||
}
|
||||
|
||||
return off;
|
||||
|
|
@ -1014,10 +992,10 @@ ssize_t ec_master_info(ec_master_t *master, /**< EtherCAT master */
|
|||
|
||||
off += sprintf(buffer + off, " Main: ");
|
||||
off += ec_master_device_info(&master->main_device,
|
||||
master->main_device_id, buffer + off);
|
||||
master->main_mac, buffer + off);
|
||||
off += sprintf(buffer + off, " Backup: ");
|
||||
off += ec_master_device_info(&master->backup_device,
|
||||
master->backup_device_id, buffer + off);
|
||||
master->backup_mac, buffer + off);
|
||||
|
||||
up(&master->device_sem);
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@
|
|||
#include <asm/semaphore.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "device_id.h"
|
||||
#include "domain.h"
|
||||
#include "fsm_master.h"
|
||||
|
||||
|
|
@ -94,16 +93,15 @@ ec_stats_t;
|
|||
|
||||
struct ec_master
|
||||
{
|
||||
struct list_head list; /**< list item for module's master list */
|
||||
atomic_t available; /**< zero, if the master is reserved for RT */
|
||||
unsigned int index; /**< master index */
|
||||
|
||||
struct kobject kobj; /**< kobject */
|
||||
|
||||
ec_device_t main_device; /**< EtherCAT device */
|
||||
const ec_device_id_t *main_device_id; /**< ID of main device */
|
||||
const uint8_t *main_mac; /**< MAC address of main device */
|
||||
ec_device_t backup_device; /**< EtherCAT backup device */
|
||||
const ec_device_id_t *backup_device_id; /**< ID of backup device */
|
||||
const uint8_t *backup_mac; /**< MAC address of backup device */
|
||||
struct semaphore device_sem; /**< device semaphore */
|
||||
|
||||
ec_fsm_master_t fsm; /**< master state machine */
|
||||
|
|
@ -164,8 +162,8 @@ struct ec_master
|
|||
|
||||
// master creation/deletion
|
||||
int ec_master_init(ec_master_t *, struct kobject *, unsigned int,
|
||||
const ec_device_id_t *, const ec_device_id_t *, unsigned int);
|
||||
void ec_master_destroy(ec_master_t *);
|
||||
const uint8_t *, const uint8_t *);
|
||||
void ec_master_clear(ec_master_t *);
|
||||
|
||||
// mode transitions
|
||||
int ec_master_enter_idle_mode(ec_master_t *);
|
||||
|
|
|
|||
268
master/module.c
268
master/module.c
|
|
@ -49,19 +49,28 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
int __init ec_init_module(void);
|
||||
void __exit ec_cleanup_module(void);
|
||||
#define MAX_MASTERS 5 /**< maximum number of masters */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct kobject ec_kobj; /**< kobject for master module */
|
||||
int __init ec_init_module(void);
|
||||
void __exit ec_cleanup_module(void);
|
||||
|
||||
static char *main; /**< main devices parameter */
|
||||
static char *backup; /**< backup devices parameter */
|
||||
static int ec_mac_parse(uint8_t *, const char *, int);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct kobject kobj; /**< kobject for master module */
|
||||
|
||||
static char *main[MAX_MASTERS]; /**< main devices parameter */
|
||||
static char *backup[MAX_MASTERS]; /**< backup devices parameter */
|
||||
|
||||
static ec_master_t *masters; /**< master array */
|
||||
static unsigned int master_count; /**< number of masters */
|
||||
static unsigned int backup_count; /**< number of backup devices */
|
||||
|
||||
static uint8_t macs[MAX_MASTERS][2][ETH_ALEN]; /**< MAC addresses */
|
||||
|
||||
static LIST_HEAD(main_ids); /**< list of main device IDs */
|
||||
static LIST_HEAD(backup_ids); /**< list of main device IDs */
|
||||
static LIST_HEAD(masters); /**< list of masters */
|
||||
static dev_t device_number; /**< XML character device number */
|
||||
ec_xmldev_t xmldev; /**< XML character device */
|
||||
|
||||
|
|
@ -76,104 +85,95 @@ MODULE_DESCRIPTION("EtherCAT master driver module");
|
|||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(EC_MASTER_VERSION);
|
||||
|
||||
module_param(main, charp, S_IRUGO);
|
||||
MODULE_PARM_DESC(main, "main device IDs");
|
||||
module_param(backup, charp, S_IRUGO);
|
||||
MODULE_PARM_DESC(backup, "backup device IDs");
|
||||
module_param_array(main, charp, &master_count, S_IRUGO);
|
||||
MODULE_PARM_DESC(main, "MAC addresses of main devices");
|
||||
module_param_array(backup, charp, &backup_count, S_IRUGO);
|
||||
MODULE_PARM_DESC(backup, "MAC addresses of backup devices");
|
||||
|
||||
/** \endcond */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Module initialization.
|
||||
Initializes \a ec_master_count masters.
|
||||
\return 0 on success, else < 0
|
||||
*/
|
||||
* Module initialization.
|
||||
* Initializes \a ec_master_count masters.
|
||||
* \return 0 on success, else < 0
|
||||
*/
|
||||
|
||||
int __init ec_init_module(void)
|
||||
{
|
||||
ec_master_t *master, *next;
|
||||
ec_device_id_t *main_dev_id, *backup_dev_id;
|
||||
unsigned int master_index = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
EC_INFO("Master driver %s\n", EC_MASTER_VERSION);
|
||||
|
||||
// init kobject and add it to the hierarchy
|
||||
memset(&ec_kobj, 0x00, sizeof(struct kobject));
|
||||
kobject_init(&ec_kobj); // no ktype
|
||||
memset(&kobj, 0x00, sizeof(struct kobject));
|
||||
kobject_init(&kobj); // no ktype
|
||||
|
||||
if (kobject_set_name(&ec_kobj, "ethercat")) {
|
||||
if (kobject_set_name(&kobj, "ethercat")) {
|
||||
EC_ERR("Failed to set module kobject name.\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
if (kobject_add(&ec_kobj)) {
|
||||
if (kobject_add(&kobj)) {
|
||||
EC_ERR("Failed to add module kobject.\n");
|
||||
ret = -EEXIST;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
if (alloc_chrdev_region(&device_number, 0, 1, "EtherCAT")) {
|
||||
EC_ERR("Failed to obtain device number!\n");
|
||||
ret = -EBUSY;
|
||||
goto out_del;
|
||||
}
|
||||
|
||||
if (ec_device_id_process_params(main, backup, &main_ids, &backup_ids))
|
||||
goto out_cdev;
|
||||
|
||||
// create as many masters as main device IDs present
|
||||
if (!list_empty(&main_ids)) {
|
||||
// main_ids and backup_ids are of equal size at this point
|
||||
main_dev_id =
|
||||
list_entry(main_ids.next, ec_device_id_t, list);
|
||||
backup_dev_id =
|
||||
list_entry(backup_ids.next, ec_device_id_t, list);
|
||||
// zero MAC addresses
|
||||
memset(macs, 0x00, sizeof(uint8_t) * MAX_MASTERS * 2 * ETH_ALEN);
|
||||
|
||||
// process MAC parameters
|
||||
for (i = 0; i < master_count; i++) {
|
||||
if (ec_mac_parse(macs[i][0], main[i], 0)) {
|
||||
ret = -EINVAL;
|
||||
goto out_cdev;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!(master = (ec_master_t *)
|
||||
kmalloc(sizeof(ec_master_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate memory for EtherCAT master %i.\n",
|
||||
master_index);
|
||||
goto out_free_masters;
|
||||
}
|
||||
|
||||
if (ec_master_init(master, &ec_kobj, master_index,
|
||||
main_dev_id, backup_dev_id, 0))
|
||||
goto out_free_masters;
|
||||
|
||||
list_add_tail(&master->list, &masters);
|
||||
master_index++;
|
||||
|
||||
// last device IDs?
|
||||
if (main_dev_id->list.next == &main_ids)
|
||||
break;
|
||||
|
||||
// next device IDs
|
||||
main_dev_id =
|
||||
list_entry(main_dev_id->list.next, ec_device_id_t, list);
|
||||
backup_dev_id =
|
||||
list_entry(backup_dev_id->list.next, ec_device_id_t, list);
|
||||
if (i < backup_count && ec_mac_parse(macs[i][1], backup[i], 1)) {
|
||||
ret = -EINVAL;
|
||||
goto out_cdev;
|
||||
}
|
||||
}
|
||||
|
||||
if (master_count) {
|
||||
if (!(masters = kmalloc(sizeof(ec_master_t) * master_count,
|
||||
GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate memory for EtherCAT masters.\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_cdev;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < master_count; i++) {
|
||||
if (ec_master_init(&masters[i], &kobj, i, macs[i][0], macs[i][1])) {
|
||||
ret = -EIO;
|
||||
goto out_free_masters;
|
||||
}
|
||||
}
|
||||
|
||||
EC_INFO("%u master%s waiting for devices.\n",
|
||||
master_index, (master_index == 1 ? "" : "s"));
|
||||
return 0;
|
||||
master_count, (master_count == 1 ? "" : "s"));
|
||||
return ret;
|
||||
|
||||
out_free_masters:
|
||||
list_for_each_entry_safe(master, next, &masters, list) {
|
||||
list_del(&master->list);
|
||||
ec_master_destroy(master);
|
||||
}
|
||||
ec_device_id_clear_list(&main_ids);
|
||||
ec_device_id_clear_list(&backup_ids);
|
||||
for (i--; i >= 0; i--) ec_master_clear(&masters[i]);
|
||||
kfree(masters);
|
||||
out_cdev:
|
||||
unregister_chrdev_region(device_number, 1);
|
||||
out_del:
|
||||
kobject_del(&ec_kobj);
|
||||
kobject_del(&kobj);
|
||||
out_put:
|
||||
kobject_put(&ec_kobj);
|
||||
return -1;
|
||||
kobject_put(&kobj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -185,41 +185,96 @@ out_put:
|
|||
|
||||
void __exit ec_cleanup_module(void)
|
||||
{
|
||||
ec_master_t *master, *next;
|
||||
unsigned int i;
|
||||
|
||||
EC_INFO("Cleaning up master module...\n");
|
||||
|
||||
list_for_each_entry_safe(master, next, &masters, list) {
|
||||
list_del(&master->list);
|
||||
ec_master_destroy(master);
|
||||
for (i = 0; i < master_count; i++) {
|
||||
ec_master_clear(&masters[i]);
|
||||
}
|
||||
|
||||
ec_device_id_clear_list(&main_ids);
|
||||
ec_device_id_clear_list(&backup_ids);
|
||||
if (master_count)
|
||||
kfree(masters);
|
||||
|
||||
unregister_chrdev_region(device_number, 1);
|
||||
kobject_del(&ec_kobj);
|
||||
kobject_put(&ec_kobj);
|
||||
kobject_del(&kobj);
|
||||
kobject_put(&kobj);
|
||||
|
||||
EC_INFO("Master module cleaned up.\n");
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* MAC address functions
|
||||
****************************************************************************/
|
||||
|
||||
int ec_mac_equal(const uint8_t *mac1, const uint8_t *mac2)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
if (mac1[i] != mac2[i])
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Gets a handle to a certain master.
|
||||
\returns pointer to master
|
||||
*/
|
||||
|
||||
ec_master_t *ec_find_master(unsigned int master_index /**< master index */)
|
||||
ssize_t ec_mac_print(const uint8_t *mac, char *buffer)
|
||||
{
|
||||
ec_master_t *master;
|
||||
|
||||
list_for_each_entry(master, &masters, list) {
|
||||
if (master->index == master_index) return master;
|
||||
off_t off = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++) {
|
||||
off += sprintf(buffer + off, "%02X", mac[i]);
|
||||
if (i < ETH_ALEN - 1) off += sprintf(buffer + off, ":");
|
||||
}
|
||||
|
||||
EC_ERR("Master %i does not exist!\n", master_index);
|
||||
return NULL;
|
||||
return off;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ec_mac_is_zero(const uint8_t *mac)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
if (mac[i])
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int ec_mac_parse(uint8_t *mac, const char *src, int allow_empty)
|
||||
{
|
||||
unsigned int i, value;
|
||||
const char *orig = src;
|
||||
char *rem;
|
||||
|
||||
if (!strlen(src)) {
|
||||
if (allow_empty){
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
EC_ERR("MAC address may not be empty.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++) {
|
||||
value = simple_strtoul(src, &rem, 16);
|
||||
if (rem != src + 2
|
||||
|| value > 0xFF
|
||||
|| (i < ETH_ALEN - 1 && *rem != ':')) {
|
||||
EC_ERR("Invalid MAC address \"%s\".\n", orig);
|
||||
return -EINVAL;
|
||||
}
|
||||
mac[i] = value;
|
||||
if (i < ETH_ALEN - 1)
|
||||
src = rem + 1; // skip colon
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -331,20 +386,19 @@ size_t ec_state_string(uint8_t states, /**< slave states */
|
|||
*/
|
||||
|
||||
int ecdev_offer(struct net_device *net_dev, /**< net_device to offer */
|
||||
ec_device_t **ecdev, /**< pointer to store a device on success */
|
||||
const char *driver_name, /**< name of the network driver */
|
||||
unsigned int device_index, /**< index of the supported device */
|
||||
ec_pollfunc_t poll, /**< device poll function */
|
||||
struct module *module /**< pointer to the module */
|
||||
struct module *module, /**< pointer to the module */
|
||||
ec_device_t **ecdev /**< pointer to store a device on success */
|
||||
)
|
||||
{
|
||||
ec_master_t *master;
|
||||
char str[50]; // FIXME
|
||||
char str[20];
|
||||
unsigned int i;
|
||||
|
||||
list_for_each_entry(master, &masters, list) {
|
||||
if (ec_device_id_check(master->main_device_id, net_dev,
|
||||
driver_name, device_index)) {
|
||||
ec_device_id_print(master->main_device_id, str);
|
||||
for (i = 0; i < master_count; i++) {
|
||||
master = &masters[i];
|
||||
if (ec_mac_equal(master->main_mac, net_dev->dev_addr)) {
|
||||
ec_mac_print(master->main_mac, str);
|
||||
EC_INFO("Accepting device %s for master %u.\n",
|
||||
str, master->index);
|
||||
|
||||
|
|
@ -367,6 +421,10 @@ int ecdev_offer(struct net_device *net_dev, /**< net_device to offer */
|
|||
*ecdev = &master->main_device; // offer accepted
|
||||
return 0; // no error
|
||||
}
|
||||
else if (master->debug_level) {
|
||||
ec_mac_print(master->main_mac, str);
|
||||
EC_DBG("Master %u declined device %s.\n", master->index, str);
|
||||
}
|
||||
}
|
||||
|
||||
*ecdev = NULL; // offer declined
|
||||
|
|
@ -387,9 +445,9 @@ int ecdev_offer(struct net_device *net_dev, /**< net_device to offer */
|
|||
void ecdev_withdraw(ec_device_t *device /**< EtherCAT device */)
|
||||
{
|
||||
ec_master_t *master = device->master;
|
||||
char str[50]; // FIXME
|
||||
char str[20];
|
||||
|
||||
ec_device_id_print(master->main_device_id, str);
|
||||
ec_mac_print(master->main_mac, str);
|
||||
|
||||
EC_INFO("Master %u releasing main device %s.\n", master->index, str);
|
||||
|
||||
|
|
@ -468,7 +526,11 @@ ec_master_t *ecrt_request_master(unsigned int master_index
|
|||
|
||||
EC_INFO("Requesting master %i...\n", master_index);
|
||||
|
||||
if (!(master = ec_find_master(master_index))) goto out_return;
|
||||
if (master_index >= master_count) {
|
||||
EC_ERR("Invalid master index %u.\n", master_index);
|
||||
goto out_return;
|
||||
}
|
||||
master = &masters[master_index];
|
||||
|
||||
if (!atomic_dec_and_test(&master->available)) {
|
||||
atomic_inc(&master->available);
|
||||
|
|
|
|||
|
|
@ -68,16 +68,14 @@ fi
|
|||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
function make_device_id()
|
||||
function parse_mac_address()
|
||||
{
|
||||
if [ -z "${1}" ]; then
|
||||
DEVICE_ID=";"
|
||||
MAC=""
|
||||
elif echo ${1} | grep -qE '^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$'; then
|
||||
DEVICE_ID="M${1};"
|
||||
elif echo ${1} | grep -qE '^[^:]+:[0-9]+$'; then
|
||||
DEVICE_ID="D${1};"
|
||||
MAC=${1}
|
||||
else
|
||||
echo Invalid device ID syntax in ${ETHERCAT_CONFIG}
|
||||
echo Invalid MAC address \"${1}\" in ${ETHERCAT_CONFIG}
|
||||
/bin/false
|
||||
rc_status -v
|
||||
rc_exit
|
||||
|
|
@ -103,10 +101,16 @@ start)
|
|||
BACKUP=$(eval echo "\${MASTER${MASTER_INDEX}_BACKUP}")
|
||||
if [ -z "${DEVICE}" ]; then break; fi
|
||||
|
||||
make_device_id ${DEVICE}
|
||||
DEVICES=${DEVICES}${DEVICE_ID}
|
||||
make_device_id ${BACKUP}
|
||||
BACKUPS=${BACKUPS}${DEVICE_ID}
|
||||
if [ ${MASTER_INDEX} -gt 0 ]; then
|
||||
DEVICES=${DEVICES},
|
||||
BACKUPS=${BACKUPS},
|
||||
fi
|
||||
|
||||
parse_mac_address ${DEVICE}
|
||||
DEVICES=${DEVICES}${MAC}
|
||||
|
||||
parse_mac_address ${BACKUP}
|
||||
BACKUPS=${BACKUPS}${MAC}
|
||||
|
||||
MASTER_INDEX=$(expr ${MASTER_INDEX} + 1)
|
||||
done
|
||||
|
|
|
|||
|
|
@ -9,20 +9,14 @@
|
|||
#
|
||||
# Master device and backup-device settings.
|
||||
#
|
||||
# The MASTERX_DEVICE variable specifies the ethernet device for master 'X',
|
||||
# while the MASTERX_BACKUP variable specifies the backup ethernet device for
|
||||
# The MASTER<X>_DEVICE variable specifies the ethernet device for master 'X',
|
||||
# while the MASTER<X>_BACKUP variable specifies the backup ethernet device for
|
||||
# redundancy purposes.
|
||||
#
|
||||
# There are three formats for specifying ethernet devices:
|
||||
# 1) MAC address (example: "00:00:08:44:ab:66"). Specify the MAC address of
|
||||
# the ethernet card to use.
|
||||
# 2) PCI bus address (example: "01:1c.0"). Specify the PCU bis address of the
|
||||
# ethernet card to use.
|
||||
# 3) Driver and device index (example: "8139too:0"). Currently there are two
|
||||
# drivers available: "8139too" and "e100". The device index is the index
|
||||
# into driver-supported PCI cards.
|
||||
# Specify the MAC address (hexadecimal with colons) of the Ethernet device to
|
||||
# use. Example: 00:00:08:44:ab:66
|
||||
#
|
||||
# The MASTERX_DEVICE variables also determine, how many masters will be
|
||||
# The MASTER<X>_DEVICE variables also determine, how many masters will be
|
||||
# created: A non-empty variable MASTER0_DEVICE will create one master, adding
|
||||
# a non-empty variable MASTER1_DEVICE will create a second master, and so on.
|
||||
#
|
||||
|
|
|
|||
Loading…
Reference in New Issue