MERGE trunk -r428:447 -> branches/stable-1.0 (Complete EEPROM data, unloading buxfix, variable data, bridging) stable-1.0
authorFlorian Pose <fp@igh-essen.com>
Mon, 26 Jun 2006 15:04:06 +0000
branchstable-1.0
changeset 1621 4bbe090553f7
parent 1620 9d7453c16ade
child 1622 fe8777a69d4a
MERGE trunk -r428:447 -> branches/stable-1.0 (Complete EEPROM data, unloading buxfix, variable data, bridging)
FEATURES
Makefile
README
TODO
devices/8139too.c
devices/Makefile
ethercat.conf.tmpl
examples/mini/Makefile
examples/mini/kernel.conf.tmpl
examples/mini/mini.c
examples/msr/Makefile
examples/msr/kernel.conf.tmpl
examples/rtai/Makefile
examples/rtai/kernel.conf.tmpl
include/ecrt.h
master/Makefile
master/canopen.c
master/domain.c
master/ethernet.c
master/ethernet.h
master/fsm.c
master/fsm.h
master/mailbox.c
master/mailbox.h
master/master.c
master/master.h
master/slave.c
master/slave.h
master/types.c
script/ethercat.sh
script/install.sh
script/sysconfig
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FEATURES	Mon Jun 26 15:04:06 2006 +0000
@@ -0,0 +1,66 @@
+-------------------------------------------------------------------------------
+
+This is the FEATURES file of the IgH EtherCAT Master.
+
+$Id$
+
+-------------------------------------------------------------------------------
+
+General Features:
+
+* Runs as kernel module for Linux 2.6.
+
+* Comes with EtherCAT-capable network driver for RTL8139 and compatible
+  network interface cards.
+  - Interrupt-less network driver operation.
+  - Easy implementation of additional network drivers through common device
+    interface of the master.
+  - Runs even with PCMCIA cards.
+
+* Supports multiple EtherCAT masters on one machine.
+
+* Supports any realtime extension through independent architecture.
+  - RTAI, IPIPE, ADEOS, etc.
+  - Runs well even without realtime extensions.
+
+* Common kernel interface, for realtime modules using EtherCAT functionality.
+  - Synchronous and asynchronous sending and receiving of frames.
+  - Avoidance of unnecessary copy operations for process data.
+
+* Separating slave groups through domains.
+  - Handling of multiple slave groups with different sampling rates.
+  - Automatic calculation of process data mapping, FMMU- and sync manager
+    configuration within the domains.
+
+* Master finite state machine (FSM). Thus:
+  - Bus monitoring during realtime operation.
+  - Automatic reconfiguration of slaves on bus power failure during realtime
+    operation.
+  - Controlling of slave states during realtime operation.
+
+* Free-Run mode, if master is idle.
+  - Automatic scanning of slaves upon topology changes.
+  - Bus visualisation and EoE processing without realtime process connected.
+
+* Implements the CANopen-over-EtherCAT (CoE) protocol.
+  - Configuration of CoE-capable slaves via SDO interface.
+  - SDO dictionary listing.
+
+* Implements the Ethernet-over-EtherCAT (EoE) protocol.
+  - Creates virtual network devices that are automatically coupled to
+    EoE-capable	slaves.
+  - Thus natively supports either a switched or a routed EoE network
+    architecture.
+
+* User space interface via the System Filesystem (SysFS).
+  - User space tool for bus visualisation.
+  - Slave EĀ²PROM image reading and writing.
+
+* Seamless integration in your favourite Linux distibution.
+  - Master and network device configuration via sysconfig files.
+  - UnitedLinux compatible init script for master control.
+
+* Virtual read-only network interface for debugging purposes and for
+  "sniffing" the EtherCAT traffic (through Ethereal, or others).
+
+-------------------------------------------------------------------------------
--- a/Makefile	Mon May 29 09:54:18 2006 +0000
+++ b/Makefile	Mon Jun 26 15:04:06 2006 +0000
@@ -1,6 +1,8 @@
 #------------------------------------------------------------------------------
 #
-#  EtherCAT Makefile
+#  Makefile
+#
+#  IgH EtherCAT master
 #
 #  $Id$
 #
@@ -53,9 +55,17 @@
 
 KERNEL_DIR := /lib/modules/$(KERNEL)/build
 CURRENT_DIR := $(shell pwd)
+INSTALL_MOD_DIR := ethercat
 
 modules:
-	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR)
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) modules
+
+install: modules_install
+	@script/install.sh $(KERNEL)
+
+modules_install:
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) \
+		INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) modules_install
 
 clean: cleandoc
 	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean
@@ -66,9 +76,6 @@
 cleandoc:
 	@rm -rf doc
 
-install:
-	@script/install.sh $(KERNEL)
-
 #------------------------------------------------------------------------------
 
 endif
--- a/README	Mon May 29 09:54:18 2006 +0000
+++ b/README	Mon Jun 26 15:04:06 2006 +0000
@@ -18,7 +18,7 @@
 
 This is an Open-Source EtherCAT master implementation for Linux 2.6.
 
-For more information, see
+See the FEATURES file for a list of features. For more information, see
 
 http://etherlab.org
 
--- a/TODO	Mon May 29 09:54:18 2006 +0000
+++ b/TODO	Mon Jun 26 15:04:06 2006 +0000
@@ -1,21 +1,39 @@
+-------------------------------------------------------------------------------
 
 EtherCAT master TODO
-====================
 
 $Id$
 
-- Mailbox-Handler
-- Dispatching of received mailbox data?
-- File access over EtherCAT (FoE)
+-------------------------------------------------------------------------------
 
-- Number of frames the NIC can handle
-- Remove slave type information from master / read XML files from user space
+Important things to do:
 
-- eepro100 driver
-- VLAN tagging
+* New SDO-Configuration interface
 
-- Calculate bus topology
+* Remove slave type information from master / New RT Interface
 
-- Documentation
+* Always use state machines / remove simple IO code
 
-- User space tool for configuration and visualisation
+* SysFS interface
+  - Add secondary slave address
+  - Add SDO dictionary
+
+* Implement all EtherCAT commands
+
+* Determine number of frames the NIC can handle
+
+* Implement eepro100 driver
+
+-------------------------------------------------------------------------------
+
+Not-so-important things to do:
+
+* User space tool for configuration
+
+* Calculate bus topology
+
+* File access over EtherCAT (FoE)
+
+* Allow VLAN tagging
+
+-------------------------------------------------------------------------------
--- a/devices/8139too.c	Mon May 29 09:54:18 2006 +0000
+++ b/devices/8139too.c	Mon Jun 26 15:04:06 2006 +0000
@@ -133,6 +133,7 @@
 #define DRV_NAME	"ec_8139too"
 #define DRV_VERSION	"0.9.27"
 
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -342,6 +343,7 @@
 
 /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
+/* prevent driver from being loaded automatically */
 //MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
 
 /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
@@ -669,10 +671,8 @@
 
 /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
-MODULE_AUTHOR("Wilhelm Hagemeister <hm@igh-essen.com>,"
-              " Florian Pose <fp@igh-essen.com>");
-MODULE_DESCRIPTION("RealTek RTL-8139 Fast Ethernet"
-                   " driver with EtherCAT functionality");
+MODULE_AUTHOR("Florian Pose <fp@igh-essen.com>");
+MODULE_DESCRIPTION("RealTek RTL-8139 EtherCAT driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(COMPILE_INFO);
 
@@ -1050,8 +1050,8 @@
 	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
 	if (board_idx == ec_device_index) {
-            rtl_ec_net_dev = dev;
-            strcpy(dev->name, "ec0");
+        rtl_ec_net_dev = dev;
+        strcpy(dev->name, "ec0");
 	}
 
 	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
@@ -1098,7 +1098,6 @@
 		(debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1));
 	spin_lock_init (&tp->lock);
 	spin_lock_init (&tp->rx_lock);
-
 	init_waitqueue_head (&tp->thr_wait);
 	init_completion (&tp->thr_exited);
 	tp->mii.dev = dev;
@@ -1111,11 +1110,10 @@
 
 	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
-        if (dev != rtl_ec_net_dev) {
-            DPRINTK("About to register device named %s (%p)...\n",
-                    dev->name, dev);
-            i = register_netdev (dev);
-            if (i) goto err_out;
+    if (dev != rtl_ec_net_dev) {
+        DPRINTK("about to register device named %s (%p)...\n", dev->name, dev);
+        i = register_netdev (dev);
+        if (i) goto err_out;
 	}
 
 	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
@@ -1207,10 +1205,10 @@
 
 	assert (dev != NULL);
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-        if (dev != rtl_ec_net_dev) {
-            unregister_netdev (dev);
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+    if (dev != rtl_ec_net_dev) {
+        unregister_netdev (dev);
 	}
 
 	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
@@ -1417,16 +1415,12 @@
 
 	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
-#ifdef EC_DEBUG
-        printk(KERN_DEBUG "%s: open\n", dev->name);
-#endif
-
-        if (dev != rtl_ec_net_dev) {
-            retval = request_irq(dev->irq, rtl8139_interrupt,
-                                 SA_SHIRQ, dev->name, dev);
-            if (retval)
-                return retval;
-        }
+    if (dev != rtl_ec_net_dev) {
+	    retval = request_irq(dev->irq, rtl8139_interrupt,
+                             SA_SHIRQ, dev->name, dev);
+        if (retval)
+            return retval;
+    }
 
 	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
@@ -1434,24 +1428,24 @@
 					   &tp->tx_bufs_dma);
 	tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
 					   &tp->rx_ring_dma);
-	if (tp->tx_bufs == NULL || tp->rx_ring == NULL)
-        {
-                /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-                if (dev != rtl_ec_net_dev) {
-                    free_irq(dev->irq, dev);
-                }
-
-                /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
-                if (tp->tx_bufs)
-                  pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
-                                      tp->tx_bufs, tp->tx_bufs_dma);
-                if (tp->rx_ring)
-                  pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
-                                      tp->rx_ring, tp->rx_ring_dma);
-
-                return -ENOMEM;
+	if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+        if (dev != rtl_ec_net_dev) {
+            free_irq(dev->irq, dev);
+        }
+
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+        if (tp->tx_bufs)
+          pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+                              tp->tx_bufs, tp->tx_bufs_dma);
+        if (tp->rx_ring)
+          pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+                              tp->rx_ring, tp->rx_ring_dma);
+
+        return -ENOMEM;
+
 	}
 
 	tp->mii.full_duplex = tp->mii.force_media;
@@ -1460,40 +1454,45 @@
 	rtl8139_init_ring (dev);
 	rtl8139_hw_start (dev);
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-        if (dev != rtl_ec_net_dev) {
-            netif_start_queue (dev);
-
-            if (netif_msg_ifup(tp)) {
-                printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d"
-                       " GP Pins %2.2x %s-duplex.\n",
-                       dev->name, pci_resource_start (tp->pci_dev, 1),
-                       dev->irq, RTL_R8 (MediaStatus),
-                       tp->mii.full_duplex ? "full" : "half");
-            }
-
-            rtl8139_start_thread(dev);
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+    if (dev != rtl_ec_net_dev) {
+        netif_start_queue (dev);
+
+        if (netif_msg_ifup(tp))
+            printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d"
+                   " GP Pins %2.2x %s-duplex.\n",
+                   dev->name, pci_resource_start (tp->pci_dev, 1),
+                   dev->irq, RTL_R8 (MediaStatus),
+                   tp->mii.full_duplex ? "full" : "half");
+
+        rtl8139_start_thread(dev);
+    }
+
+	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+	return 0;
+}
+
+
+static void rtl_check_media (struct net_device *dev, unsigned int init_media)
+{
+	struct rtl8139_private *tp = netdev_priv(dev);
+
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+    if (dev != rtl_ec_net_dev) {
+        if (tp->phys[0] >= 0) {
+            mii_check_media(&tp->mii, netif_msg_link(tp), init_media);
         }
+    } else {
+        void __iomem *ioaddr = tp->mmio_addr;
+        uint16_t state = RTL_R16(BasicModeStatus) & BMSR_LSTATUS;
+        ecdev_link_state(rtl_ec_dev, state ? 1 : 0);
+    }
 
 	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
-	return 0;
-}
-
-
-static void rtl_check_media (struct net_device *dev, unsigned int init_media)
-{
-	struct rtl8139_private *tp = netdev_priv(dev);
-
-        if (dev == rtl_ec_net_dev) {
-            void __iomem *ioaddr = tp->mmio_addr;
-            uint16_t state = RTL_R16(BasicModeStatus) & BMSR_LSTATUS;
-            ecdev_link_state(rtl_ec_dev, state ? 1 : 0);
-        }
-        else if (tp->phys[0] >= 0) {
-		mii_check_media(&tp->mii, netif_msg_link(tp), init_media);
-	}
 }
 
 /* Start the hardware at open or resume. */
@@ -1560,9 +1559,9 @@
 
 	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
-        if (dev != rtl_ec_net_dev) {
-            /* Enable all known interrupts by setting the interrupt mask. */
-            RTL_W16 (IntrMask, rtl8139_intr_mask);
+    if (dev != rtl_ec_net_dev) {
+        /* Enable all known interrupts by setting the interrupt mask. */
+        RTL_W16 (IntrMask, rtl8139_intr_mask);
 	}
 
 	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
@@ -1818,7 +1817,6 @@
 				" (queue head)" : "");
 
 	tp->xstats.tx_timeouts++;
-    printk(KERN_DEBUG "%s: tx_timeout\n", dev->name);
 
 	/* disable Tx ASAP, if not already */
 	tmp8 = RTL_R8 (ChipCmd);
@@ -1827,35 +1825,31 @@
 
     /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
-
-        if (dev != rtl_ec_net_dev) {
-            spin_lock(&tp->rx_lock);
-
-            /* Disable interrupts by clearing the interrupt mask. */
-            RTL_W16 (IntrMask, 0x0000);
-
-            /* Stop a shared interrupt from scavenging while we are. */
-            spin_lock_irqsave (&tp->lock, flags);
-            rtl8139_tx_clear (tp);
-            spin_unlock_irqrestore (&tp->lock, flags);
-
-            /* ...and finally, reset everything */
-
-            if (netif_running(dev)) {
-                rtl8139_hw_start (dev);
-                netif_wake_queue (dev);
-            }
-
-            spin_unlock(&tp->rx_lock);
+    if (dev != rtl_ec_net_dev) {
+        spin_lock(&tp->rx_lock);
+        /* Disable interrupts by clearing the interrupt mask. */
+        RTL_W16 (IntrMask, 0x0000);
+
+        /* Stop a shared interrupt from scavenging while we are. */
+        spin_lock_irqsave (&tp->lock, flags);
+        rtl8139_tx_clear (tp);
+        spin_unlock_irqrestore (&tp->lock, flags);
+
+        /* ...and finally, reset everything */
+        if (netif_running(dev)) {
+            rtl8139_hw_start (dev);
+            netif_wake_queue (dev);
         }
-        else {
-            rtl8139_tx_clear (tp);
-            rtl8139_hw_start(dev);
-        }
+        spin_unlock(&tp->rx_lock);
+    } else {
+        rtl8139_tx_clear (tp);
+        rtl8139_hw_start(dev);
+    }
 
 	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 }
 
+
 static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
 	struct rtl8139_private *tp = netdev_priv(dev);
@@ -1866,27 +1860,27 @@
 	/* Calculate the next Tx descriptor entry. */
 	entry = tp->cur_tx % NUM_TX_DESC;
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-        /* Note: the chip doesn't have auto-pad! */
-	if (likely(len < TX_BUF_SIZE))
-        {
-                if (len < ETH_ZLEN)
-                        memset(tp->tx_buf[entry], 0, ETH_ZLEN);
-
-                skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
-                if (dev != rtl_ec_net_dev) dev_kfree_skb(skb);
-	}
-        else
-        {
-                if (dev != rtl_ec_net_dev) dev_kfree_skb(skb);
-                tp->stats.tx_dropped++;
-                return 0;
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+    /* Note: the chip doesn't have auto-pad! */
+	if (likely(len < TX_BUF_SIZE)) {
+        if (len < ETH_ZLEN)
+                memset(tp->tx_buf[entry], 0, ETH_ZLEN);
+        skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
+        if (dev != rtl_ec_net_dev) {
+            dev_kfree_skb(skb);
+        }
+	} else {
+        if (dev != rtl_ec_net_dev) {
+            dev_kfree_skb(skb);
+        }
+        tp->stats.tx_dropped++;
+        return 0;
 	}
 
 	if (dev != rtl_ec_net_dev) {
-            spin_lock_irq(&tp->lock);
-        }
+        spin_lock_irq(&tp->lock);
+    }
 
 	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
@@ -1901,15 +1895,14 @@
 	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
 	if (dev != rtl_ec_net_dev) {
-                if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
-                        netif_stop_queue (dev);
-
-                spin_unlock_irq(&tp->lock);
-
-                if (netif_msg_tx_queued(tp))
-                        printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n",
-                                dev->name, len, entry);
-        }
+        if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
+                netif_stop_queue (dev);
+        spin_unlock_irq(&tp->lock);
+
+        if (netif_msg_tx_queued(tp))
+            printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n",
+                dev->name, len, entry);
+    }
 
 	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
@@ -1928,7 +1921,6 @@
 
 	dirty_tx = tp->dirty_tx;
 	tx_left = tp->cur_tx - dirty_tx;
-
 	while (tx_left > 0) {
 		int entry = dirty_tx % NUM_TX_DESC;
 		int txstatus;
@@ -1971,7 +1963,7 @@
 		tx_left--;
 	}
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
 #ifndef RTL8139_NDEBUG
 	if (dev != rtl_ec_net_dev && tp->cur_tx - dirty_tx > NUM_TX_DESC) {
@@ -1981,20 +1973,20 @@
 	}
 #endif /* RTL8139_NDEBUG */
 
-        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+    /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
 	/* only wake the queue if we did work, and the queue is stopped */
 	if (tp->dirty_tx != dirty_tx) {
 		tp->dirty_tx = dirty_tx;
 		mb();
 
-                /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
 		if (dev != rtl_ec_net_dev) {
-                    netif_wake_queue (dev);
-                }
-
-                /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+            netif_wake_queue (dev);
+        }
+
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 	}
 }
 
@@ -2128,9 +2120,15 @@
 		 RTL_R16 (RxBufAddr),
 		 RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
 
+
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
 	while ((dev == rtl_ec_net_dev || netif_running(dev))
 	       && received < budget
 	       && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
+
+    /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
 		u32 ring_offset = cur_rx % RX_BUF_LEN;
 		u32 rx_status;
 		unsigned int pkt_size;
@@ -2143,14 +2141,16 @@
 		rx_size = rx_status >> 16;
 		pkt_size = rx_size - 4;
 
-                /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-		if (dev != rtl_ec_net_dev && netif_msg_rx_status(tp))
-                        printk(KERN_DEBUG "%s:  rtl8139_rx() status %4.4x, size %4.4x,"
-                               " cur %4.4x.\n", dev->name, rx_status,
-                               rx_size, cur_rx);
-
-                /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+        if (dev != rtl_ec_net_dev) {
+		    if (netif_msg_rx_status(tp))
+                printk(KERN_DEBUG "%s:  rtl8139_rx() status %4.4x, size %4.4x,"
+                       " cur %4.4x.\n", dev->name, rx_status,
+                       rx_size, cur_rx);
+        }
+
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
 #if RTL8139_DEBUG > 2
 		{
@@ -2199,48 +2199,46 @@
 			goto out;
 		}
 
-                /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-                if (dev != rtl_ec_net_dev) {
-                    /* Malloc up new buffer, compatible with net-2e. */
-                    /* Omit the four octet CRC from the length. */
-                    skb = dev_alloc_skb(pkt_size + 2);
-
-                    if (likely(skb)) {
-                        skb->dev = dev;
-                        skb_reserve (skb, 2);	/* 16 byte align the IP fields. */
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+        if (dev != rtl_ec_net_dev) {
+            /* Malloc up new buffer, compatible with net-2e. */
+            /* Omit the four octet CRC from the length. */
+
+            skb = dev_alloc_skb (pkt_size + 2);
+            if (likely(skb)) {
+                skb->dev = dev;
+                skb_reserve (skb, 2);	/* 16 byte align the IP fields. */
 #if RX_BUF_IDX == 3
-                        wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
+                wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
 #else
-                        eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
+                eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
 #endif
-                        skb_put (skb, pkt_size);
-
-                        skb->protocol = eth_type_trans (skb, dev);
-
-                        dev->last_rx = jiffies;
-                        tp->stats.rx_bytes += pkt_size;
-                        tp->stats.rx_packets++;
-
-                        netif_receive_skb (skb);
-                    } else {
-                        if (net_ratelimit())
-                            printk (KERN_WARNING
-                                    "%s: Memory squeeze, dropping packet.\n",
-                                    dev->name);
-                        tp->stats.rx_dropped++;
-                    }
-                }
-                else
-                {
-                    ecdev_receive(rtl_ec_dev,
-                                  &rx_ring[ring_offset + 4], pkt_size);
-                    dev->last_rx = jiffies;
-                    tp->stats.rx_bytes += pkt_size;
-                    tp->stats.rx_packets++;
-                }
-
-                /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+                skb_put (skb, pkt_size);
+
+                skb->protocol = eth_type_trans (skb, dev);
+
+                dev->last_rx = jiffies;
+                tp->stats.rx_bytes += pkt_size;
+                tp->stats.rx_packets++;
+
+                netif_receive_skb (skb);
+            } else {
+                if (net_ratelimit())
+                    printk (KERN_WARNING
+                            "%s: Memory squeeze, dropping packet.\n",
+                            dev->name);
+                tp->stats.rx_dropped++;
+            }
+        } else {
+            ecdev_receive(rtl_ec_dev,
+                          &rx_ring[ring_offset + 4], pkt_size);
+            dev->last_rx = jiffies;
+            tp->stats.rx_bytes += pkt_size;
+            tp->stats.rx_packets++;
+        }
+
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
 		received++;
 
@@ -2337,11 +2335,10 @@
 		 * Order is important since data can get interrupted
 		 * again when we think we are done.
 		 */
-
-                local_irq_disable();
-                RTL_W16_F(IntrMask, rtl8139_intr_mask);
-                __netif_rx_complete(dev);
-                local_irq_enable();
+        local_irq_disable();
+        RTL_W16_F(IntrMask, rtl8139_intr_mask);
+        __netif_rx_complete(dev);
+        local_irq_enable();
 	}
 	spin_unlock(&tp->rx_lock);
 
@@ -2360,21 +2357,20 @@
 	int link_changed = 0; /* avoid bogus "uninit" warning */
 	int handled = 0;
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-	if (dev == rtl_ec_net_dev) {
-            status = RTL_R16 (IntrStatus);
-	}
-	else {
-            spin_lock(&tp->lock);
-
-            status = RTL_R16 (IntrStatus);
-
-            if (unlikely((status & rtl8139_intr_mask) == 0))
-                goto out;
-        }
-
-        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+	if (dev != rtl_ec_net_dev) {
+        spin_lock (&tp->lock);
+        status = RTL_R16 (IntrStatus);
+
+	    /* shared irq? */
+        if (unlikely((status & rtl8139_intr_mask) == 0))
+            goto out;
+    } else {
+        status = RTL_R16 (IntrStatus);
+    }
+
+    /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
 	handled = 1;
 
@@ -2382,17 +2378,17 @@
 	if (unlikely(status == 0xFFFF))
 		goto out;
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
 	if (dev != rtl_ec_net_dev) {
-            /* close possible race's with dev_close */
-            if (unlikely(!netif_running(dev))) {
-                RTL_W16 (IntrMask, 0);
-                goto out;
-            }
-	}
-
-        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+        /* close possible race's with dev_close */
+        if (unlikely(!netif_running(dev))) {
+            RTL_W16 (IntrMask, 0);
+            goto out;
+        }
+	}
+
+    /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
 	/* Acknowledge all of the current interrupt sources ASAP, but
 	   an first get an additional status bit from CSCR. */
@@ -2400,31 +2396,28 @@
 		link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
 
 	ackstat = status & ~(RxAckBits | TxErr);
-	if (ackstat) {
+	if (ackstat)
 		RTL_W16 (IntrStatus, ackstat);
-	}
 
 	/* Receive packets are processed by poll routine.
 	   If not running start it now. */
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-	if (status & RxAckBits)
-        {
-            if (dev != rtl_ec_net_dev) {
-                /* Mark for polling */
-                if (netif_rx_schedule_prep(dev)) {
-                    RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
-                    __netif_rx_schedule (dev);
-                }
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+	if (status & RxAckBits){
+        if (dev != rtl_ec_net_dev) {
+            /* Mark for polling */
+            if (netif_rx_schedule_prep(dev)) {
+                RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
+                __netif_rx_schedule (dev);
             }
-            else {
-                /* EtherCAT device: Just receive all frames */
-                rtl8139_rx(dev, tp, 100); // FIXME
-            }
-	}
-
-        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+        } else {
+            /* EtherCAT device: Just receive all frames */
+            rtl8139_rx(dev, tp, 100); // FIXME
+        }
+	}
+
+    /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
 	/* Check uncommon events with one test. */
 	if (unlikely(status & (PCIErr | PCSTimeout | RxUnderrun | RxErr)))
@@ -2437,13 +2430,14 @@
 			RTL_W16 (IntrStatus, TxErr);
 	}
  out:
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
 	if (dev != rtl_ec_net_dev) {
-            spin_unlock (&tp->lock);
-        }
-
-        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+        spin_unlock (&tp->lock);
+    }
+
+    /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
 	DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
 		 dev->name, RTL_R16 (IntrStatus));
@@ -2470,55 +2464,55 @@
 	int ret = 0;
 	unsigned long flags;
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-        if (dev != rtl_ec_net_dev) {
-            netif_stop_queue(dev);
-            if (tp->thr_pid >= 0) {
-                tp->time_to_die = 1;
-                wmb();
-                ret = kill_proc (tp->thr_pid, SIGTERM, 1);
-                if (ret) {
-                    printk (KERN_ERR "%s: unable to signal thread\n", dev->name);
-                    return ret;
-                }
-                wait_for_completion (&tp->thr_exited);
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+    if (dev != rtl_ec_net_dev) {
+        netif_stop_queue (dev);
+
+        if (tp->thr_pid >= 0) {
+            tp->time_to_die = 1;
+            wmb();
+            ret = kill_proc (tp->thr_pid, SIGTERM, 1);
+            if (ret) {
+                printk (KERN_ERR "%s: unable to signal thread\n", dev->name);
+                return ret;
             }
-
-            if (netif_msg_ifdown(tp))
-                printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
-                       dev->name, RTL_R16 (IntrStatus));
-
-            spin_lock_irqsave (&tp->lock, flags);
-
-            /* Stop the chip's Tx and Rx DMA processes. */
-            RTL_W8 (ChipCmd, 0);
-
-            /* Disable interrupts by clearing the interrupt mask. */
-            RTL_W16 (IntrMask, 0);
-
-            /* Update the error counts. */
-            tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
-            RTL_W32 (RxMissed, 0);
-
-            spin_unlock_irqrestore (&tp->lock, flags);
-
-            synchronize_irq (dev->irq);	/* racy, but that's ok here */
-            free_irq (dev->irq, dev);
+            wait_for_completion (&tp->thr_exited);
         }
-        else {
-            /* Stop the chip's Tx and Rx DMA processes. */
-            RTL_W8 (ChipCmd, 0);
-
-            /* Disable interrupts by clearing the interrupt mask. */
-            RTL_W16 (IntrMask, 0);
-
-            /* Update the error counts. */
-            tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
-            RTL_W32 (RxMissed, 0);
-        }
-
-        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+        if (netif_msg_ifdown(tp))
+            printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
+                   dev->name, RTL_R16 (IntrStatus));
+
+        spin_lock_irqsave (&tp->lock, flags);
+
+        /* Stop the chip's Tx and Rx DMA processes. */
+        RTL_W8 (ChipCmd, 0);
+
+        /* Disable interrupts by clearing the interrupt mask. */
+        RTL_W16 (IntrMask, 0);
+
+        /* Update the error counts. */
+        tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+        RTL_W32 (RxMissed, 0);
+
+        spin_unlock_irqrestore (&tp->lock, flags);
+
+        synchronize_irq (dev->irq);	/* racy, but that's ok here */
+        free_irq (dev->irq, dev);
+    } else {
+        /* Stop the chip's Tx and Rx DMA processes. */
+        RTL_W8 (ChipCmd, 0);
+
+        /* Disable interrupts by clearing the interrupt mask. */
+        RTL_W16 (IntrMask, 0);
+
+        /* Update the error counts. */
+        tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+        RTL_W32 (RxMissed, 0);
+    }
+
+    /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
 	rtl8139_tx_clear (tp);
 
@@ -2733,12 +2727,12 @@
 	struct rtl8139_private *np = netdev_priv(dev);
 	int rc;
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-	if (dev == rtl_ec_net_dev || !netif_running(dev))
-            return -EINVAL;
-
-        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+    if (dev == rtl_ec_net_dev || !netif_running(dev))
+        return -EINVAL;
+
+    /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
 	spin_lock_irq(&np->lock);
 	rc = generic_mii_ioctl(&np->mii, if_mii(rq), cmd, NULL);
@@ -2754,16 +2748,16 @@
 	void __iomem *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
 	if (dev == rtl_ec_net_dev || netif_running(dev)) {
-            spin_lock_irqsave (&tp->lock, flags);
-            tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
-            RTL_W32 (RxMissed, 0);
-            spin_unlock_irqrestore (&tp->lock, flags);
-	}
-
-        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+        spin_lock_irqsave (&tp->lock, flags);
+        tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+        RTL_W32 (RxMissed, 0);
+        spin_unlock_irqrestore (&tp->lock, flags);
+	}
+
+    /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
 	return &tp->stats;
 }
@@ -2840,12 +2834,12 @@
 
 	pci_save_state (pdev);
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
 	if (dev == rtl_ec_net_dev || !netif_running (dev))
-            return 0;
-
-        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+        return 0;
+
+    /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
 	netif_device_detach (dev);
 
@@ -2873,12 +2867,12 @@
 
 	pci_restore_state (pdev);
 
-        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+    /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 
 	if (dev == rtl_ec_net_dev || !netif_running (dev))
-            return 0;
-
-        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+        return 0;
+
+    /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
 
 	pci_set_power_state (pdev, PCI_D0);
 	rtl8139_init_ring (dev);
@@ -2928,9 +2922,8 @@
             printk(KERN_ERR "Failed to start EtherCAT device!\n");
             goto out_unregister;
         }
-    }
-    else {
-        printk(KERN_WARNING "NO EtherCAT device registered!\n");
+    } else {
+        printk(KERN_WARNING "No EtherCAT device registered!\n");
     }
 
     return 0;
--- a/devices/Makefile	Mon May 29 09:54:18 2006 +0000
+++ b/devices/Makefile	Mon Jun 26 15:04:06 2006 +0000
@@ -1,6 +1,6 @@
 #------------------------------------------------------------------------------
 #
-#  kbuild Makefile
+#  Makefile
 #
 #  IgH EtherCAT master device modules
 #
@@ -35,39 +35,45 @@
 #
 #------------------------------------------------------------------------------
 
-ifneq ($(KERNELRELEASE),)
-
 #------------------------------------------------------------------------------
 #  kbuild section
 
+ifneq ($(KERNELRELEASE),)
+
 obj-m := ec_8139too.o
 
 ec_8139too-objs := 8139too.o
 
-REV := $(shell svnversion $(src) 2>/dev/null)
+REV := $(shell svnversion $(src) 2>/dev/null || echo "unknown")
 
 EXTRA_CFLAGS = -DEC_REV=$(REV) -DEC_USER=$(USER)
 
 #------------------------------------------------------------------------------
+#  default section
 
 else
 
-#------------------------------------------------------------------------------
-#  default section
-
 ifneq ($(wildcard ../ethercat.conf),)
 include ../ethercat.conf
 else
 KERNEL := $(shell uname -r)
 endif
 
-KERNELDIR := /lib/modules/$(KERNEL)/build
+KERNEL_DIR := /lib/modules/$(KERNEL)/build
+CURRENT_DIR := $(shell pwd)
+INSTALL_MOD_DIR := ethercat/devices
 
 modules:
-	$(MAKE) -C $(KERNELDIR) M=`pwd`
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) modules
+
+install: modules_install
+
+modules_install:
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) \
+		INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) modules_install
 
 clean:
-	$(MAKE) -C $(KERNELDIR) M=`pwd` clean
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean
 
 #------------------------------------------------------------------------------
 
--- a/ethercat.conf.tmpl	Mon May 29 09:54:18 2006 +0000
+++ b/ethercat.conf.tmpl	Mon Jun 26 15:04:06 2006 +0000
@@ -12,6 +12,6 @@
 #
 # The kernel to compile the EtherCAT sources against
 #
-KERNEL := `uname -r`
+KERNEL := $(shell uname -r)
 
 #------------------------------------------------------------------------------
--- a/examples/mini/Makefile	Mon May 29 09:54:18 2006 +0000
+++ b/examples/mini/Makefile	Mon Jun 26 15:04:06 2006 +0000
@@ -56,14 +56,16 @@
 ifneq ($(wildcard kernel.conf),)
 include kernel.conf
 else
-KERNELDIR = /lib/modules/`uname -r`/build
+KERNEL_DIR := /lib/modules/$(shell uname -r)/build
 endif
 
+CURRENT_DIR := $(shell pwd)
+
 modules:
-	$(MAKE) -C $(KERNELDIR) M=`pwd`
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR)
 
 clean:
-	$(MAKE) -C $(KERNELDIR) M=`pwd` clean
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean
 
 #----------------------------------------------------------------
 
--- a/examples/mini/kernel.conf.tmpl	Mon May 29 09:54:18 2006 +0000
+++ b/examples/mini/kernel.conf.tmpl	Mon Jun 26 15:04:06 2006 +0000
@@ -9,4 +9,4 @@
 #
 #------------------------------------------------------------------------------
 
-KERNELDIR = /lib/modules/`uname -r`/build
+KERNELDIR := /lib/modules/$(shell uname -r)/build
--- a/examples/mini/mini.c	Mon May 29 09:54:18 2006 +0000
+++ b/examples/mini/mini.c	Mon Jun 26 15:04:06 2006 +0000
@@ -57,14 +57,15 @@
 
 // data fields
 //void *r_ssi_input, *r_ssi_status, *r_4102[3];
+void *r_kbus_in, *r_kbus_out;
 
 // channels
 uint32_t k_pos;
 uint8_t k_stat;
 
 ec_field_init_t domain1_fields[] = {
-    {NULL, "3", "Beckhoff", "EL5001", "InputValue",   0},
-    {NULL, "2", "Beckhoff", "EL4132", "OutputValue",  0},
+    //{&r_kbus_out, "0", "Beckhoff", "BK1120", "Outputs", 0},
+    //{&r_kbus_in,  "0", "Beckhoff", "BK1120", "Inputs",  0},
     {}
 };
 
@@ -73,6 +74,7 @@
 void run(unsigned long data)
 {
     static unsigned int counter = 0;
+    unsigned int i;
 
     spin_lock(&master_lock);
 
@@ -105,8 +107,9 @@
     }
     else {
         counter = FREQUENCY;
-        //printk(KERN_INFO "k_pos    = %i\n", k_pos);
-        //printk(KERN_INFO "k_stat   = 0x%02X\n", k_stat);
+        printk(KERN_INFO "input = ");
+        for (i = 0; i < 22; i++) printk("%02X ", *((uint8_t *) r_kbus_in + i));
+        printk("\n");
     }
 
     // restart timer
@@ -133,6 +136,8 @@
 
 int __init init_mini_module(void)
 {
+    ec_slave_t *slave;
+
     printk(KERN_INFO "=== Starting Minimal EtherCAT environment... ===\n");
 
     if ((master = ecrt_request_master(0)) == NULL) {
@@ -155,13 +160,23 @@
         goto out_release_master;
     }
 
+#if 1
+    printk(KERN_INFO "Setting variable data field sizes...\n");
+    if (!(slave = ecrt_master_get_slave(master, "0"))) {
+        printk(KERN_ERR "Failed to get slave!\n");
+        goto out_deactivate;
+    }
+    ecrt_slave_field_size(slave, "Outputs", 0, 0x16);
+    ecrt_slave_field_size(slave, "Inputs", 0, 0x16);
+#endif
+
     printk(KERN_INFO "Activating master...\n");
     if (ecrt_master_activate(master)) {
         printk(KERN_ERR "Failed to activate master!\n");
         goto out_release_master;
     }
 
-#if 0
+#if 1
     if (ecrt_master_fetch_sdo_lists(master)) {
         printk(KERN_ERR "Failed to fetch SDO lists!\n");
         goto out_deactivate;
@@ -191,14 +206,6 @@
     }
 #endif
 
-#if 0
-    printk(KERN_INFO "Writing alias...\n");
-    if (ecrt_slave_sdo_write_exp16(slave, 0xBEEF)) {
-        printk(KERN_ERR "Failed to write alias!\n");
-        goto out_deactivate;
-    }
-#endif
-
 #ifdef ASYNC
     // send once and wait...
     ecrt_master_prepare_async_io(master);
--- a/examples/msr/Makefile	Mon May 29 09:54:18 2006 +0000
+++ b/examples/msr/Makefile	Mon Jun 26 15:04:06 2006 +0000
@@ -75,13 +75,14 @@
 KERNEL := $(shell uname -r)
 endif
 
-KERNELDIR := /lib/modules/$(KERNEL)/build
+KERNEL_DIR := /lib/modules/$(KERNEL)/build
+CURRENT_DIR := $(shell pwd)
 
 modules:
-	$(MAKE) -C $(KERNELDIR) M=`pwd`
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR)
 
 clean:
-	$(MAKE) -C $(KERNELDIR) M=`pwd` clean
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean
 
 install:
 	@./install.sh $(MODULE) $(KERNEL)
--- a/examples/msr/kernel.conf.tmpl	Mon May 29 09:54:18 2006 +0000
+++ b/examples/msr/kernel.conf.tmpl	Mon Jun 26 15:04:06 2006 +0000
@@ -10,6 +10,6 @@
 #------------------------------------------------------------------------------
 
 # Kernel sources for module compilation
-KERNEL := `uname -r`
+KERNEL := $(shell uname -r)
 
 #------------------------------------------------------------------------------
--- a/examples/rtai/Makefile	Mon May 29 09:54:18 2006 +0000
+++ b/examples/rtai/Makefile	Mon Jun 26 15:04:06 2006 +0000
@@ -58,14 +58,16 @@
 ifneq ($(wildcard kernel.conf),)
 include kernel.conf
 else
-KERNELDIR = /lib/modules/`uname -r`/build
+KERNEL_DIR := /lib/modules/$(shell uname -r)/build
 endif
 
+CURRENT_DIR := $(shell pwd)
+
 modules:
-	$(MAKE) -C $(KERNELDIR) M=`pwd`
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR)
 
 clean:
-	$(MAKE) -C $(KERNELDIR) M=`pwd` clean
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean
 
 #------------------------------------------------------------------------------
 
--- a/examples/rtai/kernel.conf.tmpl	Mon May 29 09:54:18 2006 +0000
+++ b/examples/rtai/kernel.conf.tmpl	Mon Jun 26 15:04:06 2006 +0000
@@ -9,4 +9,4 @@
 #
 #------------------------------------------------------------------------------
 
-KERNELDIR = /lib/modules/`uname -r`/build
+KERNELDIR := /lib/modules/$(shell uname -r)/build
--- a/include/ecrt.h	Mon May 29 09:54:18 2006 +0000
+++ b/include/ecrt.h	Mon Jun 26 15:04:06 2006 +0000
@@ -145,6 +145,8 @@
  *  Slave Methods
  *****************************************************************************/
 
+/* there SDO functions are deprecated! */
+
 int ecrt_slave_sdo_read_exp8(ec_slave_t *slave, uint16_t sdo_index,
                               uint8_t sdo_subindex, uint8_t *value);
 int ecrt_slave_sdo_read_exp16(ec_slave_t *slave, uint16_t sdo_index,
@@ -160,7 +162,10 @@
 int ecrt_slave_sdo_read(ec_slave_t *slave, uint16_t sdo_index,
                         uint8_t sdo_subindex, uint8_t *data, size_t *size);
 
-int ecrt_slave_write_alias(ec_slave_t *slave, uint16_t alias);
+int ecrt_slave_write_alias(ec_slave_t *slave, uint16_t alias); // deprecated!
+
+int ecrt_slave_field_size(ec_slave_t *slave, const char *field_name,
+                          unsigned int field_index, size_t size);
 
 /******************************************************************************
  *  Bitwise read/write macros
--- a/master/Makefile	Mon May 29 09:54:18 2006 +0000
+++ b/master/Makefile	Mon Jun 26 15:04:06 2006 +0000
@@ -35,40 +35,46 @@
 #
 #------------------------------------------------------------------------------
 
-ifneq ($(KERNELRELEASE),)
-
 #------------------------------------------------------------------------------
 #  kbuild section
 
+ifneq ($(KERNELRELEASE),)
+
 obj-m := ec_master.o
 
 ec_master-objs := module.o master.o device.o slave.o command.o types.o \
 		domain.o mailbox.o canopen.o ethernet.o debug.o fsm.o
 
-REV := $(shell svnversion $(src) 2>/dev/null)
+REV := $(shell svnversion $(src) 2>/dev/null || echo "unknown")
 
 EXTRA_CFLAGS := -DSVNREV=$(REV) -DUSER=$(USER)
 
 #------------------------------------------------------------------------------
+#  default section
 
 else
 
-#------------------------------------------------------------------------------
-#  default section
-
 ifneq ($(wildcard ../ethercat.conf),)
 include ../ethercat.conf
 else
 KERNEL := $(shell uname -r)
 endif
 
-KERNELDIR := /lib/modules/$(KERNEL)/build
+KERNEL_DIR := /lib/modules/$(KERNEL)/build
+CURRENT_DIR := $(shell pwd)
+INSTALL_MOD_DIR := ethercat/master
 
 modules:
-	$(MAKE) -C $(KERNELDIR) M=`pwd`
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) modules
+
+install: modules_install
+
+modules_install:
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) \
+		INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) modules_install
 
 clean:
-	$(MAKE) -C $(KERNELDIR) M=`pwd` clean
+	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean
 
 #------------------------------------------------------------------------------
 
--- a/master/canopen.c	Mon May 29 09:54:18 2006 +0000
+++ b/master/canopen.c	Mon Jun 26 15:04:06 2006 +0000
@@ -48,8 +48,9 @@
 /*****************************************************************************/
 
 void ec_canopen_abort_msg(uint32_t);
-int ec_slave_fetch_sdo_descriptions(ec_slave_t *);
-int ec_slave_fetch_sdo_entries(ec_slave_t *, ec_sdo_t *, uint8_t);
+int ec_slave_fetch_sdo_descriptions(ec_slave_t *, ec_command_t *);
+int ec_slave_fetch_sdo_entries(ec_slave_t *, ec_command_t *,
+                               ec_sdo_t *, uint8_t);
 
 /*****************************************************************************/
 
@@ -68,10 +69,14 @@
                           uint8_t *target /**< 4-byte memory */
                           )
 {
+    ec_command_t command;
     size_t rec_size;
     uint8_t *data;
 
-    if (!(data = ec_slave_mbox_prepare_send(slave, 0x03, 6))) return -1;
+    ec_command_init(&command);
+
+    if (!(data = ec_slave_mbox_prepare_send(slave, &command, 0x03, 6)))
+        goto err;
 
     EC_WRITE_U16(data, 0x2 << 12); // SDO request
     EC_WRITE_U8 (data + 2, (0x1 << 1 // expedited transfer
@@ -79,14 +84,15 @@
     EC_WRITE_U16(data + 3, sdo_index);
     EC_WRITE_U8 (data + 5, sdo_subindex);
 
-    if (!(data = ec_slave_mbox_simple_io(slave, &rec_size))) return -1;
+    if (!(data = ec_slave_mbox_simple_io(slave, &command, &rec_size)))
+        goto err;
 
     if (EC_READ_U16(data) >> 12 == 0x2 && // SDO request
         EC_READ_U8 (data + 2) >> 5 == 0x4) { // abort SDO transfer request
         EC_ERR("SDO upload 0x%04X:%X aborted on slave %i.\n",
                sdo_index, sdo_subindex, slave->ring_position);
         ec_canopen_abort_msg(EC_READ_U32(data + 6));
-        return -1;
+        goto err;
     }
 
     if (EC_READ_U16(data) >> 12 != 0x3 || // SDO response
@@ -97,11 +103,16 @@
         EC_ERR("Invalid SDO upload response at slave %i!\n",
                slave->ring_position);
         ec_print_data(data, rec_size);
-        return -1;
+        goto err;
     }
 
     memcpy(target, data + 6, 4);
-    return 0;
+
+    ec_command_clear(&command);
+    return 0;
+ err:
+    ec_command_clear(&command);
+    return -1;
 }
 
 /*****************************************************************************/
@@ -120,13 +131,17 @@
 {
     uint8_t *data;
     size_t rec_size;
+    ec_command_t command;
+
+    ec_command_init(&command);
 
     if (size == 0 || size > 4) {
         EC_ERR("Invalid data size!\n");
-        return -1;
-    }
-
-    if (!(data = ec_slave_mbox_prepare_send(slave, 0x03, 0x0A))) return -1;
+        goto err;
+    }
+
+    if (!(data = ec_slave_mbox_prepare_send(slave, &command, 0x03, 0x0A)))
+        goto err;
 
     EC_WRITE_U16(data, 0x2 << 12); // SDO request
     EC_WRITE_U8 (data + 2, (0x1 // size specified
@@ -138,7 +153,8 @@
     memcpy(data + 6, sdo_data, size);
     if (size < 4) memset(data + 6 + size, 0x00, 4 - size);
 
-    if (!(data = ec_slave_mbox_simple_io(slave, &rec_size))) return -1;
+    if (!(data = ec_slave_mbox_simple_io(slave, &command, &rec_size)))
+        goto err;
 
     if (EC_READ_U16(data) >> 12 == 0x2 && // SDO request
         EC_READ_U8 (data + 2) >> 5 == 0x4) { // abort SDO transfer request
@@ -160,7 +176,11 @@
         return -1;
     }
 
-    return 0;
+    ec_command_clear(&command);
+    return 0;
+ err:
+    ec_command_clear(&command);
+    return -1;
 }
 
 /*****************************************************************************/
@@ -182,22 +202,27 @@
     uint8_t *data;
     size_t rec_size, data_size;
     uint32_t complete_size;
-
-    if (!(data = ec_slave_mbox_prepare_send(slave, 0x03, 6))) return -1;
+    ec_command_t command;
+
+    ec_command_init(&command);
+
+    if (!(data = ec_slave_mbox_prepare_send(slave, &command, 0x03, 6)))
+        goto err;
 
     EC_WRITE_U16(data, 0x2 << 12); // SDO request
     EC_WRITE_U8 (data + 2, 0x2 << 5); // initiate upload request
     EC_WRITE_U16(data + 3, sdo_index);
     EC_WRITE_U8 (data + 5, sdo_subindex);
 
-    if (!(data = ec_slave_mbox_simple_io(slave, &rec_size))) return -1;
+    if (!(data = ec_slave_mbox_simple_io(slave, &command, &rec_size)))
+        goto err;
 
     if (EC_READ_U16(data) >> 12 == 0x2 && // SDO request
         EC_READ_U8 (data + 2) >> 5 == 0x4) { // abort SDO transfer request
         EC_ERR("SDO upload 0x%04X:%X aborted on slave %i.\n",
                sdo_index, sdo_subindex, slave->ring_position);
         ec_canopen_abort_msg(EC_READ_U32(data + 6));
-        return -1;
+        goto err;
     }
 
     if (EC_READ_U16(data) >> 12 != 0x3 || // SDO response
@@ -208,30 +233,35 @@
         EC_ERR("Invalid SDO upload response at slave %i!\n",
                slave->ring_position);
         ec_print_data(data, rec_size);
-        return -1;
+        goto err;
     }
 
     if (rec_size < 10) {
         EC_ERR("Received currupted SDO upload response!\n");
         ec_print_data(data, rec_size);
-        return -1;
+        goto err;
     }
 
     if ((complete_size = EC_READ_U32(data + 6)) > *size) {
         EC_ERR("SDO data does not fit into buffer (%i / %i)!\n",
                complete_size, *size);
-        return -1;
+        goto err;
     }
 
     data_size = rec_size - 10;
 
     if (data_size != complete_size) {
         EC_ERR("SDO data incomplete - Fragmenting not implemented.\n");
-        return -1;
+        goto err;
     }
 
     memcpy(target, data + 10, data_size);
-    return 0;
+
+    ec_command_clear(&command);
+    return 0;
+ err:
+    ec_command_clear(&command);
+    return -1;
 }
 
 /*****************************************************************************/
@@ -248,8 +278,12 @@
     unsigned int i, sdo_count;
     ec_sdo_t *sdo;
     uint16_t sdo_index;
-
-    if (!(data = ec_slave_mbox_prepare_send(slave, 0x03, 8))) return -1;
+    ec_command_t command;
+
+    ec_command_init(&command);
+
+    if (!(data = ec_slave_mbox_prepare_send(slave, &command, 0x03, 8)))
+        goto err;
 
     EC_WRITE_U16(data, 0x8 << 12); // SDO information
     EC_WRITE_U8 (data + 2, 0x01); // Get OD List Request
@@ -257,21 +291,22 @@
     EC_WRITE_U16(data + 4, 0x0000);
     EC_WRITE_U16(data + 6, 0x0001); // deliver all SDOs!
 
-    if (unlikely(ec_master_simple_io(slave->master, &slave->mbox_command))) {
+    if (unlikely(ec_master_simple_io(slave->master, &command))) {
         EC_ERR("Mailbox checking failed on slave %i!\n", slave->ring_position);
-        return -1;
+        goto err;
     }
 
     do {
-        if (!(data = ec_slave_mbox_simple_receive(slave, 0x03, &rec_size)))
-            return -1;
+        if (!(data = ec_slave_mbox_simple_receive(slave, &command,
+                                                  0x03, &rec_size)))
+            goto err;
 
         if (EC_READ_U16(data) >> 12 == 0x8 && // SDO information
             (EC_READ_U8(data + 2) & 0x7F) == 0x07) { // error response
             EC_ERR("SDO information error response at slave %i!\n",
                    slave->ring_position);
             ec_canopen_abort_msg(EC_READ_U32(data + 6));
-            return -1;
+            goto err;
         }
 
         if (EC_READ_U16(data) >> 12 != 0x8 || // SDO information
@@ -279,13 +314,13 @@
             EC_ERR("Invalid SDO list response at slave %i!\n",
                    slave->ring_position);
             ec_print_data(data, rec_size);
-            return -1;
+            goto err;
         }
 
         if (rec_size < 8) {
             EC_ERR("Invalid data size!\n");
             ec_print_data(data, rec_size);
-            return -1;
+            goto err;
         }
 
         sdo_count = (rec_size - 8) / 2;
@@ -295,7 +330,7 @@
 
             if (!(sdo = (ec_sdo_t *) kmalloc(sizeof(ec_sdo_t), GFP_KERNEL))) {
                 EC_ERR("Failed to allocate memory for SDO!\n");
-                return -1;
+                goto err;
             }
 
             // Initialize SDO object
@@ -311,9 +346,13 @@
     while (EC_READ_U8(data + 2) & 0x80);
 
     // Fetch all SDO descriptions
-    if (ec_slave_fetch_sdo_descriptions(slave)) return -1;
-
-    return 0;
+    if (ec_slave_fetch_sdo_descriptions(slave, &command)) goto err;
+
+    ec_command_clear(&command);
+    return 0;
+ err:
+    ec_command_clear(&command);
+    return -1;
 }
 
 /*****************************************************************************/
@@ -323,21 +362,25 @@
    \return 0 in case of success, else < 0
 */
 
-int ec_slave_fetch_sdo_descriptions(ec_slave_t *slave /**< EtherCAT slave */)
+int ec_slave_fetch_sdo_descriptions(ec_slave_t *slave, /**< EtherCAT slave */
+                                    ec_command_t *command /**< command */
+                                    )
 {
     uint8_t *data;
     size_t rec_size, name_size;
     ec_sdo_t *sdo;
 
     list_for_each_entry(sdo, &slave->sdo_dictionary, list) {
-        if (!(data = ec_slave_mbox_prepare_send(slave, 0x03, 8))) return -1;
+        if (!(data = ec_slave_mbox_prepare_send(slave, command, 0x03, 8)))
+            return -1;
         EC_WRITE_U16(data, 0x8 << 12); // SDO information
         EC_WRITE_U8 (data + 2, 0x03); // Get object description request
         EC_WRITE_U8 (data + 3, 0x00);
         EC_WRITE_U16(data + 4, 0x0000);
         EC_WRITE_U16(data + 6, sdo->index); // SDO index
 
-        if (!(data = ec_slave_mbox_simple_io(slave, &rec_size))) return -1;
+        if (!(data = ec_slave_mbox_simple_io(slave, command, &rec_size)))
+            return -1;
 
         if (EC_READ_U16(data) >> 12 == 0x8 && // SDO information
             (EC_READ_U8 (data + 2) & 0x7F) == 0x07) { // error response
@@ -364,8 +407,10 @@
             return -1;
         }
 
+#if 0
         EC_DBG("object desc response:\n");
         ec_print_data(data, rec_size);
+#endif
 
         //sdo->unknown = EC_READ_U16(data + 8);
         sdo->object_code = EC_READ_U8(data + 11);
@@ -387,7 +432,8 @@
         }
 
         // Fetch all entries (subindices)
-        if (ec_slave_fetch_sdo_entries(slave, sdo, EC_READ_U8(data + 10)))
+        if (ec_slave_fetch_sdo_entries(slave, command, sdo,
+                                       EC_READ_U8(data + 10)))
             return -1;
     }
 
@@ -402,6 +448,7 @@
 */
 
 int ec_slave_fetch_sdo_entries(ec_slave_t *slave, /**< EtherCAT slave */
+                               ec_command_t *command, /**< command */
                                ec_sdo_t *sdo, /**< SDO */
                                uint8_t subindices /**< number of subindices */
                                )
@@ -412,7 +459,7 @@
     ec_sdo_entry_t *entry;
 
     for (i = 1; i <= subindices; i++) {
-        if (!(data = ec_slave_mbox_prepare_send(slave, 0x03, 10)))
+        if (!(data = ec_slave_mbox_prepare_send(slave, command, 0x03, 10)))
             return -1;
 
         EC_WRITE_U16(data, 0x8 << 12); // SDO information
@@ -423,7 +470,8 @@
         EC_WRITE_U8 (data + 8, i); // SDO subindex
         EC_WRITE_U8 (data + 9, 0x00); // value info (no values)
 
-        if (!(data = ec_slave_mbox_simple_io(slave, &rec_size))) return -1;
+        if (!(data = ec_slave_mbox_simple_io(slave, command, &rec_size)))
+            return -1;
 
         if (EC_READ_U16(data) >> 12 == 0x8 && // SDO information
             (EC_READ_U8 (data + 2) & 0x7F) == 0x07) { // error response
--- a/master/domain.c	Mon May 29 09:54:18 2006 +0000
+++ b/master/domain.c	Mon Jun 26 15:04:06 2006 +0000
@@ -225,7 +225,7 @@
 */
 
 int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
-                    uint32_t base_address /**< Logische Basisadresse */
+                    uint32_t base_address /**< logical base address */
                     )
 {
     ec_field_reg_t *field_reg;
@@ -234,12 +234,12 @@
     unsigned int i, j, cmd_count;
     uint32_t field_off, field_off_cmd;
     uint32_t cmd_offset;
-    size_t cmd_data_size;
+    size_t cmd_data_size, sync_size;
     ec_command_t *command;
 
     domain->base_address = base_address;
 
-    // Größe der Prozessdaten berechnen und Kommandos allozieren
+    // calculate size of process data and allocate memory
     domain->data_size = 0;
     cmd_offset = base_address;
     cmd_data_size = 0;
@@ -249,20 +249,21 @@
             fmmu = &slave->fmmus[j];
             if (fmmu->domain == domain) {
                 fmmu->logical_start_address = base_address + domain->data_size;
-                domain->data_size += fmmu->sync->size;
-                if (cmd_data_size + fmmu->sync->size > EC_MAX_DATA_SIZE) {
+                sync_size = ec_slave_calc_sync_size(slave, fmmu->sync);
+                domain->data_size += sync_size;
+                if (cmd_data_size + sync_size > EC_MAX_DATA_SIZE) {
                     if (ec_domain_add_command(domain, cmd_offset,
                                               cmd_data_size)) return -1;
                     cmd_offset += cmd_data_size;
                     cmd_data_size = 0;
                     cmd_count++;
                 }
-                cmd_data_size += fmmu->sync->size;
+                cmd_data_size += sync_size;
             }
         }
     }
 
-    // Letztes Kommando allozieren
+    // allocate last command
     if (cmd_data_size) {
         if (ec_domain_add_command(domain, cmd_offset, cmd_data_size))
             return -1;
@@ -275,14 +276,14 @@
         return 0;
     }
 
-    // Alle Prozessdatenzeiger setzen
+    // set all process data pointers
     list_for_each_entry(field_reg, &domain->field_regs, list) {
         for (i = 0; i < field_reg->slave->fmmu_count; i++) {
             fmmu = &field_reg->slave->fmmus[i];
             if (fmmu->domain == domain && fmmu->sync == field_reg->sync) {
                 field_off = fmmu->logical_start_address +
                     field_reg->field_offset;
-                // Kommando suchen
+                // search command
                 list_for_each_entry(command, &domain->commands, list) {
                     field_off_cmd = field_off - command->address.logical;
                     if (field_off >= command->address.logical &&
--- a/master/ethernet.c	Mon May 29 09:54:18 2006 +0000
+++ b/master/ethernet.c	Mon Jun 26 15:04:06 2006 +0000
@@ -79,6 +79,7 @@
     int result, i;
 
     eoe->slave = NULL;
+    ec_command_init(&eoe->command);
     eoe->state = ec_eoe_state_rx_start;
     eoe->opened = 0;
     eoe->rx_skb = NULL;
@@ -159,6 +160,8 @@
     }
 
     if (eoe->rx_skb) dev_kfree_skb(eoe->rx_skb);
+
+    ec_command_clear(&eoe->command);
 }
 
 /*****************************************************************************/
@@ -235,8 +238,8 @@
     printk("\n");
 #endif
 
-    if (!(data = ec_slave_mbox_prepare_send(eoe->slave, 0x02,
-                                            current_size + 4)))
+    if (!(data = ec_slave_mbox_prepare_send(eoe->slave, &eoe->command,
+                                            0x02, current_size + 4)))
         return -1;
 
     EC_WRITE_U8 (data,     0x00); // eoe fragment req.
@@ -246,7 +249,7 @@
                             (eoe->tx_frame_number & 0x0F) << 12));
 
     memcpy(data + 4, eoe->tx_frame->skb->data + eoe->tx_offset, current_size);
-    ec_master_queue_command(eoe->slave->master, &eoe->slave->mbox_command);
+    ec_master_queue_command(eoe->slave->master, &eoe->command);
 
     eoe->tx_offset += current_size;
     eoe->tx_fragment_number++;
@@ -310,8 +313,8 @@
     if (!eoe->slave->online || !eoe->slave->master->device->link_state)
         return;
 
-    ec_slave_mbox_prepare_check(eoe->slave);
-    ec_master_queue_command(eoe->slave->master, &eoe->slave->mbox_command);
+    ec_slave_mbox_prepare_check(eoe->slave, &eoe->command);
+    ec_master_queue_command(eoe->slave->master, &eoe->command);
     eoe->state = ec_eoe_state_rx_check;
 }
 
@@ -325,19 +328,19 @@
 
 void ec_eoe_state_rx_check(ec_eoe_t *eoe /**< EoE handler */)
 {
-    if (eoe->slave->mbox_command.state != EC_CMD_RECEIVED) {
+    if (eoe->command.state != EC_CMD_RECEIVED) {
         eoe->stats.rx_errors++;
         eoe->state = ec_eoe_state_tx_start;
         return;
     }
 
-    if (!ec_slave_mbox_check(eoe->slave)) {
+    if (!ec_slave_mbox_check(&eoe->command)) {
         eoe->state = ec_eoe_state_tx_start;
         return;
     }
 
-    ec_slave_mbox_prepare_fetch(eoe->slave);
-    ec_master_queue_command(eoe->slave->master, &eoe->slave->mbox_command);
+    ec_slave_mbox_prepare_fetch(eoe->slave, &eoe->command);
+    ec_master_queue_command(eoe->slave->master, &eoe->command);
     eoe->state = ec_eoe_state_rx_fetch;
 }
 
@@ -356,13 +359,14 @@
     uint8_t frame_number, fragment_offset, fragment_number;
     off_t offset;
 
-    if (eoe->slave->mbox_command.state != EC_CMD_RECEIVED) {
+    if (eoe->command.state != EC_CMD_RECEIVED) {
         eoe->stats.rx_errors++;
         eoe->state = ec_eoe_state_tx_start;
         return;
     }
 
-    if (!(data = ec_slave_mbox_fetch(eoe->slave, 0x02, &rec_size))) {
+    if (!(data = ec_slave_mbox_fetch(eoe->slave, &eoe->command,
+                                     0x02, &rec_size))) {
         eoe->stats.rx_errors++;
         eoe->state = ec_eoe_state_tx_start;
         return;
@@ -554,13 +558,13 @@
 
 void ec_eoe_state_tx_sent(ec_eoe_t *eoe /**< EoE handler */)
 {
-    if (eoe->slave->mbox_command.state != EC_CMD_RECEIVED) {
+    if (eoe->command.state != EC_CMD_RECEIVED) {
         eoe->stats.tx_errors++;
         eoe->state = ec_eoe_state_rx_start;
         return;
     }
 
-    if (eoe->slave->mbox_command.working_counter != 1) {
+    if (eoe->command.working_counter != 1) {
         eoe->stats.tx_errors++;
         eoe->state = ec_eoe_state_rx_start;
         return;
--- a/master/ethernet.h	Mon May 29 09:54:18 2006 +0000
+++ b/master/ethernet.h	Mon Jun 26 15:04:06 2006 +0000
@@ -73,6 +73,7 @@
 {
     struct list_head list; /**< list item */
     ec_slave_t *slave; /**< pointer to the corresponding slave */
+    ec_command_t command; /**< command */
     void (*state)(ec_eoe_t *); /**< state function for the state machine */
     struct net_device *dev; /**< net_device for virtual ethernet device */
     struct net_device_stats stats; /**< device statistics */
--- a/master/fsm.c	Mon May 29 09:54:18 2006 +0000
+++ b/master/fsm.c	Mon Jun 26 15:04:06 2006 +0000
@@ -44,14 +44,6 @@
 
 /*****************************************************************************/
 
-/**
-   Size of memory to allocate while reading categories.
-*/
-
-#define EC_CAT_MEM 0x100
-
-/*****************************************************************************/
-
 const ec_code_msg_t al_status_messages[];
 
 /*****************************************************************************/
@@ -66,15 +58,15 @@
 void ec_fsm_master_reconfigure(ec_fsm_t *);
 void ec_fsm_master_address(ec_fsm_t *);
 void ec_fsm_master_conf(ec_fsm_t *);
+void ec_fsm_master_eeprom(ec_fsm_t *);
 
 void ec_fsm_slave_start_reading(ec_fsm_t *);
 void ec_fsm_slave_read_status(ec_fsm_t *);
 void ec_fsm_slave_read_base(ec_fsm_t *);
 void ec_fsm_slave_read_dl(ec_fsm_t *);
-void ec_fsm_slave_prepare_sii(ec_fsm_t *);
-void ec_fsm_slave_read_sii(ec_fsm_t *);
-void ec_fsm_slave_category_header(ec_fsm_t *);
-void ec_fsm_slave_category_data(ec_fsm_t *);
+void ec_fsm_slave_eeprom_size(ec_fsm_t *);
+void ec_fsm_slave_fetch_eeprom(ec_fsm_t *);
+void ec_fsm_slave_fetch_eeprom2(ec_fsm_t *);
 void ec_fsm_slave_end(ec_fsm_t *);
 
 void ec_fsm_slave_conf(ec_fsm_t *);
@@ -86,8 +78,11 @@
 void ec_fsm_slave_op2(ec_fsm_t *);
 
 void ec_fsm_sii_start_reading(ec_fsm_t *);
-void ec_fsm_sii_check(ec_fsm_t *);
-void ec_fsm_sii_fetch(ec_fsm_t *);
+void ec_fsm_sii_read_check(ec_fsm_t *);
+void ec_fsm_sii_read_fetch(ec_fsm_t *);
+void ec_fsm_sii_start_writing(ec_fsm_t *);
+void ec_fsm_sii_write_check(ec_fsm_t *);
+void ec_fsm_sii_write_check2(ec_fsm_t *);
 void ec_fsm_sii_end(ec_fsm_t *);
 void ec_fsm_sii_error(ec_fsm_t *);
 
@@ -115,7 +110,6 @@
     fsm->master_slaves_responding = 0;
     fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN;
     fsm->master_validation = 0;
-    fsm->slave_cat_data = NULL;
 
     ec_command_init(&fsm->command);
     if (ec_command_prealloc(&fsm->command, EC_MAX_DATA_SIZE)) {
@@ -134,7 +128,6 @@
 
 void ec_fsm_clear(ec_fsm_t *fsm /**< finite state machine */)
 {
-    if (fsm->slave_cat_data) kfree(fsm->slave_cat_data);
     ec_command_clear(&fsm->command);
 }
 
@@ -149,11 +142,6 @@
     fsm->master_state = ec_fsm_master_start;
     fsm->master_slaves_responding = 0;
     fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN;
-
-    if (fsm->slave_cat_data) {
-        kfree(fsm->slave_cat_data);
-        fsm->slave_cat_data = NULL;
-    }
 }
 
 /*****************************************************************************/
@@ -422,7 +410,25 @@
         return;
     }
 
-    // nothing to configure. restart master state machine.
+    if (master->mode == EC_MASTER_MODE_FREERUN) {
+        // nothing to configure. check for pending EEPROM write operations.
+        list_for_each_entry(slave, &master->slaves, list) {
+            if (!slave->new_eeprom_data) continue;
+
+            // found pending EEPROM write operation. execute it!
+            EC_INFO("Writing EEPROM of slave %i...\n", slave->ring_position);
+            fsm->sii_offset = 0x0000;
+            memcpy(fsm->sii_value, slave->new_eeprom_data, 2);
+            fsm->sii_mode = 1;
+            fsm->sii_state = ec_fsm_sii_start_writing;
+            fsm->slave = slave;
+            fsm->master_state = ec_fsm_master_eeprom;
+            fsm->master_state(fsm); // execute immediately
+            return;
+        }
+    }
+
+    // nothing to do. restart master state machine.
     fsm->master_state = ec_fsm_master_start;
     fsm->master_state(fsm); // execute immediately
 }
@@ -450,7 +456,7 @@
 
     if (fsm->sii_state != ec_fsm_sii_end) return;
 
-    if (fsm->sii_result != slave->sii_vendor_id) {
+    if (EC_READ_U32(fsm->sii_value) != slave->sii_vendor_id) {
         EC_ERR("Slave %i: invalid vendor ID!\n", slave->ring_position);
         fsm->master_state = ec_fsm_master_start;
         fsm->master_state(fsm); // execute immediately
@@ -488,10 +494,10 @@
 
     if (fsm->sii_state != ec_fsm_sii_end) return;
 
-    if (fsm->sii_result != slave->sii_product_code) {
+    if (EC_READ_U32(fsm->sii_value) != slave->sii_product_code) {
         EC_ERR("Slave %i: invalid product code!\n", slave->ring_position);
         EC_ERR("expected 0x%08X, got 0x%08X.\n", slave->sii_product_code,
-               fsm->sii_result);
+               EC_READ_U32(fsm->sii_value));
         fsm->master_state = ec_fsm_master_start;
         fsm->master_state(fsm); // execute immediately
         return;
@@ -682,6 +688,49 @@
     fsm->master_state(fsm); // execute immediately
 }
 
+/*****************************************************************************/
+
+/**
+   Master state: EEPROM.
+*/
+
+void ec_fsm_master_eeprom(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_slave_t *slave = fsm->slave;
+
+    fsm->sii_state(fsm); // execute SII state machine
+
+    if (fsm->sii_state == ec_fsm_sii_error) {
+        EC_ERR("Failed to write EEPROM contents to slave %i.\n",
+               slave->ring_position);
+        kfree(slave->new_eeprom_data);
+        slave->new_eeprom_data = NULL;
+        fsm->master_state = ec_fsm_master_start;
+        fsm->master_state(fsm); // execute immediately
+        return;
+    }
+
+    if (fsm->sii_state != ec_fsm_sii_end) return;
+
+    fsm->sii_offset++;
+    if (fsm->sii_offset < slave->new_eeprom_size) {
+        memcpy(fsm->sii_value, slave->new_eeprom_data + fsm->sii_offset, 2);
+        fsm->sii_state = ec_fsm_sii_start_writing;
+        fsm->sii_state(fsm); // execute immediately
+        return;
+    }
+
+    // finished writing EEPROM
+    EC_INFO("Finished writing EEPROM of slave %i.\n", slave->ring_position);
+    kfree(slave->new_eeprom_data);
+    slave->new_eeprom_data = NULL;
+
+    // restart master state machine.
+    fsm->master_state = ec_fsm_master_start;
+    fsm->master_state(fsm); // execute immediately
+    return;
+}
+
 /******************************************************************************
  *  slave state machine
  *****************************************************************************/
@@ -787,16 +836,17 @@
     // read data link status
     ec_command_nprd(command, slave->station_address, 0x0110, 2);
     ec_master_queue_command(slave->master, command);
-    fsm->slave_state = ec_fsm_slave_prepare_sii;
-}
-
-/*****************************************************************************/
-
-/**
-   Slave state: PREPARE_SII.
-*/
-
-void ec_fsm_slave_prepare_sii(ec_fsm_t *fsm /**< finite state machine */)
+    fsm->slave_state = ec_fsm_slave_eeprom_size;
+}
+
+/*****************************************************************************/
+
+/**
+   Slave state: EEPROM_SIZE.
+   Read the actual size of the EEPROM to allocate the EEPROM image.
+*/
+
+void ec_fsm_slave_eeprom_size(ec_fsm_t *fsm /**< finite state machine */)
 {
     ec_command_t *command = &fsm->command;
     ec_slave_t *slave = fsm->slave;
@@ -811,254 +861,183 @@
     }
 
     dl_status = EC_READ_U16(command->data);
-
     for (i = 0; i < 4; i++) {
         slave->dl_link[i] = dl_status & (1 << (4 + i)) ? 1 : 0;
         slave->dl_loop[i] = dl_status & (1 << (8 + i * 2)) ? 1 : 0;
         slave->dl_signal[i] = dl_status & (1 << (9 + i * 2)) ? 1 : 0;
     }
 
-    fsm->sii_offset = 0x0004;
+    // Start fetching EEPROM size
+
+    fsm->sii_offset = 0x0040; // first category header
     fsm->sii_mode = 1;
     fsm->sii_state = ec_fsm_sii_start_reading;
-    fsm->slave_sii_num = 0;
-    fsm->slave_state = ec_fsm_slave_read_sii;
+    fsm->slave_state = ec_fsm_slave_fetch_eeprom;
     fsm->slave_state(fsm); // execute state immediately
 }
 
 /*****************************************************************************/
 
 /**
-   Slave state: READ_SII.
-*/
-
-void ec_fsm_slave_read_sii(ec_fsm_t *fsm /**< finite state machine */)
-{
-    ec_slave_t *slave = fsm->slave;
+   Slave state: FETCH_EEPROM.
+*/
+
+void ec_fsm_slave_fetch_eeprom(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_slave_t *slave = fsm->slave;
+    uint16_t cat_type, cat_size;
 
     // execute SII state machine
     fsm->sii_state(fsm);
 
     if (fsm->sii_state == ec_fsm_sii_error) {
         fsm->slave_state = ec_fsm_slave_end;
-        EC_ERR("FSM failed to read SII data at 0x%04X on slave %i.\n",
-               fsm->sii_offset, slave->ring_position);
+        EC_ERR("Failed to read EEPROM size of slave %i.\n",
+               slave->ring_position);
         return;
     }
 
     if (fsm->sii_state != ec_fsm_sii_end) return;
 
-    switch (fsm->slave_sii_num) {
-        case 0:
-            slave->sii_alias = fsm->sii_result & 0xFFFF;
-            fsm->sii_offset = 0x0008;
-            break;
-        case 1:
-            slave->sii_vendor_id = fsm->sii_result;
-            fsm->sii_offset = 0x000A;
-            break;
-        case 2:
-            slave->sii_product_code = fsm->sii_result;
-            fsm->sii_offset = 0x000C;
-            break;
-        case 3:
-            slave->sii_revision_number = fsm->sii_result;
-            fsm->sii_offset = 0x000E;
-            break;
-        case 4:
-            slave->sii_serial_number = fsm->sii_result;
-            fsm->sii_offset = 0x0018;
-            break;
-        case 5:
-            slave->sii_rx_mailbox_offset = fsm->sii_result & 0xFFFF;
-            slave->sii_rx_mailbox_size = fsm->sii_result >> 16;
-            fsm->sii_offset = 0x001A;
-            break;
-        case 6:
-            slave->sii_tx_mailbox_offset = fsm->sii_result & 0xFFFF;
-            slave->sii_tx_mailbox_size = fsm->sii_result >> 16;
-            fsm->sii_offset = 0x001C;
-            break;
-        case 7:
-            slave->sii_mailbox_protocols = fsm->sii_result & 0xFFFF;
-
-            fsm->slave_cat_offset = 0x0040;
-
-            if (fsm->slave_cat_data) {
-                EC_INFO("FSM freeing old category data on slave %i...\n",
-                        fsm->slave->ring_position);
-                kfree(fsm->slave_cat_data);
-            }
-
-            if (!(fsm->slave_cat_data =
-                  (uint8_t *) kmalloc(EC_CAT_MEM, GFP_ATOMIC))) {
-                EC_ERR("FSM Failed to allocate category data.\n");
-                fsm->slave_state = ec_fsm_slave_end;
-                return;
-            }
-
-            // start reading first category header
-            fsm->sii_offset = fsm->slave_cat_offset;
-            fsm->sii_state = ec_fsm_sii_start_reading;
-
-            fsm->slave_state = ec_fsm_slave_category_header;
-            fsm->slave_state(fsm); // execute state immediately
-            return;
-    }
-
-    fsm->slave_sii_num++;
+    cat_type = EC_READ_U16(fsm->sii_value);
+    cat_size = EC_READ_U16(fsm->sii_value + 2);
+
+    if (cat_type != 0xFFFF) { // not the last category
+        fsm->sii_offset += cat_size + 2;
+        fsm->sii_state = ec_fsm_sii_start_reading;
+        fsm->sii_state(fsm); // execute state immediately
+        return;
+    }
+
+    slave->eeprom_size = (fsm->sii_offset + 1) * 2;
+
+    if (slave->eeprom_data) {
+        EC_INFO("Freeing old EEPROM data on slave %i...\n",
+                slave->ring_position);
+        kfree(slave->eeprom_data);
+    }
+
+    if (!(slave->eeprom_data =
+          (uint8_t *) kmalloc(slave->eeprom_size, GFP_ATOMIC))) {
+        EC_ERR("Failed to allocate EEPROM data on slave %i.\n",
+               slave->ring_position);
+        fsm->slave_state = ec_fsm_slave_end;
+        return;
+    }
+
+    // Start fetching EEPROM contents
+
+    fsm->sii_offset = 0x0000;
+    fsm->sii_mode = 1;
     fsm->sii_state = ec_fsm_sii_start_reading;
+    fsm->slave_state = ec_fsm_slave_fetch_eeprom2;
     fsm->slave_state(fsm); // execute state immediately
 }
 
 /*****************************************************************************/
 
 /**
-   Slave state: CATEGORY_HEADER.
-   Start reading categories.
-*/
-
-void ec_fsm_slave_category_header(ec_fsm_t *fsm /**< finite state machine */)
-{
+   Slave state: FETCH_EEPROM2.
+*/
+
+void ec_fsm_slave_fetch_eeprom2(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_slave_t *slave = fsm->slave;
+    uint16_t *cat_word, cat_type, cat_size;
+
     // execute SII state machine
     fsm->sii_state(fsm);
 
     if (fsm->sii_state == ec_fsm_sii_error) {
-        kfree(fsm->slave_cat_data);
-        fsm->slave_cat_data = NULL;
         fsm->slave_state = ec_fsm_slave_end;
-        EC_ERR("FSM failed to read category header at 0x%04X on slave %i.\n",
-               fsm->slave_cat_offset, fsm->slave->ring_position);
+        EC_ERR("Failed to fetch EEPROM contents of slave %i.\n",
+               slave->ring_position);
         return;
     }
 
     if (fsm->sii_state != ec_fsm_sii_end) return;
 
-    // last category?
-    if ((fsm->sii_result & 0xFFFF) == 0xFFFF) {
-        kfree(fsm->slave_cat_data);
-        fsm->slave_cat_data = NULL;
-        fsm->slave_state = ec_fsm_slave_end;
-        return;
-    }
-
-    fsm->slave_cat_type = fsm->sii_result & 0x7FFF;
-    fsm->slave_cat_words = (fsm->sii_result >> 16) & 0xFFFF;
-
-    if (fsm->slave_cat_words > EC_CAT_MEM * 2) {
-        EC_ERR("FSM category memory too small! %i words needed.\n",
-               fsm->slave_cat_words);
-        fsm->slave_state = ec_fsm_slave_end;
-        return;
-    }
-
-    // start reading category data
-    fsm->slave_cat_data_offset = 0;
-    fsm->sii_offset = (fsm->slave_cat_offset + 2 +
-                       fsm->slave_cat_data_offset);
-    fsm->sii_mode = 1;
-    fsm->sii_state = ec_fsm_sii_start_reading;
-    fsm->slave_state = ec_fsm_slave_category_data;
-    fsm->slave_state(fsm); // execute state immediately
-}
-
-/*****************************************************************************/
-
-/**
-   Slave state: CATEGORY_DATA.
-   Reads category data.
-*/
-
-void ec_fsm_slave_category_data(ec_fsm_t *fsm /**< finite state machine */)
-{
-    // execute SII state machine
-    fsm->sii_state(fsm);
-
-    if (fsm->sii_state == ec_fsm_sii_error) {
-        kfree(fsm->slave_cat_data);
-        fsm->slave_cat_data = NULL;
-        fsm->slave_state = ec_fsm_slave_end;
-        EC_ERR("FSM failed to read category 0x%02X data at 0x%04X"
-               " on slave %i.\n", fsm->slave_cat_type, fsm->sii_offset,
-               fsm->slave->ring_position);
-        return;
-    }
-
-    if (fsm->sii_state != ec_fsm_sii_end) return;
-
-    fsm->slave_cat_data[fsm->slave_cat_data_offset * 2] =
-        fsm->sii_result & 0xFF;
-    fsm->slave_cat_data[fsm->slave_cat_data_offset * 2 + 1] =
-        (fsm->sii_result >> 8) & 0xFF;
-
-    // read second word "on the fly"
-    if (fsm->slave_cat_data_offset + 1 < fsm->slave_cat_words) {
-        fsm->slave_cat_data_offset++;
-        fsm->slave_cat_data[fsm->slave_cat_data_offset * 2] =
-            (fsm->sii_result >> 16) & 0xFF;
-        fsm->slave_cat_data[fsm->slave_cat_data_offset * 2 + 1] =
-            (fsm->sii_result >> 24) & 0xFF;
-    }
-
-    fsm->slave_cat_data_offset++;
-
-    if (fsm->slave_cat_data_offset < fsm->slave_cat_words) {
-        fsm->sii_offset = (fsm->slave_cat_offset + 2 +
-                           fsm->slave_cat_data_offset);
-        fsm->sii_mode = 1;
+    // 2 words fetched
+
+    if (fsm->sii_offset + 2 <= slave->eeprom_size / 2) { // 2 words fit
+        memcpy(slave->eeprom_data + fsm->sii_offset * 2, fsm->sii_value, 4);
+    }
+    else { // copy the last word
+        memcpy(slave->eeprom_data + fsm->sii_offset * 2, fsm->sii_value, 2);
+    }
+
+    if (fsm->sii_offset + 2 < slave->eeprom_size / 2) {
+        // fetch the next 2 words
+        fsm->sii_offset += 2;
         fsm->sii_state = ec_fsm_sii_start_reading;
-        fsm->slave_state = ec_fsm_slave_category_data;
-        fsm->slave_state(fsm); // execute state immediately
-        return;
-    }
-
-    // category data complete
-    switch (fsm->slave_cat_type)
-    {
-        case 0x000A:
-            if (ec_slave_fetch_strings(fsm->slave, fsm->slave_cat_data))
-                goto out_free;
-            break;
-        case 0x001E:
-            if (ec_slave_fetch_general(fsm->slave, fsm->slave_cat_data))
-                goto out_free;
-            break;
-        case 0x0028:
-            break;
-        case 0x0029:
-            if (ec_slave_fetch_sync(fsm->slave, fsm->slave_cat_data,
-                                    fsm->slave_cat_words))
-                goto out_free;
-            break;
-        case 0x0032:
-            if (ec_slave_fetch_pdo(fsm->slave, fsm->slave_cat_data,
-                                   fsm->slave_cat_words,
-                                   EC_TX_PDO))
-                goto out_free;
-            break;
-        case 0x0033:
-            if (ec_slave_fetch_pdo(fsm->slave, fsm->slave_cat_data,
-                                   fsm->slave_cat_words,
-                                   EC_RX_PDO))
-                goto out_free;
-            break;
-        default:
-            EC_WARN("FSM: Unknown category type 0x%04X in slave %i.\n",
-                    fsm->slave_cat_type, fsm->slave->ring_position);
-    }
-
-    // start reading next category header
-    fsm->slave_cat_offset += 2 + fsm->slave_cat_words;
-    fsm->sii_offset = fsm->slave_cat_offset;
-    fsm->sii_mode = 1;
-    fsm->sii_state = ec_fsm_sii_start_reading;
-    fsm->slave_state = ec_fsm_slave_category_header;
-    fsm->slave_state(fsm); // execute state immediately
-    return;
-
- out_free:
-    kfree(fsm->slave_cat_data);
-    fsm->slave_cat_data = NULL;
+        fsm->sii_state(fsm); // execute state immediately
+        return;
+    }
+
+    // Evaluate EEPROM contents
+
+    slave->sii_alias =
+        EC_READ_U16(slave->eeprom_data + 2 * 0x0004);
+    slave->sii_vendor_id =
+        EC_READ_U32(slave->eeprom_data + 2 * 0x0008);
+    slave->sii_product_code =
+        EC_READ_U32(slave->eeprom_data + 2 * 0x000A);
+    slave->sii_revision_number =
+        EC_READ_U32(slave->eeprom_data + 2 * 0x000C);
+    slave->sii_serial_number =
+        EC_READ_U32(slave->eeprom_data + 2 * 0x000E);
+    slave->sii_rx_mailbox_offset =
+        EC_READ_U16(slave->eeprom_data + 2 * 0x0018);
+    slave->sii_rx_mailbox_size =
+        EC_READ_U16(slave->eeprom_data + 2 * 0x0019);
+    slave->sii_tx_mailbox_offset =
+        EC_READ_U16(slave->eeprom_data + 2 * 0x001A);
+    slave->sii_tx_mailbox_size =
+        EC_READ_U16(slave->eeprom_data + 2 * 0x001B);
+    slave->sii_mailbox_protocols =
+        EC_READ_U16(slave->eeprom_data + 2 * 0x001C);
+
+    // evaluate category data
+    cat_word = (uint16_t *) slave->eeprom_data + 0x0040;
+    while (EC_READ_U16(cat_word) != 0xFFFF) {
+        cat_type = EC_READ_U16(cat_word) & 0x7FFF;
+        cat_size = EC_READ_U16(cat_word + 1);
+
+        switch (cat_type) {
+            case 0x000A:
+                if (ec_slave_fetch_strings(slave, (uint8_t *) (cat_word + 2)))
+                    goto end;
+                break;
+            case 0x001E:
+                if (ec_slave_fetch_general(slave, (uint8_t *) (cat_word + 2)))
+                    goto end;
+                break;
+            case 0x0028:
+                break;
+            case 0x0029:
+                if (ec_slave_fetch_sync(slave, (uint8_t *) (cat_word + 2),
+                                        cat_size))
+                    goto end;
+                break;
+            case 0x0032:
+                if (ec_slave_fetch_pdo(slave, (uint8_t *) (cat_word + 2),
+                                       cat_size, EC_TX_PDO))
+                    goto end;
+                break;
+            case 0x0033:
+                if (ec_slave_fetch_pdo(slave, (uint8_t *) (cat_word + 2),
+                                       cat_size, EC_RX_PDO))
+                    goto end;
+                break;
+            default:
+                EC_WARN("Unknown category type 0x%04X in slave %i.\n",
+                        cat_type, slave->ring_position);
+        }
+
+        cat_word += cat_size + 2;
+    }
+
+ end:
     fsm->slave_state = ec_fsm_slave_end;
 }
 
@@ -1149,7 +1128,7 @@
     if (slave->type) {
         for (j = 0; slave->type->sync_managers[j] && j < EC_MAX_SYNC; j++) {
             sync = slave->type->sync_managers[j];
-            ec_sync_config(sync, command->data + EC_SYNC_SIZE * j);
+            ec_sync_config(sync, slave, command->data + EC_SYNC_SIZE * j);
         }
     }
 
@@ -1268,7 +1247,8 @@
                     0x0600, EC_FMMU_SIZE * slave->base_fmmu_count);
     memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
     for (j = 0; j < slave->fmmu_count; j++) {
-        ec_fmmu_config(&slave->fmmus[j], command->data + EC_FMMU_SIZE * j);
+        ec_fmmu_config(&slave->fmmus[j], slave,
+                       command->data + EC_FMMU_SIZE * j);
     }
 
     ec_master_queue_command(master, command);
@@ -1391,17 +1371,17 @@
     EC_WRITE_U8 (command->data + 1, 0x01); // request read operation
     EC_WRITE_U16(command->data + 2, fsm->sii_offset);
     ec_master_queue_command(fsm->master, command);
-    fsm->sii_state = ec_fsm_sii_check;
-}
-
-/*****************************************************************************/
-
-/**
-   SII state: CHECK.
+    fsm->sii_state = ec_fsm_sii_read_check;
+}
+
+/*****************************************************************************/
+
+/**
+   SII state: READ_CHECK.
    Checks, if the SII-read-command has been sent and issues a fetch command.
 */
 
-void ec_fsm_sii_check(ec_fsm_t *fsm /**< finite state machine */)
+void ec_fsm_sii_read_check(ec_fsm_t *fsm /**< finite state machine */)
 {
     ec_command_t *command = &fsm->command;
 
@@ -1422,17 +1402,17 @@
     }
 
     ec_master_queue_command(fsm->master, command);
-    fsm->sii_state = ec_fsm_sii_fetch;
-}
-
-/*****************************************************************************/
-
-/**
-   SII state: FETCH.
+    fsm->sii_state = ec_fsm_sii_read_fetch;
+}
+
+/*****************************************************************************/
+
+/**
+   SII state: READ_FETCH.
    Fetches the result of an SII-read command.
 */
 
-void ec_fsm_sii_fetch(ec_fsm_t *fsm /**< finite state machine */)
+void ec_fsm_sii_read_fetch(ec_fsm_t *fsm /**< finite state machine */)
 {
     ec_command_t *command = &fsm->command;
 
@@ -1477,13 +1457,93 @@
 #endif
 
     // SII value received.
-    fsm->sii_result = EC_READ_U32(command->data + 6);
+    memcpy(fsm->sii_value, command->data + 6, 4);
     fsm->sii_state = ec_fsm_sii_end;
 }
 
 /*****************************************************************************/
 
 /**
+   SII state: START_WRITING.
+   Starts reading the slave information interface.
+*/
+
+void ec_fsm_sii_start_writing(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_command_t *command = &fsm->command;
+
+    // initiate write operation
+    ec_command_npwr(command, fsm->slave->station_address, 0x502, 8);
+    EC_WRITE_U8 (command->data,     0x01); // enable write access
+    EC_WRITE_U8 (command->data + 1, 0x02); // request write operation
+    EC_WRITE_U32(command->data + 2, fsm->sii_offset);
+    memcpy(command->data + 6, fsm->sii_value, 2);
+    ec_master_queue_command(fsm->master, command);
+    fsm->sii_state = ec_fsm_sii_write_check;
+}
+
+/*****************************************************************************/
+
+/**
+   SII state: WRITE_CHECK.
+*/
+
+void ec_fsm_sii_write_check(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_command_t *command = &fsm->command;
+
+    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
+        EC_ERR("SII: Reception of write command failed.\n");
+        fsm->sii_state = ec_fsm_sii_error;
+        return;
+    }
+
+    fsm->sii_start = get_cycles();
+
+    // issue check/fetch command
+    ec_command_nprd(command, fsm->slave->station_address, 0x502, 2);
+    ec_master_queue_command(fsm->master, command);
+    fsm->sii_state = ec_fsm_sii_write_check2;
+}
+
+/*****************************************************************************/
+
+/**
+   SII state: WRITE_CHECK2.
+*/
+
+void ec_fsm_sii_write_check2(ec_fsm_t *fsm /**< finite state machine */)
+{
+    ec_command_t *command = &fsm->command;
+
+    if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) {
+        EC_ERR("SII: Reception of write check command failed.\n");
+        fsm->sii_state = ec_fsm_sii_error;
+        return;
+    }
+
+    if (EC_READ_U8(command->data + 1) & 0x82) {
+        // still busy... timeout?
+        if (get_cycles() - fsm->sii_start >= (cycles_t) 10 * cpu_khz) {
+            EC_ERR("SII: Write timeout.\n");
+            fsm->sii_state = ec_fsm_sii_error;
+        }
+
+        // issue check/fetch command again
+        ec_master_queue_command(fsm->master, command);
+    }
+    else if (EC_READ_U8(command->data + 1) & 0x40) {
+        EC_ERR("SII: Write operation failed!\n");
+        fsm->sii_state = ec_fsm_sii_error;
+    }
+    else { // success
+        fsm->sii_state = ec_fsm_sii_end;
+    }
+}
+
+/*****************************************************************************/
+
+/**
    SII state: END.
    End state of the slave SII state machine.
 */
--- a/master/fsm.h	Mon May 29 09:54:18 2006 +0000
+++ b/master/fsm.h	Mon Jun 26 15:04:06 2006 +0000
@@ -67,17 +67,11 @@
     unsigned int master_validation; /**< non-zero, if validation to do */
 
     void (*slave_state)(ec_fsm_t *); /**< slave state function */
-    uint8_t slave_sii_num; /**< SII value iteration counter */
-    uint8_t *slave_cat_data; /**< temporary memory for category data */
-    uint16_t slave_cat_offset; /**< current category word offset in EEPROM */
-    uint16_t slave_cat_data_offset; /**< current offset in category data */
-    uint16_t slave_cat_type; /**< type of current category */
-    uint16_t slave_cat_words; /**< number of words of current category */
 
     void (*sii_state)(ec_fsm_t *); /**< SII state function */
     uint16_t sii_offset; /**< input: offset in SII */
     unsigned int sii_mode; /**< SII reading done by APRD (0) or NPRD (1) */
-    uint32_t sii_result; /**< output: read SII value (32bit) */
+    uint8_t sii_value[4]; /**< raw SII value (32bit) */
     cycles_t sii_start; /**< sii start */
 
     void (*change_state)(ec_fsm_t *); /**< slave state change state function */
--- a/master/mailbox.c	Mon May 29 09:54:18 2006 +0000
+++ b/master/mailbox.c	Mon Jun 26 15:04:06 2006 +0000
@@ -52,12 +52,12 @@
    \return pointer to mailbox command data
 */
 
-uint8_t *ec_slave_mbox_prepare_send(ec_slave_t *slave, /**< slave */
+uint8_t *ec_slave_mbox_prepare_send(const ec_slave_t *slave, /**< slave */
+                                    ec_command_t *command, /**< command */
                                     uint8_t type, /**< mailbox protocol */
                                     size_t size /**< size of the data */
                                     )
 {
-    ec_command_t *command = &slave->mbox_command;
     size_t total_size;
 
     if (unlikely(!slave->sii_mailbox_protocols)) {
@@ -79,7 +79,7 @@
 
     EC_WRITE_U16(command->data,     size); // mailbox service data length
     EC_WRITE_U16(command->data + 2, slave->station_address); // station address
-    EC_WRITE_U8 (command->data + 4, 0x00); // hhannel & priority
+    EC_WRITE_U8 (command->data + 4, 0x00); // channel & priority
     EC_WRITE_U8 (command->data + 5, type); // underlying protocol type
 
     return command->data + 6;
@@ -92,10 +92,10 @@
    \return 0 in case of success, else < 0
 */
 
-int ec_slave_mbox_prepare_check(ec_slave_t *slave /**< slave */)
-{
-    ec_command_t *command = &slave->mbox_command;
-
+int ec_slave_mbox_prepare_check(const ec_slave_t *slave, /**< slave */
+                                ec_command_t *command /**< command */
+                                )
+{
     // FIXME: second sync manager?
     if (ec_command_nprd(command, slave->station_address, 0x808, 8))
         return -1;
@@ -110,9 +110,9 @@
    \return 0 in case of success, else < 0
 */
 
-int ec_slave_mbox_check(const ec_slave_t *slave /**< slave */)
-{
-    return EC_READ_U8(slave->mbox_command.data + 5) & 8 ? 1 : 0;
+int ec_slave_mbox_check(const ec_command_t *command /**< command */)
+{
+    return EC_READ_U8(command->data + 5) & 8 ? 1 : 0;
 }
 
 /*****************************************************************************/
@@ -122,10 +122,10 @@
    \return 0 in case of success, else < 0
 */
 
-int ec_slave_mbox_prepare_fetch(ec_slave_t *slave /**< slave */)
-{
-    ec_command_t *command = &slave->mbox_command;
-
+int ec_slave_mbox_prepare_fetch(const ec_slave_t *slave, /**< slave */
+                                ec_command_t *command /**< command */
+                                )
+{
     if (ec_command_nprd(command, slave->station_address,
                         slave->sii_tx_mailbox_offset,
                         slave->sii_tx_mailbox_size)) return -1;
@@ -139,12 +139,12 @@
    \return pointer to the received data
 */
 
-uint8_t *ec_slave_mbox_fetch(ec_slave_t *slave, /**< slave */
+uint8_t *ec_slave_mbox_fetch(const ec_slave_t *slave, /**< slave */
+                             ec_command_t *command, /**< command */
                              uint8_t type, /**< expected mailbox protocol */
                              size_t *size /**< size of the received data */
                              )
 {
-    ec_command_t *command = &slave->mbox_command;
     size_t data_size;
 
     if ((EC_READ_U8(command->data + 5) & 0x0F) != type) {
@@ -171,14 +171,13 @@
    \return pointer to the received data
 */
 
-uint8_t *ec_slave_mbox_simple_io(ec_slave_t *slave, /**< slave */
+uint8_t *ec_slave_mbox_simple_io(const ec_slave_t *slave, /**< slave */
+                                 ec_command_t *command, /**< command */
                                  size_t *size /**< size of the received data */
                                  )
 {
     uint8_t type;
-    ec_command_t *command;
-
-    command = &slave->mbox_command;
+
     type = EC_READ_U8(command->data + 5);
 
     if (unlikely(ec_master_simple_io(slave->master, command))) {
@@ -187,7 +186,7 @@
         return NULL;
     }
 
-    return ec_slave_mbox_simple_receive(slave, type, size);
+    return ec_slave_mbox_simple_receive(slave, command, type, size);
 }
 
 /*****************************************************************************/
@@ -197,21 +196,20 @@
    \return pointer to the received data
 */
 
-uint8_t *ec_slave_mbox_simple_receive(ec_slave_t *slave, /**< slave */
+uint8_t *ec_slave_mbox_simple_receive(const ec_slave_t *slave, /**< slave */
+                                      ec_command_t *command, /**< command */
                                       uint8_t type, /**< expected protocol */
                                       size_t *size /**< received data size */
                                       )
 {
     cycles_t start, end, timeout;
-    ec_command_t *command;
-
-    command = &slave->mbox_command;
+
     start = get_cycles();
     timeout = (cycles_t) 100 * cpu_khz; // 100ms
 
     while (1)
     {
-        if (ec_slave_mbox_prepare_check(slave)) return NULL;
+        if (ec_slave_mbox_prepare_check(slave, command)) return NULL;
         if (unlikely(ec_master_simple_io(slave->master, command))) {
             EC_ERR("Mailbox checking failed on slave %i!\n",
                    slave->ring_position);
@@ -220,7 +218,7 @@
 
         end = get_cycles();
 
-        if (ec_slave_mbox_check(slave))
+        if (ec_slave_mbox_check(command))
             break; // proceed with receiving data
 
         if ((end - start) >= timeout) {
@@ -232,7 +230,7 @@
         udelay(100);
     }
 
-    if (ec_slave_mbox_prepare_fetch(slave)) return NULL;
+    if (ec_slave_mbox_prepare_fetch(slave, command)) return NULL;
     if (unlikely(ec_master_simple_io(slave->master, command))) {
         EC_ERR("Mailbox receiving failed on slave %i!\n",
                slave->ring_position);
@@ -243,7 +241,7 @@
         EC_DBG("Mailbox receive took %ius.\n", ((u32) (end - start) * 1000
                                                 / cpu_khz));
 
-    return ec_slave_mbox_fetch(slave, type, size);
-}
-
-/*****************************************************************************/
+    return ec_slave_mbox_fetch(slave, command, type, size);
+}
+
+/*****************************************************************************/
--- a/master/mailbox.h	Mon May 29 09:54:18 2006 +0000
+++ b/master/mailbox.h	Mon Jun 26 15:04:06 2006 +0000
@@ -45,14 +45,17 @@
 
 /*****************************************************************************/
 
-uint8_t *ec_slave_mbox_prepare_send(ec_slave_t *, uint8_t, size_t);
-int      ec_slave_mbox_prepare_check(ec_slave_t *);
-int      ec_slave_mbox_check(const ec_slave_t *);
-int      ec_slave_mbox_prepare_fetch(ec_slave_t *);
-uint8_t *ec_slave_mbox_fetch(ec_slave_t *, uint8_t, size_t *);
+uint8_t *ec_slave_mbox_prepare_send(const ec_slave_t *, ec_command_t *,
+                                    uint8_t, size_t);
+int      ec_slave_mbox_prepare_check(const ec_slave_t *, ec_command_t *);
+int      ec_slave_mbox_check(const ec_command_t *);
+int      ec_slave_mbox_prepare_fetch(const ec_slave_t *, ec_command_t *);
+uint8_t *ec_slave_mbox_fetch(const ec_slave_t *, ec_command_t *,
+                             uint8_t, size_t *);
 
-uint8_t *ec_slave_mbox_simple_io(ec_slave_t *, size_t *);
-uint8_t *ec_slave_mbox_simple_receive(ec_slave_t *, uint8_t, size_t *);
+uint8_t *ec_slave_mbox_simple_io(const ec_slave_t *, ec_command_t *, size_t *);
+uint8_t *ec_slave_mbox_simple_receive(const ec_slave_t *, ec_command_t *,
+                                      uint8_t, size_t *);
 
 /*****************************************************************************/
 
--- a/master/master.c	Mon May 29 09:54:18 2006 +0000
+++ b/master/master.c	Mon Jun 26 15:04:06 2006 +0000
@@ -58,6 +58,8 @@
 void ec_master_freerun(void *);
 void ec_master_eoe_run(unsigned long);
 ssize_t ec_show_master_attribute(struct kobject *, struct attribute *, char *);
+ssize_t ec_store_master_attribute(struct kobject *, struct attribute *,
+                                  const char *, size_t);
 
 /*****************************************************************************/
 
@@ -65,16 +67,18 @@
 
 EC_SYSFS_READ_ATTR(slave_count);
 EC_SYSFS_READ_ATTR(mode);
+EC_SYSFS_READ_WRITE_ATTR(eeprom_write_enable);
 
 static struct attribute *ec_def_attrs[] = {
     &attr_slave_count,
     &attr_mode,
+    &attr_eeprom_write_enable,
     NULL,
 };
 
 static struct sysfs_ops ec_sysfs_ops = {
     .show = &ec_show_master_attribute,
-    .store = NULL
+    .store = ec_store_master_attribute
 };
 
 static struct kobj_type ktype_ec_master = {
@@ -244,6 +248,8 @@
     master->release_cb = NULL;
     master->cb_data = NULL;
 
+    master->eeprom_write_enable = 0;
+
     ec_fsm_reset(&master->fsm);
 }
 
@@ -492,7 +498,7 @@
 {
     unsigned int response_tries_left;
 
-    response_tries_left = 10;
+    response_tries_left = 10000;
 
     while (1)
     {
@@ -698,13 +704,13 @@
     ec_master_eoe_stop(master);
 
     EC_INFO("Stopping Free-Run mode.\n");
+    master->mode = EC_MASTER_MODE_IDLE;
 
     if (!cancel_delayed_work(&master->freerun_work)) {
         flush_workqueue(master->workqueue);
     }
 
     ec_master_clear_slaves(master);
-    master->mode = EC_MASTER_MODE_IDLE;
 }
 
 /*****************************************************************************/
@@ -730,7 +736,8 @@
     // release master lock
     spin_unlock_bh(&master->internal_lock);
 
-    queue_delayed_work(master->workqueue, &master->freerun_work, 1);
+    if (master->mode == EC_MASTER_MODE_FREERUN)
+        queue_delayed_work(master->workqueue, &master->freerun_work, 1);
 }
 
 /*****************************************************************************/
@@ -741,11 +748,16 @@
 */
 
 void ec_sync_config(const ec_sync_t *sync, /**< sync manager */
+                    const ec_slave_t *slave, /**< EtherCAT slave */
                     uint8_t *data /**> configuration memory */
                     )
 {
+    size_t sync_size;
+
+    sync_size = ec_slave_calc_sync_size(slave, sync);
+
     EC_WRITE_U16(data,     sync->physical_start_address);
-    EC_WRITE_U16(data + 2, sync->size);
+    EC_WRITE_U16(data + 2, sync_size);
     EC_WRITE_U8 (data + 4, sync->control_byte);
     EC_WRITE_U8 (data + 5, 0x00); // status byte (read only)
     EC_WRITE_U16(data + 6, 0x0001); // enable
@@ -777,11 +789,16 @@
 */
 
 void ec_fmmu_config(const ec_fmmu_t *fmmu, /**< FMMU */
+                    const ec_slave_t *slave, /**< EtherCAT slave */
                     uint8_t *data /**> configuration memory */
                     )
 {
+    size_t sync_size;
+
+    sync_size = ec_slave_calc_sync_size(slave, fmmu->sync);
+
     EC_WRITE_U32(data,      fmmu->logical_start_address);
-    EC_WRITE_U16(data + 4,  fmmu->sync->size);
+    EC_WRITE_U16(data + 4,  sync_size); // size of fmmu
     EC_WRITE_U8 (data + 6,  0x00); // logical start bit
     EC_WRITE_U8 (data + 7,  0x07); // logical end bit
     EC_WRITE_U16(data + 8,  fmmu->sync->physical_start_address);
@@ -825,6 +842,44 @@
 /*****************************************************************************/
 
 /**
+   Formats attribute data for SysFS write access.
+   \return number of bytes processed, or negative error code
+*/
+
+ssize_t ec_store_master_attribute(struct kobject *kobj, /**< slave's kobject */
+                                  struct attribute *attr, /**< attribute */
+                                  const char *buffer, /**< memory with data */
+                                  size_t size /**< size of data to store */
+                                  )
+{
+    ec_master_t *master = container_of(kobj, ec_master_t, kobj);
+
+    if (attr == &attr_eeprom_write_enable) {
+        if (!strcmp(buffer, "1\n")) {
+            master->eeprom_write_enable = 1;
+            EC_INFO("Slave EEPROM writing enabled.\n");
+            return size;
+        }
+        else if (!strcmp(buffer, "0\n")) {
+            master->eeprom_write_enable = 0;
+            EC_INFO("Slave EEPROM writing disabled.\n");
+            return size;
+        }
+
+        EC_ERR("Invalid value for eeprom_write_enable!\n");
+
+        if (master->eeprom_write_enable) {
+            master->eeprom_write_enable = 0;
+            EC_INFO("Slave EEPROM writing disabled.\n");
+        }
+    }
+
+    return -EINVAL;
+}
+
+/*****************************************************************************/
+
+/**
    Starts Ethernet-over-EtherCAT processing for all EoE-capable slaves.
 */
 
@@ -1088,7 +1143,7 @@
                 if (ec_command_npwr(command, slave->station_address,
                                     0x0800 + j * EC_SYNC_SIZE, EC_SYNC_SIZE))
                     return -1;
-                ec_sync_config(sync, command->data);
+                ec_sync_config(sync, slave, command->data);
                 if (unlikely(ec_master_simple_io(master, command))) {
                     EC_ERR("Setting sync manager %i failed on slave %i!\n",
                            j, slave->ring_position);
@@ -1166,7 +1221,7 @@
             if (ec_command_npwr(command, slave->station_address,
                                 0x0600 + j * EC_FMMU_SIZE, EC_FMMU_SIZE))
                 return -1;
-            ec_fmmu_config(fmmu, command->data);
+            ec_fmmu_config(fmmu, slave, command->data);
             if (unlikely(ec_master_simple_io(master, command))) {
                 EC_ERR("Setting FMMU %i failed on slave %i!\n",
                        j, slave->ring_position);
--- a/master/master.h	Mon May 29 09:54:18 2006 +0000
+++ b/master/master.h	Mon Jun 26 15:04:06 2006 +0000
@@ -122,6 +122,8 @@
     int (*request_cb)(void *); /**< lock request callback */
     void (*release_cb)(void *); /**< lock release callback */
     void *cb_data; /**< data parameter of locking callbacks */
+
+    uint8_t eeprom_write_enable; /**< allow write operations to EEPROMs */
 };
 
 /*****************************************************************************/
@@ -149,9 +151,9 @@
 
 // misc.
 void ec_master_clear_slaves(ec_master_t *);
-void ec_sync_config(const ec_sync_t *, uint8_t *);
+void ec_sync_config(const ec_sync_t *, const ec_slave_t *, uint8_t *);
 void ec_eeprom_sync_config(const ec_eeprom_sync_t *, uint8_t *);
-void ec_fmmu_config(const ec_fmmu_t *, uint8_t *);
+void ec_fmmu_config(const ec_fmmu_t *, const ec_slave_t *, uint8_t *);
 void ec_master_output_stats(ec_master_t *);
 
 /*****************************************************************************/
--- a/master/slave.c	Mon May 29 09:54:18 2006 +0000
+++ b/master/slave.c	Mon Jun 26 15:04:06 2006 +0000
@@ -69,6 +69,7 @@
 EC_SYSFS_READ_ATTR(sii_name);
 EC_SYSFS_READ_ATTR(type);
 EC_SYSFS_READ_WRITE_ATTR(state);
+EC_SYSFS_READ_WRITE_ATTR(eeprom);
 
 static struct attribute *def_attrs[] = {
     &attr_ring_position,
@@ -79,6 +80,7 @@
     &attr_sii_name,
     &attr_type,
     &attr_state,
+    &attr_eeprom,
     NULL,
 };
 
@@ -145,6 +147,8 @@
     slave->type = NULL;
     slave->registered = 0;
     slave->fmmu_count = 0;
+    slave->eeprom_data = NULL;
+    slave->eeprom_size = 0;
     slave->eeprom_group = NULL;
     slave->eeprom_image = NULL;
     slave->eeprom_order = NULL;
@@ -153,13 +157,14 @@
     slave->current_state = EC_SLAVE_STATE_UNKNOWN;
     slave->state_error = 0;
     slave->online = 1;
-
-    ec_command_init(&slave->mbox_command);
+    slave->new_eeprom_data = NULL;
+    slave->new_eeprom_size = 0;
 
     INIT_LIST_HEAD(&slave->eeprom_strings);
     INIT_LIST_HEAD(&slave->eeprom_syncs);
     INIT_LIST_HEAD(&slave->eeprom_pdos);
     INIT_LIST_HEAD(&slave->sdo_dictionary);
+    INIT_LIST_HEAD(&slave->varsize_fields);
 
     for (i = 0; i < 4; i++) {
         slave->dl_link[i] = 0;
@@ -186,6 +191,7 @@
     ec_eeprom_pdo_entry_t *entry, *next_ent;
     ec_sdo_t *sdo, *next_sdo;
     ec_sdo_entry_t *en, *next_en;
+    ec_varsize_t *var, *next_var;
 
     slave = container_of(kobj, ec_slave_t, kobj);
 
@@ -234,7 +240,14 @@
         kfree(sdo);
     }
 
-    ec_command_clear(&slave->mbox_command);
+    // free information about variable sized data fields
+    list_for_each_entry_safe(var, next_var, &slave->varsize_fields, list) {
+        list_del(&var->list);
+        kfree(var);
+    }
+
+    if (slave->eeprom_data) kfree(slave->eeprom_data);
+    if (slave->new_eeprom_data) kfree(slave->new_eeprom_data);
 }
 
 /*****************************************************************************/
@@ -1121,6 +1134,8 @@
 
     EC_INFO("  EEPROM data:\n");
 
+    EC_INFO("    EEPROM content size: %i Bytes\n", slave->eeprom_size);
+
     if (slave->sii_alias)
         EC_INFO("    Configured station alias: 0x%04X (%i)\n",
                 slave->sii_alias, slave->sii_alias);
@@ -1239,6 +1254,83 @@
 /*****************************************************************************/
 
 /**
+   Schedules an EEPROM write operation.
+   \return 0 in case of success, else < 0
+*/
+
+ssize_t ec_slave_write_eeprom(ec_slave_t *slave, /**< EtherCAT slave */
+                              const uint8_t *data, /**< new EEPROM data */
+                              size_t size /**< size of data in bytes */
+                              )
+{
+    uint16_t word_size, cat_type, cat_size;
+    const uint16_t *data_words, *next_header;
+    uint16_t *new_data;
+
+    if (!slave->master->eeprom_write_enable) {
+        EC_ERR("Writing EEPROMs not allowed! Enable via"
+               " eeprom_write_enable SysFS entry.\n");
+        return -1;
+    }
+
+    if (slave->master->mode != EC_MASTER_MODE_FREERUN) {
+        EC_ERR("Writing EEPROMs only allowed in freerun mode!\n");
+        return -1;
+    }
+
+    if (slave->new_eeprom_data) {
+        EC_ERR("Slave %i already has a pending EEPROM write operation!\n",
+               slave->ring_position);
+        return -1;
+    }
+
+    // coarse check of the data
+
+    if (size % 2) {
+        EC_ERR("EEPROM size is odd! Dropping.\n");
+        return -1;
+    }
+
+    data_words = (const uint16_t *) data;
+    word_size = size / 2;
+
+    if (word_size < 0x0041) {
+        EC_ERR("EEPROM data too short! Dropping.\n");
+        return -1;
+    }
+
+    next_header = data_words + 0x0040;
+    cat_type = EC_READ_U16(next_header);
+    while (cat_type != 0xFFFF) {
+        cat_type = EC_READ_U16(next_header);
+        cat_size = EC_READ_U16(next_header + 1);
+        if ((next_header + cat_size + 2) - data_words >= word_size) {
+            EC_ERR("EEPROM data seems to be corrupted! Dropping.\n");
+            return -1;
+        }
+        next_header += cat_size + 2;
+        cat_type = EC_READ_U16(next_header);
+    }
+
+    // data ok!
+
+    if (!(new_data = (uint16_t *) kmalloc(word_size * 2, GFP_KERNEL))) {
+        EC_ERR("Unable to allocate memory for new EEPROM data!\n");
+        return -1;
+    }
+    memcpy(new_data, data, size);
+
+    slave->new_eeprom_size = word_size;
+    slave->new_eeprom_data = new_data;
+
+    EC_INFO("EEPROM writing scheduled for slave %i, %i words.\n",
+            slave->ring_position, word_size);
+    return 0;
+}
+
+/*****************************************************************************/
+
+/**
    Formats attribute data for SysFS read access.
    \return number of bytes to read
 */
@@ -1295,6 +1387,19 @@
                 return sprintf(buffer, "UNKNOWN\n");
         }
     }
+    else if (attr == &attr_eeprom) {
+        if (slave->eeprom_data) {
+            if (slave->eeprom_size > PAGE_SIZE) {
+                EC_ERR("EEPROM contents of slave %i exceed 1 page (%i/%i).\n",
+                       slave->ring_position, slave->eeprom_size,
+                       (int) PAGE_SIZE);
+            }
+            else {
+                memcpy(buffer, slave->eeprom_data, slave->eeprom_size);
+                return slave->eeprom_size;
+            }
+        }
+    }
 
     return 0;
 }
@@ -1338,10 +1443,51 @@
 
         EC_ERR("Failed to set slave state!\n");
     }
+    else if (attr == &attr_eeprom) {
+        if (!ec_slave_write_eeprom(slave, buffer, size))
+            return size;
+    }
 
     return -EINVAL;
 }
 
+/*****************************************************************************/
+
+/**
+   \return size of sync manager contents
+*/
+
+size_t ec_slave_calc_sync_size(const ec_slave_t *slave, /**< EtherCAT slave */
+                               const ec_sync_t *sync /**< sync manager */
+                               )
+{
+    unsigned int i, found;
+    const ec_field_t *field;
+    const ec_varsize_t *var;
+    size_t size;
+
+    // if size is specified, return size
+    if (sync->size) return sync->size;
+
+    // sync manager has variable size (size == 0).
+
+    size = 0;
+    for (i = 0; (field = sync->fields[i]); i++) {
+        found = 0;
+        list_for_each_entry(var, &slave->varsize_fields, list) {
+            if (var->field != field) continue;
+            size += var->size;
+            found = 1;
+        }
+
+        if (!found) {
+            EC_WARN("Variable data field \"%s\" of slave %i has no size"
+                    " information!\n", field->name, slave->ring_position);
+        }
+    }
+    return size;
+}
+
 /******************************************************************************
  *  Realtime interface
  *****************************************************************************/
@@ -1361,9 +1507,75 @@
 
 /*****************************************************************************/
 
+/**
+   \return 0 in case of success, else < 0
+   \ingroup RealtimeInterface
+*/
+
+int ecrt_slave_field_size(ec_slave_t *slave, /**< EtherCAT slave */
+                          const char *field_name, /**< data field name */
+                          unsigned int field_index, /**< data field index */
+                          size_t size /**< new data field size */
+                          )
+{
+    unsigned int i, j, field_counter;
+    const ec_sync_t *sync;
+    const ec_field_t *field;
+    ec_varsize_t *var;
+
+    if (!slave->type) {
+        EC_ERR("Slave %i has no type information!\n", slave->ring_position);
+        return -1;
+    }
+
+    field_counter = 0;
+    for (i = 0; (sync = slave->type->sync_managers[i]); i++) {
+        for (j = 0; (field = sync->fields[j]); j++) {
+            if (!strcmp(field->name, field_name)) {
+                if (field_counter++ == field_index) {
+                    // is the size of this field variable?
+                    if (field->size) {
+                        EC_ERR("Field \"%s\"[%i] of slave %i has no variable"
+                               " size!\n", field->name, field_index,
+                               slave->ring_position);
+                        return -1;
+                    }
+                    // does a size specification already exist?
+                    list_for_each_entry(var, &slave->varsize_fields, list) {
+                        if (var->field == field) {
+                            EC_WARN("Resizing field \"%s\"[%i] of slave %i.\n",
+                                    field->name, field_index,
+                                    slave->ring_position);
+                            var->size = size;
+                            return 0;
+                        }
+                    }
+                    // create a new size specification...
+                    if (!(var = kmalloc(sizeof(ec_varsize_t), GFP_KERNEL))) {
+                        EC_ERR("Failed to allocate memory for varsize_t!\n");
+                        return -1;
+                    }
+                    var->field = field;
+                    var->size = size;
+                    list_add_tail(&var->list, &slave->varsize_fields);
+                    return 0;
+                }
+            }
+        }
+    }
+
+    EC_ERR("Slave %i (\"%s %s\") has no field \"%s\"[%i]!\n",
+           slave->ring_position, slave->type->vendor_name,
+           slave->type->product_name, field_name, field_index);
+    return -1;
+}
+
+/*****************************************************************************/
+
 /**< \cond */
 
 EXPORT_SYMBOL(ecrt_slave_write_alias);
+EXPORT_SYMBOL(ecrt_slave_field_size);
 
 /**< \endcond */
 
--- a/master/slave.h	Mon May 29 09:54:18 2006 +0000
+++ b/master/slave.h	Mon Jun 26 15:04:06 2006 +0000
@@ -214,6 +214,20 @@
 /*****************************************************************************/
 
 /**
+   Variable-sized field information.
+*/
+
+typedef struct
+{
+    struct list_head list; /**< list item */
+    const ec_field_t *field; /**< data field */
+    size_t size; /**< field size */
+}
+ec_varsize_t;
+
+/*****************************************************************************/
+
+/**
    EtherCAT slave.
 */
 
@@ -261,23 +275,28 @@
     ec_fmmu_t fmmus[EC_MAX_FMMUS]; /**< FMMU configurations */
     uint8_t fmmu_count; /**< number of FMMUs used */
 
+    uint8_t *eeprom_data; /**< Complete EEPROM image */
+    uint16_t eeprom_size; /**< size of the EEPROM contents in byte */
     struct list_head eeprom_strings; /**< EEPROM STRING categories */
     struct list_head eeprom_syncs; /**< EEPROM SYNC MANAGER categories */
     struct list_head eeprom_pdos; /**< EEPROM [RT]XPDO categories */
-
     char *eeprom_group; /**< slave group acc. to EEPROM */
     char *eeprom_image; /**< slave image name acc. to EEPROM */
     char *eeprom_order; /**< slave order number acc. to EEPROM */
     char *eeprom_name; /**< slave name acc. to EEPROM */
 
+    uint16_t *new_eeprom_data; /**< new EEPROM data to write */
+    size_t new_eeprom_size; /**< size of new EEPROM data in words */
+
     struct list_head sdo_dictionary; /**< SDO directory list */
 
-    ec_command_t mbox_command; /**< mailbox command */
-
     ec_slave_state_t requested_state; /**< requested slave state */
     ec_slave_state_t current_state; /**< current slave state */
     unsigned int state_error; /**< a state error has happened */
     unsigned int online; /**< non-zero, if the slave responds. */
+
+    struct list_head varsize_fields; /**< size information for variable-sized
+                                        data fields. */
 };
 
 /*****************************************************************************/
@@ -306,6 +325,7 @@
 int ec_slave_locate_string(ec_slave_t *, unsigned int, char **);
 
 // misc.
+size_t ec_slave_calc_sync_size(const ec_slave_t *, const ec_sync_t *);
 void ec_slave_print(const ec_slave_t *, unsigned int);
 int ec_slave_check_crc(ec_slave_t *);
 
--- a/master/types.c	Mon May 29 09:54:18 2006 +0000
+++ b/master/types.c	Mon Jun 26 15:04:06 2006 +0000
@@ -67,9 +67,39 @@
 
 /*****************************************************************************/
 
+const ec_field_t bk1120_out = {"Outputs", 0}; // variable size
+const ec_field_t bk1120_in = {"Inputs", 0}; // variable size
+
+const ec_sync_t bk1120_sm0 = {0x1C00, 264, 0x26, {NULL}};
+const ec_sync_t bk1120_sm1 = {0x1E00, 264, 0x22, {NULL}};
+
+const ec_sync_t bk1120_sm2 = { // outputs
+    0x1000, 0, 0x24, // variable size
+    {&bk1120_out, NULL}
+};
+
+const ec_sync_t bk1120_sm3 = { // inputs
+    0x1600, 0, 0x00, // variable size
+    {&bk1120_in, NULL}
+};
+
 const ec_slave_type_t Beckhoff_BK1120 = {
     "Beckhoff", "BK1120", "KBUS Coupler", EC_TYPE_NORMAL,
-    {NULL} // no sync managers
+    {&bk1120_sm0, &bk1120_sm1, &bk1120_sm2, &bk1120_sm3, NULL}
+};
+
+/*****************************************************************************/
+
+const ec_field_t el1004_in = {"InputValue", 1};
+
+const ec_sync_t el1004_sm0 = { // inputs
+    0x1000, 1, 0x00,
+    {&el1004_in, NULL}
+};
+
+const ec_slave_type_t Beckhoff_EL1004 = {
+    "Beckhoff", "EL1004", "4x Digital Input, 3ms", EC_TYPE_NORMAL,
+    {&el1004_sm0, NULL}
 };
 
 /*****************************************************************************/
@@ -82,7 +112,7 @@
 };
 
 const ec_slave_type_t Beckhoff_EL1014 = {
-    "Beckhoff", "EL1014", "4x Digital Input", EC_TYPE_NORMAL,
+    "Beckhoff", "EL1014", "4x Digital Input, 10us", EC_TYPE_NORMAL,
     {&el1014_sm0, NULL}
 };
 
@@ -186,8 +216,7 @@
     {&el5101_st, &el5101_ip, &el5101_la, NULL}
 };
 
-const ec_slave_type_t Beckhoff_EL5101 =
-{
+const ec_slave_type_t Beckhoff_EL5101 = {
     "Beckhoff", "EL5101", "Incremental Encoder Interface", EC_TYPE_NORMAL,
     {&mailbox_sm0, &mailbox_sm1, &el5101_sm2, &el5101_sm3, NULL}
 };
@@ -230,10 +259,11 @@
 */
 
 ec_slave_ident_t slave_idents[] = {
+    {0x00000002, 0x03EC3052, &Beckhoff_EL1004},
     {0x00000002, 0x03F63052, &Beckhoff_EL1014},
     {0x00000002, 0x044C2C52, &Beckhoff_EK1100},
     {0x00000002, 0x04562C52, &Beckhoff_EK1110},
-    //{0x00000002, 0x04602C22, &Beckhoff_BK1120},
+    {0x00000002, 0x04602C22, &Beckhoff_BK1120},
     {0x00000002, 0x07D43052, &Beckhoff_EL2004},
     {0x00000002, 0x07F03052, &Beckhoff_EL2032},
     {0x00000002, 0x0C1E3052, &Beckhoff_EL3102},
--- a/script/ethercat.sh	Mon May 29 09:54:18 2006 +0000
+++ b/script/ethercat.sh	Mon Jun 26 15:04:06 2006 +0000
@@ -66,14 +66,14 @@
     start)
 	echo -n "Starting EtherCAT master "
 
-	if [ ! $DEVICE_INDEX ]; then
+	if [ -z "$DEVICE_INDEX" ]; then
 	    echo "ERROR: DEVICE_INDEX not set!"
 	    /bin/false
 	    rc_status -v
 	    rc_exit
 	fi
 
-	if [ ! $EOE_DEVICES ]; then
+	if [ -z "$EOE_DEVICES" ]; then
 	    EOE_DEVICES=0
 	fi
 
@@ -99,6 +99,50 @@
 	    rc_exit
 	fi
 
+	# Build EoE bridge
+	if [ -n "$EOE_BRIDGE" ]; then
+
+		EOE_INTERFACES=`/sbin/ifconfig -a | grep -o -E "^eoe[0-9]+ "`
+
+		# add bridge, if it does not already exist
+		if ! /sbin/brctl show | grep -E -q "^$EOE_BRIDGE"; then
+			if ! /sbin/brctl addbr $EOE_BRIDGE; then
+				/bin/false
+				rc_status -v
+				rc_exit
+			fi
+		fi
+
+		# free all interfaces of their addresses and add them to the bridge
+		for interface in $EOE_INTERFACES $EOE_EXTRA_INTERFACES; do
+			if ! /sbin/ifconfig $interface 0.0.0.0 up; then
+				/bin/false
+				rc_status -v
+				rc_exit
+			fi
+			if ! /sbin/brctl show | grep -E -q "^$EOE_BRIDGE.*$interface"; then
+				if ! /sbin/brctl addif $EOE_BRIDGE $interface; then
+					/bin/false
+					rc_status -v
+					rc_exit
+				fi
+			fi
+		done
+		if [ -n "$EOE_IP_ADDRESS" -a -n "$EOE_IP_NETMASK" ]; then
+			if ! /sbin/ifconfig $EOE_BRIDGE $EOE_IP_ADDRESS \
+				netmask $EOE_IP_NETMASK; then
+				/bin/false
+				rc_status -v
+				rc_exit
+			fi
+		fi
+		if ! /sbin/ifconfig $EOE_BRIDGE up; then
+			/bin/false
+			rc_status -v
+			rc_exit
+		fi
+	fi
+
 	rc_status -v
 	;;
 
--- a/script/install.sh	Mon May 29 09:54:18 2006 +0000
+++ b/script/install.sh	Mon Jun 26 15:04:06 2006 +0000
@@ -49,24 +49,11 @@
     exit 1
 fi
 
-#------------------------------------------------------------------------------
-
-# Copy files
-
-INSTALLDIR=/lib/modules/$KERNEL/kernel/drivers/net
-MODULES=(master/ec_master.ko devices/ec_8139too.ko)
-
 echo "EtherCAT installer - Kernel: $KERNEL"
-echo "  Installing modules"
-
-for mod in ${MODULES[*]}; do
-    echo "    $mod"
-    cp $mod $INSTALLDIR || exit 1
-done
 
 #------------------------------------------------------------------------------
 
-# Update dependencies
+# Update module dependencies
 
 echo "  Building module dependencies"
 depmod
--- a/script/sysconfig	Mon May 29 09:54:18 2006 +0000
+++ b/script/sysconfig	Mon Jun 26 15:04:06 2006 +0000
@@ -18,4 +18,34 @@
 #
 #EOE_DEVICES=0
 
+#
+#  Bridge all EoE interfaces after master startup
+#  This variable shall contain the name of the EoE bridge to set up.
+#  If the variable is empty or undefined, no EoE bridge will be built.
+#
+#EOE_BRIDGE=eoebr0
+
+#
+#  IP address of the EoE bridge
+#  Set both EOE_IP_ADDRESS and EOE_IP_NETMASK to let the local host communicate
+#  with devices on the EoE bridge.
+#
+#EOE_IP_ADDRESS=192.168.X.X
+
+#
+#  IP netmask of the EoE bridge
+#  See EOE_IP_ADDRESS.
+#
+#EOE_IP_NETMASK=255.255.255.0
+
+#
+#  List of extra interfaces to include in the EoE bridge.
+#  Set this to interconnect the EoE bridge with other local interfaces.
+#  If EOE_BRIDGE is empty or undefined, setting this variable has no effect.
+#  Important: The IP address of these interfaces will be cleared. Set
+#  EOE_IP_ADDRESS and EOE_IP_NETMASK accordingly to enable IP traffic to
+#  extra interfaces.
+#
+#EOE_EXTRA_INTERFACES=eth0
+
 #------------------------------------------------------------------------------