Allow only MAC addresses as device identifiers; replaced master list by
authorFlorian Pose <fp@igh-essen.com>
Thu, 08 Mar 2007 18:15:25 +0000
changeset 639 aa23c48dca2d
parent 638 b0994b4e3b37
child 640 16e9ad7d8e12
Allow only MAC addresses as device identifiers; replaced master list by
master array; hand ober MAC addresses with array module parameters.
NEWS
TODO
devices/8139too-2.6.13-ethercat.c
devices/8139too-2.6.17-ethercat.c
devices/8139too-2.6.18-ethercat.c
devices/8139too-2.6.19-ethercat.c
devices/ecdev.h
devices/forcedeth-2.6.17-ethercat.c
devices/forcedeth-2.6.19-ethercat.c
master/Kbuild
master/Makefile.am
master/device_id.c
master/device_id.h
master/globals.h
master/master.c
master/master.h
master/module.c
script/init.d/ethercat
script/sysconfig/ethercat
--- a/NEWS	Thu Mar 08 13:06:20 2007 +0000
+++ b/NEWS	Thu Mar 08 18:15:25 2007 +0000
@@ -9,12 +9,11 @@
 * 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.
--- a/TODO	Thu Mar 08 13:06:20 2007 +0000
+++ b/TODO	Thu Mar 08 18:15:25 2007 +0000
@@ -8,7 +8,6 @@
 
 * 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.
--- a/devices/8139too-2.6.13-ethercat.c	Thu Mar 08 13:06:20 2007 +0000
+++ b/devices/8139too-2.6.13-ethercat.c	Thu Mar 08 18:15:25 2007 +0000
@@ -1069,8 +1069,7 @@
 	/* 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;
 	}
--- a/devices/8139too-2.6.17-ethercat.c	Thu Mar 08 13:06:20 2007 +0000
+++ b/devices/8139too-2.6.17-ethercat.c	Thu Mar 08 18:15:25 2007 +0000
@@ -1073,8 +1073,7 @@
 	/* 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;
 	}
--- a/devices/8139too-2.6.18-ethercat.c	Thu Mar 08 13:06:20 2007 +0000
+++ b/devices/8139too-2.6.18-ethercat.c	Thu Mar 08 18:15:25 2007 +0000
@@ -1074,8 +1074,7 @@
 	/* 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;
 	}
--- a/devices/8139too-2.6.19-ethercat.c	Thu Mar 08 13:06:20 2007 +0000
+++ b/devices/8139too-2.6.19-ethercat.c	Thu Mar 08 18:15:25 2007 +0000
@@ -1073,8 +1073,7 @@
 	/* 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;
 	}
--- a/devices/ecdev.h	Thu Mar 08 13:06:20 2007 +0000
+++ b/devices/ecdev.h	Thu Mar 08 18:15:25 2007 +0000
@@ -66,9 +66,8 @@
 /*****************************************************************************/
 // 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);
 
 /*****************************************************************************/
--- a/devices/forcedeth-2.6.17-ethercat.c	Thu Mar 08 13:06:20 2007 +0000
+++ b/devices/forcedeth-2.6.17-ethercat.c	Thu Mar 08 18:15:25 2007 +0000
@@ -3336,8 +3336,7 @@
 	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;
 	}
--- a/devices/forcedeth-2.6.19-ethercat.c	Thu Mar 08 13:06:20 2007 +0000
+++ b/devices/forcedeth-2.6.19-ethercat.c	Thu Mar 08 18:15:25 2007 +0000
@@ -4628,8 +4628,7 @@
 	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;
 	}
--- a/master/Kbuild	Thu Mar 08 13:06:20 2007 +0000
+++ b/master/Kbuild	Thu Mar 08 18:15:25 2007 +0000
@@ -35,9 +35,9 @@
 
 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
--- a/master/Makefile.am	Thu Mar 08 13:06:20 2007 +0000
+++ b/master/Makefile.am	Thu Mar 08 18:15:25 2007 +0000
@@ -37,7 +37,6 @@
 	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 \
--- a/master/device_id.c	Thu Mar 08 13:06:20 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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;
-}
-                
-/*****************************************************************************/
--- a/master/device_id.h	Thu Mar 08 13:06:20 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/master/globals.h	Thu Mar 08 13:06:20 2007 +0000
+++ b/master/globals.h	Thu Mar 08 18:15:25 2007 +0000
@@ -157,6 +157,8 @@
 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 *);
 
 /*****************************************************************************/
 
--- a/master/master.c	Thu Mar 08 13:06:20 2007 +0000
+++ b/master/master.c	Thu Mar 08 18:15:25 2007 +0000
@@ -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 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 @@
 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 @@
     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 @@
     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)) {
@@ -234,34 +219,21 @@
 /*****************************************************************************/
 
 /**
-   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 */)
-{
-    ec_master_t *master = container_of(kobj, ec_master_t, kobj);
+void ec_master_clear(
+        ec_master_t *master /**< EtherCAT master */
+        )
+{
     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 @@
     ec_device_clear(&master->backup_device);
     ec_device_clear(&master->main_device);
 
-    EC_INFO("Master %i freed.\n", master->index);
-
-    kfree(master);
+    // destroy self
+    kobject_del(&master->kobj);
+    kobject_put(&master->kobj);
+
+    EC_INFO("Master %u freed.\n", master->index);
 }
 
 /*****************************************************************************/
@@ -945,30 +919,34 @@
 
 /*****************************************************************************/
 
-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 (ec_mac_is_zero(mac)) {
+        off += sprintf(buffer + off, "none.\n");
+    }
+    else {
+        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 if (dev_id->type != ec_device_id_empty) {
-        off += sprintf(buffer + off, " (WAITING).\n");      
-    }
-    else {
-        off += sprintf(buffer + off, ".\n");
+        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 @@
     
     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);
 
--- a/master/master.h	Thu Mar 08 13:06:20 2007 +0000
+++ b/master/master.h	Thu Mar 08 18:15:25 2007 +0000
@@ -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 @@
 
 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 @@
 
 // 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 *);
--- a/master/module.c	Thu Mar 08 13:06:20 2007 +0000
+++ b/master/module.c	Thu Mar 08 18:15:25 2007 +0000
@@ -49,19 +49,28 @@
 
 /*****************************************************************************/
 
+#define MAX_MASTERS 5 /**< maximum number of masters */
+
+/*****************************************************************************/
+
 int __init ec_init_module(void);
 void __exit ec_cleanup_module(void);
 
-/*****************************************************************************/
-
-struct kobject ec_kobj; /**< kobject for master module */
-
-static char *main; /**< main devices parameter */
-static char *backup; /**< backup devices parameter */
-
-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 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 dev_t device_number; /**< XML character device number */
 ec_xmldev_t xmldev; /**< XML character device */
 
@@ -76,104 +85,95 @@
 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
-    
-    if (kobject_set_name(&ec_kobj, "ethercat")) {
+    memset(&kobj, 0x00, sizeof(struct kobject));
+    kobject_init(&kobj); // no ktype
+    
+    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 @@
 
 void __exit ec_cleanup_module(void)
 {
-    ec_master_t *master, *next;
-
-    EC_INFO("Cleaning up master module...\n");
-
-    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);
+    unsigned int i;
+
+    for (i = 0; i < master_count; i++) {
+        ec_master_clear(&masters[i]);
+    }
+    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");
 }
 
-/*****************************************************************************/
-
-/**
-   Gets a handle to a certain master.
-   \returns pointer to master
-*/
-
-ec_master_t *ec_find_master(unsigned int master_index /**< master index */)
-{
-    ec_master_t *master;
-
-    list_for_each_entry(master, &masters, list) {
-        if (master->index == master_index) return master;
-    }
-
-    EC_ERR("Master %i does not exist!\n", master_index);
-    return NULL;
+/*****************************************************************************
+ * 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;
+}
+                
+/*****************************************************************************/
+
+ssize_t ec_mac_print(const uint8_t *mac, char *buffer)
+{
+    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, ":");
+    }
+
+    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 @@
 */
 
 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
-
-    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);
+    char str[20];
+    unsigned int i;
+
+    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 @@
             *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 @@
 void ecdev_withdraw(ec_device_t *device /**< EtherCAT device */)
 {
     ec_master_t *master = device->master;
-    char str[50]; // FIXME
-
-    ec_device_id_print(master->main_device_id, str);
+    char str[20];
+
+    ec_mac_print(master->main_mac, str);
     
     EC_INFO("Master %u releasing main device %s.\n", master->index, str);
     
@@ -468,7 +526,11 @@
 
     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);
--- a/script/init.d/ethercat	Thu Mar 08 13:06:20 2007 +0000
+++ b/script/init.d/ethercat	Thu Mar 08 18:15:25 2007 +0000
@@ -68,16 +68,14 @@
 
 #------------------------------------------------------------------------------
 
-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 @@
         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
--- a/script/sysconfig/ethercat	Thu Mar 08 13:06:20 2007 +0000
+++ b/script/sysconfig/ethercat	Thu Mar 08 18:15:25 2007 +0000
@@ -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.
 #