Merged
authorMartin Troxler <ch1010277@ch10lt194>
Tue, 19 Jan 2010 19:33:47 +0100
changeset 1777 a93fc03eeb06
parent 1776 65786b1d3043 (current diff)
parent 1774 a9143f82c7c5 (diff)
child 1778 94dbb44884ec
child 1799 f228415225b7
Merged
documentation/images/architecture.fig
--- a/.hgignore	Tue Jan 19 19:31:55 2010 +0100
+++ b/.hgignore	Tue Jan 19 19:33:47 2010 +0100
@@ -32,6 +32,48 @@
 devices/e1000/Makefile
 devices/e1000/Makefile.in
 devices/modules.order
+documentation/ethercat_doc.aux
+documentation/ethercat_doc.idx
+documentation/ethercat_doc.lof
+documentation/ethercat_doc.log
+documentation/ethercat_doc.lot
+documentation/ethercat_doc.nlo
+documentation/ethercat_doc.out
+documentation/ethercat_doc.pdf
+documentation/ethercat_doc.toc
+documentation/external
+documentation/graphs/fsm_change.pdf
+documentation/graphs/fsm_change.ps
+documentation/graphs/fsm_eoe.pdf
+documentation/graphs/fsm_eoe.ps
+documentation/graphs/fsm_master.pdf
+documentation/graphs/fsm_master.ps
+documentation/graphs/fsm_pdo_conf.pdf
+documentation/graphs/fsm_pdo_conf.ps
+documentation/graphs/fsm_pdo_entry_conf.pdf
+documentation/graphs/fsm_pdo_entry_conf.ps
+documentation/graphs/fsm_pdo_entry_read.pdf
+documentation/graphs/fsm_pdo_entry_read.ps
+documentation/graphs/fsm_pdo_read.pdf
+documentation/graphs/fsm_pdo_read.ps
+documentation/graphs/fsm_sii.pdf
+documentation/graphs/fsm_sii.ps
+documentation/graphs/fsm_slave_conf.pdf
+documentation/graphs/fsm_slave_conf.ps
+documentation/graphs/fsm_slave_scan.pdf
+documentation/graphs/fsm_slave_scan.ps
+documentation/images/app-config.pdf
+documentation/images/architecture.pdf
+documentation/images/attach.pdf
+documentation/images/dc.pdf
+documentation/images/fmmus.pdf
+documentation/images/fsm-coedown.pdf
+documentation/images/fsm-eoe.pdf
+documentation/images/interrupt.pdf
+documentation/images/master-locks.pdf
+documentation/images/masters.pdf
+documentation/images/phases.pdf
+documentation/images/statetrans.pdf
 examples/Kbuild
 examples/Makefile
 examples/Makefile.in
--- a/FEATURES	Tue Jan 19 19:31:55 2010 +0100
+++ b/FEATURES	Tue Jan 19 19:33:47 2010 +0100
@@ -14,13 +14,16 @@
   - Runs as kernel module for Linux 2.6.
   - Multiple masters possible on one machine.
 
-* EtherCAT-capable versions of standard Linux drivers for wide-spread
-  Ethernet devices.
-  - Interrupt-less operation of Ethernet devices.
-  - Easy implementation of additional Ethernet drivers through common device
-    interface.
+* Native EtherCAT-capable versions of standard Linux drivers for wide-spread
+  Ethernet devices, as well as a generic driver for all chips supported by the
+  Linux kernel.
+  - Interrupt-less operation of Ethernet devices when using native drivers.
+  - Easy implementation of additional native Ethernet drivers through common
+    device interface.
   - Operation possible with any device supported by the standard drivers,
     including PCMCIA devices.
+  - For any other hardware, the generic driver can be used. It uses the lower
+    layers of the Linux network stack.
 
 * Supports any realtime environment through independent architecture.
   - RTAI, Xenomai, RT-Preempt, etc.
--- a/TODO	Tue Jan 19 19:31:55 2010 +0100
+++ b/TODO	Tue Jan 19 19:33:47 2010 +0100
@@ -10,6 +10,37 @@
 
 Version 1.5.0:
 
+* Fix link detection in generic driver.
+* Remove byte-swapping functions from user space.
+* Implement 'ethercat foe_read --output-file ...'.
+* Use ec_datagram_zero() wherever possible.
+* Fix arguments of reg_read.
+* Number layout for reg_read.
+* Finish library implementation.
+* Rescan command.
+* Document ec_fsm_foe members.
+* Implement identifier parameter for cstruct command.
+* Implement sync delimiter for cstruct command.
+* Change SDO index at runtime for SDO request.
+* Output skipped datagrams again.
+* Output warning on unmatched slave configuration.
+* Output warning when send_ext() is called in illegal context.
+* Output hexadecimal values in 'ethercat xml'.
+* Add native drivers from 2.6.24 up to 2.6.31.
+
+Future issues:
+
+* Implement ecrt_slave_config_request_state().
+* Implement CompleteAccess for command-line tool.
+* Implement CompleteAccess for SDO uploads.
+* Check for Enable SDO Complete Access flag.
+* Remove default buffer size in SDO upload.
+* Improve application-triggered SDO transfers by moving the state machine into
+  the SDO handlers.
+* Check for ioctl() interface version.
+* Remove allow_scanning flag.
+* Override sync manager size?
+* Show Record / Array / List type of SDOs.
 * Distributed clocks:
     - Check 32/64 bit operations.
     - Use vendor correction factors when calculating transmission delays.
@@ -20,39 +51,6 @@
       "System Time" register instead of using the application time.
     - Check if register 0x0980 is working, to avoid clearing it when
       configuring.
-* Remove byte-swapping functions from user space.
-* Implement 'ethercat foe_read --output-file ...'.
-* Use ec_datagram_zero() where possible.
-* Fix arguments of reg_read.
-* Number layout for reg_read.
-* Show Record / Array / List type of SDOs.
-* Finish library implementation.
-* Rescan command.
-* Override sync manager size?
-* Check force_config flag before error.
-* Remove allow_scanning flag.
-* Check for ioctl() interface version.
-* Improve application-triggered SDO transfers by moving the state machine into
-  the SDO handlers.
-* Document ec_fsm_foe members.
-* Test KBUILD_EXTRA_SYMBOLS.
-* Remove default buffer size in SDO upload.
-* Check for Enable SDO Complete Access flag.
-* Implement CompleteAccess for command-line tool.
-* Implement CompleteAccess for SDO uploads.
-* Implement identifier parameter for cstruct command.
-* Implement sync delimiter for cstruct command.
-* Change SDO index at runtime for SDO request.
-* Implement ecrt_slave_config_request_state().
-* Output skipped datagrams again.
-* Output warning on unmatched slave configuration.
-* ec_direction_t default
-* Send_ext context warn
-* XML hex
-* r8169
-
-Future issues:
-
 * Mailbox protocol handlers.
 * Mailbox state machine using toggle bits.
 * External memory for SDO transfers.
--- a/configure.ac	Tue Jan 19 19:31:55 2010 +0100
+++ b/configure.ac	Tue Jan 19 19:33:47 2010 +0100
@@ -475,6 +475,30 @@
 fi
 
 #------------------------------------------------------------------------------
+# High-resolution timer support
+#------------------------------------------------------------------------------
+
+AC_ARG_ENABLE([hrtimer],
+    AS_HELP_STRING([--enable-hrtimer],
+                   [Use high-resolution timer for scheduling (default: no)]),
+    [
+        case "${enableval}" in
+            yes) hrtimer=1
+                ;;
+            no) hrtimer=0
+                ;;
+            *) AC_MSG_ERROR([Invalid value for --enable-hrtimer])
+                ;;
+        esac
+    ],
+    [hrtimer=0]
+)
+
+if test "x${hrtimer}" = "x1"; then
+    AC_DEFINE([EC_USE_HRTIMER], [1], [Use hrtimer for scheduling])
+fi
+
+#------------------------------------------------------------------------------
 # Command-line tool
 #-----------------------------------------------------------------------------
 
--- a/devices/generic.c	Tue Jan 19 19:31:55 2010 +0100
+++ b/devices/generic.c	Tue Jan 19 19:33:47 2010 +0100
@@ -70,16 +70,16 @@
 typedef struct {
     struct list_head list;
     struct net_device *netdev;
-	struct net_device *used_netdev;
-	struct socket *socket;
+    struct net_device *used_netdev;
+    struct socket *socket;
     ec_device_t *ecdev;
     uint8_t *rx_buf;
 } ec_gen_device_t;
 
 typedef struct {
     struct list_head list;
-	struct net_device *netdev;
-	char name[IFNAMSIZ];
+    struct net_device *netdev;
+    char name[IFNAMSIZ];
     int ifindex;
     uint8_t dev_addr[ETH_ALEN];
 } ec_gen_interface_desc_t;
@@ -202,7 +202,7 @@
     int ret;
     struct sockaddr_ll sa;
 
-	dev->rx_buf = kmalloc(EC_GEN_RX_BUF_SIZE, GFP_KERNEL);
+    dev->rx_buf = kmalloc(EC_GEN_RX_BUF_SIZE, GFP_KERNEL);
     if (!dev->rx_buf) {
         return -ENOMEM;
     }
@@ -242,8 +242,8 @@
 {
     int ret = 0;
 
-	dev->used_netdev = desc->netdev;
-	memcpy(dev->netdev->dev_addr, desc->dev_addr, ETH_ALEN);
+    dev->used_netdev = desc->netdev;
+    memcpy(dev->netdev->dev_addr, desc->dev_addr, ETH_ALEN);
 
     dev->ecdev = ecdev_offer(dev->netdev, ec_gen_poll, THIS_MODULE);
     if (dev->ecdev) {
@@ -254,7 +254,7 @@
             ecdev_withdraw(dev->ecdev);
             dev->ecdev = NULL;
         } else {
-			ecdev_set_link(dev->ecdev, netif_carrier_ok(dev->used_netdev)); // FIXME
+            ecdev_set_link(dev->ecdev, netif_carrier_ok(dev->used_netdev)); // FIXME
             ret = 1;
         }
     }
@@ -296,7 +296,7 @@
     size_t len = skb->len;
     int ret;
 
-	ecdev_set_link(dev->ecdev,netif_carrier_ok(dev->used_netdev));
+    ecdev_set_link(dev->ecdev, netif_carrier_ok(dev->used_netdev));
 
     iov.iov_base = skb->data;
     iov.iov_len = len;
@@ -319,8 +319,9 @@
     struct kvec iov;
     int ret, budget = 10; // FIXME
 
-	ecdev_set_link(dev->ecdev,netif_carrier_ok(dev->used_netdev));
-	do {
+    ecdev_set_link(dev->ecdev, netif_carrier_ok(dev->used_netdev));
+
+    do {
         iov.iov_base = dev->rx_buf;
         iov.iov_len = EC_GEN_RX_BUF_SIZE;
         memset(&msg, 0, sizeof(msg));
@@ -414,7 +415,7 @@
             goto out_err;
         }
         strncpy(desc->name, netdev->name, IFNAMSIZ);
-		desc->netdev = netdev;
+        desc->netdev = netdev;
         desc->ifindex = netdev->ifindex;
         memcpy(desc->dev_addr, netdev->dev_addr, ETH_ALEN);
         list_add_tail(&desc->list, &descs);
--- a/documentation/ethercat_doc.tex	Tue Jan 19 19:31:55 2010 +0100
+++ b/documentation/ethercat_doc.tex	Tue Jan 19 19:33:47 2010 +0100
@@ -16,7 +16,7 @@
 \usepackage{makeidx}
 \usepackage[refpage]{nomencl}
 \usepackage{listings}
-\usepackage{svn}
+\usepackage[nofancy]{rcsinfo}
 \usepackage{SIunits}
 \usepackage{amsmath} % for \text{}
 \usepackage{hyperref}
@@ -62,8 +62,7 @@
 \newcommand{\IgH}{\raisebox{-0.7667ex}
   {\includegraphics[height=2.2ex]{images/ighsign}}}
 
-\SVN $Date$
-\SVN $Revision$
+\rcsInfo $RCSId$
 
 \newcommand{\masterversion}{1.5.0}
 \newcommand{\linenum}[1]{\normalfont\textcircled{\tiny #1}}
@@ -71,6 +70,10 @@
 \makeindex
 \makenomenclature
 
+% Revision and date on inner footer
+\ifoot[\scriptsize\rcsInfoRevision, \rcsInfoDate]
+    {\scriptsize\rcsInfoRevision, \rcsInfoDate}
+
 %------------------------------------------------------------------------------
 
 \begin{document}
@@ -84,7 +87,7 @@
 
     {\Huge\bf IgH \includegraphics[height=2.4ex]{images/ethercat}
       Master \masterversion\\[1ex]
-      Preliminary Documentation}
+      Documentation}
 
     \vspace{1ex}
     \rule{\textwidth}{1.5mm}
@@ -93,13 +96,15 @@
     \url{fp@igh-essen.com}\\[1ex] Ingenieurgemeinschaft \IgH}
 
     \vspace{\fill}
-    {\Large Essen, \SVNDate\\[1ex]
-      Revision \SVNRevision}
+    {\Large Essen, \rcsInfoLongDate\\[1ex]
+      Revision \rcsInfoRevision}
   \end{center}
 \end{titlepage}
 
 %------------------------------------------------------------------------------
 
+\pagestyle{scrplain}
+
 \tableofcontents
 \listoftables
 \listoffigures
@@ -172,15 +177,20 @@
 
 \item Implemented according to IEC 61158-12 \cite{dlspec} \cite{alspec}.
 
-\item Comes with EtherCAT-capable drivers for several common Ethernet devices.
+\item Comes with EtherCAT-capable native drivers for several common Ethernet
+chips, as well as a generic driver for all chips supported by the Linux
+kernel.
 
   \begin{itemize}
 
-  \item The Ethernet hardware is operated without interrupts.
-
-  \item Drivers for additional Ethernet hardware can easily be implemented
-  using the common device interface (see sec.~\ref{sec:ecdev}) provided by the
-  master module.
+  \item The native drivers operate the hardware without interrupts.
+
+  \item Native drivers for additional Ethernet hardware can easily be
+  implemented using the common device interface (see sec.~\ref{sec:ecdev})
+  provided by the master module.
+
+  \item For any other hardware, the generic driver can be used. It uses the
+  lower layers of the Linux network stack.
 
   \end{itemize}
 
@@ -192,9 +202,9 @@
 
   \begin{itemize}
 
-  \item RTAI\nomenclature{RTAI}{Realtime Application Interface},
+  \item RTAI\nomenclature{RTAI}{Realtime Application Interface} \cite{rtai},
   ADEOS\nomenclature{ADEOS}{Adaptive Domain Environment for Operating
-  Systems}, etc.
+  Systems}, RT-Preempt \cite{rt-preempt}, etc.
 
   \item It runs well even without realtime extensions.
 
@@ -362,7 +372,7 @@
 
 \begin{figure}[htbp]
   \centering
-  \includegraphics[width=.9\textwidth]{images/architecture}
+  \includegraphics[width=\textwidth]{images/architecture}
   \caption{Master Architecture}
   \label{fig:arch}
 \end{figure}
@@ -933,8 +943,29 @@
 standard Ethernet hardware to communicate with the bus.
 
 The term \textit{device} is used as a synonym for Ethernet network interface
-hardware. There are device driver modules that handle Ethernet hardware, which
-a master can use to connect to an EtherCAT bus.
+hardware.
+
+\paragraph{Native Ethernet Device Drivers} There are native device driver
+modules (see sec.~\ref{sec:native-drivers}) that handle Ethernet hardware,
+which a master can use to connect to an EtherCAT bus. They offer their
+Ethernet hardware to the master module via the device interface (see
+sec.~\ref{sec:ecdev}) and must be capable to prepare Ethernet devices either
+for EtherCAT (realtime) operation or for ``normal'' operation using the
+kernel's network stack. The advantage of this approach is that the master can
+operate nearly directly on the hardware, which allows a high performance. The
+disadvantage is, that there has to be an EtherCAT-capable version of the
+original Ethernet driver.
+
+\paragraph{Generic Ethernet Device Driver} From master version 1.5, there is a
+generic Ethernet device driver module (see sec.~\ref{sec:generic-driver}),
+that uses the lower layers of the network stack to connect to the hardware.
+The advantage is, that arbitrary Ethernet hardware can be used for EtherCAT
+operation, independently of the actual hardware driver (so all Linux Ethernet
+drivers are supported without modifications). The disadvantage is, that this
+approach does not support realtime extensions like RTAI, because the Linux
+network stack is addressed. Moreover the performance is a little worse than
+the native approach, because the Ethernet frame data have to traverse the
+network stack.
 
 %------------------------------------------------------------------------------
 
@@ -947,52 +978,44 @@
 to understand how Linux handles network devices and their drivers,
 respectively.
 
-\paragraph{Tasks of a Network Driver}
-
-Network device drivers usually handle the lower two layers of the OSI model,
-that is the physical layer and the data-link layer. A network device itself
-natively handles the physical layer issues: It represents the hardware to
-connect to the medium and to send and receive data in the way, the physical
-layer protocol describes. The network device driver is responsible for getting
-data from the kernel's networking stack and forwarding it to the hardware,
-that does the physical transmission.  If data is received by the hardware
-respectively, the driver is notified (usually by means of an interrupt) and
-has to read the data from the hardware memory and forward it to the network
-stack. There are a few more tasks, a network device driver has to handle,
-including queue control, statistics and device dependent features.
-
-\paragraph{Driver Startup}
-
-Usually, a driver searches for compatible devices on module loading.
-For PCI drivers, this is done by scanning the PCI bus and checking for
-known device IDs. If a device is found, data structures are allocated
-and the device is taken into operation.
-
-\paragraph{Interrupt Operation}
-\index{Interrupt}
-
-A network device usually provides a hardware interrupt that is used to
-notify the driver of received frames and success of transmission, or
-errors, respectively. The driver has to register an interrupt service
-routine (ISR\index{ISR}\nomenclature{ISR}{Interrupt Service Routine}),
-that is executed each time, the hardware signals such an event. If the
-interrupt was thrown by the own device (multiple devices can share one
-hardware interrupt), the reason for the interrupt has to be determined
-by reading the device's interrupt register. For example, if the flag
-for received frames is set, frame data has to be copied from hardware
-to kernel memory and passed to the network stack.
-
-\paragraph{The \lstinline+net_device+ Structure}
-\index{net\_device}
-
-The driver registers a \lstinline+net_device+ structure for each device to
-communicate with the network stack and to create a ``network interface''. In
-case of an Ethernet driver, this interface appears as \textit{ethX}, where X
-is a number assigned by the kernel on registration. The \lstinline+net_device+
-structure receives events (either from userspace or from the network stack)
-via several callbacks, which have to be set before registration. Not every
-callback is mandatory, but for reasonable operation the ones below are needed
-in any case:
+\paragraph{Tasks of a Network Driver} Network device drivers usually handle
+the lower two layers of the OSI model, that is the physical layer and the
+data-link layer. A network device itself natively handles the physical layer
+issues: It represents the hardware to connect to the medium and to send and
+receive data in the way, the physical layer protocol describes. The network
+device driver is responsible for getting data from the kernel's networking
+stack and forwarding it to the hardware, that does the physical transmission.
+If data is received by the hardware respectively, the driver is notified
+(usually by means of an interrupt) and has to read the data from the hardware
+memory and forward it to the network stack. There are a few more tasks, a
+network device driver has to handle, including queue control, statistics and
+device dependent features.
+
+\paragraph{Driver Startup} Usually, a driver searches for compatible devices
+on module loading.  For PCI drivers, this is done by scanning the PCI bus and
+checking for known device IDs. If a device is found, data structures are
+allocated and the device is taken into operation.
+
+\paragraph{Interrupt Operation}\index{Interrupt} A network device usually
+provides a hardware interrupt that is used to notify the driver of received
+frames and success of transmission, or errors, respectively. The driver has to
+register an interrupt service routine
+(ISR\index{ISR}\nomenclature{ISR}{Interrupt Service Routine}), that is
+executed each time, the hardware signals such an event. If the interrupt was
+thrown by the own device (multiple devices can share one hardware interrupt),
+the reason for the interrupt has to be determined by reading the device's
+interrupt register. For example, if the flag for received frames is set, frame
+data has to be copied from hardware to kernel memory and passed to the network
+stack.
+
+\paragraph{The \lstinline+net_device+ Structure}\index{net\_device} The driver
+registers a \lstinline+net_device+ structure for each device to communicate
+with the network stack and to create a ``network interface''. In case of an
+Ethernet driver, this interface appears as \textit{ethX}, where X is a number
+assigned by the kernel on registration. The \lstinline+net_device+ structure
+receives events (either from userspace or from the network stack) via several
+callbacks, which have to be set before registration. Not every callback is
+mandatory, but for reasonable operation the ones below are needed in any case:
 
 \newsavebox\boxopen
 \sbox\boxopen{\lstinline+open()+}
@@ -1027,17 +1050,15 @@
 The actual registration is done with the \lstinline+register_netdev()+ call,
 unregistering is done with \lstinline+unregister_netdev()+.
 
-\paragraph{The \lstinline+netif+ Interface}
-\index{netif}
-
-All other communication in the direction interface $\to$ network stack is done
-via the \lstinline+netif_*()+ calls. For example, on successful device opening,
-the network stack has to be notified, that it can now pass frames to the
+\paragraph{The \lstinline+netif+ Interface}\index{netif} All other
+communication in the direction interface $\to$ network stack is done via the
+\lstinline+netif_*()+ calls. For example, on successful device opening, the
+network stack has to be notified, that it can now pass frames to the
 interface. This is done by calling \lstinline+netif_start_queue()+. After this
 call, the \lstinline+hard_start_xmit()+ callback can be called by the network
-stack. Furthermore a network driver usually manages a frame transmission queue.
-If this gets filled up, the network stack has to be told to stop passing
-further frames for a while. This happens with a call to
+stack. Furthermore a network driver usually manages a frame transmission
+queue.  If this gets filled up, the network stack has to be told to stop
+passing further frames for a while. This happens with a call to
 \lstinline+netif_stop_queue()+. If some frames have been sent, and there is
 enough space again to queue new frames, this can be notified with
 \lstinline+netif_wake_queue()+. Another important call is
@@ -1049,48 +1070,42 @@
 network stack, that was just received by the device. Frame data has to be
 included in a so-called ``socket buffer'' for that (see below).
 
-\paragraph{Socket Buffers}
-\index{Socket buffer}
-
-Socket buffers are the basic data type for the whole network stack. They serve
-as containers for network data and are able to quickly add data headers and
-footers, or strip them off again. Therefore a socket buffer consists of an
-allocated buffer and several pointers that mark beginning of the buffer
-(\lstinline+head+), beginning of data (\lstinline+data+), end of data
-(\lstinline+tail+) and end of buffer (\lstinline+end+). In addition, a socket
-buffer holds network header information and (in case of received data) a
-pointer to the \lstinline+net_device+, it was received on. There exist
-functions that create a socket buffer (\lstinline+dev_alloc_skb()+), add data
-either from front (\lstinline+skb_push()+) or back (\lstinline+skb_put()+),
-remove data from front (\lstinline+skb_pull()+) or back
-(\lstinline+skb_trim()+), or delete the buffer (\lstinline+kfree_skb()+).  A
-socket buffer is passed from layer to layer, and is freed by the layer that
-uses it the last time. In case of sending, freeing has to be done by the
-network driver.
-
-%------------------------------------------------------------------------------
-
-\section{EtherCAT Device Drivers}
-\label{sec:drivers}
-
-There are a few requirements for Ethernet network devices to function as
-EtherCAT devices, when connected to an EtherCAT bus.
-
-\paragraph{Dedicated Interfaces}
-
-For performance and realtime purposes, the EtherCAT master needs direct and
-exclusive access to the Ethernet hardware. This implies that the network device
-must not be connected to the kernel's network stack as usual, because the
-kernel would try to use it as an ordinary Ethernet device.
-
-\paragraph{Interrupt-less Operation}
-\index{Interrupt}
-
-EtherCAT frames travel through the logical EtherCAT ring and are then sent back
-to the master. Communication is highly deterministic: A frame is sent and will
-be received again after a constant time, so there is no need to notify the
-driver about frame reception: The master can instead query the hardware for
-received frames, if it expects them to be already received.
+\paragraph{Socket Buffers}\index{Socket buffer} Socket buffers are the basic
+data type for the whole network stack. They serve as containers for network
+data and are able to quickly add data headers and footers, or strip them off
+again. Therefore a socket buffer consists of an allocated buffer and several
+pointers that mark beginning of the buffer (\lstinline+head+), beginning of
+data (\lstinline+data+), end of data (\lstinline+tail+) and end of buffer
+(\lstinline+end+). In addition, a socket buffer holds network header
+information and (in case of received data) a pointer to the
+\lstinline+net_device+, it was received on. There exist functions that create
+a socket buffer (\lstinline+dev_alloc_skb()+), add data either from front
+(\lstinline+skb_push()+) or back (\lstinline+skb_put()+), remove data from
+front (\lstinline+skb_pull()+) or back (\lstinline+skb_trim()+), or delete the
+buffer (\lstinline+kfree_skb()+).  A socket buffer is passed from layer to
+layer, and is freed by the layer that uses it the last time. In case of
+sending, freeing has to be done by the network driver.
+
+%------------------------------------------------------------------------------
+
+\section{Native EtherCAT Device Drivers}
+\label{sec:native-drivers}
+
+There are a few requirements, that applies to Ethernet hardware when used with
+a native Ethernet driver with EtherCAT functionality.
+
+\paragraph{Dedicated Hardware} For performance and realtime purposes, the
+EtherCAT master needs direct and exclusive access to the Ethernet hardware.
+This implies that the network device must not be connected to the kernel's
+network stack as usual, because the kernel would try to use it as an ordinary
+Ethernet device.
+
+\paragraph{Interrupt-less Operation}\index{Interrupt} EtherCAT frames travel
+through the logical EtherCAT ring and are then sent back to the master.
+Communication is highly deterministic: A frame is sent and will be received
+again after a constant time, so there is no need to notify the driver about
+frame reception: The master can instead query the hardware for received
+frames, if it expects them to be already received.
 
 Figure~\ref{fig:interrupt} shows two workflows for cyclic frame transmission
 and reception with and without interrupts.
@@ -1123,16 +1138,15 @@
 extension (like RTAI) is used, some additional effort would have to be made to
 prioritize interrupts.
 
-\paragraph{Ethernet and EtherCAT Devices}
-
-Another issue lies in the way Linux handles devices of the same type.  For
-example, a PCI\nomenclature{PCI}{Peripheral Component Interconnect, Computer
-Bus} driver scans the PCI bus for devices it can handle. Then it registers
-itself as the responsible driver for all of the devices found. The problem is,
-that an unmodified driver can not be told to ignore a device because it will
-be used for EtherCAT later. There must be a way to handle multiple devices of
-the same type, where one is reserved for EtherCAT, while the other is treated
-as an ordinary Ethernet device.
+\paragraph{Ethernet and EtherCAT Devices} Another issue lies in the way Linux
+handles devices of the same type.  For example, a
+PCI\nomenclature{PCI}{Peripheral Component Interconnect, Computer Bus} driver
+scans the PCI bus for devices it can handle. Then it registers itself as the
+responsible driver for all of the devices found. The problem is, that an
+unmodified driver can not be told to ignore a device because it will be used
+for EtherCAT later. There must be a way to handle multiple devices of the same
+type, where one is reserved for EtherCAT, while the other is treated as an
+ordinary Ethernet device.
 
 For all this reasons, the author decided that the only acceptable solution is
 to modify standard Ethernet drivers in a way that they keep their normal
@@ -1160,15 +1174,64 @@
 
 %------------------------------------------------------------------------------
 
-\section{Device Selection}
-\label{sec:deviceselection}
-
-After loading the master module, at least one EtherCAT-capable network driver
-module has to be loaded, that offers its devices to the master (see
-sec.~\ref{sec:ecdev}. The master module knows the devices to choose from the
-module parameters (see sec.~\ref{sec:mastermod}). If the init script is used
-to start the master, the drivers and devices to use can be specified in the
-sysconfig file (see sec.~\ref{sec:sysconfig}).
+\section{Generic EtherCAT Device Driver}
+\label{sec:generic-driver}
+
+Since there are approaches to enable the complete Linux kernel for realtime
+operation \cite{rt-preempt}, it is possible to operate without native
+implementations of EtherCAT-capable Ethernet device drivers and use the Linux
+network stack instead. Fig.~\ref{fig:arch} shows the ``Generic Ethernet Driver
+Module'', that connects to local Ethernet devices via the network stack. The
+kernel module is named \lstinline+ec_generic+ and can be loaded after the
+master module like a native EtherCAT-capable Ethernet driver.
+
+The generic device driver scans the network stack for interfaces, that have
+been registered by Ethernet device drivers. It offers all possible devices to
+the EtherCAT master. If the master accepts a device, the generic driver
+creates a packet socket (see \lstinline+man 7 packet+) with
+\lstinline+socket_type+ set to \lstinline+SOCK_RAW+, bound to that device. All
+functions of the device interface (see sec.~\ref{sec:ecdev}) will then operate
+on that socket.
+
+Below are the advantages of this solution:
+
+\begin{itemize}
+\item Any Ethernet hardware, that is covered by a Linux Ethernet driver can be
+used for EtherCAT.
+\item No modifications have to be made to the actual Ethernet drivers.
+\end{itemize}
+
+The generic approach has the following disadvantages:
+
+\begin{itemize}
+\item The performance is a little worse than the native approach, because the
+frame data have to traverse the lower layers of the network stack.
+\item It is not possible to use in-kernel realtime extensions like RTAI with
+the generic driver, because the network stack code uses dynamic memory
+allocations and other things, that could cause the system to freeze in
+realtime context.
+\end{itemize}
+
+%------------------------------------------------------------------------------
+
+\section{Providing Ethernet Devices}
+\label{sec:providing-devices}
+
+After loading the master module, additional module(s) have to be loaded to
+offer devices to the master(s) (see sec.~\ref{sec:ecdev}). The master module
+knows the devices to choose from the module parameters (see
+sec.~\ref{sec:mastermod}). If the init script is used to start the master, the
+drivers and devices to use can be specified in the sysconfig file (see
+sec.~\ref{sec:sysconfig}).
+
+Modules offering Ethernet devices can be
+
+\begin{itemize}
+\item native EtherCAT-capable network driver modules (see
+sec.~\ref{sec:native-drivers}) or
+\item the generic EtherCAT device driver module (see
+sec.~\ref{sec:generic-driver}).
+\end{itemize}
 
 %------------------------------------------------------------------------------
 
@@ -1196,14 +1259,15 @@
 
 %------------------------------------------------------------------------------
 
-\section{Patching Network Drivers}
+\section{Patching Native Network Drivers}
 \label{sec:patching}
 \index{Network drivers}
 
 This section will describe, how to make a standard Ethernet driver
-EtherCAT-capable. Unfortunately, there is no standard procedure to enable an
-Ethernet driver for use with the EtherCAT master, but there are a few common
-techniques.
+EtherCAT-capable, using the native approach (see
+sec.~\ref{sec:native-drivers}). Unfortunately, there is no standard procedure
+to enable an Ethernet driver for use with the EtherCAT master, but there are a
+few common techniques.
 
 \begin{enumerate}
 
@@ -2605,14 +2669,21 @@
 
 EtherCAT buses can always be monitored by inserting a switch between master
 and slaves. This allows to connect another PC with a network monitor like
-Wireshark~\cite{wireshark}, for example.
-
-For convenience, so-called ``debug interfaces'' are supported. Debug
-interfaces are virtual network interfaces allowing to capture EtherCAT traffic
-with a network monitor (like Wireshark or tcpdump) running on the master
-machine without using external hardware. To use this functionality, the master
-sources have to be configured with the \lstinline+--enable-debug-if+ switch
-(see sec.~\ref{sec:installation}).
+Wireshark~\cite{wireshark}, for example. It is also possible to listen to
+local network interfaces on the machine running the EtherCAT master directly.
+If the generic Ethernet driver (see sec.~\ref{sec:generic-driver}) is used,
+the network monitor can directly listen on the network interface connected to
+the EtherCAT bus.
+
+When using native Ethernet drivers (see sec.~\ref{sec:native-drivers}), there
+are no local network interfaces to listen to, because the Ethernet devices
+used for EtherCAT are not registered at the network stack. For that case,
+so-called ``debug interfaces'' are supported, which are virtual network
+interfaces allowing to capture EtherCAT traffic with a network monitor (like
+Wireshark or tcpdump) running on the master machine without using external
+hardware. To use this functionality, the master sources have to be configured
+with the \lstinline+--enable-debug-if+ switch (see
+sec.~\ref{sec:installation}).
 
 Every EtherCAT master registers a read-only network interface per attached
 physical Ethernet device. The network interfaces are named \textit{ecdbgmX}
@@ -2644,8 +2715,8 @@
 connected, the debug interface can produce thousands of frames per second.
 
 \paragraph{Attention} The socket buffers needed for the operation of debug
-interfaces have to be allocated dynamically. Some Linux realtime extensions do
-not allow this in realtime context!
+interfaces have to be allocated dynamically. Some Linux realtime extensions
+(like RTAI) do not allow this in realtime context!
 
 %------------------------------------------------------------------------------
 
@@ -2794,19 +2865,58 @@
 \label{sec:installation}
 \index{Master!Installation}
 
+\section{Getting the Software}
+\label{sec:getting}
+
+There are several ways to get the master software:
+
+\begin{enumerate}
+
+\item An official release (for example \masterversion), can be downloaded from
+the master's website\footnote{\url{http://etherlab.org/en/ethercat/index.php}}
+at~the EtherLab project~\cite{etherlab} as a tarball.
+
+\item The most recent development revision (and moreover any other revision)
+can be obtained via the Mercurial~\cite{mercurial} repository on the master's
+project page on
+SourceForge.net\footnote{\url{http://sourceforge.net/projects/etherlabmaster}}.
+The whole repository can be cloned with the command
+
+\begin{lstlisting}[breaklines=true]
+hg clone http://etherlabmaster.hg.sourceforge.net/hgweb/etherlabmaster/etherlabmaster `\textit{local-dir}`
+\end{lstlisting}
+
+\item Without a local Mercurial installation, tarballs of arbitrary revisions
+can be downloaded via the ``bz2'' links in the browsable repository
+pages\footnote{\url{http://etherlabmaster.hg.sourceforge.net/hgweb/etherlabmaster/etherlabmaster}}.
+
+\end{enumerate}
+
 \section{Building the Software}
 
-The current EtherCAT master code is available at~\cite{etherlab} or can be
-obtained from the EtherLab CD. The \textit{tar.bz2} file has to be unpacked
-with the commands below (or similar):
+After downloading a tarball or cloning the repository as described in
+sec.~\ref{sec:getting}, the sources have to be prepared and configured for the
+build process.
+
+When a tarball was downloaded, it has to be extracted with the following
+commands:
 
 \begin{lstlisting}[gobble=2]
   $ `\textbf{tar xjf ethercat-\masterversion.tar.bz2}`
   $ `\textbf{cd ethercat-\masterversion/}`
 \end{lstlisting}
 
-The tarball was created with GNU Autotools, so the build process
-follows the below commands:
+The software configuration is managed with Autoconf~\cite{autoconf} so the
+released versions contain a \lstinline+configure+ shell script, that has to be
+executed for configuration (see below).
+
+\paragraph{Bootstrap} When downloading or cloning directly from the
+repository, the \lstinline+configure+ script does not yet exist. It can be
+created via the \lstinline+bootstrap.sh+ script in the master sources. The
+autoconf and automake packages are required for this.
+
+\paragraph{Configuration and Build} The configuration and the build process
+follow the below commands:
 
 \begin{lstlisting}[gobble=2]
   $ `\textbf{./configure}`
@@ -2832,6 +2942,11 @@
 
 \hline
 
+\lstinline+--enable-tool+ & Build the command-line tool ``ethercat'' (see
+sec.~\ref{sec:tool}). & yes\\
+
+\lstinline+--enable-userlib+ & Build the userspace library. & yes\\
+
 \lstinline+--enable-eoe+ & Enable EoE support & yes\\
 
 \lstinline+--enable-cycles+ & Use CPU timestamp counter. Enable this on Intel
@@ -2855,6 +2970,13 @@
 
 \lstinline+--with-e1000-kernel+ & e1000 kernel & $\dagger$\\
 
+\lstinline+--enable-r8169+ & Enable r8169 driver & no\\
+
+\lstinline+--with-r8169-kernel+ & r8169 kernel & $\dagger$\\
+
+\lstinline+--enable-generic+ & Build the generic Ethernet driver (see
+sec.~\ref{sec:generic-driver}). & no\\
+
   \end{tabular}
   \vspace{2mm}
 
@@ -3049,11 +3171,19 @@
 2004.
 
 \bibitem{rtai} RTAI. The RealTime Application Interface for Linux from DIAPM.
-\url{http://www.rtai.org}, 2006.
+\url{https://www.rtai.org}, 2010.
+
+\bibitem{rt-preempt} RT PREEMPT HOWTO.
+\url{http://rt.wiki.kernel.org/index.php/RT_PREEMPT_HOWTO}, 2010.
 
 \bibitem{doxygen} Doxygen. Source code documentation generator tool.
 \url{http://www.stack.nl/~dimitri/doxygen}, 2008.
 
+\bibitem{mercurial} Mercurial SCM. \url{http://mercurial.selenic.com}, 2010.
+
+\bibitem{autoconf} Autoconf -- GNU Project -- Free Software Foundation (FSF).
+\url{http://www.gnu.org/software/autoconf}, 2010.
+
 \end{thebibliography}
 
 \printnomenclature
--- a/documentation/images/Makefile	Tue Jan 19 19:31:55 2010 +0100
+++ b/documentation/images/Makefile	Tue Jan 19 19:33:47 2010 +0100
@@ -6,7 +6,6 @@
 
 FIGS := \
 	app-config.fig \
-	architecture.fig \
 	attach.fig \
 	dc.fig \
 	fmmus.fig \
@@ -18,14 +17,22 @@
 	phases.fig \
 	statetrans.fig
 
-PDFS = $(FIGS:.fig=.pdf)
+FIGPDFS = $(FIGS:.fig=.pdf)
 
-all: $(PDFS)
+SVGS := \
+	architecture.svg
+
+SVGPDFS = $(SVGS:.svg=.pdf)
+
+all: $(FIGPDFS) $(SVGPDFS)
 
 %.pdf: %.fig
 	fig2dev -L pdf -z A4 -p xxx -c $< $@	
 
+%.pdf: %.svg
+	inkscape --export-pdf=$@ $<
+
 clean:
-	@rm -rv $(PDFS)
+	@rm -rv $(FIGPDFS) $(SVGPDFS)
 
 #-----------------------------------------------------------------------------
--- a/documentation/images/architecture.fig	Tue Jan 19 19:31:55 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,176 +0,0 @@
-#FIG 3.2
-Portrait
-Center
-Metric
-A4      
-100.00
-Single
--2
-1200 2
-5 1 0 1 0 7 50 -1 -1 0.000 0 0 0 0 7245.000 5985.000 6975 5985 7245 5715 7515 5985
-6 5085 7965 5850 8820
-2 3 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 8
-	 5175 7965 5760 7965 5760 8775 5175 8775 5175 8415 5085 8415
-	 5085 7965 5175 7965
-2 2 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 5
-	 5490 8190 5670 8190 5670 8370 5490 8370 5490 8190
-2 2 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 5
-	 5310 8505 5400 8505 5400 8595 5310 8595 5310 8505
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 5175 8055 5085 8055
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 5175 8145 5085 8145
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 5175 8190 5085 8190
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 5175 8280 5085 8280
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 5175 8235 5085 8235
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 5175 8100 5085 8100
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 5175 8010 5085 8010
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 5175 8325 5085 8325
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 5175 8370 5085 8370
-2 2 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 5
-	 5850 8775 5085 8775 5085 8815 5850 8815 5850 8775
--6
-6 6435 7965 7200 8820
-2 3 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 8
-	 6525 7965 7110 7965 7110 8775 6525 8775 6525 8415 6435 8415
-	 6435 7965 6525 7965
-2 2 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 5
-	 6840 8190 7020 8190 7020 8370 6840 8370 6840 8190
-2 2 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 5
-	 6660 8505 6750 8505 6750 8595 6660 8595 6660 8505
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 6525 8055 6435 8055
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 6525 8145 6435 8145
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 6525 8190 6435 8190
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 6525 8280 6435 8280
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 6525 8235 6435 8235
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 6525 8100 6435 8100
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 6525 8010 6435 8010
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 6525 8325 6435 8325
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 6525 8370 6435 8370
-2 2 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 5
-	 7200 8775 6435 8775 6435 8815 7200 8815 7200 8775
--6
-6 4905 5445 5985 6030
-5 1 0 1 0 7 50 -1 -1 0.000 0 0 0 0 5445.000 5985.000 4950 5985 5445 5490 5940 5985
-4 1 0 50 -1 16 10 0.0000 4 120 465 5445 5760 Device\001
-4 1 0 50 -1 16 10 0.0000 4 120 615 5445 5925 Interface\001
--6
-6 3870 4275 4500 5355
-5 1 0 1 0 7 50 -1 20 0.000 0 0 0 0 3958.125 4815.000 3915 4320 4455 4815 3915 5310
-4 1 0 49 -1 16 10 4.7124 4 150 765 4162 4822 Application\001
-4 1 0 49 -1 16 10 4.7124 4 120 615 3997 4822 Interface\001
--6
-6 5205 2648 6480 3293
-5 1 0 1 0 7 50 -1 -1 0.000 0 0 0 0 5842.000 2655.000 6472 2655 5842 3285 5212 2655
-4 1 0 50 -1 16 12 0.0000 4 135 600 5842 3105 Device\001
-4 1 0 50 -1 16 12 0.0000 4 135 825 5842 2880 Character\001
--6
-6 3870 945 4500 2025
-5 1 0 1 0 7 49 -1 -1 0.000 0 0 0 0 3958.125 1485.000 3915 990 4455 1485 3915 1980
-4 1 0 48 -1 16 10 4.7124 4 150 765 4162 1492 Application\001
-4 1 0 48 -1 16 10 4.7124 4 120 615 3997 1492 Interface\001
--6
-6 2160 855 3420 2115
-1 3 0 1 0 7 50 -1 20 0.000 1 0.0000 2790 1485 585 585 2790 1485 3375 1485
-4 1 0 49 -1 16 12 0.0000 4 180 945 2790 1665 Application\001
-4 1 0 49 -1 16 12 0.0000 4 180 885 2790 1440 Userspace\001
--6
-1 4 0 1 0 7 50 -1 -1 0.000 1 0.0000 2484 4871 459 459 2025 4860 2944 4882
-1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 5445 4815 810 495 4635 4320 6255 5310
-1 4 0 1 0 7 50 -1 -1 4.000 1 0.0000 7058 1658 495 495 7553 2153 6563 1163
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 5445 7965 5445 7425
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 6795 7965 6795 7425
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 5445 6885 5445 5985
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 5535 8820 5625 8820 5625 8910 5535 8910 5535 8820
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 6885 8820 6975 8820 6975 8910 6885 8910 6885 8820
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 7245 6885 7245 5985
-2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
-	 7605 7605 7605 6345 4635 6345 4635 7605 7605 7605
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 4905 6885 5985 6885 5985 7425 4905 7425 4905 6885
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 6255 6885 7335 6885 7335 7425 6255 7425 6255 6885
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 5445 5490 5445 5310
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 4635 4815 4455 4815
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3915 4815 3465 4815
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 7605 3645 6885 3645 6885 5985 7605 5985 7605 3645
-2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 1575 7785 7785 7785
-2 4 0 1 0 7 50 -1 -1 0.000 0 0 9 0 0 5
-	 1755 5985 1755 3645 3465 3645 3465 5985 1755 5985
-2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 7785 8280 7785 2205
-2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 1575 8280 1575 2205
-2 4 0 1 0 7 50 -1 -1 0.000 0 0 8 0 0 5
-	 6435 5985 6435 3645 3915 3645 3915 5985 6435 5985
-2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 7785 2655 1575 2655
-2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
-	 5850 3285 5850 3645
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3915 1485 3375 1485
-2 4 0 1 0 7 50 -1 20 0.000 0 0 7 0 0 5
-	 5040 2250 3915 2250 3915 720 5040 720 5040 2250
-3 2 0 1 0 7 50 -1 -1 0.000 0 0 0 3
-	 5580 8910 5355 9045 4770 9090
-	 0.000 -1.000 0.000
-3 2 0 1 0 7 50 -1 -1 0.000 0 0 0 3
-	 6931 8910 6390 9270 4770 9450
-	 0.000 -1.000 0.000
-3 2 0 1 0 7 50 -1 -1 0.000 0 0 0 3
-	 6570 1665 6120 1890 5985 2655
-	 0.000 -1.000 0.000
-3 2 0 1 0 7 50 -1 -1 0.000 0 0 0 3
-	 5040 1485 5580 1800 5715 2655
-	 0.000 -1.000 0.000
-4 1 0 50 -1 16 10 0.0000 4 150 750 5445 7200 net_device\001
-4 1 0 50 -1 16 10 0.0000 4 150 750 6795 7200 net_device\001
-4 2 0 50 -1 12 10 0.0000 4 105 810 5355 6210 ecdev_*()\001
-4 1 0 50 -1 16 12 0.0000 4 135 1545 6345 6570 EtherCAT Network\001
-4 1 0 50 -1 16 12 0.0000 4 135 1200 6345 6750 Driver Module\001
-4 0 0 50 -1 16 12 0.0000 4 135 2130 4005 3870 EtherCAT Master Module\001
-4 1 0 50 -1 16 12 1.5708 4 135 1200 7290 4815 Network Stack\001
-4 2 0 50 -1 16 12 0.0000 4 135 810 4725 9135 EtherCAT\001
-4 2 0 50 -1 16 12 0.0000 4 135 690 4725 9495 Ethernet\001
-4 2 0 50 -1 16 12 0.0000 4 135 315 4995 8100 NIC\001
-4 2 0 50 -1 16 12 0.0000 4 135 315 6345 8100 NIC\001
-4 0 0 50 -1 16 12 0.0000 4 135 810 1665 8010 Hardware\001
-4 2 0 50 -1 12 10 4.7124 4 105 720 3645 4725 ecrt_*()\001
-4 0 0 50 -1 16 12 0.0000 4 180 945 1845 3870 Application\001
-4 0 0 50 -1 16 12 0.0000 4 135 630 1845 4095 Module\001
-4 1 0 50 -1 16 12 0.0000 4 135 390 2475 4950 Task\001
-4 0 0 50 -1 16 12 0.0000 4 180 1050 1665 2880 Kernelspace\001
-4 0 0 50 -1 16 12 0.0000 4 180 885 1665 2565 Userspace\001
-4 1 0 50 -1 16 12 4.7124 4 135 870 4635 1530 libethercat\001
-4 2 0 50 -1 12 10 4.7124 4 105 720 3645 1395 ecrt_*()\001
-4 2 0 50 -1 12 10 0.0000 4 105 810 7155 6210 netif_*()\001
-4 1 0 50 -1 16 12 0.0000 4 135 735 5445 4905 Master 0\001
-4 1 0 50 -1 16 12 0.0000 4 135 360 7065 1845 Tool\001
-4 1 0 50 -1 16 12 0.0000 4 135 765 7065 1620 'ethercat'\001
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/documentation/images/architecture.svg	Tue Jan 19 19:33:47 2010 +0100
@@ -0,0 +1,1036 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5 -->
+<!-- CreationDate: Mon Jan  4 12:21:21 2010 -->
+<!-- Magnification: 1.050 -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="875.73413"
+   height="994.51697"
+   viewBox="1640 672 6544 9311"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="architecture.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0">
+  <metadata
+     id="metadata215">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs213">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 367.84955 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="644.98529 : 367.84955 : 1"
+       inkscape:persp3d-origin="322.49265 : 245.23303 : 1"
+       id="perspective161" />
+  </defs>
+  <sodipodi:namedview
+     inkscape:window-height="1000"
+     inkscape:window-width="1385"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     guidetolerance="4"
+     gridtolerance="4"
+     objecttolerance="4"
+     borderopacity="1.0"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     showgrid="false"
+     inkscape:zoom="0.89892561"
+     inkscape:cx="414.38143"
+     inkscape:cy="658.79847"
+     inkscape:window-x="135"
+     inkscape:window-y="70"
+     inkscape:current-layer="svg2"
+     inkscape:object-paths="true"
+     inkscape:object-nodes="true"
+     inkscape:document-units="mm"
+     units="mm"
+     showborder="true"
+     inkscape:window-maximized="0" />
+  <rect
+     id="rect116"
+     style="fill:#e7f5ff;fill-opacity:1;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+     rx="125"
+     height="2456"
+     width="2645"
+     y="3934.2466"
+     x="3519.4934"
+     ry="125" />
+  <rect
+     id="rect94"
+     style="fill:#fff1cb;fill-opacity:1;stroke:#000000;stroke-width:7.99999952;stroke-linecap:butt;stroke-linejoin:miter"
+     rx="110"
+     height="1322"
+     width="2844.3892"
+     y="6769.2471"
+     x="4150.7104"
+     ry="110" />
+  <path
+     style="fill:none;stroke:#2988e6;stroke-width:21.28297615;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     d="M 4860.2219,8470.2466 L 4860.2219,5376.4053 L 2290.3936,5376.4053"
+     id="polyline86"
+     sodipodi:nodetypes="csc" />
+  <g
+     id="g3632"
+     transform="translate(-855.77813,108.24668)">
+    <polygon
+       points="5433,8362 6047,8362 6047,9212 5433,9212 5433,8834 5338,8834 5338,8362 5433,8362 "
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polygon6" />
+    <rect
+       x="5763"
+       y="8598"
+       width="188"
+       height="188"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect8" />
+    <rect
+       x="5574"
+       y="8929"
+       width="94"
+       height="94"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect10" />
+    <polyline
+       points="5433,8456 5338,8456 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline12" />
+    <polyline
+       points="5433,8551 5338,8551 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline14" />
+    <polyline
+       points="5433,8598 5338,8598 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline16" />
+    <polyline
+       points="5433,8692 5338,8692 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline18" />
+    <polyline
+       points="5433,8645 5338,8645 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline20" />
+    <polyline
+       points="5433,8503 5338,8503 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline22" />
+    <polyline
+       points="5433,8409 5338,8409 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline24" />
+    <polyline
+       points="5433,8740 5338,8740 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline26" />
+    <polyline
+       points="5433,8787 5338,8787 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline28" />
+    <rect
+       x="5338"
+       y="9212"
+       width="803"
+       height="41"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect30" />
+    <rect
+       x="5811"
+       y="9259"
+       width="94"
+       height="94"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect88" />
+  </g>
+  <g
+     id="g3544"
+     transform="translate(-855.77863,108.24668)">
+    <polyline
+       points="6850,8456 6755,8456 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline38" />
+    <polyline
+       points="6850,8551 6755,8551 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline40" />
+    <polyline
+       points="6850,8598 6755,8598 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline42" />
+    <polyline
+       points="6850,8692 6755,8692 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline44" />
+    <polyline
+       points="6850,8503 6755,8503 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline48" />
+    <polyline
+       points="6850,8409 6755,8409 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline50" />
+    <polyline
+       points="6850,8740 6755,8740 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline52" />
+    <polyline
+       points="6850,8787 6755,8787 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline54" />
+    <polygon
+       points="6850,8362 7464,8362 7464,9212 6850,9212 6850,8834 6755,8834 6755,8362 6850,8362 "
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polygon32" />
+    <rect
+       x="7181"
+       y="8598"
+       width="188"
+       height="188"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect34" />
+    <rect
+       x="6992"
+       y="8929"
+       width="94"
+       height="94"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect36" />
+    <polyline
+       points="6850,8645 6755,8645 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline46" />
+    <rect
+       x="6755"
+       y="9212"
+       width="803"
+       height="41"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect56" />
+    <rect
+       x="7228"
+       y="9259"
+       width="94"
+       height="94"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect90" />
+  </g>
+  <path
+     style="stroke:#000000;stroke-width:7.99484348;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:47.96906081,47.96906081;opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+     d="M 1062.4922,8281.2467 L 8802.7378,8281.2467"
+     id="polyline108"
+     sodipodi:nodetypes="cc" />
+  <rect
+     id="rect110"
+     style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+     rx="141"
+     height="2456"
+     width="1795"
+     y="3934.2466"
+     x="1251.4921"
+     ry="141" />
+  <polyline
+     id="polyline112"
+     style="stroke:#000000;stroke-width:7.99484348;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:47.96906081,47.96906081;opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+     points="8173,8692 8173,2314 "
+     transform="translate(629.73724,108.24668)" />
+  <polyline
+     id="polyline114"
+     style="stroke:#000000;stroke-width:7.99484348;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:47.96906081,47.96906081;fill:none;stroke-miterlimit:4;stroke-dashoffset:0"
+     points="1653,8692 1653,2314 "
+     transform="translate(-590.50768,108.24668)" />
+  <path
+     style="stroke:#000000;stroke-width:7.99484348;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:47.96906081,47.96906081;opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+     d="M 8802.7378,2895.2467 L 1062.4922,2895.2467"
+     id="polyline118"
+     sodipodi:nodetypes="cc" />
+  <text
+     style="font-size:126px;font-style:normal;font-weight:normal;text-anchor:end;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Courier"
+     id="text138"
+     font-size="126"
+     font-weight="normal"
+     font-style="normal"
+     y="6547.6665"
+     x="4783.7314"
+     xml:space="preserve">ecdev_*()</text>
+  <text
+     style="font-size:126px;font-style:normal;font-weight:normal;text-align:start;line-height:100%;text-anchor:start;fill:#000000;stroke:none;font-family:Sans"
+     id="text144"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="4170.2471"
+     x="3613.4937"
+     xml:space="preserve"
+     sodipodi:linespacing="100%">EtherCAT Master Module</text>
+  <text
+     style="font-size:152px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:end;opacity:1;fill:#2988e6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.02500001in;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Bitstream Vera Sans"
+     id="text150"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="9648.541"
+     x="5212.2598"
+     xml:space="preserve">EtherCAT</text>
+  <text
+     style="font-size:152px;font-style:normal;font-weight:normal;text-anchor:end;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+     id="text152"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="9656.4453"
+     x="6582.5713"
+     xml:space="preserve">Ethernet</text>
+  <text
+     style="font-size:152px;font-style:normal;font-weight:normal;text-anchor:end;fill:#2988e6;fill-opacity:1;stroke:none;stroke-width:0.025in;stroke-opacity:1;font-family:Sans"
+     id="text154"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="8611.2471"
+     x="4388.2222"
+     xml:space="preserve">NIC</text>
+  <text
+     style="font-size:152px;font-style:normal;font-weight:normal;text-anchor:end;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+     id="text156"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="8611.2471"
+     x="5805.2222"
+     xml:space="preserve">NIC</text>
+  <text
+     style="font-size:152px;font-style:normal;font-weight:normal;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+     id="text158"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="8517.2471"
+     x="1157.4919"
+     xml:space="preserve">Hardware</text>
+  <g
+     style="stroke:none;stroke-width:0.025in"
+     id="g160"
+     transform="matrix(1.101966e-5,1,-1,1.101966e-5,3355.623,5236.4294)">
+    <text
+       style="font-size:126px;font-style:normal;font-weight:normal;text-anchor:end;fill:#000000;stroke:none;font-family:Courier"
+       id="text162"
+       font-size="126"
+       font-weight="normal"
+       font-style="normal"
+       y="0"
+       x="0"
+       xml:space="preserve">ecrt_*()</text>
+  </g>
+  <text
+     style="font-size:132.14363098px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+     id="text164"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="4170.2471"
+     x="1346.4922"
+     xml:space="preserve"
+     sodipodi:linespacing="100%"><tspan
+       sodipodi:role="line"
+       id="tspan3492"
+       x="1346.4922"
+       y="4170.2471"
+       style="font-size:132.14363098px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;stroke:none;stroke-width:2.25;font-family:Sans">Application Module</tspan></text>
+  <g
+     id="g3351"
+     transform="translate(-44.46203,331.40336)">
+    <circle
+       transform="translate(-546.04563,-79)"
+       cx="2607"
+       cy="5113"
+       r="481"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:8"
+       id="circle76"
+       sodipodi:cx="2607"
+       sodipodi:cy="5113"
+       sodipodi:rx="481"
+       sodipodi:ry="481"
+       d="m 3088,5113 c 0,265.649 -215.351,481 -481,481 -265.649,0 -481,-215.351 -481,-481 0,-265.649 215.351,-481 481,-481 265.649,0 481,215.351 481,481 z" />
+    <text
+       xml:space="preserve"
+       x="2059.2063"
+       y="5073.6719"
+       font-style="normal"
+       font-weight="normal"
+       font-size="152"
+       id="text168"
+       style="font-size:132.14363098px;font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;text-indent:0;text-align:center;text-decoration:none;line-height:100%;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.25;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans"
+       sodipodi:linespacing="100%">Task</text>
+  </g>
+  <text
+     style="font-size:152px;font-style:normal;font-weight:normal;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+     id="text170"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="3131.2466"
+     x="1157.4919"
+     xml:space="preserve">Kernelspace</text>
+  <text
+     style="font-size:152px;font-style:normal;font-weight:normal;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+     id="text172"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="2800.2466"
+     x="1157.4919"
+     xml:space="preserve">Userspace</text>
+  <g
+     style="stroke:none;stroke-width:0.025in"
+     id="g178"
+     transform="matrix(1.101966e-5,1,-1,1.101966e-5,3235.4925,1572.2467)">
+    <text
+       style="font-size:120.13056946px;font-style:normal;font-weight:normal;text-anchor:end;fill:#000000;stroke:none;font-family:Courier"
+       id="text180"
+       font-size="126"
+       font-weight="normal"
+       font-style="normal"
+       y="0"
+       x="0"
+       xml:space="preserve">ecrt_*()</text>
+  </g>
+  <text
+     style="font-size:126px;font-style:normal;font-weight:normal;text-anchor:end;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Courier"
+     id="text182"
+     font-size="126"
+     font-weight="normal"
+     font-style="normal"
+     y="6547.6665"
+     x="8061.1538"
+     xml:space="preserve">netif_*()</text>
+  <g
+     id="g3355"
+     transform="translate(-44.46203,187.24668)">
+    <path
+       style="text-align:center;text-anchor:middle;fill:#ffffff;stroke:#000000;stroke-width:8;stroke-linecap:butt"
+       d="M 3563.9543,4456 C 3758.9776,4441.1691 3945.8786,4536.8144 4047.9255,4703.6691 C 4149.9724,4870.5238 4149.9724,5080.4762 4047.9255,5247.3309 C 3945.8786,5414.1856 3758.9776,5509.8309 3563.9543,5495 L 3563.9543,4456 z"
+       id="path64" />
+    <text
+       transform="matrix(1.101966e-5,1,-1,1.101966e-5,0,0)"
+       id="text3482"
+       style="font-size:126px;font-style:normal;font-weight:normal;line-height:100%;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+       font-size="126"
+       font-weight="normal"
+       font-style="normal"
+       y="-3836.0801"
+       x="4979.6079"
+       xml:space="preserve"
+       sodipodi:linespacing="100%"><tspan
+         style="font-size:126px;font-style:normal;font-weight:normal;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+         y="-3836.0801"
+         x="4979.6079"
+         id="tspan3484"
+         sodipodi:role="line">Application</tspan><tspan
+         style="font-size:126px;font-style:normal;font-weight:normal;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+         y="-3710.0801"
+         x="4979.6079"
+         id="tspan3486"
+         sodipodi:role="line">Interface</tspan></text>
+  </g>
+  <rect
+     style="opacity:1;fill:#e2ffe8;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+     id="rect3560"
+     width="1238.0494"
+     height="2456.2253"
+     x="6368.5278"
+     y="3934.1538"
+     rx="110.00001"
+     ry="110.00001" />
+  <g
+     id="g3580"
+     transform="translate(548.92606,108.24163)">
+    <g
+       transform="matrix(-3.6732199e-6,-1,1,-3.6732199e-6,7653,5055)"
+       id="g3586"
+       style="stroke:#000000;stroke-width:0.02499999in" />
+  </g>
+  <text
+     xml:space="preserve"
+     style="font-size:126px;font-style:normal;font-weight:normal;text-align:start;line-height:100%;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+     x="6491.4546"
+     y="4117.1338"
+     id="text3606"
+     sodipodi:linespacing="100%"><tspan
+       sodipodi:role="line"
+       id="tspan3610"
+       x="6491.4546"
+       y="4117.1338"
+       style="font-size:132.14363098px;text-align:start;text-anchor:start;stroke:none;stroke-width:2.25000358">Generic</tspan><tspan
+       sodipodi:role="line"
+       id="tspan3612"
+       x="6491.4546"
+       y="4249.2773"
+       style="font-size:132.14363098px;text-align:start;text-anchor:start;stroke:none;stroke-width:2.25000358">Ethernet</tspan><tspan
+       sodipodi:role="line"
+       id="tspan3614"
+       x="6491.4546"
+       y="4381.4209"
+       style="font-size:132.14363098px;text-align:start;text-anchor:start;stroke:none;stroke-width:2.25000358">Driver Module</tspan></text>
+  <rect
+     id="rect3618"
+     style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+     rx="110.00002"
+     height="1322"
+     width="1438.59"
+     y="6769.2471"
+     x="7142.6431"
+     ry="110" />
+  <text
+     style="font-size:132.14363098px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+     id="text3620"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="7005.2471"
+     x="7291.0054"
+     xml:space="preserve"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan3652"
+       x="7291.0054"
+       y="7005.2471"
+       style="font-size:132.14363098px;stroke:none;stroke-width:2.25">Standard</tspan><tspan
+       sodipodi:role="line"
+       id="tspan3654"
+       x="7291.0054"
+       y="7170.4268"
+       style="font-size:132.14363098px;stroke:none;stroke-width:2.25">Ethernet Driver</tspan></text>
+  <g
+     id="g3662"
+     transform="translate(735.84514,108.24668)">
+    <polyline
+       points="6850,8456 6755,8456 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline3664" />
+    <polyline
+       points="6850,8551 6755,8551 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline3666" />
+    <polyline
+       points="6850,8598 6755,8598 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline3668" />
+    <polyline
+       points="6850,8692 6755,8692 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline3670" />
+    <polyline
+       points="6850,8503 6755,8503 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline3672" />
+    <polyline
+       points="6850,8409 6755,8409 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline3674" />
+    <polyline
+       points="6850,8740 6755,8740 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline3676" />
+    <polyline
+       points="6850,8787 6755,8787 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline3678" />
+    <polygon
+       points="6850,8362 7464,8362 7464,9212 6850,9212 6850,8834 6755,8834 6755,8362 6850,8362 "
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polygon3680" />
+    <rect
+       x="7181"
+       y="8598"
+       width="188"
+       height="188"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect3682" />
+    <rect
+       x="6992"
+       y="8929"
+       width="94"
+       height="94"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect3684" />
+    <polyline
+       points="6850,8645 6755,8645 "
+       style="stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="polyline3686" />
+    <rect
+       x="6755"
+       y="9212"
+       width="803"
+       height="41"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect3688" />
+    <rect
+       x="7228"
+       y="9259"
+       width="94"
+       height="94"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect3690" />
+  </g>
+  <text
+     style="font-size:152px;font-style:normal;font-weight:normal;text-anchor:end;fill:#d7842f;fill-opacity:1;stroke:none;stroke-width:0.025in;stroke-opacity:1;font-family:Sans"
+     id="text3694"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="8611.2471"
+     x="7396.8452"
+     xml:space="preserve">NIC</text>
+  <path
+     style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#d7842f;stroke-width:21.28297615;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+     d="M 7872.6931,8470.2466 L 7868.8456,7288.0988 L 8265.1137,7288.0988 L 8265.1137,5867.8297 L 6863.0311,5867.8297 L 6863.0311,6525.8099 L 5332.4291,6525.8099 L 5332.4291,5520.389 L 5332.4291,1670.4938 L 2799.8817,1670.4938"
+     id="path3698"
+     sodipodi:nodetypes="cccccccccc" />
+  <g
+     id="g3399"
+     transform="translate(-44.46203,187.24668)">
+    <circle
+       transform="translate(-523.27342,-76.596732)"
+       cx="2929"
+       cy="1559"
+       r="614"
+       style="fill:#ffffff;stroke:#000000;stroke-width:8"
+       id="circle72"
+       sodipodi:cx="2929"
+       sodipodi:cy="1559"
+       sodipodi:rx="614"
+       sodipodi:ry="614"
+       d="m 3543,1559 c 0,339.1028 -274.8972,614 -614,614 -339.1028,0 -614,-274.8972 -614,-614 0,-339.1028 274.8972,-614 614,-614 339.1028,0 614,274.8972 614,614 z" />
+    <text
+       sodipodi:linespacing="100%"
+       xml:space="preserve"
+       x="2409.6025"
+       y="1450.2573"
+       font-style="normal"
+       font-weight="normal"
+       font-size="152"
+       id="text202"
+       style="font-size:123.86800385px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:center;text-decoration:none;line-height:100%;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.02500001in;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"><tspan
+         y="1450.2573"
+         x="2409.6025"
+         id="tspan3488"
+         sodipodi:role="line">Userspace</tspan><tspan
+         y="1574.1254"
+         x="2409.6025"
+         id="tspan3490"
+         sodipodi:role="line">Application</tspan></text>
+  </g>
+  <g
+     id="g3389"
+     transform="translate(-44.46203,187.24668)">
+    <rect
+       ry="110"
+       x="3563.9546"
+       y="676"
+       width="1181"
+       height="1606"
+       rx="110"
+       style="fill:#feeaff;fill-opacity:1;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect124" />
+    <g
+       transform="matrix(1.101966e-5,1,-1,1.101966e-5,4319.9543,1527)"
+       id="g174"
+       style="stroke:#000000;stroke-width:0.025in">
+      <text
+         xml:space="preserve"
+         x="-52.580063"
+         y="-52.831627"
+         font-style="normal"
+         font-weight="normal"
+         font-size="152"
+         id="text176"
+         style="font-size:132.14363098px;font-style:normal;font-weight:normal;text-anchor:middle;fill:#000000;stroke:none;stroke-width:2.25;font-family:Sans">libethercat</text>
+    </g>
+    <g
+       id="g3383">
+      <path
+         id="path198"
+         d="M 3563.9543,960 C 3758.9776,945.1691 3945.8786,1040.8144 4047.9255,1207.6691 C 4149.9724,1374.5238 4149.9724,1584.4762 4047.9255,1751.3309 C 3945.8786,1918.1856 3758.9776,2013.8309 3563.9543,1999 L 3563.9543,960 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:7.99791002;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         xml:space="preserve"
+         x="1474.2281"
+         y="-3836.1189"
+         font-style="normal"
+         font-weight="normal"
+         font-size="126"
+         id="text206"
+         style="font-size:120.13056946px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+         transform="matrix(1.101966e-5,1,-1,1.101966e-5,0,0)"
+         sodipodi:linespacing="125%"><tspan
+           sodipodi:role="line"
+           id="tspan3478"
+           x="1474.2281"
+           y="-3836.1189"
+           style="font-size:120.13056946px;stroke:none;stroke-width:2.25">Application</tspan><tspan
+           sodipodi:role="line"
+           id="tspan3480"
+           x="1474.2281"
+           y="-3685.9556"
+           style="font-size:120.13056946px;stroke:none;stroke-width:2.25">Interface</tspan></text>
+    </g>
+  </g>
+  <path
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:8.00239849;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     d="M 6353.8719,1844.4653 C 6353.8719,1844.4653 6037.3171,1909.1337 5856.8104,2229.688 C 5670.9667,2559.7199 5707.6919,3934.2468 5707.6919,3934.2468"
+     id="path3375"
+     sodipodi:nodetypes="czc" />
+  <g
+     id="g3377"
+     transform="translate(-44.46203,187.24668)">
+    <circle
+       transform="translate(-546.04563,-79)"
+       cx="7409"
+       cy="1740"
+       r="519"
+       style="fill:#fffdbf;fill-opacity:1;stroke:#000000;stroke-width:7.99791002;stroke-miterlimit:4;stroke-dasharray:none"
+       id="circle80"
+       sodipodi:cx="7409"
+       sodipodi:cy="1740"
+       sodipodi:rx="519"
+       sodipodi:ry="519"
+       d="m 7928,1740 c 0,286.6358 -232.3642,519 -519,519 -286.6358,0 -519,-232.3642 -519,-519 0,-286.6358 232.3642,-519 519,-519 286.6358,0 519,232.3642 519,519 z" />
+    <text
+       sodipodi:linespacing="125%"
+       xml:space="preserve"
+       x="6863.0659"
+       y="1620.1797"
+       font-style="normal"
+       font-weight="normal"
+       font-size="152"
+       id="text188"
+       style="font-size:152px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"><tspan
+         style="stroke:none;stroke-width:2.25"
+         y="1620.1797"
+         x="6863.0659"
+         id="tspan3471"
+         sodipodi:role="line">'ethercat'</tspan><tspan
+         style="stroke:none;stroke-width:2.25"
+         y="1810.1797"
+         x="6863.0659"
+         id="tspan3473"
+         sodipodi:role="line">Tool</tspan></text>
+  </g>
+  <g
+     id="g3369"
+     transform="translate(-44.46203,187.24668)">
+    <path
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:8;stroke-linecap:butt"
+       d="M 6247.9543,2708 C 6247.9543,3073.3364 5951.7907,3369.5 5586.4543,3369.5 C 5221.1179,3369.5 4924.9543,3073.3364 4924.9543,2708"
+       id="path66" />
+    <text
+       sodipodi:linespacing="125%"
+       xml:space="preserve"
+       x="5582.8276"
+       y="3003.1301"
+       font-style="normal"
+       font-weight="normal"
+       font-size="152"
+       id="text70"
+       style="font-size:132.6353302px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"><tspan
+         style="stroke:none;stroke-width:2.25"
+         y="3003.1301"
+         x="5582.8276"
+         id="tspan3467"
+         sodipodi:role="line">Character</tspan><tspan
+         style="stroke:none;stroke-width:2.25"
+         y="3168.9243"
+         x="5582.8276"
+         id="tspan3469"
+         sodipodi:role="line">Device</tspan></text>
+  </g>
+  <g
+     id="g3345"
+     transform="translate(-44.46203,187.24668)">
+    <path
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:7.99484348;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 4649.9543,6204 C 4649.9543,5916.8119 4882.7662,5684 5169.9543,5684 C 5457.1424,5684 5689.9543,5916.8119 5689.9543,6204 L 4649.9543,6204 z"
+       id="path58" />
+    <text
+       sodipodi:linespacing="125%"
+       xml:space="preserve"
+       x="5169.9546"
+       y="5968"
+       font-style="normal"
+       font-weight="normal"
+       font-size="126"
+       id="text60"
+       style="font-size:126px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"><tspan
+         id="tspan3341"
+         sodipodi:role="line"
+         x="5169.9546"
+         y="5968">Device</tspan><tspan
+         id="tspan3343"
+         sodipodi:role="line"
+         x="5169.9546"
+         y="6125.5">Interface</tspan></text>
+  </g>
+  <g
+     id="g3516"
+     transform="translate(603.21026,108.24163)">
+    <path
+       style="fill:none;stroke:#000000;stroke-width:7.99999666;stroke-linecap:butt"
+       d="M 7322,6283 C 7322,6126.4273 7448.9273,5999.5 7605.5,5999.5 C 7762.0727,5999.5 7889,6126.4273 7889,6283"
+       id="path74" />
+    <rect
+       x="7228"
+       y="3826"
+       width="755"
+       height="2456"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:7.99999666;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect106"
+       ry="109.99843"
+       rx="109.99843" />
+    <g
+       transform="matrix(-3.6732199e-6,-1,1,-3.6732199e-6,7653,5055)"
+       id="g146"
+       style="stroke:#000000;stroke-width:0.02499999in">
+      <text
+         xml:space="preserve"
+         x="0"
+         y="0"
+         font-style="normal"
+         font-weight="normal"
+         font-size="152"
+         id="text148"
+         style="font-size:152px;font-style:normal;font-weight:normal;text-anchor:middle;fill:#000000;stroke:none;stroke-width:2.24999905;font-family:Sans">Network Stack</text>
+    </g>
+  </g>
+  <g
+     id="g3656"
+     transform="translate(735.84554,108.24668)">
+    <rect
+       x="6736.9302"
+       y="7313.9893"
+       width="791.13934"
+       height="394.02103"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
+       id="rect3658"
+       ry="197.01051"
+       rx="197.61028" />
+    <text
+       xml:space="preserve"
+       x="7124.9805"
+       y="7542.9409"
+       font-style="normal"
+       font-weight="normal"
+       font-size="126"
+       id="text3660"
+       style="font-size:126px;font-style:normal;font-weight:normal;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans">net_device</text>
+  </g>
+  <g
+     id="g3522"
+     transform="translate(-855.77813,108.24668)"
+     style="stroke:#000000;stroke-opacity:1">
+    <rect
+       x="5314.6245"
+       y="7311.3203"
+       width="801.75134"
+       height="399.35959"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       id="rect96"
+       ry="199.67979"
+       rx="200.26093" />
+    <text
+       xml:space="preserve"
+       x="5707.9805"
+       y="7542.9409"
+       font-style="normal"
+       font-weight="normal"
+       font-size="126"
+       id="text134"
+       style="font-size:126px;font-style:normal;font-weight:normal;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.02500000000000000in;font-family:Sans;stroke-opacity:1">net_device</text>
+  </g>
+  <path
+     style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+     d="M 6271.9418,8470.2466 L 6271.9418,6649.2935 L 8116.176,6649.2936 L 8116.1764,6390.2468"
+     id="path3764"
+     sodipodi:nodetypes="cccc" />
+  <rect
+     style="opacity:1;fill:#fff1cb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.1872962;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+     id="rect3335"
+     width="2522.5874"
+     height="192.61136"
+     x="4222.7207"
+     y="6871.001" />
+  <text
+     style="font-size:132.14363098px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+     id="text140"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="7005.2471"
+     x="4279.7266"
+     xml:space="preserve"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan3463"
+       x="4279.7266"
+       y="7005.2471"
+       style="font-size:132.14363098px;stroke:none;stroke-width:2.25">Native EtherCAT-capable Ethernet Driver</tspan></text>
+  <g
+     id="g3526"
+     transform="translate(-855.77823,108.24668)">
+    <rect
+       x="6733.9658"
+       y="7312.4976"
+       width="797.06891"
+       height="397.00394"
+       style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect98"
+       ry="198.50197"
+       rx="199.09135" />
+    <text
+       xml:space="preserve"
+       x="7124.9805"
+       y="7542.9409"
+       font-style="normal"
+       font-weight="normal"
+       font-size="126"
+       id="text136"
+       style="font-size:126px;font-style:normal;font-weight:normal;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans">net_device</text>
+  </g>
+  <text
+     style="font-size:152px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:end;opacity:1;fill:#d7842f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.02500001in;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Bitstream Vera Sans"
+     id="text3291"
+     font-size="152"
+     font-weight="normal"
+     font-style="normal"
+     y="9648.541"
+     x="8220.8818"
+     xml:space="preserve">EtherCAT</text>
+  <g
+     id="g3315"
+     transform="translate(-164.59259,187.24668)">
+    <rect
+       ry="306.34152"
+       y="5365.6782"
+       x="6626.0581"
+       height="612.68304"
+       width="843.54913"
+       id="rect3301"
+       style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:8.00239849;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       rx="306.34152" />
+    <text
+       id="text3303"
+       y="5564.6763"
+       x="7042.9937"
+       style="font-size:120.13056946px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       xml:space="preserve"><tspan
+         style="font-size:120.13056946px;text-align:center;text-anchor:middle"
+         y="5564.6763"
+         x="7042.9937"
+         id="tspan3305"
+         sodipodi:role="line">Generic</tspan><tspan
+         id="tspan3309"
+         style="font-size:120.13056946px;text-align:center;text-anchor:middle"
+         y="5714.8394"
+         x="7042.9937"
+         sodipodi:role="line">Ethernet</tspan><tspan
+         id="tspan3307"
+         style="font-size:120.13056946px;text-align:center;text-anchor:middle"
+         y="5865.0029"
+         x="7042.9937"
+         sodipodi:role="line">Device</tspan></text>
+  </g>
+  <text
+     xml:space="preserve"
+     style="font-size:96.10446167px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+     x="-5836.0796"
+     y="7408.0576"
+     id="text3311"
+     transform="matrix(0,-1,1,0,0,0)"><tspan
+       sodipodi:role="line"
+       id="tspan3313"
+       x="-5836.0796"
+       y="7408.0576"
+       style="font-size:96.10446167px">Packet Socket</tspan></text>
+  <path
+     style="fill:#d7842f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.25;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+     d="M 7293.8713,5777.4673 C 7246.566,5782.1256 7209.78,5820.8944 7209.7799,5867.9407 C 7209.7799,5913.3576 7244.0471,5950.9172 7288.991,5957.6632 C 7299.3854,5926.8045 7305.1335,5893.7579 7305.1335,5859.3063 C 7305.1335,5830.9654 7301.0093,5803.4808 7293.8713,5777.4673 z"
+     id="path3300" />
+  <g
+     id="g3337">
+    <rect
+       ry="141.73228"
+       rx="141.73228"
+       y="5140.0127"
+       x="4332.8213"
+       height="489.50626"
+       width="833.20209"
+       id="rect3328"
+       style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:7.99484348;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+    <text
+       sodipodi:linespacing="100%"
+       xml:space="preserve"
+       x="4747.3921"
+       y="5428.1396"
+       font-style="normal"
+       font-weight="normal"
+       font-size="152"
+       id="text184"
+       style="font-size:126px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:100%;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.02500001in;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Bitstream Vera Sans">Master 0</text>
+  </g>
+  <g
+     id="g3332">
+    <rect
+       ry="141.73228"
+       rx="141.73228"
+       y="4578.2729"
+       x="4894.561"
+       height="489.50626"
+       width="833.20209"
+       id="rect3330"
+       style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:7.99484348;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+    <text
+       xml:space="preserve"
+       x="5318.4526"
+       y="4865.9692"
+       font-style="normal"
+       font-weight="normal"
+       font-size="152"
+       id="text3365"
+       style="font-size:126px;font-style:normal;font-weight:normal;line-height:100%;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.025in;font-family:Sans"
+       sodipodi:linespacing="100%"><tspan
+         sodipodi:role="line"
+         id="tspan3367"
+         x="5318.4526"
+         y="4865.9692">Master 1</tspan></text>
+  </g>
+</svg>
--- a/examples/Makefile.am	Tue Jan 19 19:31:55 2010 +0100
+++ b/examples/Makefile.am	Tue Jan 19 19:33:47 2010 +0100
@@ -27,12 +27,19 @@
 #
 #------------------------------------------------------------------------------
 
+SUBDIRS =
+
 if ENABLE_USERLIB
-SUBDIRS = \
+SUBDIRS += \
 	dc_user \
 	user
 endif
 
+if ENABLE_TTY
+SUBDIRS += \
+	tty
+endif
+
 DIST_SUBDIRS = \
 	dc_rtai \
 	dc_user \
--- a/examples/tty/Kbuild.in	Tue Jan 19 19:31:55 2010 +0100
+++ b/examples/tty/Kbuild.in	Tue Jan 19 19:33:47 2010 +0100
@@ -33,7 +33,11 @@
 
 obj-m := ec_tty_example.o
 
-ec_tty_example-objs := tty.o
+ec_tty_example-objs := \
+	serial.o \
+	tty.o
+
+CFLAGS_tty.o := -I$(src)
 
 KBUILD_EXTRA_SYMBOLS := \
 	@abs_top_builddir@/Module.symvers \
--- a/examples/tty/Makefile.am	Tue Jan 19 19:31:55 2010 +0100
+++ b/examples/tty/Makefile.am	Tue Jan 19 19:33:47 2010 +0100
@@ -31,9 +31,12 @@
 #
 #------------------------------------------------------------------------------
 
+noinst_HEADERS = \
+	serial.h \
+	tty.c
+
 EXTRA_DIST = \
-	Kbuild.in \
-	tty.c
+	Kbuild.in
 
 BUILT_SOURCES = \
 	Kbuild
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/tty/serial.c	Tue Jan 19 19:33:47 2010 +0100
@@ -0,0 +1,455 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2008  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+ *  Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include "../../include/ecrt.h" // EtherCAT realtime interface
+#include "../../include/ectty.h" // EtherCAT TTY interface
+
+/*****************************************************************************/
+
+// Optional features
+#define PFX "ec_tty_example: "
+
+/*****************************************************************************/
+
+#define VendorIdBeckhoff 0x00000002
+#define ProductCodeBeckhoffEL6002 0x17723052
+#define Beckhoff_EL6002 VendorIdBeckhoff, ProductCodeBeckhoffEL6002
+
+typedef enum {
+    SER_REQUEST_INIT,
+    SER_WAIT_FOR_INIT_RESPONSE,
+    SER_READY
+} serial_state_t;
+
+typedef struct {
+    struct list_head list;
+
+    ec_tty_t *tty;
+    ec_slave_config_t *sc;
+
+    size_t max_tx_data_size;
+    size_t max_rx_data_size;
+
+    u8 *tx_data;
+    u8 tx_data_size;
+
+    serial_state_t state;
+
+    u8 tx_request_toggle;
+    u8 tx_accepted_toggle;
+
+    u8 rx_request_toggle;
+    u8 rx_accepted_toggle;
+
+    u16 control;
+
+    u32 off_ctrl;
+    u32 off_tx;
+    u32 off_status;
+    u32 off_rx;
+} el6002_t;
+
+LIST_HEAD(handlers);
+        
+/*****************************************************************************/
+
+/* Beckhoff EL6002
+ * Vendor ID:       0x00000002
+ * Product code:    0x17723052
+ * Revision number: 0x00100000
+ */
+
+ec_pdo_entry_info_t el6002_pdo_entries[] = {
+   {0x7001, 0x01, 16}, /* Ctrl */
+   {0x7000, 0x11, 8}, /* Data Out 0 */
+   {0x7000, 0x12, 8}, /* Data Out 1 */
+   {0x7000, 0x13, 8}, /* Data Out 2 */
+   {0x7000, 0x14, 8}, /* Data Out 3 */
+   {0x7000, 0x15, 8}, /* Data Out 4 */
+   {0x7000, 0x16, 8}, /* Data Out 5 */
+   {0x7000, 0x17, 8}, /* Data Out 6 */
+   {0x7000, 0x18, 8}, /* Data Out 7 */
+   {0x7000, 0x19, 8}, /* Data Out 8 */
+   {0x7000, 0x1a, 8}, /* Data Out 9 */
+   {0x7000, 0x1b, 8}, /* Data Out 10 */
+   {0x7000, 0x1c, 8}, /* Data Out 11 */
+   {0x7000, 0x1d, 8}, /* Data Out 12 */
+   {0x7000, 0x1e, 8}, /* Data Out 13 */
+   {0x7000, 0x1f, 8}, /* Data Out 14 */
+   {0x7000, 0x20, 8}, /* Data Out 15 */
+   {0x7000, 0x21, 8}, /* Data Out 16 */
+   {0x7000, 0x22, 8}, /* Data Out 17 */
+   {0x7000, 0x23, 8}, /* Data Out 18 */
+   {0x7000, 0x24, 8}, /* Data Out 19 */
+   {0x7000, 0x25, 8}, /* Data Out 20 */
+   {0x7000, 0x26, 8}, /* Data Out 21 */
+   {0x7011, 0x01, 16}, /* Ctrl */
+   {0x7010, 0x11, 8}, /* Data Out 0 */
+   {0x7010, 0x12, 8}, /* Data Out 1 */
+   {0x7010, 0x13, 8}, /* Data Out 2 */
+   {0x7010, 0x14, 8}, /* Data Out 3 */
+   {0x7010, 0x15, 8}, /* Data Out 4 */
+   {0x7010, 0x16, 8}, /* Data Out 5 */
+   {0x7010, 0x17, 8}, /* Data Out 6 */
+   {0x7010, 0x18, 8}, /* Data Out 7 */
+   {0x7010, 0x19, 8}, /* Data Out 8 */
+   {0x7010, 0x1a, 8}, /* Data Out 9 */
+   {0x7010, 0x1b, 8}, /* Data Out 10 */
+   {0x7010, 0x1c, 8}, /* Data Out 11 */
+   {0x7010, 0x1d, 8}, /* Data Out 12 */
+   {0x7010, 0x1e, 8}, /* Data Out 13 */
+   {0x7010, 0x1f, 8}, /* Data Out 14 */
+   {0x7010, 0x20, 8}, /* Data Out 15 */
+   {0x7010, 0x21, 8}, /* Data Out 16 */
+   {0x7010, 0x22, 8}, /* Data Out 17 */
+   {0x7010, 0x23, 8}, /* Data Out 18 */
+   {0x7010, 0x24, 8}, /* Data Out 19 */
+   {0x7010, 0x25, 8}, /* Data Out 20 */
+   {0x7010, 0x26, 8}, /* Data Out 21 */
+   {0x6001, 0x01, 16}, /* Status */
+   {0x6000, 0x11, 8}, /* Data In 0 */
+   {0x6000, 0x12, 8}, /* Data In 1 */
+   {0x6000, 0x13, 8}, /* Data In 2 */
+   {0x6000, 0x14, 8}, /* Data In 3 */
+   {0x6000, 0x15, 8}, /* Data In 4 */
+   {0x6000, 0x16, 8}, /* Data In 5 */
+   {0x6000, 0x17, 8}, /* Data In 6 */
+   {0x6000, 0x18, 8}, /* Data In 7 */
+   {0x6000, 0x19, 8}, /* Data In 8 */
+   {0x6000, 0x1a, 8}, /* Data In 9 */
+   {0x6000, 0x1b, 8}, /* Data In 10 */
+   {0x6000, 0x1c, 8}, /* Data In 11 */
+   {0x6000, 0x1d, 8}, /* Data In 12 */
+   {0x6000, 0x1e, 8}, /* Data In 13 */
+   {0x6000, 0x1f, 8}, /* Data In 14 */
+   {0x6000, 0x20, 8}, /* Data In 15 */
+   {0x6000, 0x21, 8}, /* Data In 16 */
+   {0x6000, 0x22, 8}, /* Data In 17 */
+   {0x6000, 0x23, 8}, /* Data In 18 */
+   {0x6000, 0x24, 8}, /* Data In 19 */
+   {0x6000, 0x25, 8}, /* Data In 20 */
+   {0x6000, 0x26, 8}, /* Data In 21 */
+   {0x6011, 0x01, 16}, /* Status */
+   {0x6010, 0x11, 8}, /* Data In 0 */
+   {0x6010, 0x12, 8}, /* Data In 1 */
+   {0x6010, 0x13, 8}, /* Data In 2 */
+   {0x6010, 0x14, 8}, /* Data In 3 */
+   {0x6010, 0x15, 8}, /* Data In 4 */
+   {0x6010, 0x16, 8}, /* Data In 5 */
+   {0x6010, 0x17, 8}, /* Data In 6 */
+   {0x6010, 0x18, 8}, /* Data In 7 */
+   {0x6010, 0x19, 8}, /* Data In 8 */
+   {0x6010, 0x1a, 8}, /* Data In 9 */
+   {0x6010, 0x1b, 8}, /* Data In 10 */
+   {0x6010, 0x1c, 8}, /* Data In 11 */
+   {0x6010, 0x1d, 8}, /* Data In 12 */
+   {0x6010, 0x1e, 8}, /* Data In 13 */
+   {0x6010, 0x1f, 8}, /* Data In 14 */
+   {0x6010, 0x20, 8}, /* Data In 15 */
+   {0x6010, 0x21, 8}, /* Data In 16 */
+   {0x6010, 0x22, 8}, /* Data In 17 */
+   {0x6010, 0x23, 8}, /* Data In 18 */
+   {0x6010, 0x24, 8}, /* Data In 19 */
+   {0x6010, 0x25, 8}, /* Data In 20 */
+   {0x6010, 0x26, 8}, /* Data In 21 */
+};
+
+ec_pdo_info_t el6002_pdos[] = {
+   {0x1604, 23, el6002_pdo_entries + 0}, /* COM RxPDO-Map Outputs Ch.1 */
+   {0x1605, 23, el6002_pdo_entries + 23}, /* COM RxPDO-Map Outputs Ch.2 */
+   {0x1a04, 23, el6002_pdo_entries + 46}, /* COM TxPDO-Map Inputs Ch.1 */
+   {0x1a05, 23, el6002_pdo_entries + 69}, /* COM TxPDO-Map Inputs Ch.2 */
+};
+
+ec_sync_info_t el6002_syncs[] = {
+   {0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
+   {1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
+   {2, EC_DIR_OUTPUT, 2, el6002_pdos + 0, EC_WD_DISABLE},
+   {3, EC_DIR_INPUT, 2, el6002_pdos + 2, EC_WD_DISABLE},
+   {0xff}
+};
+
+/****************************************************************************/
+
+int el6002_init(el6002_t *ser, ec_master_t *master, u16 position,
+        ec_domain_t *domain)
+{
+    int ret = 0;
+
+    ser->tty = ectty_create();
+    if (IS_ERR(ser->tty)) {
+        printk(KERN_ERR PFX "Failed to create tty.\n");
+        ret = PTR_ERR(ser->tty);
+        goto out_return;
+    }
+
+    ser->sc = NULL;
+    ser->max_tx_data_size = 22;
+    ser->max_rx_data_size = 22;
+    ser->tx_data = NULL;
+    ser->tx_data_size = 0;
+    ser->state = SER_REQUEST_INIT;
+    ser->tx_request_toggle = 0;
+    ser->rx_accepted_toggle = 0;
+    ser->control = 0x0000;
+    ser->off_ctrl = 0;
+    ser->off_tx = 0;
+    ser->off_status = 0;
+    ser->off_rx = 0;
+
+    if (!(ser->sc = ecrt_master_slave_config(
+                    master, 0, position, Beckhoff_EL6002))) {
+        printk(KERN_ERR PFX "Failed to create slave configuration.\n");
+        ret = -EBUSY;
+        goto out_free_tty;
+    }
+
+    if (ecrt_slave_config_pdos(ser->sc, EC_END, el6002_syncs)) {
+        printk(KERN_ERR PFX "Failed to configure PDOs.\n");
+        ret = -ENOMEM;
+        goto out_free_tty;
+    }
+    
+    ret = ecrt_slave_config_reg_pdo_entry(
+            ser->sc, 0x7001, 0x01, domain, NULL);
+    if (ret < 0) {
+        printk(KERN_ERR PFX "Failed to register PDO entry.\n");
+        goto out_free_tty;
+    }
+    ser->off_ctrl = ret;
+
+    ret = ecrt_slave_config_reg_pdo_entry(
+            ser->sc, 0x7000, 0x11, domain, NULL);
+    if (ret < 0) {
+        printk(KERN_ERR PFX "Failed to register PDO entry.\n");
+        goto out_free_tty;
+    }
+    ser->off_tx = ret;
+
+    ret = ecrt_slave_config_reg_pdo_entry(
+            ser->sc, 0x6001, 0x01, domain, NULL);
+    if (ret < 0) {
+        printk(KERN_ERR PFX "Failed to register PDO entry.\n");
+        goto out_free_tty;
+    }
+    ser->off_status = ret;
+
+    ret = ecrt_slave_config_reg_pdo_entry(
+            ser->sc, 0x6000, 0x11, domain, NULL);
+    if (ret < 0) {
+        printk(KERN_ERR PFX "Failed to register PDO entry.\n");
+        goto out_free_tty;
+    }
+    ser->off_rx = ret;
+
+    if (ser->max_tx_data_size > 0) {
+        ser->tx_data = kmalloc(ser->max_tx_data_size, GFP_KERNEL);
+        if (ser->tx_data == NULL) {
+            ret = -ENOMEM;
+            goto out_free_tty;
+        }
+    }
+
+    return 0;
+
+out_free_tty:
+    ectty_free(ser->tty);
+out_return:
+    return ret;
+}
+
+/****************************************************************************/
+
+void el6002_clear(el6002_t *ser)
+{
+    ectty_free(ser->tty);
+    if (ser->tx_data) {
+        kfree(ser->tx_data);
+    }
+}
+
+/****************************************************************************/
+
+void el6002_run(el6002_t *ser, u8 *pd)
+{
+    u16 status = EC_READ_U16(pd + ser->off_status);
+    u8 *rx_data = pd + ser->off_rx;
+    uint8_t tx_accepted_toggle, rx_request_toggle;
+
+    switch (ser->state) {
+        case SER_READY:
+
+            /* Send data */
+            
+            tx_accepted_toggle = status & 0x0001;
+            if (tx_accepted_toggle != ser->tx_accepted_toggle) { // ready
+                ser->tx_data_size =
+                    ectty_tx_data(ser->tty, ser->tx_data, ser->max_tx_data_size);
+                if (ser->tx_data_size) {
+                    printk(KERN_INFO PFX "Sending %u bytes.\n", ser->tx_data_size);
+                    ser->tx_request_toggle = !ser->tx_request_toggle;
+                    ser->tx_accepted_toggle = tx_accepted_toggle;
+                }
+            }
+
+            /* Receive data */
+
+            rx_request_toggle = status & 0x0002;
+            if (rx_request_toggle != ser->rx_request_toggle) {
+                uint8_t rx_data_size = status >> 8;
+                ser->rx_request_toggle = rx_request_toggle;
+                printk(KERN_INFO PFX "Received %u bytes.\n", rx_data_size);
+                ectty_rx_data(ser->tty, rx_data, rx_data_size);
+                ser->rx_accepted_toggle = !ser->rx_accepted_toggle;
+            }
+
+            ser->control =
+                ser->tx_request_toggle |
+                ser->rx_accepted_toggle << 1 |
+                ser->tx_data_size << 8;
+            break;
+
+        case SER_REQUEST_INIT:
+            if (status & (1 << 2)) {
+                ser->control = 0x0000;
+                ser->state = SER_WAIT_FOR_INIT_RESPONSE;
+            } else {
+                ser->control = 1 << 2; // CW.2, request initialization
+            }
+            break;
+
+        case SER_WAIT_FOR_INIT_RESPONSE:
+            if (!(status & (1 << 2))) {
+                printk(KERN_INFO PFX "Init successful.\n");
+                ser->tx_accepted_toggle = 1;
+                ser->control = 0x0000;
+                ser->state = SER_READY;
+            }
+            break;
+    }
+
+    EC_WRITE_U16(pd + ser->off_ctrl, ser->control);
+    memcpy(pd + ser->off_tx, ser->tx_data, ser->tx_data_size);
+}
+
+/*****************************************************************************/
+
+void run_serial_devices(u8 *pd)
+{
+    el6002_t *ser;
+
+    list_for_each_entry(ser, &handlers, list) {
+        el6002_run(ser, pd);
+    }
+}
+
+/*****************************************************************************/
+
+int create_serial_devices(ec_master_t *master, ec_domain_t *domain)
+{
+    int i, ret;
+    ec_master_info_t master_info;
+    ec_slave_info_t slave_info;
+    el6002_t *ser, *next;
+
+    printk(KERN_INFO PFX "Registering serial devices...\n");
+
+    ret = ecrt_master(master, &master_info);
+    if (ret) {
+        printk(KERN_ERR PFX "Failed to obtain master information.\n");
+        goto out_return;
+    }
+
+    for (i = 0; i < master_info.slave_count; i++) {
+        ret = ecrt_master_get_slave(master, i, &slave_info);
+        if (ret) {
+            printk(KERN_ERR PFX "Failed to obtain slave information.\n");
+            goto out_free_handlers;
+        }
+
+        if (slave_info.vendor_id != VendorIdBeckhoff
+                || slave_info.product_code != ProductCodeBeckhoffEL6002) {
+            continue;
+        }
+
+        printk(KERN_INFO PFX "Creating handler for serial device"
+                " at position %i\n", i);
+
+        ser = kmalloc(sizeof(*ser), GFP_KERNEL);
+        if (!ser) {
+            printk(KERN_ERR PFX "Failed to allocate serial device object.\n");
+            ret = -ENOMEM;
+            goto out_free_handlers;
+        }
+
+        ret = el6002_init(ser, master, i, domain);
+        if (ret) {
+            printk(KERN_ERR PFX "Failed to init serial device object.\n");
+            kfree(ser);
+            goto out_free_handlers;
+        }
+
+        list_add_tail(&ser->list, &handlers);
+    }
+
+
+    printk(KERN_INFO PFX "Finished.\n");
+    return 0;
+
+out_free_handlers:
+    list_for_each_entry_safe(ser, next, &handlers, list) {
+        list_del(&ser->list);
+        el6002_clear(ser);
+        kfree(ser);
+    }
+out_return:
+    return ret;
+}
+
+/*****************************************************************************/
+
+void free_serial_devices(void)
+{
+    el6002_t *ser, *next;
+
+    printk(KERN_INFO PFX "Cleaning up serial devices...\n");
+
+    list_for_each_entry_safe(ser, next, &handlers, list) {
+        list_del(&ser->list);
+        el6002_clear(ser);
+        kfree(ser);
+    }
+
+    printk(KERN_INFO PFX "Finished cleaning up serial devices.\n");
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/tty/serial.h	Tue Jan 19 19:33:47 2010 +0100
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2008  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+ *  Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *****************************************************************************/
+
+int create_serial_devices(ec_master_t *, ec_domain_t *);
+void free_serial_devices(void);
+
+void run_serial_devices(u8 *);
+
+/*****************************************************************************/
--- a/examples/tty/tty.c	Tue Jan 19 19:31:55 2010 +0100
+++ b/examples/tty/tty.c	Tue Jan 19 19:33:47 2010 +0100
@@ -40,7 +40,8 @@
 #endif
 
 #include "../../include/ecrt.h" // EtherCAT realtime interface
-#include "../../include/ectty.h" // EtherCAT TTY interface
+
+#include "serial.h"
 
 /*****************************************************************************/
 
@@ -70,264 +71,11 @@
 static uint8_t *domain1_pd; // process data memory
 
 #define BusCouplerPos  0, 0
-#define SerialPos      0, 1
 
 #define Beckhoff_EK1100 0x00000002, 0x044c2c52
-#define Beckhoff_EL6002 0x00000002, 0x17723052
-
-// offsets for PDO entries
-static unsigned int off_ctrl;
-static unsigned int off_tx;
-static unsigned int off_status;
-static unsigned int off_rx;
-
-const static ec_pdo_entry_reg_t domain1_regs[] = {
-    {SerialPos,  Beckhoff_EL6002, 0x7001, 0x01, &off_ctrl},
-    {SerialPos,  Beckhoff_EL6002, 0x7000, 0x11, &off_tx},
-    {SerialPos,  Beckhoff_EL6002, 0x6001, 0x01, &off_status},
-    {SerialPos,  Beckhoff_EL6002, 0x6000, 0x11, &off_rx},
-    {}
-};
 
 static unsigned int counter = 0;
 
-typedef enum {
-    SER_REQUEST_INIT,
-    SER_WAIT_FOR_INIT_RESPONSE,
-    SER_READY
-} serial_state_t;
-
-typedef struct {
-    size_t max_tx_data_size;
-    size_t max_rx_data_size;
-
-    uint8_t *tx_data;
-    uint8_t tx_data_size;
-
-    serial_state_t state;
-
-    uint8_t tx_request_toggle;
-    uint8_t tx_accepted_toggle;
-
-    uint8_t rx_request_toggle;
-    uint8_t rx_accepted_toggle;
-
-    uint16_t control;
-} serial_device_t;
-
-static serial_device_t *ser = NULL;
-static ec_tty_t *tty = NULL;
-        
-/*****************************************************************************/
-
-/* Slave 1, "EL6002"
- * Vendor ID:       0x00000002
- * Product code:    0x17723052
- * Revision number: 0x00100000
- */
-
-ec_pdo_entry_info_t slave_1_pdo_entries[] = {
-   {0x7001, 0x01, 16}, /* Ctrl */
-   {0x7000, 0x11, 8}, /* Data Out 0 */
-   {0x7000, 0x12, 8}, /* Data Out 1 */
-   {0x7000, 0x13, 8}, /* Data Out 2 */
-   {0x7000, 0x14, 8}, /* Data Out 3 */
-   {0x7000, 0x15, 8}, /* Data Out 4 */
-   {0x7000, 0x16, 8}, /* Data Out 5 */
-   {0x7000, 0x17, 8}, /* Data Out 6 */
-   {0x7000, 0x18, 8}, /* Data Out 7 */
-   {0x7000, 0x19, 8}, /* Data Out 8 */
-   {0x7000, 0x1a, 8}, /* Data Out 9 */
-   {0x7000, 0x1b, 8}, /* Data Out 10 */
-   {0x7000, 0x1c, 8}, /* Data Out 11 */
-   {0x7000, 0x1d, 8}, /* Data Out 12 */
-   {0x7000, 0x1e, 8}, /* Data Out 13 */
-   {0x7000, 0x1f, 8}, /* Data Out 14 */
-   {0x7000, 0x20, 8}, /* Data Out 15 */
-   {0x7000, 0x21, 8}, /* Data Out 16 */
-   {0x7000, 0x22, 8}, /* Data Out 17 */
-   {0x7000, 0x23, 8}, /* Data Out 18 */
-   {0x7000, 0x24, 8}, /* Data Out 19 */
-   {0x7000, 0x25, 8}, /* Data Out 20 */
-   {0x7000, 0x26, 8}, /* Data Out 21 */
-   {0x7011, 0x01, 16}, /* Ctrl */
-   {0x7010, 0x11, 8}, /* Data Out 0 */
-   {0x7010, 0x12, 8}, /* Data Out 1 */
-   {0x7010, 0x13, 8}, /* Data Out 2 */
-   {0x7010, 0x14, 8}, /* Data Out 3 */
-   {0x7010, 0x15, 8}, /* Data Out 4 */
-   {0x7010, 0x16, 8}, /* Data Out 5 */
-   {0x7010, 0x17, 8}, /* Data Out 6 */
-   {0x7010, 0x18, 8}, /* Data Out 7 */
-   {0x7010, 0x19, 8}, /* Data Out 8 */
-   {0x7010, 0x1a, 8}, /* Data Out 9 */
-   {0x7010, 0x1b, 8}, /* Data Out 10 */
-   {0x7010, 0x1c, 8}, /* Data Out 11 */
-   {0x7010, 0x1d, 8}, /* Data Out 12 */
-   {0x7010, 0x1e, 8}, /* Data Out 13 */
-   {0x7010, 0x1f, 8}, /* Data Out 14 */
-   {0x7010, 0x20, 8}, /* Data Out 15 */
-   {0x7010, 0x21, 8}, /* Data Out 16 */
-   {0x7010, 0x22, 8}, /* Data Out 17 */
-   {0x7010, 0x23, 8}, /* Data Out 18 */
-   {0x7010, 0x24, 8}, /* Data Out 19 */
-   {0x7010, 0x25, 8}, /* Data Out 20 */
-   {0x7010, 0x26, 8}, /* Data Out 21 */
-   {0x6001, 0x01, 16}, /* Status */
-   {0x6000, 0x11, 8}, /* Data In 0 */
-   {0x6000, 0x12, 8}, /* Data In 1 */
-   {0x6000, 0x13, 8}, /* Data In 2 */
-   {0x6000, 0x14, 8}, /* Data In 3 */
-   {0x6000, 0x15, 8}, /* Data In 4 */
-   {0x6000, 0x16, 8}, /* Data In 5 */
-   {0x6000, 0x17, 8}, /* Data In 6 */
-   {0x6000, 0x18, 8}, /* Data In 7 */
-   {0x6000, 0x19, 8}, /* Data In 8 */
-   {0x6000, 0x1a, 8}, /* Data In 9 */
-   {0x6000, 0x1b, 8}, /* Data In 10 */
-   {0x6000, 0x1c, 8}, /* Data In 11 */
-   {0x6000, 0x1d, 8}, /* Data In 12 */
-   {0x6000, 0x1e, 8}, /* Data In 13 */
-   {0x6000, 0x1f, 8}, /* Data In 14 */
-   {0x6000, 0x20, 8}, /* Data In 15 */
-   {0x6000, 0x21, 8}, /* Data In 16 */
-   {0x6000, 0x22, 8}, /* Data In 17 */
-   {0x6000, 0x23, 8}, /* Data In 18 */
-   {0x6000, 0x24, 8}, /* Data In 19 */
-   {0x6000, 0x25, 8}, /* Data In 20 */
-   {0x6000, 0x26, 8}, /* Data In 21 */
-   {0x6011, 0x01, 16}, /* Status */
-   {0x6010, 0x11, 8}, /* Data In 0 */
-   {0x6010, 0x12, 8}, /* Data In 1 */
-   {0x6010, 0x13, 8}, /* Data In 2 */
-   {0x6010, 0x14, 8}, /* Data In 3 */
-   {0x6010, 0x15, 8}, /* Data In 4 */
-   {0x6010, 0x16, 8}, /* Data In 5 */
-   {0x6010, 0x17, 8}, /* Data In 6 */
-   {0x6010, 0x18, 8}, /* Data In 7 */
-   {0x6010, 0x19, 8}, /* Data In 8 */
-   {0x6010, 0x1a, 8}, /* Data In 9 */
-   {0x6010, 0x1b, 8}, /* Data In 10 */
-   {0x6010, 0x1c, 8}, /* Data In 11 */
-   {0x6010, 0x1d, 8}, /* Data In 12 */
-   {0x6010, 0x1e, 8}, /* Data In 13 */
-   {0x6010, 0x1f, 8}, /* Data In 14 */
-   {0x6010, 0x20, 8}, /* Data In 15 */
-   {0x6010, 0x21, 8}, /* Data In 16 */
-   {0x6010, 0x22, 8}, /* Data In 17 */
-   {0x6010, 0x23, 8}, /* Data In 18 */
-   {0x6010, 0x24, 8}, /* Data In 19 */
-   {0x6010, 0x25, 8}, /* Data In 20 */
-   {0x6010, 0x26, 8}, /* Data In 21 */
-};
-
-ec_pdo_info_t slave_1_pdos[] = {
-   {0x1604, 23, slave_1_pdo_entries + 0}, /* COM RxPDO-Map Outputs Ch.1 */
-   {0x1605, 23, slave_1_pdo_entries + 23}, /* COM RxPDO-Map Outputs Ch.2 */
-   {0x1a04, 23, slave_1_pdo_entries + 46}, /* COM TxPDO-Map Inputs Ch.1 */
-   {0x1a05, 23, slave_1_pdo_entries + 69}, /* COM TxPDO-Map Inputs Ch.2 */
-};
-
-ec_sync_info_t slave_1_syncs[] = {
-   {0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
-   {1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
-   {2, EC_DIR_OUTPUT, 2, slave_1_pdos + 0, EC_WD_DISABLE},
-   {3, EC_DIR_INPUT, 2, slave_1_pdos + 2, EC_WD_DISABLE},
-   {0xff}
-};
-
-/****************************************************************************/
-
-int serial_init(serial_device_t *ser, size_t max_tx, size_t max_rx)
-{
-    ser->max_tx_data_size = max_tx;
-    ser->max_rx_data_size = max_rx;
-    ser->tx_data = NULL;
-    ser->tx_data_size = 0;
-    ser->state = SER_REQUEST_INIT;
-    ser->tx_request_toggle = 0;
-    ser->rx_accepted_toggle = 0;
-    ser->control = 0x0000;
-
-    if (max_tx > 0) {
-        ser->tx_data = kmalloc(max_tx, GFP_KERNEL);
-        if (ser->tx_data == NULL) {
-            return -ENOMEM;
-        }
-    }
-
-    return 0;
-}
-
-/****************************************************************************/
-
-void serial_clear(serial_device_t *ser)
-{
-    if (ser->tx_data) {
-        kfree(ser->tx_data);
-    }
-}
-
-/****************************************************************************/
-
-void serial_run(serial_device_t *ser, uint16_t status, uint8_t *rx_data)
-{
-    uint8_t tx_accepted_toggle, rx_request_toggle;
-
-    switch (ser->state) {
-        case SER_READY:
-
-            /* Send data */
-            
-            tx_accepted_toggle = status & 0x0001;
-            if (tx_accepted_toggle != ser->tx_accepted_toggle) { // ready
-                ser->tx_data_size =
-                    ectty_tx_data(tty, ser->tx_data, ser->max_tx_data_size);
-                if (ser->tx_data_size) {
-                    printk(KERN_INFO PFX "Sending %u bytes.\n", ser->tx_data_size);
-                    ser->tx_request_toggle = !ser->tx_request_toggle;
-                    ser->tx_accepted_toggle = tx_accepted_toggle;
-                }
-            }
-
-            /* Receive data */
-
-            rx_request_toggle = status & 0x0002;
-            if (rx_request_toggle != ser->rx_request_toggle) {
-                uint8_t rx_data_size = status >> 8;
-                ser->rx_request_toggle = rx_request_toggle;
-                printk(KERN_INFO PFX "Received %u bytes.\n", rx_data_size);
-                ectty_rx_data(tty, rx_data, rx_data_size);
-                ser->rx_accepted_toggle = !ser->rx_accepted_toggle;
-            }
-
-            ser->control =
-                ser->tx_request_toggle |
-                ser->rx_accepted_toggle << 1 |
-                ser->tx_data_size << 8;
-            break;
-
-        case SER_REQUEST_INIT:
-            if (status & (1 << 2)) {
-                ser->control = 0x0000;
-                ser->state = SER_WAIT_FOR_INIT_RESPONSE;
-            } else {
-                ser->control = 1 << 2; // CW.2, request initialization
-            }
-            break;
-
-        case SER_WAIT_FOR_INIT_RESPONSE:
-            if (!(status & (1 << 2))) {
-                printk(KERN_INFO PFX "Init successful.\n");
-                ser->tx_accepted_toggle = 1;
-                ser->control = 0x0000;
-                ser->state = SER_READY;
-            }
-            break;
-    }
-
-}
-
 /*****************************************************************************/
 
 void check_domain1_state(void)
@@ -388,9 +136,7 @@
         check_master_state();
     }
 
-    serial_run(ser, EC_READ_U16(domain1_pd + off_status), domain1_pd + off_rx);
-    EC_WRITE_U16(domain1_pd + off_ctrl, ser->control);
-    memcpy(domain1_pd + off_tx, ser->tx_data, 22);
+    run_serial_devices(domain1_pd);
 
     // send process data
     down(&master_sem);
@@ -432,31 +178,11 @@
     
     printk(KERN_INFO PFX "Starting...\n");
 
-    ser = kmalloc(sizeof(*ser), GFP_KERNEL);
-    if (!ser) {
-        printk(KERN_ERR PFX "Failed to allocate serial device object.\n");
-        ret = -ENOMEM;
-        goto out_return;
-    }
-
-    ret = serial_init(ser, 22, 22);
-    if (ret) {
-        printk(KERN_ERR PFX "Failed to init serial device object.\n");
-        goto out_free_serial;
-    }
-
-    tty = ectty_create();
-    if (IS_ERR(tty)) {
-        printk(KERN_ERR PFX "Failed to create tty.\n");
-        ret = PTR_ERR(tty);
-        goto out_serial;
-    }
-    
     master = ecrt_request_master(0);
     if (!master) {
+        printk(KERN_ERR PFX "Requesting master 0 failed.\n");
         ret = -EBUSY; 
-        printk(KERN_ERR PFX "Requesting master 0 failed.\n");
-        goto out_tty;
+        goto out_return;
     }
 
     sema_init(&master_sem, 1);
@@ -470,30 +196,18 @@
 
     // Create configuration for bus coupler
     sc = ecrt_master_slave_config(master, BusCouplerPos, Beckhoff_EK1100);
-    if (!sc)
-        return -1;
-
-    if (!(sc = ecrt_master_slave_config(
-                    master, SerialPos, Beckhoff_EL6002))) {
-        printk(KERN_ERR PFX "Failed to get slave configuration.\n");
-        return -1;
-    }
-
-    printk("Configuring PDOs...\n");
-    if (ecrt_slave_config_pdos(sc, EC_END, slave_1_syncs)) {
-        printk(KERN_ERR PFX "Failed to configure PDOs.\n");
-        return -1;
-    }
-
-    if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
-        printk(KERN_ERR PFX "PDO entry registration failed!\n");
-        return -1;
-    }
+    if (!sc) {
+        printk(KERN_ERR PFX "Failed to create slave config.\n");
+        ret = -ENOMEM;
+        goto out_release_master;
+    }
+
+    create_serial_devices(master, domain1);
 
     printk(KERN_INFO PFX "Activating master...\n");
     if (ecrt_master_activate(master)) {
         printk(KERN_ERR PFX "Failed to activate master!\n");
-        goto out_release_master;
+        goto out_free_serial;
     }
 
     // Get internal process data for domain
@@ -508,15 +222,11 @@
     printk(KERN_INFO PFX "Started.\n");
     return 0;
 
+out_free_serial:
+    free_serial_devices();
 out_release_master:
     printk(KERN_ERR PFX "Releasing master...\n");
     ecrt_release_master(master);
-out_tty:
-    ectty_free(tty);
-out_serial:
-    serial_clear(ser);
-out_free_serial:
-    kfree(ser);
 out_return:
     printk(KERN_ERR PFX "Failed to load. Aborting.\n");
     return ret;
@@ -530,13 +240,11 @@
 
     del_timer_sync(&timer);
 
+    free_serial_devices();
+
     printk(KERN_INFO PFX "Releasing master...\n");
     ecrt_release_master(master);
 
-    ectty_free(tty);
-    serial_clear(ser);
-    kfree(ser);
-
     printk(KERN_INFO PFX "Unloading.\n");
 }
 
--- a/include/ecrt.h	Tue Jan 19 19:31:55 2010 +0100
+++ b/include/ecrt.h	Tue Jan 19 19:33:47 2010 +0100
@@ -208,8 +208,6 @@
 
 /*****************************************************************************/
 
-#ifndef __KERNEL__
-
 /** Master information.
  *
  * This is used as an output parameter of ecrt_master().
@@ -246,8 +244,6 @@
     char name[EC_MAX_STRING_LENGTH]; /**< Name of the slave. */
 } ec_slave_info_t;
 
-#endif // #ifndef __KERNEL__
-
 /*****************************************************************************/
 
 /** Domain working counter interpretation.
@@ -539,8 +535,6 @@
         uint32_t product_code /**< Expected product code. */
         );
 
-#ifndef __KERNEL__
-
 /** Obtains master information.
  *
  * No memory is allocated on the heap in
@@ -573,6 +567,8 @@
                                       information */
         );
 
+#ifndef __KERNEL__
+
 /** Returns the proposed configuration of a slave's sync manager.
  *
  * Fills a given ec_sync_info_t structure with the attributes of a sync
--- a/lib/master.c	Tue Jan 19 19:31:55 2010 +0100
+++ b/lib/master.c	Tue Jan 19 19:33:47 2010 +0100
@@ -156,7 +156,7 @@
     slave_info->error_flag = data.error_flag;
     slave_info->sync_count = data.sync_count;
     slave_info->sdo_count = data.sdo_count;
-    strncpy(slave_info->name, data.name, EC_IOCTL_STRING_SIZE);
+    strncpy(slave_info->name, data.name, EC_MAX_STRING_LENGTH);
     return 0;
 }
 
--- a/master/globals.h	Tue Jan 19 19:31:55 2010 +0100
+++ b/master/globals.h	Tue Jan 19 19:33:47 2010 +0100
@@ -51,8 +51,11 @@
 /** SDO injection timeout in microseconds. */
 #define EC_SDO_INJECTION_TIMEOUT 10000
 
-/** time to send a byte in nanoseconds. */
-#define EC_BYTE_TRANSMITION_TIME 80
+/** Time to send a byte in nanoseconds.
+ *
+ * t_ns = 1 / (100 MBit/s / 8 bit/byte) = 80 ns/byte
+ */
+#define EC_BYTE_TRANSMISSION_TIME_NS 80
 
 /** Number of state machine retries on datagram timeout. */
 #define EC_FSM_RETRIES 3
--- a/master/master.c	Tue Jan 19 19:31:55 2010 +0100
+++ b/master/master.c	Tue Jan 19 19:33:47 2010 +0100
@@ -159,7 +159,9 @@
     sema_init(&master->ext_queue_sem, 1);
 
     INIT_LIST_HEAD(&master->external_datagram_queue);
-	ec_master_set_send_interval(master,1000000 / HZ); // send interval in IDLE phase
+    
+    // send interval in IDLE phase
+    ec_master_set_send_interval(master, 1000000 / HZ);
 
     INIT_LIST_HEAD(&master->domains);
 
@@ -373,35 +375,35 @@
     // external requests are obsolete, so we wake pending waiters and remove
     // them from the list
     //
-	// SII requests
-	while (1) {
-		ec_sii_write_request_t *request;
-		if (list_empty(&master->sii_requests))
-			break;
-		// get first request
+    // SII requests
+    while (1) {
+        ec_sii_write_request_t *request;
+        if (list_empty(&master->sii_requests))
+            break;
+        // get first request
         request = list_entry(master->sii_requests.next,
                 ec_sii_write_request_t, list);
-		list_del_init(&request->list); // dequeue
-		EC_INFO("Discarding SII request, slave %u does not exist anymore.\n",
-				request->slave->ring_position);
-		request->state = EC_INT_REQUEST_FAILURE;
-		wake_up(&master->sii_queue);
-	}
-
-	// Register requests
-	while (1) {
-	    ec_reg_request_t *request;
-		if (list_empty(&master->reg_requests))
-			break;
-		// get first request
-		request = list_entry(master->reg_requests.next,
-				ec_reg_request_t, list);
-		list_del_init(&request->list); // dequeue
-		EC_INFO("Discarding Reg request, slave %u does not exist anymore.\n",
-				request->slave->ring_position);
-		request->state = EC_INT_REQUEST_FAILURE;
-		wake_up(&master->reg_queue);
-	}
+        list_del_init(&request->list); // dequeue
+        EC_INFO("Discarding SII request, slave %u does not exist anymore.\n",
+                request->slave->ring_position);
+        request->state = EC_INT_REQUEST_FAILURE;
+        wake_up(&master->sii_queue);
+    }
+
+    // Register requests
+    while (1) {
+        ec_reg_request_t *request;
+        if (list_empty(&master->reg_requests))
+            break;
+        // get first request
+        request = list_entry(master->reg_requests.next,
+                ec_reg_request_t, list);
+        list_del_init(&request->list); // dequeue
+        EC_INFO("Discarding Reg request, slave %u does not exist anymore.\n",
+                request->slave->ring_position);
+        request->state = EC_INT_REQUEST_FAILURE;
+        wake_up(&master->reg_queue);
+    }
 
     for (slave = master->slaves;
             slave < master->slaves + master->slave_count;
@@ -689,84 +691,100 @@
 
 /*****************************************************************************/
 
-/** Injects external datagrams that fit into the datagram queue
+/** Injects external datagrams that fit into the datagram queue.
  */
 void ec_master_inject_external_datagrams(
-		ec_master_t *master /**< EtherCAT master */
-		)
-{
-	ec_datagram_t *datagram, *n;
-	size_t queue_size = 0;
-	list_for_each_entry(datagram, &master->datagram_queue, queue) {
-		queue_size += datagram->data_size;
-	}
-	list_for_each_entry_safe(datagram, n, &master->external_datagram_queue, queue) {
-		queue_size += datagram->data_size;
-		if (queue_size <= master->max_queue_size) {
-			list_del_init(&datagram->queue);
+        ec_master_t *master /**< EtherCAT master */
+        )
+{
+    ec_datagram_t *datagram, *n;
+    size_t queue_size = 0;
+
+    list_for_each_entry(datagram, &master->datagram_queue, queue) {
+        queue_size += datagram->data_size;
+    }
+
+    list_for_each_entry_safe(datagram, n, &master->external_datagram_queue,
+            queue) {
+        queue_size += datagram->data_size;
+        if (queue_size <= master->max_queue_size) {
+            list_del_init(&datagram->queue);
 #if DEBUG_INJECT
-			if (master->debug_level) {
-				EC_DBG("Injecting external datagram %08x size=%u, queue_size=%u\n",(unsigned int)datagram,datagram->data_size,queue_size);
-			}
+            if (master->debug_level) {
+                EC_DBG("Injecting external datagram %08x size=%u,"
+                        " queue_size=%u\n", (unsigned int) datagram,
+                        datagram->data_size, queue_size);
+            }
 #endif
 #ifdef EC_HAVE_CYCLES
-			datagram->cycles_sent = 0;
-#endif
-			datagram->jiffies_sent = 0;
-			ec_master_queue_datagram(master, datagram);
-		}
-		else {
-			if (datagram->data_size > master->max_queue_size) {
-				list_del_init(&datagram->queue);
-				datagram->state = EC_DATAGRAM_ERROR;
-				EC_ERR("External datagram %08x is too large, size=%u, max_queue_size=%u\n",(unsigned int)datagram,datagram->data_size,master->max_queue_size);
-			}
-			else {
+            datagram->cycles_sent = 0;
+#endif
+            datagram->jiffies_sent = 0;
+            ec_master_queue_datagram(master, datagram);
+        }
+        else {
+            if (datagram->data_size > master->max_queue_size) {
+                list_del_init(&datagram->queue);
+                datagram->state = EC_DATAGRAM_ERROR;
+                EC_ERR("External datagram %p is too large,"
+                        " size=%u, max_queue_size=%u\n",
+                        datagram, datagram->data_size,
+                        master->max_queue_size);
+            } else {
 #ifdef EC_HAVE_CYCLES
-				cycles_t cycles_now = get_cycles();
-				if (cycles_now - datagram->cycles_sent
-						> sdo_injection_timeout_cycles) {
+                cycles_t cycles_now = get_cycles();
+
+                if (cycles_now - datagram->cycles_sent
+                        > sdo_injection_timeout_cycles)
 #else
-				if (jiffies - datagram->jiffies_sent
-						> sdo_injection_timeout_jiffies) {
-#endif
-					unsigned int time_us;
-					list_del_init(&datagram->queue);
-					datagram->state = EC_DATAGRAM_ERROR;
+                if (jiffies - datagram->jiffies_sent
+                        > sdo_injection_timeout_jiffies)
+#endif
+                {
+                    unsigned int time_us;
+
+                    list_del_init(&datagram->queue);
+                    datagram->state = EC_DATAGRAM_ERROR;
 #ifdef EC_HAVE_CYCLES
-					time_us = (unsigned int) ((cycles_now - datagram->cycles_sent) * 1000LL) / cpu_khz;
+                    time_us = (unsigned int)
+                        ((cycles_now - datagram->cycles_sent) * 1000LL)
+                        / cpu_khz;
 #else
-					time_us = (unsigned int) ((jiffies - datagram->jiffies_sent) * 1000000 / HZ);
-#endif
-					EC_ERR("Timeout %u us: injecting external datagram %08x size=%u, max_queue_size=%u\n",time_us,(unsigned int)datagram,datagram->data_size,master->max_queue_size);
-				}
-				else  {
+                    time_us = (unsigned int)
+                        ((jiffies - datagram->jiffies_sent) * 1000000 / HZ);
+#endif
+                    EC_ERR("Timeout %u us: injecting external datagram %p"
+                            " size=%u, max_queue_size=%u\n",
+                            time_us, datagram,
+                            datagram->data_size, master->max_queue_size);
+                }
 #if DEBUG_INJECT
-					if (master->debug_level) {
-						EC_DBG("Deferred injecting of external datagram %08x size=%u, queue_size=%u\n",(unsigned int)datagram,datagram->data_size,queue_size);
-					}
-#endif
-				}
-			}
-		}
-	}
-}
-
-/*****************************************************************************/
-
-/** sets the expected interval between calls to ecrt_master_send
-	and calculates the maximum amount of data to queue
+                else if (master->debug_level) {
+                    EC_DBG("Deferred injecting of external datagram %p"
+                            " size=%u, queue_size=%u\n",
+                            datagram, datagram->data_size, queue_size);
+                }
+#endif
+            }
+        }
+    }
+}
+
+/*****************************************************************************/
+
+/** Sets the expected interval between calls to ecrt_master_send
+ * and calculates the maximum amount of data to queue.
  */
 void ec_master_set_send_interval(
-		ec_master_t *master, /**< EtherCAT master */
-		size_t send_interval /**< send interval */
-		)
-{
-	master->send_interval = send_interval;
-	master->max_queue_size = (send_interval * 1000) / EC_BYTE_TRANSMITION_TIME;
-	master->max_queue_size -= master->max_queue_size / 10;
-}
-
+        ec_master_t *master, /**< EtherCAT master */
+        size_t send_interval /**< Send interval */
+        )
+{
+    master->send_interval = send_interval;
+    master->max_queue_size =
+        (send_interval * 1000) / EC_BYTE_TRANSMISSION_TIME_NS;
+    master->max_queue_size -= master->max_queue_size / 10;
+}
 
 /*****************************************************************************/
 
@@ -780,18 +798,23 @@
 	ec_datagram_t *queued_datagram;
 
     down(&master->io_sem);
+
 	// check, if the datagram is already queued
-	list_for_each_entry(queued_datagram, &master->external_datagram_queue, queue) {
+	list_for_each_entry(queued_datagram, &master->external_datagram_queue,
+            queue) {
 		if (queued_datagram == datagram) {
 			datagram->state = EC_DATAGRAM_QUEUED;
 			return;
 		}
 	}
+
 #if DEBUG_INJECT
 	if (master->debug_level) {
-		EC_DBG("Requesting external datagram %08x size=%u\n",(unsigned int)datagram,datagram->data_size);
+		EC_DBG("Requesting external datagram %p size=%u\n",
+                datagram, datagram->data_size);
 	}
 #endif
+
 	list_add_tail(&datagram->queue, &master->external_datagram_queue);
 	datagram->state = EC_DATAGRAM_QUEUED;
 #ifdef EC_HAVE_CYCLES
@@ -1116,66 +1139,79 @@
 
 
 /*****************************************************************************/
+
+#ifdef EC_USE_HRTIMER
+
 /*
  * Sleep related functions:
  */
 static enum hrtimer_restart ec_master_nanosleep_wakeup(struct hrtimer *timer)
 {
-	struct hrtimer_sleeper *t =
-		container_of(timer, struct hrtimer_sleeper, timer);
-	struct task_struct *task = t->task;
-
-	t->task = NULL;
-	if (task)
-		wake_up_process(task);
-
-	return HRTIMER_NORESTART;
-}
+    struct hrtimer_sleeper *t =
+        container_of(timer, struct hrtimer_sleeper, timer);
+    struct task_struct *task = t->task;
+
+    t->task = NULL;
+    if (task)
+        wake_up_process(task);
+
+    return HRTIMER_NORESTART;
+}
+
+/*****************************************************************************/
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+
 /* compatibility with new hrtimer interface */
 static inline ktime_t hrtimer_get_expires(const struct hrtimer *timer)
 {
-	return timer->expires;
-}
+    return timer->expires;
+}
+
+/*****************************************************************************/
 
 static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time)
 {
-	timer->expires = time;
-}
-#endif
-
+    timer->expires = time;
+}
+
+#endif
+
+/*****************************************************************************/
 
 void ec_master_nanosleep(const unsigned long nsecs)
 {
-	struct hrtimer_sleeper t;
-	enum hrtimer_mode mode = HRTIMER_MODE_REL;
-	hrtimer_init(&t.timer, CLOCK_MONOTONIC,mode);
-	t.timer.function = ec_master_nanosleep_wakeup;
-	t.task = current;
+    struct hrtimer_sleeper t;
+    enum hrtimer_mode mode = HRTIMER_MODE_REL;
+
+    hrtimer_init(&t.timer, CLOCK_MONOTONIC, mode);
+    t.timer.function = ec_master_nanosleep_wakeup;
+    t.task = current;
 #ifdef CONFIG_HIGH_RES_TIMERS
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
-	t.timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_RESTART;
+    t.timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_RESTART;
 #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 26)
-	t.timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
+    t.timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
 #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28)
-	t.timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
-#endif
-#endif
-	hrtimer_set_expires(&t.timer, ktime_set(0,nsecs));
-	do {
-		set_current_state(TASK_INTERRUPTIBLE);
-		hrtimer_start(&t.timer, hrtimer_get_expires(&t.timer), mode);
-
-		if (likely(t.task))
-			schedule();
-
-		hrtimer_cancel(&t.timer);
-		mode = HRTIMER_MODE_ABS;
-
-	} while (t.task && !signal_pending(current));
-}
-
+    t.timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
+#endif
+#endif
+    hrtimer_set_expires(&t.timer, ktime_set(0, nsecs));
+
+    do {
+        set_current_state(TASK_INTERRUPTIBLE);
+        hrtimer_start(&t.timer, hrtimer_get_expires(&t.timer), mode);
+
+        if (likely(t.task))
+            schedule();
+
+        hrtimer_cancel(&t.timer);
+        mode = HRTIMER_MODE_ABS;
+
+    } while (t.task && !signal_pending(current));
+}
+
+#endif // EC_USE_HRTIMER
 
 /*****************************************************************************/
 
@@ -1187,9 +1223,14 @@
     ec_slave_t *slave = NULL;
     int fsm_exec;
 	size_t sent_bytes;
-	ec_master_set_send_interval(master,1000000 / HZ); // send interval in IDLE phase
+
+    // send interval in IDLE phase
+	ec_master_set_send_interval(master, 1000000 / HZ); 
+
 	if (master->debug_level)
-		EC_DBG("Idle thread running with send interval = %d us, max data size=%d\n",master->send_interval,master->max_queue_size);
+		EC_DBG("Idle thread running with send interval = %d us,"
+                " max data size=%d\n", master->send_interval,
+                master->max_queue_size);
 
     while (!kthread_should_stop()) {
         ec_datagram_output_stats(&master->fsm_datagram);
@@ -1218,17 +1259,29 @@
         }
         ec_master_inject_external_datagrams(master);
         ecrt_master_send(master);
-		sent_bytes = master->main_device.tx_skb[master->main_device.tx_ring_index]->len;
+		sent_bytes = master->main_device.tx_skb[
+            master->main_device.tx_ring_index]->len;
         up(&master->io_sem);
 
-		if (ec_fsm_master_idle(&master->fsm))
-			ec_master_nanosleep(master->send_interval*1000);
-		else
-			ec_master_nanosleep(sent_bytes*EC_BYTE_TRANSMITION_TIME);
+		if (ec_fsm_master_idle(&master->fsm)) {
+#ifdef EC_USE_HRTIMER
+			ec_master_nanosleep(master->send_interval * 1000);
+#else
+            set_current_state(TASK_INTERRUPTIBLE);
+            schedule_timeout(1);
+#endif
+        } else {
+#ifdef EC_USE_HRTIMER
+			ec_master_nanosleep(sent_bytes * EC_BYTE_TRANSMISSION_TIME_NS);
+#else
+            schedule();
+#endif
+        }
     }
     
     if (master->debug_level)
         EC_DBG("Master IDLE thread exiting...\n");
+
     return 0;
 }
 
@@ -1241,11 +1294,16 @@
     ec_master_t *master = (ec_master_t *) priv_data;
     ec_slave_t *slave = NULL;
     int fsm_exec;
+
     if (master->debug_level)
-		EC_DBG("Operation thread running with fsm interval = %d us, max data size=%d\n",master->send_interval,master->max_queue_size);
+		EC_DBG("Operation thread running with fsm interval = %d us,"
+                " max data size=%d\n",
+                master->send_interval,
+                master->max_queue_size);
 
     while (!kthread_should_stop()) {
         ec_datagram_output_stats(&master->fsm_datagram);
+
         if (master->injection_seq_rt == master->injection_seq_fsm) {
             // output statistics
             ec_master_output_stats(master);
@@ -1266,8 +1324,19 @@
             if (fsm_exec)
                 master->injection_seq_fsm++;
         }
+
+#ifdef EC_USE_HRTIMER
 		// the op thread should not work faster than the sending RT thread
-		ec_master_nanosleep(master->send_interval*1000);
+		ec_master_nanosleep(master->send_interval * 1000);
+#else
+        if (ec_fsm_master_idle(&master->fsm)) {
+            set_current_state(TASK_INTERRUPTIBLE);
+            schedule_timeout(1);
+        }
+        else {
+            schedule();
+        }
+#endif
 	}
     
     if (master->debug_level)
@@ -2138,6 +2207,56 @@
 
 /*****************************************************************************/
 
+int ecrt_master(ec_master_t *master, ec_master_info_t *master_info)
+{
+    if (master->debug_level)
+        EC_DBG("ecrt_master(master = 0x%p, master_info = 0x%p)\n",
+                master, master_info);
+
+    master_info->slave_count = master->slave_count;
+    master_info->link_up = master->main_device.link_state;
+    master_info->scan_busy = master->scan_busy;
+    master_info->app_time = master->app_time;
+    return 0;
+}
+
+/*****************************************************************************/
+
+int ecrt_master_get_slave(ec_master_t *master, uint16_t slave_position,
+        ec_slave_info_t *slave_info)
+{
+    const ec_slave_t *slave;
+
+    if (down_interruptible(&master->master_sem)) {
+        return -EINTR;
+    }
+
+    slave = ec_master_find_slave_const(master, 0, slave_position);
+
+    slave_info->position = slave->ring_position;
+    slave_info->vendor_id = slave->sii.vendor_id;
+    slave_info->product_code = slave->sii.product_code;
+    slave_info->revision_number = slave->sii.revision_number;
+    slave_info->serial_number = slave->sii.serial_number;
+    slave_info->alias = slave->sii.alias;
+    slave_info->current_on_ebus = slave->sii.current_on_ebus;
+    slave_info->al_state = slave->current_state;
+    slave_info->error_flag = slave->error_flag;
+    slave_info->sync_count = slave->sii.sync_count;
+    slave_info->sdo_count = ec_slave_sdo_count(slave);
+    if (slave->sii.name) {
+        strncpy(slave_info->name, slave->sii.name, EC_MAX_STRING_LENGTH);
+    } else {
+        slave_info->name[0] = 0;
+    }
+
+    up(&master->master_sem);
+
+    return 0;
+}
+
+/*****************************************************************************/
+
 void ecrt_master_callbacks(ec_master_t *master,
         void (*send_cb)(void *), void (*receive_cb)(void *), void *cb_data)
 {
@@ -2218,6 +2337,8 @@
 EXPORT_SYMBOL(ecrt_master_send_ext);
 EXPORT_SYMBOL(ecrt_master_receive);
 EXPORT_SYMBOL(ecrt_master_callbacks);
+EXPORT_SYMBOL(ecrt_master);
+EXPORT_SYMBOL(ecrt_master_get_slave);
 EXPORT_SYMBOL(ecrt_master_slave_config);
 EXPORT_SYMBOL(ecrt_master_state);
 EXPORT_SYMBOL(ecrt_master_application_time);
--- a/tty/module.c	Tue Jan 19 19:31:55 2010 +0100
+++ b/tty/module.c	Tue Jan 19 19:33:47 2010 +0100
@@ -40,6 +40,7 @@
 #include <linux/tty_flip.h>
 #include <linux/termios.h>
 #include <linux/timer.h>
+#include <linux/version.h>
 
 #include "../master/globals.h"
 #include "../include/ectty.h"
@@ -379,7 +380,11 @@
 
 /*****************************************************************************/
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static int ec_tty_put_char(struct tty_struct *tty, unsigned char ch)
+#else
 static void ec_tty_put_char(struct tty_struct *tty, unsigned char ch)
+#endif
 {
     ec_tty_t *t = (ec_tty_t *) tty->driver_data;
 
@@ -390,8 +395,14 @@
     if (ec_tty_tx_space(t)) {
         t->tx_buffer[t->tx_write_idx] = ch;
         t->tx_write_idx = (t->tx_write_idx + 1) % EC_TTY_TX_BUFFER_SIZE;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+        return 1;
+#endif
     } else {
         printk(KERN_WARNING PFX "%s(): Dropped a byte!\n", __func__);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+        return 0;
+#endif
     }
 }
 
@@ -506,11 +517,19 @@
 
 /*****************************************************************************/
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+static int ec_tty_break(struct tty_struct *tty, int break_state)
+#else
 static void ec_tty_break(struct tty_struct *tty, int break_state)
+#endif
 {
 #if EC_TTY_DEBUG >= 2
     printk(KERN_INFO PFX "%s(break_state = %i).\n", __func__, break_state);
 #endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+    return -EIO; // not implemented
+#endif
 }
 
 /*****************************************************************************/