--- /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(¤t->sigmask_lock);
+ sigemptyset(¤t->blocked);
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->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(¤t->sigmask_lock);
+ flush_signals(current);
+ spin_unlock_irq(¤t->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(®s, 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, ®s, 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),
+ ðtool_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);
+}
+
+//---------------------------------------------------------------