merge stable-1.5
authorFlorian Pose <fp@igh-essen.com>
Fri, 25 Apr 2014 16:42:36 +0200
branchstable-1.5
changeset 2556 674fcdccc0f3
parent 2540 fca12d7035d1 (diff)
parent 2555 18c226b66533 (current diff)
child 2557 ded6d50de4a7
merge
configure.ac
examples/user/main.c
--- a/Makefile.am	Wed Apr 23 17:06:15 2014 +0200
+++ b/Makefile.am	Fri Apr 25 16:42:36 2014 +0200
@@ -30,11 +30,14 @@
 ACLOCAL_AMFLAGS = -I m4
 
 SUBDIRS = \
-	devices \
 	include \
-	master \
 	script
 
+if ENABLE_KERNEL
+SUBDIRS += devices
+SUBDIRS += master
+endif
+
 if BUILD_TOOL
 SUBDIRS += tool
 endif
--- a/NEWS	Wed Apr 23 17:06:15 2014 +0200
+++ b/NEWS	Fri Apr 25 16:42:36 2014 +0200
@@ -6,7 +6,11 @@
 
 -------------------------------------------------------------------------------
 
-Changes since 1.5.1:
+Changes since 1.5.2:
+
+* Fixed FoE timeout calculation bug.
+
+Changes in 1.5.2:
 
 * API extensions (find the complete description in include/ecrt.h)
     * Added redundancy features; enable using --with-devices.
--- a/configure.ac	Wed Apr 23 17:06:15 2014 +0200
+++ b/configure.ac	Fri Apr 25 16:42:36 2014 +0200
@@ -57,9 +57,42 @@
 AC_PROG_LIBTOOL
 
 #------------------------------------------------------------------------------
+# Kernel modules
+#------------------------------------------------------------------------------
+
+AC_MSG_CHECKING([whether to build kernel modules])
+
+AC_ARG_ENABLE([kernel],
+    AS_HELP_STRING([--enable-kernel],
+                   [Enable building kernel modules]),
+    [
+        case "${enableval}" in
+            yes) enablekernel=1
+                ;;
+            no) enablekernel=0
+                ;;
+            *) AC_MSG_ERROR([Invalid value for --enable-generic])
+                ;;
+        esac
+    ],
+    [enablekernel=1]
+)
+
+if test "x$enablekernel" = "x1"; then
+    AC_MSG_RESULT([yes])
+else
+    AC_MSG_RESULT([no])
+fi
+
+AM_CONDITIONAL(ENABLE_KERNEL, test "x$enablekernel" = "x1")
+AC_SUBST(ENABLE_KERNEL,[$enablekernel])
+
+#------------------------------------------------------------------------------
 # Linux sources
 #------------------------------------------------------------------------------
 
+if test "x$enablekernel" = "x1"; then
+
 AC_ARG_WITH([linux-dir],
     AC_HELP_STRING(
         [--with-linux-dir=<DIR>],
@@ -116,6 +149,8 @@
 AC_SUBST(LINUX_SOURCE_DIR,[$sourcedir])
 AC_MSG_RESULT([$LINUX_SOURCE_DIR (Kernel $linuxversion)])
 
+fi
+
 #------------------------------------------------------------------------------
 # Linux module installation subdirectory
 #------------------------------------------------------------------------------
@@ -150,7 +185,7 @@
                 ;;
         esac
     ],
-    [enablegeneric=1]
+    [enablegeneric=$enablekernel]
 )
 
 AM_CONDITIONAL(ENABLE_GENERIC, test "x$enablegeneric" = "x1")
@@ -173,7 +208,7 @@
                 ;;
         esac
     ],
-    [enable8139too=1]
+    [enable8139too=$enablekernel]
 )
 
 AM_CONDITIONAL(ENABLE_8139TOO, test "x$enable8139too" = "x1")
@@ -970,6 +1005,35 @@
 fi
 
 #------------------------------------------------------------------------------
+# syslog output in realtime context
+#------------------------------------------------------------------------------
+
+AC_MSG_CHECKING([whether to syslog in realtime context])
+
+AC_ARG_ENABLE([rt-syslog],
+    AS_HELP_STRING([--enable-rt-syslog],
+                   [Enable RT syslog (default: yes)]),
+    [
+        case "${enableval}" in
+            yes) rtsyslog=1
+                ;;
+            no) rtsyslog=0
+                ;;
+            *) AC_MSG_ERROR([Invalid value for --enable-rt-syslog])
+                ;;
+        esac
+    ],
+    [rtsyslog=1]
+)
+
+if test "x${rtsyslog}" = "x1"; then
+    AC_DEFINE([EC_RT_SYSLOG], [1], [Output to syslog in RT context])
+    AC_MSG_RESULT([yes])
+else
+    AC_MSG_RESULT([no])
+fi
+
+#------------------------------------------------------------------------------
 
 AC_CONFIG_FILES([
         Doxyfile
--- a/devices/e100-3.4-ethercat.c	Wed Apr 23 17:06:15 2014 +0200
+++ b/devices/e100-3.4-ethercat.c	Fri Apr 25 16:42:36 2014 +0200
@@ -2122,7 +2122,9 @@
 
 			// No need to detect link status as
 			// long as frames are received: Reset watchdog.
-			nic->ec_watchdog_jiffies = jiffies;
+			if (ecdev_get_link(nic->ecdev)) {
+				nic->ec_watchdog_jiffies = jiffies;
+			}
 		} else {
 			netif_receive_skb(skb);
 		}
--- a/devices/r8169-3.4-ethercat.c	Wed Apr 23 17:06:15 2014 +0200
+++ b/devices/r8169-3.4-ethercat.c	Fri Apr 25 16:42:36 2014 +0200
@@ -1,9 +1,9 @@
 /*
-* r8169.c: RealTek 8169/8168/8101 ethernet driver.
-*
-* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
-* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
-* Copyright (c) a lot of people too. Please respect their work.
+ * r8169.c: RealTek 8169/8168/8101 ethernet driver.
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
  *
  * See MAINTAINERS file for support contact information.
  */
@@ -31,6 +31,7 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
+
 #include "../globals.h"
 #include "ecdev.h"
 
@@ -744,9 +745,6 @@
 	struct mii_if_info mii;
 	struct rtl8169_counters counters;
 	u32 saved_wolopts;
-
-	ec_device_t *ecdev;
-	unsigned long ec_watchdog_jiffies;
 	u32 opts1_mask;
 
 	struct rtl_fw {
@@ -762,6 +760,9 @@
 		} phy_action;
 	} *rtl_fw;
 #define RTL_FIRMWARE_UNKNOWN	ERR_PTR(-EAGAIN)
+
+	ec_device_t *ecdev;
+	unsigned long ec_watchdog_jiffies;
 };
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -5548,7 +5549,7 @@
 	status = rtl_get_events(tp) & tp->event_slow;
 	rtl_ack_events(tp, status);
 
-	if (unlikely(!tp->ecdev && status & RxFIFOOver)) {
+	if (unlikely(!tp->ecdev && (status & RxFIFOOver))) {
 		switch (tp->mac_version) {
 		/* Work around for rx fifo overflow */
 		case RTL_GIGA_MAC_VER_11:
@@ -5560,7 +5561,7 @@
 		}
 	}
 
-	if (unlikely(!tp->ecdev && status & SYSErr))
+	if (unlikely(!tp->ecdev && (status & SYSErr)))
 		rtl8169_pcierr_interrupt(dev);
 
 	if (status & LinkChg)
@@ -5781,7 +5782,7 @@
 	rtl_request_firmware(tp);
 
 	if (!tp->ecdev) {
-		retval = request_irq(dev->irq, rtl8169_interrupt,
+		retval = request_irq(pdev->irq, rtl8169_interrupt,
 				(tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
 				dev->name, dev);
 		if (retval < 0)
--- a/documentation/ethercat_doc.tex	Wed Apr 23 17:06:15 2014 +0200
+++ b/documentation/ethercat_doc.tex	Fri Apr 25 16:42:36 2014 +0200
@@ -1239,6 +1239,25 @@
 realtime context.
 \end{itemize}
 
+\paragraph{Device Activation} In order to send and receive frames through a
+socket, the Ethernet device linked to that socket has to be activated,
+otherwise all frames will be rejected. Activation has to take place before the
+master module is loaded and can happen in several ways:
+
+\begin{itemize}
+
+\item Ad-hoc, using the command \lstinline+ip link set dev ethX up+ (or the
+older \lstinline+ifconfig ethX up+),
+
+\item Configured, depending on the distribution, for example using
+\lstinline+ifcfg+ files (\lstinline+/etc/sysconfig/network/ifcfg-ethX+) in
+openSUSE and others. This is the better choice, if the EtherCAT master shall
+start at system boot time. Since the Ethernet device shall only be activated,
+but no IP address etc.\ shall be assigned, it is enough to use
+\lstinline+STARTMODE=auto+ as configuration.
+
+\end{itemize}
+
 %------------------------------------------------------------------------------
 
 \section{Providing Ethernet Devices}
--- a/examples/user/main.c	Wed Apr 23 17:06:15 2014 +0200
+++ b/examples/user/main.c	Fri Apr 25 16:42:36 2014 +0200
@@ -1,6 +1,6 @@
 /*****************************************************************************
  *
- *  $Id: main.c,v 6a6dec6fc806 2012/09/19 17:46:58 fp $
+ *  $Id$
  *
  *  Copyright (C) 2007-2009  Florian Pose, Ingenieurgemeinschaft IgH
  *
--- a/master/datagram_pair.c	Wed Apr 23 17:06:15 2014 +0200
+++ b/master/datagram_pair.c	Fri Apr 25 16:42:36 2014 +0200
@@ -185,7 +185,9 @@
             dev_idx++) {
         ec_datagram_t *datagram = &pair->datagrams[dev_idx];
 
+#ifdef EC_RT_SYSLOG
         ec_datagram_output_stats(datagram);
+#endif
 
         if (datagram->state == EC_DATAGRAM_RECEIVED) {
             pair_wc += datagram->working_counter;
--- a/master/device.c	Wed Apr 23 17:06:15 2014 +0200
+++ b/master/device.c	Fri Apr 25 16:42:36 2014 +0200
@@ -663,7 +663,7 @@
     ec_device_debug_ring_append(device, RX, ec_data, ec_size);
 #endif
 
-    ec_master_receive_datagrams(device->master, ec_data, ec_size);
+    ec_master_receive_datagrams(device->master, device, ec_data, ec_size);
 }
 
 /*****************************************************************************/
--- a/master/domain.c	Wed Apr 23 17:06:15 2014 +0200
+++ b/master/domain.c	Fri Apr 25 16:42:36 2014 +0200
@@ -466,7 +466,10 @@
             ec_fmmu_config_t, list);
     unsigned int redundancy;
 #endif
-    unsigned int dev_idx, wc_change;
+    unsigned int dev_idx;
+#ifdef EC_RT_SYSLOG
+    unsigned int wc_change;
+#endif
 
 #if DEBUG_REDUNDANCY
     EC_MASTER_DBG(domain->master, 1, "domain %u process\n", domain->index);
@@ -569,6 +572,7 @@
 
     redundancy = redundant_wc > 0;
     if (redundancy != domain->redundancy_active) {
+#ifdef EC_RT_SYSLOG
         if (redundancy) {
             EC_MASTER_WARN(domain->master,
                     "Domain %u: Redundant link in use!\n",
@@ -578,23 +582,29 @@
                     "Domain %u: Redundant link unused again.\n",
                     domain->index);
         }
+#endif
         domain->redundancy_active = redundancy;
     }
 #else
     domain->redundancy_active = 0;
 #endif
 
+#ifdef EC_RT_SYSLOG
     wc_change = 0;
+#endif
     wc_total = 0;
     for (dev_idx = EC_DEVICE_MAIN;
             dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
         if (wc_sum[dev_idx] != domain->working_counter[dev_idx]) {
+#ifdef EC_RT_SYSLOG
             wc_change = 1;
+#endif
             domain->working_counter[dev_idx] = wc_sum[dev_idx];
         }
         wc_total += wc_sum[dev_idx];
     }
 
+#ifdef EC_RT_SYSLOG
     if (wc_change) {
         domain->working_counter_changes++;
     }
@@ -630,6 +640,7 @@
 
         domain->working_counter_changes = 0;
     }
+#endif
 }
 
 /*****************************************************************************/
--- a/master/fsm_foe.c	Wed Apr 23 17:06:15 2014 +0200
+++ b/master/fsm_foe.c	Fri Apr 25 16:42:36 2014 +0200
@@ -3,6 +3,7 @@
  *  $Id$
  *
  *  Copyright (C) 2008  Olav Zarges, imc Messsysteme GmbH
+ *                2013  Florian Pose <fp@igh-essen.com>
  *
  *  This file is part of the IgH EtherCAT Master.
  *
@@ -27,10 +28,9 @@
  *
  *****************************************************************************/
 
-/**
-   \file
-   EtherCAT FoE state machines.
-*/
+/** \file
+ * EtherCAT FoE state machines.
+ */
 
 /*****************************************************************************/
 
@@ -209,7 +209,7 @@
         )
 {
 #ifdef DEBUG_FOE
-    printk("ec_fsm_foe_error()\n");
+    EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
 #endif
 }
 
@@ -223,7 +223,7 @@
         )
 {
 #ifdef DEBUG_FOE
-    printk("ec_fsm_foe_end\n");
+    EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
 #endif
 }
 
@@ -321,7 +321,7 @@
     fsm->tx_last_packet = 0;
 
 #ifdef DEBUG_FOE
-    printk("ec_fsm_foe_write_start()\n");
+    EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
 #endif
 
     if (!(slave->sii.mailbox_protocols & EC_MBOX_FOE)) {
@@ -350,7 +350,7 @@
     ec_slave_t *slave = fsm->slave;
 
 #ifdef DEBUG_FOE
-    printk("ec_fsm_foe_ack_check()\n");
+    EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
 #endif
 
     if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -370,8 +370,8 @@
 
     if (!ec_slave_mbox_check(fsm->datagram)) {
         // slave did not put anything in the mailbox yet
-        unsigned long diff_ms =
-            (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
+        unsigned long diff_ms = (fsm->datagram->jiffies_received -
+                fsm->jiffies_start) * 1000 / HZ;
         if (diff_ms >= EC_FSM_FOE_TIMEOUT) {
             ec_foe_set_tx_error(fsm, FOE_TIMEOUT_ERROR);
             EC_SLAVE_ERR(slave, "Timeout while waiting for ack response.\n");
@@ -405,7 +405,7 @@
     size_t rec_size;
 
 #ifdef DEBUG_FOE
-    printk("ec_fsm_foe_ack_read()\n");
+    EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
 #endif
 
     if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -482,7 +482,7 @@
     ec_slave_t *slave = fsm->slave;
 
 #ifdef DEBUG_FOE
-    printk("ec_foe_state_sent_wrq()\n");
+    EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
 #endif
 
     if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -523,7 +523,7 @@
     ec_slave_t *slave = fsm->slave;
 
 #ifdef DEBUG_FOE
-    printk("ec_fsm_foe_state_data_sent()\n");
+    EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
 #endif
 
     if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -620,7 +620,7 @@
     ec_slave_t *slave = fsm->slave;
 
 #ifdef DEBUG_FOE
-    printk("ec_foe_state_rrq_sent()\n");
+    EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
 #endif
 
     if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -662,7 +662,7 @@
     fsm->rx_last_packet = 0;
 
 #ifdef DEBUG_FOE
-    printk("ec_fsm_foe_read_start()\n");
+    EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
 #endif
 
     if (!(slave->sii.mailbox_protocols & EC_MBOX_FOE)) {
@@ -691,7 +691,7 @@
     ec_slave_t *slave = fsm->slave;
 
 #ifdef DEBUG_FOE
-    printk("ec_fsm_foe_state_data_check()\n");
+    EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
 #endif
 
     if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -709,9 +709,8 @@
     }
 
     if (!ec_slave_mbox_check(fsm->datagram)) {
-        unsigned long diff_ms =
-            (fsm->datagram->jiffies_received - fsm->jiffies_start) *
-            1000 / HZ;
+        unsigned long diff_ms = (fsm->datagram->jiffies_received -
+                fsm->jiffies_start) * 1000 / HZ;
         if (diff_ms >= EC_FSM_FOE_TIMEOUT) {
             ec_foe_set_tx_error(fsm, FOE_TIMEOUT_ERROR);
             EC_SLAVE_ERR(slave, "Timeout while waiting for ack response.\n");
@@ -728,7 +727,6 @@
 
     fsm->retries = EC_FSM_RETRIES;
     fsm->state = ec_fsm_foe_state_data_read;
-
 }
 
 /*****************************************************************************/
@@ -746,7 +744,7 @@
     ec_slave_t *slave = fsm->slave;
 
 #ifdef DEBUG_FOE
-    printk("ec_fsm_foe_state_data_read()\n");
+    EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
 #endif
 
     if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
@@ -832,7 +830,7 @@
         // either it was the last packet or a new packet will fit into the
         // delivered buffer
 #ifdef DEBUG_FOE
-        printk ("last_packet=true\n");
+        EC_SLAVE_DBG(fsm->slave, 0, "last_packet=true\n");
 #endif
         if (ec_foe_prepare_send_ack(fsm, datagram)) {
             ec_foe_set_rx_error(fsm, FOE_RX_DATA_ACK_ERROR);
@@ -844,13 +842,12 @@
     else {
         // no more data fits into the delivered buffer
         // ... wait for new read request
-        printk ("ERROR: data doesn't fit in receive buffer\n");
-        printk ("       rx_buffer_size  = %d\n", fsm->rx_buffer_size);
-        printk ("       rx_buffer_offset= %d\n", fsm->rx_buffer_offset);
-        printk ("       rec_size        = %zd\n", rec_size);
-        printk ("       rx_mailbox_size = %d\n",
-                slave->configured_rx_mailbox_size);
-        printk ("       rx_last_packet  = %d\n", fsm->rx_last_packet);
+        EC_SLAVE_ERR(slave, "Data do not fit in receive buffer!\n");
+        printk("  rx_buffer_size = %d\n", fsm->rx_buffer_size);
+        printk("rx_buffer_offset = %d\n", fsm->rx_buffer_offset);
+        printk("        rec_size = %zd\n", rec_size);
+        printk(" rx_mailbox_size = %d\n", slave->configured_rx_mailbox_size);
+        printk("  rx_last_packet = %d\n", fsm->rx_last_packet);
         fsm->request->result = FOE_READY;
     }
 }
@@ -867,7 +864,7 @@
     ec_slave_t *slave = fsm->slave;
 
 #ifdef DEBUG_FOE
-    printk("ec_foe_state_sent_ack()\n");
+    EC_SLAVE_DBG(fsm->slave, 0, "%s()\n", __func__);
 #endif
 
     if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
--- a/master/fsm_master.c	Wed Apr 23 17:06:15 2014 +0200
+++ b/master/fsm_master.c	Fri Apr 25 16:42:36 2014 +0200
@@ -198,7 +198,47 @@
         ec_fsm_master_t *fsm /**< Master state machine. */
         )
 {
+    ec_master_t *master = fsm->master;
+
     fsm->idle = 1;
+
+    // check for emergency requests
+    if (!list_empty(&master->emerg_reg_requests)) {
+        ec_reg_request_t *request;
+
+        // get first request
+        request = list_entry(master->emerg_reg_requests.next,
+                ec_reg_request_t, list);
+        list_del_init(&request->list); // dequeue
+        request->state = EC_INT_REQUEST_BUSY;
+
+        if (request->transfer_size > fsm->datagram->mem_size) {
+            EC_MASTER_ERR(master, "Emergency request data too large!\n");
+            request->state = EC_INT_REQUEST_FAILURE;
+            wake_up_all(&master->request_queue);
+            fsm->state(fsm); // continue
+            return;
+        }
+
+        if (request->dir != EC_DIR_OUTPUT) {
+            EC_MASTER_ERR(master, "Emergency requests must be"
+                    " write requests!\n");
+            request->state = EC_INT_REQUEST_FAILURE;
+            wake_up_all(&master->request_queue);
+            fsm->state(fsm); // continue
+            return;
+        }
+
+        EC_MASTER_DBG(master, 1, "Writing emergency register request...\n");
+        ec_datagram_apwr(fsm->datagram, request->ring_position,
+                request->address, request->transfer_size);
+        memcpy(fsm->datagram->data, request->data, request->transfer_size);
+        fsm->datagram->device_index = EC_DEVICE_MAIN;
+        request->state = EC_INT_REQUEST_SUCCESS;
+        wake_up_all(&master->request_queue);
+        return;
+    }
+
     ec_datagram_brd(fsm->datagram, 0x0130, 2);
     ec_datagram_zero(fsm->datagram);
     fsm->datagram->device_index = fsm->dev_idx;
--- a/master/ioctl.c	Wed Apr 23 17:06:15 2014 +0200
+++ b/master/ioctl.c	Fri Apr 25 16:42:36 2014 +0200
@@ -1144,16 +1144,23 @@
         return -EINTR;
     }
 
-    if (!(slave = ec_master_find_slave(master, 0, io.slave_position))) {
-        up(&master->master_sem);
-        ec_reg_request_clear(&request);
-        EC_MASTER_ERR(master, "Slave %u does not exist!\n",
-                io.slave_position);
-        return -EINVAL;
-    }
-
-    // schedule request.
-    list_add_tail(&request.list, &slave->reg_requests);
+    if (io.emergency) {
+        request.ring_position = io.slave_position;
+        // schedule request.
+        list_add_tail(&request.list, &master->emerg_reg_requests);
+    }
+    else {
+        if (!(slave = ec_master_find_slave(master, 0, io.slave_position))) {
+            up(&master->master_sem);
+            ec_reg_request_clear(&request);
+            EC_MASTER_ERR(master, "Slave %u does not exist!\n",
+                    io.slave_position);
+            return -EINVAL;
+        }
+
+        // schedule request.
+        list_add_tail(&request.list, &slave->reg_requests);
+    }
 
     up(&master->master_sem);
 
--- a/master/ioctl.h	Wed Apr 23 17:06:15 2014 +0200
+++ b/master/ioctl.h	Fri Apr 25 16:42:36 2014 +0200
@@ -56,7 +56,7 @@
  *
  * Increment this when changing the ioctl interface!
  */
-#define EC_IOCTL_VERSION_MAGIC 27
+#define EC_IOCTL_VERSION_MAGIC 28
 
 // Command-line tool
 #define EC_IOCTL_MODULE                EC_IOR(0x00, ec_ioctl_module_t)
@@ -419,6 +419,7 @@
 typedef struct {
     // inputs
     uint16_t slave_position;
+    uint8_t emergency;
     uint16_t address;
     size_t size;
     uint8_t *data;
--- a/master/master.c	Wed Apr 23 17:06:15 2014 +0200
+++ b/master/master.c	Fri Apr 25 16:42:36 2014 +0200
@@ -60,6 +60,10 @@
  */
 #define DEBUG_INJECT 0
 
+/** Always output corrupted frames.
+ */
+#define FORCE_OUTPUT_CORRUPTED 0
+
 #ifdef EC_HAVE_CYCLES
 
 /** Frame timeout in cycles.
@@ -232,6 +236,7 @@
     master->app_cb_data = NULL;
 
     INIT_LIST_HEAD(&master->sii_requests);
+    INIT_LIST_HEAD(&master->emerg_reg_requests);
 
     init_waitqueue_head(&master->request_queue);
 
@@ -847,9 +852,13 @@
                     > ext_injection_timeout_jiffies)
 #endif
             {
+#if defined EC_RT_SYSLOG || DEBUG_INJECT
                 unsigned int time_us;
+#endif
 
                 datagram->state = EC_DATAGRAM_ERROR;
+
+#if defined EC_RT_SYSLOG || DEBUG_INJECT
 #ifdef EC_HAVE_CYCLES
                 time_us = (unsigned int)
                     ((cycles_now - datagram->cycles_sent) * 1000LL)
@@ -862,6 +871,7 @@
                         " external datagram %s size=%zu,"
                         " max_queue_size=%zu\n", time_us, datagram->name,
                         datagram->data_size, master->max_queue_size);
+#endif
             }
             else {
 #if DEBUG_INJECT
@@ -939,8 +949,10 @@
     list_for_each_entry(queued_datagram, &master->datagram_queue, queue) {
         if (queued_datagram == datagram) {
             datagram->skip_count++;
+#ifdef EC_RT_SYSLOG
             EC_MASTER_DBG(master, 1,
                     "Datagram %p already queued (skipping).\n", datagram);
+#endif
             datagram->state = EC_DATAGRAM_QUEUED;
             return;
         }
@@ -1106,10 +1118,12 @@
  *
  * \return 0 in case of success, else < 0
  */
-void ec_master_receive_datagrams(ec_master_t *master, /**< EtherCAT master */
-                                 const uint8_t *frame_data, /**< frame data */
-                                 size_t size /**< size of the received data */
-                                 )
+void ec_master_receive_datagrams(
+        ec_master_t *master, /**< EtherCAT master */
+        ec_device_t *device, /**< EtherCAT device */
+        const uint8_t *frame_data, /**< frame data */
+        size_t size /**< size of the received data */
+        )
 {
     size_t frame_size, data_size;
     uint8_t datagram_type, datagram_index;
@@ -1118,14 +1132,16 @@
     ec_datagram_t *datagram;
 
     if (unlikely(size < EC_FRAME_HEADER_SIZE)) {
-        if (master->debug_level) {
+        if (master->debug_level || FORCE_OUTPUT_CORRUPTED) {
             EC_MASTER_DBG(master, 0, "Corrupted frame received"
-                    " (size %zu < %u byte):\n",
-                    size, EC_FRAME_HEADER_SIZE);
+                    " on %s (size %zu < %u byte):\n",
+                    device->dev->name, size, EC_FRAME_HEADER_SIZE);
             ec_print_data(frame_data, size);
         }
         master->stats.corrupted++;
+#ifdef EC_RT_SYSLOG
         ec_master_output_stats(master);
+#endif
         return;
     }
 
@@ -1136,14 +1152,17 @@
     cur_data += EC_FRAME_HEADER_SIZE;
 
     if (unlikely(frame_size > size)) {
-        if (master->debug_level) {
+        if (master->debug_level || FORCE_OUTPUT_CORRUPTED) {
             EC_MASTER_DBG(master, 0, "Corrupted frame received"
-                    " (invalid frame size %zu for "
-                    "received size %zu):\n", frame_size, size);
+                    " on %s (invalid frame size %zu for "
+                    "received size %zu):\n", device->dev->name,
+                    frame_size, size);
             ec_print_data(frame_data, size);
         }
         master->stats.corrupted++;
+#ifdef EC_RT_SYSLOG
         ec_master_output_stats(master);
+#endif
         return;
     }
 
@@ -1158,13 +1177,16 @@
 
         if (unlikely(cur_data - frame_data
                      + data_size + EC_DATAGRAM_FOOTER_SIZE > size)) {
-            if (master->debug_level) {
+            if (master->debug_level || FORCE_OUTPUT_CORRUPTED) {
                 EC_MASTER_DBG(master, 0, "Corrupted frame received"
-                        " (invalid data size %zu):\n", data_size);
+                        " on %s (invalid data size %zu):\n",
+                        device->dev->name, data_size);
                 ec_print_data(frame_data, size);
             }
             master->stats.corrupted++;
+#ifdef EC_RT_SYSLOG
             ec_master_output_stats(master);
+#endif
             return;
         }
 
@@ -1183,7 +1205,9 @@
         // no matching datagram was found
         if (!matched) {
             master->stats.unmatched++;
+#ifdef EC_RT_SYSLOG
             ec_master_output_stats(master);
+#endif
 
             if (unlikely(master->debug_level > 0)) {
                 EC_MASTER_DBG(master, 0, "UNMATCHED datagram:\n");
@@ -2476,6 +2500,8 @@
             list_del_init(&datagram->queue);
             datagram->state = EC_DATAGRAM_TIMED_OUT;
             master->stats.timeouts++;
+
+#ifdef EC_RT_SYSLOG
             ec_master_output_stats(master);
 
             if (unlikely(master->debug_level > 0)) {
@@ -2493,6 +2519,7 @@
                         " index %02X waited %u us.\n",
                         datagram, datagram->index, time_us);
             }
+#endif /* RT_SYSLOG */
         }
     }
 }
--- a/master/master.h	Wed Apr 23 17:06:15 2014 +0200
+++ b/master/master.h	Fri Apr 25 16:42:36 2014 +0200
@@ -305,6 +305,8 @@
     void *app_cb_data; /**< Application callback data. */
 
     struct list_head sii_requests; /**< SII write requests. */
+    struct list_head emerg_reg_requests; /**< Emergency register access
+                                           requests. */
 
     wait_queue_head_t request_queue; /**< Wait queue for external requests
                                        from user space. */
@@ -341,7 +343,8 @@
 #endif
 
 // datagram IO
-void ec_master_receive_datagrams(ec_master_t *, const uint8_t *, size_t);
+void ec_master_receive_datagrams(ec_master_t *, ec_device_t *,
+        const uint8_t *, size_t);
 void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *);
 void ec_master_queue_datagram_ext(ec_master_t *, ec_datagram_t *);
 
--- a/master/reg_request.c	Wed Apr 23 17:06:15 2014 +0200
+++ b/master/reg_request.c	Fri Apr 25 16:42:36 2014 +0200
@@ -62,6 +62,7 @@
     reg->address = 0;
     reg->transfer_size = 0;
     reg->state = EC_INT_REQUEST_INIT;
+    reg->ring_position = 0;
     return 0;
 }
 
--- a/master/reg_request.h	Wed Apr 23 17:06:15 2014 +0200
+++ b/master/reg_request.h	Fri Apr 25 16:42:36 2014 +0200
@@ -54,6 +54,7 @@
     uint16_t address; /**< Register address. */
     size_t transfer_size; /**< Size of the data to transfer. */
     ec_internal_request_state_t state; /**< Request state. */
+    uint16_t ring_position; /**< Ring position for emergency requests. */
 };
 
 /*****************************************************************************/
--- a/script/ethercat.conf	Wed Apr 23 17:06:15 2014 +0200
+++ b/script/ethercat.conf	Fri Apr 25 16:42:36 2014 +0200
@@ -4,10 +4,12 @@
 #
 #  $Id$
 #
+#  vim: spelllang=en spell tw=78
+#
 #------------------------------------------------------------------------------
 
 #
-# Master devices.
+# Main Ethernet devices.
 #
 # The MASTER<X>_DEVICE variable specifies the Ethernet device for a master
 # with index 'X'.
@@ -26,6 +28,15 @@
 #MASTER1_DEVICE=""
 
 #
+# Backup Ethernet devices
+#
+# The MASTER<X>_BACKUP variables specify the devices used for redundancy. They
+# behaves nearly the same as the MASTER<X>_DEVICE variable, except that it
+# does not interpret the ff:ff:ff:ff:ff:ff address.
+#
+#MASTER0_BACKUP=""
+
+#
 # Ethernet driver modules to use for EtherCAT operation.
 #
 # Specify a non-empty list of Ethernet drivers, that shall be used for EtherCAT
@@ -42,6 +53,10 @@
 # Note: The e100, e1000, e1000e and r8169 drivers are not built by default.
 # Enable them with the --enable-<driver> configure switches.
 #
+# Attention: When using the generic driver, the corresponding Ethernet device
+# has to be activated (with OS methods, for example 'ip link set ethX up'),
+# before the master is started, otherwise all frames will time out.
+#
 DEVICE_MODULES=""
 
 #
--- a/script/ethercat.service.in	Wed Apr 23 17:06:15 2014 +0200
+++ b/script/ethercat.service.in	Fri Apr 25 16:42:36 2014 +0200
@@ -1,10 +1,24 @@
 #
-# EtherCAT Master Kernel Modules
+# EtherCAT master kernel modules
 #
 
 [Unit]
 Description=EtherCAT Master Kernel Modules
 
+#
+# Uncomment this, if the generic Ethernet driver is used. It assures, that the
+# network interfaces are configured, before the master starts.
+#
+#Requires=network.service # Stop master, if network is stopped
+#After=network.service # Start master, after network is ready
+
+#
+# Uncomment this, if a native Ethernet driver is used. It assures, that the
+# network interfaces are configured, after the Ethernet drivers have been
+# replaced. Otherwise, the networking configuration tools could be confused.
+#
+#Before=network.service
+
 [Service]
 Type=oneshot
 RemainAfterExit=yes
--- a/script/sysconfig/ethercat	Wed Apr 23 17:06:15 2014 +0200
+++ b/script/sysconfig/ethercat	Fri Apr 25 16:42:36 2014 +0200
@@ -53,6 +53,10 @@
 # Note: The e100, e1000, e1000e and r8169 drivers are not built by default.
 # Enable them with the --enable-<driver> configure switches.
 #
+# Attention: When using the generic driver, the corresponding Ethernet device
+# has to be activated (with OS methods, for example 'ip link set ethX up'),
+# before the master is started, otherwise all frames will time out.
+#
 DEVICE_MODULES=""
 
 #
--- a/tool/Command.cpp	Wed Apr 23 17:06:15 2014 +0200
+++ b/tool/Command.cpp	Fri Apr 25 16:42:36 2014 +0200
@@ -150,7 +150,9 @@
 Command::Command(const string &name, const string &briefDesc):
     name(name),
     briefDesc(briefDesc),
-    verbosity(Normal)
+    verbosity(Normal),
+    emergency(false),
+    force(false)
 {
 }
 
@@ -204,6 +206,13 @@
 
 /*****************************************************************************/
 
+void Command::setEmergency(bool e)
+{
+    emergency = e;
+};
+
+/*****************************************************************************/
+
 void Command::setForce(bool f)
 {
     force = f;
@@ -489,6 +498,19 @@
 
 /****************************************************************************/
 
+int Command::emergencySlave() const
+{
+    unsigned int ret;
+
+    stringstream str;
+    str << positions;
+    str >> ret;
+
+    return ret;
+}
+
+/****************************************************************************/
+
 string Command::alStateString(uint8_t state)
 {
     string ret;
--- a/tool/Command.h	Wed Apr 23 17:06:15 2014 +0200
+++ b/tool/Command.h	Fri Apr 25 16:42:36 2014 +0200
@@ -107,6 +107,9 @@
         void setDataType(const string &);
         const string &getDataType() const;
 
+        void setEmergency(bool);
+        bool getEmergency() const;
+
         void setForce(bool);
         bool getForce() const;
 
@@ -140,6 +143,7 @@
         ConfigList selectedConfigs(MasterDevice &);
         typedef list<ec_ioctl_domain_t> DomainList;
         DomainList selectedDomains(MasterDevice &, const ec_ioctl_master_t &);
+        int emergencySlave() const;
 
         static string alStateString(uint8_t);
 
@@ -152,6 +156,7 @@
         string positions;
         string domains;
         string dataType;
+        bool emergency;
         bool force;
         string outputFile;
         string skin;
@@ -189,6 +194,13 @@
 
 /****************************************************************************/
 
+inline bool Command::getEmergency() const
+{
+    return emergency;
+}
+
+/****************************************************************************/
+
 inline bool Command::getForce() const
 {
     return force;
--- a/tool/CommandRegRead.cpp	Wed Apr 23 17:06:15 2014 +0200
+++ b/tool/CommandRegRead.cpp	Fri Apr 25 16:42:36 2014 +0200
@@ -149,6 +149,7 @@
         throwSingleSlaveRequired(slaves.size());
     }
     io.slave_position = slaves.front().position;
+    io.emergency = false;
 
     io.data = new uint8_t[io.size];
 
--- a/tool/CommandRegWrite.cpp	Wed Apr 23 17:06:15 2014 +0200
+++ b/tool/CommandRegWrite.cpp	Fri Apr 25 16:42:36 2014 +0200
@@ -68,10 +68,12 @@
         << typeInfo()
         << endl
         << "Command-specific options:" << endl
-        << "  --alias    -a <alias>" << endl
-        << "  --position -p <pos>    Slave selection. See the help of" << endl
-        << "                         the 'slaves' command." << endl
-        << "  --type     -t <type>   Data type (see above)." << endl
+        << "  --alias     -a <alias>" << endl
+        << "  --position  -p <pos>    Slave selection. See the help of"
+        << endl
+        << "                          the 'slaves' command." << endl
+        << "  --type      -t <type>   Data type (see above)." << endl
+        << "  --emergency -e          Send as emergency request." << endl
         << endl
         << numericInfo();
 
@@ -85,7 +87,6 @@
     stringstream strOffset, err;
     ec_ioctl_slave_reg_t io;
     ifstream file;
-    SlaveList slaves;
 
     if (args.size() != 2) {
         err << "'" << getName() << "' takes exactly two arguments!";
@@ -158,12 +159,19 @@
         throw e;
     }
 
-    slaves = selectedSlaves(m);
-    if (slaves.size() != 1) {
-        delete [] io.data;
-        throwSingleSlaveRequired(slaves.size());
-    }
-    io.slave_position = slaves.front().position;
+    if (getEmergency()) {
+        io.slave_position = emergencySlave();
+        io.emergency = true;
+    }
+    else {
+        SlaveList slaves = selectedSlaves(m);
+        if (slaves.size() != 1) {
+            delete [] io.data;
+            throwSingleSlaveRequired(slaves.size());
+        }
+        io.slave_position = slaves.front().position;
+        io.emergency = false;
+    }
 
     // send data to master
     try {
--- a/tool/main.cpp	Wed Apr 23 17:06:15 2014 +0200
+++ b/tool/main.cpp	Fri Apr 25 16:42:36 2014 +0200
@@ -83,6 +83,7 @@
 string dataTypeStr;
 Command::Verbosity verbosity = Command::Normal;
 bool force = false;
+bool emergency = false;
 bool helpRequested = false;
 string outputFile;
 string skin;
@@ -149,6 +150,7 @@
         {"type",        required_argument, NULL, 't'},
         {"output-file", required_argument, NULL, 'o'},
         {"skin",        required_argument, NULL, 's'},
+        {"emergency",   no_argument,       NULL, 'e'},
         {"force",       no_argument,       NULL, 'f'},
         {"quiet",       no_argument,       NULL, 'q'},
         {"verbose",     no_argument,       NULL, 'v'},
@@ -157,7 +159,7 @@
     };
 
     do {
-        c = getopt_long(argc, argv, "m:a:p:d:t:o:s:fqvh", longOptions, NULL);
+        c = getopt_long(argc, argv, "m:a:p:d:t:o:s:efqvh", longOptions, NULL);
 
         switch (c) {
             case 'm':
@@ -188,6 +190,10 @@
                 skin = optarg;
                 break;
 
+            case 'e':
+                emergency = true;
+                break;
+
             case 'f':
                 force = true;
                 break;
@@ -315,6 +321,7 @@
                     cmd->setDataType(dataTypeStr);
                     cmd->setOutputFile(outputFile);
                     cmd->setSkin(skin);
+                    cmd->setEmergency(emergency);
                     cmd->setForce(force);
                     cmd->execute(commandArgs);
                 } catch (InvalidUsageException &e) {