trunk, tags und branches
authorFlorian Pose <fp@igh-essen.com>
Fri, 21 Oct 2005 11:21:42 +0000
changeset 0 05c992bf5847
child 1 98acc19c7594
trunk, tags und branches
Doxyfile
Makefile
TODO
drivers/Makefile
drivers/drv_8139too.c
drivers/ec_command.c
drivers/ec_command.h
drivers/ec_dbg.h
drivers/ec_device.c
drivers/ec_device.h
drivers/ec_globals.h
drivers/ec_master.c
drivers/ec_master.h
drivers/ec_slave.c
drivers/ec_slave.h
drivers/ec_types.c
drivers/ec_types.h
mini/Makefile
mini/ec_mini.c
rs232dbg/Makefile
rs232dbg/aip_com.c
rs232dbg/aip_com.h
rs232dbg/aip_comP.h
rs232dbg/rs232dbg.c
rs232dbg/rs232dbg.h
rt/Makefile
rt/TAGS
rt/aip_com.c
rt/aip_com.h
rt/aip_comP.h
rt/cif-rtai-io.h
rt/msr_io.c
rt/msr_io.h
rt/msr_load
rt/msr_unload
rt/msrserv.pl
rt/rt_lib
rt/tmp/_msr_io.c
rt/tmp/_msr_io.h
user/Makefile
user/ec_command.c
user/ec_command.h
user/ec_globals.h
user/ec_master.c
user/ec_master.h
user/ec_slave.c
user/ec_slave.h
user/main.c
user/main_gui.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Doxyfile	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,1004 @@
+#################################################################
+#
+#  Doxyfile
+#
+#  IgH EtherCAT-Treiber
+#
+#  $LastChangedDate$
+#  $Author$
+#
+#################################################################
+
+# Doxyfile 1.2.18
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = EtherCAT
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 0.1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ../src-docs
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, 
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en 
+# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese, 
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian.
+
+OUTPUT_LANGUAGE        = German
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these class will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited 
+# members of a class in the documentation of that class as if those members were 
+# ordinary class members. Constructors, destructors and assignment operators of 
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH        = 
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower case letters. If set to YES upper case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# users are adviced to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments  will behave just like the Qt-style comments (thus requiring an 
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = YES
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# reimplements.
+
+INHERIT_DOCS           = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 3
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= NO
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consist of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 
+# only. Doxygen will then generate output that is more tailored for C. 
+# For instance some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
+# only. Doxygen will then generate output that is more tailored for Java. 
+# For instance namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = drivers
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp 
+# *.h++ *.idl *.odl
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = drivers/drv_8139too.c
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories 
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories.
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.
+
+INPUT_FILTER           = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output dir.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non empty doxygen will try to run 
+# the html help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the Html help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+, 
+# or Internet explorer 4.0+). Note that for large projects the tree generation 
+# can take a very long time. In such cases it is better to disable this feature. 
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = YES
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimised for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assigments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_XML           = NO
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse the 
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or 
+# super classes. Setting the tag to NO turns the diagrams off. Note that this 
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is 
+# recommended to install and use dot, since it yield more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermedate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
+
+# The CGI_NAME tag should be the name of the CGI script that 
+# starts the search engine (doxysearch) with the correct parameters. 
+# A script with this name will be generated by doxygen.
+
+CGI_NAME               = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the 
+# cgi binaries are located. See the documentation of your http daemon for 
+# details.
+
+CGI_URL                = 
+
+# The DOC_URL tag should be the absolute URL to the directory where the 
+# documentation is located. If left blank the absolute path to the 
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL                = 
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the 
+# documentation is located. If left blank the directory on the local machine 
+# will be used.
+
+DOC_ABSPATH            = 
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary 
+# is installed.
+
+BIN_ABSPATH            = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to 
+# documentation generated for other projects. This allows doxysearch to search 
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS          = 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,38 @@
+#################################################################
+#
+#  Globales Makefile
+#
+#  IgH EtherCAT-Treiber
+#
+#  $Id$
+#
+#################################################################
+
+all: .rs232dbg .drivers .rt .mini
+
+doc docs:
+	doxygen Doxyfile
+
+#################################################################
+
+.drivers:
+	$(MAKE) -C drivers
+
+.rt:
+	$(MAKE) -C rt
+
+.rs232dbg:
+	$(MAKE) -C rs232dbg
+
+.mini:
+	$(MAKE) -C mini
+
+#################################################################
+
+clean:
+	$(MAKE) -C rt clean
+	$(MAKE) -C drivers clean
+	$(MAKE) -C rs232dbg clean
+	$(MAKE) -C mini clean
+
+#################################################################
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TODO	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,8 @@
+TODO-Liste EtherCAT-Treiber
+
+$Date$
+$Author$
+
+- Konfiguration SSI-/Inkrementalgeberklemmen
+- Ethernet over EtherCAT (EoE)
+- Retry bei Asynchroner Kommunikation
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/Makefile	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,71 @@
+#################################################################
+#
+#  Makefile
+#
+#  IgH EtherCAT-Treiber
+#
+#  $Date$
+#  $Author$
+#
+#################################################################
+
+#KERNELDIR=/usr/src/linux
+#KERNELDIR=/home/rich/linux-2.4.20.CX1100-rthal5
+#KERNELDIR=./linux-2.4.20.CX1100-rthal5
+
+#IgH
+KERNELDIR = /vol/projekte/msr_messen_steuern_regeln/linux/kernel/2.4.20/include/linux-2.4.20.CX1100-rthal5
+RTAIDIR   = /vol/projekte/msr_messen_steuern_regeln/linux/kernel/2.4.20/include/rtai-24.1.13
+RTLIBDIR = rt_lib
+
+#euler-nottuln
+#KERNELDIR = /usr/src/linux
+#RTAIDIR = /usr/src/rtai
+
+#patra
+#KERNELDIR = /usr/src/linux-2.4.20.CX1100-rthal5
+#RTAIDIR   = /usr/src/rtai-24.1.13
+
+#include $(KERNELDIR)/.config
+
+ECAT_8139_OBJ = drv_8139too.o ec_device.o ec_master.o \
+	ec_slave.o ec_command.o ec_types.o
+
+
+CFLAGS = -O2 -Wall -Wuninitialized -D__KERNEL__ -DMODULE \
+	-I$(KERNELDIR)/include -D_RTAI -I$(RTAIDIR)/include \
+	-I$(RTLIBDIR)/msr-include
+
+ifdef CONFIG_SMP
+	CFLAGS += -D__SMP__ -DSMP
+endif
+
+#################################################################
+
+all: .depend ecat_8139too.o
+
+ecat_8139too.o: $(ECAT_8139_OBJ)
+	$(LD) -r $(ECAT_8139_OBJ) -o $@
+
+.c.o:
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+doc docs:
+	$(MAKE) -C .. doc
+
+#################################################################
+
+.depend:
+	$(CC) $(CFLAGS) -M *.c > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+#################################################################
+
+clean:
+	rm -f *.o *~ core .depend
+
+#################################################################
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/drv_8139too.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,2997 @@
+/******************************************************************************
+ *
+ *  drv_8139too.c
+ *
+ *  EtherCAT-Treiber für RTL8139-kompatible Netzwerkkarten.
+ *           
+ *  Autoren: Wilhelm Hagemeister, Florian Pose
+ *
+ *  $Date$
+ *  $Author$
+ *
+ *  (C) Copyright IgH 2005
+ *  Ingenieurgemeinschaft IgH
+ *  Heinz-Bäcker Str. 34
+ *  D-45356 Essen
+ *  Tel.: +49 201/61 99 31
+ *  Fax.: +49 201/61 98 36
+ *  E-mail: sp@igh-essen.com
+ *
+ ******************************************************************************/
+
+/*
+	8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
+
+	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000-2002 Jeff Garzik
+
+	Much code comes from Donald Becker's rtl8139.c driver,
+	versions 1.13 and older.  This driver was originally based
+	on rtl8139.c version 1.07.  Header of rtl8139.c version 1.13:
+
+	-----<snip>-----
+
+        	Written 1997-2001 by Donald Becker.
+		This software may be used and distributed according to the
+		terms of the GNU General Public License (GPL), incorporated
+		herein by reference.  Drivers based on or derived from this
+		code fall under the GPL and must retain the authorship,
+		copyright and license notice.  This file is not a complete
+		program and may only be used when the entire operating
+		system is licensed under the GPL.
+
+		This driver is for boards based on the RTL8129 and RTL8139
+		PCI ethernet chips.
+
+		The author may be reached as becker@scyld.com, or C/O Scyld
+		Computing Corporation 410 Severn Ave., Suite 210 Annapolis
+		MD 21403
+
+		Support and updates available at
+		http://www.scyld.com/network/rtl8139.html
+
+		Twister-tuning table provided by Kinston
+		<shangh@realtek.com.tw>.
+
+	-----<snip>-----
+
+	This software may be used and distributed according to the terms
+	of the GNU General Public License, incorporated herein by reference.
+
+	Contributors:
+
+		Donald Becker - he wrote the original driver, kudos to him!
+		(but please don't e-mail him for support, this isn't his driver)
+
+		Tigran Aivazian - bug fixes, skbuff free cleanup
+
+		Martin Mares - suggestions for PCI cleanup
+
+		David S. Miller - PCI DMA and softnet updates
+
+		Ernst Gill - fixes ported from BSD driver
+
+		Daniel Kobras - identified specific locations of
+			posted MMIO write bugginess
+
+		Gerard Sharp - bug fix, testing and feedback
+
+		David Ford - Rx ring wrap fix
+
+		Dan DeMaggio - swapped RTL8139 cards with me, and allowed me
+		to find and fix a crucial bug on older chipsets.
+
+		Donald Becker/Chris Butterworth/Marcus Westergren -
+		Noticed various Rx packet size-related buglets.
+
+		Santiago Garcia Mantinan - testing and feedback
+
+		Jens David - 2.2.x kernel backports
+
+		Martin Dennett - incredibly helpful insight on undocumented
+		features of the 8139 chips
+
+		Jean-Jacques Michel - bug fix
+
+		Tobias Ringström - Rx interrupt status checking suggestion
+
+		Andrew Morton - Clear blocked signals, avoid
+		buffer overrun setting current->comm.
+
+		Kalle Olavi Niemitalo - Wake-on-LAN ioctls
+
+		Robert Kuebel - Save kernel thread from dying on any signal.
+
+	Submitting bug reports:
+
+		"rtl8139-diag -mmmaaavvveefN" output
+		enable RTL8139_DEBUG below, and look at 'dmesg' or kernel log
+
+		See 8139too.txt for more details.
+
+*/
+
+#define DRV_NAME	"8139too_ecat"
+#define DRV_VERSION	"0.9.26"
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/completion.h>
+#include <linux/crc32.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+#include "ec_device.h"
+#include <rtai.h>
+#include <linux/delay.h>
+#include "ec_dbg.h"
+
+/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+
+#define RTL8139_DRIVER_NAME   DRV_NAME " Fast Ethernet driver " DRV_VERSION
+#define PFX DRV_NAME ": "
+
+
+/* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */
+#ifdef CONFIG_8139TOO_PIO
+#define USE_IO_OPS 1
+#endif
+
+/* define to 1 to enable copious debugging info */
+//#define RTL8139_DEBUG 1
+#undef RTL8139_DEBUG
+
+/* define to 1 to disable lightweight runtime debugging checks */
+#undef RTL8139_NDEBUG
+
+
+#ifdef RTL8139_DEBUG
+/* note: prints function name for you */
+#  define DPRINTK(fmt, args...) EC_DBG(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#  define DPRINTK(fmt, args...)
+#endif
+
+#ifdef RTL8139_NDEBUG
+#  define assert(expr) do {} while (0)
+#else
+#  define assert(expr) \
+        if(!(expr)) {					\
+        printk( "Assertion failed! %s,%s,%s,line=%d\n",	\
+        #expr,__FILE__,__FUNCTION__,__LINE__);		\
+        }
+#endif
+
+
+/* A few user-configurable values. */
+/* media options */
+#define MAX_UNITS 8
+static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+   The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
+static int multicast_filter_limit = 32;
+
+/* bitmapped message enable number */
+static int debug = -1;
+
+/* Size of the in-memory receive ring. */
+#define RX_BUF_LEN_IDX	2	/* 0==8K, 1==16K, 2==32K, 3==64K */
+#define RX_BUF_LEN	(8192 << RX_BUF_LEN_IDX)
+#define RX_BUF_PAD	16
+#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
+#define RX_BUF_TOT_LEN	(RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
+
+/* Number of Tx descriptor registers. */
+#define NUM_TX_DESC	4
+
+/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE	1536
+
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE	MAX_ETH_FRAME_SIZE
+#define TX_BUF_TOT_LEN	(TX_BUF_SIZE * NUM_TX_DESC)
+
+/* PCI Tuning Parameters
+   Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
+
+/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
+#define RX_FIFO_THRESH	7	/* Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST	7	/* Maximum PCI burst, '6' is 1024 */
+#define TX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
+#define TX_RETRY	8	/* 0-15.  retries = 16 + (TX_RETRY * 16) */
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (6*HZ)
+
+
+enum {
+	HAS_MII_XCVR = 0x010000,
+	HAS_CHIP_XCVR = 0x020000,
+	HAS_LNK_CHNG = 0x040000,
+};
+
+#define RTL_NUM_STATS 4		/* number of ETHTOOL_GSTATS u64's */
+#define RTL_REGS_VER 1		/* version of reg. data in ETHTOOL_GREGS */
+#define RTL_MIN_IO_SIZE 0x80
+#define RTL8139B_IO_SIZE 256
+
+#define RTL8129_CAPS	HAS_MII_XCVR
+#define RTL8139_CAPS	HAS_CHIP_XCVR|HAS_LNK_CHNG
+
+typedef enum {
+	RTL8139 = 0,
+	RTL8139_CB,
+	SMC1211TX,
+	/*MPX5030,*/
+	DELTA8139,
+	ADDTRON8139,
+	DFE538TX,
+	DFE690TXD,
+	FE2000VX,
+	ALLIED8139,
+	RTL8129,
+	FNW3603TX,
+	FNW3800TX,
+} board_t;
+
+
+/* indexed by board_t, above */
+static struct {
+	const char *name;
+	u32 hw_flags;
+} board_info[] __devinitdata = {
+	{ "RealTek RTL8139 Fast Ethernet", RTL8139_CAPS },
+	{ "RealTek RTL8139B PCI/CardBus", RTL8139_CAPS },
+	{ "SMC1211TX EZCard 10/100 (RealTek RTL8139)", RTL8139_CAPS },
+/*	{ MPX5030, "Accton MPX5030 (RealTek RTL8139)", RTL8139_CAPS },*/
+	{ "Delta Electronics 8139 10/100BaseTX", RTL8139_CAPS },
+	{ "Addtron Technolgy 8139 10/100BaseTX", RTL8139_CAPS },
+	{ "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS },
+	{ "D-Link DFE-690TXD (RealTek RTL8139)", RTL8139_CAPS },
+	{ "AboCom FE2000VX (RealTek RTL8139)", RTL8139_CAPS },
+	{ "Allied Telesyn 8139 CardBus", RTL8139_CAPS },
+	{ "RealTek RTL8129", RTL8129_CAPS },
+	{ "Planex FNW-3603-TX 10/100 CardBus", RTL8139_CAPS },
+	{ "Planex FNW-3800-TX 10/100 CardBus", RTL8139_CAPS },
+};
+
+
+static struct pci_device_id rtl8139_pci_tbl[] __devinitdata = {
+	{0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139_CB },
+	{0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX },
+/*	{0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },*/
+	{0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 },
+	{0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 },
+	{0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE538TX },
+	{0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE690TXD },
+	{0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FE2000VX },
+	{0x1259, 0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALLIED8139 },
+	{0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FNW3603TX },
+	{0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FNW3800TX },
+
+#ifdef CONFIG_8139TOO_8129
+	{0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
+#endif
+
+	/* some crazy cards report invalid vendor ids like
+	 * 0x0001 here.  The other ids are valid and constant,
+	 * so we simply don't match on the main vendor id.
+	 */
+	{PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 },
+	{PCI_ANY_ID, 0x8139, 0x1186, 0x1300, 0, 0, DFE538TX },
+	{PCI_ANY_ID, 0x8139, 0x13d1, 0xab06, 0, 0, FE2000VX },
+
+	{0,}
+};
+MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
+
+static struct {
+	const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+	{ "early_rx" },
+	{ "tx_buf_mapped" },
+	{ "tx_timeouts" },
+	{ "rx_lost_in_ring" },
+};
+
+/* The rest of these values should never change. */
+
+/* Symbolic offsets to registers. */
+enum RTL8139_registers {
+	MAC0 = 0,		/* Ethernet hardware address. */
+	MAR0 = 8,		/* Multicast filter. */
+	TxStatus0 = 0x10,	/* Transmit status (Four 32bit registers). */
+	TxAddr0 = 0x20,		/* Tx descriptors (also four 32bit). */
+	RxBuf = 0x30,
+	ChipCmd = 0x37,
+	RxBufPtr = 0x38,
+	RxBufAddr = 0x3A,
+	IntrMask = 0x3C,
+	IntrStatus = 0x3E,
+	TxConfig = 0x40,
+	ChipVersion = 0x43,
+	RxConfig = 0x44,
+	Timer = 0x48,		/* A general-purpose counter. */
+	RxMissed = 0x4C,	/* 24 bits valid, write clears. */
+	Cfg9346 = 0x50,
+	Config0 = 0x51,
+	Config1 = 0x52,
+	FlashReg = 0x54,
+	MediaStatus = 0x58,
+	Config3 = 0x59,
+	Config4 = 0x5A,		/* absent on RTL-8139A */
+	HltClk = 0x5B,
+	MultiIntr = 0x5C,
+	TxSummary = 0x60,
+	BasicModeCtrl = 0x62,
+	BasicModeStatus = 0x64,
+	NWayAdvert = 0x66,
+	NWayLPAR = 0x68,
+	NWayExpansion = 0x6A,
+	/* Undocumented registers, but required for proper operation. */
+	FIFOTMS = 0x70,		/* FIFO Control and test. */
+	CSCR = 0x74,		/* Chip Status and Configuration Register. */
+	PARA78 = 0x78,
+	PARA7c = 0x7c,		/* Magic transceiver parameter register. */
+	Config5 = 0xD8,		/* absent on RTL-8139A */
+};
+
+enum ClearBitMasks {
+	MultiIntrClear = 0xF000,
+	ChipCmdClear = 0xE2,
+	Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
+};
+
+enum ChipCmdBits {
+	CmdReset = 0x10,
+	CmdRxEnb = 0x08,
+	CmdTxEnb = 0x04,
+	RxBufEmpty = 0x01,
+};
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+	PCIErr = 0x8000,
+	PCSTimeout = 0x4000,
+	RxFIFOOver = 0x40,
+	RxUnderrun = 0x20,
+	RxOverflow = 0x10,
+	TxErr = 0x08,
+	TxOK = 0x04,
+	RxErr = 0x02,
+	RxOK = 0x01,
+
+	RxAckBits = RxFIFOOver | RxOverflow | RxOK,
+};
+
+enum TxStatusBits {
+	TxHostOwns = 0x2000,
+	TxUnderrun = 0x4000,
+	TxStatOK = 0x8000,
+	TxOutOfWindow = 0x20000000,
+	TxAborted = 0x40000000,
+	TxCarrierLost = 0x80000000,
+};
+enum RxStatusBits {
+	RxMulticast = 0x8000,
+	RxPhysical = 0x4000,
+	RxBroadcast = 0x2000,
+	RxBadSymbol = 0x0020,
+	RxRunt = 0x0010,
+	RxTooLong = 0x0008,
+	RxCRCErr = 0x0004,
+	RxBadAlign = 0x0002,
+	RxStatusOK = 0x0001,
+};
+
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+	AcceptErr = 0x20,
+	AcceptRunt = 0x10,
+	AcceptBroadcast = 0x08,
+	AcceptMulticast = 0x04,
+	AcceptMyPhys = 0x02,
+	AcceptAllPhys = 0x01,
+};
+
+/* Bits in TxConfig. */
+enum tx_config_bits {
+	TxIFG1 = (1 << 25),	/* Interframe Gap Time */
+	TxIFG0 = (1 << 24),	/* Enabling these bits violates IEEE 802.3 */
+	TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
+	TxCRC = (1 << 16),	/* DISABLE appending CRC to end of Tx packets */
+	TxClearAbt = (1 << 0),	/* Clear abort (WO) */
+	TxDMAShift = 8,		/* DMA burst value (0-7) is shifted this many bits */
+	TxRetryShift = 4,	/* TXRR value (0-15) is shifted this many bits */
+
+	TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
+};
+
+/* Bits in Config1 */
+enum Config1Bits {
+	Cfg1_PM_Enable = 0x01,
+	Cfg1_VPD_Enable = 0x02,
+	Cfg1_PIO = 0x04,
+	Cfg1_MMIO = 0x08,
+	LWAKE = 0x10,		/* not on 8139, 8139A */
+	Cfg1_Driver_Load = 0x20,
+	Cfg1_LED0 = 0x40,
+	Cfg1_LED1 = 0x80,
+	SLEEP = (1 << 1),	/* only on 8139, 8139A */
+	PWRDN = (1 << 0),	/* only on 8139, 8139A */
+};
+
+/* Bits in Config3 */
+enum Config3Bits {
+	Cfg3_FBtBEn    = (1 << 0), /* 1 = Fast Back to Back */
+	Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
+	Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
+	Cfg3_CardB_En  = (1 << 3), /* 1 = enable CardBus registers */
+	Cfg3_LinkUp    = (1 << 4), /* 1 = wake up on link up */
+	Cfg3_Magic     = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
+	Cfg3_PARM_En   = (1 << 6), /* 0 = software can set twister parameters */
+	Cfg3_GNTSel    = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
+};
+
+/* Bits in Config4 */
+enum Config4Bits {
+	LWPTN = (1 << 2),	/* not on 8139, 8139A */
+};
+
+/* Bits in Config5 */
+enum Config5Bits {
+	Cfg5_PME_STS     = (1 << 0), /* 1 = PCI reset resets PME_Status */
+	Cfg5_LANWake     = (1 << 1), /* 1 = enable LANWake signal */
+	Cfg5_LDPS        = (1 << 2), /* 0 = save power when link is down */
+	Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
+	Cfg5_UWF         = (1 << 4), /* 1 = accept unicast wakeup frame */
+	Cfg5_MWF         = (1 << 5), /* 1 = accept multicast wakeup frame */
+	Cfg5_BWF         = (1 << 6), /* 1 = accept broadcast wakeup frame */
+};
+
+enum RxConfigBits {
+	/* rx fifo threshold */
+	RxCfgFIFOShift = 13,
+	RxCfgFIFONone = (7 << RxCfgFIFOShift),
+
+	/* Max DMA burst */
+	RxCfgDMAShift = 8,
+	RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
+
+	/* rx ring buffer length */
+	RxCfgRcv8K = 0,
+	RxCfgRcv16K = (1 << 11),
+	RxCfgRcv32K = (1 << 12),
+	RxCfgRcv64K = (1 << 11) | (1 << 12),
+
+	/* Disable packet wrap at end of Rx buffer */
+	RxNoWrap = (1 << 7),
+};
+
+
+/* Twister tuning parameters from RealTek.
+   Completely undocumented, but required to tune bad links on some boards. */
+enum CSCRBits {
+	CSCR_LinkOKBit = 0x0400,
+	CSCR_LinkChangeBit = 0x0800,
+	CSCR_LinkStatusBits = 0x0f000,
+	CSCR_LinkDownOffCmd = 0x003c0,
+	CSCR_LinkDownCmd = 0x0f3c0,
+};
+
+
+enum Cfg9346Bits {
+	Cfg9346_Lock = 0x00,
+	Cfg9346_Unlock = 0xC0,
+};
+
+#ifdef CONFIG_8139TOO_TUNE_TWISTER
+
+enum TwisterParamVals {
+	PARA78_default	= 0x78fa8388,
+	PARA7c_default	= 0xcb38de43,	/* param[0][3] */
+	PARA7c_xxx	= 0xcb38de43,
+};
+
+static const unsigned long param[4][4] = {
+	{0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
+	{0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+	{0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+	{0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
+};
+
+#endif /* CONFIG_8139TOO_TUNE_TWISTER */
+
+typedef enum {
+	CH_8139 = 0,
+	CH_8139_K,
+	CH_8139A,
+	CH_8139B,
+	CH_8130,
+	CH_8139C,
+} chip_t;
+
+enum chip_flags {
+	HasHltClk = (1 << 0),
+	HasLWake = (1 << 1),
+};
+
+
+/* directly indexed by chip_t, above */
+const static struct {
+	const char *name;
+	u8 version; /* from RTL8139C docs */
+	u32 RxConfigMask; /* should clear the bits supported by this chip */
+	u32 flags;
+} rtl_chip_info[] = {
+	{ "RTL-8139",
+	  0x40,
+	  0xf0fe0040, /* XXX copied from RTL8139A, verify */
+	  HasHltClk,
+	},
+
+	{ "RTL-8139 rev K",
+	  0x60,
+	  0xf0fe0040,
+	  HasHltClk,
+	},
+
+	{ "RTL-8139A",
+	  0x70,
+	  0xf0fe0040,
+	  HasHltClk, /* XXX undocumented? */
+	},
+
+	{ "RTL-8139B",
+	  0x78,
+	  0xf0fc0040,
+	  HasLWake,
+	},
+
+	{ "RTL-8130",
+	  0x7C,
+	  0xf0fe0040, /* XXX copied from RTL8139A, verify */
+	  HasLWake,
+	},
+
+	{ "RTL-8139C",
+	  0x74,
+	  0xf0fc0040, /* XXX copied from RTL8139B, verify */
+	  HasLWake,
+	},
+
+};
+
+struct rtl_extra_stats {
+	unsigned long early_rx;
+	unsigned long tx_buf_mapped;
+	unsigned long tx_timeouts;
+	unsigned long rx_lost_in_ring;
+};
+
+struct rtl8139_private {
+	void *mmio_addr;
+	int drv_flags;
+	struct pci_dev *pci_dev;
+	struct net_device_stats stats;
+	unsigned char *rx_ring;
+	unsigned int cur_rx;	/* Index into the Rx buffer of next Rx pkt. */
+	unsigned int tx_flag;
+	unsigned long cur_tx;
+	unsigned long dirty_tx;
+	unsigned char *tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */
+	unsigned char *tx_bufs;	/* Tx bounce buffer region. */
+	dma_addr_t rx_ring_dma;
+	dma_addr_t tx_bufs_dma;
+	signed char phys[4];		/* MII device addresses. */
+	char twistie, twist_row, twist_col;	/* Twister tune state. */
+	unsigned int default_port:4;	/* Last dev->if_port value. */
+	spinlock_t lock;
+	chip_t chipset;
+	pid_t thr_pid;
+	wait_queue_head_t thr_wait;
+	struct completion thr_exited;
+	u32 rx_config;
+	struct rtl_extra_stats xstats;
+	int time_to_die;
+	struct mii_if_info mii;
+	unsigned int regs_len;
+};
+
+MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM (multicast_filter_limit, "i");
+MODULE_PARM (max_interrupt_work, "i");
+MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM (debug, "i");
+MODULE_PARM_DESC (debug, "8139too bitmapped message enable number");
+MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses");
+MODULE_PARM_DESC (max_interrupt_work, "8139too maximum events handled per interrupt");
+MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps");
+MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)");
+
+static int read_eeprom (void *ioaddr, int location, int addr_len);
+static int rtl8139_open (struct net_device *dev);
+static int mdio_read (struct net_device *dev, int phy_id, int location);
+static void mdio_write (struct net_device *dev, int phy_id, int location,
+			int val);
+static int rtl8139_thread (void *data);
+static void rtl8139_tx_timeout (struct net_device *dev);
+static void rtl8139_init_ring (struct net_device *dev);
+static int rtl8139_start_xmit (struct sk_buff *skb,
+			       struct net_device *dev);
+static void rtl8139_interrupt (int irq, void *dev_instance,
+			       struct pt_regs *regs);
+static void rt_rtl8139_interrupt(void);
+static int rtl8139_close (struct net_device *dev);
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
+static void rtl8139_set_rx_mode (struct net_device *dev);
+static void __set_rx_mode (struct net_device *dev);
+static void rtl8139_hw_start (struct net_device *dev);
+
+#ifdef USE_IO_OPS
+
+#define RTL_R8(reg)		inb (((unsigned long)ioaddr) + (reg))
+#define RTL_R16(reg)		inw (((unsigned long)ioaddr) + (reg))
+#define RTL_R32(reg)		((unsigned long) inl (((unsigned long)ioaddr) + (reg)))
+#define RTL_W8(reg, val8)	outb ((val8), ((unsigned long)ioaddr) + (reg))
+#define RTL_W16(reg, val16)	outw ((val16), ((unsigned long)ioaddr) + (reg))
+#define RTL_W32(reg, val32)	outl ((val32), ((unsigned long)ioaddr) + (reg))
+#define RTL_W8_F		RTL_W8
+#define RTL_W16_F		RTL_W16
+#define RTL_W32_F		RTL_W32
+#undef readb
+#undef readw
+#undef readl
+#undef writeb
+#undef writew
+#undef writel
+#define readb(addr) inb((unsigned long)(addr))
+#define readw(addr) inw((unsigned long)(addr))
+#define readl(addr) inl((unsigned long)(addr))
+#define writeb(val,addr) outb((val),(unsigned long)(addr))
+#define writew(val,addr) outw((val),(unsigned long)(addr))
+#define writel(val,addr) outl((val),(unsigned long)(addr))
+
+#else
+
+/* write MMIO register, with flush */
+/* Flush avoids rtl8139 bug w/ posted MMIO writes */
+#define RTL_W8_F(reg, val8)	do { writeb ((val8), ioaddr + (reg)); readb (ioaddr + (reg)); } while (0)
+#define RTL_W16_F(reg, val16)	do { writew ((val16), ioaddr + (reg)); readw (ioaddr + (reg)); } while (0)
+#define RTL_W32_F(reg, val32)	do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0)
+
+
+#define MMIO_FLUSH_AUDIT_COMPLETE 1
+#if MMIO_FLUSH_AUDIT_COMPLETE
+
+/* write MMIO register */
+#define RTL_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16)	writew ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32)	writel ((val32), ioaddr + (reg))
+
+#else
+
+/* write MMIO register, then flush */
+#define RTL_W8		RTL_W8_F
+#define RTL_W16		RTL_W16_F
+#define RTL_W32		RTL_W32_F
+
+#endif /* MMIO_FLUSH_AUDIT_COMPLETE */
+
+/* read MMIO register */
+#define RTL_R8(reg)		readb (ioaddr + (reg))
+#define RTL_R16(reg)		readw (ioaddr + (reg))
+#define RTL_R32(reg)		((unsigned long) readl (ioaddr + (reg)))
+
+#endif /* USE_IO_OPS */
+
+/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+#define ECATcard 1  // Diese Ethernetkarte wird für Ethercat verwendet
+
+//#define ECAT_DEBUG
+
+EtherCAT_device_t rtl_ecat_dev;
+
+/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static const u16 rtl8139_intr_mask =
+	PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
+	TxErr | TxOK | RxErr | RxOK;
+
+static const unsigned int rtl8139_rx_config =
+	RxCfgRcv32K | RxNoWrap |
+	(RX_FIFO_THRESH << RxCfgFIFOShift) |
+	(RX_DMA_BURST << RxCfgDMAShift);
+
+static const unsigned int rtl8139_tx_config =
+	(TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
+
+static void __rtl8139_cleanup_dev (struct net_device *dev)
+{
+	struct rtl8139_private *tp;
+	struct pci_dev *pdev;
+
+	assert (dev != NULL);
+	assert (dev->priv != NULL);
+
+	tp = dev->priv;
+	assert (tp->pci_dev != NULL);
+	pdev = tp->pci_dev;
+
+#ifndef USE_IO_OPS
+	if (tp->mmio_addr)
+		iounmap (tp->mmio_addr);
+#endif /* !USE_IO_OPS */
+
+	/* it's ok to call this even if we have no regions to free */
+	pci_release_regions (pdev);
+
+#ifndef RTL8139_NDEBUG
+	/* poison memory before freeing */
+	memset (dev, 0xBC,
+		sizeof (struct net_device) +
+		sizeof (struct rtl8139_private));
+#endif /* RTL8139_NDEBUG */
+
+	kfree (dev);
+
+	pci_set_drvdata (pdev, NULL);
+}
+
+
+static void rtl8139_chip_reset (void *ioaddr)
+{
+	int i;
+	int succ = 0 ;
+	/* Soft reset the chip. */
+	RTL_W8 (ChipCmd, CmdReset);
+
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--) {
+		barrier();
+		if ((RTL_R8 (ChipCmd) & CmdReset) == 0) {
+		    succ = 1;
+		    break;
+		}
+		udelay (10);
+	}
+	EC_DBG("rtl8139 chipreset");
+	if(succ == 0)
+	    EC_DBG("failed");
+	else
+	    EC_DBG("success at count %d",i);
+
+}
+
+
+static int __devinit rtl8139_init_board (struct pci_dev *pdev,
+					 struct net_device **dev_out)
+{
+	void *ioaddr;
+	struct net_device *dev;
+	struct rtl8139_private *tp;
+	u8 tmp8;
+	int rc;
+	unsigned int i;
+	u32 pio_start, pio_end, pio_flags, pio_len;
+	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+	u32 tmp;
+
+	assert (pdev != NULL);
+
+	*dev_out = NULL;
+
+	/* dev and dev->priv zeroed in alloc_etherdev */
+	dev = alloc_etherdev (sizeof (*tp));
+	if (dev == NULL) {
+		EC_DBG (KERN_ERR PFX "%s: Unable to alloc new net device\n", pdev->slot_name);
+		return -ENOMEM;
+	}
+	SET_MODULE_OWNER(dev);
+	tp = dev->priv;
+	tp->pci_dev = pdev;
+
+	/* enable device (incl. PCI PM wakeup and hotplug setup) */
+	rc = pci_enable_device (pdev);
+	if (rc)
+		goto err_out;
+
+	pio_start = pci_resource_start (pdev, 0);
+	pio_end = pci_resource_end (pdev, 0);
+	pio_flags = pci_resource_flags (pdev, 0);
+	pio_len = pci_resource_len (pdev, 0);
+
+	mmio_start = pci_resource_start (pdev, 1);
+	mmio_end = pci_resource_end (pdev, 1);
+	mmio_flags = pci_resource_flags (pdev, 1);
+	mmio_len = pci_resource_len (pdev, 1);
+
+	/* set this immediately, we need to know before
+	 * we talk to the chip directly */
+	DPRINTK("PIO region size == 0x%02X\n", pio_len);
+	DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);
+
+#ifdef USE_IO_OPS
+	/* make sure PCI base addr 0 is PIO */
+	if (!(pio_flags & IORESOURCE_IO)) {
+		EC_DBG (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pdev->slot_name);
+		rc = -ENODEV;
+		goto err_out;
+	}
+	/* check for weird/broken PCI region reporting */
+	if (pio_len < RTL_MIN_IO_SIZE) {
+		EC_DBG (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pdev->slot_name);
+		rc = -ENODEV;
+		goto err_out;
+	}
+#else
+	/* make sure PCI base addr 1 is MMIO */
+	if (!(mmio_flags & IORESOURCE_MEM)) {
+		EC_DBG (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pdev->slot_name);
+		rc = -ENODEV;
+		goto err_out;
+	}
+	if (mmio_len < RTL_MIN_IO_SIZE) {
+		EC_DBG (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pdev->slot_name);
+		rc = -ENODEV;
+		goto err_out;
+	}
+#endif
+
+	rc = pci_request_regions (pdev, "8139too");
+	if (rc)
+		goto err_out;
+
+	/* enable PCI bus-mastering */
+	pci_set_master (pdev);
+
+#ifdef USE_IO_OPS
+	ioaddr = (void *) pio_start;
+	dev->base_addr = pio_start;
+	tp->mmio_addr = ioaddr;
+	tp->regs_len = pio_len;
+#else
+	/* ioremap MMIO region */
+	ioaddr = ioremap (mmio_start, mmio_len);
+	if (ioaddr == NULL) {
+		EC_DBG (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pdev->slot_name);
+		rc = -EIO;
+		goto err_out;
+	}
+	dev->base_addr = (long) ioaddr;
+	tp->mmio_addr = ioaddr;
+	tp->regs_len = mmio_len;
+#endif /* USE_IO_OPS */
+
+	/* Bring old chips out of low-power mode. */
+	RTL_W8 (HltClk, 'R');
+
+	/* check for missing/broken hardware */
+	if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
+		EC_DBG (KERN_ERR PFX "%s: Chip not responding, ignoring board\n",
+			pdev->slot_name);
+		rc = -EIO;
+		goto err_out;
+	}
+
+	/* identify chip attached to board */
+	tmp = RTL_R8 (ChipVersion);
+	for (i = 0; i < ARRAY_SIZE (rtl_chip_info); i++)
+		if (tmp == rtl_chip_info[i].version) {
+			tp->chipset = i;
+			goto match;
+		}
+
+	/* if unknown chip, assume array element #0, original RTL-8139 in this case */
+	EC_DBG (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n",
+		pdev->slot_name);
+	EC_DBG (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pdev->slot_name, RTL_R32 (TxConfig));
+	tp->chipset = 0;
+
+match:
+	DPRINTK ("chipset id (%d) == index %d, '%s'\n",
+		tmp,
+		tp->chipset,
+		rtl_chip_info[tp->chipset].name);
+
+	if (tp->chipset >= CH_8139B) {
+		u8 new_tmp8 = tmp8 = RTL_R8 (Config1);
+		DPRINTK("PCI PM wakeup\n");
+		if ((rtl_chip_info[tp->chipset].flags & HasLWake) &&
+		    (tmp8 & LWAKE))
+			new_tmp8 &= ~LWAKE;
+		new_tmp8 |= Cfg1_PM_Enable;
+		if (new_tmp8 != tmp8) {
+			RTL_W8 (Cfg9346, Cfg9346_Unlock);
+			RTL_W8 (Config1, tmp8);
+			RTL_W8 (Cfg9346, Cfg9346_Lock);
+		}
+		if (rtl_chip_info[tp->chipset].flags & HasLWake) {
+			tmp8 = RTL_R8 (Config4);
+			if (tmp8 & LWPTN)
+				RTL_W8 (Config4, tmp8 & ~LWPTN);
+		}
+	} else {
+		DPRINTK("Old chip wakeup\n");
+		tmp8 = RTL_R8 (Config1);
+		tmp8 &= ~(SLEEP | PWRDN);
+		RTL_W8 (Config1, tmp8);
+	}
+
+	rtl8139_chip_reset (ioaddr);
+
+	*dev_out = dev;
+	return 0;
+
+err_out:
+	__rtl8139_cleanup_dev (dev);
+	return rc;
+}
+
+
+static int __devinit rtl8139_init_one (struct pci_dev *pdev,
+				       const struct pci_device_id *ent)
+{
+	struct net_device *dev = NULL;
+	struct rtl8139_private *tp;
+	int i, addr_len, option;
+	void *ioaddr;
+	static int board_idx = -1;
+	u8 pci_rev;
+
+	assert (pdev != NULL);
+	assert (ent != NULL);
+
+	board_idx++;
+
+
+	/* when we're built into the kernel, the driver version message
+	 * is only printed if at least one 8139 board has been found
+	 */
+#ifndef MODULE
+	{
+		static int printed_version;
+		if (!printed_version++)
+			EC_DBG (KERN_INFO RTL8139_DRIVER_NAME "\n");
+	}
+#endif
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
+
+	if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
+	    pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
+		EC_DBG(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
+		       pdev->slot_name, pdev->vendor, pdev->device, pci_rev);
+		EC_DBG(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
+	}
+
+	i = rtl8139_init_board (pdev, &dev);
+	if (i < 0)
+		return i;
+
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+	if (board_idx == ECATcard)
+        {
+          EC_DBG("EtherCAT registering board %d.\n", board_idx);
+
+          if (EtherCAT_device_assign(&rtl_ecat_dev, dev) < 0)
+            goto err_out;
+
+	  strcpy(dev->name,"ECAT");  //device name überschreiben
+	}
+
+	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+	tp = dev->priv;
+	ioaddr = tp->mmio_addr;
+
+	assert (ioaddr != NULL);
+	assert (dev != NULL);
+	assert (tp != NULL);
+
+	addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
+	for (i = 0; i < 3; i++)
+		((u16 *) (dev->dev_addr))[i] =
+		    le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len));
+
+	/* The Rtl8139-specific entries in the device structure. */
+	dev->open = rtl8139_open;
+	dev->hard_start_xmit = rtl8139_start_xmit;
+	dev->stop = rtl8139_close;
+	dev->get_stats = rtl8139_get_stats;
+	dev->set_multicast_list = rtl8139_set_rx_mode;
+	dev->do_ioctl = netdev_ioctl;
+	dev->tx_timeout = rtl8139_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
+
+	dev->irq = pdev->irq;
+
+	/* dev->priv/tp zeroed and aligned in init_etherdev */
+	tp = dev->priv;
+
+	/* note: tp->chipset set in rtl8139_init_board */
+	tp->drv_flags = board_info[ent->driver_data].hw_flags;
+	tp->mmio_addr = ioaddr;
+	spin_lock_init (&tp->lock);
+
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+	if (board_idx == ECATcard)
+        {
+          rtl_ecat_dev.lock = &tp->lock;
+	}
+
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+	init_waitqueue_head (&tp->thr_wait);
+	init_completion (&tp->thr_exited);
+	tp->mii.dev = dev;
+	tp->mii.mdio_read = mdio_read;
+	tp->mii.mdio_write = mdio_write;
+	tp->mii.phy_id_mask = 0x3f;
+	tp->mii.reg_num_mask = 0x1f;
+
+	/* dev is fully set up and ready to use now */
+
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+	/* EtherCAT-Karten nicht beim Stack anmelden. */
+        if (dev != rtl_ecat_dev.dev)
+	{
+          DPRINTK("About to register device named %s (%p)...\n", dev->name, dev);
+          i = register_netdev (dev);
+          if (i) goto err_out;
+	}
+
+	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+	pci_set_drvdata (pdev, dev);
+
+	EC_DBG (KERN_INFO "%s: %s at 0x%lx, "
+		"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+		"IRQ %d\n",
+		dev->name,
+		board_info[ent->driver_data].name,
+		dev->base_addr,
+		dev->dev_addr[0], dev->dev_addr[1],
+		dev->dev_addr[2], dev->dev_addr[3],
+		dev->dev_addr[4], dev->dev_addr[5],
+		dev->irq);
+
+	EC_DBG (KERN_DEBUG "%s:  Identified 8139 chip type '%s'\n",
+		dev->name, rtl_chip_info[tp->chipset].name);
+
+	/* Find the connected MII xcvrs.
+	   Doing this in open() would allow detecting external xcvrs later, but
+	   takes too much time. */
+#ifdef CONFIG_8139TOO_8129
+	if (tp->drv_flags & HAS_MII_XCVR) {
+		int phy, phy_idx = 0;
+		for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {
+			int mii_status = mdio_read(dev, phy, 1);
+			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+				u16 advertising = mdio_read(dev, phy, 4);
+				tp->phys[phy_idx++] = phy;
+				EC_DBG(KERN_INFO "%s: MII transceiver %d status 0x%4.4x "
+					   "advertising %4.4x.\n",
+					   dev->name, phy, mii_status, advertising);
+			}
+		}
+		if (phy_idx == 0) {
+			EC_DBG(KERN_INFO "%s: No MII transceivers found!  Assuming SYM "
+				   "transceiver.\n",
+				   dev->name);
+			tp->phys[0] = 32;
+		}
+	} else
+#endif
+		tp->phys[0] = 32;
+	tp->mii.phy_id = tp->phys[0];
+
+	/* The lower four bits are the media type. */
+	option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
+	if (option > 0) {
+		tp->mii.full_duplex = (option & 0x210) ? 1 : 0;
+		tp->default_port = option & 0xFF;
+		if (tp->default_port)
+			tp->mii.force_media = 1;
+	}
+	if (board_idx < MAX_UNITS  &&  full_duplex[board_idx] > 0)
+		tp->mii.full_duplex = full_duplex[board_idx];
+	if (tp->mii.full_duplex) {
+		EC_DBG(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+		/* Changing the MII-advertised media because might prevent
+		   re-connection. */
+		tp->mii.force_media = 1;
+	}
+	if (tp->default_port) {
+		EC_DBG(KERN_INFO "  Forcing %dMbps %s-duplex operation.\n",
+			   (option & 0x20 ? 100 : 10),
+			   (option & 0x10 ? "full" : "half"));
+		mdio_write(dev, tp->phys[0], 0,
+				   ((option & 0x20) ? 0x2000 : 0) | 	/* 100Mbps? */
+				   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
+	}
+
+	/* Put the chip into low-power mode. */
+	if (rtl_chip_info[tp->chipset].flags & HasHltClk)
+		RTL_W8 (HltClk, 'H');	/* 'R' would leave the clock running. */
+
+	return 0;
+
+err_out:
+	__rtl8139_cleanup_dev (dev);
+	return i;
+}
+
+
+static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	struct rtl8139_private *np;
+
+	assert (dev != NULL);
+	np = dev->priv;
+	assert (np != NULL);
+	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+	/* EtherCATkarten nicht beim Stack angemeldet */
+        if (dev != rtl_ecat_dev.dev) {
+	    unregister_netdev (dev);
+	}
+	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+	__rtl8139_cleanup_dev (dev);
+}
+
+
+/* Serial EEPROM section. */
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
+#define EE_CS			0x08	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */
+#define EE_WRITE_0		0x00
+#define EE_WRITE_1		0x02
+#define EE_DATA_READ	0x01	/* EEPROM chip data out. */
+#define EE_ENB			(0x80 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
+ */
+
+#define eeprom_delay()	readl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5)
+#define EE_READ_CMD		(6)
+#define EE_ERASE_CMD	(7)
+
+static int __devinit read_eeprom (void *ioaddr, int location, int addr_len)
+{
+	int i;
+	unsigned retval = 0;
+	void *ee_addr = ioaddr + Cfg9346;
+	int read_cmd = location | (EE_READ_CMD << addr_len);
+
+	writeb (EE_ENB & ~EE_CS, ee_addr);
+	writeb (EE_ENB, ee_addr);
+	eeprom_delay ();
+
+	/* Shift the read command bits out. */
+	for (i = 4 + addr_len; i >= 0; i--) {
+		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		writeb (EE_ENB | dataval, ee_addr);
+		eeprom_delay ();
+		writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay ();
+	}
+	writeb (EE_ENB, ee_addr);
+	eeprom_delay ();
+
+	for (i = 16; i > 0; i--) {
+		writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay ();
+		retval =
+		    (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 :
+				     0);
+		writeb (EE_ENB, ee_addr);
+		eeprom_delay ();
+	}
+
+	/* Terminate the EEPROM access. */
+	writeb (~EE_CS, ee_addr);
+	eeprom_delay ();
+
+	return retval;
+}
+
+/* MII serial management: mostly bogus for now. */
+/* Read and write the MII management registers using software-generated
+   serial MDIO protocol.
+   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues. */
+#define MDIO_DIR		0x80
+#define MDIO_DATA_OUT	0x04
+#define MDIO_DATA_IN	0x02
+#define MDIO_CLK		0x01
+#define MDIO_WRITE0 (MDIO_DIR)
+#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
+
+#define mdio_delay(mdio_addr)	readb(mdio_addr)
+
+
+static char mii_2_8139_map[8] = {
+	BasicModeCtrl,
+	BasicModeStatus,
+	0,
+	0,
+	NWayAdvert,
+	NWayLPAR,
+	NWayExpansion,
+	0
+};
+
+
+#ifdef CONFIG_8139TOO_8129
+/* Syncronize the MII management interface by shifting 32 one bits out. */
+static void mdio_sync (void *mdio_addr)
+{
+	int i;
+
+	for (i = 32; i >= 0; i--) {
+		writeb (MDIO_WRITE1, mdio_addr);
+		mdio_delay (mdio_addr);
+		writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr);
+		mdio_delay (mdio_addr);
+	}
+}
+#endif
+
+static int mdio_read (struct net_device *dev, int phy_id, int location)
+{
+	struct rtl8139_private *tp = dev->priv;
+	int retval = 0;
+#ifdef CONFIG_8139TOO_8129
+	void *mdio_addr = tp->mmio_addr + Config4;
+	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	int i;
+#endif
+
+	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
+		return location < 8 && mii_2_8139_map[location] ?
+		    readw (tp->mmio_addr + mii_2_8139_map[location]) : 0;
+	}
+
+#ifdef CONFIG_8139TOO_8129
+	mdio_sync (mdio_addr);
+	/* Shift the read command bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
+
+		writeb (MDIO_DIR | dataval, mdio_addr);
+		mdio_delay (mdio_addr);
+		writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
+		mdio_delay (mdio_addr);
+	}
+
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		writeb (0, mdio_addr);
+		mdio_delay (mdio_addr);
+		retval = (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 : 0);
+		writeb (MDIO_CLK, mdio_addr);
+		mdio_delay (mdio_addr);
+	}
+#endif
+
+	return (retval >> 1) & 0xffff;
+}
+
+
+static void mdio_write (struct net_device *dev, int phy_id, int location,
+			int value)
+{
+	struct rtl8139_private *tp = dev->priv;
+#ifdef CONFIG_8139TOO_8129
+	void *mdio_addr = tp->mmio_addr + Config4;
+	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
+	int i;
+#endif
+
+	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
+		void *ioaddr = tp->mmio_addr;
+		if (location == 0) {
+			RTL_W8 (Cfg9346, Cfg9346_Unlock);
+			RTL_W16 (BasicModeCtrl, value);
+			RTL_W8 (Cfg9346, Cfg9346_Lock);
+		} else if (location < 8 && mii_2_8139_map[location])
+			RTL_W16 (mii_2_8139_map[location], value);
+		return;
+	}
+
+#ifdef CONFIG_8139TOO_8129
+	mdio_sync (mdio_addr);
+
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval =
+		    (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+		writeb (dataval, mdio_addr);
+		mdio_delay (mdio_addr);
+		writeb (dataval | MDIO_CLK, mdio_addr);
+		mdio_delay (mdio_addr);
+	}
+	/* Clear out extra bits. */
+	for (i = 2; i > 0; i--) {
+		writeb (0, mdio_addr);
+		mdio_delay (mdio_addr);
+		writeb (MDIO_CLK, mdio_addr);
+		mdio_delay (mdio_addr);
+	}
+#endif
+}
+
+
+static int rtl8139_open (struct net_device *dev)
+{
+	struct rtl8139_private *tp = dev->priv;
+	int retval;
+#ifdef RTL8139_DEBUG
+	void *ioaddr = tp->mmio_addr;
+#endif
+
+        EC_DBG(KERN_DEBUG "%s: open\n", dev->name);
+
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+        if (dev != rtl_ecat_dev.dev) 
+
+	    retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev);
+	else  {//ist Ethercatcard
+	    //rt_disable_irq(dev->irq);
+          retval =  rt_request_global_irq (dev->irq,rt_rtl8139_interrupt);
+	  //rt_enable_irq(dev->irq);
+        }
+        if (retval)
+          return retval;
+
+	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+	tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+					   &tp->tx_bufs_dma);
+	tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+					   &tp->rx_ring_dma);
+	if (tp->tx_bufs == NULL || tp->rx_ring == NULL)
+        {
+          /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+          if (dev != rtl_ecat_dev.dev) 
+            free_irq(dev->irq, dev);
+          else
+            rt_free_global_irq (dev->irq);
+          
+          /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+          if (tp->tx_bufs)
+            pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+                                tp->tx_bufs, tp->tx_bufs_dma);
+          if (tp->rx_ring)
+            pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+                                tp->rx_ring, tp->rx_ring_dma);
+          
+          return -ENOMEM;
+
+	}
+
+	tp->mii.full_duplex = tp->mii.force_media;
+	tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
+	tp->twistie = (tp->chipset == CH_8139_K) ? 1 : 0;
+	tp->time_to_die = 0;
+
+	rtl8139_init_ring (dev);
+	rtl8139_hw_start (dev);
+
+	DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d"
+			" GP Pins %2.2x %s-duplex.\n",
+			dev->name, pci_resource_start (tp->pci_dev, 1),
+			dev->irq, RTL_R8 (MediaStatus),
+			tp->mii.full_duplex ? "full" : "half");
+
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+        if (dev != rtl_ecat_dev.dev)
+        {
+          EC_DBG(KERN_DEBUG "%s: starting kernel thread...\n", dev->name);
+          tp->thr_pid = kernel_thread (rtl8139_thread, dev, CLONE_FS | CLONE_FILES);
+
+          if (tp->thr_pid < 0)
+            EC_DBG (KERN_WARNING "%s: unable to start kernel thread\n",
+                    dev->name);
+	}
+#if 0
+        else
+        {
+          rt_enable_irq(dev->irq);
+        }
+#endif
+
+	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+        EC_DBG(KERN_DEBUG "%s: open finished.\n", dev->name);
+
+	return 0;
+}
+
+
+static void rtl_check_media (struct net_device *dev)
+{
+	struct rtl8139_private *tp = dev->priv;
+
+	if (tp->phys[0] >= 0) {
+		u16 mii_lpa = mdio_read(dev, tp->phys[0], MII_LPA);
+		if (mii_lpa == 0xffff)
+			;					/* Not there */
+		else if ((mii_lpa & LPA_100FULL) == LPA_100FULL
+				 || (mii_lpa & 0x00C0) == LPA_10FULL)
+			tp->mii.full_duplex = 1;
+
+		EC_DBG (KERN_INFO "%s: Setting %s%s-duplex based on"
+                        " auto-negotiated partner ability %4.4x.\n",
+		        dev->name, mii_lpa == 0 ? "" :
+                        (mii_lpa & 0x0180) ? "100mbps " : "10mbps ",
+			tp->mii.full_duplex ? "full" : "half", mii_lpa);
+	}
+        EC_DBG(KERN_DEBUG "rtl_check_media done.\n");
+}
+
+/* Start the hardware at open or resume. */
+static void rtl8139_hw_start (struct net_device *dev)
+{
+	struct rtl8139_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	u32 i;
+	u8 tmp;
+
+        EC_DBG(KERN_DEBUG "%s: rtl8139_hw_start\n", dev->name);
+
+	/* Bring old chips out of low-power mode. */
+	if (rtl_chip_info[tp->chipset].flags & HasHltClk)
+		RTL_W8 (HltClk, 'R');
+
+	rtl8139_chip_reset (ioaddr);
+
+	/* unlock Config[01234] and BMCR register writes */
+	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+	/* Restore our idea of the MAC address. */
+	RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
+	RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+
+	/* Must enable Tx/Rx before setting transfer thresholds! */
+	RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+	tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
+	RTL_W32 (RxConfig, tp->rx_config);
+
+	/* Check this value: the documentation for IFG contradicts ifself. */
+	RTL_W32 (TxConfig, rtl8139_tx_config);
+
+	tp->cur_rx = 0;
+
+	rtl_check_media (dev);
+
+	if (tp->chipset >= CH_8139B) {
+		/* Disable magic packet scanning, which is enabled
+		 * when PM is enabled in Config1.  It can be reenabled
+		 * via ETHTOOL_SWOL if desired.  */
+		RTL_W8 (Config3, RTL_R8 (Config3) & ~Cfg3_Magic);
+	}
+
+	DPRINTK("init buffer addresses\n");
+
+	/* Lock Config[01234] and BMCR register writes */
+	RTL_W8 (Cfg9346, Cfg9346_Lock);
+
+	/* init Rx ring buffer DMA address */
+	RTL_W32_F (RxBuf, tp->rx_ring_dma);
+
+	/* init Tx buffer DMA addresses */
+	for (i = 0; i < NUM_TX_DESC; i++)
+		RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs));
+
+	RTL_W32 (RxMissed, 0);
+
+	rtl8139_set_rx_mode (dev);
+
+	/* no early-rx interrupts */
+	RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear);
+
+	/* make sure RxTx has started */
+	tmp = RTL_R8 (ChipCmd);
+	if ((!(tmp & CmdRxEnb)) || (!(tmp & CmdTxEnb)))
+		RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+	/* Enable all known interrupts by setting the interrupt mask. */
+	RTL_W16 (IntrMask, rtl8139_intr_mask);
+
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+        if (dev != rtl_ecat_dev.dev) netif_start_queue (dev);
+	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/        
+
+        EC_DBG(KERN_DEBUG "%s: rtl8139_hw_start finished.\n", dev->name);
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void rtl8139_init_ring (struct net_device *dev)
+{
+	struct rtl8139_private *tp = dev->priv;
+	int i;
+
+	tp->cur_rx = 0;
+	tp->cur_tx = 0;
+	tp->dirty_tx = 0;
+
+	for (i = 0; i < NUM_TX_DESC; i++)
+		tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
+}
+
+
+/* This must be global for CONFIG_8139TOO_TUNE_TWISTER case */
+static int next_tick = 3 * HZ;
+
+#ifndef CONFIG_8139TOO_TUNE_TWISTER
+static inline void rtl8139_tune_twister (struct net_device *dev,
+				  struct rtl8139_private *tp) {}
+#else
+static void rtl8139_tune_twister (struct net_device *dev,
+				  struct rtl8139_private *tp)
+{
+	int linkcase;
+	void *ioaddr = tp->mmio_addr;
+
+	/* This is a complicated state machine to configure the "twister" for
+	   impedance/echos based on the cable length.
+	   All of this is magic and undocumented.
+	 */
+	switch (tp->twistie) {
+	case 1:
+		if (RTL_R16 (CSCR) & CSCR_LinkOKBit) {
+			/* We have link beat, let us tune the twister. */
+			RTL_W16 (CSCR, CSCR_LinkDownOffCmd);
+			tp->twistie = 2;	/* Change to state 2. */
+			next_tick = HZ / 10;
+		} else {
+			/* Just put in some reasonable defaults for when beat returns. */
+			RTL_W16 (CSCR, CSCR_LinkDownCmd);
+			RTL_W32 (FIFOTMS, 0x20);	/* Turn on cable test mode. */
+			RTL_W32 (PARA78, PARA78_default);
+			RTL_W32 (PARA7c, PARA7c_default);
+			tp->twistie = 0;	/* Bail from future actions. */
+		}
+		break;
+	case 2:
+		/* Read how long it took to hear the echo. */
+		linkcase = RTL_R16 (CSCR) & CSCR_LinkStatusBits;
+		if (linkcase == 0x7000)
+			tp->twist_row = 3;
+		else if (linkcase == 0x3000)
+			tp->twist_row = 2;
+		else if (linkcase == 0x1000)
+			tp->twist_row = 1;
+		else
+			tp->twist_row = 0;
+		tp->twist_col = 0;
+		tp->twistie = 3;	/* Change to state 2. */
+		next_tick = HZ / 10;
+		break;
+	case 3:
+		/* Put out four tuning parameters, one per 100msec. */
+		if (tp->twist_col == 0)
+			RTL_W16 (FIFOTMS, 0);
+		RTL_W32 (PARA7c, param[(int) tp->twist_row]
+			 [(int) tp->twist_col]);
+		next_tick = HZ / 10;
+		if (++tp->twist_col >= 4) {
+			/* For short cables we are done.
+			   For long cables (row == 3) check for mistune. */
+			tp->twistie =
+			    (tp->twist_row == 3) ? 4 : 0;
+		}
+		break;
+	case 4:
+		/* Special case for long cables: check for mistune. */
+		if ((RTL_R16 (CSCR) &
+		     CSCR_LinkStatusBits) == 0x7000) {
+			tp->twistie = 0;
+			break;
+		} else {
+			RTL_W32 (PARA7c, 0xfb38de03);
+			tp->twistie = 5;
+			next_tick = HZ / 10;
+		}
+		break;
+	case 5:
+		/* Retune for shorter cable (column 2). */
+		RTL_W32 (FIFOTMS, 0x20);
+		RTL_W32 (PARA78, PARA78_default);
+		RTL_W32 (PARA7c, PARA7c_default);
+		RTL_W32 (FIFOTMS, 0x00);
+		tp->twist_row = 2;
+		tp->twist_col = 0;
+		tp->twistie = 3;
+		next_tick = HZ / 10;
+		break;
+
+	default:
+		/* do nothing */
+		break;
+	}
+}
+#endif /* CONFIG_8139TOO_TUNE_TWISTER */
+
+
+static inline void rtl8139_thread_iter (struct net_device *dev,
+				 struct rtl8139_private *tp,
+				 void *ioaddr)
+{
+	int mii_lpa;
+
+	mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
+
+	if (!tp->mii.force_media && mii_lpa != 0xffff) {
+		int duplex = (mii_lpa & LPA_100FULL)
+		    || (mii_lpa & 0x01C0) == 0x0040;
+		if (tp->mii.full_duplex != duplex) {
+			tp->mii.full_duplex = duplex;
+
+			if (mii_lpa) {
+				EC_DBG (KERN_INFO
+					"%s: Setting %s-duplex based on MII #%d link"
+					" partner ability of %4.4x.\n",
+					dev->name,
+					tp->mii.full_duplex ? "full" : "half",
+					tp->phys[0], mii_lpa);
+			} else {
+				EC_DBG(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n",
+				       dev->name);
+			}
+#if 0
+			RTL_W8 (Cfg9346, Cfg9346_Unlock);
+			RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20);
+			RTL_W8 (Cfg9346, Cfg9346_Lock);
+#endif
+		}
+	}
+
+	next_tick = HZ * 60;
+
+	rtl8139_tune_twister (dev, tp);
+
+	DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
+		 dev->name, RTL_R16 (NWayLPAR));
+	DPRINTK ("%s:  Other registers are IntMask %4.4x IntStatus %4.4x\n",
+		 dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus));
+	DPRINTK ("%s:  Chip config %2.2x %2.2x.\n",
+		 dev->name, RTL_R8 (Config0),
+		 RTL_R8 (Config1));
+}
+
+
+static int rtl8139_thread (void *data)
+{
+	struct net_device *dev = data;
+	struct rtl8139_private *tp = dev->priv;
+	unsigned long timeout;
+
+        EC_DBG(KERN_DEBUG "%s: thread\n", dev->name);
+
+	daemonize ();
+	reparent_to_init();
+	spin_lock_irq(&current->sigmask_lock);
+	sigemptyset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	strncpy (current->comm, dev->name, sizeof(current->comm) - 1);
+	current->comm[sizeof(current->comm) - 1] = '\0';
+
+        EC_DBG(KERN_DEBUG "%s: thread entering loop...\n", dev->name);
+
+	while (1) {
+		timeout = next_tick;
+		do {
+			timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
+		} while (!signal_pending (current) && (timeout > 0));
+
+		if (signal_pending (current)) {
+			spin_lock_irq(&current->sigmask_lock);
+			flush_signals(current);
+			spin_unlock_irq(&current->sigmask_lock);
+		}
+
+		if (tp->time_to_die)
+			break;
+
+		rtnl_lock ();
+                EC_DBG(KERN_DEBUG "%s: thread iter\n", dev->name);
+		rtl8139_thread_iter (dev, tp, tp->mmio_addr);
+                EC_DBG(KERN_DEBUG "%s: thread iter finished.\n", dev->name);
+		rtnl_unlock ();
+	}
+
+        EC_DBG(KERN_DEBUG "%s: thread exiting...\n", dev->name);
+
+	complete_and_exit (&tp->thr_exited, 0);
+
+        EC_DBG(KERN_DEBUG "%s: thread exit.\n", dev->name);
+}
+
+
+static void rtl8139_tx_clear (struct rtl8139_private *tp)
+{
+	tp->cur_tx = 0;
+	tp->dirty_tx = 0;
+
+	/* XXX account for unsent Tx packets in tp->stats.tx_dropped */
+}
+
+
+static void rtl8139_tx_timeout (struct net_device *dev)
+{
+	struct rtl8139_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int i;
+	u8 tmp8;
+	unsigned long flags;
+
+        EC_DBG(KERN_DEBUG "%s: tx_timeout\n", dev->name);
+
+	DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x "
+		 "media %2.2x.\n", dev->name,
+		 RTL_R8 (ChipCmd),
+		 RTL_R16 (IntrStatus),
+		 RTL_R8 (MediaStatus));
+
+	tp->xstats.tx_timeouts++;
+
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+        if (dev == rtl_ecat_dev.dev)
+        {
+          if (rtl_ecat_dev.state != ECAT_DS_SENT)
+          {
+            EC_DBG(KERN_WARNING "EtherCAT: Wrong status at timeout!\n");
+          }
+          else
+          {
+            rtl_ecat_dev.state = ECAT_DS_TIMEOUT;
+          }
+        }
+
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+	/* disable Tx ASAP, if not already */
+	tmp8 = RTL_R8 (ChipCmd);
+	if (tmp8 & CmdTxEnb)
+		RTL_W8 (ChipCmd, CmdRxEnb);
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	RTL_W16 (IntrMask, 0x0000);
+
+	/* Emit info to figure out what went wrong. */
+	EC_DBG (KERN_DEBUG "%s: Tx queue start entry %ld  dirty entry %ld.\n",
+		dev->name, tp->cur_tx, tp->dirty_tx);
+	for (i = 0; i < NUM_TX_DESC; i++)
+		EC_DBG (KERN_DEBUG "%s:  Tx descriptor %d is %8.8lx.%s\n",
+			dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),
+			i == (int) (tp->dirty_tx % NUM_TX_DESC) ?
+				" (queue head)" : "");
+
+	/* Stop a shared interrupt from scavenging while we are. */
+	if(dev == rtl_ecat_dev.dev) {
+	    flags = rt_spin_lock_irqsave (&tp->lock);
+	    rtl8139_tx_clear (tp);
+	    rt_spin_unlock_irqrestore (&tp->lock,flags);
+	}
+	else {
+	    spin_lock_irqsave (&tp->lock, flags);
+	    rtl8139_tx_clear (tp);
+	    spin_unlock_irqrestore (&tp->lock, flags);
+	}
+	/* ...and finally, reset everything */
+	rtl8139_hw_start (dev);
+
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+        if (dev != rtl_ecat_dev.dev) netif_wake_queue (dev);
+	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+        EC_DBG(KERN_DEBUG "%s: tx_timeout finished.\n", dev->name);
+}
+
+static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+	struct rtl8139_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	unsigned int entry;
+	unsigned int len = skb->len;
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = tp->cur_tx % NUM_TX_DESC;
+
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+	if (likely(len < TX_BUF_SIZE))
+        {
+          skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
+
+          // Socket buffer nicht löschen, wenn vom EtherCAT-device
+          if (dev != rtl_ecat_dev.dev) dev_kfree_skb(skb); 
+	}
+        else
+        {
+          if (dev != rtl_ecat_dev.dev) dev_kfree_skb(skb);
+          tp->stats.tx_dropped++;
+          return 0;
+	}
+
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+	/* Note: the chip doesn't have auto-pad! */
+	if(dev == rtl_ecat_dev.dev)
+	    rt_spin_lock_irq(&tp->lock);
+	else
+	    spin_lock_irq(&tp->lock);
+
+	RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
+		   tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
+
+	dev->trans_start = jiffies;
+
+	tp->cur_tx++;
+	wmb();
+
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+	if (dev != rtl_ecat_dev.dev && ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx))
+          netif_stop_queue (dev);
+
+	/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+	if(dev == rtl_ecat_dev.dev)
+	    rt_spin_unlock_irq(&tp->lock);
+	else
+	    spin_unlock_irq(&tp->lock);
+	DPRINTK ("%s: Queued Tx packet size %u to slot %d.\n",
+		 dev->name, len, entry);
+
+	return 0;
+}
+
+
+static void rtl8139_tx_interrupt (struct net_device *dev,
+				  struct rtl8139_private *tp,
+				  void *ioaddr)
+{
+	unsigned long dirty_tx, tx_left;
+
+	assert (dev != NULL);
+	assert (tp != NULL);
+	assert (ioaddr != NULL);
+
+	dirty_tx = tp->dirty_tx;
+	tx_left = tp->cur_tx - dirty_tx;
+
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+	if (dev == rtl_ecat_dev.dev) {
+	    (rtl_ecat_dev.tx_intr_cnt)++;
+	    rdtscl(rtl_ecat_dev.tx_time); // Get CPU cycles
+	}
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+	while (tx_left > 0) {
+		int entry = dirty_tx % NUM_TX_DESC;
+		int txstatus;
+
+		txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32)));
+
+		if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
+			break;	/* It still hasn't been Txed */
+
+		/* Note: TxCarrierLost is always asserted at 100mbps. */
+		if (txstatus & (TxOutOfWindow | TxAborted)) {
+			/* There was an major error, log it. */
+			DPRINTK ("%s: Transmit error, Tx status %8.8x.\n",
+				 dev->name, txstatus);
+			tp->stats.tx_errors++;
+			if (txstatus & TxAborted) {
+				tp->stats.tx_aborted_errors++;
+				RTL_W32 (TxConfig, TxClearAbt);
+				RTL_W16 (IntrStatus, TxErr);
+				wmb();
+			}
+			if (txstatus & TxCarrierLost)
+				tp->stats.tx_carrier_errors++;
+			if (txstatus & TxOutOfWindow)
+				tp->stats.tx_window_errors++;
+
+                        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+                        
+                        if (dev == rtl_ecat_dev.dev)
+                        {
+                          rtl_ecat_dev.state = ECAT_DS_ERROR;
+                        }
+                        
+                        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+		} else {
+			if (txstatus & TxUnderrun) {
+				/* Add 64 to the Tx FIFO threshold. */
+				if (tp->tx_flag < 0x00300000)
+					tp->tx_flag += 0x00020000;
+				tp->stats.tx_fifo_errors++;
+			}
+			tp->stats.collisions += (txstatus >> 24) & 15;
+			tp->stats.tx_bytes += txstatus & 0x7ff;
+			tp->stats.tx_packets++;
+		}
+
+		dirty_tx++;
+		tx_left--;
+	}
+
+#ifndef RTL8139_NDEBUG
+	if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
+		EC_DBG (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
+		        dev->name, dirty_tx, tp->cur_tx);
+		dirty_tx += NUM_TX_DESC;
+	}
+#endif /* RTL8139_NDEBUG */
+
+	/* only wake the queue if we did work, and the queue is stopped */
+	if (tp->dirty_tx != dirty_tx) {
+		tp->dirty_tx = dirty_tx;
+		mb();
+
+                /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+		if (dev != rtl_ecat_dev.dev && netif_queue_stopped (dev))
+                  netif_wake_queue (dev);
+
+                /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+	}
+}
+
+
+/* TODO: clean this up!  Rx reset need not be this intensive */
+static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
+			    struct rtl8139_private *tp, void *ioaddr)
+{
+	u8 tmp8;
+#ifdef CONFIG_8139_OLD_RX_RESET
+	int tmp_work;
+#endif
+
+	DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n",
+	         dev->name, rx_status);
+	tp->stats.rx_errors++;
+	if (!(rx_status & RxStatusOK)) {
+		if (rx_status & RxTooLong) {
+			DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",
+			 	dev->name, rx_status);
+			/* A.C.: The chip hangs here. */
+		}
+		if (rx_status & (RxBadSymbol | RxBadAlign))
+			tp->stats.rx_frame_errors++;
+		if (rx_status & (RxRunt | RxTooLong))
+			tp->stats.rx_length_errors++;
+		if (rx_status & RxCRCErr)
+			tp->stats.rx_crc_errors++;
+	} else {
+		tp->xstats.rx_lost_in_ring++;
+	}
+
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+                        
+        if (dev == rtl_ecat_dev.dev)
+        {
+          rtl_ecat_dev.state = ECAT_DS_ERROR;
+        }
+                        
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+#ifndef CONFIG_8139_OLD_RX_RESET
+	tmp8 = RTL_R8 (ChipCmd);
+	RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb);
+	RTL_W8 (ChipCmd, tmp8);
+	RTL_W32 (RxConfig, tp->rx_config);
+	tp->cur_rx = 0;
+#else
+	/* Reset the receiver, based on RealTek recommendation. (Bug?) */
+
+	/* disable receive */
+	RTL_W8_F (ChipCmd, CmdTxEnb);
+	tmp_work = 200;
+	while (--tmp_work > 0) {
+		udelay(1);
+		tmp8 = RTL_R8 (ChipCmd);
+		if (!(tmp8 & CmdRxEnb))
+			break;
+	}
+	if (tmp_work <= 0)
+		EC_DBG (KERN_WARNING PFX "rx stop wait too long\n");
+	/* restart receive */
+	tmp_work = 200;
+	while (--tmp_work > 0) {
+		RTL_W8_F (ChipCmd, CmdRxEnb | CmdTxEnb);
+		udelay(1);
+		tmp8 = RTL_R8 (ChipCmd);
+		if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
+			break;
+	}
+	if (tmp_work <= 0)
+		EC_DBG (KERN_WARNING PFX "tx/rx enable wait too long\n");
+
+	/* and reinitialize all rx related registers */
+	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+	/* Must enable Tx/Rx before setting transfer thresholds! */
+	RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+	tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
+	RTL_W32 (RxConfig, tp->rx_config);
+	tp->cur_rx = 0;
+
+	DPRINTK("init buffer addresses\n");
+
+	/* Lock Config[01234] and BMCR register writes */
+	RTL_W8 (Cfg9346, Cfg9346_Lock);
+
+	/* init Rx ring buffer DMA address */
+	RTL_W32_F (RxBuf, tp->rx_ring_dma);
+
+	/* A.C.: Reset the multicast list. */
+	__set_rx_mode (dev);
+#endif
+}
+
+static void rtl8139_rx_interrupt (struct net_device *dev,
+				  struct rtl8139_private *tp, void *ioaddr)
+{
+	unsigned char *rx_ring;
+	u16 cur_rx;
+
+	assert (dev != NULL);
+	assert (tp != NULL);
+	assert (ioaddr != NULL);
+
+	rx_ring = tp->rx_ring;
+	cur_rx = tp->cur_rx;
+
+	DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
+		 " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
+		 RTL_R16 (RxBufAddr),
+		 RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
+
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+	if (dev == rtl_ecat_dev.dev) {
+	    (rtl_ecat_dev.rx_intr_cnt)++;
+	    rdtscl(rtl_ecat_dev.rx_time); // Get CPU cycles
+	}
+	/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+	while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
+		int ring_offset = cur_rx % RX_BUF_LEN;
+		u32 rx_status;
+		unsigned int rx_size;
+		unsigned int pkt_size;
+		struct sk_buff *skb;
+
+		rmb();
+
+		/* read size+status of next frame from DMA ring buffer */
+		rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
+		rx_size = rx_status >> 16;
+		pkt_size = rx_size - 4;
+
+
+		DPRINTK ("%s:  rtl8139_rx() status %4.4x, size %4.4x,"
+			 " cur %4.4x.\n", dev->name, rx_status,
+			 rx_size, cur_rx);
+#if RTL8139_DEBUG > 2
+
+                /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+                        
+                if (dev == rtl_ecat_dev.dev)
+		{
+			int i;
+			DPRINTK ("%s: Frame contents ", dev->name);
+			for (i = 0; i < 70; i++)
+				EC_DBG (" %2.2x",
+					rx_ring[ring_offset + i]);
+			EC_DBG (".\n");
+		}
+
+                /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+#endif
+
+		/* Packet copy from FIFO still in progress.
+		 * Theoretically, this should never happen
+		 * since EarlyRx is disabled.
+		 */
+		if (rx_size == 0xfff0) {
+			tp->xstats.early_rx++;
+			break;
+		}
+
+		/* If Rx err or invalid rx_size/rx_status received
+		 * (which happens if we get lost in the ring),
+		 * Rx process gets reset, so we abort any further
+		 * Rx processing.
+		 */
+		if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
+		    (rx_size < 8) ||
+		    (!(rx_status & RxStatusOK))) {
+			rtl8139_rx_err (rx_status, dev, tp, ioaddr);
+			return;
+		}
+
+		/* Malloc up new buffer, compatible with net-2e. */
+		/* Omit the four octet CRC from the length. */
+
+		/* TODO: consider allocating skb's outside of
+		 * interrupt context, both to speed interrupt processing,
+		 * and also to reduce the chances of having to
+		 * drop packets here under memory pressure.
+		 */
+
+                /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+                if (dev != rtl_ecat_dev.dev)
+                {
+                  skb = dev_alloc_skb(pkt_size + 2);
+
+                  if (skb)
+                  {
+                    skb->dev = dev;
+                    skb_reserve (skb, 2);	/* 16 byte align the IP fields. */
+                    eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
+                    skb_put (skb, pkt_size);
+                    skb->protocol = eth_type_trans (skb, dev); // Entfernt auch den Ethernet Header!
+                    netif_rx(skb);
+                 
+                    
+                    dev->last_rx = jiffies;
+                    tp->stats.rx_bytes += pkt_size;
+                    tp->stats.rx_packets++;
+                  }
+                  else
+                  {
+                    EC_DBG (KERN_WARNING
+                            "%s: Memory squeeze, dropping packet.\n",
+                            dev->name);
+                    tp->stats.rx_dropped++;
+                  }
+                }
+                else
+                {
+                  if (rtl_ecat_dev.state != ECAT_DS_SENT)
+                  {
+                    EC_DBG(KERN_WARNING "EtherCAT: Received frame while not in SENT state!\n");
+                  }
+                  else
+                  {
+//                    rdtscl(rtl_ecat_dev.rx_time); // Get CPU cycles
+                  
+                    // Copy received data to ethercat-device buffer, skip Ethernet-II header
+                    memcpy(rtl_ecat_dev.rx_data, &rx_ring[ring_offset + 4] + ETH_HLEN,
+                           pkt_size - ETH_HLEN);
+                    rtl_ecat_dev.rx_data_length = pkt_size - ETH_HLEN;
+
+                    rtl_ecat_dev.state = ECAT_DS_RECEIVED;
+
+                    dev->last_rx = jiffies;
+                    tp->stats.rx_bytes += pkt_size;
+                    tp->stats.rx_packets++;
+                  }
+                }
+                  
+                /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+		cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
+		RTL_W16 (RxBufPtr, cur_rx - 16);
+
+		if (RTL_R16 (IntrStatus) & RxAckBits)
+			RTL_W16_F (IntrStatus, RxAckBits);
+	}
+
+	DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
+		 " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
+		 RTL_R16 (RxBufAddr),
+		 RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
+
+	tp->cur_rx = cur_rx;
+}
+
+
+static void rtl8139_weird_interrupt (struct net_device *dev,
+				     struct rtl8139_private *tp,
+				     void *ioaddr,
+				     int status, int link_changed)
+{
+	DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
+		 dev->name, status);
+
+	assert (dev != NULL);
+	assert (tp != NULL);
+	assert (ioaddr != NULL);
+
+	/* Update the error count. */
+	tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+	RTL_W32 (RxMissed, 0);
+
+	if ((status & RxUnderrun) && link_changed &&
+	    (tp->drv_flags & HAS_LNK_CHNG)) {
+		/* Really link-change on new chips. */
+		int lpar = RTL_R16 (NWayLPAR);
+		int duplex = (lpar & LPA_100FULL) || (lpar & 0x01C0) == 0x0040
+				|| tp->mii.force_media;
+		if (tp->mii.full_duplex != duplex) {
+			tp->mii.full_duplex = duplex;
+#if 0
+			RTL_W8 (Cfg9346, Cfg9346_Unlock);
+			RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20);
+			RTL_W8 (Cfg9346, Cfg9346_Lock);
+#endif
+		}
+		status &= ~RxUnderrun;
+	}
+
+	/* XXX along with rtl8139_rx_err, are we double-counting errors? */
+	if (status &
+	    (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
+		tp->stats.rx_errors++;
+
+	if (status & PCSTimeout)
+		tp->stats.rx_length_errors++;
+	if (status & (RxUnderrun | RxFIFOOver))
+		tp->stats.rx_fifo_errors++;
+	if (status & PCIErr) {
+		u16 pci_cmd_status;
+		pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);
+		pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status);
+
+		EC_DBG (KERN_ERR "%s: PCI Bus error %4.4x.\n",
+			dev->name, pci_cmd_status);
+	}
+}
+
+
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void rtl8139_interrupt (int irq, void *dev_instance,
+			       struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_instance;
+	struct rtl8139_private *tp = dev->priv;
+	int boguscnt = max_interrupt_work;
+	void *ioaddr = tp->mmio_addr;
+	int ackstat, status;
+	int link_changed = 0; /* avoid bogus "uninit" warning */
+
+	if(dev == rtl_ecat_dev.dev) {
+	    rt_spin_lock (&tp->lock);
+	    (rtl_ecat_dev.intr_cnt)++;
+	}
+	else
+	    spin_lock (&tp->lock);
+
+	do {
+		status = RTL_R16 (IntrStatus);
+
+		/* h/w no longer present (hotplug?) or major error, bail */
+		if (status == 0xFFFF)
+			break;
+
+		if ((status &
+		     (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
+		      RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0)
+			break;
+
+		/* Acknowledge all of the current interrupt sources ASAP, but
+		   an first get an additional status bit from CSCR. */
+		if (status & RxUnderrun)
+			link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
+
+		/* The chip takes special action when we clear RxAckBits,
+		 * so we clear them later in rtl8139_rx_interrupt
+		 */
+		ackstat = status & ~(RxAckBits | TxErr);
+		RTL_W16 (IntrStatus, ackstat);
+
+		DPRINTK ("%s: interrupt  status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n",
+			 dev->name, ackstat, status, RTL_R16 (IntrStatus));
+
+		if ((dev == rtl_ecat_dev.dev || netif_running (dev)) && (status & RxAckBits))
+			rtl8139_rx_interrupt (dev, tp, ioaddr);
+
+		/* Check uncommon events with one test. */
+		if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
+		  	      RxFIFOOver | RxErr))
+			rtl8139_weird_interrupt (dev, tp, ioaddr,
+						 status, link_changed);
+
+		if ((dev == rtl_ecat_dev.dev || netif_running (dev)) && (status & (TxOK | TxErr))) {
+			rtl8139_tx_interrupt (dev, tp, ioaddr);
+			if (status & TxErr)
+				RTL_W16 (IntrStatus, TxErr);
+		}
+
+		boguscnt--;
+	} while (boguscnt > 0);
+
+	if (boguscnt <= 0) {
+		EC_DBG (KERN_WARNING "%s: Too much work at interrupt, "
+			"IntrStatus=0x%4.4x.\n", dev->name, status);
+
+		/* Clear all interrupt sources. */
+		RTL_W16 (IntrStatus, 0xffff);
+	}
+
+	if(dev == rtl_ecat_dev.dev)
+	    rt_spin_unlock (&tp->lock);
+	else
+	    spin_unlock (&tp->lock);
+
+	DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
+		 dev->name, RTL_R16 (IntrStatus));
+}
+
+/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+static void rt_rtl8139_interrupt(void)
+{
+  rtl8139_interrupt(rtl_ecat_dev.dev->irq, rtl_ecat_dev.dev, NULL);
+}
+
+/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+static int rtl8139_close (struct net_device *dev)
+{
+	struct rtl8139_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int ret = 0;
+	unsigned long flags;
+
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+        if (dev != rtl_ecat_dev.dev)
+        {
+	    netif_stop_queue(dev);
+
+	    if (tp->thr_pid >= 0) {
+		tp->time_to_die = 1;
+		wmb();
+		ret = kill_proc (tp->thr_pid, SIGTERM, 1);
+		if (ret) {
+			EC_DBG (KERN_ERR "%s: unable to signal thread\n", dev->name);
+			return ret;
+		}
+		wait_for_completion (&tp->thr_exited);
+	    }
+	}
+	
+
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+	DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n",
+			dev->name, RTL_R16 (IntrStatus));
+
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+	mdelay(1); //hm
+
+        if (dev == rtl_ecat_dev.dev)
+        {
+	    flags = rt_spin_lock_irqsave (&tp->lock);
+        }
+	else
+        {
+	    spin_lock_irqsave (&tp->lock, flags);
+        }
+
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+	/* Stop the chip's Tx and Rx DMA processes. */
+	RTL_W8 (ChipCmd, 0);
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	RTL_W16 (IntrMask, 0);
+
+	/* Update the error counts. */
+	tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+	RTL_W32 (RxMissed, 0);
+
+        if (dev == rtl_ecat_dev.dev) {
+	    rt_spin_unlock_irqrestore (&tp->lock, flags);
+	    synchronize_irq ();
+	}
+	else {
+	    spin_unlock_irqrestore (&tp->lock, flags);
+	    synchronize_irq ();
+	}
+
+
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+	EC_DBG ("rtl8139: freeing irq");
+	mdelay(1); //hm
+
+        if (dev != rtl_ecat_dev.dev)
+        {
+          free_irq (dev->irq, dev);
+	} 
+	else
+        {
+	    rt_disable_irq(dev->irq);
+          rt_free_global_irq (dev->irq);
+          rt_enable_irq(dev->irq);
+	}
+
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+	rtl8139_tx_clear (tp);
+
+	pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+			    tp->rx_ring, tp->rx_ring_dma);
+	pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+			    tp->tx_bufs, tp->tx_bufs_dma);
+	tp->rx_ring = NULL;
+	tp->tx_bufs = NULL;
+
+	/* Green! Put the chip in low-power mode. */
+	RTL_W8 (Cfg9346, Cfg9346_Unlock);
+
+	if (rtl_chip_info[tp->chipset].flags & HasHltClk)
+		RTL_W8 (HltClk, 'H');	/* 'R' would leave the clock running. */
+
+	EC_DBG ("rtl8139: closing done\n");
+
+	return 0;
+}
+
+
+/* Get the ethtool Wake-on-LAN settings.  Assumes that wol points to
+   kernel memory, *wol has been initialized as {ETHTOOL_GWOL}, and
+   other threads or interrupts aren't messing with the 8139.  */
+static void netdev_get_wol (struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct rtl8139_private *np = dev->priv;
+	void *ioaddr = np->mmio_addr;
+
+	if (rtl_chip_info[np->chipset].flags & HasLWake) {
+		u8 cfg3 = RTL_R8 (Config3);
+		u8 cfg5 = RTL_R8 (Config5);
+
+		wol->supported = WAKE_PHY | WAKE_MAGIC
+			| WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+
+		wol->wolopts = 0;
+		if (cfg3 & Cfg3_LinkUp)
+			wol->wolopts |= WAKE_PHY;
+		if (cfg3 & Cfg3_Magic)
+			wol->wolopts |= WAKE_MAGIC;
+		/* (KON)FIXME: See how netdev_set_wol() handles the
+		   following constants.  */
+		if (cfg5 & Cfg5_UWF)
+			wol->wolopts |= WAKE_UCAST;
+		if (cfg5 & Cfg5_MWF)
+			wol->wolopts |= WAKE_MCAST;
+		if (cfg5 & Cfg5_BWF)
+			wol->wolopts |= WAKE_BCAST;
+	}
+}
+
+
+/* Set the ethtool Wake-on-LAN settings.  Return 0 or -errno.  Assumes
+   that wol points to kernel memory and other threads or interrupts
+   aren't messing with the 8139.  */
+static int netdev_set_wol (struct net_device *dev,
+			   const struct ethtool_wolinfo *wol)
+{
+	struct rtl8139_private *np = dev->priv;
+	void *ioaddr = np->mmio_addr;
+	u32 support;
+	u8 cfg3, cfg5;
+
+	support = ((rtl_chip_info[np->chipset].flags & HasLWake)
+		   ? (WAKE_PHY | WAKE_MAGIC
+		      | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)
+		   : 0);
+	if (wol->wolopts & ~support)
+		return -EINVAL;
+
+	cfg3 = RTL_R8 (Config3) & ~(Cfg3_LinkUp | Cfg3_Magic);
+	if (wol->wolopts & WAKE_PHY)
+		cfg3 |= Cfg3_LinkUp;
+	if (wol->wolopts & WAKE_MAGIC)
+		cfg3 |= Cfg3_Magic;
+	RTL_W8 (Cfg9346, Cfg9346_Unlock);
+	RTL_W8 (Config3, cfg3);
+	RTL_W8 (Cfg9346, Cfg9346_Lock);
+
+	cfg5 = RTL_R8 (Config5) & ~(Cfg5_UWF | Cfg5_MWF | Cfg5_BWF);
+	/* (KON)FIXME: These are untested.  We may have to set the
+	   CRC0, Wakeup0 and LSBCRC0 registers too, but I have no
+	   documentation.  */
+	if (wol->wolopts & WAKE_UCAST)
+		cfg5 |= Cfg5_UWF;
+	if (wol->wolopts & WAKE_MCAST)
+		cfg5 |= Cfg5_MWF;
+	if (wol->wolopts & WAKE_BCAST)
+		cfg5 |= Cfg5_BWF;
+	RTL_W8 (Config5, cfg5);	/* need not unlock via Cfg9346 */
+
+	return 0;
+}
+
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	struct rtl8139_private *np = dev->priv;
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		strcpy (info.bus_info, np->pci_dev->slot_name);
+		info.regdump_len = np->regs_len;
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii, &ecmd);
+		spin_unlock_irq(&np->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		return mii_nway_restart(&np->mii);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		edata.data = mii_link_ok(&np->mii);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		debug = edata.data;
+		return 0;
+	}
+
+	case ETHTOOL_GWOL:
+		{
+			struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
+			spin_lock_irq (&np->lock);
+			netdev_get_wol (dev, &wol);
+			spin_unlock_irq (&np->lock);
+			if (copy_to_user (useraddr, &wol, sizeof (wol)))
+				return -EFAULT;
+			return 0;
+		}
+
+	case ETHTOOL_SWOL:
+		{
+			struct ethtool_wolinfo wol;
+			int rc;
+			if (copy_from_user (&wol, useraddr, sizeof (wol)))
+				return -EFAULT;
+			spin_lock_irq (&np->lock);
+			rc = netdev_set_wol (dev, &wol);
+			spin_unlock_irq (&np->lock);
+			return rc;
+		}
+
+/* TODO: we are too slack to do reg dumping for pio, for now */
+#ifndef CONFIG_8139TOO_PIO
+	/* NIC register dump */
+	case ETHTOOL_GREGS: {
+                struct ethtool_regs regs;
+		unsigned int regs_len = np->regs_len;
+                u8 *regbuf = kmalloc(regs_len, GFP_KERNEL);
+                int rc;
+
+		if (!regbuf)
+			return -ENOMEM;
+		memset(regbuf, 0, regs_len);
+
+                rc = copy_from_user(&regs, useraddr, sizeof(regs));
+		if (rc) {
+			rc = -EFAULT;
+			goto err_out_gregs;
+		}
+                
+                if (regs.len > regs_len)
+                        regs.len = regs_len;
+                if (regs.len < regs_len) {
+			rc = -EINVAL;
+			goto err_out_gregs;
+		}
+
+                regs.version = RTL_REGS_VER;
+                rc = copy_to_user(useraddr, &regs, sizeof(regs));
+		if (rc) {
+			rc = -EFAULT;
+			goto err_out_gregs;
+		}
+
+                useraddr += offsetof(struct ethtool_regs, data);
+
+                spin_lock_irq(&np->lock);
+                memcpy_fromio(regbuf, np->mmio_addr, regs_len);
+                spin_unlock_irq(&np->lock);
+
+                if (copy_to_user(useraddr, regbuf, regs_len))
+                        rc = -EFAULT;
+
+err_out_gregs:
+		kfree(regbuf);
+		return rc;
+	}
+#endif /* CONFIG_8139TOO_PIO */
+
+	/* get string list(s) */
+	case ETHTOOL_GSTRINGS: {
+		struct ethtool_gstrings estr = { ETHTOOL_GSTRINGS };
+
+		if (copy_from_user(&estr, useraddr, sizeof(estr)))
+			return -EFAULT;
+		if (estr.string_set != ETH_SS_STATS)
+			return -EINVAL;
+
+		estr.len = RTL_NUM_STATS;
+		if (copy_to_user(useraddr, &estr, sizeof(estr)))
+			return -EFAULT;
+		if (copy_to_user(useraddr + sizeof(estr),
+				 &ethtool_stats_keys,
+				 sizeof(ethtool_stats_keys)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get NIC-specific statistics */
+	case ETHTOOL_GSTATS: {
+		struct ethtool_stats estats = { ETHTOOL_GSTATS };
+		u64 *tmp_stats;
+		const unsigned int sz = sizeof(u64) * RTL_NUM_STATS;
+		int i;
+
+		estats.n_stats = RTL_NUM_STATS;
+		if (copy_to_user(useraddr, &estats, sizeof(estats)))
+			return -EFAULT;
+
+		tmp_stats = kmalloc(sz, GFP_KERNEL);
+		if (!tmp_stats)
+			return -ENOMEM;
+		memset(tmp_stats, 0, sz);
+
+		i = 0;
+		tmp_stats[i++] = np->xstats.early_rx;
+		tmp_stats[i++] = np->xstats.tx_buf_mapped;
+		tmp_stats[i++] = np->xstats.tx_timeouts;
+		tmp_stats[i++] = np->xstats.rx_lost_in_ring;
+		if (i != RTL_NUM_STATS)
+			BUG();
+
+		i = copy_to_user(useraddr + sizeof(estats), tmp_stats, sz);
+		kfree(tmp_stats);
+
+		if (i)
+			return -EFAULT;
+		return 0;
+	}
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct rtl8139_private *np = dev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
+
+	if (dev == rtl_ecat_dev.dev || !netif_running(dev))
+		return -EINVAL;
+
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
+	}
+
+	return rc;
+}
+
+
+static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
+{
+	struct rtl8139_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
+
+	EC_DBG("%s: rtl8139 GETSTATS called...",dev->name);
+
+	if (dev == rtl_ecat_dev.dev) {
+		flags = rt_spin_lock_irqsave (&tp->lock);
+		tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+		RTL_W32 (RxMissed, 0);
+		rt_spin_unlock_irqrestore (&tp->lock, flags);
+	}
+	else {
+	    if (netif_running(dev)) {
+		spin_lock_irqsave (&tp->lock, flags);
+		tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+		RTL_W32 (RxMissed, 0);
+		spin_unlock_irqrestore (&tp->lock, flags);
+	    }
+	}
+
+	return &tp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   This routine is not state sensitive and need not be SMP locked. */
+
+static void __set_rx_mode (struct net_device *dev)
+{
+	struct rtl8139_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	u32 mc_filter[2];	/* Multicast hash filter */
+	int i, rx_mode;
+	u32 tmp;
+
+	DPRINTK ("%s:   rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n",
+			dev->name, dev->flags, RTL_R32 (RxConfig));
+
+	/* Note: do not reorder, GCC is clever about common statements. */
+	if (dev->flags & IFF_PROMISC) {
+		/* Unconditionally log net taps. */
+		EC_DBG (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+			dev->name);
+		rx_mode =
+		    AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+		    AcceptAllPhys;
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+	} else if ((dev->mc_count > multicast_filter_limit)
+		   || (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter perfectly -- accept all multicasts. */
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+	} else {
+		struct dev_mc_list *mclist;
+		rx_mode = AcceptBroadcast | AcceptMyPhys;
+		mc_filter[1] = mc_filter[0] = 0;
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+		     i++, mclist = mclist->next) {
+			int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+			rx_mode |= AcceptMulticast;
+		}
+	}
+
+	/* We can safely update without stopping the chip. */
+	tmp = rtl8139_rx_config | rx_mode;
+	if (tp->rx_config != tmp) {
+		RTL_W32_F (RxConfig, tmp);
+		tp->rx_config = tmp;
+	}
+	RTL_W32_F (MAR0 + 0, mc_filter[0]);
+	RTL_W32_F (MAR0 + 4, mc_filter[1]);
+}
+
+static void rtl8139_set_rx_mode (struct net_device *dev)
+{
+	unsigned long flags;
+	struct rtl8139_private *tp = dev->priv;
+
+	if(dev == rtl_ecat_dev.dev) {
+	    flags = rt_spin_lock_irqsave (&tp->lock);
+	    __set_rx_mode(dev);
+	    rt_spin_unlock_irqrestore (&tp->lock, flags);
+	}
+	else {
+	    spin_lock_irqsave (&tp->lock, flags);
+	    __set_rx_mode(dev);
+	    spin_unlock_irqrestore (&tp->lock, flags);
+	}
+}
+
+#ifdef CONFIG_PM
+
+static int rtl8139_suspend (struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	struct rtl8139_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
+
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+	if (dev == rtl_ecat_dev.dev || !netif_running (dev))
+		return 0;
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+	netif_device_detach (dev);
+
+	spin_lock_irqsave (&tp->lock, flags);
+
+	/* Disable interrupts, stop Tx and Rx. */
+	RTL_W16 (IntrMask, 0);
+	RTL_W8 (ChipCmd, 0);
+
+	/* Update the error counts. */
+	tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+	RTL_W32 (RxMissed, 0);
+
+	spin_unlock_irqrestore (&tp->lock, flags);
+	return 0;
+}
+
+
+static int rtl8139_resume (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+	if (dev == rtl_ecat_dev.dev || !netif_running (dev))
+		return 0;
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+        netif_device_attach (dev);
+
+	rtl8139_hw_start (dev);
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+
+static struct pci_driver rtl8139_pci_driver = {
+	.name		= DRV_NAME,
+	.id_table	= rtl8139_pci_tbl,
+	.probe		= rtl8139_init_one,
+	.remove		= __devexit_p(rtl8139_remove_one),
+#ifdef CONFIG_PM
+	.suspend	= rtl8139_suspend,
+	.resume		= rtl8139_resume,
+#endif /* CONFIG_PM */
+};
+
+
+static int rtl8139_init_module (void)
+{
+	/* when we're a module, we always print a version message,
+	 * even if no 8139 board is found.
+	 */
+#ifdef MODULE
+	EC_DBG (KERN_INFO RTL8139_DRIVER_NAME "\n");
+#endif
+
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+/*        if (ecat_dev)
+        {
+          EC_DBG(KERN_WARNING "EtherCAT device already exists!!!\n");
+          return -ENOMEM;
+        }
+*/
+//        if ((ecat_dev = (EtherCAT_device_t*) kmalloc(sizeof(EtherCAT_device_t), GFP_KERNEL)) == NULL)
+//          return -ENOMEM;
+
+        EtherCAT_device_init(&rtl_ecat_dev);
+
+        printk(KERN_DEBUG "Driver rtl_ecat_dev has adress %X.\n", (unsigned) &rtl_ecat_dev);
+
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+	return pci_module_init (&rtl8139_pci_driver);
+}
+
+
+static void rtl8139_cleanup_module (void)
+{
+	pci_unregister_driver (&rtl8139_pci_driver);
+
+        /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+//        if (ecat_dev)
+        {
+          EtherCAT_device_clear(&rtl_ecat_dev);
+//          kfree(ecat_dev);
+//          ecat_dev = NULL;
+        }
+
+        /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+}
+
+
+module_init(rtl8139_init_module);
+module_exit(rtl8139_cleanup_module);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ec_command.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,58 @@
+/****************************************************************
+ *
+ *  e c _ c o m m a n d . c
+ *
+ *  Methoden für ein EtherCAT-Kommando.
+ *
+ *  $Date$
+ *  $Author$
+ *
+ ***************************************************************/
+
+#include <linux/slab.h>
+
+#include "ec_command.h"
+
+/***************************************************************/
+
+/**
+   Kommando-Konstruktor.
+
+   Initialisiert alle Variablen innerhalb des Kommandos auf die
+   Default-Werte.
+   
+   @param cmd Zeiger auf das zu initialisierende Kommando.
+*/
+
+void EtherCAT_command_init(EtherCAT_command_t *cmd)
+{
+  cmd->type = ECAT_CMD_NONE;
+  cmd->address.logical = 0x00000000;
+  cmd->data_length = 0;
+
+  cmd->next = NULL;
+
+  cmd->state = ECAT_CS_READY;
+  cmd->index = 0;
+  cmd->working_counter = 0;
+  cmd->reserved = 0; //Hm
+}
+
+/***************************************************************/
+
+/**
+   Kommando-Destruktor.
+
+   Setzt nur den Status auf ECAT_CS_READY und das
+   reserved-Flag auf 0.
+   
+   @param cmd Zeiger auf das zu initialisierende Kommando.
+*/
+
+void EtherCAT_command_clear(EtherCAT_command_t *cmd)
+{
+  cmd->state = ECAT_CS_READY;
+  cmd->reserved = 0;
+}
+
+/***************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ec_command.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,93 @@
+/****************************************************************
+ *
+ *  e c _ c o m m a n d . h
+ *
+ *  Struktur für ein EtherCAT-Kommando.
+ *
+ *  $Date$
+ *  $Author$
+ *
+ ***************************************************************/
+
+#ifndef _EC_COMMAND_H_
+#define _EC_COMMAND_H_
+
+#include "ec_globals.h"
+
+/**
+   Status eines EtherCAT-Kommandos.
+*/
+
+typedef enum
+{
+  ECAT_CS_READY, ECAT_CS_SENT, ECAT_CS_RECEIVED
+}
+EtherCAT_command_state_t;
+
+/**
+   EtherCAT-Adresse.
+
+   Im EtherCAT-Rahmen sind 4 Bytes für die Adresse reserviert, die
+   ja nach Kommandoty eine andere bedeutung haben: Bei Autoinkrement-
+   befehlen sind die ersten zwei Bytes die (negative)
+   Autoinkrement-Adresse, bei Knoten-adressierten Befehlen entsprechen
+   sie der Knotenadresse. Das dritte und vierte Byte entspricht in
+   diesen Fällen der physikalischen Speicheradresse auf dem Slave.
+   Bei einer logischen Adressierung entsprechen alle vier Bytes
+   der logischen Adresse.
+*/
+
+typedef union
+{
+  struct
+  {
+    union
+    {
+      short pos; /**< (Negative) Ring-Position des Slaves */
+      unsigned short node; /**< Konfigurierte Knotenadresse */
+    }
+    dev;
+
+    unsigned short mem; /**< Physikalische Speicheradresse im Slave */
+  }
+  phy;
+
+  unsigned long logical; /**< Logische Adresse */
+  unsigned char raw[4]; /**< Rohdaten für die generierung des Frames */
+}
+EtherCAT_address_t;
+
+/***************************************************************/
+
+/**
+   EtherCAT-Kommando.
+*/
+
+typedef struct EtherCAT_command
+{
+  EtherCAT_cmd_type_t type; /**< Typ des Kommandos (APRD, NPWR, etc...) */
+  EtherCAT_address_t address; /**< Adresse des/der Empfänger */
+  unsigned int data_length; /**< Länge der zu sendenden und/oder empfangenen Daten */
+
+  struct EtherCAT_command *next; /**< (Für den Master) Zeiger auf nächstes Kommando
+                                    in der Liste */
+
+  EtherCAT_command_state_t state; /**< Zustand des Kommandos (bereit, gesendet, etc...) */
+  unsigned char index; /**< Kommando-Index, mit der das Kommando gesendet wurde (wird
+                          vom Master beim Senden gesetzt. */
+  unsigned int working_counter; /**< Working-Counter bei Empfang (wird vom Master gesetzt) */
+
+  unsigned char data[ECAT_FRAME_BUFFER_SIZE]; /**< Kommandodaten */
+
+  unsigned char reserved; /**< Markiert, das das Kommando gerade benutzt wird */
+}
+EtherCAT_command_t;
+
+/***************************************************************/
+
+void EtherCAT_command_init(EtherCAT_command_t *);
+void EtherCAT_command_clear(EtherCAT_command_t *);
+
+/***************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ec_dbg.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,23 @@
+#ifndef ECDBG_H_
+#define ECDBG_H_
+
+
+//#define DEBUG_SEND_RECEIVE
+#define ECMASTER_DEBUG
+
+
+#include "../rs232dbg/rs232dbg.h"
+
+
+#ifdef ECMASTER_DEBUG
+/* note: prints function name for you */
+//#  define EC_DBG(fmt, args...) SDBG_print(fmt, ## args)
+
+#define EC_DBG(fmt, args...) SDBG_print("%s: " fmt, __FUNCTION__ , ## args)
+//#define EC_DBG(fmt, args...) printk(KERN_INFO fmt, ## args)
+#else
+#define EC_DBG(fmt, args...)
+#endif
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ec_device.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,320 @@
+/****************************************************************
+ *
+ *  e c _ d e v i c e . c
+ *
+ *  Methoden für ein EtherCAT-Gerät.
+ *
+ *  $Date$
+ *  $Author$
+ *
+ ***************************************************************/
+
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <rtai.h>
+
+#include "ec_device.h"
+#include "ec_dbg.h"
+
+/***************************************************************/
+
+/**
+   EtherCAT-Geräte-Konstuktor.
+   
+   Initialisiert ein EtherCAT-Gerät, indem es die Variablen
+   in der Struktur auf die Default-Werte setzt.
+
+   @param ecd Zu initialisierendes EtherCAT-Gerät
+*/
+
+void EtherCAT_device_init(EtherCAT_device_t *ecd)
+{
+  ecd->dev = NULL;
+  ecd->tx_skb = NULL;
+  ecd->rx_skb = NULL;
+  ecd->tx_time = 0;
+  ecd->rx_time = 0;
+  ecd->tx_intr_cnt = 0;
+  ecd->rx_intr_cnt = 0;
+  ecd->intr_cnt = 0;
+  ecd->state = ECAT_DS_READY;
+  ecd->rx_data_length = 0;
+  ecd->lock = NULL;
+}
+
+/***************************************************************/
+
+/**
+   EtherCAT-Geräte-Destuktor.
+   
+   Gibt den dynamisch allozierten Speicher des
+   EtherCAT-Gerätes (die beiden Socket-Buffer) wieder frei.
+
+   @param ecd EtherCAT-Gerät
+*/
+
+void EtherCAT_device_clear(EtherCAT_device_t *ecd)
+{
+  ecd->dev = NULL;
+
+  if (ecd->tx_skb)
+  {
+    dev_kfree_skb(ecd->tx_skb);
+    ecd->tx_skb = NULL;
+  }
+
+  if (ecd->rx_skb)
+  {
+    dev_kfree_skb(ecd->rx_skb);
+    ecd->rx_skb = NULL;
+  }
+}
+
+/***************************************************************/
+
+/**
+   Weist einem EtherCAT-Gerät das entsprechende net_device zu.
+   
+   Prüft das net_device, allokiert Socket-Buffer in Sende- und
+   Empfangsrichtung und weist dem EtherCAT-Gerät und den
+   Socket-Buffern das net_device zu.
+
+   @param ecd EtherCAT-Device
+   @param dev net_device
+
+   @return 0: Erfolg, < 0: Konnte Socket-Buffer nicht allozieren.
+*/
+
+int EtherCAT_device_assign(EtherCAT_device_t *ecd,
+                           struct net_device *dev)
+{
+  if (!dev)
+  {
+    EC_DBG("EtherCAT: Device is NULL!\n");
+    return -1;
+  }
+
+  if ((ecd->tx_skb = dev_alloc_skb(ECAT_FRAME_BUFFER_SIZE)) == NULL)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Could not allocate device tx socket buffer!\n");
+    return -1;
+  }
+
+  if ((ecd->rx_skb = dev_alloc_skb(ECAT_FRAME_BUFFER_SIZE)) == NULL)
+  {
+    dev_kfree_skb(ecd->tx_skb);
+    ecd->tx_skb = NULL;
+
+    EC_DBG(KERN_ERR "EtherCAT: Could not allocate device rx socket buffer!\n");
+    return -1;
+  }
+
+  ecd->dev = dev;
+  ecd->tx_skb->dev = dev;
+  ecd->rx_skb->dev = dev;
+
+  EC_DBG("EtherCAT: Assigned Device %X.\n", (unsigned) dev);
+
+  return 0;
+}
+
+/***************************************************************/
+
+/**
+   Führt die open()-Funktion des Netzwerktreibers aus.
+
+   Dies entspricht einem "ifconfig up". Vorher wird der Zeiger
+   auf das EtherCAT-Gerät auf Gültigkeit geprüft und der
+   Gerätezustand zurückgesetzt.
+
+   @param ecd EtherCAT-Gerät
+
+   @return 0 bei Erfolg, < 0: Ungültiger Zeiger, oder open()
+   fehlgeschlagen
+*/
+
+int EtherCAT_device_open(EtherCAT_device_t *ecd)
+{
+  if (!ecd)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Trying to open a NULL device!\n");
+    return -1;
+  }
+
+  if (!ecd->dev)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: No device to open!\n");
+    return -1;
+  }
+
+  // Reset old device state
+  ecd->state = ECAT_DS_READY;
+  ecd->tx_intr_cnt = 0;
+  ecd->rx_intr_cnt = 0;
+
+  return ecd->dev->open(ecd->dev);
+}
+
+/***************************************************************/
+
+/**
+   Führt die stop()-Funktion des net_devices aus.
+
+   @param ecd EtherCAT-Gerät
+
+   @return 0 bei Erfolg, < 0: Kein Gerät zum Schliessen
+*/
+
+int EtherCAT_device_close(EtherCAT_device_t *ecd)
+{
+  if (!ecd->dev)
+  {
+    EC_DBG("EtherCAT: No device to close!\n");
+    return -1;
+  }
+
+  EC_DBG("EtherCAT: txcnt: %u, rxcnt: %u\n",
+         (unsigned int) ecd->tx_intr_cnt,
+         (unsigned int) ecd->rx_intr_cnt);
+
+  EC_DBG("EtherCAT: Stopping device at 0x%X\n",
+         (unsigned int) ecd->dev);
+
+  return ecd->dev->stop(ecd->dev);
+}
+
+/***************************************************************/
+
+/**
+   Sendet einen Rahmen über das EtherCAT-Gerät.
+
+   Kopiert die zu sendenden Daten in den statischen Socket-
+   Buffer, fügt den Ethernat-II-Header hinzu und ruft die
+   start_xmit()-Funktion der Netzwerkkarte auf.
+
+   @param ecd EtherCAT-Gerät
+   @param data Zeiger auf die zu sendenden Daten
+   @param length Länge der zu sendenden Daten
+
+   @return 0 bei Erfolg, < 0: Vorheriger Rahmen noch
+   nicht empfangen, oder kein Speicher mehr vorhanden
+*/
+
+int EtherCAT_device_send(EtherCAT_device_t *ecd,
+                         unsigned char *data,
+                         unsigned int length)
+{
+  unsigned char *frame_data;
+  struct ethhdr *eth;
+
+  if (ecd->state == ECAT_DS_SENT)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Trying to send frame while last was not received!\n");
+    return -1;
+  }
+
+  skb_trim(ecd->tx_skb, 0); // Clear transmit socket buffer
+  skb_reserve(ecd->tx_skb, ETH_HLEN); // Reserve space for Ethernet-II header
+
+  // Copy data to socket buffer
+  frame_data = skb_put(ecd->tx_skb, length);
+  memcpy(frame_data, data, length);
+
+  // Add Ethernet-II-Header
+  if ((eth = (struct ethhdr *) skb_push(ecd->tx_skb, ETH_HLEN)) == NULL)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: device_send - Could not allocate Ethernet-II header!\n");
+    return -1;
+  }
+
+  eth->h_proto = htons(0x88A4); // Protocol type
+  memcpy(eth->h_source, ecd->dev->dev_addr, ecd->dev->addr_len); // Hardware address
+  memset(eth->h_dest, 0xFF, ecd->dev->addr_len); // Broadcast address
+
+  rdtscl(ecd->tx_time); // Get CPU cycles
+
+  // Start sending of frame
+  ecd->state = ECAT_DS_SENT;
+  ecd->dev->hard_start_xmit(ecd->tx_skb, ecd->dev);
+  
+  return 0;
+}
+
+/***************************************************************/
+
+/**
+   Holt einen empfangenen Rahmen von der Netzwerkkarte.
+
+   Zuerst wird geprüft, ob überhaupt ein Rahmen empfangen
+   wurde. Wenn ja, wird diesem mit Hilfe eines Spin-Locks
+   in den angegebenen Speicherbereich kopiert.
+
+   @param ecd EtherCAT-Gerät
+   @param data Zeiger auf den Speicherbereich, in den die
+   empfangenen Daten kopiert werden sollen
+   @param size Größe des angegebenen Speicherbereichs
+
+   @return Anzahl der kopierten Bytes bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_device_receive(EtherCAT_device_t *ecd, 
+                            unsigned char *data,
+                            unsigned int size)
+{
+  int cnt;
+//  unsigned long flags;
+  
+  if (ecd->state != ECAT_DS_RECEIVED)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: receive - Nothing received!\n");
+    return -1;
+  }
+    
+//  flags = rt_spin_lock_irqsave(ecd->lock);
+
+  cnt = min(ecd->rx_data_length, size);
+  memcpy(data,ecd->rx_data, cnt);
+
+//  rt_spin_unlock_irqrestore(ecd->lock, flags);
+
+  return cnt;
+}
+
+/***************************************************************/
+
+/**
+   Gibt alle Informationen über das Device-Objekt aus.
+
+   @param ecd EtherCAT-Gerät
+*/
+
+void EtherCAT_device_debug(EtherCAT_device_t *ecd)
+{
+  EC_DBG(KERN_DEBUG "---EtherCAT device information begin---\n");
+
+  if (ecd)
+  {
+    EC_DBG(KERN_DEBUG "Assigned net_device: %X\n", (unsigned) ecd->dev);
+    EC_DBG(KERN_DEBUG "Transmit socket buffer: %X\n", (unsigned) ecd->tx_skb);
+    EC_DBG(KERN_DEBUG "Receive socket buffer: %X\n", (unsigned) ecd->rx_skb);
+    EC_DBG(KERN_DEBUG "Time of last transmission: %u\n", (unsigned) ecd->tx_time);
+    EC_DBG(KERN_DEBUG "Time of last receive: %u\n", (unsigned) ecd->rx_time);
+    EC_DBG(KERN_DEBUG "Number of transmit interrupts: %u\n", (unsigned) ecd->tx_intr_cnt);
+    EC_DBG(KERN_DEBUG "Number of receive interrupts: %u\n", (unsigned) ecd->rx_intr_cnt);
+    EC_DBG(KERN_DEBUG "Total Number of interrupts: %u\n", (unsigned) ecd->intr_cnt);
+    EC_DBG(KERN_DEBUG "Actual device state: %i\n", (int) ecd->state);
+    EC_DBG(KERN_DEBUG "Receive buffer: %X\n", (unsigned) ecd->rx_data);
+    EC_DBG(KERN_DEBUG "Receive buffer fill state: %u/%u\n",
+           (unsigned) ecd->rx_data_length, ECAT_FRAME_BUFFER_SIZE);
+    EC_DBG(KERN_DEBUG "Lock: %X\n", (unsigned) ecd->lock);
+  }
+  else
+  {
+    EC_DBG(KERN_DEBUG "Device is NULL!\n");
+  }
+
+  EC_DBG(KERN_DEBUG "---EtherCAT device information end---\n");
+}
+
+/***************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ec_device.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,86 @@
+/****************************************************************
+ *
+ *  e c _ d e v i c e . h
+ *
+ *  Struktur für ein EtherCAT-Gerät.
+ *
+ *  $Date$
+ *  $Author$
+ *
+ ***************************************************************/
+
+#ifndef _EC_DEVICE_H_
+#define _EC_DEVICE_H_
+
+#include "ec_globals.h"
+
+/**
+   Zustand eines EtherCAT-Gerätes.
+   
+   Eine Für EtherCAT reservierte Netzwerkkarte kann bestimmte Zustände haben.
+*/
+
+typedef enum
+{
+  ECAT_DS_READY,    /**< Das Gerät ist bereit zum Senden */
+  ECAT_DS_SENT,     /**< Das Gerät hat einen Rahmen abgesendet,
+                       aber noch keine Antwort enpfangen */
+  ECAT_DS_RECEIVED, /**< Das Gerät hat eine Antwort auf einen
+                       zuvor gesendeten Rahmen empfangen */
+  ECAT_DS_TIMEOUT,  /**< Nach dem Senden eines Rahmens meldete
+                       das Gerät einen Timeout */
+  ECAT_DS_ERROR     /**< Nach dem Senden eines frames hat das
+                       Gerät einen Fehler festgestellt. */
+}
+EtherCAT_device_state_t;
+
+#define ECAT_BUS_TIME(ecd_ptr) ((((ecd_ptr)->rx_time - \
+                                  (ecd_ptr)->tx_time) * 1000) / cpu_khz)
+
+/***************************************************************/
+
+/**
+   EtherCAT-Gerät.
+
+   Ein EtherCAT-Gerät ist eine Netzwerkkarte, die vom
+   EtherCAT-Master dazu verwendet wird, um Frames zu senden
+   und zu empfangen.
+*/
+
+typedef struct
+{
+  struct net_device *dev;    /**< Zeiger auf das reservierte net_device */
+  struct sk_buff *tx_skb;    /**< Zeiger auf Transmit-Socketbuffer */
+  struct sk_buff *rx_skb;    /**< Zeiger auf Receive-Socketbuffer */
+  unsigned long tx_time;     /**< Zeit des letzten Sendens */
+  unsigned long rx_time;     /**< Zeit des letzten Empfangs */
+  unsigned long tx_intr_cnt; /**< Anzahl Tx-Interrupts */
+  unsigned long rx_intr_cnt; /**< Anzahl Rx-Interrupts */
+  unsigned long intr_cnt;    /**< Anzahl Interrupts */
+  volatile EtherCAT_device_state_t state; /**< Gesendet, Empfangen,
+                                             Timeout, etc. */
+  unsigned char rx_data[ECAT_FRAME_BUFFER_SIZE]; /**< Puffer für
+                                                    empfangene Rahmen */
+  volatile unsigned int rx_data_length; /**< Länge des zuletzt
+                                           empfangenen Rahmens */
+  spinlock_t *lock; /**< Zeiger auf das Spinlock des net_devices */
+}
+EtherCAT_device_t;
+
+/***************************************************************/
+
+void EtherCAT_device_init(EtherCAT_device_t *);
+int EtherCAT_device_assign(EtherCAT_device_t *, struct net_device *);
+void EtherCAT_device_clear(EtherCAT_device_t *);
+
+int EtherCAT_device_open(EtherCAT_device_t *);
+int EtherCAT_device_close(EtherCAT_device_t *);
+
+int EtherCAT_device_send(EtherCAT_device_t *, unsigned char *, unsigned int);
+int EtherCAT_device_receive(EtherCAT_device_t *, unsigned char *, unsigned int);
+
+void EtherCAT_device_debug(EtherCAT_device_t *);
+
+/***************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ec_globals.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,77 @@
+/****************************************************************
+ *
+ *  e c _ g l o b a l s . h
+ *
+ *  Globale Definitionen und Makros für das EtherCAT-Protokoll.
+ *
+ *  $Date$
+ *  $Author$
+ *
+ ***************************************************************/
+
+#ifndef _EC_GLOBALS_
+#define _EC_GLOBALS_
+
+/**
+   Maximale Größe eines EtherCAT-Frames
+*/
+#define ECAT_FRAME_BUFFER_SIZE 1600
+
+/**
+   Anzahl der Kommandos in einem Master-Kommandoring
+*/
+#define ECAT_COMMAND_RING_SIZE 10
+
+/**
+   Anzahl der Versuche beim Asynchronen Senden/Empfangen
+*/
+#define ECAT_NUM_RETRIES 10
+
+/**
+   NULL-Define, falls noch nicht definiert.
+*/
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+/**
+   EtherCAT-Kommando-Typ
+*/
+
+typedef enum
+{
+  ECAT_CMD_NONE = 0x00, /**< Dummy */
+  ECAT_CMD_APRD = 0x01, /**< Auto-increment physical read */
+  ECAT_CMD_APWR = 0x02, /**< Auto-increment physical write */
+  ECAT_CMD_NPRD = 0x04, /**< Node-addressed physical read */
+  ECAT_CMD_NPWR = 0x05, /**< Node-addressed physical write */
+  ECAT_CMD_BRD = 0x07,  /**< Broadcast read */
+  ECAT_CMD_BWR = 0x08,  /**< Broadcast write */
+  ECAT_CMD_LRW = 0x0C   /**< Logical read/write */
+}
+EtherCAT_cmd_type_t;
+
+/**
+   Zustand eines EtherCAT-Slaves
+*/
+
+typedef enum
+{
+  ECAT_STATE_UNKNOWN = 0x00, /**< Status unbekannt */
+  ECAT_STATE_INIT = 0x01,    /**< Init-Zustand (Keine Mailbox-
+                                Kommunikation, Kein I/O) */
+  ECAT_STATE_PREOP = 0x02,   /**< Pre-Operational (Mailbox-
+                                Kommunikation, Kein I/O) */
+  ECAT_STATE_SAVEOP = 0x04,  /**< Save-Operational (Mailbox-
+                                Kommunikation und Input Update) */
+  ECAT_STATE_OP = 0x08,      /**< Operational, (Mailbox-
+                                Kommunikation und Input/Output Update) */
+  ECAT_ACK_STATE = 0x10      /**< Acknoledge-Bit beim Zustandswechsel
+                                (dies ist kein eigener Zustand) */
+}
+EtherCAT_state_t;
+
+/***************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ec_master.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,1767 @@
+/****************************************************************
+ *
+ *  e c _ m a s t e r . c
+ *
+ *  Methoden für einen EtherCAT-Master.
+ *
+ *  $Date$
+ *  $Author$
+ *
+ ***************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "ec_globals.h"
+#include "ec_master.h"
+#include "ec_dbg.h"
+
+// FIXME: Klappt nur solange, wie es nur einen Master gibt! fp
+static int ASYNC = 0;
+
+/***************************************************************/
+
+/**
+   Konstruktor des EtherCAT-Masters.
+
+   @param master Zeiger auf den zu initialisierenden
+   EtherCAT-Master
+   @param dev Zeiger auf das EtherCAT-gerät, mit dem der
+   Master arbeiten soll
+
+   @return 0 bei Erfolg, sonst < 0 (= dev ist NULL)
+*/
+
+int EtherCAT_master_init(EtherCAT_master_t *master,
+                         EtherCAT_device_t *dev)
+{
+  unsigned int i;
+
+  if (!dev)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Master init without device!\n");
+    return -1;
+  }
+
+  master->slaves = NULL;
+  master->slave_count = 0;
+  master->first_command = NULL;
+  master->process_data_command = NULL;
+  master->dev = dev;
+  master->command_index = 0x00;
+  master->tx_data_length = 0;
+  master->process_data = NULL;
+  master->process_data_length = 0;
+  master->cmd_ring_index = 0;
+
+  for (i = 0; i < ECAT_COMMAND_RING_SIZE; i++)
+  {
+    EtherCAT_command_init(&master->cmd_ring[i]);
+  }
+
+  return 0;
+}
+
+/***************************************************************/
+
+/**
+   Destruktor eines EtherCAT-Masters.
+
+   Entfernt alle Kommandos aus der Liste, löscht den Zeiger
+   auf das Slave-Array und gibt die Prozessdaten frei.
+
+   @param master Zeiger auf den zu löschenden Master
+*/
+
+void EtherCAT_master_clear(EtherCAT_master_t *master)
+{
+  EC_DBG("Master clear");
+
+  // Remove all pending commands
+  while (master->first_command)
+  {
+    EtherCAT_remove_command(master, master->first_command);
+  }
+
+  // Remove all slaves
+  EtherCAT_clear_slaves(master);
+
+  if (master->process_data)
+  {
+    kfree(master->process_data);
+    master->process_data = NULL;
+  }
+
+  master->process_data_length = 0;
+
+  EC_DBG("done...\n");
+}
+
+/***************************************************************/
+
+/**
+   Überprüft die angeschlossenen Slaves.
+
+   Vergleicht die an den Bus angeschlossenen Slaves mit
+   den im statischen-Slave-Array vorgegebenen Konfigurationen.
+   Stimmen Anzahl oder Typen nicht überein, gibt diese
+   Methode einen Fehler aus.
+
+   @param master Der EtherCAT-Master
+   @param slaves Zeiger auf ein statisches Slave-Array
+   @param slave_count Anzahl der Slaves im Array
+
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_check_slaves(EtherCAT_master_t *master,
+                          EtherCAT_slave_t *slaves,
+                          unsigned int slave_count)
+{
+  EtherCAT_command_t *cmd;
+  EtherCAT_slave_t *cur;
+  unsigned int i, j, found, length, pos;
+  unsigned char data[2];
+
+  // EtherCAT_clear_slaves() must be called before!
+  if (master->slaves || master->slave_count)
+  {
+    EC_DBG(KERN_ERR "EtherCAT duplicate slave check!");
+    return -1;
+  }
+
+  // No slaves. 
+  if (slave_count == 0)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: No slaves in list!");
+    return -1;
+  }
+
+  // Determine number of slaves on bus
+
+  if ((cmd = EtherCAT_broadcast_read(master, 0x0000, 4)) == NULL)
+  {
+    return -1;
+  }
+  
+  if (EtherCAT_async_send_receive(master) != 0)
+  {
+    return -1;
+  }
+
+  if (cmd->working_counter != slave_count)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Wrong number of slaves on bus: %i / %i\n",
+           cmd->working_counter, slave_count);
+    EtherCAT_remove_command(master, cmd);
+    
+    return -1;
+  }
+  else
+  {
+    EC_DBG("EtherCAT: Slave count on bus: %i. Found: %i.\n",
+           cmd->working_counter, slave_count);
+  }
+
+  EtherCAT_remove_command(master, cmd);  
+
+   // For every slave in the list
+  for (i = 0; i < slave_count; i++)
+  {
+    cur = &slaves[i];
+
+    if (!cur->desc)
+    {
+      EC_DBG(KERN_ERR "EtherCAT: Slave %i has no description.\n", i);
+      return -1;
+    }
+
+    // Set ring position
+    cur->ring_position = -i;
+    cur->station_address = i + 1;
+
+    // Write station address
+    
+    data[0] = cur->station_address & 0x00FF;
+    data[1] = (cur->station_address & 0xFF00) >> 8;
+
+    if ((cmd = EtherCAT_position_write(master, cur->ring_position, 0x0010, 2, data)) == NULL)
+    {
+      return -1;
+    }
+    
+    if (EtherCAT_async_send_receive(master) != 0)
+    {
+      return -1;
+    }
+    
+    if (cmd->working_counter != 1)
+    {
+      EC_DBG(KERN_ERR "EtherCAT: Slave %i did not repond while writing station address!\n", i);
+      return -1;
+    }
+    
+    EtherCAT_remove_command(master, cmd);    
+
+    // Read base data
+
+    if ((cmd = EtherCAT_read(master, cur->station_address, 0x0000, 4)) == NULL)
+    {
+      EC_DBG(KERN_ERR "EtherCAT: Could not create command!\n");
+      return -1;
+    }
+
+    if (EtherCAT_async_send_receive(master) != 0)
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      EC_DBG(KERN_ERR "EtherCAT: Could not send command!\n");
+      return -1;
+    }
+
+    if (cmd->working_counter != 1)
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      EC_DBG(KERN_ERR "EtherCAT: Slave %i did not respond while reading base data!\n", i);
+      return -1;
+    }
+
+    // Get base data
+    cur->type = cmd->data[0];
+    cur->revision = cmd->data[1];
+    cur->build = cmd->data[2] | (cmd->data[3] << 8);
+
+    EtherCAT_remove_command(master, cmd);
+    
+    // Read identification from "Slave Information Interface" (SII)
+
+    if (EtherCAT_read_slave_information(master, cur->station_address,
+                                        0x0008, &cur->vendor_id) != 0)
+    {
+      EC_DBG(KERN_ERR "EtherCAT: Could not read SII!\n");
+      return -1;
+    }
+
+    if (EtherCAT_read_slave_information(master, cur->station_address,
+                                        0x000A, &cur->product_code) != 0)
+    {
+      EC_DBG(KERN_ERR "EtherCAT: Could not read SII!\n");
+      return -1;
+    }
+
+    if (EtherCAT_read_slave_information(master, cur->station_address,
+                                        0x000E, &cur->revision_number) != 0)
+    {
+      EC_DBG(KERN_ERR "EtherCAT: Could not read SII!\n");
+      return -1;
+    }
+
+    // Search for identification in "database"
+
+    found = 0;
+
+    for (j = 0; j < slave_idents_count; j++)
+    {
+      if (slave_idents[j].vendor_id == cur->vendor_id
+          && slave_idents[j].product_code == cur->product_code)
+      {
+        found = 1;
+
+        if (cur->desc != slave_idents[j].desc)
+        {
+          EC_DBG(KERN_ERR "EtherCAT: Unexpected slave device \"%s %s\""
+                 " at position %i. Expected: \"%s %s\"\n",
+                 slave_idents[j].desc->vendor_name,
+                 slave_idents[j].desc->product_name, i,
+                 cur->desc->vendor_name, cur->desc->product_name);
+          return -1;
+        }
+
+        break;
+      }
+    }
+
+    if (!found)
+    {
+      EC_DBG(KERN_ERR "EtherCAT: Unknown slave device (vendor %X, code %X) at position %i.\n",
+             i, cur->vendor_id, cur->product_code);
+      return -1;      
+    }
+  }
+
+  length = 0;
+  for (i = 0; i < slave_count; i++)
+  {
+    length += slaves[i].desc->data_length;
+  }
+
+  if ((master->process_data = (unsigned char *)
+       kmalloc(sizeof(unsigned char) * length, GFP_KERNEL)) == NULL)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Could not allocate %i bytes for process data.\n", length);
+    return -1;
+  }
+
+  master->process_data_length = length;
+  memset(master->process_data, 0x00, length);
+
+  pos = 0;
+  for (i = 0; i < slave_count; i++)
+  {
+    slaves[i].process_data = master->process_data + pos;
+    slaves[i].logical_address0 = pos;
+
+    EC_DBG(KERN_DEBUG "EtherCAT: Slave %i - \"%s %s\" - Logical Address 0x%08X\n",
+           i, slaves[i].desc->vendor_name, slaves[i].desc->product_name, pos);
+
+    pos += slaves[i].desc->data_length;
+  }  
+
+  master->slaves = slaves;
+  master->slave_count = slave_count;
+
+  return 0;
+}
+
+/***************************************************************/
+
+/**
+   Entfernt den Zeiger auf das Slave-Array.
+
+   @param master EtherCAT-Master
+*/
+
+void EtherCAT_clear_slaves(EtherCAT_master_t *master)
+{
+  master->slaves = NULL;
+  master->slave_count = 0;
+}
+
+/***************************************************************/
+
+/**
+   Liest Daten aus dem Slave-Information-Interface
+   eines EtherCAT-Slaves.
+
+   @param master EtherCAT-Master
+   @param node_address Knotenadresse des Slaves
+   @param offset Adresse des zu lesenden SII-Registers
+   @param target Zeiger auf einen 4 Byte großen Speicher
+   zum Ablegen der Daten
+
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_read_slave_information(EtherCAT_master_t *master,
+                                    unsigned short int node_address,
+                                    unsigned short int offset,
+                                    unsigned int *target)
+{
+  EtherCAT_command_t *cmd;
+  unsigned char data[10];
+  unsigned int tries_left;
+
+  // Initiate read operation
+
+  data[0] = 0x00;
+  data[1] = 0x01;
+  data[2] = offset & 0xFF;
+  data[3] = (offset & 0xFF00) >> 8;
+  data[4] = 0x00;
+  data[5] = 0x00;
+
+  if ((cmd = EtherCAT_write(master, node_address, 0x502, 6, data)) == NULL)
+    return -2;
+
+  if (EtherCAT_async_send_receive(master) != 0)
+  {
+    EtherCAT_remove_command(master, cmd);
+    return -3;
+  }
+
+  if (cmd->working_counter != 1)
+  {
+    EtherCAT_remove_command(master, cmd);
+    EC_DBG(KERN_ERR "EtherCAT: SII-read - Slave %04X did not respond!\n",
+           node_address);
+    return -4;
+  }
+
+  EtherCAT_remove_command(master, cmd);
+
+  // Get status of read operation
+
+  // ?? FIXME warum hier tries ?? Hm
+
+  // Der Slave legt die Informationen des Slave-Information-Interface
+  // in das Datenregister und löscht daraufhin ein Busy-Bit. Solange
+  // den Status auslesen, bis das Bit weg ist. fp
+
+  tries_left = 1000;
+  while (tries_left)
+  {
+    udelay(10);
+
+    if ((cmd = EtherCAT_read(master, node_address, 0x502, 10)) == NULL)
+      return -2;
+    
+    if (EtherCAT_async_send_receive(master) != 0)
+    {
+      EtherCAT_remove_command(master, cmd);
+      return -3;
+    }
+    
+    if (cmd->working_counter != 1)
+    {
+      EtherCAT_remove_command(master, cmd);
+      EC_DBG(KERN_ERR "EtherCAT: SII-read status - Slave %04X did not respond!\n",
+             node_address);
+      return -4;
+    }
+
+    if ((cmd->data[1] & 0x81) == 0)
+    {
+      memcpy(target, cmd->data + 6, 4);
+      EtherCAT_remove_command(master, cmd);
+      break;
+    }
+    
+    EtherCAT_remove_command(master, cmd);
+
+    tries_left--;
+  }
+
+  if (!tries_left)
+  {
+    EC_DBG(KERN_WARNING "EtherCAT: SSI-read. Slave %04X timed out!\n",
+           node_address);
+    return -1;
+  }
+
+  return 0;
+}
+
+/***************************************************************/
+
+/**
+   Führt ein asynchrones Senden und Empfangen aus.
+
+   Sendet alle wartenden Kommandos und wartet auf die
+   entsprechenden Antworten.
+
+   @param master EtherCAT-Master
+   
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_async_send_receive(EtherCAT_master_t *master)
+{
+  unsigned int wait_cycles;
+  int i;
+  
+  // Send all commands
+
+  //EC_DBG("Master async send");
+
+  for (i = 0; i < ECAT_NUM_RETRIES; i++)
+  {
+    ASYNC = 1;
+    if (EtherCAT_send(master) < 0) return -1;
+    ASYNC = 0;
+
+    // Wait until something is received or an error has occurred
+    wait_cycles = 10;
+    while (master->dev->state == ECAT_DS_SENT && wait_cycles)
+    {
+      udelay(1000);
+      wait_cycles--;
+    }
+    
+    //EC_DBG("Master async send: tries %d",tries_left);
+    
+    if (!wait_cycles)
+    {
+      EC_DBG(KERN_ERR "EtherCAT: Asynchronous receive timeout.\n");
+      continue;
+    }
+
+    if (master->dev->state != ECAT_DS_RECEIVED)
+    {
+      EC_DBG(KERN_ERR "EtherCAT: Asyncronous send error. State %i\n", master->dev->state);
+      continue;
+    }
+    
+    // Receive all commands
+    if (EtherCAT_receive(master) < 0)
+    {
+      // Noch mal versuchen
+      master->dev->state = ECAT_DS_READY;
+      EC_DBG("Retry Asynchronous send/recieve: %d", i);
+      continue;
+    }
+
+    return 0; // Erfolgreich
+  }
+
+  return -1;
+}
+
+/***************************************************************/
+
+/**
+   Sendet alle wartenden Kommandos.
+
+   Errechnet erst die benötigte Gesamt-Rahmenlänge, und erstellt
+   dann alle Kommando-Bytefolgen im statischen Sendespeicher.
+   Danach wird die Sendefunktion des EtherCAT-Gerätes aufgerufen.
+
+   @param master EtherCAT-Master
+   
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_send(EtherCAT_master_t *master)
+{
+  unsigned int i, length, framelength, pos;
+  EtherCAT_command_t *cmd;
+  int cmdcnt = 0;
+
+  length = 0;
+  for (cmd = master->first_command; cmd != NULL; cmd = cmd->next)
+  {
+    if (cmd->state != ECAT_CS_READY) continue;
+    length += cmd->data_length + 12;
+    cmdcnt++;
+  }
+
+  if (length == 0)
+  {
+    EC_DBG(KERN_WARNING "EtherCAT: Nothing to send...\n");
+    return 0;
+  }
+
+  framelength = length + 2;
+  if (framelength < 46) framelength = 46;
+
+  if (ASYNC && framelength > 46)
+    EC_DBG(KERN_WARNING "Framelength: %d", framelength);
+
+  if (ASYNC && cmdcnt > 1)
+    EC_DBG(KERN_WARNING "CMDcount: %d", cmdcnt);
+
+  master->tx_data[0] = length & 0xFF;
+  master->tx_data[1] = ((length & 0x700) >> 8) | 0x10;
+  pos = 2;
+
+  for (cmd = master->first_command; cmd != NULL; cmd = cmd->next)
+  {
+    if (cmd->state != ECAT_CS_READY) continue;
+
+    cmd->index = master->command_index;
+    master->command_index = (master->command_index + 1) % 0x0100;
+
+    cmd->state = ECAT_CS_SENT;
+
+    master->tx_data[pos + 0] = cmd->type;
+    master->tx_data[pos + 1] = cmd->index;
+
+    master->tx_data[pos + 2] = cmd->address.raw[0];
+    master->tx_data[pos + 3] = cmd->address.raw[1];
+    master->tx_data[pos + 4] = cmd->address.raw[2];
+    master->tx_data[pos + 5] = cmd->address.raw[3];
+
+    master->tx_data[pos + 6] = cmd->data_length & 0xFF;
+    master->tx_data[pos + 7] = (cmd->data_length & 0x700) >> 8;
+
+    if (cmd->next) master->tx_data[pos + 7] |= 0x80;
+
+    master->tx_data[pos + 8] = 0x00;
+    master->tx_data[pos + 9] = 0x00;
+
+    if (cmd->type == ECAT_CMD_APWR
+        || cmd->type == ECAT_CMD_NPWR
+        || cmd->type == ECAT_CMD_BWR
+        || cmd->type == ECAT_CMD_LRW) // Write
+    {
+      for (i = 0; i < cmd->data_length; i++) master->tx_data[pos + 10 + i] = cmd->data[i];
+    }
+    else // Read
+    {
+      for (i = 0; i < cmd->data_length; i++) master->tx_data[pos + 10 + i] = 0x00;
+    }
+
+    master->tx_data[pos + 10 + cmd->data_length] = 0x00;
+    master->tx_data[pos + 11 + cmd->data_length] = 0x00;
+
+    pos += 12 + cmd->data_length;
+  }
+
+  // Pad with zeros
+  while (pos < 46) master->tx_data[pos++] = 0x00;
+  
+  master->tx_data_length = framelength;
+
+#ifdef DEBUG_SEND_RECEIVE
+  EC_DBG(KERN_DEBUG "\n");
+  EC_DBG(KERN_DEBUG ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+  EC_DBG(KERN_DEBUG);
+  for (i = 0; i < framelength; i++)
+  {
+    EC_DBG("%02X ", master->tx_data[i]);
+
+    if ((i + 1) % 16 == 0) EC_DBG("\n" KERN_DEBUG);
+  }
+  EC_DBG("\n");
+  EC_DBG(KERN_DEBUG "-----------------------------------------------\n");
+#endif
+ 
+  // Send frame
+  if (EtherCAT_device_send(master->dev, master->tx_data, framelength) != 0)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Could not send!\n");
+    EC_DBG(KERN_DEBUG "EtherCAT: tx_data content:\n");
+    EC_DBG(KERN_DEBUG);
+    for (i = 0; i < framelength; i++)
+    {
+      EC_DBG("%02X ", master->tx_data[i]);      
+      if ((i + 1) % 16 == 0) EC_DBG("\n" KERN_DEBUG);
+    }
+    EC_DBG("\n");
+    return -1;
+  }
+
+  return 0;
+}
+
+/***************************************************************/
+
+/**
+   Holt alle empfangenen Kommandos vom EtherCAT-Gerät.
+
+   Kopiert einen empfangenen Rahmen vom EtherCAT-Gerät
+   in den Statischen Empfangsspeicher und ordnet dann
+   allen gesendeten Kommandos ihre Antworten zu.
+
+   @param master EtherCAT-Master
+   
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_receive(EtherCAT_master_t *master)
+{
+  EtherCAT_command_t *cmd;
+  unsigned int length, pos, found, rx_data_length;
+  unsigned int command_follows, command_type, command_index;
+  unsigned int i;
+
+  // Copy received data into master buffer (with locking)
+  rx_data_length = EtherCAT_device_receive(master->dev, master->rx_data,
+                                           ECAT_FRAME_BUFFER_SIZE);
+
+#ifdef DEBUG_SEND_RECEIVE
+  for (i = 0; i < rx_data_length; i++)
+  {
+    if (master->rx_data[i] == master->tx_data[i]) EC_DBG("   ");
+    else EC_DBG("%02X ", master->rx_data[i]);
+    if ((i + 1) % 16 == 0) EC_DBG("\n" KERN_DEBUG);
+  }
+  EC_DBG("\n");
+  EC_DBG(KERN_DEBUG "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+  EC_DBG(KERN_DEBUG "\n");
+#endif
+
+  if (rx_data_length < 2)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Received corrupted frame (illegal length)!\n");
+    EC_DBG(KERN_DEBUG "EtherCAT: tx_data content:\n");
+    EC_DBG(KERN_DEBUG);
+    for (i = 0; i < master->tx_data_length; i++)
+    {
+      EC_DBG("%02X ", master->tx_data[i]);      
+      if ((i + 1) % 16 == 0) EC_DBG("\n" KERN_DEBUG);
+    }
+    EC_DBG("\n");
+    EC_DBG(KERN_DEBUG "EtherCAT: rx_data content:\n");
+    EC_DBG(KERN_DEBUG);
+    for (i = 0; i < rx_data_length; i++)
+    {
+      EC_DBG("%02X ", master->rx_data[i]);
+      if ((i + 1) % 16 == 0) EC_DBG("\n" KERN_DEBUG);
+    }
+    EC_DBG("\n");
+    return -1;
+  }
+
+  // Länge des gesamten Frames prüfen
+  length = ((master->rx_data[1] & 0x07) << 8) | (master->rx_data[0] & 0xFF);
+
+  if (length > rx_data_length)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Received corrupted frame (length does not match)!\n");
+    EC_DBG(KERN_DEBUG "EtherCAT: tx_data content:\n");
+    EC_DBG(KERN_DEBUG);
+    for (i = 0; i < master->tx_data_length; i++)
+    {
+      EC_DBG("%02X ", master->tx_data[i]);      
+      if ((i + 1) % 16 == 0) EC_DBG("\n" KERN_DEBUG);
+    }
+    EC_DBG("\n");
+    EC_DBG(KERN_DEBUG "EtherCAT: rx_data content:\n");
+    EC_DBG(KERN_DEBUG);
+    for (i = 0; i < rx_data_length; i++)
+    {
+      EC_DBG("%02X ", master->rx_data[i]);
+      if ((i + 1) % 16 == 0) EC_DBG("\n" KERN_DEBUG);
+    }
+    EC_DBG("\n");
+    return -1;
+  }
+
+  pos = 2; // LibPCAP: 16
+  command_follows = 1;
+  while (command_follows)
+  {
+    if (pos + 10 > rx_data_length)
+    {
+      EC_DBG(KERN_ERR "EtherCAT: Received frame with incomplete command header!\n");
+      EC_DBG(KERN_DEBUG "EtherCAT: tx_data content:\n");
+      EC_DBG(KERN_DEBUG);
+      for (i = 0; i < master->tx_data_length; i++)
+      {
+        EC_DBG("%02X ", master->tx_data[i]);      
+        if ((i + 1) % 16 == 0) EC_DBG("\n" KERN_DEBUG);
+      }
+      EC_DBG("\n");
+      EC_DBG(KERN_DEBUG "EtherCAT: rx_data content:\n");
+      EC_DBG(KERN_DEBUG);
+      for (i = 0; i < rx_data_length; i++)
+      {
+        EC_DBG("%02X ", master->rx_data[i]);
+        if ((i + 1) % 16 == 0) EC_DBG("\n" KERN_DEBUG);
+      }
+      EC_DBG("\n");
+      return -1;
+    }
+
+    command_type = master->rx_data[pos];
+    command_index = master->rx_data[pos + 1];
+    length = (master->rx_data[pos + 6] & 0xFF)
+      | ((master->rx_data[pos + 7] & 0x07) << 8);
+    command_follows = master->rx_data[pos + 7] & 0x80;
+
+    if (pos + length + 12 > rx_data_length)
+    {
+      EC_DBG(KERN_ERR "EtherCAT: Received frame with incomplete command data!\n");
+      EC_DBG(KERN_DEBUG "EtherCAT: tx_data content:\n");
+      EC_DBG(KERN_DEBUG);
+      for (i = 0; i < master->tx_data_length; i++)
+      {
+        EC_DBG("%02X ", master->tx_data[i]);      
+        if ((i + 1) % 16 == 0) EC_DBG("\n" KERN_DEBUG);
+      }
+      EC_DBG("\n");
+      EC_DBG(KERN_DEBUG "EtherCAT: rx_data content:\n");
+      EC_DBG(KERN_DEBUG);
+      for (i = 0; i < rx_data_length; i++)
+      {
+        EC_DBG("%02X ", master->rx_data[i]);
+        if ((i + 1) % 16 == 0) EC_DBG("\n" KERN_DEBUG);
+      }
+      EC_DBG("\n");
+      return -1;
+    }
+
+    found = 0;
+
+    for (cmd = master->first_command; cmd != NULL; cmd = cmd->next)
+    {
+      if (cmd->state == ECAT_CS_SENT
+          && cmd->type == command_type
+          && cmd->index == command_index
+          && cmd->data_length == length)
+      {
+        found = 1;
+        cmd->state = ECAT_CS_RECEIVED;
+
+        // Empfangene Daten in Kommandodatenspeicher kopieren
+        memcpy(cmd->data, master->rx_data + pos + 10, length);
+
+        // Working-Counter setzen
+        cmd->working_counter = (master->rx_data[pos + length + 10] & 0xFF)
+          | ((master->rx_data[pos + length + 11] & 0xFF) << 8);
+      }
+    }
+
+    if (!found)
+    {
+      EC_DBG(KERN_WARNING "EtherCAT: WARNING - Command not assigned!\n");
+    }
+
+    pos += length + 12;
+  }
+
+  for (cmd = master->first_command; cmd != NULL; cmd = cmd->next)
+  {
+    if (cmd->state == ECAT_CS_SENT)
+    {
+      EC_DBG(KERN_WARNING "EtherCAT: WARNING - One command received no response!\n");
+    }
+  }
+
+  master->dev->state = ECAT_DS_READY;
+
+  return 0;
+}
+
+/***************************************************************/
+
+#define ECAT_FUNC_HEADER \
+  EtherCAT_command_t *cmd; \
+  if ((cmd = alloc_cmd(master)) == NULL) \
+  { \
+    EC_DBG(KERN_ERR "EtherCAT: Out of memory while creating command!\n"); \
+    return NULL; \
+  } \
+  EtherCAT_command_init(cmd)
+
+#define ECAT_FUNC_WRITE_FOOTER \
+  cmd->data_length = length; \
+  memcpy(cmd->data, data, length); \
+  add_command(master, cmd); \
+  return cmd
+
+#define ECAT_FUNC_READ_FOOTER \
+  cmd->data_length = length; \
+  add_command(master, cmd); \
+  return cmd
+
+/***************************************************************/
+
+/**
+   Erstellt ein EtherCAT-NPRD-Kommando.
+
+   Alloziert ein "node-adressed physical read"-Kommando
+   und fügt es in die Liste des Masters ein.
+
+   @param master EtherCAT-Master
+   @param node_address Adresse des Knotens (Slaves)
+   @param offset Physikalische Speicheradresse im Slave
+   @param length Länge der zu lesenden Daten
+   
+   @return Adresse des Kommandos bei Erfolg, sonst NULL
+*/
+
+EtherCAT_command_t *EtherCAT_read(EtherCAT_master_t *master,
+                                  unsigned short node_address,
+                                  unsigned short offset,
+                                  unsigned int length)
+{
+  if (node_address == 0x0000)
+    EC_DBG(KERN_WARNING "EtherCAT: Using node address 0x0000!\n");
+
+  ECAT_FUNC_HEADER;
+
+  cmd->type = ECAT_CMD_NPRD;
+  cmd->address.phy.dev.node = node_address;
+  cmd->address.phy.mem = offset;
+
+  ECAT_FUNC_READ_FOOTER;
+}
+
+/***************************************************************/
+
+/**
+   Erstellt ein EtherCAT-NPWR-Kommando.
+
+   Alloziert ein "node-adressed physical write"-Kommando
+   und fügt es in die Liste des Masters ein.
+
+   @param master EtherCAT-Master
+   @param node_address Adresse des Knotens (Slaves)
+   @param offset Physikalische Speicheradresse im Slave
+   @param length Länge der zu schreibenden Daten
+   @param data Zeiger auf Speicher mit zu schreibenden Daten
+   
+   @return Adresse des Kommandos bei Erfolg, sonst NULL
+*/
+
+EtherCAT_command_t *EtherCAT_write(EtherCAT_master_t *master,
+                                   unsigned short node_address,
+                                   unsigned short offset,
+                                   unsigned int length,
+                                   const unsigned char *data)
+{
+  if (node_address == 0x0000)
+    EC_DBG(KERN_WARNING "WARNING: Using node address 0x0000!\n");
+
+  ECAT_FUNC_HEADER;
+
+  cmd->type = ECAT_CMD_NPWR;
+  cmd->address.phy.dev.node = node_address;
+  cmd->address.phy.mem = offset;
+
+  ECAT_FUNC_WRITE_FOOTER;
+}
+
+/***************************************************************/
+
+/**
+   Erstellt ein EtherCAT-APRD-Kommando.
+
+   Alloziert ein "autoincerement physical read"-Kommando
+   und fügt es in die Liste des Masters ein.
+
+   @param master EtherCAT-Master
+   @param ring_position (Negative) Position des Slaves im Bus
+   @param offset Physikalische Speicheradresse im Slave
+   @param length Länge der zu lesenden Daten
+   
+   @return Adresse des Kommandos bei Erfolg, sonst NULL
+*/
+
+EtherCAT_command_t *EtherCAT_position_read(EtherCAT_master_t *master,
+                                           short ring_position,
+                                           unsigned short offset,
+                                           unsigned int length)
+{
+  ECAT_FUNC_HEADER;
+
+  cmd->type = ECAT_CMD_APRD;
+  cmd->address.phy.dev.pos = ring_position;
+  cmd->address.phy.mem = offset;
+
+  ECAT_FUNC_READ_FOOTER;
+}
+
+/***************************************************************/
+
+/**
+   Erstellt ein EtherCAT-APWR-Kommando.
+
+   Alloziert ein "autoincrement physical write"-Kommando
+   und fügt es in die Liste des Masters ein.
+
+   @param master EtherCAT-Master
+   @param ring_position (Negative) Position des Slaves im Bus
+   @param offset Physikalische Speicheradresse im Slave
+   @param length Länge der zu schreibenden Daten
+   @param data Zeiger auf Speicher mit zu schreibenden Daten
+   
+   @return Adresse des Kommandos bei Erfolg, sonst NULL
+*/
+
+EtherCAT_command_t *EtherCAT_position_write(EtherCAT_master_t *master,
+                                            short ring_position,
+                                            unsigned short offset,
+                                            unsigned int length,
+                                            const unsigned char *data)
+{
+  ECAT_FUNC_HEADER;
+
+  cmd->type = ECAT_CMD_APWR;
+  cmd->address.phy.dev.pos = ring_position;
+  cmd->address.phy.mem = offset;
+
+  ECAT_FUNC_WRITE_FOOTER;
+}
+
+/***************************************************************/
+
+/**
+   Erstellt ein EtherCAT-BRD-Kommando.
+
+   Alloziert ein "broadcast read"-Kommando
+   und fügt es in die Liste des Masters ein.
+
+   @param master EtherCAT-Master
+   @param offset Physikalische Speicheradresse im Slave
+   @param length Länge der zu lesenden Daten
+   
+   @return Adresse des Kommandos bei Erfolg, sonst NULL
+*/
+
+EtherCAT_command_t *EtherCAT_broadcast_read(EtherCAT_master_t *master,
+                                            unsigned short offset,
+                                            unsigned int length)
+{
+  ECAT_FUNC_HEADER;
+
+  cmd->type = ECAT_CMD_BRD;
+  cmd->address.phy.dev.node = 0x0000;
+  cmd->address.phy.mem = offset;
+
+  ECAT_FUNC_READ_FOOTER;
+}
+
+/***************************************************************/
+
+/**
+   Erstellt ein EtherCAT-BWR-Kommando.
+
+   Alloziert ein "broadcast write"-Kommando
+   und fügt es in die Liste des Masters ein.
+
+   @param master EtherCAT-Master
+   @param offset Physikalische Speicheradresse im Slave
+   @param length Länge der zu schreibenden Daten
+   @param data Zeiger auf Speicher mit zu schreibenden Daten
+   
+   @return Adresse des Kommandos bei Erfolg, sonst NULL
+*/
+
+EtherCAT_command_t *EtherCAT_broadcast_write(EtherCAT_master_t *master,
+                                             unsigned short offset,
+                                             unsigned int length,
+                                             const unsigned char *data)
+{
+  ECAT_FUNC_HEADER;
+
+  cmd->type = ECAT_CMD_BWR;
+  cmd->address.phy.dev.node = 0x0000;
+  cmd->address.phy.mem = offset;
+
+  ECAT_FUNC_WRITE_FOOTER;
+}
+
+/***************************************************************/
+
+/**
+   Erstellt ein EtherCAT-LRW-Kommando.
+
+   Alloziert ein "logical read write"-Kommando
+   und fügt es in die Liste des Masters ein.
+
+   @param master EtherCAT-Master
+   @param offset Logische Speicheradresse
+   @param length Länge der zu lesenden/schreibenden Daten
+   @param data Zeiger auf Speicher mit zu lesenden/schreibenden Daten
+   
+   @return Adresse des Kommandos bei Erfolg, sonst NULL
+*/
+
+EtherCAT_command_t *EtherCAT_logical_read_write(EtherCAT_master_t *master,
+                                                unsigned int offset,
+                                                unsigned int length,
+                                                unsigned char *data)
+{
+  ECAT_FUNC_HEADER;
+
+  cmd->type = ECAT_CMD_LRW;
+  cmd->address.logical = offset;
+
+  ECAT_FUNC_WRITE_FOOTER;
+}
+
+/***************************************************************/
+
+/**
+   Alloziert ein neues Kommando aus dem Kommandoring.
+
+   Durchsucht den Kommandoring nach einem freien Kommando,
+   reserviert es und gibt dessen Adresse zurück.
+
+   @param master EtherCAT-Master
+   
+   @return Adresse des Kommandos bei Erfolg, sonst NULL
+*/
+
+EtherCAT_command_t *alloc_cmd(EtherCAT_master_t *master)
+{
+  int j;
+
+  for (j = 0; j < ECAT_COMMAND_RING_SIZE; j++) // Einmal rum suchen
+  { 
+    // Solange suchen, bis freies Kommando gefunden
+    if (master->cmd_ring[master->cmd_ring_index].reserved == 0)
+    {
+      master->cmd_ring[master->cmd_ring_index].reserved = 1; // Belegen
+      return &master->cmd_ring[master->cmd_ring_index];
+    }
+
+    master->cmd_ring_index++;
+    master->cmd_ring_index %= ECAT_COMMAND_RING_SIZE;
+  }
+
+  EC_DBG(KERN_WARNING "EtherCAT: Command ring full!\n");
+
+  return NULL; // Nix gefunden
+}
+
+/***************************************************************/
+
+/**
+   Fügt ein Kommando in die Liste des Masters ein.
+
+   @param master EtherCAT-Master
+   @param cmd Zeiger auf das einzufügende Kommando
+*/
+
+void add_command(EtherCAT_master_t *master,
+                 EtherCAT_command_t *cmd)
+{
+  EtherCAT_command_t **last_cmd;
+
+  // Find the address of the last pointer in the list
+  last_cmd = &(master->first_command);
+  while (*last_cmd) last_cmd = &(*last_cmd)->next;
+
+  // Let this pointer point to the new command
+  *last_cmd = cmd;
+}
+
+/***************************************************************/
+
+/**
+   Entfernt ein Kommando aus der Liste und gibt es frei.
+
+   Prüft erst, ob das Kommando in der Liste des Masters
+   ist. Wenn ja, wird es entfernt und die Reservierung wird
+   aufgehoben.
+
+   @param master EtherCAT-Master
+   @param rem_cmd Zeiger auf das zu entfernende Kommando
+   
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+void EtherCAT_remove_command(EtherCAT_master_t *master,
+                             EtherCAT_command_t *rem_cmd)
+{
+  EtherCAT_command_t **last_cmd;
+
+  last_cmd = &master->first_command;
+  while (*last_cmd)
+  {
+    if (*last_cmd == rem_cmd)
+    {
+      *last_cmd = rem_cmd->next;
+
+      EtherCAT_command_clear(rem_cmd);
+
+      return;
+    }
+
+    last_cmd = &(*last_cmd)->next;
+  }
+
+  EC_DBG(KERN_WARNING "EtherCAT: Trying to remove non-existent command!\n");
+}
+
+/***************************************************************/
+
+/**
+   Ändert den Zustand eines Slaves (asynchron).
+
+   Führt eine (asynchrone) Zustandsänderung bei einem Slave durch.
+
+   @param master EtherCAT-Master
+   @param slave Slave, dessen Zustand geändert werden soll
+   @param state_and_ack Neuer Zustand, evtl. mit gesetztem
+   Acknowledge-Flag
+   
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_state_change(EtherCAT_master_t *master,
+                          EtherCAT_slave_t *slave,
+                          unsigned char state_and_ack)
+{
+  EtherCAT_command_t *cmd;
+  unsigned char data[2];
+  unsigned int tries_left;
+
+  data[0] = state_and_ack;
+  data[1] = 0x00;
+
+  if ((cmd = EtherCAT_write(master, slave->station_address,
+                            0x0120, 2, data)) == NULL)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Could not set state %02X - Out of memory!\n", state_and_ack);
+    return -1;
+  }
+
+  if (EtherCAT_async_send_receive(master) != 0)
+  {
+    EtherCAT_remove_command(master, cmd);
+    
+    EC_DBG(KERN_ERR "EtherCAT: Could not set state %02X - Unable to send!\n", state_and_ack);
+    return -2;
+  }
+
+  if (cmd->working_counter != 1)
+  {
+    EtherCAT_remove_command(master, cmd);
+    
+    EC_DBG(KERN_ERR "EtherCAT: Could not set state %02X - Device did not respond!\n", state_and_ack);
+    return -3;
+  }
+
+  EtherCAT_remove_command(master, cmd);  
+
+  slave->requested_state = state_and_ack & 0x0F;
+
+  tries_left = 1000;
+
+  while (tries_left)
+  {
+    udelay(10);
+
+    if ((cmd = EtherCAT_read(master, slave->station_address,
+                             0x0130, 2)) == NULL)
+    {
+      EC_DBG(KERN_ERR "EtherCAT: Could not check state %02X - Out of memory!\n", state_and_ack);
+      return -1;
+    }
+    
+    if (EtherCAT_async_send_receive(master) != 0)
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      EC_DBG(KERN_ERR "EtherCAT: Could not check state %02X - Unable to send!\n", state_and_ack);
+      return -2;
+    }
+    
+    if (cmd->working_counter != 1)
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      EC_DBG(KERN_ERR "EtherCAT: Could not check state %02X - Device did not respond!\n", state_and_ack);
+      return -3;
+    }
+
+    if (cmd->data[0] & 0x10) // State change error
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      EC_DBG(KERN_ERR "EtherCAT: Could not set state %02X - Device refused state change (code %02X)!\n", state_and_ack, cmd->data[0]);
+      return -4;
+    }
+
+    if (cmd->data[0] == (state_and_ack & 0x0F)) // State change successful
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      break;
+    }
+
+    EtherCAT_remove_command(master, cmd);
+    
+    tries_left--;
+  }
+
+  if (!tries_left)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Could not check state %02X - Timeout while checking!\n", state_and_ack);
+    return -5;
+  }
+
+  slave->current_state = state_and_ack & 0x0F;
+
+  return 0;
+}
+
+/***************************************************************/
+
+/**
+   Konfiguriert einen Slave und setzt den Operational-Zustand.
+
+   Führt eine komplette Konfiguration eines Slaves durch,
+   setzt Sync-Manager und FMMU's, führt die entsprechenden
+   Zustandsübergänge durch, bis der Slave betriebsbereit ist.
+
+   @param master EtherCAT-Master
+   @param slave Zu aktivierender Slave
+   
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_activate_slave(EtherCAT_master_t *master,
+                            EtherCAT_slave_t *slave)
+{
+  EtherCAT_command_t *cmd;
+  const EtherCAT_slave_desc_t *desc;
+  unsigned char fmmu[16];
+  unsigned char data[256];
+
+  desc = slave->desc;
+
+  if (EtherCAT_state_change(master, slave, ECAT_STATE_INIT) != 0)
+  {
+    return -1;
+  }
+
+  // Resetting FMMU's
+
+  memset(data, 0x00, 256);
+
+  if ((cmd = EtherCAT_write(master, slave->station_address, 0x0600, 256, data)) == NULL)
+    return -1;
+
+  if (EtherCAT_async_send_receive(master) < 0)
+  {
+    EtherCAT_remove_command(master, cmd);
+    
+    return -1;
+  }
+
+  if (cmd->working_counter != 1)
+  {
+    EtherCAT_remove_command(master, cmd);
+    
+    EC_DBG(KERN_ERR "EtherCAT: Resetting FMMUs - Slave %04X did not respond!\n",
+           slave->station_address);
+    return -2;
+  }
+
+  EtherCAT_remove_command(master, cmd);
+
+  // Resetting Sync Manager channels
+
+  if (desc->type != ECAT_ST_SIMPLE_NOSYNC)
+  {
+    memset(data, 0x00, 256);
+
+    if ((cmd = EtherCAT_write(master, slave->station_address, 0x0800, 256, data)) == NULL)
+      return -1;
+
+    if (EtherCAT_async_send_receive(master) < 0)
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      return -1;
+    }
+
+    if (cmd->working_counter != 1)
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      EC_DBG(KERN_ERR "EtherCAT: Resetting SMs - Slave %04X did not respond!\n",
+             slave->station_address);
+      return -2;
+    }
+
+    EtherCAT_remove_command(master, cmd);
+  }
+
+  // Init Mailbox communication
+
+  if (desc->type == ECAT_ST_MAILBOX)
+  {
+    if (desc->sm0)
+    {
+      if ((cmd = EtherCAT_write(master, slave->station_address, 0x0800, 8, desc->sm0)) == NULL)
+        return -1;
+      
+      if (EtherCAT_async_send_receive(master) < 0)
+      {
+        EtherCAT_remove_command(master, cmd);
+        
+        return -1;
+      }
+      
+      if (cmd->working_counter != 1)
+      {
+        EtherCAT_remove_command(master, cmd);
+        
+        EC_DBG(KERN_ERR "EtherCAT: Setting SM0 - Slave %04X did not respond!\n",
+               slave->station_address);
+        return -3;
+      }
+      
+      EtherCAT_remove_command(master, cmd);
+    }
+
+    if (desc->sm1)
+    {
+      if ((cmd = EtherCAT_write(master, slave->station_address, 0x0808, 8, desc->sm1)) == NULL)
+        return -1;
+      
+      if (EtherCAT_async_send_receive(master) < 0)
+      {
+        EtherCAT_remove_command(master, cmd);
+        
+        return -1;
+      }
+      
+      if (cmd->working_counter != 1)
+      {
+        EtherCAT_remove_command(master, cmd);
+        
+        EC_DBG(KERN_ERR "EtherCAT: Setting SM1 - Slave %04X did not respond!\n",
+               slave->station_address);
+        return -2;
+      }
+      
+      EtherCAT_remove_command(master, cmd);
+    }
+  }
+
+  // Change state to PREOP
+
+  if (EtherCAT_state_change(master, slave, ECAT_STATE_PREOP) != 0)
+  {
+    return -5;
+  }
+
+  // Set FMMU's
+
+  if (desc->fmmu0)
+  {
+    memcpy(fmmu, desc->fmmu0, 16);
+
+    fmmu[0] = slave->logical_address0 & 0x000000FF;
+    fmmu[1] = (slave->logical_address0 & 0x0000FF00) >> 8;    
+    fmmu[2] = (slave->logical_address0 & 0x00FF0000) >> 16;
+    fmmu[3] = (slave->logical_address0 & 0xFF000000) >> 24;
+
+    if ((cmd = EtherCAT_write(master, slave->station_address, 0x0600, 16, fmmu)) == NULL)
+      return -1;
+
+    if (EtherCAT_async_send_receive(master) < 0)
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      return -1;
+    }
+
+    if (cmd->working_counter != 1)
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      EC_DBG(KERN_ERR "EtherCAT: Setting FMMU0 - Slave %04X did not respond!\n",
+             slave->station_address);
+      return -2;
+    }
+
+    EtherCAT_remove_command(master, cmd);
+  }
+
+  // Set Sync Managers
+
+  if (desc->type != ECAT_ST_MAILBOX)
+  {
+    if (desc->sm0)
+    {
+      if ((cmd = EtherCAT_write(master, slave->station_address, 0x0800, 8, desc->sm0)) == NULL)
+        return -1;
+      
+      if (EtherCAT_async_send_receive(master) < 0)
+      {
+        EtherCAT_remove_command(master, cmd);
+        
+        return -1;
+      }
+
+      if (cmd->working_counter != 1)
+      {
+        EtherCAT_remove_command(master, cmd);
+        
+        EC_DBG(KERN_ERR "EtherCAT: Setting SM0 - Slave %04X did not respond!\n",
+               slave->station_address);
+        return -3;
+      }
+      
+      EtherCAT_remove_command(master, cmd);
+    }
+
+    if (desc->sm1)
+    {
+      if ((cmd = EtherCAT_write(master, slave->station_address, 0x0808, 8, desc->sm1)) == NULL)
+        return -1;
+      
+      if (EtherCAT_async_send_receive(master) < 0)
+      {
+        EtherCAT_remove_command(master, cmd);
+        
+        return -1;
+      }
+      
+      if (cmd->working_counter != 1)
+      {
+        EtherCAT_remove_command(master, cmd);
+        
+        EC_DBG(KERN_ERR "EtherCAT: Setting SM1 - Slave %04X did not respond!\n",
+               slave->station_address);
+        return -3;
+      }
+      
+      EtherCAT_remove_command(master, cmd);
+    }
+  }
+  
+  if (desc->sm2)
+  {
+    if ((cmd = EtherCAT_write(master, slave->station_address, 0x0810, 8, desc->sm2)) == NULL)
+      return -1;
+      
+    if (EtherCAT_async_send_receive(master) < 0)
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      return -1;
+    }
+      
+    if (cmd->working_counter != 1)
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      EC_DBG(KERN_ERR "EtherCAT: Setting SM2 - Slave %04X did not respond!\n",
+             slave->station_address);
+      return -3;
+    }
+      
+    EtherCAT_remove_command(master, cmd);
+  }
+
+  if (desc->sm3)
+  {
+    if ((cmd = EtherCAT_write(master, slave->station_address, 0x0818, 8, desc->sm3)) == NULL)
+      return -1;
+      
+    if (EtherCAT_async_send_receive(master) < 0)
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      return -1;
+    }
+
+    if (cmd->working_counter != 1)
+    {
+      EtherCAT_remove_command(master, cmd);
+      
+      EC_DBG(KERN_ERR "EtherCAT: Setting SM3 - Slave %04X did not respond!\n",
+             slave->station_address);
+      return -3;
+    }
+      
+    EtherCAT_remove_command(master, cmd);
+  }
+
+  // Change state to SAVEOP
+  if (EtherCAT_state_change(master, slave, ECAT_STATE_SAVEOP) != 0)
+  {
+    return -12;
+  }
+
+  // Change state to OP
+  if (EtherCAT_state_change(master, slave, ECAT_STATE_OP) != 0)
+  {
+    return -13;
+  }
+
+  return 0;
+}
+
+/***************************************************************/
+
+/**
+   Setzt einen Slave zurück in den Init-Zustand.
+
+   @param master EtherCAT-Master
+   @param slave Zu deaktivierender Slave
+   
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_deactivate_slave(EtherCAT_master_t *master,
+                            EtherCAT_slave_t *slave)
+{
+  if (EtherCAT_state_change(master, slave, ECAT_STATE_INIT) != 0)
+  {
+    return -1;
+  }
+
+  return 0;
+}
+
+/***************************************************************/
+
+/**
+   Aktiviert alle Slaves.
+
+   @see EtherCAT_activate_slave
+
+   @param master EtherCAT-Master
+   
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_activate_all_slaves(EtherCAT_master_t *master)
+{
+  unsigned int i;
+
+  for (i = 0; i < master->slave_count; i++)
+  {
+    EC_DBG("Activate Slave: %d\n",i);
+
+    if (EtherCAT_activate_slave(master, &master->slaves[i]) < 0)
+    {
+      return -1;
+    }
+
+    EC_DBG("done...\n");
+  }
+
+  return 0;
+}
+
+/***************************************************************/
+
+/**
+   Deaktiviert alle Slaves.
+
+   @see EtherCAT_deactivate_slave
+
+   @param master EtherCAT-Master
+   
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_deactivate_all_slaves(EtherCAT_master_t *master)
+{
+  unsigned int i;
+  int ret = 0;
+
+  for (i = 0; i < master->slave_count; i++)
+  {
+    EC_DBG("Deactivate Slave: %d\n",i);
+    
+    if (EtherCAT_deactivate_slave(master, &master->slaves[i]) < 0)
+    {
+      ret = -1;
+    }
+    
+    EC_DBG("done...\n");
+  }
+
+  return ret;
+}
+
+/***************************************************************/
+
+/**
+   Sendet alle Prozessdaten an die Slaves.
+
+   Erstellt ein "logical read write"-Kommando mit den
+   Prozessdaten des Masters und sendet es an den Bus.
+
+   @param master EtherCAT-Master
+   
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_write_process_data(EtherCAT_master_t *master)
+{
+  if (master->process_data_command)
+  {
+    EtherCAT_remove_command(master, master->process_data_command);
+    EtherCAT_command_clear(master->process_data_command);
+    master->process_data_command = NULL;
+  }
+
+  if ((master->process_data_command
+       = EtherCAT_logical_read_write(master, 0,
+                                     master->process_data_length,
+                                     master->process_data)) == NULL)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Could not allocate process data command!\n");
+    return -1;
+  }
+
+  if (EtherCAT_send(master) < 0)
+  {
+    EtherCAT_remove_command(master, master->process_data_command);
+    EtherCAT_command_clear(master->process_data_command);
+    master->process_data_command = NULL;
+    EC_DBG(KERN_ERR "EtherCAT: Could not send process data command!\n");
+    return -1;
+  }
+
+  return 0;
+}
+
+/***************************************************************/
+
+/**
+   Empfängt alle Prozessdaten von den Slaves.
+
+   Empfängt ein zuvor gesendetes "logical read write"-Kommando
+   und kopiert die empfangenen daten in den Prozessdatenspeicher
+   des Masters.
+
+   @param master EtherCAT-Master
+   
+   @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_read_process_data(EtherCAT_master_t *master)
+{
+  int ret = -1;
+
+  if (!master->process_data_command)
+  {
+    EC_DBG(KERN_WARNING "EtherCAT: No process data command available!\n");
+    return -1;
+  }
+
+  if (EtherCAT_receive(master) < 0)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Could not receive cyclic command!\n");
+  }
+  else if (master->process_data_command->state != ECAT_CS_RECEIVED)
+  {
+    EC_DBG(KERN_WARNING "EtherCAT: Process data command not received!\n");
+  }
+  else
+  {
+    // Daten von Kommando in Prozessdaten des Master kopieren
+    memcpy(master->process_data, master->process_data_command->data, master->process_data_length);
+    ret = 0;
+  }
+
+  EtherCAT_remove_command(master, master->process_data_command);
+  EtherCAT_command_clear(master->process_data_command);
+  master->process_data_command = NULL;
+
+  return ret;
+}
+
+/***************************************************************/
+
+/**
+   Setzt einen Byte-Wert im Speicher.
+
+   @param data Startadresse
+   @param offset Byte-Offset
+   @param value Wert
+*/
+
+void set_byte(unsigned char *data,
+              unsigned int offset,
+              unsigned char value)
+{
+  data[offset] = value;
+}
+
+/***************************************************************/
+
+/**
+   Setzt einen Word-Wert im Speicher.
+
+   @param data Startadresse
+   @param offset Byte-Offset
+   @param value Wert
+*/
+
+void set_word(unsigned char *data,
+              unsigned int offset,
+              unsigned int value)
+{
+  data[offset] = value & 0xFF;
+  data[offset + 1] = (value & 0xFF00) >> 8;
+}
+
+/***************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ec_master.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,134 @@
+/****************************************************************
+ *
+ *  e c _ m a s t e r . h
+ *
+ *  Struktur für einen EtherCAT-Master.
+ *
+ *  $Date$
+ *  $Author$
+ *
+ ***************************************************************/
+
+#ifndef _EC_MASTER_H_
+#define _EC_MASTER_H_
+
+#include "ec_device.h"
+#include "ec_slave.h"
+#include "ec_command.h"
+
+/***************************************************************/
+
+/**
+   EtherCAT-Master
+
+   Verwaltet die EtherCAT-Slaves und kommuniziert mit
+   dem zugewiesenen EtherCAT-Gerät.
+*/
+
+typedef struct
+{
+  EtherCAT_slave_t *slaves; /**< Zeiger auf statischen Speicher
+                               mit Slave-Informationen */
+  unsigned int slave_count; /**< Anzahl der Slaves in slaves */
+
+  EtherCAT_command_t *first_command; /**< Zeiger auf das erste
+                                        Kommando in der Liste */
+  EtherCAT_command_t *process_data_command; /**< Zeiger Auf das Kommando
+                                               zum Senden und Empfangen
+                                               der Prozessdaten */
+
+  EtherCAT_device_t *dev; /**< Zeiger auf das zugewiesene EtherCAT-Gerät */
+
+  unsigned char command_index; /**< Aktueller Kommando-Index */
+
+  unsigned char tx_data[ECAT_FRAME_BUFFER_SIZE]; /**< Statischer Speicher
+                                                    für zu sendende Daten */
+  unsigned int tx_data_length; /**< Länge der Daten im Sendespeicher */
+  unsigned char rx_data[ECAT_FRAME_BUFFER_SIZE]; /**< Statische Speicher für
+                                                    eine Kopie des Rx-Buffers
+                                                    im EtherCAT-Gerät */
+
+  unsigned char *process_data; /**< Zeiger auf Speicher mit Prozessdaten */
+  unsigned int process_data_length; /**< Länge der Prozessdaten */
+
+  EtherCAT_command_t cmd_ring[ECAT_COMMAND_RING_SIZE]; /** Statischer Kommandoring */
+  unsigned int cmd_ring_index; /**< Index des nächsten Kommandos im Ring */
+}
+EtherCAT_master_t;
+
+/***************************************************************/
+
+// Master creation and deletion
+int EtherCAT_master_init(EtherCAT_master_t *, EtherCAT_device_t *);
+void EtherCAT_master_clear(EtherCAT_master_t *);
+
+// Slave management
+int EtherCAT_check_slaves(EtherCAT_master_t *, EtherCAT_slave_t *, unsigned int);
+void EtherCAT_clear_slaves(EtherCAT_master_t *);
+int EtherCAT_activate_slave(EtherCAT_master_t *, EtherCAT_slave_t *);
+int EtherCAT_deactivate_slave(EtherCAT_master_t *, EtherCAT_slave_t *);
+int EtherCAT_activate_all_slaves(EtherCAT_master_t *);
+int EtherCAT_deactivate_all_slaves(EtherCAT_master_t *);
+
+// Sending and receiving
+int EtherCAT_async_send_receive(EtherCAT_master_t *);
+int EtherCAT_send(EtherCAT_master_t *);
+int EtherCAT_receive(EtherCAT_master_t *);
+int EtherCAT_write_process_data(EtherCAT_master_t *);
+int EtherCAT_read_process_data(EtherCAT_master_t *);
+
+/***************************************************************/
+
+// Slave information interface
+int EtherCAT_read_slave_information(EtherCAT_master_t *,
+                                    unsigned short int,
+                                    unsigned short int,
+                                    unsigned int *);
+
+// EtherCAT commands
+EtherCAT_command_t *EtherCAT_read(EtherCAT_master_t *,
+                                  unsigned short,
+                                  unsigned short,
+                                  unsigned int);
+EtherCAT_command_t *EtherCAT_write(EtherCAT_master_t *,
+                                   unsigned short,
+                                   unsigned short,
+                                   unsigned int,
+                                   const unsigned char *);
+EtherCAT_command_t *EtherCAT_position_read(EtherCAT_master_t *,
+                                           short,
+                                           unsigned short,
+                                           unsigned int);
+EtherCAT_command_t *EtherCAT_position_write(EtherCAT_master_t *,
+                                            short,
+                                            unsigned short,
+                                            unsigned int,
+                                            const unsigned char *);
+EtherCAT_command_t *EtherCAT_broadcast_read(EtherCAT_master_t *,
+                                            unsigned short,
+                                            unsigned int);
+EtherCAT_command_t *EtherCAT_broadcast_write(EtherCAT_master_t *,
+                                             unsigned short,
+                                             unsigned int,
+                                             const unsigned char *);
+EtherCAT_command_t *EtherCAT_logical_read_write(EtherCAT_master_t *,
+                                                unsigned int,
+                                                unsigned int,
+                                                unsigned char *);
+
+void EtherCAT_remove_command(EtherCAT_master_t *, EtherCAT_command_t *);
+
+// Slave states
+int EtherCAT_state_change(EtherCAT_master_t *, EtherCAT_slave_t *, unsigned char);
+
+/***************************************************************/
+
+// Private functions
+EtherCAT_command_t *alloc_cmd(EtherCAT_master_t *);
+void add_command(EtherCAT_master_t *, EtherCAT_command_t *);
+void set_byte(unsigned char *, unsigned int, unsigned char);
+void set_word(unsigned char *, unsigned int, unsigned int);
+
+/***************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ec_slave.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,160 @@
+/****************************************************************
+ *
+ *  e c _ s l a v e . c
+ *
+ *  Methoden für einen EtherCAT-Slave.
+ *
+ *  $Date$
+ *  $Author$
+ *
+ ***************************************************************/
+
+#include <linux/kernel.h>
+
+#include "ec_globals.h"
+#include "ec_slave.h"
+#include "ec_dbg.h"
+
+/***************************************************************/
+
+/**
+   EtherCAT-Slave-Konstruktor.
+
+   Initialisiert einen EtherCAT-Slave.
+
+   @param slave Zeiger auf den zu initialisierenden Slave
+*/
+
+void EtherCAT_slave_init(EtherCAT_slave_t *slave)
+{
+  slave->type = 0;
+  slave->revision = 0;
+  slave->build = 0;
+
+  slave->ring_position = 0;
+  slave->station_address = 0;
+
+  slave->vendor_id = 0;
+  slave->product_code = 0;
+  slave->revision_number = 0;
+  
+  slave->desc = 0;
+  
+  slave->logical_address0 = 0;
+
+  slave->current_state = ECAT_STATE_UNKNOWN;
+  slave->requested_state = ECAT_STATE_UNKNOWN;
+}
+
+/***************************************************************/
+
+/**
+   EtherCAT-Slave-Destruktor.
+
+   Im Moment ohne Funktionalität.
+
+   @param slave Zeiger auf den zu zerstörenden Slave
+*/
+
+void EtherCAT_slave_clear(EtherCAT_slave_t *slave)
+{
+  // Nothing yet...
+}
+
+/***************************************************************/
+
+/**
+   Liest einen bestimmten Kanal des Slaves als Integer-Wert.
+
+   Prüft zuerst, ob der entsprechende Slave eine
+   bekannte Beschreibung besitzt, ob dort eine
+   read()-Funktion hinterlegt ist und ob die angegebene
+   Kanalnummer gültig ist. Wenn ja, wird der dekodierte
+   Wert zurückgegeben, sonst ist der Wert 0.
+
+   @param slave EtherCAT-Slave
+   @param channel Kanalnummer
+
+   @return Gelesener Wert bzw. 0
+*/
+
+int EtherCAT_read_value(EtherCAT_slave_t *slave,
+                        unsigned int channel)
+{
+  if (!slave->desc)
+  {
+    EC_DBG(KERN_WARNING "EtherCAT: Reading failed - "
+           "Slave %04X (at %0X) has no description.\n",
+           slave->station_address, (unsigned int) slave);
+    return 0;
+  }
+
+  if (!slave->desc->read)
+  {
+    EC_DBG(KERN_WARNING "EtherCAT: Reading failed - "
+           "Slave type (%s %s) has no read method.\n",
+           slave->desc->vendor_name, slave->desc->product_name);
+    return 0;
+  }
+
+  if (channel >= slave->desc->channels)
+  {
+    EC_DBG(KERN_WARNING "EtherCAT: Reading failed - "
+           "Slave %4X (%s %s) has no channel %i.\n",
+           slave->station_address, slave->desc->vendor_name,
+           slave->desc->product_name, channel);
+    return 0;
+  }
+
+  return slave->desc->read(slave->process_data, channel);
+}
+
+/***************************************************************/
+
+/**
+   Schreibt einen bestimmten Kanal des Slaves als Integer-Wert .
+
+   Prüft zuerst, ob der entsprechende Slave eine
+   bekannte Beschreibung besitzt, ob dort eine
+   write()-Funktion hinterlegt ist und ob die angegebene
+   Kanalnummer gültig ist. Wenn ja, wird der Wert entsprechend
+   kodiert und geschrieben.
+
+   @param slave EtherCAT-Slave
+   @param channel Kanalnummer
+   @param value Zu schreibender Wert
+*/
+
+void EtherCAT_write_value(EtherCAT_slave_t *slave,
+                          unsigned int channel,
+                          int value)
+{
+  if (!slave->desc)
+  {
+    EC_DBG(KERN_WARNING "EtherCAT: Writing failed - "
+           "Slave %04X (at %0X) has no description.\n",
+           slave->station_address, (unsigned int) slave);
+    return;
+  }
+
+  if (!slave->desc->write)
+  {
+    EC_DBG(KERN_WARNING "EtherCAT: Writing failed - "
+           "Slave type (%s %s) has no write method.\n",
+           slave->desc->vendor_name, slave->desc->product_name);
+    return;
+  }
+
+  if (channel >= slave->desc->channels)
+  {
+    EC_DBG(KERN_WARNING "EtherCAT: Writing failed - "
+           "Slave %4X (%s %s) has no channel %i.\n",
+           slave->station_address, slave->desc->vendor_name,
+           slave->desc->product_name, channel);
+    return;
+  }
+
+  slave->desc->write(slave->process_data, channel, value);
+}
+
+/***************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ec_slave.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,67 @@
+/****************************************************************
+ *
+ *  e c _ s l a v e . h
+ *
+ *  Struktur für einen EtherCAT-Slave.
+ *
+ *  $Date$
+ *  $Author$
+ *
+ ***************************************************************/
+
+#ifndef _EC_SLAVE_H_
+#define _EC_SLAVE_H_
+
+#include "ec_types.h"
+
+/***************************************************************/
+
+/**
+   EtherCAT-Slave
+*/
+
+typedef struct
+{
+  // Base data
+  unsigned char type; /**< Slave-Typ */
+  unsigned char revision; /**< Revision */
+  unsigned short build; /**< Build-Nummer */
+
+  // Addresses
+  short ring_position; /**< (Negative) Position des Slaves im Bus */
+  unsigned short station_address; /**< Konfigurierte Slave-Adresse */
+
+  // Slave information interface
+  unsigned int vendor_id; /**< Identifikationsnummer des Herstellers */
+  unsigned int product_code; /**< Herstellerspezifischer Produktcode */
+  unsigned int revision_number; /**< Revisionsnummer */
+
+  const EtherCAT_slave_desc_t *desc; /**< Zeiger auf die Beschreibung
+                                        des Slave-Typs */
+
+  unsigned int logical_address0; /**< Konfigurierte, logische adresse */
+
+  EtherCAT_state_t current_state; /**< Aktueller Zustand */
+  EtherCAT_state_t requested_state; /**< Angeforderter Zustand */
+
+  unsigned char *process_data; /**< Zeiger auf den Speicherbereich
+                                  im Prozessdatenspeicher des Masters */
+}
+EtherCAT_slave_t;
+
+#define ECAT_INIT_SLAVE(TYPE) {0, 0, 0, 0, 0, 0, 0, 0, \
+                               TYPE, 0, ECAT_STATE_UNKNOWN, \
+                               ECAT_STATE_UNKNOWN, NULL}
+
+/***************************************************************/
+
+// Slave construction and deletion
+void EtherCAT_slave_init(EtherCAT_slave_t *);
+void EtherCAT_slave_clear(EtherCAT_slave_t *);
+
+int EtherCAT_read_value(EtherCAT_slave_t *, unsigned int);
+void EtherCAT_write_value(EtherCAT_slave_t *, unsigned int, int);
+
+/***************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ec_types.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,157 @@
+/****************************************************************
+ *
+ *  e c _ t y p e s . c
+ *
+ *  EtherCAT-Slave-Typen.
+ *
+ *  $Date: 2005-09-07 17:50:50 +0200 (Mit, 07 Sep 2005) $
+ *  $Author: fp $
+ *
+ ***************************************************************/
+
+#include "ec_globals.h"
+#include "ec_types.h"
+
+/***************************************************************/
+
+unsigned char sm0_multi[] = {0x00, 0x18, 0xF6, 0x00, 0x26, 0x00, 0x01, 0x00};
+unsigned char sm1_multi[] = {0xF6, 0x18, 0xF6, 0x00, 0x22, 0x00, 0x01, 0x00};
+
+unsigned char sm0_1014[] = {0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00};
+
+unsigned char sm0_2004[] = {0x00, 0x0F, 0x01, 0x00, 0x46, 0x00, 0x01, 0x00};
+
+unsigned char sm2_31xx[] = {0x00, 0x10, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00};
+unsigned char sm3_31xx[] = {0x00, 0x11, 0x06, 0x00, 0x20, 0x00, 0x01, 0x00};
+
+unsigned char sm2_4102[] = {0x00, 0x10, 0x04, 0x00, 0x24, 0x00, 0x01, 0x00};
+
+
+unsigned char fmmu0_1014[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07,
+                              0x00, 0x10, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00};
+
+unsigned char fmmu0_2004[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07,
+                              0x00, 0x0F, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00};
+
+unsigned char fmmu0_31xx[] = {0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07,
+                              0x00, 0x11, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00};
+
+unsigned char fmmu0_4102[] = {0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07,
+                              0x00, 0x10, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00};
+
+int read_1014(unsigned char *data, unsigned int channel)
+{
+  return (data[0] >> channel) & 0x01;
+}
+
+void write_2004(unsigned char *data, unsigned int channel, int value)
+{
+  if (value)
+  {
+    data[0] |= (1 << channel);
+  }
+  else
+  {
+    data[0] &= ~(1 << channel);
+  }
+}
+
+int read_31xx(unsigned char *data, unsigned int channel)
+{
+  return (short int) ((data[channel * 3 + 2] << 8) | data[channel * 3 + 1]);
+}
+
+void write_4102(unsigned char *data, unsigned int channel, int value)
+{
+  data[channel * 3 + 1] = (value & 0xFF00) >> 8;
+  data[channel * 3 + 2] = value & 0xFF;
+}
+
+/***************************************************************/
+
+EtherCAT_slave_desc_t Beckhoff_EK1100[] =
+{{
+  "Beckhoff", "EK1100", "Bus Coupler",
+  ECAT_ST_SIMPLE_NOSYNC,
+  NULL, NULL, NULL, NULL,
+  NULL,
+  0, 0,
+  NULL, NULL
+}};
+
+EtherCAT_slave_desc_t Beckhoff_EL1014[] =
+{{
+  "Beckhoff", "EL1014", "4x Digital Input",
+  ECAT_ST_SIMPLE,
+  sm0_1014, NULL, NULL, NULL,
+  fmmu0_1014,
+  1, 4,
+  read_1014, NULL
+}};
+
+EtherCAT_slave_desc_t Beckhoff_EL2004[] =
+{{
+  "Beckhoff", "EL2004", "4x Digital Output",
+  ECAT_ST_SIMPLE,
+  sm0_2004, NULL, NULL, NULL,
+  fmmu0_2004,
+  1, 4,
+  NULL, write_2004
+}};
+
+EtherCAT_slave_desc_t Beckhoff_EL3102[] =
+{{
+  "Beckhoff", "EL3102", "2x Analog Input Diff",
+  ECAT_ST_MAILBOX,
+  sm0_multi, sm1_multi, sm2_31xx, sm3_31xx,
+  fmmu0_31xx,
+  6, 2,
+  read_31xx, NULL
+}};
+
+EtherCAT_slave_desc_t Beckhoff_EL3162[] =
+{{
+  "Beckhoff", "EL3162", "2x Analog Input",
+  ECAT_ST_MAILBOX,
+  sm0_multi, sm1_multi, sm2_31xx, sm3_31xx,
+  fmmu0_31xx,
+  6, 2,
+  read_31xx, NULL
+}};
+
+EtherCAT_slave_desc_t Beckhoff_EL4102[] =
+{{
+  "Beckhoff", "EL4102", "2x Analog Output",
+  ECAT_ST_MAILBOX,
+  sm0_multi, sm1_multi, sm2_4102, NULL,
+  fmmu0_4102,
+  4, 2,
+  NULL, write_4102
+}};
+
+EtherCAT_slave_desc_t Beckhoff_EL5001[] =
+{{
+  "Beckhoff", "EL5001", "SSI-Interface",
+  ECAT_ST_SIMPLE,
+  NULL, NULL, NULL, NULL, // Noch nicht eingepflegt...
+  NULL,
+  0, 0,
+  NULL, NULL
+}};
+
+/***************************************************************/
+
+unsigned int slave_idents_count = 7;
+
+struct slave_ident slave_idents[] = 
+{
+  {0x00000002, 0x03F63052, Beckhoff_EL1014},
+  {0x00000002, 0x044C2C52, Beckhoff_EK1100},
+  {0x00000002, 0x07D43052, Beckhoff_EL2004},
+  {0x00000002, 0x0C1E3052, Beckhoff_EL3102},
+  {0x00000002, 0x0C5A3052, Beckhoff_EL3162},
+  {0x00000002, 0x10063052, Beckhoff_EL4102},
+  {0x00000002, 0x13893052, Beckhoff_EL5001}
+};
+
+/***************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/ec_types.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,104 @@
+/****************************************************************
+ *
+ *  e c _ t y p e s . h
+ *
+ *  EtherCAT-Slave-Typen.
+ *
+ *  $Date: 2005-09-07 17:50:50 +0200 (Mit, 07 Sep 2005) $
+ *  $Author: fp $
+ *
+ ***************************************************************/
+
+#ifndef _EC_TYPES_H_
+#define _EC_TYPES_H_
+
+/**
+   Typ eines EtherCAT-Slaves.
+
+   Dieser Typ muss für die Konfiguration bekannt sein. Der
+   Master entscheidet danach, ober bspw. Mailboxes konfigurieren,
+   oder Sync-Manager setzen soll.
+*/
+
+typedef enum
+{
+  ECAT_ST_SIMPLE, ECAT_ST_MAILBOX, ECAT_ST_SIMPLE_NOSYNC
+}
+EtherCAT_slave_type_t;
+
+/***************************************************************/
+
+/**
+   Beschreibung eines EtherCAT-Slave-Typs.
+
+   Diese Beschreibung dient zur Konfiguration einer bestimmten
+   Slave-Art. Sie enthält die Konfigurationsdaten für die
+   Slave-internen Sync-Manager und FMMU's.
+*/
+
+typedef struct slave_desc
+{
+  const char *vendor_name; /**< Name des Herstellers */
+  const char *product_name; /**< Name des Slaves-Typs */
+  const char *product_desc; /**< Genauere Beschreibung des Slave-Typs */
+
+  const EtherCAT_slave_type_t type; /**< Art des Slave-Typs */
+
+  const unsigned char *sm0; /**< Konfigurationsdaten des
+                               ersten Sync-Managers */
+  const unsigned char *sm1; /**< Konfigurationsdaten des
+                               zweiten Sync-Managers */
+  const unsigned char *sm2; /**< Konfigurationsdaten des
+                               dritten Sync-Managers */
+  const unsigned char *sm3; /**< Konfigurationsdaten des
+                               vierten Sync-Managers */
+
+  const unsigned char *fmmu0; /**< Konfigurationsdaten
+                                 der ersten FMMU */
+
+  const unsigned int data_length; /**< Länge der Prozessdaten in Bytes */
+  const unsigned int channels; /**< Anzahl der Kanäle */
+
+  int (*read) (unsigned char *, unsigned int); /**< Funktion zum Dekodieren
+                                                  und Lesen der Kanaldaten */
+  void (*write) (unsigned char *, unsigned int, int); /**< Funktion zum Kodieren
+                                                         und Schreiben der
+                                                         Kanaldaten */
+}
+EtherCAT_slave_desc_t;
+
+/***************************************************************/
+
+/**
+   Identifikation eines Slave-Typs.
+
+   Diese Struktur wird zur 1:n-Zuordnung von Hersteller- und
+   Produktcodes zu den einzelnen Slave-Typen verwendet.
+*/
+
+struct slave_ident
+{
+  const unsigned int vendor_id; /**< Hersteller-Code */
+  const unsigned int product_code; /**< Herstellerspezifischer Produktcode */
+  const EtherCAT_slave_desc_t *desc; /**< Zeiger auf den dazugehörigen
+                                        Slave-Typ */
+};
+
+extern struct slave_ident slave_idents[]; /**< Statisches Array der
+                                             Slave-Identifikationen */
+extern unsigned int slave_idents_count; /**< Anzahl der bekannten Slave-
+                                           Identifikationen */
+
+/***************************************************************/
+
+extern EtherCAT_slave_desc_t Beckhoff_EK1100[];
+extern EtherCAT_slave_desc_t Beckhoff_EL1014[];
+extern EtherCAT_slave_desc_t Beckhoff_EL2004[];
+extern EtherCAT_slave_desc_t Beckhoff_EL3102[];
+extern EtherCAT_slave_desc_t Beckhoff_EL3162[];
+extern EtherCAT_slave_desc_t Beckhoff_EL4102[];
+extern EtherCAT_slave_desc_t Beckhoff_EL5001[];
+
+/***************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mini/Makefile	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,41 @@
+#----------------------------------------------------------------
+#
+#  Makefile
+#
+#  Minimales EtherCAT-Modul
+#
+#  $Id$
+#
+#----------------------------------------------------------------
+
+MSRDIR = /vol/projekte/msr_messen_steuern_regeln
+KERNELDIR = $(MSRDIR)/linux/kernel/2.4.20/include/linux-2.4.20.CX1100-rthal5
+CFLAGS = -O2 -Wall -Wuninitialized -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include
+
+MODULE = ec_mini_mod.o
+
+SRC = ec_mini.c 
+OBJ = $(SRC:.c=.o)
+
+#----------------------------------------------------------------
+
+all: .depend Makefile $(MODULE)
+
+$(MODULE): $(OBJ)
+	$(LD) -r $(OBJ) -o $@
+
+#----------------------------------------------------------------
+
+depend .depend dep:
+	$(CC) $(CFLAGS) -M $(SRC) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+#----------------------------------------------------------------
+
+clean:
+	rm -f *.o *~ core .depend
+
+#----------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mini/ec_mini.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,345 @@
+/******************************************************************************
+ *
+ * ec_mini.c
+ *
+ * Minimalmodul für EtherCAT
+ *           
+ * $Id$
+ *
+ ******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/tqueue.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "../drivers/ec_master.h"
+#include "../drivers/ec_device.h"
+#include "../drivers/ec_types.h"
+#include "../drivers/ec_dbg.h"
+
+extern EtherCAT_device_t rtl_ecat_dev;
+
+//static EtherCAT_master_t *ecat_master = NULL;
+
+#if 0
+static EtherCAT_slave_t ecat_slaves[] =
+{
+  // Block 1
+  ECAT_INIT_SLAVE(Beckhoff_EK1100),
+  ECAT_INIT_SLAVE(Beckhoff_EL4102),
+  ECAT_INIT_SLAVE(Beckhoff_EL3162),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL3102),
+  ECAT_INIT_SLAVE(Beckhoff_EL4102),
+  ECAT_INIT_SLAVE(Beckhoff_EL4102),
+  ECAT_INIT_SLAVE(Beckhoff_EL4102),
+  ECAT_INIT_SLAVE(Beckhoff_EL3162),
+  ECAT_INIT_SLAVE(Beckhoff_EL3162),
+  ECAT_INIT_SLAVE(Beckhoff_EL3162),
+  ECAT_INIT_SLAVE(Beckhoff_EL3102),
+  ECAT_INIT_SLAVE(Beckhoff_EL3102),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+
+  // Block 2
+  ECAT_INIT_SLAVE(Beckhoff_EK1100),
+  ECAT_INIT_SLAVE(Beckhoff_EL4102),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL3162),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL3102),
+
+  // Block 3
+  ECAT_INIT_SLAVE(Beckhoff_EK1100),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014)
+};
+
+#define ECAT_SLAVES_COUNT (sizeof(ecat_slaves) / sizeof(EtherCAT_slave_t))
+#endif
+
+double value;
+int dig1;
+
+/******************************************************************************
+ *
+ * Function: next2004
+ *
+ *****************************************************************************/
+
+#if 0
+static int next2004(int *wrap)
+{
+  static int i = 0;
+  unsigned int j = 0;
+
+  *wrap = 0;
+
+  for (j = 0; j < ECAT_SLAVES_COUNT; j++)
+  {
+    i++;
+
+    i %= ECAT_SLAVES_COUNT;
+
+    if (i == 0) *wrap = 1;
+
+    if (ecat_slaves[i].desc == Beckhoff_EL2004)
+    {
+      return i;
+    }
+  }
+
+  return -1;
+}
+#endif
+
+/******************************************************************************
+ *
+ * Function: msr_controller
+ *
+ * Beschreibung: Zyklischer Prozess
+ *
+ *****************************************************************************/
+
+#if 0
+void msr_controller()
+{
+  static int ms = 0;
+  static int cnt = 0;
+  static unsigned long int k = 0;
+  static int firstrun = 1;
+  
+  static int klemme = 12;
+  static int kanal = 0;
+  static int up_down = 0;
+  int wrap = 0;
+
+  ms++;
+  ms %= 1000;
+
+#if 0
+  ecat_tx_delay = ((unsigned int) (100000 / HZ) * (ecat_master->dev->tx_time-k))
+    / (current_cpu_data.loops_per_jiffy / 10);  
+  ecat_rx_delay = ((unsigned int) (100000 / HZ) * (ecat_master->dev->rx_time-k))
+    / (current_cpu_data.loops_per_jiffy / 10);  
+  
+  rx_intr = ecat_master->dev->rx_intr_cnt;
+  tx_intr = ecat_master->dev->tx_intr_cnt;
+  total_intr = ecat_master->dev->intr_cnt;
+#endif
+
+  // Prozessdaten lesen
+  if (!firstrun)
+  {
+    EtherCAT_read_process_data(ecat_master);
+
+    // Daten lesen und skalieren
+    value = EtherCAT_read_value(&ecat_master->slaves[5], 0) / 3276.7;
+    dig1 = EtherCAT_read_value(&ecat_master->slaves[3], 0);
+  }
+
+  // Daten schreiben
+  EtherCAT_write_value(&ecat_master->slaves[4], 0, ms > 500 ? 1 : 0);
+  EtherCAT_write_value(&ecat_master->slaves[4], 1, ms > 500 ? 0 : 1);
+  EtherCAT_write_value(&ecat_master->slaves[4], 2, ms > 500 ? 0 : 1);
+  EtherCAT_write_value(&ecat_master->slaves[4], 3, ms > 500 ? 1 : 0);
+
+  if (cnt++ > 20)
+  {
+    cnt = 0;
+
+    if (++kanal > 3)
+    {
+      kanal = 0;
+      klemme = next2004(&wrap);
+
+      if (wrap == 1)
+      { 
+        if (up_down == 1) up_down = 0;
+        else up_down = 1;
+      }
+    }
+  }
+
+  if (klemme >= 0)
+    EtherCAT_write_value(&ecat_master->slaves[klemme], kanal,up_down);
+  
+  //EtherCAT_write_value(&ecat_master->slaves[13], 1, ms > 500 ? 0 : 1);
+  //EtherCAT_write_value(&ecat_master->slaves[14], 2, ms > 500 ? 0 : 1);
+  //EtherCAT_write_value(&ecat_master->slaves[15], 3, ms > 500 ? 1 : 0);
+  
+  // Prozessdaten schreiben
+  rdtscl(k);
+  EtherCAT_write_process_data(ecat_master);
+  firstrun = 0;
+}
+#endif
+
+/******************************************************************************
+*
+* Function: init
+*
+******************************************************************************/
+
+//#define ECAT_OPEN
+
+int init()
+{   
+#ifdef ECAT_OPEN
+  int rv = -1;
+#endif
+
+  EC_DBG(KERN_INFO "=== Starting Minimal EtherCAT environment... ===\n");
+
+  EtherCAT_device_debug(&rtl_ecat_dev);
+  //mdelay(5000);
+
+#ifdef ECAT_OPEN
+  EC_DBG("Opening EtherCAT device.\n");
+
+  // HIER PASSIERT DER FEHLER:
+  if (EtherCAT_device_open(&rtl_ecat_dev) < 0)
+  {
+    EC_DBG(KERN_ERR "msr_modul: Could not initialize EtherCAT NIC.\n");
+    goto out_nothing;
+  }
+
+  if (!rtl_ecat_dev.dev) // Es gibt kein EtherCAT-Device
+  {  
+    EC_DBG(KERN_ERR "msr_modul: No EtherCAT device!\n");
+    goto out_close;
+  }
+#endif
+
+#if 0
+  // EtherCAT-Master und Slaves initialisieren
+  EC_DBG("Initialising EtherCAT master\n");
+
+  if ((ecat_master = (EtherCAT_master_t *) kmalloc(sizeof(EtherCAT_master_t), GFP_KERNEL)) == 0)
+  {
+    EC_DBG(KERN_ERR "msr_modul: Could not alloc memory for EtherCAT master!\n");
+    goto out_close;
+  }
+
+  if (EtherCAT_master_init(ecat_master, &rtl_ecat_dev) < 0)
+  {
+    EC_DBG(KERN_ERR "EtherCAT could not init master!\n");
+    goto out_master;
+  }
+#endif
+
+#if 0
+  EC_DBG("Checking EtherCAT slaves.\n");
+
+  if (EtherCAT_check_slaves(ecat_master, ecat_slaves, ECAT_SLAVES_COUNT) != 0)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Could not init slaves!\n");
+    goto out_masterclear;
+  }
+
+  EC_DBG("Activating all EtherCAT slaves.\n");
+
+  if (EtherCAT_activate_all_slaves(ecat_master) != 0)
+  {
+    EC_DBG(KERN_ERR "EtherCAT: Could not activate slaves!\n");
+    goto out_masterclear;
+  }
+
+  // Zyklischen Aufruf starten
+
+  EC_DBG("Starting cyclic sample thread.\n");
+
+  EtherCAT_write_process_data(ecat_master);
+
+  EC_DBG("Initialised sample thread.\n");
+#endif
+
+  EC_DBG(KERN_INFO "=== Minimal EtherCAT environment started. ===\n");
+
+  return 0;
+
+#if 0
+ out_masterclear:
+  EC_DBG(KERN_INFO "Clearing EtherCAT master.\n");
+  EtherCAT_master_clear(ecat_master);
+#endif
+
+#if 0
+ out_master:
+  EC_DBG(KERN_INFO "Freeing EtherCAT master.\n");
+  kfree(ecat_master);
+#endif
+
+#ifdef ECAT_OPEN
+ out_close:
+  EC_DBG(KERN_INFO "Closing device.\n");
+  EtherCAT_device_close(&rtl_ecat_dev);
+
+ out_nothing:
+  return rv;
+#endif
+}
+
+/******************************************************************************
+*
+* Function: cleanup
+*
+******************************************************************************/
+
+void cleanup()
+{
+  EC_DBG(KERN_INFO "=== Stopping Minimal EtherCAT environment... ===\n");
+
+  // Noch einmal lesen
+  //EC_DBG(KERN_INFO "Reading process data.\n");
+  //EtherCAT_read_process_data(ecat_master);
+
+#if 0
+  if (ecat_master)
+  {
+#if 0
+    EC_DBG(KERN_INFO "Deactivating slaves.\n");
+    EtherCAT_deactivate_all_slaves(ecat_master);
+#endif
+
+    EC_DBG(KERN_INFO "Clearing EtherCAT master.\n");
+    EtherCAT_master_clear(ecat_master);
+
+    EC_DBG(KERN_INFO "Freeing EtherCAT master.\n");
+    kfree(ecat_master);
+    ecat_master = NULL;
+  }
+#endif
+
+#ifdef ECAT_OPEN
+  EC_DBG(KERN_INFO "Closing device.\n");
+  EtherCAT_device_close(&rtl_ecat_dev);
+#endif
+
+  EC_DBG(KERN_INFO "=== Minimal EtherCAT environment stopped. ===\n");
+}
+
+/*****************************************************************************/
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Florian Pose <fp@igh-essen.com>");
+MODULE_DESCRIPTION ("Minimal EtherCAT environment");
+
+module_init(init);
+module_exit(cleanup);
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rs232dbg/Makefile	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,82 @@
+#IgH
+KERNELDIR = /vol/projekte/msr_messen_steuern_regeln/linux/kernel/2.4.20/include/linux-2.4.20.CX1100-rthal5
+RTAIDIR   = /vol/projekte/msr_messen_steuern_regeln/linux/kernel/2.4.20/include/rtai-24.1.13
+RTLIBDIR = rt_lib
+
+#euler-nottuln
+#KERNELDIR = /usr/src/linux
+#RTAIDIR = /usr/src/rtai
+
+#patra
+#KERNELDIR = /usr/src/linux-2.4.20.CX1100-rthal5
+#RTAIDIR   = /usr/src/rtai-24.1.13
+
+RTLIBDIR=rt_lib
+
+#include $(KERNELDIR)/.config
+
+#CFLAGS = -DRTAI -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -I$(RTAIDIR)/include -I$(RTLIBDIR)/msr-include \
+#	-Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fomit-frame-pointer \
+#	-pipe -mpreferred-stack-boundary=2 -march=i686 -nostdinc -iwithprefix include
+
+CFLAGS = -O2 -Wall -Wuninitialized -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -D_RTAI -I$(RTAIDIR)/include -I$(RTLIBDIR)/msr-include
+
+#CFLAGS += -DSIMULATION
+#LDFLAGS = 
+
+#VPATH = $(RTLIBDIR)/
+
+TARGET = sdbg
+MODULE = $(TARGET).o
+
+SRC = rs232dbg.c aip_com.c
+
+#Suchpfad für die Dateien aus dem RT-Lib-Verzeichnis
+VPATH = $(RTLIBDIR)/msr-core:$(RTLIBDIR)/msr-control:$(RTLIBDIR)/msr-math:$(RTLIBDIR)/msr-misc:$(RTLIBDIR)/msr-utils
+
+#Datei aus dem RT-Libverzeichnis für dies Projekt
+RTSRC = 
+
+ALLSRC = $(SRC) $(RTSRC)
+
+OBJS = $(ALLSRC:.c=.o)  
+
+
+all: .depend $(TARGET).o Makefile
+
+$(TARGET).o: $(SRC:.c=.o) $(RTSRC:.c=.o)
+	$(LD) -r $(OBJS)  -o $@ $(LDFLAGS)
+
+install: msr_modul.o
+	lsmod | grep cif-rtai >/dev/null 2>&1 && sudo rmmod msr_modul || true
+	sudo insmod msr_modul.o
+
+clean:
+	rm -f *.o *~ core .depend
+
+depend .depend dep:
+	$(CC) $(CFLAGS) -M *.c > $@
+
+
+
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+
+#all: msr_module.o
+#
+#msr_io.o: msr_io.c msr_io.h
+#	$(CC) $(CFLAGS) -c -o $@ $<
+#
+#msr_module.o: msr_io.o
+#	$(LD) -r -o $@ $^
+#
+
+#                  $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
+
+
+#clean:
+#	rm -f *.o *~ core
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rs232dbg/aip_com.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,847 @@
+/** rt_com
+ *  ======
+ *
+ * RT-Linux kernel module for communication across serial lines.
+ *
+ * Copyright (C) 1997 Jens Michaelsen
+ * Copyright (C) 1997-2000 Jochen Kupper
+ * Copyright (C) 1999 Hua Mao <hmao@nmt.edu>
+ * Copyright (C) 1999 Roberto Finazzi
+ * Copyright (C) 2000-2002 Giuseppe Renoldi
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; see the file License. if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * $Id: aip_com.c,v 1.1 2005/09/16 14:16:31 hm Exp hm $ */
+#define VERSION "0.6.pre2-rtaicvs (modified by Hm, IgH for aip)"   //Hm, IgH
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#ifdef _RTAI
+#include <rtai.h>
+#endif
+
+#include "aip_com.h"
+#include "aip_comP.h"
+
+/* Hm, IgH
+MODULE_AUTHOR("Jochen Kuepper");
+MODULE_DESCRIPTION("real-time serial port driver");
+MODULE_LICENSE("GPL");
+*/
+
+
+/* size of internal queues
+* This is the default value. */
+unsigned int            rt_com_buffersize = RT_COM_BUF_SIZ;
+
+/** Default: mode=0 - no hw flow control
+ *           used=0 - port and irq setting by rt_com_hwparam.
+ *                    If you want to work like
+ *                    a standard rt_com you can set used=1. */
+struct rt_com_struct    rt_com_table[] = { 
+       {    // ttyS0 - COM1
+        RT_COM_BASE_BAUD,   // int baud_base;
+        0x3f8,          // int port;
+        4,              // int irq;
+        rt_com0_isr,    // void (*isr)(void);
+        115200,  // int baud;
+        8,  // unsigned int wordlength;
+        RT_COM_PARITY_NONE, // unsigned int parity;
+        1,  // stopbits;
+        RT_COM_NO_HAND_SHAKE,   // int mode;
+        RT_COM_FIFO_SIZE_8,     // int fifotrig;
+        1 //Hm, IgH   // int used;
+    }, {    // ttyS1 - COM2
+        RT_COM_BASE_BAUD,   // int baud_base;
+        0x2f8,          // int port;
+        3,              // int irq;
+        rt_com1_isr,    // void (*isr)(void);
+        0,  // int baud;
+        8,  // unsigned int wordlength;
+        RT_COM_PARITY_NONE, // unsigned int parity;
+        1,  // stopbits;
+        RT_COM_NO_HAND_SHAKE,   // int mode;
+        RT_COM_FIFO_SIZE_8,     // int fifotrig;
+        0   // int used;
+    }
+};
+
+/** Number and descriptions of serial ports to manage.  You also need
+ * to create an ISR ( rt_comN_isr() ) for each port.  */
+#define RT_COM_CNT  (sizeof(rt_com_table) / sizeof(struct rt_com_struct))
+
+/** Internal: Remaining free space of buffer
+ *
+ * @return amount of free space remaining in a buffer (input or output)
+ *
+ * @author Jochen Kupper
+ * @version 2000/03/10 */
+static inline unsigned int rt_com_buffer_free(unsigned int head, unsigned int tail)
+{
+    return(head < tail) ? (tail - head) : (rt_com_buffersize - (head - tail));
+}
+
+/** Clear input buffer.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @return       0 if all right, -ENODEV or -EPERM on error.
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/12 */
+int rt_com_clear_input(unsigned int ttyS)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else if (0 >= (rt_com_table[ttyS]).used) {
+        return(-EPERM);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        struct rt_buf_struct    *b = &(p->ibuf);
+        long                    state;
+        rt_com_irq_off(state);
+        b->tail = b->head;
+        if (p->fifotrig)
+            outb(inb(p->port + RT_COM_FCR) | FCR_INPUT_FIFO_RESET, p->port + RT_COM_FCR);
+        rt_com_irq_on(state);
+        if (p->mode & RT_COM_HW_FLOW) {
+            /* with hardware flow set RTS */
+            p->mcr |= MCR_RTS;
+            outb(p->mcr, p->port + RT_COM_MCR);
+        }
+
+        return(0);
+    }
+}
+
+/** Clear output buffer.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @return       0 if all right, negative error conditions otherwise
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/12
+ */
+int rt_com_clear_output(unsigned int ttyS)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (0 >= (rt_com_table[ttyS]).used) {
+            return(-EPERM);
+        }
+        else {
+            struct rt_buf_struct    *b = &(p->obuf);
+            long                    state;
+            rt_com_irq_off(state);
+            p->ier &= ~IER_ETBEI;
+            outb(p->ier, p->port | RT_COM_IER);
+            b->tail = b->head;
+            if (p->fifotrig)
+                outb(inb(p->port + RT_COM_FCR) | FCR_OUTPUT_FIFO_RESET, p->port + RT_COM_FCR);
+            rt_com_irq_on(state);
+            return(0);
+        }
+    }
+}
+
+/** Set functioning mode.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @param mode   functioning mode 
+ * @return       0 if all right, negative on error
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/12
+ */
+int rt_com_set_mode(unsigned int ttyS, int mode)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (0 >= p->used) {
+            return(-EPERM);
+        }
+        else {
+            p->mode = mode;
+            if (p->used & RT_COM_PORT_SETUP) {
+                /* setup done */
+                if (mode == RT_COM_NO_HAND_SHAKE) {
+                    /* if no hw signals disable modem interrupts */
+                    p->ier &= ~IER_EDSSI;
+                }
+                else {
+                    /* else enable it */
+                    p->ier |= IER_EDSSI;
+                }
+
+                outb(p->ier, p->port + RT_COM_IER);
+            }
+
+            return(0);
+        }
+    }
+}
+
+/** Set receiver fifo trigger level.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @param fifotrig   receiver fifo trigger level 
+ * @return           0 if all right, negative on error
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/12
+ */
+int rt_com_set_fifotrig(unsigned int ttyS, int fifotrig)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        p->fifotrig = fifotrig;
+        if (p->used & RT_COM_PORT_SETUP) {
+            /* setup done */
+            if (p->fifotrig)
+                outb(FCR_FIFO_ENABLE | p->fifotrig, p->port + RT_COM_FCR);  // enable fifo
+            else
+                outb(0, p->port + RT_COM_FCR);  // disable fifo	
+        }
+    }
+
+    return(0);
+}
+
+/** Set output signal for modem control (DTR, RTS).
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @param signal Output signals: RT_COM_DTR or RT_COM_RTS.
+ * @param value  Status: 0 or 1. 
+ * @return       0 if all right, negative error code otherwise
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/12 */
+int rt_com_write_modem(unsigned int ttyS, int signal, int value)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else if (value &~0x01) {
+        return(-EINVAL);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (0 >= p->used) {
+            return(-EPERM);
+        }
+        else {
+            if (value)
+                p->mcr |= signal;
+            else
+                p->mcr &= ~signal;
+            outb(p->mcr, p->port + RT_COM_MCR);
+            return(0);
+        }
+    }
+}
+
+/** Read input signal from modem (CTS, DSR, RI, DCD).
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @param signal Input signals: RT_COM_CTS, RT_COM_DSR, RT_COM_RI, RT_COM_DCD
+ *               or any combination.  
+ * @return       input signal status; that is the bitwise-OR of the signal
+ *               argument and the MSR register.
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/12 */
+int rt_com_read_modem(unsigned int ttyS, int signal)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else if (signal & 0xf) {
+        return(-EINVAL);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (0 >= p->used) {
+            return(-EPERM);
+        }
+        else {
+            return(inb(p->port + RT_COM_MSR) & signal);
+        }
+    }
+}
+
+/** Return last error detected.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @return       bit 0 :1 = Input buffer overflow
+ *               bit 1 :1 = Receive data overrun 
+ *               bit 2 :1 = Parity error 
+ *               bit 3 :1 = Framing error
+ *               bit 4 :1 = Break detected 
+ *
+ * @author Roberto Finazzi
+ * @version 2000/03/12
+ */
+int rt_com_error(unsigned int ttyS)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        int                     tmp = p->error;
+        p->error = 0;
+        return(tmp);
+    }
+}
+
+/** Write data to a line.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @param buffer Address of data.
+ * @param count  Number of bytes to write. If negative, send byte only if 
+ *               possible to send them all together.
+ * @return       Number of bytes not written. Negative values are error
+ *               conditions.
+ *
+ * @author Jens Michaelsen, Jochen Kupper, Giuseppe Renoldi
+ * @version 2000/03/12 */
+int rt_com_write(unsigned int ttyS, char *buffer, int count)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (!(p->used & RT_COM_PORT_SETUP)) {
+            return(-EPERM);
+        }
+        else {
+            struct rt_buf_struct    *b = &(p->obuf);
+            long                    state;
+            int                     bytestosend;
+            if (count == 0)
+                return(0);
+            bytestosend = rt_com_buffer_free(b->head, b->tail);
+            if (count < 0) {
+                count = -count;
+                if (count > bytestosend)
+                    return(count);
+                bytestosend = count;
+            }
+            else {
+                if (count <= bytestosend)
+                    bytestosend = count;
+            }
+
+            rt_com_irq_off(state);  
+            while (bytestosend-- > 0) {
+                /* put byte into buffer, move pointers to next elements */
+                b->buf[b->head++] = *buffer++;
+                if (b->head >= rt_com_buffersize)
+                    b->head = 0;
+                --count;
+            }
+
+            p->ier |= IER_ETBEI;
+            outb(p->ier, p->port + RT_COM_IER);
+            rt_com_irq_on(state);
+            return(count);
+        }
+    }
+}
+
+/** Read data we got from a line.
+ *
+ * @param ttyS   Port to use corresponding to internal numbering scheme.
+ * @param buffer Address of data buffer. Needs to be of size > cnt !
+ * @param count  Number of bytes to read.
+ * @return       Number of bytes actually read.
+ *
+ * @author Jens Michaelsen, Jochen Kupper
+ * @version 2000/03/17 */
+int rt_com_read(unsigned int ttyS, char *buffer, int count)
+{
+    if (0 > count) {
+        return(-EINVAL);
+    }
+    else if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (!(p->used & RT_COM_PORT_SETUP)) {
+            return(-EPERM);
+        }
+        else {
+            struct rt_buf_struct    *b = &(p->ibuf);
+            int                     done = 0;
+            long                    state;
+            rt_com_irq_off(state);
+            while ((b->head != b->tail) && (--count >= 0)) {
+                done++;
+                *buffer++ = b->buf[b->tail++];
+                b->tail &= (RT_COM_BUF_SIZ - 1);
+            }
+
+            rt_com_irq_on(state);
+            if ((p->mode & RT_COM_HW_FLOW) && (rt_com_buffer_free(b->head, b->tail) > RT_COM_BUF_HI)) {
+                /* if hardware flow and enough free space on input buffer
+				   then set RTS */
+                p->mcr |= MCR_RTS;
+                outb(p->mcr, p->port + RT_COM_MCR);
+            }
+
+            return(done);
+        }
+    }
+}
+
+/** Get first byte from the write buffer.
+ *
+ * @param p  rt_com_struct of the line we are writing to.
+ * @param c  Address to put the char in.
+ * @return   Number of characters we actually got.
+ * 
+ * @author Jens Michaelsen, Jochen Kupper
+ * @version 1999/10/01
+ */
+static inline int rt_com_irq_get(struct rt_com_struct *p, unsigned char *c)
+{
+    struct rt_buf_struct    *b = &(p->obuf);
+    if (b->head != b->tail) {
+        *c = b->buf[b->tail++];
+        b->tail &= (RT_COM_BUF_SIZ - 1);
+        return(1);
+    }
+
+    return(0);
+}
+
+/** Concatenate a byte to the read buffer.
+ *
+ * @param p   rt_com_struct of the line we are writing to.
+ * @param ch  Byte to put into buffer.
+ *
+ * @author Jens Michaelsen, Jochen Kupper
+ * @version 1999/07/20 */
+static inline void rt_com_irq_put(struct rt_com_struct *p, unsigned char ch)
+{
+    struct rt_buf_struct    *b = &(p->ibuf);
+    b->buf[b->head++] = ch;
+    b->head &= (RT_COM_BUF_SIZ - 1);
+}
+
+/** Real interrupt handler.
+ *
+ * This one is called by the registered ISRs and does the actual work.
+ *
+ * @param ttyS  Port to use corresponding to internal numbering scheme.
+ *
+ * @author Jens Michaelsen, Jochen Kupper, Hua Mao, Roberto Finazzi
+ * @version 2000/03/17 */
+static inline int rt_com_isr(unsigned int ttyS)
+{
+    struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+    struct rt_buf_struct    *b = &(p->ibuf);
+    unsigned int            base = p->port;
+    int                     buff, data_to_tx;
+    int                     loop = 4;
+    int                     toFifo = 16;
+    unsigned char           data, msr, lsr, iir;
+
+    do {
+        //iir=inb(base + RT_COM_IIR);
+        //rt_printk("iir=0x%02x\n",iir);
+        /* get available data from port */
+        lsr = inb(base + RT_COM_LSR);
+        if (0x1e & lsr)
+            p->error = lsr & 0x1e;
+        while (LSR_DATA_READY & lsr) {
+            data = inb(base + RT_COM_RXB);
+
+            //rt_printk("[%02x<- ",data);	
+            rt_com_irq_put(p, data);
+            lsr = inb(base + RT_COM_LSR);
+            if (0x1e & lsr)
+                p->error = 0x1e & lsr;
+        }
+
+        /* controls on buffer full and RTS clear on hardware flow
+           control */
+        buff = rt_com_buffer_free(b->head, b->tail);
+        if (buff < RT_COM_BUF_FULL)
+            p->error = RT_COM_BUFFER_FULL;
+
+        if ((p->mode & RT_COM_HW_FLOW) && (buff < RT_COM_BUF_LOW)) {
+            p->mcr &= ~MCR_RTS;
+            outb(p->mcr, p->port + RT_COM_MCR);
+        }
+
+        /* if possible, put data to port */
+        msr = inb(base + RT_COM_MSR);
+        if
+        (
+            (p->mode == RT_COM_NO_HAND_SHAKE) ||
+            ((p->mode & RT_COM_DSR_ON_TX) && (MSR_DSR & msr) && (p->mode & RT_COM_HW_FLOW) && (MSR_CTS & msr))
+        ) {
+            /* (DSR && (CTS || Mode==no hw flow)) or Mode==no handshake */
+            // if (THRE==1) i.e. transmitter empty
+            if ((lsr = inb(base + RT_COM_LSR)) & LSR_THRE) {
+                // if there are data to transmit
+                if ((data_to_tx = rt_com_irq_get(p, &data)) != 0) {
+                    do {
+                        //rt_printk("->%02x] ",data);	
+                        outb(data, base + RT_COM_TXB);
+                    } while ((--toFifo > 0) && (data_to_tx = rt_com_irq_get(p, &data) != 0));
+                }
+
+                if (!data_to_tx) {
+                    /* no data in output buffer, disable Transmitter
+	               	   Holding Register Empty Interrupt */
+                    p->ier &= ~IER_ETBEI;
+                    outb(p->ier, base + RT_COM_IER);
+                }
+            }
+        }
+
+        /* check the low nibble of IIR wheather there is another pending
+           interrupt.  bit 0 = 0 if interrupt pending, bits 1,2,3 
+		   are the interrupt ID */
+        iir = inb(base + RT_COM_IIR);
+    } while (((iir & 0x0F) != 1) && (--loop > 0));
+
+#if defined RTLINUX_V2
+    rtl_hard_enable_irq(p->irq);
+#endif
+    return 0;
+}
+
+/** Interrupt Service Routines
+ *
+ * These are the Interrupt Service Routines to be registered with the
+ * OS. They simply call the genereric interrupt handler for the
+ * current port to do the work.
+ *
+ * @author Jens Michaelsen, Jochen Kupper, Hua Mao
+ * @version 1999/11/11 */
+static void rt_com0_isr(void)
+{
+    //rt_printk("rt_com0_isr\n");
+    rt_com_isr(0);
+}
+
+static void rt_com1_isr(void)
+{
+    //rt_printk("rt_com1_isr\n");
+    rt_com_isr(1);
+}
+
+/** Setup one port
+ *
+ * Calls from init_module + cleanup_module have baud == 0; in these
+ * cases we only do some cleanup.
+ *
+ * To allocate a port, give usefull setup parameter, to deallocate
+ * give negative baud.
+ *
+ * @param ttyS       Number corresponding to internal port numbering scheme.
+ *                   This is esp. the index of the rt_com_table to use.
+ * @param baud       Data transmission rate to use [Byte/s]. If negative,
+ *                   deallocate port instead. Called with baud == 0 from
+ *                   init_module for basic initialization. Needs to be called
+ *                   by user-task again before use !
+ * @param mode       see rt_com_set_mode docs for now
+ * @param parity     Parity for transmission protocol.
+ *                   (RT_COM_PARITY_EVEN, RT_COM_PARITY_ODD, RT_COM_PARITY_NONE)
+ * @param stopbits   Number of stopbits to use. 1 gives you one stopbit, 2
+ *                   actually gives really two stopbits for wordlengths of
+ *                   6 - 8 bit, but 1.5 stopbits for a wordlength of 5 bits.
+ * @param wordlength Number of bits per word (5 - 8 bits).
+ * @param fifotrig   if <0 set trigger fifo using default value set
+ *                   in rt_com_table[], otherwise set trigger fifo accordingly
+ *                   to the parameter
+ * @return           0       - all right
+ *                   -ENODEV - no entry for that ttyS in rt_com_table
+ *                   -EPERM  - get hardware resources first (the port needs to
+ *                             be setup hardware-wise first, that means you have
+ *                             to specify a positive used flag at compile time
+ *                             or call rt_com_set_hwparm first.)
+ *
+ * @author Jens Michaelsen, Jochen Kupper, Roberto Finazzi
+ * @version 2000/03/12 */
+int rt_com_setup
+(
+    unsigned int    ttyS,
+    int             baud,
+    int             mode,
+    unsigned int    parity,
+    unsigned int    stopbits,
+    unsigned int    wordlength,
+    int             fifotrig			
+)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (0 == p->used) {
+            /*  */
+            return(-EPERM);
+        }
+        else {
+            unsigned int    base = p->port;
+
+            /* Stop everything, set DLAB */
+            outb(0x00, base + RT_COM_IER);
+            outb(0x80, base + RT_COM_LCR);
+
+            /* clear irqs */
+            inb(base + RT_COM_IIR);
+            inb(base + RT_COM_LSR);
+            inb(base + RT_COM_RXB);
+            inb(base + RT_COM_MSR);
+
+            /* initialize error code */
+            p->error = 0;
+
+            /* if 0 == baud, nothing else to do ! */
+            if (baud == 0)
+                return(0);
+
+            if (0 > baud) {
+                /* free the port */
+                /* disable interrupts */
+                outb(0, base + RT_COM_IER);
+                //MOD_DEC_USE_COUNT;  Hm, IgH
+                return(0);
+            }
+            else {
+                /* allocate and set-up the port */
+                unsigned int    divider = p->baud_base / baud;
+
+                //MOD_INC_USE_COUNT; Hm, IgH
+
+                /* set transfer rate */
+                outb(divider % 256, base + RT_COM_DLL);
+                outb(divider / 256, base + RT_COM_DLM);
+
+                /* bits 3,4 + 5 determine parity, mask away anything else */
+                parity &= 0x38;
+
+                /* set transmission parameters and clear DLAB */
+                outb((wordlength - 5) | ((stopbits - 1) << 2) | parity, base + RT_COM_LCR);
+
+                /* set-up MCR value and write it */
+                p->mcr = MCR_DTR | MCR_RTS | MCR_OUT1 | MCR_OUT2;
+                outb(p->mcr, base + RT_COM_MCR);
+
+                /* set-up IER value and write it */
+                p->mode = mode;
+                if (p->mode == RT_COM_NO_HAND_SHAKE) {
+                    /* if no handshaking signals enable only receiver interrupts  */
+                    p->ier = IER_ERBI | IER_ELSI;
+                }
+                else {
+                    /* enable receiver and modem interrupts */
+                    p->ier = IER_ERBI | IER_ELSI | IER_EDSSI;
+                }
+
+                outb(p->ier, base + RT_COM_IER);
+		if (fifotrig>=0)
+		    p->fifotrig = fifotrig;	
+                outb(FCR_FIFO_ENABLE | p->fifotrig, base + RT_COM_FCR); // enable fifo
+                /* mark setup done */
+                p->used |= RT_COM_PORT_SETUP;
+                return(0);
+            }
+        }
+
+        return(0);
+    }
+}
+
+/** Set hardware parameter for a specific port.
+ *
+ * Change port address and irq setting for a specified port. The port
+ * must have an entry in rt_com_table beforehand.
+ *
+ * To allow the specification of additional ports we would need to
+ * dynamically allocate memory, that's not really feasible within a
+ * real-time context, although we could preallocate a few entries in
+ * init_module. However, it doesn't make too much sense, as you can
+ * specify all ports that really exist (in hardware) at compile time
+ * and enable only these you want to use.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @param port   port address, if zero, use standard value from rt_com_table
+ * @param irq    irq address, if zero, use standard value from rt_com_table
+ * @return        0       everything all right,
+ *               -ENODEV  no entry in rt_com_table for that device,
+ *               -EBUSY   port-region is used already.
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/10 */
+int rt_com_hwsetup(unsigned int ttyS, int port, int irq)
+{
+    if (ttyS < RT_COM_CNT) {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (0 == p->used) {
+            if (0 != port)
+                p->port = port;
+            if (0 != irq)
+                p->irq = irq;
+            if (-EBUSY == check_region(p->port, 8)) {
+                return(-EBUSY);
+            }
+
+            request_region(p->port, 8, RT_COM_NAME);
+            rt_com_request_irq(p->irq, p->isr);
+            p->used = 1;
+            rt_com_setup(ttyS, p->baud, p->mode, p->parity, p->stopbits, p->wordlength, p->fifotrig);
+            return(0);
+        }
+        else {
+            if (port >= 0)
+                return(-EBUSY);
+            rt_com_setup(ttyS, 0, 0, 0, 0, 0, 0);
+            rt_com_free_irq(p->irq);
+            release_region(p->port, 8);
+            p->used = 0;
+            return(0);
+        }
+    }
+
+    return(-ENODEV);
+}
+
+/** Initialization
+ *
+ * For all ports that have a used flag greater than 0, request port
+ * memory and register ISRs. If we cannot get the memory of all these
+ * ports, release all already requested ports and return an error.
+ *
+ * @return Success status, zero on success. With a non-zero return
+ * value of this routine, insmod will fail to load the module !
+ *
+ * @author Jochen Kupper, Hua Mao, Roberto Finazzi
+ * @version 2000/03/10 */
+//int init_module(void)   //Hm, IgH
+int init_aip_com(void)
+{
+    int             errorcode = 0;
+    unsigned int    i, j;
+
+    printk(KERN_INFO "rt_com: Loading real-time serial port driver (version "VERSION ").\n");
+
+    for (i = 0; i < RT_COM_CNT; i++) {
+        struct rt_com_struct    *p = &(rt_com_table[i]);
+
+        // if used set default values
+        if (p->used > 0) {
+	    printk(KERN_WARNING "RS232 testing %d\n",i);
+            if (-EBUSY == check_region(p->port, 8)) {
+                errorcode = -EBUSY;
+                printk(KERN_WARNING "rt_com: error %d: cannot request port region %x\n", errorcode, p->port);
+                break;
+            }
+
+            request_region(p->port, 8, "rt_com");
+            rt_com_request_irq(p->irq, p->isr);
+	    printk(KERN_WARNING "RS232 Request IRQ: %d\n",p->irq);
+            rt_com_setup(i, p->baud, p->mode, p->parity, p->stopbits, p->wordlength, p->fifotrig);
+        }
+    }
+
+    if (0 != errorcode) {
+        printk(KERN_WARNING "rt_com: giving up.\n");
+        for (j = 0; j < i; j++) {
+            struct rt_com_struct    *p = &(rt_com_table[j]);
+            if (0 < p->used) {
+                rt_com_free_irq(p->irq);
+                release_region(p->port, 8);
+            }
+        }
+    }
+    else {
+        printk(KERN_INFO "rt_com: sucessfully loaded.\n");
+    }
+
+    return(errorcode);
+}
+
+/** Cleanup
+ *
+ * Unregister ISR and releases memory for all ports
+ *
+ * @author Jochen Kupper
+ * @version 1999/10/01 */
+//void cleanup_module(void)  Hm, IgH
+void cleanup_aip_com(void)
+{
+    int i;
+    for (i = 0; i < RT_COM_CNT; i++) {
+        struct rt_com_struct    *p = &(rt_com_table[i]);
+        if (0 < p->used) {
+            rt_com_free_irq(p->irq);
+            rt_com_setup(i, 0, 0, 0, 0, 0, 0);
+            release_region(p->port, 8);
+        }
+    }
+
+    printk(KERN_INFO "rt_com: unloaded.\n");
+}
+
+/*
+EXPORT_SYMBOL(rt_com_buffersize);
+EXPORT_SYMBOL(rt_com_clear_input);
+EXPORT_SYMBOL(rt_com_clear_output);
+EXPORT_SYMBOL(rt_com_error);
+EXPORT_SYMBOL(rt_com_hwsetup);
+EXPORT_SYMBOL(rt_com_read);
+EXPORT_SYMBOL(rt_com_read_modem);
+EXPORT_SYMBOL(rt_com_setup);
+EXPORT_SYMBOL(rt_com_table);
+EXPORT_SYMBOL(rt_com_write);
+EXPORT_SYMBOL(rt_com_write_modem);
+EXPORT_SYMBOL(rt_com_set_mode);
+EXPORT_SYMBOL(rt_com_set_fifotrig);
+*/
+
+/**
+ * Local Variables:
+ * mode: C
+ * c-file-style: "Stroustrup"
+ * End:
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rs232dbg/aip_com.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,159 @@
+/**************************************************************************************************
+*
+*                          aip_com.h
+*
+*           Macros für Kommunikation über serielle Schnittstelle
+*           Basiert auf rt_com.h von rtai !! (siehe unten)
+*
+*           
+*           Autor: Wilhelm Hagemeister
+*
+*           (C) Copyright IgH 2002
+*           Ingenieurgemeinschaft IgH
+*           Heinz-Bäcker Str. 34
+*           D-45356 Essen
+*           Tel.: +49 201/61 99 31
+*           Fax.: +49 201/61 98 36
+*           E-mail: hm@igh-essen.com
+*
+*
+*           $RCSfile: aip_com.h,v $
+*           $Revision: 1.1 $
+*           $Author: hm $
+*           $Date: 2004/09/30 15:50:32 $
+*           $State: Exp $
+*
+*
+*
+*
+*
+*
+*
+*
+*
+**************************************************************************************************/
+
+/** rt_com
+ *  ======
+ *
+ * RT-Linux kernel module for communication across serial lines.
+ *
+ * Copyright (C) 1997 Jens Michaelsen
+ * Copyright (C) 1997-2000 Jochen Kupper
+ * Copyright (C) 2002 Giuseppe Renoldi
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; see the file License. if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * $Id: aip_com.h,v 1.1 2004/09/30 15:50:32 hm Exp $ */
+
+
+
+#ifndef AIP_COM_H
+#define AIP_COM_H
+
+/** This is the interface definition of the plain rt_com API.
+ *
+ * This should be all you need to use rt_com within your real-time
+ * kernel module.
+ *
+ * (When POSIX is done, we will reference the appropriate header
+ * here - probably depending on a flag.) */
+
+int init_aip_com(void);              //Hm, IgH
+void cleanup_aip_com(void);          //Hm, IgH
+
+
+/** specify hardware parameters, set-up communication parameters */
+extern int rt_com_hwsetup( unsigned int ttyS, int base, int irq );
+extern int rt_com_setup( unsigned int ttyS, int baud, int mode,
+			 unsigned int parity, unsigned int stopbits,
+			 unsigned int wordlength, int fifotrig );
+
+/** read/write from/to input/output buffer */
+extern int rt_com_read( unsigned int, char *, int );
+extern int rt_com_write( unsigned int ttyS, char *buffer, int count );
+
+/** clear input or output buffer */
+extern int rt_com_clear_input( unsigned int ttyS );
+extern int rt_com_clear_output( unsigned int ttyS );
+
+/** read input signal from modem (CTS,DSR,RI,DCD), set output signal
+ * for modem control (DTR,RTS) */
+extern int rt_com_read_modem( unsigned int ttyS, int signal );
+extern int rt_com_write_modem( unsigned int ttyS, int signal, int value );
+
+/** functioning mode and fifo trigger setting */
+extern int rt_com_set_mode( unsigned int ttyS, int mode);
+extern int rt_com_set_fifotrig( unsigned int ttyS, int fifotrig);
+
+/** return last error detected */
+extern int rt_com_error( unsigned int ttyS );
+
+
+/** size of internal queues, this is constant during module lifetime */
+extern unsigned int rt_com_buffersize;
+
+#define rt_com_set_param rt_com_hwsetup
+#define rt_com_setup_old(a,b,c,d,e) rt_com_setup((a),(b),0,(c),(d),(e),-1)
+
+
+/** functioning modes */
+#define RT_COM_NO_HAND_SHAKE  0x00
+#define RT_COM_DSR_ON_TX      0x01
+#define RT_COM_HW_FLOW	      0x02
+
+/** parity flags */
+#define RT_COM_PARITY_EVEN    0x18
+#define RT_COM_PARITY_NONE    0x00
+#define RT_COM_PARITY_ODD     0x08
+#define RT_COM_PARITY_HIGH    0x28
+#define RT_COM_PARITY_LOW     0x38
+
+/* FIFO Control */
+#define RT_COM_FIFO_DISABLE   0x00
+#define RT_COM_FIFO_SIZE_1    0x00
+#define RT_COM_FIFO_SIZE_4    0x40
+#define RT_COM_FIFO_SIZE_8    0x80
+#define RT_COM_FIFO_SIZE_14   0xC0
+
+/** rt_com_write_modem  masks */
+#define RT_COM_DTR            0x01
+#define RT_COM_RTS            0x02 
+
+/** rt_com_read_modem masks */
+#define RT_COM_CTS            0x10
+#define RT_COM_DSR            0x20
+#define RT_COM_RI             0x40
+#define RT_COM_DCD            0x80
+
+/** rt_com_error masks */
+#define RT_COM_BUFFER_FULL    0x01
+#define RT_COM_OVERRUN_ERR    0x02
+#define RT_COM_PARITY_ERR     0x04
+#define RT_COM_FRAMING_ERR    0x08
+#define RT_COM_BREAK          0x10
+
+
+#endif /* RT_COM_H */
+
+
+
+/**
+ * Local Variables:
+ * mode: C
+ * c-file-style: "Stroustrup"
+ * End:
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rs232dbg/aip_comP.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,206 @@
+/**
+ * rt_com
+ * ======
+ *
+ * RT-Linux kernel module for communication across serial lines.
+ *
+ * Copyright (C) 1997 Jens Michaelsen
+ * Copyright (C) 1997-2000 Jochen Kupper
+ * Copyright (C) 1999 Hua Mao <hmao@nmt.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; see the file License. if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+
+
+#ifndef AIP_COM_P_H
+#define AIP_COM_P_H
+
+
+#define RT_COM_NAME "rt_com(aip)"  //Hm, IgH
+
+/* input/ouput buffer (FIFO) sizes */
+#define RT_COM_BUF_SIZ        2048 //256	// MUST BE ONLY POWER OF 2 !!
+/* amount of free space on input buffer for RTS reset */
+#define RT_COM_BUF_LOW        (RT_COM_BUF_SIZ / 3)
+/* amount of free space on input buffer for RTS set */
+#define RT_COM_BUF_HI         (RT_COM_BUF_SIZ * 2 / 3)
+/* limit of free space on input buffer for buffer full error */
+#define RT_COM_BUF_FULL       20
+
+
+/* usage flags */
+#define RT_COM_PORT_FREE      0x00
+#define RT_COM_PORT_INUSE     0x01
+#define RT_COM_PORT_SETUP     0x02
+
+
+/* Some hardware description */
+#define RT_COM_BASE_BAUD      115200
+
+/** Interrupt Service Routines
+ * These are private functions */
+static void rt_com0_isr( void );
+static void rt_com1_isr( void );
+
+
+
+
+/** Interrupt handling
+ *
+ * Define internal convinience macros for interrupt handling, so we
+ * get rid of the system dependencies.
+ */
+//#define rt_com_irq_off( state )         do{}while(0) //rt_global_save_flags( &state ); rt_global_cli() schreiben und lesen sowieso in IRQ Hm
+//#define rt_com_irq_on(state)            do{}while(0) //rt_global_restore_flags( state ) 
+#define rt_com_irq_off( state )         rt_global_save_flags( &state ); rt_global_cli() 
+#define rt_com_irq_on(state)            rt_global_restore_flags( state ) 
+#define rt_com_request_irq( irq, isr )  rt_request_global_irq( irq, isr ); rt_enable_irq( irq );
+#define rt_com_free_irq( irq )          rt_free_global_irq( irq )
+
+
+/* port register offsets */
+#define RT_COM_RXB  0x00
+#define RT_COM_TXB  0x00
+#define RT_COM_IER  0x01
+#define RT_COM_IIR  0x02
+#define RT_COM_FCR  0x02
+#define RT_COM_LCR  0x03
+#define RT_COM_MCR  0x04
+#define RT_COM_LSR  0x05
+#define RT_COM_MSR  0x06
+#define RT_COM_DLL  0x00
+#define RT_COM_DLM  0x01
+
+/** MCR Modem Control Register masks */
+#define MCR_DTR               0x01 // Data Terminal Ready
+#define MCR_RTS               0x02 // Request To Send 
+#define MCR_OUT1              0x04
+#define MCR_OUT2              0x08
+#define MCR_LOOP              0x10
+#define MCR_AFE               0x20 // AutoFlow Enable
+
+/** IER Interrupt Enable Register masks */
+#define IER_ERBI              0x01  // Enable Received Data Available Interrupt
+#define IER_ETBEI             0x02  // Enable Transmitter Holding Register
+                                    // Empty Interrupt
+#define IER_ELSI              0x04  // Enable Receiver Line Status Interrupt
+#define IER_EDSSI             0x08  // Enable Modem Status Interrupt
+
+/** MSR Modem Status Register masks */
+#define MSR_DELTA_CTS         0x01
+#define MSR_DELTA_DSR         0x02
+#define MSR_TERI              0x04
+#define MSR_DELTA_DCD         0x08
+#define MSR_CTS               0x10
+#define MSR_DSR               0x20
+#define MSR_RI                0x40
+#define MSR_DCD               0x80
+
+/** LSR Line Status Register masks */
+#define LSR_DATA_READY        0x01
+#define LSR_OVERRUN_ERR       0x02
+#define LSR_PARITY_ERR        0x04
+#define LSR_FRAMING_ERR       0x08
+#define LSR_BREAK             0x10
+#define LSR_THRE              0x20	// Transmitter Holding Register
+#define LSR_TEMT              0x40	// Transmitter Empty
+
+/** FCR FIFO Control Register masks */
+#define FCR_FIFO_ENABLE       0x01
+#define FCR_INPUT_FIFO_RESET  0x02
+#define FCR_OUTPUT_FIFO_RESET 0x04
+
+/** data buffer
+ *
+ * Used for buffering of input and output data. Two buffers per port
+ * (one for input, one for output). Organized as a FIFO */
+struct rt_buf_struct{
+    unsigned int  head;
+    unsigned int  tail;
+    char buf[ RT_COM_BUF_SIZ ];
+};
+
+
+
+/** Port data
+ *
+ * Internal information structure containing all data for a port. One
+ * structure for every port.
+ *
+ * Contains all current setup parameters and all data currently
+ * buffered by rt_com.
+ *
+ * mode (functioning mode)
+ *   possible values:
+ *   - RT_COM_DSR_ON_TX     - for standard functioning mode (DSR needed on TX)
+ *   - RT_COM_NO_HAND_SHAKE - for comunication without hand shake signals
+ *                            (only RXD-TXD-GND)
+ *   - RT_COM_HW_FLOW       - for hardware flow control (RTS-CTS)
+ *   Of course RT_COM_DSR_ON_TX and RT_COM_NO_HAND_SHAKE cannot be
+ *   sppecified at the same time.
+ *
+ *   NOTE: When you select a mode that uses hand shake signals pay
+ *   attention that no input signals (CTS,DSR,RI,DCD) must be
+ *   floating.
+ *
+ * used (usage flag)
+ *   possible values:
+ *   - RT_COM_PORT_INUSE - port region requested by init_module
+ *   - RT_COM_PORT_FREE  - port region requested by rt_com_set_param
+ *   - RT_COM_PORT_SETUP - port parameters are setup,
+ *                         don't specify at compile time !
+ *
+ * error
+ *   last error detected
+ *
+ * ier (interrupt enable register)
+ *   copy of IER chip register, last value set by rt_com.
+ *
+ * mcr (modem control register)
+ *   copy of the MCR internal register
+ */
+struct rt_com_struct{
+    int baud_base;
+    int port;
+    int irq;
+    void (*isr)(void);
+	int baud;
+	unsigned int wordlength;
+	unsigned int parity;
+	unsigned int stopbits;
+    int mode;
+	int fifotrig;
+    int used;
+	int error;
+    int type;
+    int ier;
+    int mcr;
+    struct rt_buf_struct ibuf;
+    struct rt_buf_struct obuf;
+};
+
+
+#endif /* RT_COM_P_H */
+
+
+
+/**
+ * Local Variables:
+ * mode: C
+ * c-file-style: "Stroustrup"
+ * End:
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rs232dbg/rs232dbg.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,136 @@
+/******************************************************************************
+*
+*           msr_io.c
+*
+*           Debugging über Serielle Schnittstelle
+*           
+*           Autoren: Wilhelm Hagemeister
+*
+*           $LastChangedDate: 2005-09-16 17:45:46 +0200 (Fri, 16 Sep 2005) $
+*           $Author: hm $
+*
+*           (C) Copyright IgH 2005
+*           Ingenieurgemeinschaft IgH
+*           Heinz-Bäcker Str. 34
+*           D-45356 Essen
+*           Tel.: +49 201/61 99 31
+*           Fax.: +49 201/61 98 36
+*           E-mail: sp@igh-essen.com
+*
+* /bin/setserial /dev/ttyS0 uart none
+* /bin/setserial /dev/ttyS1 uart none
+*
+*
+******************************************************************************/
+
+/*--Includes-----------------------------------------------------------------*/
+
+#include <linux/module.h>
+#include <linux/tqueue.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+
+#include "aip_com.h"
+#include "rs232dbg.h"
+#include <rtai.h>
+
+spinlock_t rs232wlock;
+
+
+void SDBG_print(const char *format, ...) 
+{
+    va_list argptr;  
+    static char buf[1024];                               
+    int len;
+    if(format != NULL) {
+	va_start(argptr,format); 
+	len = vsnprintf(buf, sizeof(buf), format, argptr);
+        if (len > 0 && buf[len - 1] == '\n') len--; // fp
+	rt_com_write(0,buf,len);
+	rt_com_write(0,"\r\n",2);
+	va_end(argptr); 
+    }
+}
+
+/*
+void SDBG_print(unsigned char *buf)
+{
+    static int counter = 0;
+    unsigned char cbuf[20];
+    unsigned long flags;
+
+//    flags = rt_spin_lock_irqsave (&rs232wlock);
+
+    sprintf(cbuf,"%0d -- ",counter);
+    rt_com_write(0,cbuf,strlen(cbuf));
+    rt_com_write(0,buf,strlen(buf));
+    rt_com_write(0,"\r\n",2);
+    counter++;
+    counter %= 10; //did we miss frames ??
+//    rt_spin_unlock_irqrestore (&rs232wlock,flags);
+}
+*/
+
+
+/*
+*******************************************************************************
+*
+* Function: msr_init
+*
+* Beschreibung: MSR initialisieren
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+*******************************************************************************
+*/
+
+int msr_init(void)
+{   
+    spin_lock_init (&rs2323wlock);
+
+    printk("starting RS232 Setup\n");
+    if(init_aip_com())
+    {
+	printk("RS232 Setup failed\n");
+	return -1;
+    }
+
+    SDBG_print("Hello Word, Serial Debugger started...");
+    mdelay(10);
+    return 0;
+}
+
+/*
+*******************************************************************************
+*
+* Function: msr_io_cleanup
+*
+* Beschreibung: Aufräumen
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+*******************************************************************************
+*/
+
+void msr_io_cleanup(void)
+{
+  cleanup_aip_com();
+}
+
+/*---Treiber-Einsprungspunkte etc.-------------------------------------------*/
+
+MODULE_LICENSE("GPL");
+
+module_init(msr_init);
+module_exit(msr_io_cleanup);
+
+/*---Ende--------------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rs232dbg/rs232dbg.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,7 @@
+
+#ifndef RS232DBG_H
+#define RS232DBG_H
+
+void SDBG_print(const char *format, ...);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/Makefile	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,83 @@
+#IgH
+KERNELDIR = /vol/projekte/msr_messen_steuern_regeln/linux/kernel/2.4.20/include/linux-2.4.20.CX1100-rthal5
+RTAIDIR   = /vol/projekte/msr_messen_steuern_regeln/linux/kernel/2.4.20/include/rtai-24.1.13
+RTLIBDIR = rt_lib
+
+#euler-nottuln
+#KERNELDIR = /usr/src/linux
+#RTAIDIR = /usr/src/rtai
+
+
+#patra
+#KERNELDIR = /usr/src/linux-2.4.20.CX1100-rthal5
+#RTAIDIR   = /usr/src/rtai-24.1.13
+
+RTLIBDIR=rt_lib
+
+#include $(KERNELDIR)/.config
+
+#CFLAGS = -DRTAI -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -I$(RTAIDIR)/include -I$(RTLIBDIR)/msr-include \
+#	-Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fomit-frame-pointer \
+#	-pipe -mpreferred-stack-boundary=2 -march=i686 -nostdinc -iwithprefix include
+
+CFLAGS = -O2 -Wall -Wuninitialized -D__KERNEL__ -DMODULE -DSERIALDEBUG -DMSR_NO_PROC -I$(KERNELDIR)/include -D_RTAI -I$(RTAIDIR)/include -I$(RTLIBDIR)/msr-include
+
+#CFLAGS += -DSIMULATION
+#LDFLAGS = 
+
+#VPATH = $(RTLIBDIR)/
+
+TARGET = msr_modul
+MODULE = $(TARGET).o
+
+SRC = msr_io.c 
+
+#Suchpfad für die Dateien aus dem RT-Lib-Verzeichnis
+VPATH = $(RTLIBDIR)/msr-core:$(RTLIBDIR)/msr-control:$(RTLIBDIR)/msr-math:$(RTLIBDIR)/msr-misc:$(RTLIBDIR)/msr-utils
+
+#Datei aus dem RT-Libverzeichnis für dies Projekt
+RTSRC = msr_main.c msr_lists.c msr_charbuf.c msr_reg.c msr_interpreter.c msr_utils.c msr_messages.c msr_base64.c msr_proc.c msr_error_reg.c
+
+ALLSRC = $(SRC) $(RTSRC)
+
+OBJS = $(ALLSRC:.c=.o)  
+
+
+all: .depend $(TARGET).o Makefile
+
+$(TARGET).o: $(SRC:.c=.o) $(RTSRC:.c=.o)
+	$(LD) -r $(OBJS)  -o $@ $(LDFLAGS)
+
+install: msr_modul.o
+	lsmod | grep cif-rtai >/dev/null 2>&1 && sudo rmmod msr_modul || true
+	sudo insmod msr_modul.o
+
+clean:
+	rm -f *.o *~ core .depend
+
+depend .depend dep:
+	$(CC) $(CFLAGS) -M *.c > $@
+
+
+
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+
+#all: msr_module.o
+#
+#msr_io.o: msr_io.c msr_io.h
+#	$(CC) $(CFLAGS) -c -o $@ $<
+#
+#msr_module.o: msr_io.o
+#	$(LD) -r -o $@ $^
+#
+
+#                  $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
+
+
+#clean:
+#	rm -f *.o *~ core
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/TAGS	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,57 @@
+
+_msr_io.c,315
+#  define __KERNEL__44,1091
+#  define MODULE47,1134
+spinlock_t data_lock 64,1449
+#define PB_CARDS 79,1926
+} card[91,2142
+void x_PB_io(109,2505
+int msr_io_init(151,3460
+#define FIFO_BUF 157,3532
+int msr_io_register(235,5684
+int msr_io_write(261,6090
+int msr_io_read(363,8522
+void msr_io_cleanup(400,9200
+
+_msr_io.h,100
+#define _MSR_IO_H_119,3261
+struct cif_in_t cif_in_t128,3512
+struct cif_out_t cif_out_t135,3664
+
+cif-rtai-io.h,0
+
+msr_io.c,559
+RT_TASK check_running;54,1293
+RT_TASK process_image;55,1316
+SEM data_lock;57,1340
+#define PARAM_FILENO 60,1381
+#define CVT_FILENO 61,1405
+#define MSG_FILENO	62,1427
+#define PB_CARDS 64,1449
+} card[78,1692
+int msr_print(80,1711
+inline int msr_print_error(97,1982
+inline int msr_print_info(106,2138
+inline int msr_print_warn(115,2294
+void x_PB_io(140,2830
+void process_thread(145,2909
+void check_thread(254,6015
+void msr_io_cleanup(343,8029
+int msr_init(374,8740
+#define FIFO_BUF 389,9019
+#define TIMERTICS 396,9180
+#define MSG_BUF 397,9245
+
+msr_io.h,363
+#define _AIM_GLOBALS_H_35,698
+struct P101_In P101_In37,723
+struct P201_In P201_In45,859
+struct P301_In P301_In50,940
+struct P101_Out P101_Out56,1022
+struct P201_Out P201_Out62,1120
+struct P301_Out P301_Out65,1161
+struct IMO_to_dSPACE IMO_to_dSPACE69,1203
+struct dSPACE_to_IMO dSPACE_to_IMO76,1338
+} IMO;99,1765
+} cvt;128,2230
+} param;131,2247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/aip_com.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,851 @@
+/** rt_com
+ *  ======
+ *
+ * RT-Linux kernel module for communication across serial lines.
+ *
+ * Copyright (C) 1997 Jens Michaelsen
+ * Copyright (C) 1997-2000 Jochen Kupper
+ * Copyright (C) 1999 Hua Mao <hmao@nmt.edu>
+ * Copyright (C) 1999 Roberto Finazzi
+ * Copyright (C) 2000-2002 Giuseppe Renoldi
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; see the file License. if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * $Id: aip_com.c,v 1.1 2005/09/16 14:16:31 hm Exp hm $ */
+#define VERSION "0.6.pre2-rtaicvs (modified by Hm, IgH for aip)"   //Hm, IgH
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#ifdef _RTAI
+#include <rtai.h>
+#endif
+
+#include "aip_com.h"
+#include "aip_comP.h"
+
+#include <msr_rcsinfo.h>
+
+RCS_ID("$Header: /home/hm/projekte/msr_messen_steuern_regeln/ethercat/src-hm/rs232rt/RCS/aip_com.c,v 1.1 2005/09/16 14:16:31 hm Exp hm $");
+
+/* Hm, IgH
+MODULE_AUTHOR("Jochen Kuepper");
+MODULE_DESCRIPTION("real-time serial port driver");
+MODULE_LICENSE("GPL");
+*/
+
+
+/* size of internal queues
+* This is the default value. */
+unsigned int            rt_com_buffersize = RT_COM_BUF_SIZ;
+
+/** Default: mode=0 - no hw flow control
+ *           used=0 - port and irq setting by rt_com_hwparam.
+ *                    If you want to work like
+ *                    a standard rt_com you can set used=1. */
+struct rt_com_struct    rt_com_table[] = { 
+       {    // ttyS0 - COM1
+        RT_COM_BASE_BAUD,   // int baud_base;
+        0x3f8,          // int port;
+        4,              // int irq;
+        rt_com0_isr,    // void (*isr)(void);
+        115200,  // int baud;
+        8,  // unsigned int wordlength;
+        RT_COM_PARITY_NONE, // unsigned int parity;
+        1,  // stopbits;
+        RT_COM_NO_HAND_SHAKE,   // int mode;
+        RT_COM_FIFO_SIZE_8,     // int fifotrig;
+        1 //Hm, IgH   // int used;
+    }, {    // ttyS1 - COM2
+        RT_COM_BASE_BAUD,   // int baud_base;
+        0x2f8,          // int port;
+        3,              // int irq;
+        rt_com1_isr,    // void (*isr)(void);
+        0,  // int baud;
+        8,  // unsigned int wordlength;
+        RT_COM_PARITY_NONE, // unsigned int parity;
+        1,  // stopbits;
+        RT_COM_NO_HAND_SHAKE,   // int mode;
+        RT_COM_FIFO_SIZE_8,     // int fifotrig;
+        0   // int used;
+    }
+};
+
+/** Number and descriptions of serial ports to manage.  You also need
+ * to create an ISR ( rt_comN_isr() ) for each port.  */
+#define RT_COM_CNT  (sizeof(rt_com_table) / sizeof(struct rt_com_struct))
+
+/** Internal: Remaining free space of buffer
+ *
+ * @return amount of free space remaining in a buffer (input or output)
+ *
+ * @author Jochen Kupper
+ * @version 2000/03/10 */
+static inline unsigned int rt_com_buffer_free(unsigned int head, unsigned int tail)
+{
+    return(head < tail) ? (tail - head) : (rt_com_buffersize - (head - tail));
+}
+
+/** Clear input buffer.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @return       0 if all right, -ENODEV or -EPERM on error.
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/12 */
+int rt_com_clear_input(unsigned int ttyS)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else if (0 >= (rt_com_table[ttyS]).used) {
+        return(-EPERM);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        struct rt_buf_struct    *b = &(p->ibuf);
+        long                    state;
+        rt_com_irq_off(state);
+        b->tail = b->head;
+        if (p->fifotrig)
+            outb(inb(p->port + RT_COM_FCR) | FCR_INPUT_FIFO_RESET, p->port + RT_COM_FCR);
+        rt_com_irq_on(state);
+        if (p->mode & RT_COM_HW_FLOW) {
+            /* with hardware flow set RTS */
+            p->mcr |= MCR_RTS;
+            outb(p->mcr, p->port + RT_COM_MCR);
+        }
+
+        return(0);
+    }
+}
+
+/** Clear output buffer.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @return       0 if all right, negative error conditions otherwise
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/12
+ */
+int rt_com_clear_output(unsigned int ttyS)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (0 >= (rt_com_table[ttyS]).used) {
+            return(-EPERM);
+        }
+        else {
+            struct rt_buf_struct    *b = &(p->obuf);
+            long                    state;
+            rt_com_irq_off(state);
+            p->ier &= ~IER_ETBEI;
+            outb(p->ier, p->port | RT_COM_IER);
+            b->tail = b->head;
+            if (p->fifotrig)
+                outb(inb(p->port + RT_COM_FCR) | FCR_OUTPUT_FIFO_RESET, p->port + RT_COM_FCR);
+            rt_com_irq_on(state);
+            return(0);
+        }
+    }
+}
+
+/** Set functioning mode.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @param mode   functioning mode 
+ * @return       0 if all right, negative on error
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/12
+ */
+int rt_com_set_mode(unsigned int ttyS, int mode)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (0 >= p->used) {
+            return(-EPERM);
+        }
+        else {
+            p->mode = mode;
+            if (p->used & RT_COM_PORT_SETUP) {
+                /* setup done */
+                if (mode == RT_COM_NO_HAND_SHAKE) {
+                    /* if no hw signals disable modem interrupts */
+                    p->ier &= ~IER_EDSSI;
+                }
+                else {
+                    /* else enable it */
+                    p->ier |= IER_EDSSI;
+                }
+
+                outb(p->ier, p->port + RT_COM_IER);
+            }
+
+            return(0);
+        }
+    }
+}
+
+/** Set receiver fifo trigger level.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @param fifotrig   receiver fifo trigger level 
+ * @return           0 if all right, negative on error
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/12
+ */
+int rt_com_set_fifotrig(unsigned int ttyS, int fifotrig)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        p->fifotrig = fifotrig;
+        if (p->used & RT_COM_PORT_SETUP) {
+            /* setup done */
+            if (p->fifotrig)
+                outb(FCR_FIFO_ENABLE | p->fifotrig, p->port + RT_COM_FCR);  // enable fifo
+            else
+                outb(0, p->port + RT_COM_FCR);  // disable fifo	
+        }
+    }
+
+    return(0);
+}
+
+/** Set output signal for modem control (DTR, RTS).
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @param signal Output signals: RT_COM_DTR or RT_COM_RTS.
+ * @param value  Status: 0 or 1. 
+ * @return       0 if all right, negative error code otherwise
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/12 */
+int rt_com_write_modem(unsigned int ttyS, int signal, int value)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else if (value &~0x01) {
+        return(-EINVAL);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (0 >= p->used) {
+            return(-EPERM);
+        }
+        else {
+            if (value)
+                p->mcr |= signal;
+            else
+                p->mcr &= ~signal;
+            outb(p->mcr, p->port + RT_COM_MCR);
+            return(0);
+        }
+    }
+}
+
+/** Read input signal from modem (CTS, DSR, RI, DCD).
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @param signal Input signals: RT_COM_CTS, RT_COM_DSR, RT_COM_RI, RT_COM_DCD
+ *               or any combination.  
+ * @return       input signal status; that is the bitwise-OR of the signal
+ *               argument and the MSR register.
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/12 */
+int rt_com_read_modem(unsigned int ttyS, int signal)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else if (signal & 0xf) {
+        return(-EINVAL);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (0 >= p->used) {
+            return(-EPERM);
+        }
+        else {
+            return(inb(p->port + RT_COM_MSR) & signal);
+        }
+    }
+}
+
+/** Return last error detected.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @return       bit 0 :1 = Input buffer overflow
+ *               bit 1 :1 = Receive data overrun 
+ *               bit 2 :1 = Parity error 
+ *               bit 3 :1 = Framing error
+ *               bit 4 :1 = Break detected 
+ *
+ * @author Roberto Finazzi
+ * @version 2000/03/12
+ */
+int rt_com_error(unsigned int ttyS)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        int                     tmp = p->error;
+        p->error = 0;
+        return(tmp);
+    }
+}
+
+/** Write data to a line.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @param buffer Address of data.
+ * @param count  Number of bytes to write. If negative, send byte only if 
+ *               possible to send them all together.
+ * @return       Number of bytes not written. Negative values are error
+ *               conditions.
+ *
+ * @author Jens Michaelsen, Jochen Kupper, Giuseppe Renoldi
+ * @version 2000/03/12 */
+int rt_com_write(unsigned int ttyS, char *buffer, int count)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (!(p->used & RT_COM_PORT_SETUP)) {
+            return(-EPERM);
+        }
+        else {
+            struct rt_buf_struct    *b = &(p->obuf);
+            long                    state;
+            int                     bytestosend;
+            if (count == 0)
+                return(0);
+            bytestosend = rt_com_buffer_free(b->head, b->tail);
+            if (count < 0) {
+                count = -count;
+                if (count > bytestosend)
+                    return(count);
+                bytestosend = count;
+            }
+            else {
+                if (count <= bytestosend)
+                    bytestosend = count;
+            }
+
+            rt_com_irq_off(state);  
+            while (bytestosend-- > 0) {
+                /* put byte into buffer, move pointers to next elements */
+                b->buf[b->head++] = *buffer++;
+                if (b->head >= rt_com_buffersize)
+                    b->head = 0;
+                --count;
+            }
+
+            p->ier |= IER_ETBEI;
+            outb(p->ier, p->port + RT_COM_IER);
+            rt_com_irq_on(state);
+            return(count);
+        }
+    }
+}
+
+/** Read data we got from a line.
+ *
+ * @param ttyS   Port to use corresponding to internal numbering scheme.
+ * @param buffer Address of data buffer. Needs to be of size > cnt !
+ * @param count  Number of bytes to read.
+ * @return       Number of bytes actually read.
+ *
+ * @author Jens Michaelsen, Jochen Kupper
+ * @version 2000/03/17 */
+int rt_com_read(unsigned int ttyS, char *buffer, int count)
+{
+    if (0 > count) {
+        return(-EINVAL);
+    }
+    else if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (!(p->used & RT_COM_PORT_SETUP)) {
+            return(-EPERM);
+        }
+        else {
+            struct rt_buf_struct    *b = &(p->ibuf);
+            int                     done = 0;
+            long                    state;
+            rt_com_irq_off(state);
+            while ((b->head != b->tail) && (--count >= 0)) {
+                done++;
+                *buffer++ = b->buf[b->tail++];
+                b->tail &= (RT_COM_BUF_SIZ - 1);
+            }
+
+            rt_com_irq_on(state);
+            if ((p->mode & RT_COM_HW_FLOW) && (rt_com_buffer_free(b->head, b->tail) > RT_COM_BUF_HI)) {
+                /* if hardware flow and enough free space on input buffer
+				   then set RTS */
+                p->mcr |= MCR_RTS;
+                outb(p->mcr, p->port + RT_COM_MCR);
+            }
+
+            return(done);
+        }
+    }
+}
+
+/** Get first byte from the write buffer.
+ *
+ * @param p  rt_com_struct of the line we are writing to.
+ * @param c  Address to put the char in.
+ * @return   Number of characters we actually got.
+ * 
+ * @author Jens Michaelsen, Jochen Kupper
+ * @version 1999/10/01
+ */
+static inline int rt_com_irq_get(struct rt_com_struct *p, unsigned char *c)
+{
+    struct rt_buf_struct    *b = &(p->obuf);
+    if (b->head != b->tail) {
+        *c = b->buf[b->tail++];
+        b->tail &= (RT_COM_BUF_SIZ - 1);
+        return(1);
+    }
+
+    return(0);
+}
+
+/** Concatenate a byte to the read buffer.
+ *
+ * @param p   rt_com_struct of the line we are writing to.
+ * @param ch  Byte to put into buffer.
+ *
+ * @author Jens Michaelsen, Jochen Kupper
+ * @version 1999/07/20 */
+static inline void rt_com_irq_put(struct rt_com_struct *p, unsigned char ch)
+{
+    struct rt_buf_struct    *b = &(p->ibuf);
+    b->buf[b->head++] = ch;
+    b->head &= (RT_COM_BUF_SIZ - 1);
+}
+
+/** Real interrupt handler.
+ *
+ * This one is called by the registered ISRs and does the actual work.
+ *
+ * @param ttyS  Port to use corresponding to internal numbering scheme.
+ *
+ * @author Jens Michaelsen, Jochen Kupper, Hua Mao, Roberto Finazzi
+ * @version 2000/03/17 */
+static inline int rt_com_isr(unsigned int ttyS)
+{
+    struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+    struct rt_buf_struct    *b = &(p->ibuf);
+    unsigned int            base = p->port;
+    int                     buff, data_to_tx;
+    int                     loop = 4;
+    int                     toFifo = 16;
+    unsigned char           data, msr, lsr, iir;
+
+    do {
+        //iir=inb(base + RT_COM_IIR);
+        //rt_printk("iir=0x%02x\n",iir);
+        /* get available data from port */
+        lsr = inb(base + RT_COM_LSR);
+        if (0x1e & lsr)
+            p->error = lsr & 0x1e;
+        while (LSR_DATA_READY & lsr) {
+            data = inb(base + RT_COM_RXB);
+
+            //rt_printk("[%02x<- ",data);	
+            rt_com_irq_put(p, data);
+            lsr = inb(base + RT_COM_LSR);
+            if (0x1e & lsr)
+                p->error = 0x1e & lsr;
+        }
+
+        /* controls on buffer full and RTS clear on hardware flow
+           control */
+        buff = rt_com_buffer_free(b->head, b->tail);
+        if (buff < RT_COM_BUF_FULL)
+            p->error = RT_COM_BUFFER_FULL;
+
+        if ((p->mode & RT_COM_HW_FLOW) && (buff < RT_COM_BUF_LOW)) {
+            p->mcr &= ~MCR_RTS;
+            outb(p->mcr, p->port + RT_COM_MCR);
+        }
+
+        /* if possible, put data to port */
+        msr = inb(base + RT_COM_MSR);
+        if
+        (
+            (p->mode == RT_COM_NO_HAND_SHAKE) ||
+            ((p->mode & RT_COM_DSR_ON_TX) && (MSR_DSR & msr) && (p->mode & RT_COM_HW_FLOW) && (MSR_CTS & msr))
+        ) {
+            /* (DSR && (CTS || Mode==no hw flow)) or Mode==no handshake */
+            // if (THRE==1) i.e. transmitter empty
+            if ((lsr = inb(base + RT_COM_LSR)) & LSR_THRE) {
+                // if there are data to transmit
+                if ((data_to_tx = rt_com_irq_get(p, &data)) != 0) {
+                    do {
+                        //rt_printk("->%02x] ",data);	
+                        outb(data, base + RT_COM_TXB);
+                    } while ((--toFifo > 0) && (data_to_tx = rt_com_irq_get(p, &data) != 0));
+                }
+
+                if (!data_to_tx) {
+                    /* no data in output buffer, disable Transmitter
+	               	   Holding Register Empty Interrupt */
+                    p->ier &= ~IER_ETBEI;
+                    outb(p->ier, base + RT_COM_IER);
+                }
+            }
+        }
+
+        /* check the low nibble of IIR wheather there is another pending
+           interrupt.  bit 0 = 0 if interrupt pending, bits 1,2,3 
+		   are the interrupt ID */
+        iir = inb(base + RT_COM_IIR);
+    } while (((iir & 0x0F) != 1) && (--loop > 0));
+
+#if defined RTLINUX_V2
+    rtl_hard_enable_irq(p->irq);
+#endif
+    return 0;
+}
+
+/** Interrupt Service Routines
+ *
+ * These are the Interrupt Service Routines to be registered with the
+ * OS. They simply call the genereric interrupt handler for the
+ * current port to do the work.
+ *
+ * @author Jens Michaelsen, Jochen Kupper, Hua Mao
+ * @version 1999/11/11 */
+static void rt_com0_isr(void)
+{
+    //rt_printk("rt_com0_isr\n");
+    rt_com_isr(0);
+}
+
+static void rt_com1_isr(void)
+{
+    //rt_printk("rt_com1_isr\n");
+    rt_com_isr(1);
+}
+
+/** Setup one port
+ *
+ * Calls from init_module + cleanup_module have baud == 0; in these
+ * cases we only do some cleanup.
+ *
+ * To allocate a port, give usefull setup parameter, to deallocate
+ * give negative baud.
+ *
+ * @param ttyS       Number corresponding to internal port numbering scheme.
+ *                   This is esp. the index of the rt_com_table to use.
+ * @param baud       Data transmission rate to use [Byte/s]. If negative,
+ *                   deallocate port instead. Called with baud == 0 from
+ *                   init_module for basic initialization. Needs to be called
+ *                   by user-task again before use !
+ * @param mode       see rt_com_set_mode docs for now
+ * @param parity     Parity for transmission protocol.
+ *                   (RT_COM_PARITY_EVEN, RT_COM_PARITY_ODD, RT_COM_PARITY_NONE)
+ * @param stopbits   Number of stopbits to use. 1 gives you one stopbit, 2
+ *                   actually gives really two stopbits for wordlengths of
+ *                   6 - 8 bit, but 1.5 stopbits for a wordlength of 5 bits.
+ * @param wordlength Number of bits per word (5 - 8 bits).
+ * @param fifotrig   if <0 set trigger fifo using default value set
+ *                   in rt_com_table[], otherwise set trigger fifo accordingly
+ *                   to the parameter
+ * @return           0       - all right
+ *                   -ENODEV - no entry for that ttyS in rt_com_table
+ *                   -EPERM  - get hardware resources first (the port needs to
+ *                             be setup hardware-wise first, that means you have
+ *                             to specify a positive used flag at compile time
+ *                             or call rt_com_set_hwparm first.)
+ *
+ * @author Jens Michaelsen, Jochen Kupper, Roberto Finazzi
+ * @version 2000/03/12 */
+int rt_com_setup
+(
+    unsigned int    ttyS,
+    int             baud,
+    int             mode,
+    unsigned int    parity,
+    unsigned int    stopbits,
+    unsigned int    wordlength,
+    int             fifotrig			
+)
+{
+    if (ttyS >= RT_COM_CNT) {
+        return(-ENODEV);
+    }
+    else {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (0 == p->used) {
+            /*  */
+            return(-EPERM);
+        }
+        else {
+            unsigned int    base = p->port;
+
+            /* Stop everything, set DLAB */
+            outb(0x00, base + RT_COM_IER);
+            outb(0x80, base + RT_COM_LCR);
+
+            /* clear irqs */
+            inb(base + RT_COM_IIR);
+            inb(base + RT_COM_LSR);
+            inb(base + RT_COM_RXB);
+            inb(base + RT_COM_MSR);
+
+            /* initialize error code */
+            p->error = 0;
+
+            /* if 0 == baud, nothing else to do ! */
+            if (baud == 0)
+                return(0);
+
+            if (0 > baud) {
+                /* free the port */
+                /* disable interrupts */
+                outb(0, base + RT_COM_IER);
+                //MOD_DEC_USE_COUNT;  Hm, IgH
+                return(0);
+            }
+            else {
+                /* allocate and set-up the port */
+                unsigned int    divider = p->baud_base / baud;
+
+                //MOD_INC_USE_COUNT; Hm, IgH
+
+                /* set transfer rate */
+                outb(divider % 256, base + RT_COM_DLL);
+                outb(divider / 256, base + RT_COM_DLM);
+
+                /* bits 3,4 + 5 determine parity, mask away anything else */
+                parity &= 0x38;
+
+                /* set transmission parameters and clear DLAB */
+                outb((wordlength - 5) | ((stopbits - 1) << 2) | parity, base + RT_COM_LCR);
+
+                /* set-up MCR value and write it */
+                p->mcr = MCR_DTR | MCR_RTS | MCR_OUT1 | MCR_OUT2;
+                outb(p->mcr, base + RT_COM_MCR);
+
+                /* set-up IER value and write it */
+                p->mode = mode;
+                if (p->mode == RT_COM_NO_HAND_SHAKE) {
+                    /* if no handshaking signals enable only receiver interrupts  */
+                    p->ier = IER_ERBI | IER_ELSI;
+                }
+                else {
+                    /* enable receiver and modem interrupts */
+                    p->ier = IER_ERBI | IER_ELSI | IER_EDSSI;
+                }
+
+                outb(p->ier, base + RT_COM_IER);
+		if (fifotrig>=0)
+		    p->fifotrig = fifotrig;	
+                outb(FCR_FIFO_ENABLE | p->fifotrig, base + RT_COM_FCR); // enable fifo
+                /* mark setup done */
+                p->used |= RT_COM_PORT_SETUP;
+                return(0);
+            }
+        }
+
+        return(0);
+    }
+}
+
+/** Set hardware parameter for a specific port.
+ *
+ * Change port address and irq setting for a specified port. The port
+ * must have an entry in rt_com_table beforehand.
+ *
+ * To allow the specification of additional ports we would need to
+ * dynamically allocate memory, that's not really feasible within a
+ * real-time context, although we could preallocate a few entries in
+ * init_module. However, it doesn't make too much sense, as you can
+ * specify all ports that really exist (in hardware) at compile time
+ * and enable only these you want to use.
+ *
+ * @param ttyS   Port to use; corresponding to internal numbering scheme.
+ * @param port   port address, if zero, use standard value from rt_com_table
+ * @param irq    irq address, if zero, use standard value from rt_com_table
+ * @return        0       everything all right,
+ *               -ENODEV  no entry in rt_com_table for that device,
+ *               -EBUSY   port-region is used already.
+ *
+ * @author Roberto Finazzi, Jochen Kupper
+ * @version 2000/03/10 */
+int rt_com_hwsetup(unsigned int ttyS, int port, int irq)
+{
+    if (ttyS < RT_COM_CNT) {
+        struct rt_com_struct    *p = &(rt_com_table[ttyS]);
+        if (0 == p->used) {
+            if (0 != port)
+                p->port = port;
+            if (0 != irq)
+                p->irq = irq;
+            if (-EBUSY == check_region(p->port, 8)) {
+                return(-EBUSY);
+            }
+
+            request_region(p->port, 8, RT_COM_NAME);
+            rt_com_request_irq(p->irq, p->isr);
+            p->used = 1;
+            rt_com_setup(ttyS, p->baud, p->mode, p->parity, p->stopbits, p->wordlength, p->fifotrig);
+            return(0);
+        }
+        else {
+            if (port >= 0)
+                return(-EBUSY);
+            rt_com_setup(ttyS, 0, 0, 0, 0, 0, 0);
+            rt_com_free_irq(p->irq);
+            release_region(p->port, 8);
+            p->used = 0;
+            return(0);
+        }
+    }
+
+    return(-ENODEV);
+}
+
+/** Initialization
+ *
+ * For all ports that have a used flag greater than 0, request port
+ * memory and register ISRs. If we cannot get the memory of all these
+ * ports, release all already requested ports and return an error.
+ *
+ * @return Success status, zero on success. With a non-zero return
+ * value of this routine, insmod will fail to load the module !
+ *
+ * @author Jochen Kupper, Hua Mao, Roberto Finazzi
+ * @version 2000/03/10 */
+//int init_module(void)   //Hm, IgH
+int init_aip_com(void)
+{
+    int             errorcode = 0;
+    unsigned int    i, j;
+
+    printk(KERN_INFO "rt_com: Loading real-time serial port driver (version "VERSION ").\n");
+
+    for (i = 0; i < RT_COM_CNT; i++) {
+        struct rt_com_struct    *p = &(rt_com_table[i]);
+
+        // if used set default values
+        if (p->used > 0) {
+	    printk(KERN_WARNING "RS232 testing %d\n",i);
+            if (-EBUSY == check_region(p->port, 8)) {
+                errorcode = -EBUSY;
+                printk(KERN_WARNING "rt_com: error %d: cannot request port region %x\n", errorcode, p->port);
+                break;
+            }
+
+            request_region(p->port, 8, "rt_com");
+            rt_com_request_irq(p->irq, p->isr);
+	    printk(KERN_WARNING "RS232 Request IRQ: %d\n",p->irq);
+            rt_com_setup(i, p->baud, p->mode, p->parity, p->stopbits, p->wordlength, p->fifotrig);
+        }
+    }
+
+    if (0 != errorcode) {
+        printk(KERN_WARNING "rt_com: giving up.\n");
+        for (j = 0; j < i; j++) {
+            struct rt_com_struct    *p = &(rt_com_table[j]);
+            if (0 < p->used) {
+                rt_com_free_irq(p->irq);
+                release_region(p->port, 8);
+            }
+        }
+    }
+    else {
+        printk(KERN_INFO "rt_com: sucessfully loaded.\n");
+    }
+
+    return(errorcode);
+}
+
+/** Cleanup
+ *
+ * Unregister ISR and releases memory for all ports
+ *
+ * @author Jochen Kupper
+ * @version 1999/10/01 */
+//void cleanup_module(void)  Hm, IgH
+void cleanup_aip_com(void)
+{
+    int i;
+    for (i = 0; i < RT_COM_CNT; i++) {
+        struct rt_com_struct    *p = &(rt_com_table[i]);
+        if (0 < p->used) {
+            rt_com_free_irq(p->irq);
+            rt_com_setup(i, 0, 0, 0, 0, 0, 0);
+            release_region(p->port, 8);
+        }
+    }
+
+    printk(KERN_INFO "rt_com: unloaded.\n");
+}
+
+/*
+EXPORT_SYMBOL(rt_com_buffersize);
+EXPORT_SYMBOL(rt_com_clear_input);
+EXPORT_SYMBOL(rt_com_clear_output);
+EXPORT_SYMBOL(rt_com_error);
+EXPORT_SYMBOL(rt_com_hwsetup);
+EXPORT_SYMBOL(rt_com_read);
+EXPORT_SYMBOL(rt_com_read_modem);
+EXPORT_SYMBOL(rt_com_setup);
+EXPORT_SYMBOL(rt_com_table);
+EXPORT_SYMBOL(rt_com_write);
+EXPORT_SYMBOL(rt_com_write_modem);
+EXPORT_SYMBOL(rt_com_set_mode);
+EXPORT_SYMBOL(rt_com_set_fifotrig);
+*/
+
+/**
+ * Local Variables:
+ * mode: C
+ * c-file-style: "Stroustrup"
+ * End:
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/aip_com.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,159 @@
+/**************************************************************************************************
+*
+*                          aip_com.h
+*
+*           Macros für Kommunikation über serielle Schnittstelle
+*           Basiert auf rt_com.h von rtai !! (siehe unten)
+*
+*           
+*           Autor: Wilhelm Hagemeister
+*
+*           (C) Copyright IgH 2002
+*           Ingenieurgemeinschaft IgH
+*           Heinz-Bäcker Str. 34
+*           D-45356 Essen
+*           Tel.: +49 201/61 99 31
+*           Fax.: +49 201/61 98 36
+*           E-mail: hm@igh-essen.com
+*
+*
+*           $RCSfile: aip_com.h,v $
+*           $Revision: 1.1 $
+*           $Author: hm $
+*           $Date: 2004/09/30 15:50:32 $
+*           $State: Exp $
+*
+*
+*
+*
+*
+*
+*
+*
+*
+**************************************************************************************************/
+
+/** rt_com
+ *  ======
+ *
+ * RT-Linux kernel module for communication across serial lines.
+ *
+ * Copyright (C) 1997 Jens Michaelsen
+ * Copyright (C) 1997-2000 Jochen Kupper
+ * Copyright (C) 2002 Giuseppe Renoldi
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; see the file License. if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * $Id: aip_com.h,v 1.1 2004/09/30 15:50:32 hm Exp $ */
+
+
+
+#ifndef AIP_COM_H
+#define AIP_COM_H
+
+/** This is the interface definition of the plain rt_com API.
+ *
+ * This should be all you need to use rt_com within your real-time
+ * kernel module.
+ *
+ * (When POSIX is done, we will reference the appropriate header
+ * here - probably depending on a flag.) */
+
+int init_aip_com(void);              //Hm, IgH
+void cleanup_aip_com(void);          //Hm, IgH
+
+
+/** specify hardware parameters, set-up communication parameters */
+extern int rt_com_hwsetup( unsigned int ttyS, int base, int irq );
+extern int rt_com_setup( unsigned int ttyS, int baud, int mode,
+			 unsigned int parity, unsigned int stopbits,
+			 unsigned int wordlength, int fifotrig );
+
+/** read/write from/to input/output buffer */
+extern int rt_com_read( unsigned int, char *, int );
+extern int rt_com_write( unsigned int ttyS, char *buffer, int count );
+
+/** clear input or output buffer */
+extern int rt_com_clear_input( unsigned int ttyS );
+extern int rt_com_clear_output( unsigned int ttyS );
+
+/** read input signal from modem (CTS,DSR,RI,DCD), set output signal
+ * for modem control (DTR,RTS) */
+extern int rt_com_read_modem( unsigned int ttyS, int signal );
+extern int rt_com_write_modem( unsigned int ttyS, int signal, int value );
+
+/** functioning mode and fifo trigger setting */
+extern int rt_com_set_mode( unsigned int ttyS, int mode);
+extern int rt_com_set_fifotrig( unsigned int ttyS, int fifotrig);
+
+/** return last error detected */
+extern int rt_com_error( unsigned int ttyS );
+
+
+/** size of internal queues, this is constant during module lifetime */
+extern unsigned int rt_com_buffersize;
+
+#define rt_com_set_param rt_com_hwsetup
+#define rt_com_setup_old(a,b,c,d,e) rt_com_setup((a),(b),0,(c),(d),(e),-1)
+
+
+/** functioning modes */
+#define RT_COM_NO_HAND_SHAKE  0x00
+#define RT_COM_DSR_ON_TX      0x01
+#define RT_COM_HW_FLOW	      0x02
+
+/** parity flags */
+#define RT_COM_PARITY_EVEN    0x18
+#define RT_COM_PARITY_NONE    0x00
+#define RT_COM_PARITY_ODD     0x08
+#define RT_COM_PARITY_HIGH    0x28
+#define RT_COM_PARITY_LOW     0x38
+
+/* FIFO Control */
+#define RT_COM_FIFO_DISABLE   0x00
+#define RT_COM_FIFO_SIZE_1    0x00
+#define RT_COM_FIFO_SIZE_4    0x40
+#define RT_COM_FIFO_SIZE_8    0x80
+#define RT_COM_FIFO_SIZE_14   0xC0
+
+/** rt_com_write_modem  masks */
+#define RT_COM_DTR            0x01
+#define RT_COM_RTS            0x02 
+
+/** rt_com_read_modem masks */
+#define RT_COM_CTS            0x10
+#define RT_COM_DSR            0x20
+#define RT_COM_RI             0x40
+#define RT_COM_DCD            0x80
+
+/** rt_com_error masks */
+#define RT_COM_BUFFER_FULL    0x01
+#define RT_COM_OVERRUN_ERR    0x02
+#define RT_COM_PARITY_ERR     0x04
+#define RT_COM_FRAMING_ERR    0x08
+#define RT_COM_BREAK          0x10
+
+
+#endif /* RT_COM_H */
+
+
+
+/**
+ * Local Variables:
+ * mode: C
+ * c-file-style: "Stroustrup"
+ * End:
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/aip_comP.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,206 @@
+/**
+ * rt_com
+ * ======
+ *
+ * RT-Linux kernel module for communication across serial lines.
+ *
+ * Copyright (C) 1997 Jens Michaelsen
+ * Copyright (C) 1997-2000 Jochen Kupper
+ * Copyright (C) 1999 Hua Mao <hmao@nmt.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; see the file License. if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+
+
+#ifndef AIP_COM_P_H
+#define AIP_COM_P_H
+
+
+#define RT_COM_NAME "rt_com(aip)"  //Hm, IgH
+
+/* input/ouput buffer (FIFO) sizes */
+#define RT_COM_BUF_SIZ        256	// MUST BE ONLY POWER OF 2 !!
+/* amount of free space on input buffer for RTS reset */
+#define RT_COM_BUF_LOW        (RT_COM_BUF_SIZ / 3)
+/* amount of free space on input buffer for RTS set */
+#define RT_COM_BUF_HI         (RT_COM_BUF_SIZ * 2 / 3)
+/* limit of free space on input buffer for buffer full error */
+#define RT_COM_BUF_FULL       20
+
+
+/* usage flags */
+#define RT_COM_PORT_FREE      0x00
+#define RT_COM_PORT_INUSE     0x01
+#define RT_COM_PORT_SETUP     0x02
+
+
+/* Some hardware description */
+#define RT_COM_BASE_BAUD      115200
+
+/** Interrupt Service Routines
+ * These are private functions */
+static void rt_com0_isr( void );
+static void rt_com1_isr( void );
+
+
+
+
+/** Interrupt handling
+ *
+ * Define internal convinience macros for interrupt handling, so we
+ * get rid of the system dependencies.
+ */
+//#define rt_com_irq_off( state )         do{}while(0) //rt_global_save_flags( &state ); rt_global_cli() schreiben und lesen sowieso in IRQ Hm
+//#define rt_com_irq_on(state)            do{}while(0) //rt_global_restore_flags( state ) 
+#define rt_com_irq_off( state )         rt_global_save_flags( &state ); rt_global_cli() 
+#define rt_com_irq_on(state)            rt_global_restore_flags( state ) 
+#define rt_com_request_irq( irq, isr )  rt_request_global_irq( irq, isr ); rt_enable_irq( irq );
+#define rt_com_free_irq( irq )          rt_free_global_irq( irq )
+
+
+/* port register offsets */
+#define RT_COM_RXB  0x00
+#define RT_COM_TXB  0x00
+#define RT_COM_IER  0x01
+#define RT_COM_IIR  0x02
+#define RT_COM_FCR  0x02
+#define RT_COM_LCR  0x03
+#define RT_COM_MCR  0x04
+#define RT_COM_LSR  0x05
+#define RT_COM_MSR  0x06
+#define RT_COM_DLL  0x00
+#define RT_COM_DLM  0x01
+
+/** MCR Modem Control Register masks */
+#define MCR_DTR               0x01 // Data Terminal Ready
+#define MCR_RTS               0x02 // Request To Send 
+#define MCR_OUT1              0x04
+#define MCR_OUT2              0x08
+#define MCR_LOOP              0x10
+#define MCR_AFE               0x20 // AutoFlow Enable
+
+/** IER Interrupt Enable Register masks */
+#define IER_ERBI              0x01  // Enable Received Data Available Interrupt
+#define IER_ETBEI             0x02  // Enable Transmitter Holding Register
+                                    // Empty Interrupt
+#define IER_ELSI              0x04  // Enable Receiver Line Status Interrupt
+#define IER_EDSSI             0x08  // Enable Modem Status Interrupt
+
+/** MSR Modem Status Register masks */
+#define MSR_DELTA_CTS         0x01
+#define MSR_DELTA_DSR         0x02
+#define MSR_TERI              0x04
+#define MSR_DELTA_DCD         0x08
+#define MSR_CTS               0x10
+#define MSR_DSR               0x20
+#define MSR_RI                0x40
+#define MSR_DCD               0x80
+
+/** LSR Line Status Register masks */
+#define LSR_DATA_READY        0x01
+#define LSR_OVERRUN_ERR       0x02
+#define LSR_PARITY_ERR        0x04
+#define LSR_FRAMING_ERR       0x08
+#define LSR_BREAK             0x10
+#define LSR_THRE              0x20	// Transmitter Holding Register
+#define LSR_TEMT              0x40	// Transmitter Empty
+
+/** FCR FIFO Control Register masks */
+#define FCR_FIFO_ENABLE       0x01
+#define FCR_INPUT_FIFO_RESET  0x02
+#define FCR_OUTPUT_FIFO_RESET 0x04
+
+/** data buffer
+ *
+ * Used for buffering of input and output data. Two buffers per port
+ * (one for input, one for output). Organized as a FIFO */
+struct rt_buf_struct{
+    unsigned int  head;
+    unsigned int  tail;
+    char buf[ RT_COM_BUF_SIZ ];
+};
+
+
+
+/** Port data
+ *
+ * Internal information structure containing all data for a port. One
+ * structure for every port.
+ *
+ * Contains all current setup parameters and all data currently
+ * buffered by rt_com.
+ *
+ * mode (functioning mode)
+ *   possible values:
+ *   - RT_COM_DSR_ON_TX     - for standard functioning mode (DSR needed on TX)
+ *   - RT_COM_NO_HAND_SHAKE - for comunication without hand shake signals
+ *                            (only RXD-TXD-GND)
+ *   - RT_COM_HW_FLOW       - for hardware flow control (RTS-CTS)
+ *   Of course RT_COM_DSR_ON_TX and RT_COM_NO_HAND_SHAKE cannot be
+ *   sppecified at the same time.
+ *
+ *   NOTE: When you select a mode that uses hand shake signals pay
+ *   attention that no input signals (CTS,DSR,RI,DCD) must be
+ *   floating.
+ *
+ * used (usage flag)
+ *   possible values:
+ *   - RT_COM_PORT_INUSE - port region requested by init_module
+ *   - RT_COM_PORT_FREE  - port region requested by rt_com_set_param
+ *   - RT_COM_PORT_SETUP - port parameters are setup,
+ *                         don't specify at compile time !
+ *
+ * error
+ *   last error detected
+ *
+ * ier (interrupt enable register)
+ *   copy of IER chip register, last value set by rt_com.
+ *
+ * mcr (modem control register)
+ *   copy of the MCR internal register
+ */
+struct rt_com_struct{
+    int baud_base;
+    int port;
+    int irq;
+    void (*isr)(void);
+	int baud;
+	unsigned int wordlength;
+	unsigned int parity;
+	unsigned int stopbits;
+    int mode;
+	int fifotrig;
+    int used;
+	int error;
+    int type;
+    int ier;
+    int mcr;
+    struct rt_buf_struct ibuf;
+    struct rt_buf_struct obuf;
+};
+
+
+#endif /* RT_COM_P_H */
+
+
+
+/**
+ * Local Variables:
+ * mode: C
+ * c-file-style: "Stroustrup"
+ * End:
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/cif-rtai-io.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,43 @@
+unsigned long cif_open_card(
+		unsigned int board_no,
+		unsigned int in_size,
+		unsigned int out_size,
+		void (*callback)(unsigned long priv_data),
+		unsigned long priv_data
+		);
+
+void cif_close_card(
+		unsigned long fd
+		);
+
+int cif_reset_card(
+		unsigned long fd,
+		unsigned int timeout,
+		unsigned int context	// 1 = interrupt context
+		);
+
+void cif_set_host_state(
+		unsigned long fd,
+		unsigned int state
+		);
+
+int cif_exchange_io(
+		unsigned long fd,
+		void *recv_data,
+		void *send_data
+		);
+
+int cif_read_io(
+		unsigned long fd,
+		void *recv_data
+		);
+
+int cif_write_io(
+		unsigned long fd,
+		void *send_data
+		);
+
+int cif_card_ready(
+		unsigned long fd
+		);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/msr_io.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,539 @@
+/******************************************************************************
+ *
+ * msr_io.c
+ *
+ * Sample Modul für EtherCAT
+ *           
+ * Autoren: Wilhelm Hagemeister, Florian Pose
+ *
+ * $Date$
+ * $Author$
+ *
+ * (C) Copyright IgH 2005
+ * Ingenieurgemeinschaft IgH
+ * Heinz-Bäcker Str. 34
+ * D-45356 Essen
+ * Tel.: +49 201/61 99 31
+ * Fax.: +49 201/61 98 36
+ * E-mail: hm@igh-essen.com
+ *
+ * /bin/setserial /dev/ttyS0 uart none
+ * /bin/setserial /dev/ttyS1 uart none
+ *
+ ******************************************************************************/
+
+/*--Includes-----------------------------------------------------------------*/
+
+#include <linux/module.h>
+#include <linux/tqueue.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <msr_reg.h>
+#include <msr_messages.h>
+#include <msr_main.h>
+
+#include <rtai.h>
+#include <rtai_sched.h>
+
+#include "msr_io.h"
+
+//#include <msr_float.h>
+
+#include "../drivers/ec_master.h"
+#include "../drivers/ec_device.h"
+#include "../drivers/ec_types.h"
+#include "../rs232dbg/rs232dbg.h"
+
+/*--Defines------------------------------------------------------------------*/
+
+#define TIMERTICS 1e6	// in ns; Thus have a task time of 1ms
+#define MSR_ABTASTFREQUENZ (1e9/TIMERTICS)
+
+//#define MSR_ABTASTFREQUENZ (1000) //1e9/TIMERTICS)
+#define TICK ((1000000 / MSR_ABTASTFREQUENZ) * 1000)
+#define TIMER_FREQ (APIC_TIMER ? FREQ_APIC : FREQ_8254)
+#define APIC_TIMER 0
+
+//#define MSR_SLOW_DEBUG
+
+/*--Globale Variablen--------------------------------------------------------*/
+
+RT_TASK process_image;
+
+const int Tick = TICK;
+
+unsigned int ecat_tx_delay = 0; //Zeit vom Ende der TimerInterruptRoutine bis
+                                //TX-Interrupt der Netzwerkkarte 
+unsigned int ecat_rx_delay = 0; //RX-Interrupt der Netzwerkkarte
+
+unsigned int tx_intr = 0;
+unsigned int rx_intr = 0;
+unsigned int total_intr = 0;
+
+unsigned int thread_end = 0;
+
+#define USE_ETHERCAT
+
+#ifdef USE_ETHERCAT
+
+static EtherCAT_master_t *ecat_master = NULL;
+
+extern EtherCAT_device_t rtl_ecat_dev;
+
+//#define ECAT_SLAVES_COUNT 16
+
+static EtherCAT_slave_t ecat_slaves[] =
+{
+    //Block 1
+  ECAT_INIT_SLAVE(Beckhoff_EK1100),
+  ECAT_INIT_SLAVE(Beckhoff_EL4102),
+  ECAT_INIT_SLAVE(Beckhoff_EL3162),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL3102),
+  ECAT_INIT_SLAVE(Beckhoff_EL4102),
+  ECAT_INIT_SLAVE(Beckhoff_EL4102),
+  ECAT_INIT_SLAVE(Beckhoff_EL4102),
+  ECAT_INIT_SLAVE(Beckhoff_EL3162),
+  ECAT_INIT_SLAVE(Beckhoff_EL3162),
+  ECAT_INIT_SLAVE(Beckhoff_EL3162),
+  ECAT_INIT_SLAVE(Beckhoff_EL3102),
+  ECAT_INIT_SLAVE(Beckhoff_EL3102),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  //Block 2
+  ECAT_INIT_SLAVE(Beckhoff_EK1100),
+  ECAT_INIT_SLAVE(Beckhoff_EL4102),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL3162),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL3102),
+  //Block 3
+  ECAT_INIT_SLAVE(Beckhoff_EK1100),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014)
+
+
+};
+
+#define ECAT_SLAVES_COUNT (sizeof(ecat_slaves)/sizeof(EtherCAT_slave_t))
+
+#endif
+
+double value;
+int dig1;
+
+
+static int next2004(int *wrap)
+{
+    static int i=0;
+
+    int j=0;
+
+    *wrap = 0;
+    for(j=0;j<ECAT_SLAVES_COUNT;j++) {
+	i++;
+	i %= ECAT_SLAVES_COUNT;
+	if(i == 0) *wrap = 1;
+	if(ecat_slaves[i].desc == Beckhoff_EL2004) {
+	    return i;
+	}
+    }
+    return -1;
+}
+
+/*
+*******************************************************************************
+*
+* Function: msr_controller
+*
+* Beschreibung: Zyklischer Prozess
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+*******************************************************************************
+*/
+
+void msr_controller(void)
+{
+  static int ms = 0;
+  static int cnt = 0;
+  static unsigned long int k = 0;
+  static int firstrun = 1;
+
+  static int klemme = 12;
+  static int kanal = 0;
+  static int up_down = 0;
+  int wrap = 0;
+
+  ms++;
+  ms %= 1000;
+
+#ifdef USE_ETHERCAT
+  ecat_tx_delay = ((unsigned int) (100000 / HZ) * (ecat_master->dev->tx_time-k))
+    / (current_cpu_data.loops_per_jiffy / 10);  
+  ecat_rx_delay = ((unsigned int) (100000 / HZ) * (ecat_master->dev->rx_time-k))
+    / (current_cpu_data.loops_per_jiffy / 10);  
+
+  rx_intr = ecat_master->dev->rx_intr_cnt;
+  tx_intr = ecat_master->dev->tx_intr_cnt;
+  total_intr = ecat_master->dev->intr_cnt;
+  // Prozessdaten lesen
+  if(!firstrun) {
+      EtherCAT_read_process_data(ecat_master);
+
+      // Daten lesen und skalieren
+      value = EtherCAT_read_value(&ecat_master->slaves[5], 0) / 3276.7;
+      dig1 = EtherCAT_read_value(&ecat_master->slaves[3], 0);
+  }
+  // Daten schreiben
+
+  EtherCAT_write_value(&ecat_master->slaves[4], 0, ms > 500 ? 1 : 0);
+  EtherCAT_write_value(&ecat_master->slaves[4], 1, ms > 500 ? 0 : 1);
+  EtherCAT_write_value(&ecat_master->slaves[4], 2, ms > 500 ? 0 : 1);
+  EtherCAT_write_value(&ecat_master->slaves[4], 3, ms > 500 ? 1 : 0);
+
+
+   if(cnt++ > 20) {
+      cnt = 0;
+      if(++kanal > 3) {
+	  kanal = 0;
+	  klemme = next2004(&wrap);
+	  if (wrap == 1) { 
+	      if(up_down == 1) 
+		  up_down = 0;
+	      else up_down = 1;
+	      }
+	  }
+      }
+   if (klemme >=0)
+    EtherCAT_write_value(&ecat_master->slaves[klemme], kanal,up_down);
+  
+//  EtherCAT_write_value(&ecat_master->slaves[13], 1, ms > 500 ? 0 : 1);
+//  EtherCAT_write_value(&ecat_master->slaves[14], 2, ms > 500 ? 0 : 1);
+//  EtherCAT_write_value(&ecat_master->slaves[15], 3, ms > 500 ? 1 : 0);
+
+  // Prozessdaten schreiben
+  rdtscl(k);
+  EtherCAT_write_process_data(ecat_master);
+  firstrun = 0;
+#endif
+}
+
+/*
+*******************************************************************************
+*
+* Function: msr_run_interrupt
+*
+* Beschreibung: Interrupt abarbeiten
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+*******************************************************************************
+*/
+
+void process_thread(int priv_data)
+{
+  while (1)
+  {
+
+#ifdef USE_ETHERCAT
+    MSR_RTAITHREAD_CODE(msr_controller(); msr_write_kanal_list(); );  
+#else
+    MSR_RTAITHREAD_CODE( msr_write_kanal_list(); );  
+#endif
+
+
+
+    /*   if(counter++ >=MSR_ABTASTFREQUENZ) {
+	counter = 0;
+	sprintf(buf,"rt:life");
+	msr_print_info(buf);
+    }
+    */
+    rt_task_wait_period();
+  }
+  thread_end = 1;
+}
+
+/*
+*******************************************************************************
+*
+* Function: msr_register_channels
+*
+* Beschreibung: Kanäle registrieren
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+*******************************************************************************
+*/
+
+int msr_globals_register(void)
+{
+  msr_reg_kanal("/value", "V", &value, TDBL);
+  msr_reg_kanal("/dig1", "", &dig1, TINT);
+  msr_reg_kanal("/Taskinfo/Ecat/TX-Delay","us",&ecat_tx_delay,TUINT);
+  msr_reg_kanal("/Taskinfo/Ecat/RX-Delay","us",&ecat_rx_delay,TUINT);
+  msr_reg_kanal("/Taskinfo/Ecat/TX-Cnt","",&tx_intr,TUINT);
+  msr_reg_kanal("/Taskinfo/Ecat/RX-Cnt","",&rx_intr,TUINT);
+  msr_reg_kanal("/Taskinfo/Ecat/Total-Cnt","",&total_intr,TUINT);
+
+  return 0;
+}
+
+/*
+*******************************************************************************
+*
+* Function: msr_init
+*
+* Beschreibung: MSR initialisieren
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+*******************************************************************************
+*/
+
+int msr_init(void)
+{   
+  int rv = -1;
+  RTIME tick_period, now;
+
+//  rt_mount_rtai();
+
+  msr_print_info("Initialising rtlib.");
+
+  // RT-lib initialisieren    
+  if (msr_rtlib_init(1, MSR_ABTASTFREQUENZ, 10, msr_globals_register) < 0)
+  {
+    msr_print_warn("msr_modul: can't initialize rtlib!");
+    goto out_umount;
+  }
+
+#ifdef USE_ETHERCAT
+  msr_print_info("Opening EtherCAT device.");
+
+  mdelay(100);
+
+  if (EtherCAT_device_open(&rtl_ecat_dev) < 0)
+  {
+    msr_print_warn("msr_modul: Could not initialize EtherCAT NIC.");
+    goto out_rtlib;
+  }
+
+  if (!rtl_ecat_dev.dev) // Es gibt kein EtherCAT-Device
+  {  
+    msr_print_warn("msr_modul: No EtherCAT device!");
+    goto out_close;
+  }
+//    goto out_close;
+
+  // EtherCAT-Master und Slaves initialisieren
+
+  msr_print_info("Initialising EtherCAT master");
+
+  if ((ecat_master = (EtherCAT_master_t *) kmalloc(sizeof(EtherCAT_master_t), GFP_KERNEL)) == 0)
+  {
+    msr_print_warn(KERN_ERR "msr_modul: Could not alloc memory for EtherCAT master!\n");
+    goto out_close;
+  }
+
+  if (EtherCAT_master_init(ecat_master, &rtl_ecat_dev) < 0)
+  {
+    msr_print_warn(KERN_ERR "EtherCAT could not init master!\n");
+    goto out_master;
+  }
+
+  msr_print_info("Checking EtherCAT slaves.");
+  mdelay(10); //Nachricht abwarten
+
+  if (EtherCAT_check_slaves(ecat_master, ecat_slaves, ECAT_SLAVES_COUNT) != 0)
+  {
+    msr_print_warn(KERN_ERR "EtherCAT: Could not init slaves!\n");
+    goto out_masterclear;
+  }
+
+  msr_print_info("Activating all EtherCAT slaves.");
+  mdelay(10); //Nachricht abwarten
+
+  if (EtherCAT_activate_all_slaves(ecat_master) != 0)
+  {
+    printk(KERN_ERR "EtherCAT: Could not activate slaves!\n");
+    goto out_masterclear;
+  }
+
+  // Zyklischen Aufruf starten
+
+#endif
+  msr_print_info("Starting cyclic sample thread.");
+  mdelay(10); //Nachricht abwarten
+
+  EtherCAT_write_process_data(ecat_master);
+
+  //mdelay(100);
+  tick_period = start_rt_timer(nano2count(TIMERTICS));
+  now = rt_get_time();
+
+  if ((rv = rt_task_init(&process_image, process_thread, 0/*data*/, 64000/*stacksize*/, 0/*prio*/, 1/*use fpu*/, 0/*signal*/)))
+  {
+      msr_print_error("Could not initialise process_thread\n");
+      goto out_stoptimer;
+  }
+
+  msr_print_info("Initialised sample thread\n");
+
+  if ((rv = rt_task_make_periodic(&process_image, 
+				  now + tick_period, 
+				  tick_period)))
+  {
+      msr_print_error("Could not start process_thread\n");
+      goto out_stoptask;
+  }
+
+  msr_print_info("Started sample thread.");
+
+  return 0;
+
+ out_stoptask:
+  msr_print_info("Deleting task....");
+  rt_task_delete(&process_image);
+
+ out_stoptimer:
+  msr_print_info("Stopping timer.");
+  stop_rt_timer();
+
+#ifdef USE_ETHERCAT
+ out_masterclear:
+  msr_print_info("Clearing EtherCAT master.");
+  EtherCAT_master_clear(ecat_master);
+
+ out_master:
+    msr_print_info("Freeing EtherCAT master.");
+  kfree(ecat_master);
+
+ out_close:
+  msr_print_info("Closing device.");
+
+  EtherCAT_device_close(&rtl_ecat_dev);
+#endif
+
+ out_rtlib:
+  msr_print_info("msr_rtlib_cleanup()");
+  mdelay(10);
+  msr_rtlib_cleanup();
+
+ out_umount:
+//  rt_umount_rtai();
+
+  return rv;
+}
+
+/*
+*******************************************************************************
+*
+* Function: msr_io_cleanup
+*
+* Beschreibung: Aufräumen
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+*******************************************************************************
+*/
+
+void msr_io_cleanup(void)
+{
+
+  msr_print_info("Stopping timer.");
+
+  stop_rt_timer();
+
+  msr_print_info("Deleting task....");
+
+  rt_task_delete(&process_image);
+/*
+  for(i=0;i<1000;i++) {
+      udelay(100);
+      if(thread_end == 1) {
+	  msr_print_info("Task ended at count %d",i);
+	  break;
+      }
+  }
+*/
+  //noch einmal lesen
+
+  msr_print_info("Read Processdata");
+  EtherCAT_read_process_data(ecat_master);
+
+  //EtherCAT_read_process_data(ecat_master);
+#ifdef USE_ETHERCAT
+  if (ecat_master)
+  {
+
+    msr_print_info("Deactivating slaves.");
+
+
+    EtherCAT_deactivate_all_slaves(ecat_master);    
+
+
+    msr_print_info("Clearing EtherCAT master.");
+
+    EtherCAT_master_clear(ecat_master);
+
+    msr_print_info("Freeing EtherCAT master.");
+
+
+    kfree(ecat_master);
+    ecat_master = NULL;
+  }
+
+  msr_print_info("Closing device.");
+
+  EtherCAT_device_close(&rtl_ecat_dev);
+
+#endif
+  msr_print_info("msr_rtlib_cleanup()");
+
+  msr_rtlib_cleanup();
+  //rt_umount_rtai();
+}
+
+/*---Treiber-Einsprungspunkte etc.-------------------------------------------*/
+
+MODULE_LICENSE("GPL");
+
+module_init(msr_init);
+module_exit(msr_io_cleanup);
+
+/*---Ende--------------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/msr_io.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,39 @@
+
+/******************************************************************************
+*
+*
+*           Alle globalen Variabeln
+*           
+*           Autor: Richard Hacker
+*
+*           (C) Copyright IgH 2005
+*           Ingenieurgemeinschaft IgH
+*           Heinz-Bäcker Str. 34
+*           D-45356 Essen
+*           Tel.: +49 201/61 99 31
+*           Fax.: +49 201/61 98 36
+*           E-mail: ha@igh-essen.com
+*
+*
+*           $RCSfile: msr_io.h,v $
+*           $Revision: 1.2 $
+*           $Author: hm $
+*           $Date: 2005/09/02 10:26:38 $
+*           $State: Exp $
+*
+*
+*
+*
+*
+*
+*
+*
+*
+******************************************************************************/
+
+#ifndef _ETH_GLOBALS_H_
+#define _ETH_GLOBALS_H_
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/msr_load	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,36 @@
+#!/bin/sh 
+module="msr_modul"
+device="msr"
+mode="664"
+
+# Group: since distributions do it differently, look for wheel or use staff
+if grep '^staff:' /etc/group > /dev/null; then
+    group="staff"
+else
+    group="wheel"
+fi
+
+# invoke insmod with all arguments we got
+# and use a pathname, as newer modutils don't look in . by default
+/sbin/insmod -f ./$module.o $* || exit 1
+
+major=`cat /proc/devices | awk "\\$2==\"$device\" {print \\$1}"`
+
+echo $major
+# Remove stale nodes and replace them, then give gid and perms
+# Usually the script is shorter, it's scull that has several devices in it.
+
+rm -f /dev/${device}
+mknod /dev/${device} c $major 0
+# ln -sf ${device}0 /dev/${device}
+chgrp users /dev/${device}
+chmod $mode  /dev/${device}
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/msr_unload	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,16 @@
+#!/bin/sh
+module="msr_modul"
+device="msr"
+
+# invoke rmmod with all arguments we got
+/sbin/rmmod $module $* || exit 1
+
+# Remove stale nodes
+
+rm -f /dev/${device} /dev/${device}0 
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/msrserv.pl	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,230 @@
+#!/usr/bin/perl -w
+
+# Multithreaded Server 
+# according to the example from "Programming Perl"
+#
+# works with read/write on a device-file  
+#
+# $Revision: 1.1 $
+# $Date: 2002/07/09 10:10:59 $
+# $RCSfile: msrserv.pl,v $
+#
+
+require 5.002;
+use strict;
+BEGIN { $ENV{PATH} = '/usr/bin:/bin' }
+use Socket;
+use Carp;
+use FileHandle;
+use Getopt::Std; 
+
+use Sys::Syslog qw(:DEFAULT setlogsock); 
+
+use vars qw (
+	     $self $pid $dolog $port $dev %opts $selfbase
+	     $len $offset $stream $written $read $log $blksize
+	     $authfile %authhosts
+	     );
+
+
+# Do logging to local syslogd by unix-domain socket instead of inetd
+setlogsock("unix");  
+
+# Prototypes and some little Tools
+sub spawn;
+sub logmsg { 
+  my ($level, @text) = @_;
+  syslog("daemon|$level", @text) if $dolog;
+#  print STDERR "daemon|$level", @text, "\n" if $dolog;
+}
+sub out {
+  my $waitpid = wait; 
+  logmsg("notice", "$waitpid exited");
+  unlink "$selfbase.pid";
+  exit 0;
+}
+
+sub help {
+  print "\n  usage: $0 [-l og] [-h elp] [-p port] [-d device]\n"; 
+  exit; 
+}
+
+# Process Options
+%opts = (
+	 "l" => 1,
+	 "h" => 0,
+	 "p" => 2345,
+	 "d" => "/dev/msr"
+	 );
+  
+getopts("lhp:d:", \%opts);
+
+help if $opts{"h"};
+
+( $self =  $0 ) =~ s+.*/++ ;
+( $selfbase = $self ) =~ s/\..*//;
+$log = "$selfbase.log";
+$dolog = $opts{"l"};
+$port = $opts{"p"};
+$dev = $opts{"d"};
+$blksize = 1024; # try to write as much bytes
+$authfile = "/opt/kbw/etc/hosts.auth"; 
+
+# Start logging
+openlog($self, 'pid');
+
+# Flush Output, dont buffer
+$| = 1;
+
+# first fork and run in background
+if ($pid = fork) {
+#  open LOG, ">$log" if $dolog;
+#  close LOG;
+  logmsg("notice", "forked process: $pid\n");
+  exit 0;
+}
+
+# Server tells about startup success
+open (PID, ">$selfbase.pid");
+print PID "$$\n";
+close PID;
+
+# Cleanup on exit (due to kill -TERM signal)
+$SIG{TERM} = \&out;
+
+# We use streams
+my $proto = getprotobyname('tcp');
+
+# Open Server socket
+socket(Server, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
+setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
+  or die "setsocketopt: $!";
+bind (Server, sockaddr_in($port, INADDR_ANY))
+  or die "bind: $!";
+listen (Server, SOMAXCONN) 
+  or die "listen: $!";
+
+%authhosts = ();
+# get authorized hosts
+open (AUTH, $authfile) 
+  or logmsg ("notice", "Could not read allowed hosts file: $authfile");
+while (<AUTH>) {
+    chomp;
+    my $host = lc $_;
+    logmsg ("notice", "Authorized host: $host");
+    $authhosts{$_} = 1 if $host =~ /^[\d\w]/;
+}
+close (AUTH);
+
+# tell about open server socket
+logmsg ("notice", "Server started at port $port");
+
+my $waitpid = 0;
+my $paddr;
+
+# wait for children to return, thus avoiding zombies
+sub REAPER {
+  $waitpid = wait;
+  $SIG{CHLD} = \&REAPER; 
+  logmsg ("notice", "reaped $waitpid", ($? ? " with exit $?" : ""));
+}
+
+# also all sub-processes should wait for their children
+$SIG{CHLD} = \&REAPER;
+
+# start a new server for every incoming request
+for ( ; $paddr = accept(Client, Server); close (Client)) {
+  my ($port, $iaddr) = sockaddr_in($paddr);
+  my $name = lc gethostbyaddr($iaddr, AF_INET);
+  my $ipaddr = inet_ntoa($iaddr);
+  my $n = 0;
+
+# tell about the requesting client
+  logmsg ("info", "Connection from $ipaddr ($name) at port $port");
+
+  spawn sub {
+    my ($head, $hlen, $pos, $pegel, $typ, $siz, $nch, $nrec, $dat, $i, $j, $n, $llen); 
+    my ($watchpegel, $shmpegel);
+    my ($rin, $rout, $in, $line, $data_requested, $oversample);
+    my (@channels);
+    
+#   to use stdio on writing to Client
+    Client->autoflush();
+
+#   Open Device 
+    sysopen (DEV, "$dev", O_RDWR | O_NONBLOCK, 0666) or die("can't open $dev");
+
+#   Bitmask to check for input on stdin
+    $rin = "";
+    vec($rin, fileno(Client), 1) = 1; 
+
+#   check for authorized hosts
+    my $access = 'allow';
+    $access = 'allow' if $authhosts{$ipaddr};
+    $line = "<remote_host host=\"$ipaddr\" access=\"$access\">\n";
+    $len = length $line;
+    $offset = 0;
+    while ($len) {
+	$written = syswrite (DEV, $line, $len, $offset);
+	$len -= $written;
+	$offset += $written;
+    }
+
+    while ( 1 ) {
+      $in = select ($rout=$rin, undef, undef, 0.0); # poll client
+#     look for any Input from Client
+      if ($in) {
+#       exit on EOF
+	$len = sysread (Client, $line, $blksize) or exit;
+	logmsg("info", "got $len bytes: \"$line\""); 
+	$offset = 0;
+#       copy request to device
+	while ($len) {
+	  $written = syswrite (DEV, $line, $len, $offset);
+	  $len -= $written;
+	  $offset += $written;
+	}
+      }
+#     look for some output from device
+      if ($len = sysread DEV, $stream, $blksize) {
+	print Client $stream;
+      } else {
+	select undef, undef, undef, 0.1; # calm down if nothing on device
+      }
+    }
+  }
+}
+
+sub spawn {
+  my $coderef = shift;
+
+  unless (@_ == 0 && $coderef && ref($coderef) eq 'CODE') {
+    confess "usage: spawn CODEREF";
+  }
+  my $pid; 
+  if (!defined($pid = fork)) {
+    logmsg ("notice", "fork failed: $!");
+    return;
+  } elsif ($pid) {
+    logmsg ("notice", "Request $pid");
+    return; # Parent
+  }
+
+# do not use fdup as in the original example
+# open (STDIN, "<&Client") or die "Can't dup client to stdin";
+# open (STDOUT, ">&Client") or die "Can't dup client to stdout";
+# STDOUT->autoflush();
+  exit &$coderef();
+}
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/rt_lib	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,1 @@
+../../../linux/kernel_space/rt_lib-3.0.1-push
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/tmp/_msr_io.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,420 @@
+/**************************************************************************************************
+*
+*                          msr_io.c
+*
+*           Verwaltung der IO-Karten
+*           
+*           
+*           Autor: Wilhelm Hagemeister
+*
+*           (C) Copyright IgH 2002
+*           Ingenieurgemeinschaft IgH
+*           Heinz-Bäcker Str. 34
+*           D-45356 Essen
+*           Tel.: +49 201/61 99 31
+*           Fax.: +49 201/61 98 36
+*           E-mail: sp@igh-essen.com
+*
+*
+*           $RCSfile: msr_io.c,v $
+*           $Revision: 1.9 $
+*           $Author: ha $
+*           $Date: 2005/06/24 20:06:56 $
+*           $State: Exp $
+*
+*
+*           $Log: msr_io.c,v $
+*           Revision 1.9  2005/06/24 20:06:56  ha
+*           *** empty log message ***
+*
+*           Revision 1.8  2005/06/24 17:39:05  ha
+*           *** empty log message ***
+*
+*
+*
+*
+*
+*
+**************************************************************************************************/
+
+
+/*--includes-------------------------------------------------------------------------------------*/
+
+#ifndef __KERNEL__
+#  define __KERNEL__
+#endif
+#ifndef MODULE
+#  define MODULE
+#endif
+
+#include <linux/delay.h> 	/* mdelay() */
+#include <linux/spinlock.h> 
+#include <linux/param.h>	/* HZ */
+#include <linux/sched.h> 	/* jiffies */
+#include <linux/fs.h>     /* everything... */
+#include <rtai_fifos.h>
+
+#include "msr_io.h"
+
+#include <msr_messages.h>
+
+
+#include "aim_globals.h"
+
+spinlock_t data_lock = SPIN_LOCK_UNLOCKED;
+
+#include "cif-rtai-io.h"
+
+/*--defines--------------------------------------------------------------------------------------*/
+
+
+/*--external functions---------------------------------------------------------------------------*/
+
+
+/*--external data--------------------------------------------------------------------------------*/
+
+
+/*--public data----------------------------------------------------------------------------------*/
+
+#define PB_CARDS 4
+struct {
+	unsigned int fd;
+	unsigned int timestamp;
+	unsigned int fault;
+	unsigned int active;
+	void *in_buf;
+	void *out_buf;
+	size_t in_buf_len;
+	size_t out_buf_len;
+
+	unsigned int reset_timeout;
+} card[PB_CARDS];
+
+
+/*
+***************************************************************************************************
+*
+* Function: msr_io_init
+*
+* Beschreibung: Initialisieren der I/O-Karten
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+***************************************************************************************************
+*/
+void x_PB_io(unsigned long card_no) {
+	int rv = 0;
+	unsigned int flags;
+
+	spin_lock_irqsave(&data_lock, flags);
+
+	switch (card_no) {
+	case 0:
+		rv = cif_exchange_io(card[0].fd,card[0].in_buf,card[0].out_buf);
+		if (!rv)
+			card[0].timestamp = jiffies;
+		break;
+	case 1:
+		rv = cif_exchange_io(card[1].fd,card[1].in_buf,card[1].out_buf);
+//		rv = cif_read_io(card[1].fd,card[1].in_buf);
+//		IMO.to_dSPACE.P101.HX_Stat = 51;
+//		IMO.from_dSPACE.P101.HX_Control |= IMO.to_dSPACE.P101.HX_Stat<<4;
+//		rv += cif_write_io(card[1].fd,card[1].out_buf);
+		if (!rv)
+			card[1].timestamp = jiffies;
+		break;
+	/*
+	case 2:
+		rv = cif_exchange_io(card[2].fd,&cif_in.P201,&cif_out.P201);
+		break;
+	*/
+	case 3:
+		rv = cif_exchange_io(card[3].fd,card[3].in_buf,card[3].out_buf);
+		if (!rv)
+			card[3].timestamp = jiffies;
+		break;
+	}
+
+	if (rv) {
+			msr_print_error("Error during exchange_io %i %i", 
+					card_no, rv );
+	}
+
+	spin_unlock_irqrestore(&data_lock, flags);
+
+}
+
+int msr_io_init()
+{   
+    int rv;
+
+    memset(card, 0, sizeof(card));
+
+#define FIFO_BUF 10000
+
+    if ((rv = rtf_create(0, FIFO_BUF)) < 0) {
+	    msr_print_error("Could not open FIFO %i", rv);
+	    return -1;
+    }
+
+#ifndef _SIMULATION
+/*
+    card[0].in_buf_len = sizeof(IMO.from_dSPACE);
+    card[0].out_buf_len = sizeof(IMO.to_dSPACE);
+    card[0].in_buf = &IMO.from_dSPACE;
+    card[0].out_buf = &IMO.to_dSPACE;
+    card[0].active = 1;
+    if (!(card[0].fd = cif_open_card(0, card[0].in_buf_len,
+				    card[0].out_buf_len, x_PB_io, 0))) {
+	msr_print_error("Cannot open CIF card PB01");
+	return -1;
+    }
+ 
+
+    card[1].in_buf_len = sizeof(IMO.to_dSPACE.P101);
+    card[1].out_buf_len = sizeof(IMO.from_dSPACE.P101);
+    card[1].in_buf = &IMO.to_dSPACE.P101;
+    card[1].out_buf = &IMO.from_dSPACE.P101;
+    card[1].active = 1;
+    if (!(card[1].fd = cif_open_card(1, card[1].in_buf_len, 
+				    card[1].out_buf_len, x_PB_io, 1))) {
+	msr_print_error("Cannot open CIF card P101");
+	return -1;
+    }
+ 
+    card[2].in_buf_len = sizeof(IMO.to_dSPACE.P201);
+    card[2].out_buf_len = sizeof(IMO.from_dSPACE.P201);
+    card[2].in_buf = &IMO.to_dSPACE.P201;
+    card[2].out_buf = &IMO.from_dSPACE.P201;
+    if (!(card[2].fd = cif_open_card(2, card[2].in_buf_len, 
+				    card[2].out_buf_len, x_PB_io, 2))) {
+	msr_print_error("Cannot open CIF card P201");
+	return -1;
+    }
+ 
+*/
+    card[3].in_buf_len = sizeof(dSPACE.in);
+    card[3].out_buf_len = sizeof(dSPACE.out);
+    card[3].in_buf = &dSPACE.in;
+    card[3].out_buf = &dSPACE.out;
+    card[3].active = 1;
+    if (!(card[3].fd = cif_open_card(0,  card[3].in_buf_len, 
+				    card[3].out_buf_len, x_PB_io,3))) {
+	msr_print_error("Cannot open CIF card P301");
+	return -1;
+    }
+ 
+    //msr_reg_chk_failure(&int_cif_io_fail,TINT,T_CHK_HIGH,0,T_CRIT,"CIF Card was not ready to exchange data");
+
+
+#endif
+
+    return 0;
+}
+
+/*
+***************************************************************************************************
+*
+* Function: msr_io_register
+*
+* Beschreibung: Rohdaten als Kanaele registrieren
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+***************************************************************************************************
+*/
+
+int msr_io_register()
+{
+
+#ifndef _SIMULATION
+
+#endif
+
+    return 0;
+}
+
+
+/*
+***************************************************************************************************
+*
+* Function: msr_io_write
+*
+* Beschreibung: Schreiben der Werte
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+***************************************************************************************************
+*/
+int msr_io_write()
+{
+    static int return_value = 0;
+    int rv;
+    int i = 0;
+    unsigned int flags;
+    unsigned int com_check_timestamp = 0;
+    static int COM_Up = 1;
+
+    if (jiffies - com_check_timestamp > HZ/20) {
+
+	    if ( rtf_put_if(0,&IMO,sizeof(IMO)) != sizeof(IMO)) {
+		    //msr_print_error("Could not output data");
+	    }
+
+	    com_check_timestamp = jiffies;
+
+	    spin_lock_irqsave(&data_lock, flags);
+	    for ( i=0; i < PB_CARDS; i++) {
+		    // Ignore inactive and cards that already have a fault
+		    if (!card[i].active || card[i].fault)
+			    continue;
+
+		    // For active cards, check timestamp value. Mark card
+		    // as faulty if there was no data exchange in the last
+		    // 50ms
+		    if (jiffies - card[i].timestamp > HZ/20) {
+			    COM_Up = 0;
+			    card[i].fault = 1;
+			    card[i].reset_timeout = jiffies;
+			    msr_print_error("Card %i timed out", i);
+		    }
+
+	    }
+    
+	    spin_unlock_irqrestore(&data_lock, flags);
+    
+	    for ( i = 0; i < PB_CARDS; i++ ) {
+		    if (!card[i].active || (card[i].active && !card[i].fault))
+			    continue;
+
+		    switch (card[i].fault) {
+		    case 1:
+			    rv = cif_write_io(card[i].fd,card[i].out_buf);
+
+			    if (!rv) {
+				    msr_print_error("Card %i online", i);
+				    card[i].fault = 0;
+				    card[i].timestamp = jiffies;
+				    break;
+			    }
+
+			    msr_print_error("rv of cif_write_io(%i) = %i", 
+					    i, rv);
+
+			    card[i].fault = 2;
+			    cif_set_host_state(card[i].fd,0);
+			    card[i].reset_timeout = jiffies;
+
+		    case 2:
+			    if (cif_card_ready(card[i].fd)) {
+				    cif_set_host_state(card[i].fd,1);
+				    card[i].fault = 0;
+				    break;
+			    }
+			    if (jiffies < card[i].reset_timeout)
+				    break;
+
+			    rv = cif_reset_card(card[i].fd,10,1);
+			    msr_print_error("rv of cif_reset_card(%i) = %i", 
+					    i, rv);
+
+			    // Reset again in 10 seconds
+			    card[i].reset_timeout += 10*HZ;
+		    }
+	    }
+    }
+
+    if (COM_Up)
+	    IMO.to_dSPACE.Status = IMO.from_dSPACE.WatchDog;
+
+//    if (return_value)
+//	int_cif_io_fail = 1;
+
+    return return_value;
+}
+
+/*
+***************************************************************************************************
+*
+* Function: msr_io_read
+*
+* Beschreibung: Lesen der Werte
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+***************************************************************************************************
+*/
+int msr_io_read()
+{
+    int return_value = 0;
+
+#ifndef _SIMULATION
+
+    int_cif_io_fail = 0;
+    /*
+    return_value = cif_exchange_io(fd_PB01,
+		    &cif_out,&cif_in,
+		    sizeof(cif_out),sizeof(cif_in)
+		    );
+		    */
+/*     if (return_value) */
+/* 	int_cif_io_fail = 1; */
+//    printk("%i\n", return_value);
+
+#endif
+    return return_value;
+}
+
+
+/*
+***************************************************************************************************
+*
+* Function: msr_io_cleanup
+*
+* Beschreibung: Aufräumen
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+***************************************************************************************************
+*/
+void msr_io_cleanup()
+{
+/*
+    cif_set_host_state(card[0].fd,0);
+    cif_close_card(card[0].fd);
+
+    cif_set_host_state(card[1].fd,0);
+    cif_close_card(card[1].fd);
+
+    cif_set_host_state(card[2].fd,0);
+    cif_close_card(card[2].fd);
+
+
+*/
+    cif_set_host_state(card[3].fd,0);
+    cif_close_card(card[3].fd);
+
+    rtf_destroy(0);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/tmp/_msr_io.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,236 @@
+/**************************************************************************************************
+*
+*                          msr_io.h
+*
+*           Verwaltung der IO-Karten
+
+*           
+*           Autor: Wilhelm Hagemeister
+*
+*           (C) Copyright IgH 2002
+*           Ingenieurgemeinschaft IgH
+*           Heinz-Bäcker Str. 34
+*           D-45356 Essen
+*           Tel.: +49 201/61 99 31
+*           Fax.: +49 201/61 98 36
+*           E-mail: sp@igh-essen.com
+*
+*
+*           $RCSfile: msr_io.h,v $
+*           $Revision: 1.5 $
+*           $Author: ha $
+*           $Date: 2005/06/24 20:08:15 $
+*           $State: Exp $
+*
+*
+*           $Log: msr_io.h,v $
+*           Revision 1.5  2005/06/24 20:08:15  ha
+*           *** empty log message ***
+*
+*           Revision 1.4  2005/06/24 17:39:05  ha
+*           *** empty log message ***
+*
+*           Revision 1.3  2005/02/28 17:11:48  hm
+*           *** empty log message ***
+*
+*           Revision 1.1  2005/02/10 16:34:24  hm
+*           Initial revision
+*
+*           Revision 1.4  2004/12/21 22:03:54  hm
+*           *** empty log message ***
+*
+*           Revision 1.3  2004/12/16 15:44:01  hm
+*           *** empty log message ***
+*
+*           Revision 1.2  2004/12/01 17:07:49  hm
+*           *** empty log message ***
+*
+*           Revision 1.1  2004/11/26 15:14:21  hm
+*           Initial revision
+*
+*           Revision 1.1  2004/11/01 11:05:20  hm
+*           Initial revision
+*
+*           Revision 1.1  2004/10/21 12:09:23  hm
+*           Initial revision
+*
+*           Revision 1.3  2004/09/21 18:10:58  hm
+*           *** empty log message ***
+*
+*           Revision 1.2  2004/07/22 17:28:02  hm
+*           *** empty log message ***
+*
+*           Revision 1.1  2004/06/21 08:46:52  hm
+*           Initial revision
+*
+*           Revision 1.4  2004/06/02 20:38:42  hm
+*           *** empty log message ***
+*
+*           Revision 1.3  2004/06/02 20:38:18  hm
+*           *** empty log message ***
+*
+*           Revision 1.2  2004/06/02 12:15:17  hm
+*           *** empty log message ***
+*
+*           Revision 1.5  2003/02/20 17:33:37  hm
+*           *** empty log message ***
+*
+*           Revision 1.4  2003/02/14 18:17:28  hm
+*           *** empty log message ***
+*
+*           Revision 1.3  2003/02/13 17:11:12  hm
+*           *** empty log message ***
+*
+*           Revision 1.2  2003/01/30 15:05:58  hm
+*           *** empty log message ***
+*
+*           Revision 1.1  2003/01/24 20:40:09  hm
+*           Initial revision
+*
+*           Revision 1.1  2003/01/22 15:55:40  hm
+*           Initial revision
+*
+*           Revision 1.1  2002/08/13 16:26:27  hm
+*           Initial revision
+*
+*           Revision 1.4  2002/07/04 13:34:27  sp
+*           *** empty log message ***
+*
+*           Revision 1.3  2002/07/04 12:08:34  sp
+*           *** empty log message ***
+*
+*           Revision 1.2  2002/07/04 08:44:19  sp
+*           Änderung des Autors :) und des Datums
+*
+*           Revision 1.1  2002/07/04 08:25:26  sp
+*           Initial revision
+*
+*
+*
+*
+*
+*
+*
+**************************************************************************************************/
+
+/*--Schutz vor mehrfachem includieren------------------------------------------------------------*/
+
+#ifndef _MSR_IO_H_
+#define _MSR_IO_H_
+
+/*--includes-------------------------------------------------------------------------------------*/
+
+//#include "msr_control.h"
+
+/*--defines--------------------------------------------------------------------------------------*/
+
+
+struct cif_in_t {			/* Von Feld nach dSPACE */
+	uint8_t CIM_stat;
+	uint8_t P101[91];
+	uint8_t P201[72];
+	uint8_t P301[72];
+} __attribute__ ((packed));
+
+struct cif_out_t {			/* Von dSPACE zum Feld */
+	uint8_t WatchDog;
+	uint8_t P101[39];
+	uint8_t P201[32];
+	uint8_t P301[32];
+} __attribute__ ((packed));
+
+/*--external functions---------------------------------------------------------------------------*/
+
+/*--external data--------------------------------------------------------------------------------*/
+
+/*--public data----------------------------------------------------------------------------------*/
+
+/*
+***************************************************************************************************
+*
+* Function: msr_io_init
+*
+* Beschreibung: Initialisieren der I/O-Karten
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+***************************************************************************************************
+*/
+int msr_io_init();
+
+/*
+***************************************************************************************************
+*
+* Function: msr_io_register
+*
+* Beschreibung: Kanaele oder Parameter registrieren
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+***************************************************************************************************
+*/
+
+int msr_io_register();
+
+/*
+***************************************************************************************************
+*
+* Function: msr_io_write
+*
+* Beschreibung: Schreiben der Werte
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+***************************************************************************************************
+*/
+int msr_io_write();
+
+/*
+***************************************************************************************************
+*
+* Function: msr_io_write
+*
+* Beschreibung: Lesen der Werte
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+***************************************************************************************************
+*/
+int msr_io_read();
+
+/*
+***************************************************************************************************
+*
+* Function: msr_io_cleanup
+*
+* Beschreibung: Aufräumen
+*
+* Parameter:
+*
+* Rückgabe: 
+*               
+* Status: exp
+*
+***************************************************************************************************
+*/
+void msr_io_cleanup();
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/user/Makefile	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,64 @@
+#----------------------------------------------------------------
+#
+#  M a k e f i l e
+#
+#  $LastChangedDate$
+#  $Author$
+#
+#----------------------------------------------------------------
+
+LIBNET_DIR = ../../soft/libnet-install
+LIBPCAP_DIR = ../../soft/libpcap-install
+FLTK_DIR = ../../soft/fltk-2.0-install
+
+CC = g++
+CFLAGS = -Wall -g -I$(LIBNET_DIR)/include -I$(LIBPCAP_DIR)/include \
+	`$(FLTK_DIR)/bin/fltk-config --cflags`
+
+TEST_EXE = ethercat-test
+TEST_OBJ = main.o ec_master.o ec_command.o ec_slave.o
+TEST_LDFLAGS = -L$(LIBNET_DIR)/lib -lnet -lpcap -lpthread
+
+GUI_EXE = ethercat-gui
+GUI_OBJ = main_gui.o ec_master.o ec_command.o ec_slave.o
+GUI_LDFLAGS = -L$(LIBNET_DIR)/lib -lnet -lpcap -lpthread `$(FLTK_DIR)/bin/fltk-config --ldflags`
+
+#----------------------------------------------------------------
+
+first: $(TEST_EXE) $(GUI_EXE)
+
+$(TEST_EXE): $(TEST_OBJ)
+	$(CC) $(TEST_OBJ) $(TEST_LDFLAGS) -o $@
+
+$(GUI_EXE): $(GUI_OBJ)
+	$(CC) $(GUI_OBJ) $(GUI_LDFLAGS) -o $@
+
+.c.o:
+	$(CC) $(CFLAGS) -c $< -o $@
+
+.cpp.o:
+	$(CC) $(CFLAGS) -c $< -o $@
+
+#----------------------------------------------------------------
+
+main.o: main.c \
+	ec_globals.h ec_master.h ec_command.h ec_slave.h
+
+main_gui.o: main_gui.cpp \
+	ec_globals.h ec_master.h ec_command.h ec_slave.h
+
+ec_command.o: ec_command.c ec_command.h
+
+ec_master.o: ec_master.c ec_master.h \
+	ec_globals.h ec_command.h ec_slave.h
+
+ec_slave.o: ec_slave.c ec_slave.h \
+	ec_globals.h
+
+#----------------------------------------------------------------
+
+clean:
+	rm -f *.o $(TEST_EXE) $(GUI_EXE) *~
+
+#----------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/user/ec_command.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,61 @@
+//---------------------------------------------------------------
+//
+//  e c _ c o m m a n d . c
+//
+//  $LastChangedDate$
+//  $Author$
+//
+//---------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ec_command.h"
+
+//---------------------------------------------------------------
+
+void EtherCAT_command_init(EtherCAT_command_t *cmd)
+{
+  cmd->command_type = 0x00;
+  cmd->node_address = 0x0000;
+  cmd->ring_position = 0x0000;
+  cmd->mem_address = 0x0000;
+  cmd->logical_address = 0x00000000;
+  cmd->data_length = 0;
+  cmd->status = Waiting;
+  cmd->next = NULL;
+  cmd->working_counter = 0;
+  cmd->data = NULL;
+}
+
+//---------------------------------------------------------------
+
+void EtherCAT_command_clear(EtherCAT_command_t *cmd)
+{
+  if (cmd->data)
+  {
+    free(cmd->data);
+  }
+
+  EtherCAT_command_init(cmd);
+}
+
+//---------------------------------------------------------------
+
+void EtherCAT_command_print_data(EtherCAT_command_t *cmd)
+{
+  unsigned int i;
+
+  printf("[");
+
+  for (i = 0; i < cmd->data_length; i++)
+  {
+    printf("%02X", cmd->data[i]);
+
+    if (i < cmd->data_length - 1) printf(" ");
+  }
+
+  printf("]\n");
+}
+
+//---------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/user/ec_command.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,42 @@
+//---------------------------------------------------------------
+//
+//  e c _ c o m m a n d . h
+//
+//  $LastChangedDate$
+//  $Author$
+//
+//---------------------------------------------------------------
+
+typedef enum {Waiting, Sent, Received} EtherCAT_cmd_status_t;
+
+//---------------------------------------------------------------
+
+typedef struct EtherCAT_command
+{
+  unsigned char command_type;
+  short ring_position;
+  unsigned short node_address;
+  unsigned short mem_address;
+  unsigned int logical_address;
+  unsigned int data_length;
+
+  struct EtherCAT_command *next;
+
+  EtherCAT_cmd_status_t status;
+  unsigned char command_index;
+  unsigned int working_counter;
+
+  unsigned char *data;
+  
+}
+EtherCAT_command_t;
+
+//---------------------------------------------------------------
+
+void EtherCAT_command_init(EtherCAT_command_t *);
+void EtherCAT_command_clear(EtherCAT_command_t *);
+
+// Debug
+void EtherCAT_command_print_data(EtherCAT_command_t *);
+
+//---------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/user/ec_globals.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,26 @@
+//---------------------------------------------------------------
+//
+//  e c _ g l o b a l s . h
+//
+//  $LastChangedDate$
+//  $Author$
+//
+//---------------------------------------------------------------
+
+#define EC_CMD_APRD 0x01 // Auto-increment physical read
+#define EC_CMD_APWR 0x02 // Auto-increment physical write
+#define EC_CMD_NPRD 0x04 // Node-addressed physical read
+#define EC_CMD_NPWR 0x05 // Node-addressed physical write
+#define EC_CMD_BRD  0x07 // Broadcast read
+#define EC_CMD_BWR  0x08 // Broadcast write
+#define EC_CMD_LRW  0x0C // Logical read/write
+
+#define EC_STATE_UNKNOWN 0x00
+#define EC_STATE_INIT    0x01
+#define EC_STATE_PREOP   0x02
+#define EC_STATE_SAVEOP  0x04
+#define EC_STATE_OP      0x08
+
+#define EC_ACK_STATE 0x10
+
+//---------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/user/ec_master.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,1407 @@
+//---------------------------------------------------------------
+//
+//  e c _ m a s t e r . c
+//
+//  $LastChangedDate$
+//  $Author$
+//
+//---------------------------------------------------------------
+
+#include "ec_globals.h"
+#include "ec_master.h"
+
+#define DEBUG_SEND_RECEIVE
+
+//---------------------------------------------------------------
+
+int EtherCAT_master_init(EtherCAT_master_t *master,
+                         char *eth_dev)
+{
+  char errbuf_libpcap[PCAP_ERRBUF_SIZE];
+  char errbuf_libnet[LIBNET_ERRBUF_SIZE];
+
+  master->slaves = NULL;
+  master->slave_count = 0;
+
+  master->first_command = NULL;
+  master->command_index = 0x00;
+
+  master->process_data = NULL;
+  master->pre_cb = NULL;
+  master->post_cb = NULL;
+  master->thread_continue = 0;
+  master->cycle_time = 0;
+  
+  // Init Libpcap
+  master->pcap_handle = pcap_open_live(eth_dev, BUFSIZ, 1, 0, errbuf_libpcap);
+
+  if (master->pcap_handle == NULL)
+  {
+    fprintf(stderr, "Couldn't open device %s: %s\n", eth_dev, errbuf_libpcap);
+    return 1;
+  }
+
+  // Init Libnet
+  if (!(master->net_handle = libnet_init(LIBNET_LINK, eth_dev, errbuf_libnet)))
+  {
+    fprintf(stderr, "Could not init %s: %s!\n", eth_dev, errbuf_libnet);
+
+    pcap_close(master->pcap_handle);
+
+    return 1;
+  }
+
+  return 0;
+}
+
+//---------------------------------------------------------------
+
+void EtherCAT_master_clear(EtherCAT_master_t *master)
+{
+  libnet_destroy(master->net_handle);
+  pcap_close(master->pcap_handle);
+
+  // Remove all pending commands
+  while (master->first_command)
+  {
+    EtherCAT_remove_command(master, master->first_command);
+  }
+
+  // Remove all slaves
+  EtherCAT_clear_slaves(master);
+}
+
+//---------------------------------------------------------------
+
+int EtherCAT_check_slaves(EtherCAT_master_t *master,
+                          EtherCAT_slave_t *slaves,
+                          unsigned int slave_count)
+{
+  EtherCAT_command_t *cmd;
+  EtherCAT_slave_t *cur;
+  unsigned int i, j, found;
+  unsigned char data[2];
+
+  // EtherCAT_clear_slaves() must be called before!
+  if (master->slave_count) return -1;
+
+  // Determine number of slaves
+
+  if ((cmd = EtherCAT_broadcast_read(master, 0x0000, 4)) == NULL)
+  {
+    return -1;
+  }
+  
+  if (EtherCAT_send_receive(master) != 0)
+  {
+    return -1;
+  }
+
+  master->slave_count = cmd->working_counter;
+
+  EtherCAT_remove_command(master, cmd);
+
+  if (master->slave_count < slave_count)
+  {
+    fprintf(stderr, "ERROR: Too few slaves on EtherCAT bus!\n");
+    return -1;
+  }
+
+  // No slaves. Stop further processing...
+  if (master->slave_count == 0) return 0;
+
+   // For every slave in the list
+  for (i = 0; i < master->slave_count; i++)
+  {
+    cur = &slaves[i];
+
+    if (!cur->desc)
+    {
+      fprintf(stderr, "ERROR: Slave has no description (list position %i)!\n", i);
+      return -1;
+    }
+
+    // Set ring position
+    cur->ring_position = -i;
+    cur->station_address = i + 1;
+
+    // Write station address
+    
+    data[0] = cur->station_address & 0x00FF;
+    data[1] = (cur->station_address & 0xFF00) >> 8;
+
+    if ((cmd = EtherCAT_position_write(master, cur->ring_position, 0x0010, 2, data)) == NULL)
+    {
+      master->slave_count = 0;
+      fprintf(stderr, "ERROR: Could not create command!\n");
+      return -1;
+    }
+    
+    if (EtherCAT_send_receive(master) != 0)
+    {
+      master->slave_count = 0;
+      fprintf(stderr, "ERROR: Could not send command!\n");
+      return -1;
+    }
+    
+    if (cmd->working_counter != 1)
+    {
+      master->slave_count = 0;
+      fprintf(stderr, "ERROR: Slave %i did not repond while writing station address!\n", i);
+      return -1;
+    }
+    
+    EtherCAT_remove_command(master, cmd);
+
+    // Read base data
+
+    if ((cmd = EtherCAT_read(master, cur->station_address, 0x0000, 4)) == NULL)
+    {
+      master->slave_count = 0;
+      fprintf(stderr, "ERROR: Could not create command!\n");
+      return -1;
+    }
+
+    if (EtherCAT_send_receive(master) != 0)
+    {
+      EtherCAT_remove_command(master, cmd);
+      master->slave_count = 0;
+      fprintf(stderr, "ERROR: Could not send command!\n");
+      return -4;
+    }
+
+    if (cmd->working_counter != 1)
+    {
+      EtherCAT_remove_command(master, cmd);
+      master->slave_count = 0;
+      fprintf(stderr, "ERROR: Slave %i did not respond while reading base data!\n", i);
+      return -5;
+    }
+
+    // Get base data
+    cur->type = cmd->data[0];
+    cur->revision = cmd->data[1];
+    cur->build = cmd->data[2] | (cmd->data[3] << 8);
+
+    EtherCAT_remove_command(master, cmd);
+
+    // Read identification from "Slave Information Interface" (SII)
+
+    if (EtherCAT_read_slave_information(master, cur->station_address, 0x0008, &cur->vendor_id) != 0)
+    {
+      master->slave_count = 0;
+      fprintf(stderr, "ERROR: Could not read SII!\n", i);
+      return -1;
+    }
+
+    if (EtherCAT_read_slave_information(master, cur->station_address, 0x000A, &cur->product_code) != 0)
+    {
+      master->slave_count = 0;
+      fprintf(stderr, "ERROR: Could not read SII!\n", i);
+      return -1;
+    }
+
+    if (EtherCAT_read_slave_information(master, cur->station_address, 0x000E, &cur->revision_number) != 0)
+    {
+      master->slave_count = 0;
+      fprintf(stderr, "ERROR: Could not read SII!\n", i);
+      return -1;
+    }
+
+    // Search for identification in "database"
+
+    found = 0;
+
+    for (j = 0; j < slave_idents_count; j++)
+    {
+      if (slave_idents[j].vendor_id == cur->vendor_id
+          && slave_idents[j].product_code == cur->product_code)
+      {
+        found = 1;
+
+        if (cur->desc != slave_idents[j].desc)
+        {
+          fprintf(stderr, "ERROR: Unexpected slave device at position %i:"
+                  "%s %s. Expected: %s %s\n",
+                  i, slave_idents[j].desc->vendor_name, slave_idents[j].desc->product_name,
+                  cur->desc->vendor_name, cur->desc->product_name);
+          return -1;
+        }
+
+        break;
+      }
+    }
+
+    if (!found)
+    {
+      fprintf(stderr, "ERROR: Unknown slave device at position %i: Vendor %X, Code %X",
+              i, cur->vendor_id, cur->product_code);
+      return -1;      
+    }
+  }
+
+  return 0;
+}
+
+//---------------------------------------------------------------
+
+void EtherCAT_clear_slaves(EtherCAT_master_t *master)
+{
+  unsigned int i;
+
+  if (master->slave_count == 0) return;
+
+  for (i = 0; i < master->slave_count; i++)
+  {
+    EtherCAT_slave_clear(&master->slaves[i]);
+  }
+
+  free(master->slaves);
+  master->slaves = NULL;
+}
+
+//---------------------------------------------------------------
+
+int EtherCAT_read_slave_information(EtherCAT_master_t *master,
+                                    unsigned short int node_address,
+                                    unsigned short int offset,
+                                    unsigned int *target)
+{
+  EtherCAT_command_t *cmd;
+  unsigned char data[10];
+  unsigned int tries;
+
+  // Initiate read operation
+
+  data[0] = 0x00;
+  data[1] = 0x01;
+  data[2] = offset & 0xFF;
+  data[3] = (offset & 0xFF00) >> 8;
+  data[4] = 0x00;
+  data[5] = 0x00;
+
+  if ((cmd = EtherCAT_write(master, node_address, 0x502, 6, data)) == NULL)
+  {
+    fprintf(stderr, "ERROR: Could not allocate command!\n");
+    return -2;
+  }
+
+  if (EtherCAT_send_receive(master) != 0)
+  {
+    EtherCAT_remove_command(master, cmd);
+    fprintf(stderr, "ERROR: Could not write to slave!\n");
+    return -3;
+  }
+
+  if (cmd->working_counter != 1)
+  {
+    EtherCAT_remove_command(master, cmd);
+    fprintf(stderr, "ERROR: Command not processed by slave!\n");
+    return -4;
+  }
+
+  EtherCAT_remove_command(master, cmd);
+
+  // Get status of read operation
+
+  tries = 0;
+  while (tries < 10)
+  {
+    if ((cmd = EtherCAT_read(master, node_address, 0x502, 10)) == NULL)
+    {
+      fprintf(stderr, "ERROR: Could not allocate command!\n");
+      return -2;
+    }
+    
+    if (EtherCAT_send_receive(master) != 0)
+    {
+      EtherCAT_remove_command(master, cmd);
+
+      fprintf(stderr, "ERROR: Could not read from slave!\n");
+      return -3;
+    }
+    
+    if (cmd->working_counter != 1)
+    {
+      EtherCAT_remove_command(master, cmd);
+
+      fprintf(stderr, "ERROR: Command not processed by slave!\n");
+      return -4;
+    }
+
+    if ((cmd->data[1] & 0x81) == 0)
+    {
+#if 0
+      printf("SLI status data: %02X %02X Address: %02X %02X\n", cmd->data[0], cmd->data[1], cmd->data[2], cmd->data[3]);
+      printf("Data: %02X %02X %02X %02X\n", cmd->data[6], cmd->data[7], cmd->data[8], cmd->data[9]);
+#endif
+
+      memcpy(target, cmd->data + 6, 4);
+
+      EtherCAT_remove_command(master, cmd);
+
+      break;
+    }
+    
+    EtherCAT_remove_command(master, cmd);
+
+    tries++;
+  }
+
+  if (tries == 10) fprintf(stderr, "ERROR: Timeout while reading SII!\n");
+
+  return 0;
+}
+
+//---------------------------------------------------------------
+
+int EtherCAT_send_receive(EtherCAT_master_t *master)
+{
+  libnet_ptag_t ptag;
+  struct pcap_pkthdr header;
+  const unsigned char *packet;
+  unsigned char dst[6], src[6];
+  unsigned int i, length, framelength, pos, command_type, command_index;
+  EtherCAT_command_t *cmd;
+  unsigned char *data;
+  int bytes, command_follows, found;
+
+#ifdef DEBUG_SEND_RECEIVE
+  found = 0;
+#endif
+
+  length = 0;
+  for (cmd = master->first_command; cmd != NULL; cmd = cmd->next)
+  {
+    //if (cmd->status != Waiting) continue;
+    length += cmd->data_length + 12;
+
+#ifdef DEBUG_SEND_RECEIVE
+    found++;
+#endif
+  }
+
+#ifdef DEBUG_SEND_RECEIVE
+  printf("Sending %i commands with length %i...\n", found, length);
+#endif
+
+  if (length == 0) return 0;
+
+  framelength = length + 2;
+  if (framelength < 46) framelength = 46;
+
+  data = (unsigned char *) malloc(sizeof(unsigned char) * framelength);
+  if (!data) return -1;
+
+  data[0] = length & 0xFF;
+  data[1] = ((length & 0x700) >> 8) | 0x10;
+  pos = 2;
+
+  for (cmd = master->first_command; cmd != NULL; cmd = cmd->next)
+  {
+    if (cmd->status != Waiting)
+    {
+      printf("Old command: %02X\n", cmd->command_type);
+      continue;
+    }
+
+    cmd->command_index = master->command_index;
+    master->command_index = (master->command_index + 1) % 0x0100;
+
+    cmd->status = Sent;
+
+    data[pos + 0] = cmd->command_type;
+    data[pos + 1] = cmd->command_index;
+
+    switch (cmd->command_type)
+    {
+      case EC_CMD_APRD:
+      case EC_CMD_APWR:
+        data[pos + 2] = cmd->ring_position & 0xFF;
+        data[pos + 3] = (cmd->ring_position & 0xFF00) >> 8;
+        data[pos + 4] = cmd->mem_address & 0xFF;
+        data[pos + 5] = (cmd->mem_address & 0xFF00) >> 8;
+        break;
+
+      case EC_CMD_NPRD:
+      case EC_CMD_NPWR:
+        data[pos + 2] = cmd->node_address & 0xFF;
+        data[pos + 3] = (cmd->node_address & 0xFF00) >> 8;
+        data[pos + 4] = cmd->mem_address & 0xFF;
+        data[pos + 5] = (cmd->mem_address & 0xFF00) >> 8;
+        break;
+
+      case EC_CMD_BRD:
+      case EC_CMD_BWR:
+        data[pos + 2] = 0x00;
+        data[pos + 3] = 0x00;
+        data[pos + 4] = cmd->mem_address & 0xFF;
+        data[pos + 5] = (cmd->mem_address & 0xFF00) >> 8;
+        break;
+
+      case EC_CMD_LRW:
+        data[pos + 2] = cmd->logical_address & 0x000000FF;
+        data[pos + 3] = (cmd->logical_address & 0x0000FF00) >> 8;
+        data[pos + 4] = (cmd->logical_address & 0x00FF0000) >> 16;
+        data[pos + 5] = (cmd->logical_address & 0xFF000000) >> 24;
+        break;
+
+      default:
+        data[pos + 2] = 0x00;
+        data[pos + 3] = 0x00;
+        data[pos + 4] = 0x00;
+        data[pos + 5] = 0x00;
+        fprintf(stderr, "WARNING: Default adress while frame construction...\n");
+        break;
+    }
+
+    data[pos + 6] = cmd->data_length & 0xFF;
+    data[pos + 7] = (cmd->data_length & 0x700) >> 8;
+
+    if (cmd->next) data[pos + 7] |= 0x80;
+
+    data[pos + 8] = 0x00;
+    data[pos + 9] = 0x00;
+
+    if (cmd->command_type == EC_CMD_APWR
+        || cmd->command_type == EC_CMD_NPWR
+        || cmd->command_type == EC_CMD_BWR
+        || cmd->command_type == EC_CMD_LRW) // Write
+    {
+      for (i = 0; i < cmd->data_length; i++) data[pos + 10 + i] = cmd->data[i];
+    }
+    else // Read
+    {
+      for (i = 0; i < cmd->data_length; i++) data[pos + 10 + i] = 0x00;
+    }
+
+    data[pos + 10 + cmd->data_length] = 0x00;
+    data[pos + 11 + cmd->data_length] = 0x00;
+
+    pos += 12 + cmd->data_length;
+  }
+
+  // Pad with zeros
+  while (pos < 46) data[pos++] = 0x00;
+
+#ifdef DEBUG_SEND_RECEIVE
+  printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+  for (i = 0; i < framelength; i++)
+  {
+    printf("%02X ", data[i]);
+
+    if ((i + 1) % 16 == 0) printf("\n");
+  }
+  printf("\n-----------------------------------------------\n");
+#endif
+ 
+  dst[0] = 0xFF;
+  dst[1] = 0xFF;
+  dst[2] = 0xFF;
+  dst[3] = 0xFF;
+  dst[4] = 0xFF;
+  dst[5] = 0xFF;
+
+  src[0] = 0x00;
+  src[1] = 0x00;
+  src[2] = 0x00;
+  src[3] = 0x00;
+  src[4] = 0x00;
+  src[5] = 0x00;
+
+  // Send frame
+  ptag = libnet_build_ethernet(dst, src, 0x88A4, data, framelength, master->net_handle, 0);
+  bytes = libnet_write(master->net_handle);
+  libnet_clear_packet(master->net_handle);
+
+  if (bytes == -1)
+  {
+    free(data);
+    fprintf(stderr, "Could not write!\n");
+    return -1;
+  }
+
+  packet = pcap_next(master->pcap_handle, &header); // LibPCap receives sent frame first
+  packet = pcap_next(master->pcap_handle, &header);
+
+#ifdef DEBUG_SEND_RECEIVE
+  for (i = 0; i < header.len - 14; i++)
+  {
+    if (packet[i + 14] == data[i]) printf("   ");
+    else printf("%02X ", packet[i + 14]);
+
+    if ((i + 1) % 16 == 0) printf("\n");
+  }
+  printf("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
+#endif
+
+  // Free sent data
+  free(data);
+
+  pos = 16;
+  command_follows = 1;
+  while (command_follows)
+  {
+    command_type = packet[pos];
+    command_index = packet[pos + 1];
+    length = (packet[pos + 6] & 0xFF) | ((packet[pos + 7] & 0x07) << 8);
+    command_follows = packet[pos + 7] & 0x80;
+
+#if 0
+    printf("Command %02X received!\n", command_index);
+#endif
+
+    found = 0;
+
+    for (cmd = master->first_command; cmd != NULL; cmd = cmd->next)
+    {
+      if (cmd->status == Sent
+          && cmd->command_type == command_type
+          && cmd->command_index == command_index
+          && cmd->data_length == length)
+      {
+        found = 1;
+        cmd->status = Received;
+
+        cmd->data = (unsigned char *) malloc(sizeof(unsigned char) * length);
+        memcpy(cmd->data, packet + pos + 10, length);
+
+        cmd->working_counter = (packet[pos + length + 10] & 0xFF)
+          | ((packet[pos + length + 11] & 0xFF) << 8);
+      }
+    }
+
+    if (!found)
+    {
+      fprintf(stderr, "WARNING: Command not assigned!\n");
+    }
+
+    pos += length + 12;
+  }
+
+  for (cmd = master->first_command; cmd != NULL; cmd = cmd->next)
+  {
+    if (cmd->status == Sent)
+    {
+      fprintf(stderr, "WARNING: Command not sent!\n");
+    }
+  }
+      
+  return 0;
+}
+
+//---------------------------------------------------------------
+
+EtherCAT_command_t *EtherCAT_read(EtherCAT_master_t *master,
+                                  unsigned short node_address,
+                                  unsigned short offset,
+                                  unsigned int length)
+{
+  EtherCAT_command_t *cmd;
+
+  if (node_address == 0x0000) fprintf(stderr, "WARNING: Using node address 0x0000!\n");
+
+  cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t));
+
+  if (cmd == NULL)
+  {
+    return NULL;
+  }
+
+  EtherCAT_command_init(cmd);
+
+  cmd->command_type = EC_CMD_NPRD;
+  cmd->node_address = node_address;
+  cmd->mem_address = offset;
+  cmd->data_length = length;
+
+  // Add command to master's list
+  add_command(master, cmd);
+
+  return cmd;
+}
+
+//---------------------------------------------------------------
+
+EtherCAT_command_t *EtherCAT_write(EtherCAT_master_t *master,
+                                   unsigned short node_address,
+                                   unsigned short offset,
+                                   unsigned int length,
+                                   const unsigned char *data)
+{
+  EtherCAT_command_t *cmd;
+
+  if (node_address == 0x0000) fprintf(stderr, "WARNING: Using node address 0x0000!\n");
+
+  cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t));
+
+  if (cmd == NULL)
+  {
+    return NULL;
+  }
+
+  EtherCAT_command_init(cmd);
+
+  cmd->command_type = EC_CMD_NPWR;
+  cmd->node_address = node_address;
+  cmd->mem_address = offset;
+  cmd->data_length = length;
+
+  cmd->data = (unsigned char *) malloc(sizeof(unsigned char) * length);
+
+  if (cmd->data == NULL)
+  {
+    free(cmd);
+    return NULL;
+  }
+
+  memcpy(cmd->data, data, length);
+
+  // Add command to master's list
+  add_command(master, cmd);
+
+  return cmd;
+}
+
+//---------------------------------------------------------------
+
+EtherCAT_command_t *EtherCAT_position_read(EtherCAT_master_t *master,
+                                           short ring_position,
+                                           unsigned short offset,
+                                           unsigned int length)
+{
+  EtherCAT_command_t *cmd;
+
+  cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t));
+
+  if (cmd == NULL)
+  {
+    return NULL;
+  }
+
+  EtherCAT_command_init(cmd);
+
+  cmd->command_type = EC_CMD_APRD;
+  cmd->ring_position = ring_position;
+  cmd->mem_address = offset;
+  cmd->data_length = length;
+
+  // Add command to master's list
+  add_command(master, cmd);
+
+  return cmd;
+}
+
+//---------------------------------------------------------------
+
+EtherCAT_command_t *EtherCAT_position_write(EtherCAT_master_t *master,
+                                            short ring_position,
+                                            unsigned short offset,
+                                            unsigned int length,
+                                            const unsigned char *data)
+{
+  EtherCAT_command_t *cmd;
+
+  cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t));
+
+  if (cmd == NULL)
+  {
+    return NULL;
+  }
+
+  EtherCAT_command_init(cmd);
+
+  cmd->command_type = EC_CMD_APWR;
+  cmd->ring_position = ring_position;
+  cmd->mem_address = offset;
+  cmd->data_length = length;
+
+  cmd->data = (unsigned char *) malloc(sizeof(unsigned char) * length);
+
+  if (cmd->data == NULL)
+  {
+    free(cmd);
+    return NULL;
+  }
+
+  memcpy(cmd->data, data, length);
+
+  // Add command to master's list
+  add_command(master, cmd);
+
+  return cmd;
+}
+
+//---------------------------------------------------------------
+
+EtherCAT_command_t *EtherCAT_broadcast_read(EtherCAT_master_t *master,
+                                            unsigned short offset,
+                                            unsigned int length)
+{
+  EtherCAT_command_t *cmd;
+
+  cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t));
+
+  if (cmd == NULL)
+  {
+    return NULL;
+  }
+
+  EtherCAT_command_init(cmd);
+
+  cmd->command_type = EC_CMD_BRD;
+  cmd->mem_address = offset;
+  cmd->data_length = length;
+
+  // Add command to master's list
+  add_command(master, cmd);
+
+  return cmd;
+}
+
+//---------------------------------------------------------------
+
+EtherCAT_command_t *EtherCAT_broadcast_write(EtherCAT_master_t *master,
+                                             unsigned short offset,
+                                             unsigned int length,
+                                             const unsigned char *data)
+{
+  EtherCAT_command_t *cmd;
+
+  cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t));
+
+  if (cmd == NULL)
+  {
+    return NULL;
+  }
+
+  EtherCAT_command_init(cmd);
+
+  cmd->command_type = EC_CMD_BWR;
+  cmd->mem_address = offset;
+  cmd->data_length = length;
+
+  cmd->data = (unsigned char *) malloc(sizeof(unsigned char) * length);
+
+  if (cmd->data == NULL)
+  {
+    free(cmd);
+    return NULL;
+  }
+
+  memcpy(cmd->data, data, length);
+
+  // Add command to master's list
+  add_command(master, cmd);
+
+  return cmd;
+}
+
+//---------------------------------------------------------------
+
+EtherCAT_command_t *EtherCAT_logical_read_write(EtherCAT_master_t *master,
+                                                unsigned int offset,
+                                                unsigned int length,
+                                                unsigned char *data)
+{
+  EtherCAT_command_t *cmd;
+
+  cmd = (EtherCAT_command_t *) malloc(sizeof(EtherCAT_command_t));
+
+  if (cmd == NULL)
+  {
+    return NULL;
+  }
+
+  EtherCAT_command_init(cmd);
+
+  cmd->command_type = EC_CMD_LRW;
+  cmd->mem_address = offset;
+  cmd->data_length = length;
+
+  cmd->data = (unsigned char *) malloc(sizeof(unsigned char) * length);
+
+  if (cmd->data == NULL)
+  {
+    free(cmd);
+    return NULL;
+  }
+
+  memcpy(cmd->data, data, length);
+
+  // Add command to master's list
+  add_command(master, cmd);
+
+  return cmd;
+}
+
+//---------------------------------------------------------------
+
+void add_command(EtherCAT_master_t *master, EtherCAT_command_t *cmd)
+{
+  EtherCAT_command_t **last_cmd;
+
+  // Find last position in the list
+  last_cmd = &(master->first_command);
+  while (*last_cmd) last_cmd = &(*last_cmd)->next;
+
+  *last_cmd = cmd;
+}
+
+//---------------------------------------------------------------
+
+void EtherCAT_remove_command(EtherCAT_master_t *master,
+                             EtherCAT_command_t *rem_cmd)
+{
+  EtherCAT_command_t **last_cmd;
+
+  last_cmd = &(master->first_command);
+  while (*last_cmd)
+  {
+    if (*last_cmd == rem_cmd)
+    {
+      *last_cmd = rem_cmd->next;
+      EtherCAT_command_clear(rem_cmd);
+
+      return;
+    }
+
+    last_cmd = &(*last_cmd)->next;
+  }
+}
+
+//---------------------------------------------------------------
+
+int EtherCAT_state_change(EtherCAT_master_t *master,
+                          EtherCAT_slave_t *slave,
+                          unsigned char state_and_ack)
+{
+  EtherCAT_command_t *cmd;
+  unsigned char data[2];
+  unsigned int tries_left;
+
+  data[0] = state_and_ack;
+  data[1] = 0x00;
+
+  if ((cmd = EtherCAT_write(master, slave->station_address,
+                            0x0120, 2, data)) == NULL)
+  {
+    return -1;
+  }
+
+  if (EtherCAT_send_receive(master) != 0)
+  {
+    EtherCAT_remove_command(master, cmd);
+    return -2;
+  }
+
+  if (cmd->working_counter != 1)
+  {
+    EtherCAT_remove_command(master, cmd);
+    return -3;
+  }
+
+  EtherCAT_remove_command(master, cmd);
+
+  slave->requested_state = state_and_ack & 0x0F;
+
+  tries_left = 10;
+
+  while (tries_left)
+  {
+    if ((cmd = EtherCAT_read(master, slave->station_address,
+                             0x0130, 2)) == NULL)
+    {
+      return -1;
+    }
+    
+    if (EtherCAT_send_receive(master) != 0)
+    {
+      EtherCAT_remove_command(master, cmd);
+      return -2;
+    }
+    
+    if (cmd->working_counter != 1)
+    {
+      EtherCAT_remove_command(master, cmd);
+      return -3;
+    }
+
+    if (cmd->data[0] & 0x10) // State change error
+    {
+      EtherCAT_remove_command(master, cmd);
+      return -4;
+    }
+
+    if (cmd->data[0] == state_and_ack & 0x0F) // State change successful
+    {
+      EtherCAT_remove_command(master, cmd);
+      break;
+    }
+
+    EtherCAT_remove_command(master, cmd);
+
+    //printf("Trying again...\n");
+
+    tries_left--;
+  }
+
+  if (!tries_left)
+  {
+    return -5;
+  }
+
+  slave->current_state = state_and_ack & 0x0F;
+
+  return 0;
+}
+
+//---------------------------------------------------------------
+
+int EtherCAT_broadcast_state_change(EtherCAT_master_t *master,
+                                    unsigned char state)
+{
+  EtherCAT_command_t *cmd;
+  unsigned char data[2];
+  unsigned int tries_left;
+
+  data[0] = state;
+  data[1] = 0x00;
+
+  if ((cmd = EtherCAT_broadcast_write(master, 0x0120, 2, data)) == NULL)
+  {
+    return -1;
+  }
+
+  if (EtherCAT_send_receive(master) != 0)
+  {
+    EtherCAT_remove_command(master, cmd);
+    return -2;
+  }
+
+  if (cmd->working_counter != master->slave_count)
+  {
+    EtherCAT_remove_command(master, cmd);
+    return -3;
+  }
+
+  EtherCAT_remove_command(master, cmd);
+
+  tries_left = 10;
+
+  while (tries_left)
+  {
+    if ((cmd = EtherCAT_broadcast_read(master, 0x0130, 2)) == NULL)
+    {
+      return -1;
+    }
+    
+    if (EtherCAT_send_receive(master) != 0)
+    {
+      EtherCAT_remove_command(master, cmd);
+      return -2;
+    }
+    
+    if (cmd->working_counter != master->slave_count)
+    {
+      EtherCAT_remove_command(master, cmd);
+      return -3;
+    }
+
+    if (cmd->data[0] & 0x10) // State change error
+    {
+      EtherCAT_remove_command(master, cmd);
+      return -4;
+    }
+
+    if (cmd->data[0] == state) // State change successful
+    {
+      EtherCAT_remove_command(master, cmd);
+      break;
+    }
+
+    EtherCAT_remove_command(master, cmd);
+
+    //printf("Trying again...\n");
+
+    tries_left--;
+  }
+
+  if (!tries_left)
+  {
+    return -5;
+  }
+
+  return 0;
+}
+
+//---------------------------------------------------------------
+
+int EtherCAT_start(EtherCAT_master_t *master,
+                   unsigned int length,
+                   void (*pre_cb)(unsigned char *),
+                   void (*post_cb)(unsigned char *),
+                   unsigned int cycle_time)
+{
+  if (master->process_data)
+  {
+    fprintf(stderr, "ERROR: Process data already allocated!\n");
+    return -1;
+  }
+
+  if ((master->process_data = (unsigned char *) malloc(length)) == NULL)
+  {
+    fprintf(stderr, "ERROR: Could not allocate process data block!\n");
+    return -2;
+  }
+
+  memset(master->process_data, 0x00, length);
+
+  master->process_data_length = length;
+  master->pre_cb = pre_cb;
+  master->post_cb = post_cb;
+  master->cycle_time = cycle_time;
+
+  master->thread_continue = 1;
+
+  if (pthread_create(&master->thread, NULL, thread_function, (void *) master) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not create thread!\n");
+    return -3;
+  }
+
+  return 0;
+}
+
+//---------------------------------------------------------------
+
+int EtherCAT_stop(EtherCAT_master_t *master)
+{
+  if (!master->thread_continue)
+  {
+    fprintf(stderr, "ERROR: Thread not running!\n");
+    return -1;
+  }
+
+  master->thread_continue = 0;
+  pthread_join(master->thread, NULL);
+
+  if (master->process_data)
+  {
+    free(master->process_data);
+    master->process_data = NULL;
+  }
+
+  master->pre_cb = NULL;
+  master->post_cb = NULL;
+
+  return 0;
+}
+
+//---------------------------------------------------------------
+
+double current_timestamp()
+{
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  return tv.tv_sec + (double) tv.tv_usec / 1000000.0;
+}
+
+//---------------------------------------------------------------
+
+void *thread_function(void *data)
+{
+  EtherCAT_master_t *master;
+  EtherCAT_command_t *cmd;
+  double bus_start_time, bus_end_time;
+  double cycle_start_time, cycle_end_time, last_cycle_start_time;
+  unsigned int wait_usecs;
+
+  master = (EtherCAT_master_t *) data;
+
+  last_cycle_start_time = 0.0;
+
+  while (master->thread_continue)
+  {
+    cycle_start_time = current_timestamp();
+
+    if (last_cycle_start_time != 0.0)
+    {
+      master->last_cycle_time = cycle_start_time - last_cycle_start_time;
+      master->last_jitter = (master->last_cycle_time - (master->cycle_time / 1000000.0))
+        / (master->cycle_time / 1000000.0) * 100.0;
+    }
+
+    last_cycle_start_time = cycle_start_time;
+
+    if (master->pre_cb) master->pre_cb(master->process_data);
+
+    cmd = EtherCAT_logical_read_write(master,
+                                      0x00000000,
+                                      master->process_data_length,
+                                      master->process_data);
+
+    bus_start_time = current_timestamp();
+
+    EtherCAT_send_receive(master);
+
+    bus_end_time = current_timestamp();
+    master->bus_time = bus_end_time - bus_start_time;
+    
+#if 0
+    printf("Working counter: %i\n", cmd->working_counter);
+#endif
+    
+    memcpy(master->process_data, cmd->data, master->process_data_length);
+
+    EtherCAT_remove_command(master, cmd);
+
+    if (master->post_cb) master->post_cb(master->process_data);
+
+    // Calculate working time
+
+    cycle_end_time = current_timestamp();
+    master->last_cycle_work_time = cycle_end_time - cycle_start_time;
+    master->last_cycle_busy_rate = master->last_cycle_work_time
+      / ((double) master->cycle_time / 1000000.0) * 100.0;
+    wait_usecs = master->cycle_time - (unsigned int) (master->last_cycle_work_time * 1000000.0);
+
+    //printf("USECS to wait: %i\n", wait_usecs);
+
+    usleep(wait_usecs);
+
+    //printf("waited: %lf\n", current_timestamp() - cycle_end_time);
+  }
+
+  return (void *) 0;
+}
+
+//---------------------------------------------------------------
+
+int EtherCAT_activate_slave(EtherCAT_master_t *master,
+                            EtherCAT_slave_t *slave)
+{
+  EtherCAT_command_t *cmd;
+  const EtherCAT_slave_desc_t *desc;
+  unsigned char fmmu[16];
+  unsigned char data[256];
+
+  if (EtherCAT_state_change(master, slave, EC_STATE_INIT) != 0)
+  {
+    return -1;
+  }
+
+  // Resetting FMMU's
+
+  memset(data, 0x00, 256);
+  cmd = EtherCAT_write(master, slave->station_address, 0x0600, 256, data);
+  EtherCAT_send_receive(master);
+
+  if (cmd->working_counter != 1)
+  {
+    fprintf(stderr, "ERROR: Slave did not respond!\n");
+    return -2;
+  }
+
+  EtherCAT_remove_command(master, cmd);
+
+  // Resetting Sync Manager channels
+
+  memset(data, 0x00, 256);
+  cmd = EtherCAT_write(master, slave->station_address, 0x0800, 256, data);
+  EtherCAT_send_receive(master);
+
+  if (cmd->working_counter != 1)
+  {
+    fprintf(stderr, "ERROR: Slave did not respond!\n");
+    return -2;
+  }
+
+  EtherCAT_remove_command(master, cmd);
+
+  desc = slave->desc;
+
+  // Init Mailbox communication
+
+  if (desc->type == MAILBOX)
+  {
+    if (desc->sm0)
+    {
+      cmd = EtherCAT_write(master, slave->station_address, 0x0800, 8, desc->sm0);
+      
+      EtherCAT_send_receive(master);
+      
+      if (cmd->working_counter != 1)
+      {
+        fprintf(stderr, "ERROR: Not all slaves responded!\n");
+        return -3;
+      }
+      
+      EtherCAT_remove_command(master, cmd);
+    }
+
+    if (desc->sm1)
+    {
+      cmd = EtherCAT_write(master, slave->station_address, 0x0808, 8, desc->sm1);
+      
+      EtherCAT_send_receive(master);
+      
+      if (cmd->working_counter != 1)
+      {
+        fprintf(stderr, "ERROR: Not all slaves responded!\n");
+        return -4;
+      }
+      
+      EtherCAT_remove_command(master, cmd);
+    }
+  }
+
+  // Change state to PREOP
+
+  if (EtherCAT_state_change(master, slave, EC_STATE_PREOP) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not set state!\n");
+    return -5;
+  }
+
+  // Set FMMU's
+
+  if (desc->fmmu0)
+  {
+    memcpy(fmmu, desc->fmmu0, 16);
+
+    fmmu[0] = slave->logical_address0 & 0x000000FF;
+    fmmu[1] = (slave->logical_address0 & 0x0000FF00) >> 8;    
+    fmmu[2] = (slave->logical_address0 & 0x00FF0000) >> 16;
+    fmmu[3] = (slave->logical_address0 & 0xFF000000) >> 24;
+
+    cmd = EtherCAT_write(master, slave->station_address, 0x0600, 16, fmmu);
+    EtherCAT_send_receive(master);
+
+    if (cmd->working_counter != 1)
+    {
+      fprintf(stderr, "ERROR: Not all slaves responded (%i of 1)!\n",
+              cmd->working_counter);
+      return -6;
+    }
+
+    EtherCAT_remove_command(master, cmd);
+  }
+
+  // Set Sync Managers
+
+  if (desc->type != MAILBOX)
+  {
+    if (desc->sm0)
+    {
+      cmd = EtherCAT_write(master, slave->station_address, 0x0800, 8, desc->sm0);
+      
+      EtherCAT_send_receive(master);
+      
+      if (cmd->working_counter != 1)
+      {
+        fprintf(stderr, "ERROR: Not all slaves responded!\n");
+        return -8;
+      }
+      
+      EtherCAT_remove_command(master, cmd);
+    }
+
+    if (desc->sm1)
+    {
+      cmd = EtherCAT_write(master, slave->station_address, 0x0808, 8, desc->sm1);
+      
+      EtherCAT_send_receive(master);
+      
+      if (cmd->working_counter != 1)
+      {
+        fprintf(stderr, "ERROR: Not all slaves responded!\n");
+        return -9;
+      }
+      
+      EtherCAT_remove_command(master, cmd);
+    }
+  }
+  
+  if (desc->sm2)
+  {
+    cmd = EtherCAT_write(master, slave->station_address, 0x0810, 8, desc->sm2);
+      
+    EtherCAT_send_receive(master);
+      
+    if (cmd->working_counter != 1)
+    {
+      fprintf(stderr, "ERROR: Not all slaves responded!\n");
+      return -10;
+    }
+      
+    EtherCAT_remove_command(master, cmd);
+  }
+
+  if (desc->sm3)
+  {
+    cmd = EtherCAT_write(master, slave->station_address, 0x0818, 8, desc->sm3);
+      
+    EtherCAT_send_receive(master);
+      
+    if (cmd->working_counter != 1)
+    {
+      fprintf(stderr, "ERROR: Not all slaves responded!\n");
+      return -11;
+    }
+      
+    EtherCAT_remove_command(master, cmd);
+  }
+
+  // Change state to SAVEOP
+
+  if (EtherCAT_state_change(master, slave, EC_STATE_SAVEOP) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not set state!\n");
+    return -12;
+  }
+
+  // Change state to OP
+
+  if (EtherCAT_state_change(master, slave, EC_STATE_OP) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not set state!\n");
+    return -13;
+  }
+
+  return 0;
+}
+
+//---------------------------------------------------------------
+
+int EtherCAT_deactivate_slave(EtherCAT_master_t *master,
+                            EtherCAT_slave_t *slave)
+{
+  if (EtherCAT_state_change(master, slave, EC_STATE_INIT) != 0)
+  {
+    return -1;
+  }
+
+  return 0;
+}
+
+//---------------------------------------------------------------
+
+void set_byte(unsigned char *data,
+              unsigned int offset,
+              unsigned char value)
+{
+  data[offset] = value;
+}
+
+//---------------------------------------------------------------
+
+void set_word(unsigned char *data,
+              unsigned int offset,
+              unsigned int value)
+{
+  data[offset] = value & 0xFF;
+  data[offset + 1] = (value & 0xFF00) >> 8;
+}
+
+//---------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/user/ec_master.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,120 @@
+//---------------------------------------------------------------
+//
+//  e c _ m a s t e r . h
+//
+//  $LastChangedDate$
+//  $Author$
+//
+//---------------------------------------------------------------
+
+#include <pcap.h>
+#include <libnet.h>
+#include <pthread.h>
+
+#include "ec_slave.h"
+#include "ec_command.h"
+
+//---------------------------------------------------------------
+
+typedef struct
+{
+  EtherCAT_slave_t *slaves; // Slaves array
+  unsigned int slave_count; // Number of slaves
+
+  EtherCAT_command_t *first_command; // List of commands
+
+  pcap_t *pcap_handle;  // Handle for libpcap
+  libnet_t *net_handle; // Handle for libnet
+
+  unsigned char command_index; // Current command index
+
+  unsigned char *process_data;
+  unsigned int process_data_length;
+  void (*pre_cb)(unsigned char *);
+  void (*post_cb)(unsigned char *);
+  pthread_t thread;
+  int thread_continue;
+  unsigned int cycle_time;
+
+  double bus_time;
+
+  double last_jitter;
+  double last_cycle_time;
+  double last_cycle_work_time;
+  double last_cycle_busy_rate;
+}
+EtherCAT_master_t;
+
+//---------------------------------------------------------------
+
+// Master creation and deletion
+int EtherCAT_master_init(EtherCAT_master_t *, char *);
+void EtherCAT_master_clear(EtherCAT_master_t *);
+
+// Checking for slaves
+int EtherCAT_check_slaves(EtherCAT_master_t *, EtherCAT_slave_t *, unsigned int);
+void EtherCAT_clear_slaves(EtherCAT_master_t *);
+
+// Slave information interface
+int EtherCAT_read_slave_information(EtherCAT_master_t *,
+                                    unsigned short int,
+                                    unsigned short int,
+                                    unsigned int *);
+
+// EtherCAT commands
+EtherCAT_command_t *EtherCAT_read(EtherCAT_master_t *,
+                                  unsigned short,
+                                  unsigned short,
+                                  unsigned int);
+EtherCAT_command_t *EtherCAT_write(EtherCAT_master_t *,
+                                   unsigned short,
+                                   unsigned short,
+                                   unsigned int,
+                                   const unsigned char *);
+EtherCAT_command_t *EtherCAT_position_read(EtherCAT_master_t *,
+                                           short,
+                                           unsigned short,
+                                           unsigned int);
+EtherCAT_command_t *EtherCAT_position_write(EtherCAT_master_t *,
+                                            short,
+                                            unsigned short,
+                                            unsigned int,
+                                            const unsigned char *);
+EtherCAT_command_t *EtherCAT_broadcast_read(EtherCAT_master_t *,
+                                            unsigned short,
+                                            unsigned int);
+EtherCAT_command_t *EtherCAT_broadcast_write(EtherCAT_master_t *,
+                                             unsigned short,
+                                             unsigned int,
+                                             const unsigned char *);
+EtherCAT_command_t *EtherCAT_logical_read_write(EtherCAT_master_t *,
+                                                unsigned int,
+                                                unsigned int,
+                                                unsigned char *);
+
+void EtherCAT_remove_command(EtherCAT_master_t *, EtherCAT_command_t *);
+
+// Slave states
+int EtherCAT_state_change(EtherCAT_master_t *, EtherCAT_slave_t *, unsigned char);
+int EtherCAT_broadcast_state_change(EtherCAT_master_t *, unsigned char);
+
+int EtherCAT_activate_slave(EtherCAT_master_t *, EtherCAT_slave_t *);
+int EtherCAT_deactivate_slave(EtherCAT_master_t *, EtherCAT_slave_t *);
+
+// Sending and receiving
+int EtherCAT_send_receive(EtherCAT_master_t *);
+
+int EtherCAT_start(EtherCAT_master_t *,
+                   unsigned int,
+                   void (*)(unsigned char *),
+                   void (*)(unsigned char *),
+                   unsigned int);
+int EtherCAT_stop(EtherCAT_master_t *);
+
+// Private functions
+void add_command(EtherCAT_master_t *, EtherCAT_command_t *);
+void set_byte(unsigned char *, unsigned int, unsigned char);
+void set_word(unsigned char *, unsigned int, unsigned int);
+void *thread_function(void *);
+
+//---------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/user/ec_slave.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,137 @@
+//---------------------------------------------------------------
+//
+//  e c _ s l a v e . c
+//
+//  $LastChangedDate$
+//  $Author$
+//
+//---------------------------------------------------------------
+
+#include <stdlib.h>
+
+#include "ec_globals.h"
+#include "ec_slave.h"
+
+//---------------------------------------------------------------
+
+void EtherCAT_slave_init(EtherCAT_slave_t *slave)
+{
+  slave->type = 0;
+  slave->revision = 0;
+  slave->build = 0;
+
+  slave->ring_position = 0;
+  slave->station_address = 0;
+
+  slave->vendor_id = 0;
+  slave->product_code = 0;
+  slave->revision_number = 0;
+  
+  slave->desc = NULL;
+  
+  slave->logical_address0 = 0;
+
+  slave->current_state = EC_STATE_UNKNOWN;
+  slave->requested_state = EC_STATE_UNKNOWN;
+}
+
+//---------------------------------------------------------------
+
+void EtherCAT_slave_clear(EtherCAT_slave_t *slave)
+{
+  // Nothing yet...
+}
+
+//---------------------------------------------------------------
+
+void EtherCAT_slave_print(EtherCAT_slave_t *slave)
+{
+}
+
+//---------------------------------------------------------------
+
+unsigned char sm0_multi[] = {0x00, 0x18, 0xF6, 0x00, 0x26, 0x00, 0x01, 0x00};
+unsigned char sm1_multi[] = {0xF6, 0x18, 0xF6, 0x00, 0x22, 0x00, 0x01, 0x00};
+
+unsigned char sm0_1014[] = {0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00};
+
+unsigned char sm0_2004[] = {0x00, 0x0F, 0x01, 0x00, 0x46, 0x00, 0x01, 0x00};
+
+unsigned char sm2_31xx[] = {0x00, 0x10, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00};
+unsigned char sm3_31xx[] = {0x00, 0x11, 0x06, 0x00, 0x20, 0x00, 0x01, 0x00};
+
+unsigned char sm2_4102[] = {0x00, 0x10, 0x04, 0x00, 0x24, 0x00, 0x01, 0x00};
+
+
+unsigned char fmmu0_1014[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07,
+                              0x00, 0x10, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00};
+
+unsigned char fmmu0_2004[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07,
+                              0x00, 0x0F, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00};
+
+unsigned char fmmu0_31xx[] = {0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07,
+                              0x00, 0x11, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00};
+
+unsigned char fmmu0_4102[] = {0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07,
+                              0x00, 0x10, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00};
+
+//---------------------------------------------------------------
+
+EtherCAT_slave_desc_t Beckhoff_EK1100[] = {"Beckhoff", "EK1100", "Bus Coupler",
+                                           SIMPLE,
+                                           NULL, NULL, NULL, NULL, // Noch nicht eingepflegt...
+                                           NULL,
+                                           0};
+
+EtherCAT_slave_desc_t Beckhoff_EL1014[] = {"Beckhoff", "EL1014", "4x Digital Input",
+                                           SIMPLE,
+                                           sm0_1014, NULL, NULL, NULL,
+                                           fmmu0_1014,
+                                           1};
+
+EtherCAT_slave_desc_t Beckhoff_EL2004[] = {"Beckhoff", "EL2004", "4x Digital Output",
+                                           SIMPLE,
+                                           sm0_2004, NULL, NULL, NULL,
+                                           fmmu0_2004,
+                                           1};
+
+EtherCAT_slave_desc_t Beckhoff_EL3102[] = {"Beckhoff", "EL3102", "2x Analog Input Diff",
+                                           MAILBOX,
+                                           sm0_multi, sm1_multi, sm2_31xx, sm3_31xx,
+                                           fmmu0_31xx,
+                                           6};
+
+EtherCAT_slave_desc_t Beckhoff_EL3162[] = {"Beckhoff", "EL3162", "2x Analog Input",
+                                           MAILBOX,
+                                           sm0_multi, sm1_multi, sm2_31xx, sm3_31xx,
+                                           fmmu0_31xx,
+                                           6};
+
+EtherCAT_slave_desc_t Beckhoff_EL4102[] = {"Beckhoff", "EL4102", "2x Analog Output",
+                                           MAILBOX,
+                                           sm0_multi, sm1_multi, sm2_4102, NULL,
+                                           fmmu0_4102,
+                                           4};
+
+EtherCAT_slave_desc_t Beckhoff_EL5001[] = {"Beckhoff", "EL5001", "SSI-Interface",
+                                           SIMPLE,
+                                           NULL, NULL, NULL, NULL, // Noch nicht eingepflegt...
+                                           NULL,
+                                           0};
+
+//---------------------------------------------------------------
+
+unsigned int slave_idents_count = 7;
+
+struct slave_ident slave_idents[] = 
+{
+  {0x00000002, 0x03F63052, Beckhoff_EL1014},
+  {0x00000002, 0x044C2C52, Beckhoff_EK1100},
+  {0x00000002, 0x07D43052, Beckhoff_EL2004},
+  {0x00000002, 0x0C1E3052, Beckhoff_EL3102},
+  {0x00000002, 0x0C5A3052, Beckhoff_EL3162},
+  {0x00000002, 0x10063052, Beckhoff_EL4102},
+  {0x00000002, 0x13893052, Beckhoff_EL5001}
+};
+
+//---------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/user/ec_slave.h	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,96 @@
+//---------------------------------------------------------------
+//
+//  e c _ s l a v e . h
+//
+//  $LastChangedDate$
+//  $Author$
+//
+//---------------------------------------------------------------
+
+#define SIMPLE 0
+#define MAILBOX 1
+
+//---------------------------------------------------------------
+
+typedef struct slave_desc EtherCAT_slave_desc_t;
+
+typedef struct
+{
+  // Base data
+  unsigned char type;
+  unsigned char revision;
+  unsigned short build;
+
+  // Addresses
+  short ring_position;
+  unsigned short station_address;
+
+  // Slave information interface
+  unsigned int vendor_id;
+  unsigned int product_code;
+  unsigned int revision_number;
+
+  const EtherCAT_slave_desc_t *desc;
+
+  unsigned int logical_address0;
+
+  unsigned int current_state;
+  unsigned int requested_state;
+
+  unsigned char *process_data;
+}
+EtherCAT_slave_t;
+
+#define ECAT_INIT_SLAVE(TYPE) {0, 0, 0, 0, 0, 0, 0, 0, TYPE, 0, 0, 0, NULL}
+
+//---------------------------------------------------------------
+
+// Slave construction and deletion
+void EtherCAT_slave_init(EtherCAT_slave_t *);
+void EtherCAT_slave_clear(EtherCAT_slave_t *);
+
+// Debug
+void EtherCAT_slave_print(EtherCAT_slave_t *);
+
+//---------------------------------------------------------------
+
+typedef struct slave_desc
+{
+  const char *vendor_name;
+  const char *product_name;
+  const char *product_desc;
+
+  const int type;
+
+  const unsigned char *sm0;
+  const unsigned char *sm1;
+  const unsigned char *sm2;
+  const unsigned char *sm3;
+
+  const unsigned char *fmmu0;
+
+  const unsigned int data_length;
+}
+EtherCAT_slave_desc_t;
+
+extern EtherCAT_slave_desc_t Beckhoff_EK1100[];
+extern EtherCAT_slave_desc_t Beckhoff_EL1014[];
+extern EtherCAT_slave_desc_t Beckhoff_EL2004[];
+extern EtherCAT_slave_desc_t Beckhoff_EL3102[];
+extern EtherCAT_slave_desc_t Beckhoff_EL3162[];
+extern EtherCAT_slave_desc_t Beckhoff_EL4102[];
+extern EtherCAT_slave_desc_t Beckhoff_EL5001[];
+
+//---------------------------------------------------------------
+
+struct slave_ident
+{
+  const unsigned int vendor_id;
+  const unsigned int product_code;
+  const EtherCAT_slave_desc_t *desc;
+};
+
+extern struct slave_ident slave_idents[];
+extern unsigned int slave_idents_count;
+
+//---------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/user/main.c	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,439 @@
+//---------------------------------------------------------------
+//
+//  m a i n . c
+//
+//  $LastChangedDate$
+//  $Author$
+//
+//---------------------------------------------------------------
+
+#include <stdio.h>
+#include <string.h> // memset()
+#include <unistd.h> // usleep()
+#include <signal.h>
+
+#include "ec_globals.h"
+#include "ec_master.h"
+
+//---------------------------------------------------------------
+
+void signal_handler(int);
+void write_data(unsigned char *);
+
+int continue_running;
+unsigned short int word;
+
+//---------------------------------------------------------------
+
+int main(int argc, char **argv)
+{
+  EtherCAT_master_t master;
+  EtherCAT_command_t *cmd, *cmd2;
+  unsigned char data[256];
+  unsigned int i, number;
+  struct sigaction sa;
+  
+  sa.sa_handler = signal_handler;
+  sigaction(SIGINT, &sa, NULL);
+
+  printf("CatEther-Testprogramm.\n");
+
+  EtherCAT_master_init(&master, "eth1");
+
+  if (EtherCAT_check_slaves(&master, NULL, 0) != 0)
+  {
+    fprintf(stderr, "ERROR while searching for slaves!\n");
+    return -1;
+  }
+
+  if (master.slave_count == 0)
+  {
+    fprintf(stderr, "ERROR: No slaves found!\n");
+    return -1;
+  }
+
+  for (i = 0; i < master.slave_count; i++)
+  {
+    printf("Slave found: Type %02X, Revision %02X, Build %04X\n",
+           master.slaves[i].type, master.slaves[i].revision, master.slaves[i].build);
+  }
+
+  printf("Writing Station addresses.\n");
+
+  for (i = 0; i < master.slave_count; i++)
+  {
+    data[0] = i & 0x00FF;
+    data[1] = (i & 0xFF00) >> 8;
+
+    cmd = EtherCAT_position_write(&master, 0 - i, 0x0010, 2, data);
+    
+    EtherCAT_send_receive(&master);
+    
+    if (cmd->working_counter != 1)
+    {
+      fprintf(stderr, "ERROR: Slave did'n repond!\n");
+      return -1;
+    }
+    
+    EtherCAT_remove_command(&master, cmd);
+  }
+
+  //----------
+
+  for (i = 0; i < master.slave_count; i++)
+  {
+    printf("\nKlemme %i:\n", i);
+
+    EtherCAT_read_slave_information(&master, i, 0x0008, &number);
+    printf("Vendor ID: 0x%04X (%i)\n", number, number);
+
+    EtherCAT_read_slave_information(&master, i, 0x000A, &number);
+    printf("Product Code: 0x%04X (%i)\n", number, number);
+
+    EtherCAT_read_slave_information(&master, i, 0x000E, &number);
+    printf("Revision Number: 0x%04X (%i)\n", number, number);
+  }
+
+  //----------
+
+  printf("\nResetting FMMU's.\n");
+
+  memset(data, 0x00, 256);
+  cmd = EtherCAT_broadcast_write(&master, 0x0600, 256, data);
+  EtherCAT_send_receive(&master);
+
+  if (cmd->working_counter != master.slave_count)
+  {
+    fprintf(stderr, "ERROR: Not all slaves responded (%i of %i)!\n",
+            cmd->working_counter, master.slave_count);
+    return -1;
+  }
+
+  EtherCAT_remove_command(&master, cmd);
+
+  //----------
+
+  printf("Resetting Sync Manager channels.\n");
+
+  memset(data, 0x00, 256);
+  cmd = EtherCAT_broadcast_write(&master, 0x0800, 256, data);
+  EtherCAT_send_receive(&master);
+
+  if (cmd->working_counter != master.slave_count)
+  {
+    fprintf(stderr, "ERROR: Not all slaves responded (%i of %i)!\n",
+            cmd->working_counter, master.slave_count);
+    return -1;
+  }
+
+  EtherCAT_remove_command(&master, cmd);
+
+  //----------
+
+  printf("Setting INIT state for devices.\n");
+
+  if (EtherCAT_broadcast_state_change(&master, EC_STATE_INIT) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not set INIT state!\n");
+    return -1;
+  }
+
+  //----------
+
+  printf("Setting PREOP state for bus coupler.\n");
+
+  if (EtherCAT_state_change(&master, &master.slaves[0], EC_STATE_PREOP) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not set state!\n");
+    return -1;
+  }
+
+  //----------
+
+  printf("Setting Sync managers 0 and 1 of device 1.\n");
+
+  data[0] = 0x00;
+  data[1] = 0x18;
+  data[2] = 0xF6;
+  data[3] = 0x00;
+  data[4] = 0x26;
+  data[5] = 0x00;
+  data[6] = 0x01;
+  data[7] = 0x00;
+  cmd = EtherCAT_write(&master, 0x0001, 0x0800, 8, data);
+
+  data[0] = 0xF6;
+  data[1] = 0x18;
+  data[2] = 0xF6;
+  data[3] = 0x00;
+  data[4] = 0x22;
+  data[5] = 0x00;
+  data[6] = 0x01;
+  data[7] = 0x00;
+  cmd2 = EtherCAT_write(&master, 0x0001, 0x0808, 8, data);
+
+  EtherCAT_send_receive(&master);
+
+  if (cmd->working_counter != 1 || cmd2->working_counter != 1)
+  {
+    fprintf(stderr, "ERROR: Not all slaves responded!\n");
+
+    return -1;
+  }
+
+  EtherCAT_remove_command(&master, cmd);
+  EtherCAT_remove_command(&master, cmd2);
+
+
+  //----------
+
+  printf("Setting PREOP state for device 1.\n");
+
+  if (EtherCAT_state_change(&master, &master.slaves[1], EC_STATE_PREOP))
+  {
+    fprintf(stderr, "ERROR: Could not set state!\n");
+    return -1;
+  }
+
+  //----------
+
+  printf("Setting PREOP state for device 4.\n");
+
+  if (EtherCAT_state_change(&master, &master.slaves[4], EC_STATE_PREOP))
+  {
+    fprintf(stderr, "ERROR: Could not set state!\n");
+    return -1;
+  }
+
+  //----------
+
+#if 1
+  printf("Setting FMMU 0 of device 1.\n");
+
+  data[0] = 0x00; // Logical start address [4]
+  data[1] = 0x00;
+  data[2] = 0x00;
+  data[3] = 0x00;
+  data[4] = 0x04; // Length [2]
+  data[5] = 0x00;
+  data[6] = 0x00; // Start bit
+  data[7] = 0x07; // End bit
+  data[8] = 0x00; // Physical start address [2]
+  data[9] = 0x10;
+  data[10] = 0x00; // Physical start bit
+  data[11] = 0x02; // Read/write enable
+  data[12] = 0x01; // channel enable [2]
+  data[13] = 0x00;
+  data[14] = 0x00; // Reserved [2]
+  data[15] = 0x00;
+  cmd = EtherCAT_write(&master, 0x0001, 0x0600, 16, data);
+  EtherCAT_send_receive(&master);
+
+  if (cmd->working_counter != 1)
+  {
+    fprintf(stderr, "ERROR: Not all slaves responded (%i of 1)!\n",
+            cmd->working_counter);
+    return -1;
+  }
+
+  EtherCAT_remove_command(&master, cmd);
+#endif
+
+  //----------
+
+#if 1
+  printf("Setting FMMU 0 of device 4.\n");
+
+  data[0] = 0x04; // Logical start address [4]
+  data[1] = 0x00;
+  data[2] = 0x00;
+  data[3] = 0x00;
+  data[4] = 0x01; // Length [2]
+  data[5] = 0x00;
+  data[6] = 0x00; // Start bit
+  data[7] = 0x07; // End bit
+  data[8] = 0x00; // Physical start address [2]
+  data[9] = 0x0F;
+  data[10] = 0x00; // Physical start bit
+  data[11] = 0x02; // Read/write enable
+  data[12] = 0x01; // channel enable [2]
+  data[13] = 0x00;
+  data[14] = 0x00; // Reserved [2]
+  data[15] = 0x00;
+  cmd = EtherCAT_write(&master, 0x0004, 0x0600, 16, data);
+  EtherCAT_send_receive(&master);
+
+  if (cmd->working_counter != 1)
+  {
+    fprintf(stderr, "ERROR: Not all slaves responded (%i of 1)!\n",
+            cmd->working_counter);
+    return -1;
+  }
+
+  EtherCAT_remove_command(&master, cmd);
+#endif
+
+  //----------
+
+  printf("Setting Sync manager 2 of device 1.\n");
+
+  data[0] = 0x00;
+  data[1] = 0x10;
+  data[2] = 0x04;
+  data[3] = 0x00;
+  data[4] = 0x24;
+  data[5] = 0x00;
+  data[6] = 0x01;
+  data[7] = 0x00;
+  cmd = EtherCAT_write(&master, 0x0001, 0x0810, 8, data);
+  EtherCAT_send_receive(&master);
+
+  if (cmd->working_counter != 1)
+  {
+    fprintf(stderr, "ERROR: Not all slaves responded (%i of 1)!\n", cmd->working_counter);
+    return -1;
+  }
+
+  EtherCAT_remove_command(&master, cmd);
+
+  //----------
+
+  printf("Setting Sync manager 0 for device 4.\n");
+
+  data[0] = 0x00;
+  data[1] = 0x0F;
+  data[2] = 0x01;
+  data[3] = 0x00;
+  data[4] = 0x46; // 46
+  data[5] = 0x00;
+  data[6] = 0x01;
+  data[7] = 0x00;
+  cmd = EtherCAT_write(&master, 0x0004, 0x0800, 8, data);
+
+  EtherCAT_send_receive(&master);
+
+  if (cmd->working_counter != 1)
+  {
+    fprintf(stderr, "ERROR: Not all slaves responded!\n");
+
+    return -1;
+  }
+
+  EtherCAT_remove_command(&master, cmd);
+
+  //----------
+
+  printf("Setting SAVEOP state for bus coupler.\n");
+
+  if (EtherCAT_state_change(&master, 0x0000, EC_STATE_SAVEOP) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not set state!\n");
+    return -1;
+  }
+
+  //----------
+
+  printf("Setting SAVEOP state for device 1.\n");
+
+  if (EtherCAT_state_change(&master, &master.slaves[1], EC_STATE_SAVEOP) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not set state!\n");
+    return -1;
+  }
+
+  //----------
+
+  printf("Setting SAVEOP state for device 4.\n");
+
+  if (EtherCAT_state_change(&master, &master.slaves[4], EC_STATE_SAVEOP) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not set state!\n");
+    return -1;
+  }
+
+  //----------
+
+  printf("Setting OP state for bus coupler.\n");
+
+  if (EtherCAT_state_change(&master, &master.slaves[0], EC_STATE_OP) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not set state!\n");
+    return -1;
+  }
+
+  //----------
+
+  printf("Setting OP state for device 1.\n");
+
+  if (EtherCAT_state_change(&master, &master.slaves[1], EC_STATE_OP) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not set state!\n");
+    return -1;
+  }
+
+  //----------
+
+  printf("Setting OP state for device 4.\n");
+
+  if (EtherCAT_state_change(&master, &master.slaves[4], EC_STATE_OP) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not set state!\n");
+    return -1;
+  }
+
+  //----------
+
+  word = 0;
+
+  printf("Starting thread...\n");
+
+  if (EtherCAT_start(&master, 5, write_data, NULL, 10000) != 0)
+  {
+    return -1;
+  }
+
+  continue_running = 1;
+
+  while (continue_running)
+  {
+    usleep(200000);
+
+    word += 1000;
+    word = word & 0x7FFF;
+  }
+
+  //----------
+
+  printf("Stopping master thread...\n");
+  EtherCAT_stop(&master);
+
+  EtherCAT_master_clear(&master);
+
+  printf("Finished.\n");
+  
+  return 0;
+}
+
+//---------------------------------------------------------------
+
+void write_data(unsigned char *data)
+{
+  data[0] = word & 0xFF;
+  data[1] = (word & 0xFF00) >> 8;
+  data[2] = word & 0xFF;
+  data[3] = (word & 0xFF00) >> 8;
+
+  data[4] = 0x01;
+}
+
+//---------------------------------------------------------------
+
+void signal_handler(int signum)
+{
+  if (signum == SIGINT || signum == SIGTERM)
+  {
+    continue_running = 0;
+  }
+}
+
+//---------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/user/main_gui.cpp	Fri Oct 21 11:21:42 2005 +0000
@@ -0,0 +1,287 @@
+//---------------------------------------------------------------
+//
+//  m a i n _ g u i . c p p
+//
+//  $LastChangedDate$
+//  $Author$
+//
+//---------------------------------------------------------------
+
+#include <stdio.h>
+#include <string.h> // memset()
+#include <unistd.h> // usleep()
+#include <signal.h>
+
+#include <fltk/Window.h>
+#include <fltk/Slider.h>
+#include <fltk/ValueOutput.h>
+#include <fltk/FillSlider.h>
+#include <fltk/CheckButton.h>
+#include <fltk/run.h>
+using namespace fltk;
+
+#include "ec_globals.h"
+#include "ec_master.h"
+
+#define SLIDER_UPDATE_CYCLE 0.02
+#define VALUES_UPDATE_CYCLE 0.50
+
+//---------------------------------------------------------------
+
+unsigned short int write_value;
+signed short int read_value;
+unsigned char dig_value;
+
+void write_data(unsigned char *);
+void read_data(unsigned char *);
+
+void slider_write_callback(Widget *, void *);
+void slider_read_timeout(void *);
+void values_timeout(void *);
+
+Window *window;
+Slider *slider_read, *slider_write;
+ValueOutput *output_cycle, *output_jitter, *output_work, *output_busy, *output_bus;
+CheckButton *check1, *check2, *check3, *check4;
+EtherCAT_master_t master;
+
+double max_cycle, max_jitter, max_work, max_busy, max_bus;
+
+//---------------------------------------------------------------
+
+#define SLAVE_COUNT 7
+
+EtherCAT_slave_t slaves[SLAVE_COUNT] =
+{
+  ECAT_INIT_SLAVE(Beckhoff_EK1100),
+  ECAT_INIT_SLAVE(Beckhoff_EL4102),
+  ECAT_INIT_SLAVE(Beckhoff_EL3162),
+  ECAT_INIT_SLAVE(Beckhoff_EL1014),
+  ECAT_INIT_SLAVE(Beckhoff_EL5001),
+  ECAT_INIT_SLAVE(Beckhoff_EL2004),
+  ECAT_INIT_SLAVE(Beckhoff_EL3102)
+};
+
+//---------------------------------------------------------------
+
+int main(int argc, char **argv)
+{
+  //unsigned int i;
+  EtherCAT_slave_t *buskoppler, *input, *output, *dig_in, *dig_out;
+  struct sched_param sched;
+
+  printf("CatEther-Testprogramm.\n\n");
+
+  //----------
+
+#if 1
+  printf("Setting highest task priority...\n");
+
+  sched.sched_priority = sched_get_priority_max(SCHED_RR);
+  if (sched_setscheduler(0, SCHED_RR, &sched) == -1)
+  {
+    fprintf(stderr, "ERROR: Could not set priority: %s\n", strerror(errno)); 
+    return -1;
+  }
+#endif
+
+  //----------
+
+  printf("Initializing master...\n");
+  EtherCAT_master_init(&master, "eth1");
+
+  printf("Checking slaves...\n");
+  if (EtherCAT_check_slaves(&master, slaves, SLAVE_COUNT) != 0)
+  {
+    fprintf(stderr, "ERROR while searching for slaves!\n");
+    return -1;
+  }
+
+  //----------
+
+  // Check for slaves
+
+  buskoppler = &slaves[0];
+  output = &slaves[1];
+  dig_in = &slaves[3];
+  dig_out = &slaves[5];
+  input = &slaves[6];
+
+  // Set Mapping addresses
+
+  output->logical_address0 = 0x00000000;
+  input->logical_address0 = 0x00000004;
+  dig_in->logical_address0 = 0x0000000F;
+  dig_out->logical_address0 = 0x0000000E;
+
+  //----------
+
+  printf("Init output slave...\n");
+
+  if (EtherCAT_activate_slave(&master, output) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not init slave!\n");
+    return -1;
+  }
+
+  printf("Init input slave...\n");
+
+  if (EtherCAT_activate_slave(&master, input) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not init slave!\n");
+    return -1;
+  }
+
+  printf("Init digital input slave...\n");
+
+  if (EtherCAT_activate_slave(&master, dig_in) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not init slave!\n");
+    return -1;
+  }
+
+  printf("Init digital output slave...\n");
+
+  if (EtherCAT_activate_slave(&master, dig_out) != 0)
+  {
+    fprintf(stderr, "ERROR: Could not init slave!\n");
+    return -1;
+  }
+
+  //----------
+
+  printf("Starting FLTK window...\n");
+  
+  window = new Window(300, 300);
+  window->begin();
+
+  slider_read = new FillSlider(50, 10, 40, 280);
+  slider_read->set_vertical();
+  slider_read->buttoncolor(BLUE);
+  
+  slider_read->deactivate();
+
+  slider_write = new Slider(110, 10, 40, 280);
+  slider_write->set_vertical();
+  slider_write->callback(slider_write_callback, NULL);
+
+  output_cycle = new ValueOutput(200, 50, 90, 25, "Cycle time [µs]");
+  output_cycle->align(ALIGN_LEFT | ALIGN_TOP);
+
+  output_jitter = new ValueOutput(200, 90, 90, 25, "Jitter [%]");
+  output_jitter->align(ALIGN_LEFT | ALIGN_TOP);
+
+  output_work = new ValueOutput(200, 130, 90, 25, "Work time [µs]");
+  output_work->align(ALIGN_LEFT | ALIGN_TOP);
+
+  output_busy = new ValueOutput(200, 170, 90, 25, "Busy rate [%]");
+  output_busy->align(ALIGN_LEFT | ALIGN_TOP);
+
+  output_bus = new ValueOutput(200, 210, 90, 25, "Bus time [µs]");
+  output_bus->align(ALIGN_LEFT | ALIGN_TOP);
+
+  check1 = new CheckButton(200, 240, 30, 25, "1");
+  check2 = new CheckButton(250, 240, 30, 25, "2");
+  check3 = new CheckButton(200, 270, 30, 25, "3");
+  check4 = new CheckButton(250, 270, 30, 25, "4");
+
+  //  output_cycle = new Output(200, 35, 90, 25);
+
+  window->end();
+  window->show();
+
+  add_timeout(SLIDER_UPDATE_CYCLE, slider_read_timeout, NULL);
+  add_timeout(VALUES_UPDATE_CYCLE, values_timeout, NULL);
+
+  printf("Starting thread...\n");
+
+  if (EtherCAT_start(&master, 20, write_data, read_data, 10000) != 0)
+  {
+    return -1;
+  }
+
+  run(); // Start FLTK loop
+
+  remove_timeout(slider_read_timeout, NULL);
+  remove_timeout(values_timeout, NULL);
+
+  printf("Stopping master thread...\n");
+  EtherCAT_stop(&master);
+
+  printf("Deactivating slaves...\n");
+
+  EtherCAT_deactivate_slave(&master, dig_out);
+  EtherCAT_deactivate_slave(&master, dig_in);
+  EtherCAT_deactivate_slave(&master, input);
+  EtherCAT_deactivate_slave(&master, output);
+  EtherCAT_deactivate_slave(&master, buskoppler);
+
+  EtherCAT_master_clear(&master);
+
+  printf("Finished.\n");
+  
+  return 0;
+}
+
+//---------------------------------------------------------------
+
+void write_data(unsigned char *data)
+{
+  data[0] = write_value & 0xFF;
+  data[1] = (write_value & 0xFF00) >> 8;
+
+  data[14] = (write_value * 16 / 32767) & 0x0F;
+}
+
+//---------------------------------------------------------------
+
+void read_data(unsigned char *data)
+{
+  read_value = data[5] | data[6] << 8;
+  dig_value = data[15];
+}
+
+//---------------------------------------------------------------
+
+void slider_read_timeout(void *data)
+{
+  slider_read->value((double) read_value / 65536 + 0.5);
+  slider_read->redraw();
+
+  check1->value(dig_value & 1);
+  check2->value(dig_value & 2);
+  check3->value(dig_value & 4);
+  check4->value(dig_value & 8);
+
+  if (max_cycle < master.last_cycle_time) max_cycle = master.last_cycle_time;
+  if (max_jitter < master.last_jitter) max_jitter = master.last_jitter;
+  if (max_work < master.last_cycle_work_time) max_work = master.last_cycle_work_time;
+  if (max_busy < master.last_cycle_busy_rate) max_busy = master.last_cycle_busy_rate;
+  if (max_bus < master.bus_time) max_bus = master.bus_time;
+
+  repeat_timeout(SLIDER_UPDATE_CYCLE, slider_read_timeout, NULL);
+}
+
+//---------------------------------------------------------------
+
+void values_timeout(void *data)
+{
+  output_cycle->value(max_cycle * 1000000.0);
+  output_jitter->value(max_jitter);
+  output_work->value(max_work * 1000000.0);
+  output_busy->value(max_busy);
+  output_bus->value(max_bus * 1000000.0);
+
+  max_cycle = max_jitter = max_work = max_busy = max_bus = 0.0;
+
+  repeat_timeout(VALUES_UPDATE_CYCLE, values_timeout, NULL);
+}
+
+//---------------------------------------------------------------
+
+void slider_write_callback(Widget *sender, void *data)
+{
+  write_value = (short unsigned int) (32767 * slider_write->value() + 0.5);
+}
+
+//---------------------------------------------------------------