--- a/Makefile.am Mon Sep 25 17:28:31 2006 +0000
+++ b/Makefile.am Tue Sep 26 16:38:38 2006 +0000
@@ -70,7 +70,8 @@
$(MINI_FILES) $(RTAI_FILES) $(MSR_FILES)
mydist:
- $(MAKE) dist distdir=$(PACKAGE)-$(VERSION)-r`svnversion $(srcdir)`
+ @SVNREV=`svnversion $(srcdir)` && \
+ $(MAKE) dist-bzip2 distdir=$(PACKAGE)-$(VERSION)-r$${SVNREV}
dist-hook:
if which svnversion >/dev/null 2>&1; then \
--- a/documentation/ethercat_doc.tex Mon Sep 25 17:28:31 2006 +0000
+++ b/documentation/ethercat_doc.tex Tue Sep 26 16:38:38 2006 +0000
@@ -4300,9 +4300,10 @@
\label{sec:make}
\index{Master!Compilation}
-The current EtherCAT master code is available at~\cite{etherlab}.
-After downloading the \textit{tar.bz2} file, it has to be unpacked
-with the command below (or similar):
+The current EtherCAT master code is available at~\cite{etherlab} or
+can be obtained from the EtherLab\textsuperscript{\textregistered} CD.
+The \textit{tar.bz2} file has to be unpacked with the command below
+(or similar):
\begin{lstlisting}
host> `\textbf{tar xjf ethercat-1.1-rXXX.tar.bz2}`
@@ -4340,10 +4341,12 @@
host# `\textbf{make install}`
\end{lstlisting}
-If the EtherCAT master shall be run as a service (recommended), the
-init script and the sysconfig file have to be copied to the
-appropriate locations. The below example is suitable for SUSE Linux.
-It may vary for other distributions.
+If the EtherCAT master shall be run as a service
+(recommended\footnote{Even if the EtherCAT master shall not be loaded
+ on system startup, the use of the init script is recommended for
+ manual (un-)loading.}), the init script and the sysconfig file have
+to be copied to the appropriate locations. The below example is
+suitable for SUSE Linux. It may vary for other distributions.
\begin{lstlisting}
host# `\textbf{cd /opt/etherlab}`
@@ -4352,14 +4355,33 @@
host# `\textbf{insserv ethercat}`
\end{lstlisting}
-Now the sysconfig file has to be customized. For the contents of the
-file, see section~\ref{sec:sysconfig}. To give a short summary: The
-most important thing is to adjust the \textit{DEVICE\_INDEX} variable.
-It has to be set to the index of the compatible network device to use
+Now the sysconfig file \texttt{/etc/sysconfig/ethercat} (see
+section~\ref{sec:sysconfig}) has to be customized: This is mainly done
+by uncommenting and adjusting the \textit{DEVICE\_INDEX} variable. It
+has to be set to the index of the compatible network device to use
with EtherCAT, where the order of devices is dependent on their
-position in the PCI bus. If this is not known, the index can be
-determinded with trial and error, but it has to be considered that a
-wrong value can cause a loss of network connection.
+position in the PCI bus:
+
+\begin{lstlisting}[numbers=left,basicstyle=\ttfamily\scriptsize]
+ host# `\textbf{lspci}`
+ 00:00.0 Host bridge: VIA Technologies, Inc. VT8363/8365 [KT133/KM133] (rev 03)
+ 00:01.0 PCI bridge: VIA Technologies, Inc. VT8363/8365 [KT133/KM133 AGP]
+ 00:04.0 ISA bridge: VIA Technologies, Inc. VT82C686 [Apollo Super South] (rev 40)
+ 00:04.1 IDE interface: VIA Technologies, Inc. VT82C586A/B/VT82C686/A/B/VT823x/A/C...
+ 00:04.2 USB Controller: VIA Technologies, Inc. VT82xxxxx UHCI USB 1.1 Controller...
+ 00:04.3 USB Controller: VIA Technologies, Inc. VT82xxxxx UHCI USB 1.1 Controller...
+ 00:04.4 Bridge: VIA Technologies, Inc. VT82C686 [Apollo Super ACPI] (rev 40)
+ 00:09.0 Ethernet controller: D-Link System Inc RTL8139 Ethernet (rev 10)
+ 00:0a.0 Ethernet controller: Intel Corporation 82557/8/9 [Ethernet Pro 100] (rev 08)
+ 00:0b.0 Ethernet controller: D-Link System Inc RTL8139 Ethernet (rev 10)
+ 00:0c.0 VGA compatible controller: ATI Technologies Inc Rage XL (rev 27)
+ 00:11.0 Unknown mass storage controller: Promise Technology, Inc. PDC20265...
+\end{lstlisting}
+
+In the above output of the \textit{lspci} command, two compatible
+network devices can be found in lines~\textcircled{\tiny 9} and
+\textcircled{\tiny 11}. The \textit{DEVICE\_INDEX} variable should be
+set to $0$ or $1$, respectively.
After the basic configuration is done, the master can be started with
the below command:
--- a/master/domain.c Mon Sep 25 17:28:31 2006 +0000
+++ b/master/domain.c Tue Sep 26 16:38:38 2006 +0000
@@ -357,7 +357,7 @@
}
}
- EC_INFO("Domain %i - Allocated %i bytes in %i datagram%s\n",
+ EC_INFO("Domain %i - Allocated %i bytes in %i datagram%s.\n",
domain->index, domain->data_size, datagram_count,
datagram_count == 1 ? "" : "s");
--- a/master/master.c Mon Sep 25 17:28:31 2006 +0000
+++ b/master/master.c Tue Sep 26 16:38:38 2006 +0000
@@ -108,7 +108,7 @@
master->index = index;
master->device = NULL;
- master->reserved = 0;
+ atomic_set(&master->available, 1);
INIT_LIST_HEAD(&master->slaves);
INIT_LIST_HEAD(&master->datagram_queue);
INIT_LIST_HEAD(&master->domains);
@@ -1041,9 +1041,10 @@
/**
Measures the time, a frame is on the bus.
-*/
-
-void ec_master_measure_bus_time(ec_master_t *master)
+ \return 0 in case of success, else < 0
+*/
+
+int ec_master_measure_bus_time(ec_master_t *master)
{
ec_datagram_t datagram;
cycles_t cycles_start, cycles_end, cycles_timeout;
@@ -1054,7 +1055,7 @@
if (ec_datagram_brd(&datagram, 0x130, 2)) {
EC_ERR("Failed to allocate datagram for bus time measuring.\n");
ec_datagram_clear(&datagram);
- return;
+ return -1;
}
cycles_timeout = (cycles_t) EC_IO_TIMEOUT * (cpu_khz / 1000);
@@ -1093,11 +1094,13 @@
EC_INFO("Bus time is (min/avg/max) %u/%u.%u/%u us.\n",
min, sum / 100, sum % 100, max);
+ return 0;
error:
// Dequeue and free datagram
list_del(&datagram.queue);
ec_datagram_clear(&datagram);
+ return -1;
}
/******************************************************************************
--- a/master/master.h Mon Sep 25 17:28:31 2006 +0000
+++ b/master/master.h Tue Sep 26 16:38:38 2006 +0000
@@ -44,6 +44,7 @@
#include <linux/list.h>
#include <linux/sysfs.h>
#include <linux/timer.h>
+#include <asm/atomic.h>
#include "device.h"
#include "domain.h"
@@ -91,7 +92,7 @@
struct ec_master
{
struct list_head list; /**< list item for module's master list */
- unsigned int reserved; /**< non-zero, if the master is reserved for RT */
+ atomic_t available; /**< zero, if the master is reserved for RT */
unsigned int index; /**< master index */
struct kobject kobj; /**< kobject */
@@ -158,7 +159,7 @@
// misc.
void ec_master_output_stats(ec_master_t *);
void ec_master_clear_slaves(ec_master_t *);
-void ec_master_measure_bus_time(ec_master_t *);
+int ec_master_measure_bus_time(ec_master_t *);
// other methods
void ec_sync_config(const ec_sii_sync_t *, const ec_slave_t *, uint8_t *);
--- a/master/module.c Mon Sep 25 17:28:31 2006 +0000
+++ b/master/module.c Tue Sep 26 16:38:38 2006 +0000
@@ -401,71 +401,78 @@
if (!(master = ec_find_master(master_index))) goto out_return;
- if (master->reserved) {
+ if (!atomic_dec_and_test(&master->available)) {
+ atomic_inc(&master->available);
EC_ERR("Master %i is already in use!\n", master_index);
goto out_return;
}
- master->reserved = 1;
if (!master->device) {
EC_ERR("Master %i has no assigned device!\n", master_index);
goto out_release;
}
- if (!try_module_get(master->device->module)) {
+ if (!try_module_get(master->device->module)) { // possible race?
EC_ERR("Failed to reserve device module!\n");
goto out_release;
}
- ec_master_measure_bus_time(master);
- ec_master_idle_stop(master);
- ec_master_reset(master);
+ if (!master->device->link_state) {
+ EC_ERR("Link is DOWN.\n");
+ goto out_module_put;
+ }
+
+ ec_master_reset(master); // also stops idle mode
master->mode = EC_MASTER_MODE_OPERATION;
- if (!master->device->link_state) EC_WARN("Link is DOWN.\n");
+ if (ec_master_measure_bus_time(master)) {
+ EC_ERR("Bus time measuring failed!\n");
+ goto out_reset;
+ }
if (ec_master_bus_scan(master)) {
EC_ERR("Bus scan failed!\n");
- goto out_module_put;
- }
-
- EC_INFO("Master %i is ready.\n", master_index);
+ goto out_reset;
+ }
+
+ EC_INFO("Successfully requested master %i.\n", master_index);
return master;
+ out_reset:
+ ec_master_reset(master);
+ ec_master_idle_start(master);
out_module_put:
module_put(master->device->module);
+ out_release:
+ atomic_inc(&master->available);
+ out_return:
+ EC_ERR("Failed to request master %i.\n", master_index);
+ return NULL;
+}
+
+/*****************************************************************************/
+
+/**
+ Releases a reserved EtherCAT master.
+ \ingroup RealtimeInterface
+*/
+
+void ecrt_release_master(ec_master_t *master /**< EtherCAT master */)
+{
+ EC_INFO("Releasing master %i...\n", master->index);
+
+ if (atomic_read(&master->available)) {
+ EC_ERR("Master %i was never requested!\n", master->index);
+ return;
+ }
+
ec_master_reset(master);
ec_master_idle_start(master);
- out_release:
- master->reserved = 0;
- out_return:
- EC_ERR("Failed requesting master %i.\n", master_index);
- return NULL;
-}
-
-/*****************************************************************************/
-
-/**
- Releases a reserved EtherCAT master.
- \ingroup RealtimeInterface
-*/
-
-void ecrt_release_master(ec_master_t *master /**< EtherCAT master */)
-{
- EC_INFO("Releasing master %i...\n", master->index);
-
- if (!master->reserved) {
- EC_ERR("Master %i was never requested!\n", master->index);
- return;
- }
-
- ec_master_reset(master);
- ec_master_idle_start(master);
module_put(master->device->module);
- master->reserved = 0;
-
- EC_INFO("Released master %i.\n", master->index);
+ atomic_inc(&master->available);
+
+ EC_INFO("Successfully released master %i.\n", master->index);
return;
}